diff options
-rw-r--r-- | src/quickcontrols2/qquickstyle.cpp | 62 | ||||
-rw-r--r-- | tests/auto/qquickstyle/qquickstyle.pro | 8 | ||||
-rw-r--r-- | tests/auto/qquickstyle/qrcStyles1/QrcStyle1/Button.qml | 2 | ||||
-rw-r--r-- | tests/auto/qquickstyle/qrcStyles2/QrcStyle2/Button.qml | 2 | ||||
-rw-r--r-- | tests/auto/qquickstyle/tst_qquickstyle.cpp | 111 |
5 files changed, 183 insertions, 2 deletions
diff --git a/src/quickcontrols2/qquickstyle.cpp b/src/quickcontrols2/qquickstyle.cpp index 804b53fd..73c604de 100644 --- a/src/quickcontrols2/qquickstyle.cpp +++ b/src/quickcontrols2/qquickstyle.cpp @@ -260,13 +260,71 @@ struct QQuickStyleSpec Q_GLOBAL_STATIC(QQuickStyleSpec, styleSpec) +static QStringList parseStylePathsWithColon(const QString &var) +{ + QStringList paths; + const QChar colon = QLatin1Char(':'); + int currentIndex = 0; + + do { + int nextColonIndex = -1; + QString path; + + if (var.at(currentIndex) == colon) { + // This is either a list separator, or a qrc path. + if (var.at(currentIndex + 1) == colon) { + // It's a double colon (list separator followed by qrc path); + // find the end of the path. + nextColonIndex = var.indexOf(colon, currentIndex + 2); + path = var.mid(currentIndex + 1, + nextColonIndex == -1 ? -1 : nextColonIndex - currentIndex - 1); + } else { + // It's a single colon. + nextColonIndex = var.indexOf(colon, currentIndex + 1); + if (currentIndex == 0) { + // If we're at the start of the string, then it's a qrc path. + path = var.mid(currentIndex, + nextColonIndex == -1 ? -1 : nextColonIndex - currentIndex); + } else { + // Otherwise, it's a separator. + path = var.mid(currentIndex + 1, + nextColonIndex == -1 ? -1 : nextColonIndex - currentIndex - 1); + } + } + } else { + // It's a file path. + nextColonIndex = var.indexOf(colon, currentIndex); + path = var.mid(currentIndex, + nextColonIndex == -1 ? -1 : nextColonIndex - currentIndex); + } + + paths += path; + currentIndex = nextColonIndex; + + // Keep going until we can't find any more colons, + // or we're at the last character. + } while (currentIndex != -1 && currentIndex < var.size() - 1); + + return paths; +} + QStringList QQuickStylePrivate::stylePaths() { // system/custom style paths QStringList paths; if (Q_UNLIKELY(!qEnvironmentVariableIsEmpty("QT_QUICK_CONTROLS_STYLE_PATH"))) { - const QByteArray value = qgetenv("QT_QUICK_CONTROLS_STYLE_PATH"); - paths += QString::fromLocal8Bit(value).split(QDir::listSeparator(), QString::SkipEmptyParts); + const QString value = QString::fromLocal8Bit(qgetenv("QT_QUICK_CONTROLS_STYLE_PATH")); + const QChar listSeparator = QDir::listSeparator(); + if (listSeparator == QLatin1Char(':')) { + // Split manually to avoid breaking paths on systems where : is the list separator, + // since it's also used for qrc paths. + paths += parseStylePathsWithColon(value); + } else { + // Fast/simpler path for systems where something other than : is used as + // the list separator (such as ';'). + const QStringList customPaths = value.split(listSeparator, QString::SkipEmptyParts); + paths += customPaths; + } } // built-in import paths diff --git a/tests/auto/qquickstyle/qquickstyle.pro b/tests/auto/qquickstyle/qquickstyle.pro index da74b6cd..983e5438 100644 --- a/tests/auto/qquickstyle/qquickstyle.pro +++ b/tests/auto/qquickstyle/qquickstyle.pro @@ -10,3 +10,11 @@ QT_PRIVATE += core-private gui-private quickcontrols2-private include (../shared/util.pri) TESTDATA = $$PWD/data/* + +qrcStyles1.files = $$files(qrcStyles1/QrcStyle1/*.qml) +qrcStyles1.prefix = / +RESOURCES += qrcStyles1 + +qrcStyles2.files = $$files(qrcStyles2/QrcStyle2/*.qml) +qrcStyles2.prefix = / +RESOURCES += qrcStyles2 diff --git a/tests/auto/qquickstyle/qrcStyles1/QrcStyle1/Button.qml b/tests/auto/qquickstyle/qrcStyles1/QrcStyle1/Button.qml new file mode 100644 index 00000000..5b08222c --- /dev/null +++ b/tests/auto/qquickstyle/qrcStyles1/QrcStyle1/Button.qml @@ -0,0 +1,2 @@ +import QtQuick.Templates 2.0 as T +T.Button { } diff --git a/tests/auto/qquickstyle/qrcStyles2/QrcStyle2/Button.qml b/tests/auto/qquickstyle/qrcStyles2/QrcStyle2/Button.qml new file mode 100644 index 00000000..5b08222c --- /dev/null +++ b/tests/auto/qquickstyle/qrcStyles2/QrcStyle2/Button.qml @@ -0,0 +1,2 @@ +import QtQuick.Templates 2.0 as T +T.Button { } diff --git a/tests/auto/qquickstyle/tst_qquickstyle.cpp b/tests/auto/qquickstyle/tst_qquickstyle.cpp index 4a34f24a..8b2358f8 100644 --- a/tests/auto/qquickstyle/tst_qquickstyle.cpp +++ b/tests/auto/qquickstyle/tst_qquickstyle.cpp @@ -55,6 +55,8 @@ private slots: void commandLineArgument(); void environmentVariables(); void availableStyles(); + void qrcInQtQuickControlsStylePathEnvVar_data(); + void qrcInQtQuickControlsStylePathEnvVar(); private: void loadControls(); @@ -67,6 +69,7 @@ void tst_QQuickStyle::cleanup() QGuiApplicationPrivate::styleOverride.clear(); qunsetenv("QT_QUICK_CONTROLS_STYLE"); + qunsetenv("QT_QUICK_CONTROLS_STYLE_PATH"); qunsetenv("QT_QUICK_CONTROLS_FALLBACK_STYLE"); qunsetenv("QT_QUICK_CONTROLS_CONF"); } @@ -167,6 +170,114 @@ void tst_QQuickStyle::availableStyles() } } +void tst_QQuickStyle::qrcInQtQuickControlsStylePathEnvVar_data() +{ + QTest::addColumn<QString>("environmentVariable"); + QTest::addColumn<QStringList>("expectedAvailableStyles"); + + const QChar listSeparator = QDir::listSeparator(); + const QStringList defaultAvailableStyles = QQuickStyle::availableStyles(); + + { + QString environmentVariable; + QDebug stream(&environmentVariable); + stream.noquote().nospace() << "/some/bogus/path/" << listSeparator + << ":/qrcStyles1"; + + QStringList expectedAvailableStyles = defaultAvailableStyles; + // We need to move the Default style to the start of the list, + // as that's what availableStyles() does. + expectedAvailableStyles.insert(1, QLatin1String("QrcStyle1")); + + QTest::addRow("%s", qPrintable(environmentVariable)) + << environmentVariable << expectedAvailableStyles; + } + + { + QString environmentVariable; + QDebug stream(&environmentVariable); + stream.noquote().nospace() << ":/qrcStyles2" << listSeparator + << "/some/bogus/path"; + + QStringList expectedAvailableStyles = defaultAvailableStyles; + expectedAvailableStyles.insert(1, QLatin1String("QrcStyle2")); + + QTest::addRow("%s", qPrintable(environmentVariable)) + << environmentVariable << expectedAvailableStyles; + } + + { + QString environmentVariable; + QDebug stream(&environmentVariable); + stream.noquote().nospace() << ":/qrcStyles1" << listSeparator + << ":/qrcStyles2" << listSeparator + << QFINDTESTDATA("data"); + + QStringList expectedAvailableStyles = defaultAvailableStyles; + expectedAvailableStyles.insert(1, QLatin1String("DummyStyle")); + expectedAvailableStyles.insert(1, QLatin1String("QrcStyle2")); + expectedAvailableStyles.insert(1, QLatin1String("QrcStyle1")); + + QTest::addRow("%s", qPrintable(environmentVariable)) + << environmentVariable << expectedAvailableStyles; + } + + { + QString environmentVariable; + QDebug stream(&environmentVariable); + stream.noquote().nospace() << QFINDTESTDATA("data") << listSeparator + << ":/qrcStyles1" << listSeparator + << ":/qrcStyles2"; + + QStringList expectedAvailableStyles = defaultAvailableStyles; + expectedAvailableStyles.insert(1, QLatin1String("QrcStyle2")); + expectedAvailableStyles.insert(1, QLatin1String("QrcStyle1")); + expectedAvailableStyles.insert(1, QLatin1String("DummyStyle")); + + QTest::addRow("%s", qPrintable(environmentVariable)) + << environmentVariable << expectedAvailableStyles; + } + + { + QString environmentVariable; + QDebug stream(&environmentVariable); + // Same as the last row, except it adds a superfluous separator + // to ensure that it handles it gracefully rather than failing an assertion. + stream.noquote().nospace() << QFINDTESTDATA("data") << listSeparator + << ":/qrcStyles1" << listSeparator + << ":/qrcStyles2" << listSeparator; + + QStringList expectedAvailableStyles = defaultAvailableStyles; + expectedAvailableStyles.insert(1, QLatin1String("QrcStyle2")); + expectedAvailableStyles.insert(1, QLatin1String("QrcStyle1")); + expectedAvailableStyles.insert(1, QLatin1String("DummyStyle")); + + QTest::addRow("%s", qPrintable(environmentVariable)) + << environmentVariable << expectedAvailableStyles; + } +} + +/* + Tests that qrc paths work with QT_QUICK_CONTROLS_STYLE_PATH. +*/ +void tst_QQuickStyle::qrcInQtQuickControlsStylePathEnvVar() +{ + QFETCH(QString, environmentVariable); + QFETCH(QStringList, expectedAvailableStyles); + + qputenv("QT_QUICK_CONTROLS_STYLE_PATH", environmentVariable.toLocal8Bit()); + + const QStringList availableStyles = QQuickStyle::availableStyles(); + if (availableStyles != expectedAvailableStyles) { + QString failureMessage; + QDebug stream(&failureMessage); + stream << "Mismatch in actual vs expected available styles:" + << "\n Expected:" << expectedAvailableStyles + << "\n Actual:" << availableStyles; + QFAIL(qPrintable(failureMessage)); + } +} + QTEST_MAIN(tst_QQuickStyle) #include "tst_qquickstyle.moc" |