aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMitch Curtis <[email protected]>2022-06-23 15:33:34 +0800
committerMitch Curtis <[email protected]>2022-10-13 11:34:11 +0800
commit49b9f1f1e85ce9aee960b1384fb542daacd8b7a7 (patch)
tree575cebdd0dd014d6569bfec36f20dbe5f6cddf4b
parent5eb52b725526c26d0efa3856b6aba1919010f8fd (diff)
Make QQuickAttachedPropertyPropagator public
This type has been used internally as QQuickAttachedObject by the Imagine, Material and Universal styles to enable propagation of colors, dark mode flags, etc. for a while now. Users would benefit from having access to it to create their own styles (although it's not just limited to that use case). This patch: - Makes the type public in quickcontrols2. - Adds documentation and an example. - Fixes the test_window test to ensure that propagation through child windows actually works. [ChangeLog][Controls] Added QQuickAttachedPropertyPropagator, which provides a way to propagate attached properties from parent objects to children. This is especially useful when creating your own style. Fixes: QTBUG-63267 Change-Id: I2f1794dc4a9f2be56fad2f5e5f39e2ab845157fa Reviewed-by: Fabian Kosmale <[email protected]> Reviewed-by: Richard Moe Gustavsen <[email protected]>
-rw-r--r--examples/quickcontrols2/CMakeLists.txt1
-rw-r--r--examples/quickcontrols2/attachedstyleproperties/CMakeLists.txt52
-rw-r--r--examples/quickcontrols2/attachedstyleproperties/MyStyle/ApplicationWindow.qml17
-rw-r--r--examples/quickcontrols2/attachedstyleproperties/MyStyle/Button.qml33
-rw-r--r--examples/quickcontrols2/attachedstyleproperties/MyStyle/CMakeLists.txt47
-rw-r--r--examples/quickcontrols2/attachedstyleproperties/MyStyle/Label.qml11
-rw-r--r--examples/quickcontrols2/attachedstyleproperties/MyStyle/Popup.qml48
-rw-r--r--examples/quickcontrols2/attachedstyleproperties/MyStyle/Switch.qml58
-rw-r--r--examples/quickcontrols2/attachedstyleproperties/MyStyle/ToolBar.qml24
-rw-r--r--examples/quickcontrols2/attachedstyleproperties/MyStyle/mystyle.cpp136
-rw-r--r--examples/quickcontrols2/attachedstyleproperties/MyStyle/mystyle.h76
-rw-r--r--examples/quickcontrols2/attachedstyleproperties/attachedstyleproperties.cpp28
-rw-r--r--examples/quickcontrols2/attachedstyleproperties/attachedstyleproperties.qml110
-rw-r--r--examples/quickcontrols2/attachedstyleproperties/doc/images/qtquickcontrols2-attachedstyleproperties.pngbin0 -> 11703 bytes
-rw-r--r--examples/quickcontrols2/attachedstyleproperties/doc/src/qtquickcontrols2-attachedstyleproperties.qdoc18
-rw-r--r--src/qml/doc/src/cppintegration/definetypes.qdoc8
-rw-r--r--src/quickcontrols2/CMakeLists.txt1
-rw-r--r--src/quickcontrols2/imagine/qquickimaginestyle.cpp8
-rw-r--r--src/quickcontrols2/imagine/qquickimaginestyle_p.h6
-rw-r--r--src/quickcontrols2/ios/qquickiosstyle.cpp4
-rw-r--r--src/quickcontrols2/ios/qquickiosstyle_p.h4
-rw-r--r--src/quickcontrols2/material/qquickmaterialstyle.cpp16
-rw-r--r--src/quickcontrols2/material/qquickmaterialstyle_p.h7
-rw-r--r--src/quickcontrols2/qquickattachedpropertypropagator.cpp380
-rw-r--r--src/quickcontrols2/qquickattachedpropertypropagator.h37
-rw-r--r--src/quickcontrols2/universal/qquickuniversalstyle.cpp14
-rw-r--r--src/quickcontrols2/universal/qquickuniversalstyle_p.h7
-rw-r--r--src/quickcontrols2impl/CMakeLists.txt1
-rw-r--r--src/quickcontrols2impl/qquickattachedobject.cpp243
-rw-r--r--src/quickcontrols2impl/qquickattachedobject_p.h51
-rw-r--r--tests/auto/quickcontrols2/qquickmaterialstyle/data/tst_material.qml222
31 files changed, 1305 insertions, 363 deletions
diff --git a/examples/quickcontrols2/CMakeLists.txt b/examples/quickcontrols2/CMakeLists.txt
index 3473052f68..e4021bf430 100644
--- a/examples/quickcontrols2/CMakeLists.txt
+++ b/examples/quickcontrols2/CMakeLists.txt
@@ -1,6 +1,7 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
+qt_internal_add_example(attachedstyleproperties)
qt_internal_add_example(gallery)
if (TARGET Qt::Sql)
add_subdirectory(chattutorial)
diff --git a/examples/quickcontrols2/attachedstyleproperties/CMakeLists.txt b/examples/quickcontrols2/attachedstyleproperties/CMakeLists.txt
new file mode 100644
index 0000000000..229129f5c6
--- /dev/null
+++ b/examples/quickcontrols2/attachedstyleproperties/CMakeLists.txt
@@ -0,0 +1,52 @@
+cmake_minimum_required(VERSION 3.16)
+project(attachedstyleproperties LANGUAGES CXX)
+
+set(CMAKE_AUTOMOC ON)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/quickcontrols2/attachedstyleproperties")
+
+find_package(Qt6 REQUIRED COMPONENTS Core Gui Qml QuickControls2)
+qt_standard_project_setup()
+
+add_subdirectory(MyStyle)
+
+qt_add_executable(attachedstylepropertiesexample
+ WIN32
+ MACOSX_BUNDLE
+ attachedstyleproperties.cpp
+)
+
+qt_add_qml_module(attachedstylepropertiesexample
+ URI App
+ VERSION 1.0
+ QML_FILES
+ attachedstyleproperties.qml
+ NO_RESOURCE_TARGET_PATH
+)
+
+target_link_libraries(attachedstylepropertiesexample PRIVATE
+ Qt::Core
+ Qt::Gui
+ Qt::Qml
+ Qt::QuickControls2
+)
+
+add_dependencies(attachedstylepropertiesexample MyStyle)
+
+install(TARGETS attachedstylepropertiesexample
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
+
+include(../../quick/shared/QtBundleQmlModuleForMacOS.cmake)
+
+set(app_target "attachedstylepropertiesexample")
+set(qml_plugin_target "MyStyleplugin")
+set(qml_module_uri "MyStyle")
+add_qml_module_to_macos_app_bundle(
+ "${app_target}" "${qml_plugin_target}" "${qml_module_uri}")
diff --git a/examples/quickcontrols2/attachedstyleproperties/MyStyle/ApplicationWindow.qml b/examples/quickcontrols2/attachedstyleproperties/MyStyle/ApplicationWindow.qml
new file mode 100644
index 0000000000..8a7bbc7ed2
--- /dev/null
+++ b/examples/quickcontrols2/attachedstyleproperties/MyStyle/ApplicationWindow.qml
@@ -0,0 +1,17 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Templates as T
+
+import MyStyle
+
+T.ApplicationWindow {
+ color: MyStyle.windowColor
+
+ Behavior on color {
+ ColorAnimation {
+ duration: 150
+ }
+ }
+}
diff --git a/examples/quickcontrols2/attachedstyleproperties/MyStyle/Button.qml b/examples/quickcontrols2/attachedstyleproperties/MyStyle/Button.qml
new file mode 100644
index 0000000000..7eabcb0b35
--- /dev/null
+++ b/examples/quickcontrols2/attachedstyleproperties/MyStyle/Button.qml
@@ -0,0 +1,33 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Templates as T
+
+import MyStyle
+
+T.Button {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ padding: 6
+ horizontalPadding: padding + 2
+ spacing: 6
+
+ contentItem: Text {
+ text: control.text
+ font: control.font
+ color: control.MyStyle.buttonTextColor
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ background: Rectangle {
+ implicitWidth: 60
+ implicitHeight: 40
+ color: control.down ? Qt.darker(control.MyStyle.buttonColor, 1.1) : control.MyStyle.buttonColor
+ }
+}
diff --git a/examples/quickcontrols2/attachedstyleproperties/MyStyle/CMakeLists.txt b/examples/quickcontrols2/attachedstyleproperties/MyStyle/CMakeLists.txt
new file mode 100644
index 0000000000..310670677e
--- /dev/null
+++ b/examples/quickcontrols2/attachedstyleproperties/MyStyle/CMakeLists.txt
@@ -0,0 +1,47 @@
+if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
+ message(FATAL_ERROR "MyStyle should be built as part of the 'attachedstyleproperties' project, and not in isolation.")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/quickcontrols2/attachedstyleproperties")
+
+qt_add_qml_module(MyStyle
+ URI MyStyle
+ VERSION 1.0
+ IMPORTS
+ QtQuick.Controls.Material
+ QML_FILES
+ ApplicationWindow.qml
+ Button.qml
+ Label.qml
+ Popup.qml
+ Switch.qml
+ ToolBar.qml
+ SOURCES
+ mystyle.cpp
+ mystyle.h
+)
+
+include(GenerateExportHeader)
+target_include_directories(MyStyle PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) # find autogenerated header
+generate_export_header(MyStyle)
+
+find_package(Qt6 REQUIRED COMPONENTS Core Gui Qml QuickControls2)
+
+target_link_libraries(MyStyle PRIVATE
+ Qt::Core
+ Qt::Gui
+ Qt::Qml
+ Qt::QuickControls2
+)
+
+message(STATUS "@@@ INSTALL_EXAMPLEDIR ${INSTALL_EXAMPLEDIR}")
+
+install(TARGETS MyStyle
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
+
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/qmldir
+ DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
diff --git a/examples/quickcontrols2/attachedstyleproperties/MyStyle/Label.qml b/examples/quickcontrols2/attachedstyleproperties/MyStyle/Label.qml
new file mode 100644
index 0000000000..3d045aa70e
--- /dev/null
+++ b/examples/quickcontrols2/attachedstyleproperties/MyStyle/Label.qml
@@ -0,0 +1,11 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Templates as T
+
+import MyStyle
+
+T.Label {
+ color: MyStyle.windowTextColor
+}
diff --git a/examples/quickcontrols2/attachedstyleproperties/MyStyle/Popup.qml b/examples/quickcontrols2/attachedstyleproperties/MyStyle/Popup.qml
new file mode 100644
index 0000000000..0f5e753f60
--- /dev/null
+++ b/examples/quickcontrols2/attachedstyleproperties/MyStyle/Popup.qml
@@ -0,0 +1,48 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Templates as T
+import MyStyle
+
+T.Popup {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ padding: 12
+
+ enter: Transition {
+ NumberAnimation {
+ property: "opacity"
+ from: 0.0
+ to: 1.0
+ easing.type: Easing.OutCubic
+ duration: 150
+ }
+ }
+
+ exit: Transition {
+ NumberAnimation {
+ property: "opacity"
+ from: 1.0
+ to: 0.0
+ easing.type: Easing.OutCubic
+ duration: 150
+ }
+ }
+
+ background: Rectangle {
+ radius: 2
+ color: control.MyStyle.popupColor
+ border.color: control.MyStyle.popupBorderColor
+ }
+
+ T.Overlay.modeless: Rectangle {
+ color: control.MyStyle.backgroundDimColor
+ Behavior on opacity { NumberAnimation { duration: 150 } }
+ }
+}
diff --git a/examples/quickcontrols2/attachedstyleproperties/MyStyle/Switch.qml b/examples/quickcontrols2/attachedstyleproperties/MyStyle/Switch.qml
new file mode 100644
index 0000000000..59bda147b7
--- /dev/null
+++ b/examples/quickcontrols2/attachedstyleproperties/MyStyle/Switch.qml
@@ -0,0 +1,58 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Templates as T
+
+import MyStyle
+
+T.Switch {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ padding: 6
+ horizontalPadding: padding + 2
+ spacing: 6
+
+ indicator: Rectangle {
+ implicitWidth: 56
+ implicitHeight: 28
+
+ x: control.text
+ ? (control.mirrored ? control.width - width - control.rightPadding : control.leftPadding)
+ : control.leftPadding + (control.availableWidth - width) / 2
+ y: control.topPadding + (control.availableHeight - height) / 2
+
+ radius: 8
+ color: control.down ? Qt.darker(control.MyStyle.buttonColor, 1.1) : control.MyStyle.buttonColor
+
+ Rectangle {
+ x: Math.max(0, Math.min(parent.width - width, control.visualPosition * parent.width - (width / 2)))
+ y: (parent.height - height) / 2
+ width: 28
+ height: 28
+ radius: 8
+ color: Qt.lighter(control.MyStyle.buttonColor)
+
+ Behavior on x {
+ enabled: !control.down
+ SmoothedAnimation { velocity: 200 }
+ }
+ }
+ }
+
+ contentItem: Text {
+ leftPadding: control.indicator && !control.mirrored ? control.indicator.width + control.spacing : 0
+ rightPadding: control.indicator && control.mirrored ? control.indicator.width + control.spacing : 0
+
+ text: control.text
+ font: control.font
+ color: control.MyStyle.windowTextColor
+ elide: Text.ElideRight
+ verticalAlignment: Text.AlignVCenter
+ }
+}
diff --git a/examples/quickcontrols2/attachedstyleproperties/MyStyle/ToolBar.qml b/examples/quickcontrols2/attachedstyleproperties/MyStyle/ToolBar.qml
new file mode 100644
index 0000000000..b0cd597c87
--- /dev/null
+++ b/examples/quickcontrols2/attachedstyleproperties/MyStyle/ToolBar.qml
@@ -0,0 +1,24 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Templates as T
+
+import MyStyle
+
+T.ToolBar {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ background: Rectangle {
+ implicitHeight: 40
+ // Ensure that we use Control's attached MyStyle object by qualifying
+ // the binding with its id. If we don't do this, an extra, unnecessary
+ // attached MyStyle object will be created for the Rectangle.
+ color: control.MyStyle.toolBarColor
+ }
+}
diff --git a/examples/quickcontrols2/attachedstyleproperties/MyStyle/mystyle.cpp b/examples/quickcontrols2/attachedstyleproperties/MyStyle/mystyle.cpp
new file mode 100644
index 0000000000..40f7af702e
--- /dev/null
+++ b/examples/quickcontrols2/attachedstyleproperties/MyStyle/mystyle.cpp
@@ -0,0 +1,136 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "mystyle.h"
+
+// If no value was inherited from a parent or explicitly set, the "global" values are used.
+static MyStyle::Theme globalTheme = MyStyle::Light;
+
+MyStyle::MyStyle(QObject *parent)
+ : QQuickAttachedPropertyPropagator(parent)
+ , m_theme(globalTheme)
+{
+ // A static function could be called here that reads globalTheme from a
+ // settings file once at startup. That value would override the global
+ // value. This is similar to what the Imagine and Material styles do, for
+ // example.
+
+ initialize();
+}
+
+MyStyle *MyStyle::qmlAttachedProperties(QObject *object)
+{
+ return new MyStyle(object);
+}
+
+MyStyle::Theme MyStyle::theme() const
+{
+ return m_theme;
+}
+
+void MyStyle::setTheme(Theme theme)
+{
+ // When this function is called, we know that the user has explicitly
+ // set a theme on this attached object. We set this to true even if
+ // the effective theme didn't change, because it's important that
+ // the user's specified value is respected (and not inherited from
+ // from the parent).
+ m_explicitTheme = true;
+ if (m_theme == theme)
+ return;
+
+ m_theme = theme;
+ propagateTheme();
+ themeChange();
+
+}
+
+void MyStyle::inheritTheme(Theme theme)
+{
+ if (m_explicitTheme || m_theme == theme)
+ return;
+
+ m_theme = theme;
+ propagateTheme();
+ themeChange();
+}
+
+void MyStyle::propagateTheme()
+{
+ const auto styles = attachedChildren();
+ for (QQuickAttachedPropertyPropagator *child : styles) {
+ MyStyle *myStyle = qobject_cast<MyStyle *>(child);
+ if (myStyle)
+ myStyle->inheritTheme(m_theme);
+ }
+}
+
+void MyStyle::resetTheme()
+{
+ if (!m_explicitTheme)
+ return;
+
+ m_explicitTheme = false;
+ MyStyle *myStyle = qobject_cast<MyStyle *>(attachedParent());
+ inheritTheme(myStyle ? myStyle->theme() : globalTheme);
+}
+
+void MyStyle::themeChange()
+{
+ emit themeChanged();
+ // Emit any other change signals for properties that depend on the theme here...
+}
+
+QColor MyStyle::windowColor() const
+{
+ return m_theme == Light ? QColor::fromRgb(0xf0f0f0) : QColor::fromRgb(0x303030);
+}
+
+QColor MyStyle::windowTextColor() const
+{
+ return m_theme == Light ? QColor::fromRgb(0x5c5c5c) : QColor::fromRgb(0xe0e0e0);
+}
+
+QColor MyStyle::buttonColor() const
+{
+ return m_theme == Light ? QColor::fromRgb(0xc2e1ff) : QColor::fromRgb(0x74bbff);
+}
+
+QColor MyStyle::buttonTextColor() const
+{
+ return m_theme == Light ? QColor::fromRgb(0x5c5c5c) : QColor::fromRgb(0xffffff);
+}
+
+QColor MyStyle::toolBarColor() const
+{
+ return m_theme == Light ? QColor::fromRgb(0x4da6ff) : QColor::fromRgb(0x0066cc);
+}
+
+QColor MyStyle::popupColor() const
+{
+// const QColor winColor = windowColor();
+// return m_theme == Light ? winColor.darker(120) : winColor.lighter(120);
+ return windowColor().lighter(120);
+}
+
+QColor MyStyle::popupBorderColor() const
+{
+ const QColor winColor = windowColor();
+ return m_theme == Light ? winColor.darker(140) : winColor.lighter(140);
+}
+
+QColor MyStyle::backgroundDimColor() const
+{
+ const QColor winColor = windowColor().darker();
+ return QColor::fromRgb(winColor.red(), winColor.green(), winColor.blue(), 100);
+}
+
+void MyStyle::attachedParentChange(QQuickAttachedPropertyPropagator *newParent, QQuickAttachedPropertyPropagator *oldParent)
+{
+ Q_UNUSED(oldParent);
+ MyStyle *attachedParentStyle = qobject_cast<MyStyle *>(newParent);
+ if (attachedParentStyle) {
+ inheritTheme(attachedParentStyle->theme());
+ // Do any other inheriting here...
+ }
+}
diff --git a/examples/quickcontrols2/attachedstyleproperties/MyStyle/mystyle.h b/examples/quickcontrols2/attachedstyleproperties/MyStyle/mystyle.h
new file mode 100644
index 0000000000..da87ab4718
--- /dev/null
+++ b/examples/quickcontrols2/attachedstyleproperties/MyStyle/mystyle.h
@@ -0,0 +1,76 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef MYSTYLE_H
+#define MYSTYLE_H
+
+#include <QColor>
+#include <QQmlEngine>
+#include <QQuickAttachedPropertyPropagator>
+
+#include "mystyle_export.h"
+
+class MYSTYLE_EXPORT MyStyle : public QQuickAttachedPropertyPropagator
+{
+ Q_OBJECT
+ // Provide a RESET function in order to allow an item to set MyStyle.theme to undefined
+ // in order to use its parent's (or global) theme after one was explicitly set on it.
+ Q_PROPERTY(Theme theme READ theme WRITE setTheme RESET resetTheme NOTIFY themeChanged FINAL)
+ // As the values of these properties only depend on the theme, they can all use the theme
+ // property's change signal.
+ Q_PROPERTY(QColor windowColor READ windowColor NOTIFY themeChanged FINAL)
+ Q_PROPERTY(QColor windowTextColor READ windowTextColor NOTIFY themeChanged FINAL)
+ Q_PROPERTY(QColor buttonColor READ buttonColor NOTIFY themeChanged FINAL)
+ Q_PROPERTY(QColor buttonTextColor READ buttonTextColor NOTIFY themeChanged FINAL)
+ Q_PROPERTY(QColor toolBarColor READ toolBarColor NOTIFY themeChanged FINAL)
+ Q_PROPERTY(QColor popupColor READ popupColor NOTIFY themeChanged FINAL)
+ Q_PROPERTY(QColor popupBorderColor READ popupBorderColor NOTIFY themeChanged FINAL)
+ Q_PROPERTY(QColor backgroundDimColor READ backgroundDimColor NOTIFY themeChanged FINAL)
+
+ QML_ELEMENT
+ QML_ATTACHED(MyStyle)
+ QML_UNCREATABLE("")
+ QML_ADDED_IN_VERSION(1, 0)
+
+public:
+ enum Theme {
+ Light,
+ Dark
+ };
+
+ Q_ENUM(Theme)
+
+ explicit MyStyle(QObject *parent = nullptr);
+
+ static MyStyle *qmlAttachedProperties(QObject *object);
+
+ Theme theme() const;
+ void setTheme(Theme theme);
+ void inheritTheme(Theme theme);
+ void propagateTheme();
+ void resetTheme();
+ void themeChange();
+
+ QColor windowColor() const;
+ QColor windowTextColor() const;
+ QColor buttonColor() const;
+ QColor buttonTextColor() const;
+ QColor toolBarColor() const;
+ QColor popupColor() const;
+ QColor popupBorderColor() const;
+ QColor backgroundDimColor() const;
+
+Q_SIGNALS:
+ void themeChanged();
+
+protected:
+ void attachedParentChange(QQuickAttachedPropertyPropagator *newParent, QQuickAttachedPropertyPropagator *oldParent) override;
+
+private:
+ // Whether a color value was explicitly set on the specific object that this attached style object represents.
+ bool m_explicitTheme = false;
+ // The actual values for this item, whether explicit, inherited or globally set.
+ Theme m_theme = Light;
+};
+
+#endif // MYSTYLE_H
diff --git a/examples/quickcontrols2/attachedstyleproperties/attachedstyleproperties.cpp b/examples/quickcontrols2/attachedstyleproperties/attachedstyleproperties.cpp
new file mode 100644
index 0000000000..376e53c055
--- /dev/null
+++ b/examples/quickcontrols2/attachedstyleproperties/attachedstyleproperties.cpp
@@ -0,0 +1,28 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include <QGuiApplication>
+#include <QQmlApplicationEngine>
+#include <QDir>
+
+int main(int argc, char *argv[])
+{
+ QGuiApplication app(argc, argv);
+ app.setOrganizationName("QtProject");
+ app.setOrganizationDomain("qt-project.org");
+ app.setApplicationName("Attached Objects");
+
+ QQmlApplicationEngine engine;
+#ifdef Q_OS_MACOS
+ engine.addImportPath(app.applicationDirPath() + "/../PlugIns");
+#endif
+ const QUrl url(QStringLiteral("qrc:/attachedstyleproperties.qml"));
+ QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
+ &app, [url](QObject *obj, const QUrl &objUrl) {
+ if (!obj && url == objUrl)
+ QCoreApplication::exit(-1);
+ }, Qt::QueuedConnection);
+ engine.load(url);
+
+ return app.exec();
+}
diff --git a/examples/quickcontrols2/attachedstyleproperties/attachedstyleproperties.qml b/examples/quickcontrols2/attachedstyleproperties/attachedstyleproperties.qml
new file mode 100644
index 0000000000..e08e19801f
--- /dev/null
+++ b/examples/quickcontrols2/attachedstyleproperties/attachedstyleproperties.qml
@@ -0,0 +1,110 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Layouts
+
+import MyStyle
+
+ApplicationWindow {
+ width: 800
+ height: 600
+ title: qsTr("Attached Objects")
+ visible: true
+
+ MyStyle.theme: darkModeSwitch.checked ? MyStyle.Dark : MyStyle.Light
+
+ header: ToolBar {
+ MyStyle.theme: MyStyle.Dark
+
+ RowLayout {
+ anchors.fill: parent
+ anchors.leftMargin: 12
+
+ Label {
+ text: qsTr("This is a Label in a ToolBar")
+ }
+
+ Item {
+ Layout.fillWidth: true
+ }
+
+ Switch {
+ id: darkModeSwitch
+ text: qsTr("Dark mode")
+ }
+ }
+ }
+
+ ColumnLayout {
+ anchors.centerIn: parent
+ spacing: 20
+
+ Label {
+ text: qsTr("This is a Label in an ApplicationWindow")
+ Layout.alignment: Qt.AlignHCenter
+ }
+
+ RowLayout {
+ Button {
+ text: qsTr("Open Popup")
+ onClicked: popup.open()
+ }
+
+ Button {
+ text: qsTr("Open Window")
+ onClicked: {
+ if (!childWindow.active)
+ childWindow.show()
+ else
+ childWindow.raise()
+ }
+ }
+ }
+ }
+
+ Popup {
+ id: popup
+ dim: true
+ anchors.centerIn: parent
+
+ ColumnLayout {
+ anchors.centerIn: parent
+ spacing: 20
+
+ Label {
+ text: qsTr("This is a Label in a Popup")
+ Layout.alignment: Qt.AlignHCenter
+ }
+
+ Button {
+ text: qsTr("Close Popup")
+ Layout.alignment: Qt.AlignHCenter
+ onClicked: popup.close()
+ }
+ }
+ }
+
+ ApplicationWindow {
+ id: childWindow
+ width: 600
+ height: 400
+ title: qsTr("Attached Objects - Child Window")
+
+ ColumnLayout {
+ anchors.centerIn: parent
+ spacing: 20
+
+ Label {
+ text: qsTr("This is a Label in a child ApplicationWindow")
+ Layout.alignment: Qt.AlignHCenter
+ }
+
+ Button {
+ text: qsTr("Close Window")
+ Layout.alignment: Qt.AlignHCenter
+ onClicked: childWindow.close()
+ }
+ }
+ }
+}
diff --git a/examples/quickcontrols2/attachedstyleproperties/doc/images/qtquickcontrols2-attachedstyleproperties.png b/examples/quickcontrols2/attachedstyleproperties/doc/images/qtquickcontrols2-attachedstyleproperties.png
new file mode 100644
index 0000000000..2cd5f214f7
--- /dev/null
+++ b/examples/quickcontrols2/attachedstyleproperties/doc/images/qtquickcontrols2-attachedstyleproperties.png
Binary files differ
diff --git a/examples/quickcontrols2/attachedstyleproperties/doc/src/qtquickcontrols2-attachedstyleproperties.qdoc b/examples/quickcontrols2/attachedstyleproperties/doc/src/qtquickcontrols2-attachedstyleproperties.qdoc
new file mode 100644
index 0000000000..de43fc80bd
--- /dev/null
+++ b/examples/quickcontrols2/attachedstyleproperties/doc/src/qtquickcontrols2-attachedstyleproperties.qdoc
@@ -0,0 +1,18 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \example attachedstyleproperties
+ \keyword Qt Quick Controls - Attached Style Properties Example
+ \title Qt Quick Controls - Attached Style Properties Example
+ \ingroup qtquickcontrols2-examples
+ \brief Demonstrates use of QQuickAttachedPropertyPropagator.
+
+ \image qtquickcontrols2-attachedstyleproperties.png
+
+ The Attached Style Properties example is a simple application that shows
+ how to use \l QQuickAttachedPropertyPropagator to propagate attached
+ property values to child objects.
+
+ \include examples-run.qdocinc
+*/
diff --git a/src/qml/doc/src/cppintegration/definetypes.qdoc b/src/qml/doc/src/cppintegration/definetypes.qdoc
index 5799fda87e..e6a6dbfe36 100644
--- a/src/qml/doc/src/cppintegration/definetypes.qdoc
+++ b/src/qml/doc/src/cppintegration/definetypes.qdoc
@@ -595,6 +595,14 @@ qDebug() << "Value of MessageBoard.expired:" << attached->expired();
\endcode
+\section3 Propagating Attached Properties
+
+\l QQuickAttachedPropertyPropagator can be subclassed to propagate attached properties
+from a parent object to its children, similar to \l {Control::}{font} and
+\l {Item::}{palette} propagation. It supports propagation through
+\l {Item}{items}, \l {Popup}{popups}, and \l {Window}{windows}.
+
+
\section2 Property Modifier Types
A property modifier type is a special kind of QML object type. A property
diff --git a/src/quickcontrols2/CMakeLists.txt b/src/quickcontrols2/CMakeLists.txt
index 65dbf409b3..24a2ca8ca2 100644
--- a/src/quickcontrols2/CMakeLists.txt
+++ b/src/quickcontrols2/CMakeLists.txt
@@ -27,6 +27,7 @@ qt_internal_add_qml_module(QuickControls2
NO_PLUGIN_OPTIONAL
NO_GENERATE_PLUGIN_SOURCE
SOURCES
+ qquickattachedpropertypropagator.cpp qquickattachedpropertypropagator.h
qquickstyle.cpp qquickstyle.h qquickstyle_p.h
qquickstyleplugin.cpp qquickstyleplugin_p.h
qtquickcontrols2global.h
diff --git a/src/quickcontrols2/imagine/qquickimaginestyle.cpp b/src/quickcontrols2/imagine/qquickimaginestyle.cpp
index e3270cec49..377103e2f2 100644
--- a/src/quickcontrols2/imagine/qquickimaginestyle.cpp
+++ b/src/quickcontrols2/imagine/qquickimaginestyle.cpp
@@ -17,7 +17,7 @@ static QString ensureSlash(const QString &path)
}
QQuickImagineStyle::QQuickImagineStyle(QObject *parent)
- : QQuickAttachedObject(parent),
+ : QQuickAttachedPropertyPropagator(parent),
m_path(*GlobalPath())
{
init();
@@ -58,7 +58,7 @@ void QQuickImagineStyle::inheritPath(const QString &path)
void QQuickImagineStyle::propagatePath()
{
const auto styles = attachedChildren();
- for (QQuickAttachedObject *child : styles) {
+ for (QQuickAttachedPropertyPropagator *child : styles) {
QQuickImagineStyle *imagine = qobject_cast<QQuickImagineStyle *>(child);
if (imagine)
imagine->inheritPath(m_path);
@@ -98,7 +98,7 @@ QUrl QQuickImagineStyle::url() const
return QUrl::fromLocalFile(path);
}
-void QQuickImagineStyle::attachedParentChange(QQuickAttachedObject *newParent, QQuickAttachedObject *oldParent)
+void QQuickImagineStyle::attachedParentChange(QQuickAttachedPropertyPropagator *newParent, QQuickAttachedPropertyPropagator *oldParent)
{
Q_UNUSED(oldParent);
QQuickImagineStyle *imagine = qobject_cast<QQuickImagineStyle *>(newParent);
@@ -129,7 +129,7 @@ void QQuickImagineStyle::init()
globalsInitialized = true;
}
- QQuickAttachedObject::init(); // TODO: lazy init?
+ QQuickAttachedPropertyPropagator::initialize(); // TODO: lazy init?
}
QT_END_NAMESPACE
diff --git a/src/quickcontrols2/imagine/qquickimaginestyle_p.h b/src/quickcontrols2/imagine/qquickimaginestyle_p.h
index 738577080f..81f17fb58c 100644
--- a/src/quickcontrols2/imagine/qquickimaginestyle_p.h
+++ b/src/quickcontrols2/imagine/qquickimaginestyle_p.h
@@ -17,11 +17,11 @@
#include <QtCore/qvariant.h>
#include <QtQml/qqml.h>
-#include <QtQuickControls2Impl/private/qquickattachedobject_p.h>
+#include <QtQuickControls2/qquickattachedpropertypropagator.h>
QT_BEGIN_NAMESPACE
-class QQuickImagineStyle : public QQuickAttachedObject
+class QQuickImagineStyle : public QQuickAttachedPropertyPropagator
{
Q_OBJECT
Q_PROPERTY(QString path READ path WRITE setPath RESET resetPath NOTIFY pathChanged FINAL)
@@ -48,7 +48,7 @@ Q_SIGNALS:
void pathChanged();
protected:
- void attachedParentChange(QQuickAttachedObject *newParent, QQuickAttachedObject *oldParent) override;
+ void attachedParentChange(QQuickAttachedPropertyPropagator *newParent, QQuickAttachedPropertyPropagator *oldParent) override;
private:
void init();
diff --git a/src/quickcontrols2/ios/qquickiosstyle.cpp b/src/quickcontrols2/ios/qquickiosstyle.cpp
index f773833f00..74338d370c 100644
--- a/src/quickcontrols2/ios/qquickiosstyle.cpp
+++ b/src/quickcontrols2/ios/qquickiosstyle.cpp
@@ -18,7 +18,7 @@ static QQuickIOSStyle::Theme qquickios_effective_theme()
}
QQuickIOSStyle::QQuickIOSStyle(QObject *parent)
- : QQuickAttachedObject(parent)
+ : QQuickAttachedPropertyPropagator(parent)
{
init();
m_theme = qquickios_effective_theme();
@@ -41,7 +41,7 @@ void QQuickIOSStyle::init()
// QSharedPointer<QSettings> settings = QQuickStylePrivate::settings(QStringLiteral("iOS"));
// globalsInitialized = true;
// }
- QQuickAttachedObject::init(); // TODO: lazy init?
+ QQuickAttachedPropertyPropagator::initialize(); // TODO: lazy init?
}
QQuickIOSStyle::Theme QQuickIOSStyle::theme() const
diff --git a/src/quickcontrols2/ios/qquickiosstyle_p.h b/src/quickcontrols2/ios/qquickiosstyle_p.h
index 49e5dde0a1..b71d9b0f86 100644
--- a/src/quickcontrols2/ios/qquickiosstyle_p.h
+++ b/src/quickcontrols2/ios/qquickiosstyle_p.h
@@ -17,11 +17,11 @@
#include <QtCore/qvariant.h>
#include <QtQml/qqml.h>
-#include <QtQuickControls2Impl/private/qquickattachedobject_p.h>
+#include <QtQuickControls2/qquickattachedpropertypropagator.h>
QT_BEGIN_NAMESPACE
-class QQuickIOSStyle : public QQuickAttachedObject
+class QQuickIOSStyle : public QQuickAttachedPropertyPropagator
{
Q_OBJECT
Q_PROPERTY(QUrl url READ url CONSTANT)
diff --git a/src/quickcontrols2/material/qquickmaterialstyle.cpp b/src/quickcontrols2/material/qquickmaterialstyle.cpp
index b4c782f023..9114462828 100644
--- a/src/quickcontrols2/material/qquickmaterialstyle.cpp
+++ b/src/quickcontrols2/material/qquickmaterialstyle.cpp
@@ -399,7 +399,7 @@ static QQuickMaterialStyle::Theme effectiveTheme(QQuickMaterialStyle::Theme them
return theme;
}
-QQuickMaterialStyle::QQuickMaterialStyle(QObject *parent) : QQuickAttachedObject(parent),
+QQuickMaterialStyle::QQuickMaterialStyle(QObject *parent) : QQuickAttachedPropertyPropagator(parent),
m_customPrimary(globalPrimaryCustom),
m_customAccent(globalAccentCustom),
m_customForeground(globalForegroundCustom),
@@ -412,7 +412,7 @@ QQuickMaterialStyle::QQuickMaterialStyle(QObject *parent) : QQuickAttachedObject
m_foreground(globalForeground),
m_background(globalBackground)
{
- QQuickAttachedObject::init();
+ QQuickAttachedPropertyPropagator::initialize();
}
QQuickMaterialStyle *QQuickMaterialStyle::qmlAttachedProperties(QObject *object)
@@ -464,7 +464,7 @@ void QQuickMaterialStyle::inheritTheme(Theme theme)
void QQuickMaterialStyle::propagateTheme()
{
const auto styles = attachedChildren();
- for (QQuickAttachedObject *child : styles) {
+ for (QQuickAttachedPropertyPropagator *child : styles) {
QQuickMaterialStyle *material = qobject_cast<QQuickMaterialStyle *>(child);
if (material)
material->inheritTheme(m_theme);
@@ -530,7 +530,7 @@ void QQuickMaterialStyle::inheritPrimary(uint primary, bool custom)
void QQuickMaterialStyle::propagatePrimary()
{
const auto styles = attachedChildren();
- for (QQuickAttachedObject *child : styles) {
+ for (QQuickAttachedPropertyPropagator *child : styles) {
QQuickMaterialStyle *material = qobject_cast<QQuickMaterialStyle *>(child);
if (material)
material->inheritPrimary(m_primary, m_customPrimary);
@@ -594,7 +594,7 @@ void QQuickMaterialStyle::inheritAccent(uint accent, bool custom)
void QQuickMaterialStyle::propagateAccent()
{
const auto styles = attachedChildren();
- for (QQuickAttachedObject *child : styles) {
+ for (QQuickAttachedPropertyPropagator *child : styles) {
QQuickMaterialStyle *material = qobject_cast<QQuickMaterialStyle *>(child);
if (material)
material->inheritAccent(m_accent, m_customAccent);
@@ -666,7 +666,7 @@ void QQuickMaterialStyle::inheritForeground(uint foreground, bool custom, bool h
void QQuickMaterialStyle::propagateForeground()
{
const auto styles = attachedChildren();
- for (QQuickAttachedObject *child : styles) {
+ for (QQuickAttachedPropertyPropagator *child : styles) {
QQuickMaterialStyle *material = qobject_cast<QQuickMaterialStyle *>(child);
if (material)
material->inheritForeground(m_foreground, m_customForeground, m_hasForeground);
@@ -731,7 +731,7 @@ void QQuickMaterialStyle::inheritBackground(uint background, bool custom, bool h
void QQuickMaterialStyle::propagateBackground()
{
const auto styles = attachedChildren();
- for (QQuickAttachedObject *child : styles) {
+ for (QQuickAttachedPropertyPropagator *child : styles) {
QQuickMaterialStyle *material = qobject_cast<QQuickMaterialStyle *>(child);
if (material)
material->inheritBackground(m_background, m_customBackground, m_hasBackground);
@@ -1319,7 +1319,7 @@ void QQuickMaterialStyle::initGlobals()
}
}
-void QQuickMaterialStyle::attachedParentChange(QQuickAttachedObject *newParent, QQuickAttachedObject *oldParent)
+void QQuickMaterialStyle::attachedParentChange(QQuickAttachedPropertyPropagator *newParent, QQuickAttachedPropertyPropagator *oldParent)
{
Q_UNUSED(oldParent);
QQuickMaterialStyle *material = qobject_cast<QQuickMaterialStyle *>(newParent);
diff --git a/src/quickcontrols2/material/qquickmaterialstyle_p.h b/src/quickcontrols2/material/qquickmaterialstyle_p.h
index 5c009b124b..99344a6192 100644
--- a/src/quickcontrols2/material/qquickmaterialstyle_p.h
+++ b/src/quickcontrols2/material/qquickmaterialstyle_p.h
@@ -16,11 +16,12 @@
//
#include <QtGui/qcolor.h>
-#include <QtQuickControls2Impl/private/qquickattachedobject_p.h>
+#include <QtQml/qqml.h>
+#include <QtQuickControls2/qquickattachedpropertypropagator.h>
QT_BEGIN_NAMESPACE
-class QQuickMaterialStyle : public QQuickAttachedObject
+class QQuickMaterialStyle : public QQuickAttachedPropertyPropagator
{
Q_OBJECT
Q_PROPERTY(Theme theme READ theme WRITE setTheme RESET resetTheme NOTIFY themeChanged FINAL)
@@ -256,7 +257,7 @@ Q_SIGNALS:
void toolTextColorChanged();
protected:
- void attachedParentChange(QQuickAttachedObject *newParent, QQuickAttachedObject *oldParent) override;
+ void attachedParentChange(QQuickAttachedPropertyPropagator *newParent, QQuickAttachedPropertyPropagator *oldParent) override;
private:
void init();
diff --git a/src/quickcontrols2/qquickattachedpropertypropagator.cpp b/src/quickcontrols2/qquickattachedpropertypropagator.cpp
new file mode 100644
index 0000000000..07bcb93d7f
--- /dev/null
+++ b/src/quickcontrols2/qquickattachedpropertypropagator.cpp
@@ -0,0 +1,380 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qquickattachedpropertypropagator.h"
+
+#include <QtCore/qpointer.h>
+#include <QtQuick/qquickwindow.h>
+#include <QtQuick/private/qquickitem_p.h>
+#include <QtQuick/private/qquickitemchangelistener_p.h>
+#include <QtQuickTemplates2/private/qquickpopup_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QQuickAttachedPropertyPropagator
+ \brief The QQuickAttachedPropertyPropagator class provides a way to
+ propagate attached properties.
+ \inmodule QtQuickControls2
+ \since 6.5
+
+ In QML, it is possible to
+ \l {Attached Properties and Attached Signal Handlers}{attach properties and
+ signal handlers} to objects. \l {Providing Attached Properties} goes into more
+ detail about how to expose your own C++ attached types.
+
+ QQuickAttachedPropertyPropagator provides an API to propagate attached
+ properties from a parent object to its children, similar to
+ \l {Control::}{font} and \l {Item::}{palette} propagation. It supports
+ propagation through \l {Item}{items}, \l {Popup}{popups}, and
+ \l {Window}{windows}.
+
+ If propagation of properties is not important, consider using a
+ \l {QML_SINGLETON}{C++} or
+ \l {Contents of a Module Definition qmldir File}{QML} singleton instead,
+ as it is better suited for that use case, and is more efficient in that
+ it only requires one QObject.
+
+ To use QQuickAttachedPropertyPropagator:
+ \list
+ \li Derive from it
+ \li Call \l initialize() in the constructor
+ \li Define set/inherit/propagate/reset functions for each property as needed
+ \li Reimplement \l attachedParentChange() to handle property inheritance
+ \endlist
+
+ For an example that demonstrates this in depth, see
+ \l {Qt Quick Controls - Attached Style Properties Example}.
+
+ \sa {Styling Qt Quick Controls}
+*/
+
+static QQuickAttachedPropertyPropagator *attachedObject(const QMetaObject *type, QObject *object, bool create = false)
+{
+ if (!object)
+ return nullptr;
+ auto func = qmlAttachedPropertiesFunction(object, type);
+ return qobject_cast<QQuickAttachedPropertyPropagator *>(qmlAttachedPropertiesObject(object, func, create));
+}
+
+/*!
+ \internal
+
+ Tries to find a QQuickAttachedPropertyPropagator whose type is \a ourAttachedType
+ and is attached to an ancestor of \a objectWeAreAttachedTo.
+
+ QQuickAttachedPropertyPropagator needs to know who its parent attached object is in
+ order to inherit attached property values from it. This is called when an
+ instance of QQuickAttachedPropertyPropagator is created, and whenever
+ \c {objectWeAreAttachedTo}'s parent changes, for example.
+*/
+static QQuickAttachedPropertyPropagator *findAttachedParent(const QMetaObject *ourAttachedType, QObject *objectWeAreAttachedTo)
+{
+ QQuickItem *item = qobject_cast<QQuickItem *>(objectWeAreAttachedTo);
+ if (item) {
+ // lookup parent items and popups
+ QQuickItem *parent = item->parentItem();
+ while (parent) {
+ QQuickAttachedPropertyPropagator *attached = attachedObject(ourAttachedType, parent);
+ if (attached)
+ return attached;
+
+ QQuickPopup *popup = qobject_cast<QQuickPopup *>(parent->parent());
+ if (popup)
+ return attachedObject(ourAttachedType, popup);
+
+ parent = parent->parentItem();
+ }
+
+ // fallback to item's window
+ QQuickAttachedPropertyPropagator *attached = attachedObject(ourAttachedType, item->window());
+ if (attached)
+ return attached;
+ } else {
+ // lookup popup's window
+ QQuickPopup *popup = qobject_cast<QQuickPopup *>(objectWeAreAttachedTo);
+ if (popup)
+ return attachedObject(ourAttachedType, popup->popupItem()->window());
+ }
+
+ // lookup parent window
+ QQuickWindow *window = qobject_cast<QQuickWindow *>(objectWeAreAttachedTo);
+ if (window) {
+ // It doesn't seem like a parent window can be anything but transient in Qt Quick.
+ QQuickWindow *parentWindow = qobject_cast<QQuickWindow *>(window->transientParent());
+ if (parentWindow) {
+ QQuickAttachedPropertyPropagator *attached = attachedObject(ourAttachedType, parentWindow);
+ if (attached)
+ return attached;
+ }
+ }
+
+ // fallback to engine (global)
+ if (objectWeAreAttachedTo) {
+ QQmlEngine *engine = qmlEngine(objectWeAreAttachedTo);
+ if (engine) {
+ QByteArray name = QByteArray("_q_") + ourAttachedType->className();
+ QQuickAttachedPropertyPropagator *attached = engine->property(name).value<QQuickAttachedPropertyPropagator *>();
+ if (!attached) {
+ attached = attachedObject(ourAttachedType, engine, true);
+ engine->setProperty(name, QVariant::fromValue(attached));
+ }
+ return attached;
+ }
+ }
+
+ return nullptr;
+}
+
+static QList<QQuickAttachedPropertyPropagator *> findAttachedChildren(const QMetaObject *type, QObject *object)
+{
+ QList<QQuickAttachedPropertyPropagator *> children;
+
+ QQuickItem *item = qobject_cast<QQuickItem *>(object);
+ if (!item) {
+ QQuickWindow *window = qobject_cast<QQuickWindow *>(object);
+ if (window)
+ item = window->contentItem();
+ }
+
+ if (!item)
+ return children;
+
+ // At this point, "item" could either be an item that the attached object is
+ // attached to directly, or the contentItem of a window that the attached object
+ // is attached to.
+
+ // Look for attached properties on items.
+ const auto childItems = item->childItems();
+ for (QQuickItem *child : childItems) {
+ QQuickAttachedPropertyPropagator *attached = attachedObject(type, child);
+ if (attached)
+ children += attached;
+ else
+ children += findAttachedChildren(type, child);
+ }
+
+ // Look for attached properties on windows. Windows declared in QML
+ // as children of a Window are QObject-parented to the contentItem (see
+ // QQuickWindowPrivate::data_append()). Windows declared as children
+ // of items are QObject-parented to those items.
+ const auto &windowChildren = item->children();
+ for (QObject *child : windowChildren) {
+ QQuickWindow *childWindow = qobject_cast<QQuickWindow *>(child);
+ if (childWindow) {
+ QQuickAttachedPropertyPropagator *attached = attachedObject(type, childWindow);
+ if (attached)
+ children += attached;
+ }
+ }
+
+ return children;
+}
+
+static QQuickItem *findAttachedItem(QObject *parent)
+{
+ QQuickItem *item = qobject_cast<QQuickItem *>(parent);
+ if (!item) {
+ QQuickPopup *popup = qobject_cast<QQuickPopup *>(parent);
+ if (popup)
+ item = popup->popupItem();
+ }
+ return item;
+}
+
+class QQuickAttachedPropertyPropagatorPrivate : public QObjectPrivate, public QQuickItemChangeListener
+{
+public:
+ Q_DECLARE_PUBLIC(QQuickAttachedPropertyPropagator)
+
+ static QQuickAttachedPropertyPropagatorPrivate *get(QQuickAttachedPropertyPropagator *attachedObject)
+ {
+ return attachedObject->d_func();
+ }
+
+ void attachTo(QObject *object);
+ void detachFrom(QObject *object);
+ void setAttachedParent(QQuickAttachedPropertyPropagator *parent);
+
+ void itemWindowChanged(QQuickWindow *window);
+ void itemParentChanged(QQuickItem *item, QQuickItem *parent) override;
+
+ QList<QQuickAttachedPropertyPropagator *> attachedChildren;
+ QPointer<QQuickAttachedPropertyPropagator> attachedParent;
+};
+
+void QQuickAttachedPropertyPropagatorPrivate::attachTo(QObject *object)
+{
+ QQuickItem *item = findAttachedItem(object);
+ if (item) {
+ connect(item, &QQuickItem::windowChanged, this, &QQuickAttachedPropertyPropagatorPrivate::itemWindowChanged);
+ QQuickItemPrivate::get(item)->addItemChangeListener(this, QQuickItemPrivate::Parent);
+ }
+}
+
+void QQuickAttachedPropertyPropagatorPrivate::detachFrom(QObject *object)
+{
+ QQuickItem *item = findAttachedItem(object);
+ if (item) {
+ disconnect(item, &QQuickItem::windowChanged, this, &QQuickAttachedPropertyPropagatorPrivate::itemWindowChanged);
+ QQuickItemPrivate::get(item)->removeItemChangeListener(this, QQuickItemPrivate::Parent);
+ }
+}
+
+/*!
+ \internal
+
+ This function sets the attached parent of this attached object.
+
+ Currently it is called when:
+ \list
+ \li The target item's parent changes.
+ \li The target item's window changes.
+ \li The attached object is constructed, to set the attached parent
+ and the attached parent of the attached object children.
+ \li The attached object is destructed.
+ \endlist
+
+ \quotefromfile ../../examples/quickcontrols2/attachedstyleproperties/MyStyle/mystyle.cpp
+ \skipto MyStyle::resetTheme
+ \printuntil }
+*/
+void QQuickAttachedPropertyPropagatorPrivate::setAttachedParent(QQuickAttachedPropertyPropagator *parent)
+{
+ Q_Q(QQuickAttachedPropertyPropagator);
+ if (attachedParent == parent)
+ return;
+
+ QQuickAttachedPropertyPropagator *oldParent = attachedParent;
+ if (attachedParent)
+ QQuickAttachedPropertyPropagatorPrivate::get(attachedParent)->attachedChildren.removeOne(q);
+ attachedParent = parent;
+ if (parent)
+ QQuickAttachedPropertyPropagatorPrivate::get(parent)->attachedChildren.append(q);
+ q->attachedParentChange(parent, oldParent);
+}
+
+void QQuickAttachedPropertyPropagatorPrivate::itemWindowChanged(QQuickWindow *window)
+{
+ Q_Q(QQuickAttachedPropertyPropagator);
+ QQuickAttachedPropertyPropagator *attachedParent = nullptr;
+ QQuickItem *item = qobject_cast<QQuickItem *>(q->sender());
+ if (item)
+ attachedParent = findAttachedParent(q->metaObject(), item);
+ if (!attachedParent)
+ attachedParent = attachedObject(q->metaObject(), window);
+ setAttachedParent(attachedParent);
+}
+
+void QQuickAttachedPropertyPropagatorPrivate::itemParentChanged(QQuickItem *item, QQuickItem *parent)
+{
+ Q_Q(QQuickAttachedPropertyPropagator);
+ Q_UNUSED(parent);
+ setAttachedParent(findAttachedParent(q->metaObject(), item));
+}
+
+/*!
+ Constructs a QQuickAttachedPropertyPropagator with the given \a parent.
+
+ The \c parent will be used to find this object's
+ \l {attachedParent()}{attached parent}.
+
+ Derived classes should call \l initialize() in their constructor.
+*/
+QQuickAttachedPropertyPropagator::QQuickAttachedPropertyPropagator(QObject *parent)
+ : QObject(*(new QQuickAttachedPropertyPropagatorPrivate), parent)
+{
+ Q_D(QQuickAttachedPropertyPropagator);
+ d->attachTo(parent);
+}
+
+/*!
+ Destroys the QQuickAttachedPropertyPropagator.
+*/
+QQuickAttachedPropertyPropagator::~QQuickAttachedPropertyPropagator()
+{
+ Q_D(QQuickAttachedPropertyPropagator);
+ d->detachFrom(parent());
+ d->setAttachedParent(nullptr);
+}
+
+/*!
+ This function returns the attached children of this attached object.
+
+ The attached children are used when propagating property values:
+
+ \quotefromfile ../../examples/quickcontrols2/attachedstyleproperties/MyStyle/mystyle.cpp
+ \skipto MyStyle::propagateTheme
+ \printuntil }
+ \printuntil }
+*/
+QList<QQuickAttachedPropertyPropagator *> QQuickAttachedPropertyPropagator::attachedChildren() const
+{
+ Q_D(const QQuickAttachedPropertyPropagator);
+ return d->attachedChildren;
+}
+
+/*!
+ This function returns the attached parent of this attached object.
+
+ The attached parent is used when inheriting property values:
+
+ \quotefromfile ../../examples/quickcontrols2/attachedstyleproperties/MyStyle/mystyle.cpp
+ \skipto MyStyle::resetTheme
+ \printuntil }
+*/
+QQuickAttachedPropertyPropagator *QQuickAttachedPropertyPropagator::attachedParent() const
+{
+ Q_D(const QQuickAttachedPropertyPropagator);
+ return d->attachedParent;
+}
+
+/*!
+ Finds and sets the attached parent for this attached object, and then does
+ the same for its children. This must be called upon construction of the
+ attached object in order for propagation to work.
+
+ It can be useful to read global/default values before calling this
+ function. For example, before calling \c initialize(), the
+ \l {Imagine Style}{Imagine} style checks a static "globalsInitialized" flag
+ to see if it should read default values from \l QSettings. The values from
+ that file form the basis for any attached property values that have not
+ been explicitly set.
+
+ \quotefromfile ../../examples/quickcontrols2/attachedstyleproperties/MyStyle/mystyle.cpp
+ \skipto MyStyle::MyStyle
+ \printuntil }
+*/
+void QQuickAttachedPropertyPropagator::initialize()
+{
+ Q_D(QQuickAttachedPropertyPropagator);
+ QQuickAttachedPropertyPropagator *attachedParent = findAttachedParent(metaObject(), parent());
+ if (attachedParent)
+ d->setAttachedParent(attachedParent);
+
+ const QList<QQuickAttachedPropertyPropagator *> attachedChildren = findAttachedChildren(metaObject(), parent());
+ for (QQuickAttachedPropertyPropagator *child : attachedChildren)
+ QQuickAttachedPropertyPropagatorPrivate::get(child)->setAttachedParent(this);
+}
+
+/*!
+ This function is called whenever the attached parent of this
+ QQuickAttachedPropertyPropagator changes from \a oldParent to \a newParent.
+
+ Subclasses should reimplement this function to inherit attached properties
+ from \c newParent.
+
+ \quotefromfile ../../examples/quickcontrols2/attachedstyleproperties/MyStyle/mystyle.cpp
+ \skipto attachedParentChange
+ \printuntil }
+ \printuntil }
+*/
+void QQuickAttachedPropertyPropagator::attachedParentChange(QQuickAttachedPropertyPropagator *newParent, QQuickAttachedPropertyPropagator *oldParent)
+{
+ Q_UNUSED(newParent);
+ Q_UNUSED(oldParent);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickattachedpropertypropagator.cpp"
diff --git a/src/quickcontrols2/qquickattachedpropertypropagator.h b/src/quickcontrols2/qquickattachedpropertypropagator.h
new file mode 100644
index 0000000000..ec5ff7991a
--- /dev/null
+++ b/src/quickcontrols2/qquickattachedpropertypropagator.h
@@ -0,0 +1,37 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QQUICKATTACHEDOBJECT_H
+#define QQUICKATTACHEDOBJECT_H
+
+#include <QtCore/qobject.h>
+#include <QtQuickControls2/qtquickcontrols2global.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickAttachedPropertyPropagatorPrivate;
+
+class Q_QUICKCONTROLS2_EXPORT QQuickAttachedPropertyPropagator : public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit QQuickAttachedPropertyPropagator(QObject *parent = nullptr);
+ ~QQuickAttachedPropertyPropagator();
+
+ QList<QQuickAttachedPropertyPropagator *> attachedChildren() const;
+
+ QQuickAttachedPropertyPropagator *attachedParent() const;
+
+protected:
+ void initialize();
+
+ virtual void attachedParentChange(QQuickAttachedPropertyPropagator *newParent, QQuickAttachedPropertyPropagator *oldParent);
+
+private:
+ Q_DECLARE_PRIVATE(QQuickAttachedPropertyPropagator)
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKATTACHEDOBJECT_H
diff --git a/src/quickcontrols2/universal/qquickuniversalstyle.cpp b/src/quickcontrols2/universal/qquickuniversalstyle.cpp
index 9de295757c..cacf20a75f 100644
--- a/src/quickcontrols2/universal/qquickuniversalstyle.cpp
+++ b/src/quickcontrols2/universal/qquickuniversalstyle.cpp
@@ -118,11 +118,11 @@ static QRgb GlobalBackground = qquickuniversal_light_color(QQuickUniversalStyle:
static bool HasGlobalForeground = false;
static bool HasGlobalBackground = false;
-QQuickUniversalStyle::QQuickUniversalStyle(QObject *parent) : QQuickAttachedObject(parent),
+QQuickUniversalStyle::QQuickUniversalStyle(QObject *parent) : QQuickAttachedPropertyPropagator(parent),
m_hasForeground(HasGlobalForeground), m_hasBackground(HasGlobalBackground), m_theme(GlobalTheme),
m_accent(GlobalAccent), m_foreground(GlobalForeground), m_background(GlobalBackground)
{
- init();
+ initialize();
}
QQuickUniversalStyle *QQuickUniversalStyle::qmlAttachedProperties(QObject *object)
@@ -166,7 +166,7 @@ void QQuickUniversalStyle::inheritTheme(Theme theme)
void QQuickUniversalStyle::propagateTheme()
{
const auto styles = attachedChildren();
- for (QQuickAttachedObject *child : styles) {
+ for (QQuickAttachedPropertyPropagator *child : styles) {
QQuickUniversalStyle *universal = qobject_cast<QQuickUniversalStyle *>(child);
if (universal)
universal->inheritTheme(m_theme);
@@ -216,7 +216,7 @@ void QQuickUniversalStyle::inheritAccent(QRgb accent)
void QQuickUniversalStyle::propagateAccent()
{
const auto styles = attachedChildren();
- for (QQuickAttachedObject *child : styles) {
+ for (QQuickAttachedPropertyPropagator *child : styles) {
QQuickUniversalStyle *universal = qobject_cast<QQuickUniversalStyle *>(child);
if (universal)
universal->inheritAccent(m_accent);
@@ -270,7 +270,7 @@ void QQuickUniversalStyle::inheritForeground(QRgb foreground, bool has)
void QQuickUniversalStyle::propagateForeground()
{
const auto styles = attachedChildren();
- for (QQuickAttachedObject *child : styles) {
+ for (QQuickAttachedPropertyPropagator *child : styles) {
QQuickUniversalStyle *universal = qobject_cast<QQuickUniversalStyle *>(child);
if (universal)
universal->inheritForeground(m_foreground, m_hasForeground);
@@ -325,7 +325,7 @@ void QQuickUniversalStyle::inheritBackground(QRgb background, bool has)
void QQuickUniversalStyle::propagateBackground()
{
const auto styles = attachedChildren();
- for (QQuickAttachedObject *child : styles) {
+ for (QQuickAttachedPropertyPropagator *child : styles) {
QQuickUniversalStyle *universal = qobject_cast<QQuickUniversalStyle *>(child);
if (universal)
universal->inheritBackground(m_background, m_hasBackground);
@@ -473,7 +473,7 @@ QColor QQuickUniversalStyle::systemColor(SystemColor role) const
return QColor::fromRgba(m_theme == QQuickUniversalStyle::Dark ? qquickuniversal_dark_color(role) : qquickuniversal_light_color(role));
}
-void QQuickUniversalStyle::attachedParentChange(QQuickAttachedObject *newParent, QQuickAttachedObject *oldParent)
+void QQuickUniversalStyle::attachedParentChange(QQuickAttachedPropertyPropagator *newParent, QQuickAttachedPropertyPropagator *oldParent)
{
Q_UNUSED(oldParent);
QQuickUniversalStyle *universal = qobject_cast<QQuickUniversalStyle *>(newParent);
diff --git a/src/quickcontrols2/universal/qquickuniversalstyle_p.h b/src/quickcontrols2/universal/qquickuniversalstyle_p.h
index 7fa6e1a58a..024fde2192 100644
--- a/src/quickcontrols2/universal/qquickuniversalstyle_p.h
+++ b/src/quickcontrols2/universal/qquickuniversalstyle_p.h
@@ -16,13 +16,14 @@
//
#include <QtGui/qcolor.h>
-#include <QtQuickControls2Impl/private/qquickattachedobject_p.h>
+#include <QtQml/qqml.h>
+#include <QtQuickControls2/qquickattachedpropertypropagator.h>
QT_BEGIN_NAMESPACE
class QQuickUniversalStylePrivate;
-class QQuickUniversalStyle : public QQuickAttachedObject
+class QQuickUniversalStyle : public QQuickAttachedPropertyPropagator
{
Q_OBJECT
Q_PROPERTY(Theme theme READ theme WRITE setTheme RESET resetTheme NOTIFY themeChanged FINAL)
@@ -182,7 +183,7 @@ Q_SIGNALS:
void paletteChanged();
protected:
- void attachedParentChange(QQuickAttachedObject *newParent, QQuickAttachedObject *oldParent) override;
+ void attachedParentChange(QQuickAttachedPropertyPropagator *newParent, QQuickAttachedPropertyPropagator *oldParent) override;
private:
bool variantToRgba(const QVariant &var, const char *name, QRgb *rgba) const;
diff --git a/src/quickcontrols2impl/CMakeLists.txt b/src/quickcontrols2impl/CMakeLists.txt
index 87a5a1634c..acbc91b15e 100644
--- a/src/quickcontrols2impl/CMakeLists.txt
+++ b/src/quickcontrols2impl/CMakeLists.txt
@@ -15,7 +15,6 @@ qt_internal_add_qml_module(QuickControls2Impl
PLUGIN_TARGET qtquickcontrols2implplugin
SOURCES
qquickanimatednode.cpp qquickanimatednode_p.h
- qquickattachedobject.cpp qquickattachedobject_p.h
qquickchecklabel.cpp qquickchecklabel_p.h
qquickclippedtext.cpp qquickclippedtext_p.h
qquickcolor.cpp qquickcolor_p.h
diff --git a/src/quickcontrols2impl/qquickattachedobject.cpp b/src/quickcontrols2impl/qquickattachedobject.cpp
deleted file mode 100644
index a6bf6fc667..0000000000
--- a/src/quickcontrols2impl/qquickattachedobject.cpp
+++ /dev/null
@@ -1,243 +0,0 @@
-// Copyright (C) 2017 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#include "qquickattachedobject_p.h"
-
-#include <QtCore/qpointer.h>
-#include <QtQuick/qquickwindow.h>
-#include <QtQuick/private/qquickitem_p.h>
-#include <QtQuick/private/qquickitemchangelistener_p.h>
-#include <QtQuickTemplates2/private/qquickpopup_p.h>
-
-QT_BEGIN_NAMESPACE
-
-static QQuickAttachedObject *attachedObject(const QMetaObject *type, QObject *object, bool create = false)
-{
- if (!object)
- return nullptr;
- auto func = qmlAttachedPropertiesFunction(object, type);
- return qobject_cast<QQuickAttachedObject *>(qmlAttachedPropertiesObject(object, func, create));
-}
-
-static QQuickAttachedObject *findAttachedParent(const QMetaObject *type, QObject *object)
-{
- QQuickItem *item = qobject_cast<QQuickItem *>(object);
- if (item) {
- // lookup parent items and popups
- QQuickItem *parent = item->parentItem();
- while (parent) {
- QQuickAttachedObject *attached = attachedObject(type, parent);
- if (attached)
- return attached;
-
- QQuickPopup *popup = qobject_cast<QQuickPopup *>(parent->parent());
- if (popup)
- return attachedObject(type, popup);
-
- parent = parent->parentItem();
- }
-
- // fallback to item's window
- QQuickAttachedObject *attached = attachedObject(type, item->window());
- if (attached)
- return attached;
- } else {
- // lookup popup's window
- QQuickPopup *popup = qobject_cast<QQuickPopup *>(object);
- if (popup)
- return attachedObject(type, popup->popupItem()->window());
- }
-
- // lookup parent window
- QQuickWindow *window = qobject_cast<QQuickWindow *>(object);
- if (window) {
- QQuickWindow *parentWindow = qobject_cast<QQuickWindow *>(window->parent());
- if (parentWindow) {
- QQuickAttachedObject *attached = attachedObject(type, window);
- if (attached)
- return attached;
- }
- }
-
- // fallback to engine (global)
- if (object) {
- QQmlEngine *engine = qmlEngine(object);
- if (engine) {
- QByteArray name = QByteArray("_q_") + type->className();
- QQuickAttachedObject *attached = engine->property(name).value<QQuickAttachedObject *>();
- if (!attached) {
- attached = attachedObject(type, engine, true);
- engine->setProperty(name, QVariant::fromValue(attached));
- }
- return attached;
- }
- }
-
- return nullptr;
-}
-
-static QList<QQuickAttachedObject *> findAttachedChildren(const QMetaObject *type, QObject *object)
-{
- QList<QQuickAttachedObject *> children;
-
- QQuickItem *item = qobject_cast<QQuickItem *>(object);
- if (!item) {
- QQuickWindow *window = qobject_cast<QQuickWindow *>(object);
- if (window) {
- item = window->contentItem();
-
- const auto &windowChildren = window->children();
- for (QObject *child : windowChildren) {
- QQuickWindow *childWindow = qobject_cast<QQuickWindow *>(child);
- if (childWindow) {
- QQuickAttachedObject *attached = attachedObject(type, childWindow);
- if (attached)
- children += attached;
- }
- }
- }
- }
-
- if (item) {
- const auto childItems = item->childItems();
- for (QQuickItem *child : childItems) {
- QQuickAttachedObject *attached = attachedObject(type, child);
- if (attached)
- children += attached;
- else
- children += findAttachedChildren(type, child);
- }
- }
-
- return children;
-}
-
-static QQuickItem *findAttachedItem(QObject *parent)
-{
- QQuickItem *item = qobject_cast<QQuickItem *>(parent);
- if (!item) {
- QQuickPopup *popup = qobject_cast<QQuickPopup *>(parent);
- if (popup)
- item = popup->popupItem();
- }
- return item;
-}
-
-class QQuickAttachedObjectPrivate : public QObjectPrivate, public QQuickItemChangeListener
-{
-public:
- Q_DECLARE_PUBLIC(QQuickAttachedObject)
-
- static QQuickAttachedObjectPrivate *get(QQuickAttachedObject *attachedObject)
- {
- return attachedObject->d_func();
- }
-
- void attachTo(QObject *object);
- void detachFrom(QObject *object);
-
- void itemWindowChanged(QQuickWindow *window);
- void itemParentChanged(QQuickItem *item, QQuickItem *parent) override;
-
- QList<QQuickAttachedObject *> attachedChildren;
- QPointer<QQuickAttachedObject> attachedParent;
-};
-
-void QQuickAttachedObjectPrivate::attachTo(QObject *object)
-{
- QQuickItem *item = findAttachedItem(object);
- if (item) {
- connect(item, &QQuickItem::windowChanged, this, &QQuickAttachedObjectPrivate::itemWindowChanged);
- QQuickItemPrivate::get(item)->addItemChangeListener(this, QQuickItemPrivate::Parent);
- }
-}
-
-void QQuickAttachedObjectPrivate::detachFrom(QObject *object)
-{
- QQuickItem *item = findAttachedItem(object);
- if (item) {
- disconnect(item, &QQuickItem::windowChanged, this, &QQuickAttachedObjectPrivate::itemWindowChanged);
- QQuickItemPrivate::get(item)->removeItemChangeListener(this, QQuickItemPrivate::Parent);
- }
-}
-
-void QQuickAttachedObjectPrivate::itemWindowChanged(QQuickWindow *window)
-{
- Q_Q(QQuickAttachedObject);
- QQuickAttachedObject *attachedParent = nullptr;
- QQuickItem *item = qobject_cast<QQuickItem *>(q->sender());
- if (item)
- attachedParent = findAttachedParent(q->metaObject(), item);
- if (!attachedParent)
- attachedParent = attachedObject(q->metaObject(), window);
- q->setAttachedParent(attachedParent);
-}
-
-void QQuickAttachedObjectPrivate::itemParentChanged(QQuickItem *item, QQuickItem *parent)
-{
- Q_Q(QQuickAttachedObject);
- Q_UNUSED(parent);
- q->setAttachedParent(findAttachedParent(q->metaObject(), item));
-}
-
-QQuickAttachedObject::QQuickAttachedObject(QObject *parent)
- : QObject(*(new QQuickAttachedObjectPrivate), parent)
-{
- Q_D(QQuickAttachedObject);
- d->attachTo(parent);
-}
-
-QQuickAttachedObject::~QQuickAttachedObject()
-{
- Q_D(QQuickAttachedObject);
- d->detachFrom(parent());
- setAttachedParent(nullptr);
-}
-
-QList<QQuickAttachedObject *> QQuickAttachedObject::attachedChildren() const
-{
- Q_D(const QQuickAttachedObject);
- return d->attachedChildren;
-}
-
-QQuickAttachedObject *QQuickAttachedObject::attachedParent() const
-{
- Q_D(const QQuickAttachedObject);
- return d->attachedParent;
-}
-
-void QQuickAttachedObject::setAttachedParent(QQuickAttachedObject *parent)
-{
- Q_D(QQuickAttachedObject);
- if (d->attachedParent == parent)
- return;
-
- QQuickAttachedObject *oldParent = d->attachedParent;
- if (d->attachedParent)
- QQuickAttachedObjectPrivate::get(d->attachedParent)->attachedChildren.removeOne(this);
- d->attachedParent = parent;
- if (parent)
- QQuickAttachedObjectPrivate::get(parent)->attachedChildren.append(this);
- attachedParentChange(parent, oldParent);
-}
-
-void QQuickAttachedObject::init()
-{
- QQuickAttachedObject *attachedParent = findAttachedParent(metaObject(), parent());
- if (attachedParent)
- setAttachedParent(attachedParent);
-
- const QList<QQuickAttachedObject *> attachedChildren = findAttachedChildren(metaObject(), parent());
- for (QQuickAttachedObject *child : attachedChildren)
- child->setAttachedParent(this);
-}
-
-void QQuickAttachedObject::attachedParentChange(QQuickAttachedObject *newParent, QQuickAttachedObject *oldParent)
-{
- Q_UNUSED(newParent);
- Q_UNUSED(oldParent);
-}
-
-QT_END_NAMESPACE
-
-#include "moc_qquickattachedobject_p.cpp"
diff --git a/src/quickcontrols2impl/qquickattachedobject_p.h b/src/quickcontrols2impl/qquickattachedobject_p.h
deleted file mode 100644
index 3473c16936..0000000000
--- a/src/quickcontrols2impl/qquickattachedobject_p.h
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright (C) 2017 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#ifndef QQUICKATTACHEDOBJECT_P_H
-#define QQUICKATTACHEDOBJECT_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 <QtQml/qqml.h>
-#include <QtCore/qobject.h>
-#include <QtQuickControls2Impl/private/qtquickcontrols2implglobal_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QQuickAttachedObjectPrivate;
-
-class Q_QUICKCONTROLS2IMPL_PRIVATE_EXPORT QQuickAttachedObject : public QObject
-{
- Q_OBJECT
-
-public:
- explicit QQuickAttachedObject(QObject *parent = nullptr);
- ~QQuickAttachedObject();
-
- QList<QQuickAttachedObject *> attachedChildren() const;
-
- QQuickAttachedObject *attachedParent() const;
- void setAttachedParent(QQuickAttachedObject *parent);
-
-protected:
- void init();
-
- virtual void attachedParentChange(QQuickAttachedObject *newParent, QQuickAttachedObject *oldParent);
-
-private:
- Q_DISABLE_COPY(QQuickAttachedObject)
- Q_DECLARE_PRIVATE(QQuickAttachedObject)
-};
-
-QT_END_NAMESPACE
-
-#endif // QQUICKATTACHEDOBJECT_P_H
diff --git a/tests/auto/quickcontrols2/qquickmaterialstyle/data/tst_material.qml b/tests/auto/quickcontrols2/qquickmaterialstyle/data/tst_material.qml
index 689d90ca25..34754420d0 100644
--- a/tests/auto/quickcontrols2/qquickmaterialstyle/data/tst_material.qml
+++ b/tests/auto/quickcontrols2/qquickmaterialstyle/data/tst_material.qml
@@ -275,49 +275,199 @@ TestCase {
compare(popupObject.label2.color.toString(), popupObject.Material.textSelectionColor.toString())
}
- function test_window() {
- let parent = createTemporaryObject(windowComponent)
-
- let control = button.createObject(parent.contentItem)
- compare(control.Material.primary, parent.Material.primary)
- compare(control.Material.accent, parent.Material.accent)
- compare(control.Material.background, parent.Material.background)
- compare(control.Material.foreground, parent.Material.foreground)
- compare(control.Material.theme, parent.Material.theme)
-
- let styledChild = styledWindowComponent.createObject(parent)
- verify(styledChild.Material.primary !== parent.Material.primary)
- verify(styledChild.Material.accent !== parent.Material.accent)
- verify(styledChild.Material.background !== parent.Material.background)
- verify(styledChild.Material.foreground !== parent.Material.foreground)
- verify(styledChild.Material.theme !== parent.Material.theme)
-
- let unstyledChild = windowComponent.createObject(parent)
- compare(unstyledChild.Material.primary, parent.Material.primary)
- compare(unstyledChild.Material.accent, parent.Material.accent)
- compare(unstyledChild.Material.background, parent.Material.background)
- compare(unstyledChild.Material.foreground, parent.Material.foreground)
- compare(unstyledChild.Material.theme, parent.Material.theme)
-
- parent.Material.primary = Material.Lime
+ component StyledChildWindow: Window {
+ objectName: "styledChildWindow"
+
+ Material.objectName: objectName + "MaterialAttached"
+ Material.theme: Material.Dark
+ Material.primary: Material.Brown
+ Material.accent: Material.Green
+ Material.background: Material.Yellow
+ Material.foreground: Material.Grey
+ }
+
+ component StyledChildAppWindow: ApplicationWindow {
+ objectName: "styledChildAppWindow"
+
+ Material.objectName: objectName + "MaterialAttached"
+ Material.theme: Material.Dark
+ Material.primary: Material.Brown
+ Material.accent: Material.Green
+ Material.background: Material.Yellow
+ Material.foreground: Material.Grey
+ }
+
+ component UnstyledChildWindow: Window {
+ objectName: "unstyledChildWindow"
+ Material.objectName: objectName + "MaterialAttached"
+ }
+
+ component UnstyledChildAppWindow: ApplicationWindow {
+ objectName: "unstyledChildAppWindow"
+ Material.objectName: objectName + "MaterialAttached"
+ }
+
+ Component {
+ id: parentWindowComponent
+
+ Window {
+ objectName: "rootWindow"
+
+ Material.objectName: objectName + "MaterialAttached"
+
+ property alias styledChildWindow: styledChildWindow
+ property alias unstyledChildWindow: unstyledChildWindow
+
+ StyledChildWindow {
+ id: styledChildWindow
+ }
+
+ UnstyledChildWindow {
+ id: unstyledChildWindow
+ }
+ }
+ }
+
+ Component {
+ id: parentAppWindowComponent
+
+ ApplicationWindow {
+ objectName: "rootAppWindow"
+
+ Material.objectName: objectName + "MaterialAttached"
+
+ property alias styledChildWindow: styledChildWindow
+ property alias unstyledChildWindow: unstyledChildWindow
+
+ StyledChildAppWindow {
+ id: styledChildWindow
+ }
+
+ UnstyledChildAppWindow {
+ id: unstyledChildWindow
+ }
+ }
+ }
+
+ Component {
+ id: parentMixed1WindowComponent
+
+ ApplicationWindow {
+ objectName: "rootAppWindow"
+
+ Material.objectName: objectName + "MaterialAttached"
+
+ property alias styledChildWindow: styledChildWindow
+ property alias unstyledChildWindow: unstyledChildWindow
+
+ StyledChildWindow {
+ id: styledChildWindow
+ }
+
+ UnstyledChildWindow {
+ id: unstyledChildWindow
+ }
+ }
+ }
+
+ Component {
+ id: parentMixed2WindowComponent
+
+ Window {
+ id: rootWindow
+ objectName: "rootWindow"
+
+ Material.objectName: objectName + "MaterialAttached"
+
+ property alias styledChildWindow: styledChildWindow
+ property alias unstyledChildWindow: unstyledChildWindow
+
+ StyledChildAppWindow {
+ id: styledChildWindow
+ }
+
+ UnstyledChildAppWindow {
+ id: unstyledChildWindow
+ }
+ }
+ }
+
+ function test_window_data() {
+ return [
+ { tag: "Window", component: parentWindowComponent },
+ { tag: "ApplicationWindow", component: parentAppWindowComponent },
+ // Test a combination of Window and ApplicationWindow.
+ { tag: "mixed-1", component: parentMixed1WindowComponent },
+ { tag: "mixed-2", component: parentMixed2WindowComponent },
+ ]
+ }
+
+ function test_window(data) {
+ let parentWindow = createTemporaryObject(data.component, null)
+ verify(parentWindow)
+
+ let control = button.createObject(parentWindow.contentItem)
+ verify(control)
+ compare(control.Material.primary, parentWindow.Material.primary)
+ compare(control.Material.accent, parentWindow.Material.accent)
+ compare(control.Material.background, parentWindow.Material.background)
+ compare(control.Material.foreground, parentWindow.Material.foreground)
+ compare(control.Material.theme, parentWindow.Material.theme)
+
+ let styledChildWindow = parentWindow.styledChildWindow
+ verify(styledChildWindow)
+ verify(styledChildWindow.Material.primary !== parentWindow.Material.primary)
+ verify(styledChildWindow.Material.accent !== parentWindow.Material.accent)
+ verify(styledChildWindow.Material.background !== parentWindow.Material.background)
+ verify(styledChildWindow.Material.foreground !== parentWindow.Material.foreground)
+ verify(styledChildWindow.Material.theme !== parentWindow.Material.theme)
+
+ let unstyledChildWindow = parentWindow.unstyledChildWindow
+ verify(unstyledChildWindow)
+ compare(unstyledChildWindow.Material.primary, parentWindow.Material.primary)
+ compare(unstyledChildWindow.Material.accent, parentWindow.Material.accent)
+ compare(unstyledChildWindow.Material.background, parentWindow.Material.background)
+ compare(unstyledChildWindow.Material.foreground, parentWindow.Material.foreground)
+ compare(unstyledChildWindow.Material.theme, parentWindow.Material.theme)
+
+ parentWindow.Material.primary = Material.Lime
compare(control.Material.primary, Material.color(Material.Lime))
- verify(styledChild.Material.primary !== Material.color(Material.Lime))
- // ### TODO: compare(unstyledChild.Material.primary, Material.color(Material.Lime))
+ verify(styledChildWindow.Material.primary !== Material.color(Material.Lime))
+ compare(unstyledChildWindow.Material.primary, Material.color(Material.Lime))
- parent.Material.accent = Material.Cyan
+ parentWindow.Material.accent = Material.Cyan
compare(control.Material.accent, Material.color(Material.Cyan))
- verify(styledChild.Material.accent !== Material.color(Material.Cyan))
- // ### TODO: compare(unstyledChild.Material.accent, Material.color(Material.Cyan))
+ verify(styledChildWindow.Material.accent !== Material.color(Material.Cyan))
+ compare(unstyledChildWindow.Material.accent, Material.color(Material.Cyan))
- parent.Material.background = Material.Indigo
+ parentWindow.Material.background = Material.Indigo
compare(control.Material.background, Material.color(Material.Indigo))
- verify(styledChild.Material.background !== Material.color(Material.Indigo))
- // ### TODO: compare(unstyledChild.Material.background, Material.color(Material.Indigo))
+ verify(styledChildWindow.Material.background !== Material.color(Material.Indigo))
+ compare(unstyledChildWindow.Material.background, Material.color(Material.Indigo))
- parent.Material.foreground = Material.Pink
+ parentWindow.Material.foreground = Material.Pink
compare(control.Material.foreground, Material.color(Material.Pink))
- verify(styledChild.Material.foreground !== Material.color(Material.Pink))
- // ### TODO: compare(unstyledChild.Material.foreground, Material.color(Material.Pink))
+ verify(styledChildWindow.Material.foreground !== Material.color(Material.Pink))
+ compare(unstyledChildWindow.Material.foreground, Material.color(Material.Pink))
+
+ // Test that theme changes are propagated to child windows.
+ // Make sure that this check actually does something (in case the default changes).
+ compare(parentWindow.Material.theme, Material.Light)
+ // styledChildWindow was already dark, so make it light to verify that it doesn't change.
+ styledChildWindow.Material.theme = Material.Light
+ // Reset background since Theme affects it and we use it to test that the colors change.
+ parentWindow.Material.background = undefined
+ // Setting theme to Dark should result in the background colors of control and unstyledChildWindow changing.
+ // Note that since Window is unstyled, its actual (background) color won't change.
+ parentWindow.Material.theme = Material.Dark
+ compare(control.Material.theme, Material.Dark)
+ compare(styledChildWindow.Material.theme, Material.Light)
+ compare(unstyledChildWindow.Material.theme, Material.Dark)
+ // Make sure that the colors actually changed.
+ compare(parentWindow.Material.background, Qt.color("#303030"))
+ compare(control.Material.background, parentWindow.Material.background)
+ verify(styledChildWindow.Material.background !== parentWindow.Material.background)
+ compare(unstyledChildWindow.Material.background, parentWindow.Material.background)
}
function test_loader() {