Revision control

++ // Copyright (C) 2025 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 "qqstylekit_p.h"
++ #include "qqstylekitstyle_p.h"
++ #include "qqstylekittheme_p.h"
++ #include "qqstylekitreader_p.h"
++
++ #include <QtGui/QStyleHints>
++
++ QT_BEGIN_NAMESPACE
++
++ QPointer<QQStyleKitAttached> QQStyleKitAttached::s_instance;
++ bool QQStyleKitAttached::s_transitionsEnabled = true;
++
++ /*!
++ \qmltype StyleKit
++ \inqmlmodule Qt.labs.StyleKit
++ \brief A singleton for setting and accessing the current style.
++
++ \c StyleKit is a singleton for setting the application \l Style.
++
++ \snippet PlainStyleMain.qml 1
++
++ It also provides properties for global StyleKit configuration and debugging.
++
++ \labs
++
++ \sa Style, StyleVariation
++ */
++
++ /*!
++ \qmlproperty Style StyleKit::style
++
++ The active style for the application.
++
++ Set this to a \l Style instance to apply it to all \l {Qt Quick Controls}.
++
++ \snippet PlainStyleMain.qml 1
++
++ \note For best startup performance, set the style on the root \l ApplicationWindow, before
++ any child controls.
++
++ \sa styleUrl, Style
++ */
++
++ /*!
++ \qmlproperty url StyleKit::styleUrl
++
++ An alternative to \l style that loads a \l Style from a URL.
++
++ \sa style
++ */
++
++ /*!
++ \qmlproperty bool StyleKit::transitionsEnabled
++
++ Controls whether transitions are enabled globally.
++
++ Set this to \c false to disable all transitions in the
++ current style.
++
++ The default value is \c true.
++
++ \sa {ControlStyle::transition}
++ */
++
++ /*!
++ \qmlproperty StyleKitDebug StyleKit::debug
++ \readonly
++
++ A run-time debugging tool that can be used to trace
++ style properties for a specific \l Control.
++ */
++
++ /*!
++ \qmlmethod bool StyleKit::styleLoaded()
++
++ Returns \c true when the active \l style and its current \l {Style::}{theme} have both
++ finished loading. This can be used to defer initialization logic that
++ depends on resolved style properties.
++
++ \sa style, {Style::}{theme}
++ */
++
++ QQStyleKit::QQStyleKit(QObject *parent)
++ : QObject(parent)
++ {
++ }
++
++ QQStyleKitAttached *QQStyleKit::qmlAttachedProperties(QObject *obj)
++ {
++ /* QQStyleKitAttached is a singleton. It doesn't matter where it's
++ * used from in the application, it will always represent the same
++ * application global style and theme. */
++ if (!QQStyleKitAttached::s_instance)
++ QQStyleKitAttached::s_instance = new QQStyleKitAttached(QGuiApplication::instance());
++ if (!QQStyleKitAttached::s_instance->m_engine && obj)
++ QQStyleKitAttached::s_instance->m_engine = qmlEngine(obj);
++ return QQStyleKitAttached::s_instance.get();
++ }
++
++ QQStyleKitAttached::QQStyleKitAttached(QObject *parent)
++ : QObject(parent)
++ {
++ connect(QGuiApplication::styleHints(), &QStyleHints::colorSchemeChanged, this, [this](){
++ if (m_style && QString::compare(m_style->themeName(), "System"_L1, Qt::CaseInsensitive) == 0)
++ m_style->recreateTheme();
++ });
++ }
++
++ QQStyleKitAttached::~QQStyleKitAttached()
++ {
++ QQStyleKitAttached::s_instance = nullptr;
++ if (m_ownsStyle) {
++ delete m_style;
++ m_style = nullptr;
++ }
++ }
++
++ QQStyleKitStyle *QQStyleKitAttached::style() const
++ {
++ return m_style;
++ }
++
++ void QQStyleKitAttached::setStyle(QQStyleKitStyle *style)
++ {
++ if (m_style == style)
++ return;
++
++ if (m_ownsStyle)
++ m_style->deleteLater();
++
++ m_style = style;
++ m_style->reapplyStyle();
++
++ emit styleChanged();
++ }
++
++ QUrl QQStyleKitAttached::styleUrl() const
++ {
++ return m_styleUrl;
++ }
++
++ void QQStyleKitAttached::setStyleUrl(const QUrl &styleUrl)
++ {
++ if (m_styleUrl == styleUrl)
++ return;
++
++ m_styleUrl = styleUrl;
++
++ Q_ASSERT(m_engine);
++ QQmlComponent component(m_engine, styleUrl, this);
++ if (!component.errors().isEmpty()) {
++ qmlWarning(this) << "Could not create a Style from url '" << styleUrl << "': " << component.errorString();
++ return;
++ }
++
++ /* Avoid creating anything other than StyleKit Style objects by checking the metaobject
++ * of the root type before creating the object. This to avoid instantiating items or other
++ * object that could cause unwanted side effects. */
++ QQmlComponentPrivate *componentPrivate = QQmlComponentPrivate::get(&component);
++ const auto compilationUnit = componentPrivate->compilationUnit();
++ const auto propertyCache = compilationUnit ? compilationUnit->rootPropertyCache() : nullptr;
++ const auto firstMetaObject = propertyCache ? propertyCache->firstCppMetaObject() : nullptr;
++ if (!firstMetaObject || !firstMetaObject->inherits(&QQStyleKitStyle::staticMetaObject)) {
++ qmlWarning(this) << "Could not create a Style from url '" << styleUrl << "': the root item is not a Style.";
++ return;
++ }
++
++ auto *style = qobject_cast<QQStyleKitStyle *>(component.create());
++ if (!style) {
++ qmlWarning(this) << "Could not create a Style from url '" << styleUrl << "': failed to create an instance of the resolved Component.";
++ return;
++ }
++
++ style->componentComplete();
++ setStyle(style);
++ m_ownsStyle = true;
++ emit styleUrlChanged();
++ }
++
++ bool QQStyleKitAttached::transitionsEnabled() const
++ {
++ return s_transitionsEnabled;
++ }
++
++ void QQStyleKitAttached::setTransitionsEnabled(bool enabled)
++ {
++ if (enabled == s_transitionsEnabled)
++ return;
++
++ s_transitionsEnabled = enabled;
++ emit transitionsEnabledChanged();
++ }
++
++ QQStyleKitDebug *QQStyleKitAttached::debug() const
++ {
++ return &const_cast<QQStyleKitAttached *>(this)->m_debug;
++ }
++
++ bool QQStyleKitAttached::styleLoaded() const
++ {
++ return m_style && m_style->loaded();
++ }
++
++ QT_END_NAMESPACE
++
++ #include "moc_qqstylekit_p.cpp"
++