aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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() {