diff options
Diffstat (limited to 'src/controls/Private/qquickcontrolsettings.cpp')
-rw-r--r-- | src/controls/Private/qquickcontrolsettings.cpp | 190 |
1 files changed, 152 insertions, 38 deletions
diff --git a/src/controls/Private/qquickcontrolsettings.cpp b/src/controls/Private/qquickcontrolsettings.cpp index 017a0714..c000a658 100644 --- a/src/controls/Private/qquickcontrolsettings.cpp +++ b/src/controls/Private/qquickcontrolsettings.cpp @@ -106,6 +106,57 @@ bool QQuickControlSettings::hoverEnabled() const return !isMobile() || !hasTouchScreen(); } +QString QQuickControlSettings::makeStyleComponentPath(const QString &controlStyleName, const QString &styleDirPath) +{ + return styleDirPath + QStringLiteral("/") + controlStyleName; +} + +QUrl QQuickControlSettings::makeStyleComponentUrl(const QString &controlStyleName, QString styleDirPath) +{ + QString styleFilePath = makeStyleComponentPath(controlStyleName, styleDirPath); + + if (styleDirPath.startsWith(QStringLiteral(":/"))) + return QUrl(QStringLiteral("qrc") + styleFilePath); + + return QUrl::fromLocalFile(styleFilePath); +} + +QQmlComponent *QQuickControlSettings::styleComponent(const QUrl &styleDirUrl, const QString &controlStyleName, QObject *control) +{ + Q_UNUSED(styleDirUrl); // required for hack that forces this function to be re-called from within QML when style changes + + // QUrl doesn't consider qrc-based URLs as local files, so bypass it here. + QString styleFilePath = makeStyleComponentPath(controlStyleName, m_styleMap.value(m_name).m_styleDirPath); + QUrl styleFileUrl; + if (QFile::exists(styleFilePath)) { + styleFileUrl = makeStyleComponentUrl(controlStyleName, m_styleMap.value(m_name).m_styleDirPath); + } else { + // It's OK for a style to pick and choose which controls it wants to provide style files for. + styleFileUrl = makeStyleComponentUrl(controlStyleName, m_styleMap.value(QStringLiteral("Base")).m_styleDirPath); + } + + return new QQmlComponent(qmlEngine(control), styleFileUrl); +} + +static QString relativeStyleImportPath(QQmlEngine *engine, const QString &styleName) +{ + QString path; + bool found = false; + foreach (const QString &import, engine->importPathList()) { + QDir dir(import + QStringLiteral("/QtQuick/Controls/Styles")); + if (dir.exists(styleName)) { + found = true; + path = dir.absolutePath(); + break; + } + if (found) + break; + } + if (!found) + path = ":/QtQuick/Controls/Styles"; + return path; +} + static QString styleImportPath(QQmlEngine *engine, const QString &styleName) { QString path = qgetenv("QT_QUICK_CONTROLS_STYLE"); @@ -113,19 +164,7 @@ static QString styleImportPath(QQmlEngine *engine, const QString &styleName) if (fromResource(path)) { path = info.path(); } else if (info.isRelative()) { - bool found = false; - foreach (const QString &import, engine->importPathList()) { - QDir dir(import + QLatin1String("/QtQuick/Controls/Styles")); - if (dir.exists(styleName)) { - found = true; - path = dir.absolutePath(); - break; - } - if (found) - break; - } - if (!found) - path = ":/QtQuick/Controls/Styles"; + path = relativeStyleImportPath(engine, styleName); } else { path = info.absolutePath(); } @@ -134,40 +173,109 @@ static QString styleImportPath(QQmlEngine *engine, const QString &styleName) QQuickControlSettings::QQuickControlSettings(QQmlEngine *engine) { + // First, register all style paths in the default style location. + QDir dir; + const QString defaultStyle = defaultStyleName(); + dir.setPath(relativeStyleImportPath(engine, defaultStyle)); + dir.setFilter(QDir::Dirs | QDir::NoDotAndDotDot); + foreach (const QString &styleDirectory, dir.entryList()) { + findStyle(engine, styleDirectory); + } + m_name = styleImportName(); - m_path = styleImportPath(engine, m_name); - QString path = styleFilePath(); + // If the style name is a path.. + const QString styleNameFromEnvVar = qgetenv("QT_QUICK_CONTROLS_STYLE"); + if (QFile::exists(styleNameFromEnvVar)) { + StyleData styleData; + styleData.m_styleDirPath = styleNameFromEnvVar; + m_styleMap[m_name] = styleData; + } - QDir dir(path); - if (!dir.exists()) { + // Then check if the style the user wanted is known to us. Otherwise, use the fallback style. + if (m_styleMap.contains(m_name)) { + m_path = m_styleMap.value(m_name).m_styleDirPath; + } else { QString unknownStyle = m_name; - m_name = defaultStyleName(); - m_path = styleImportPath(engine, m_name); + m_name = defaultStyle; + m_path = m_styleMap.value(defaultStyle).m_styleDirPath; qWarning() << "WARNING: Cannot find style" << unknownStyle << "- fallback:" << styleFilePath(); - } else { - typedef bool (*StyleInitFunc)(); - typedef const char *(*StylePathFunc)(); - - foreach (const QString &fileName, dir.entryList()) { - if (QLibrary::isLibrary(fileName)) { - QLibrary lib(dir.absoluteFilePath(fileName)); - StyleInitFunc initFunc = (StyleInitFunc) lib.resolve("qt_quick_controls_style_init"); - if (initFunc) - initFunc(); - StylePathFunc pathFunc = (StylePathFunc) lib.resolve("qt_quick_controls_style_path"); - if (pathFunc) - m_path = QString::fromLocal8Bit(pathFunc()); - if (initFunc || pathFunc) - break; - } - } } + // Can't really do anything about this failing here, so don't bother checking... + resolveCurrentStylePath(); + connect(this, SIGNAL(styleNameChanged()), SIGNAL(styleChanged())); connect(this, SIGNAL(stylePathChanged()), SIGNAL(styleChanged())); } +bool QQuickControlSettings::resolveCurrentStylePath() +{ + if (!m_styleMap.contains(m_name)) { + qWarning() << "WARNING: Cannot find style" << m_name; + return false; + } + + StyleData styleData = m_styleMap.value(m_name); + + if (styleData.m_stylePluginPath.isEmpty()) + return true; // It's not a plugin; don't have to do anything. + + typedef bool (*StyleInitFunc)(); + typedef const char *(*StylePathFunc)(); + + QLibrary lib(styleData.m_stylePluginPath); + if (!lib.load()) { + qWarning().nospace() << "WARNING: Cannot load plugin " << styleData.m_stylePluginPath + << " for style " << m_name << ": " << lib.errorString(); + return false; + } + + // Check for the existence of this first, as we don't want to init if this doesn't exist. + StylePathFunc pathFunc = (StylePathFunc) lib.resolve("qt_quick_controls_style_path"); + if (!pathFunc) { + qWarning() << "WARNING: Style" << m_name << "is a plugin but does not expose qt_quick_controls_style_path"; + return false; + } + + StyleInitFunc initFunc = (StyleInitFunc) lib.resolve("qt_quick_controls_style_init"); + if (initFunc) + initFunc(); + + styleData.m_styleDirPath = QString::fromLocal8Bit(pathFunc()); + m_styleMap[m_name] = styleData; + return true; +} + +void QQuickControlSettings::findStyle(QQmlEngine *engine, const QString &styleName) +{ + QString path = styleImportPath(engine, styleName); + QDir dir; + dir.setFilter(QDir::Files | QDir::NoDotAndDotDot); + dir.setPath(path); + dir.cd(styleName); + + StyleData styleData; + + foreach (const QString &fileName, dir.entryList()) { + // This assumes that there is only one library in the style directory, + // which should be a safe assumption. If at some point it's determined + // not to be safe, we'll have to resolve the init and path functions + // here, to be sure that it is the correct library. + if (QLibrary::isLibrary(fileName)) { + styleData.m_stylePluginPath = dir.absoluteFilePath(fileName); + break; + } + } + + // If there's no plugin for the style, then the style's files are + // contained in this directory (which contains a qmldir file instead). + if (styleData.m_stylePluginPath.isEmpty()) + styleData.m_styleDirPath = dir.absolutePath(); + + m_styleMap[styleName] = styleData; +} + QUrl QQuickControlSettings::style() const { QUrl result; @@ -189,8 +297,14 @@ QString QQuickControlSettings::styleName() const void QQuickControlSettings::setStyleName(const QString &name) { if (m_name != name) { + QString oldName = m_name; m_name = name; - emit styleNameChanged(); + + // Don't change the style if it can't be resolved. + if (!resolveCurrentStylePath()) + m_name = oldName; + else + emit styleNameChanged(); } } @@ -209,7 +323,7 @@ void QQuickControlSettings::setStylePath(const QString &path) QString QQuickControlSettings::styleFilePath() const { - return m_path + QLatin1Char('/') + m_name; + return m_path; } extern Q_GUI_EXPORT int qt_defaultDpiX(); |