diff options
author | Volker Hilsheimer <volker.hilsheimer@qt.io> | 2022-02-21 16:18:51 +0100 |
---|---|---|
committer | Volker Hilsheimer <volker.hilsheimer@qt.io> | 2022-02-24 19:46:01 +0100 |
commit | 4cca8ee527bfa94947f897d4d9b91aa8eb63d9c3 (patch) | |
tree | ca49a4a875807c502b41b68a1a6454d83d3a2413 | |
parent | 32b596b7b10eac63293cf3bd3e04a15bd826fbf1 (diff) |
QGuiApplication: use translation-based layout direction unless explicitly set
The stored layout direction used to get changed during initialization
to what was auto-detected based on the translation. Changing the
translation then overwrote that stored value, even if an explicit call
to setLayoutDirection was made by the application.
Calling QGuiApplication::setLayoutDirection(Auto) has so far been a
no-op.
Change this logic so that the stored layout direction continues to be
LayoutDirectionAuto also if it's set based on auto-detection, and only
overwrite it when explicitly called with a non-Auto value. This way,
applications can set a layout direction that stays unchanged even when
translators are installed.
Add test coverage that uses a QTranslator.
In practice, this is not a change of behavior, unless applications called
setLayoutDirection(Auto) (which is no longer a no-op), or called
setLayoutDirection() and then installed a translator and expected the
translator's layout direction to come into effect in spite of the explicit
setting.
[ChangeLog][Gui][QGuiApplication] Calling setLayoutDirection with a non-
auto value now disables the auto-detection based on installed
translators. Applications that explicitly set a layout direction and also
want translators installed afterwards to take effect should reset the
layout direction to Auto, which is now no longer a no-op.
Fixes: QTBUG-100632
Pick-to: 6.3
Change-Id: I1fdcebd43a9b1b468ff95bf15f53f441bb214e08
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
-rw-r--r-- | src/gui/kernel/qguiapplication.cpp | 37 | ||||
-rw-r--r-- | tests/auto/gui/kernel/qguiapplication/tst_qguiapplication.cpp | 60 |
2 files changed, 83 insertions, 14 deletions
diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index da71580a73..883b22b7ed 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -191,6 +191,7 @@ static int touchDoubleTapDistance = 0; QWindow *QGuiApplicationPrivate::currentMousePressWindow = nullptr; static Qt::LayoutDirection layout_direction = Qt::LayoutDirectionAuto; +static Qt::LayoutDirection effective_layout_direction = Qt::LeftToRight; static bool force_reverse = false; QGuiApplicationPrivate *QGuiApplicationPrivate::self = nullptr; @@ -1672,8 +1673,8 @@ void QGuiApplicationPrivate::init() Q_UNUSED(loadTestability); #endif // QT_CONFIG(library) - if (layout_direction == Qt::LayoutDirectionAuto || force_reverse) - QGuiApplication::setLayoutDirection(qt_detectRTLLanguage() ? Qt::RightToLeft : Qt::LeftToRight); + // trigger changed signal and event delivery + QGuiApplication::setLayoutDirection(layout_direction); if (!QGuiApplicationPrivate::displayName) QObject::connect(q, &QGuiApplication::applicationNameChanged, @@ -1699,7 +1700,7 @@ QGuiApplicationPrivate::~QGuiApplicationPrivate() QCursorData::cleanup(); #endif - layout_direction = Qt::LeftToRight; + layout_direction = Qt::LayoutDirectionAuto; cleanupThreadData(); @@ -1943,7 +1944,9 @@ bool QGuiApplication::notify(QObject *object, QEvent *event) bool QGuiApplication::event(QEvent *e) { if (e->type() == QEvent::LanguageChange) { - setLayoutDirection(qt_detectRTLLanguage()?Qt::RightToLeft:Qt::LeftToRight); + // if the layout direction was set explicitly, then don't override it here + if (layout_direction == Qt::LayoutDirectionAuto) + setLayoutDirection(layout_direction); for (auto *topLevelWindow : QGuiApplication::topLevelWindows()) { if (topLevelWindow->flags() != Qt::Desktop) postEvent(topLevelWindow, new QEvent(QEvent::LanguageChange)); @@ -3881,7 +3884,8 @@ void QGuiApplication::sync() \property QGuiApplication::layoutDirection \brief the default layout direction for this application - On system start-up, the default layout direction depends on the + On system start-up, or when the direction is explicitly set to + Qt::LayoutDirectionAuto, the default layout direction depends on the application's language. The notifier signal was introduced in Qt 5.4. @@ -3891,11 +3895,15 @@ void QGuiApplication::sync() void QGuiApplication::setLayoutDirection(Qt::LayoutDirection direction) { - if (layout_direction == direction || direction == Qt::LayoutDirectionAuto) - return; - layout_direction = direction; + if (direction == Qt::LayoutDirectionAuto) + direction = qt_detectRTLLanguage() ? Qt::RightToLeft : Qt::LeftToRight; + + // no change to the explicitly set or auto-detected layout direction + if (direction == effective_layout_direction) + return; + effective_layout_direction = direction; if (qGuiApp) { emit qGuiApp->layoutDirectionChanged(direction); QGuiApplicationPrivate::self->notifyLayoutDirectionChange(); @@ -3904,10 +3912,15 @@ void QGuiApplication::setLayoutDirection(Qt::LayoutDirection direction) Qt::LayoutDirection QGuiApplication::layoutDirection() { - // layout_direction is only ever Qt::LayoutDirectionAuto if setLayoutDirection - // was never called, or called with Qt::LayoutDirectionAuto (which is a no-op). - // In that case we return the default LeftToRight. - return layout_direction == Qt::LayoutDirectionAuto ? Qt::LeftToRight : layout_direction; + /* + effective_layout_direction defaults to Qt::LeftToRight, and is updated with what is + auto-detected by a call to setLayoutDirection(Qt::LayoutDirectionAuto). This happens in + QGuiApplicationPrivate::init and when the language changes (or before if the application + calls the static function, but then no translators are installed so the auto-detection + always yields Qt::LeftToRight). + So we can be certain that it's always the right value. + */ + return effective_layout_direction; } /*! diff --git a/tests/auto/gui/kernel/qguiapplication/tst_qguiapplication.cpp b/tests/auto/gui/kernel/qguiapplication/tst_qguiapplication.cpp index 5eab76898b..e3b4bd296f 100644 --- a/tests/auto/gui/kernel/qguiapplication/tst_qguiapplication.cpp +++ b/tests/auto/gui/kernel/qguiapplication/tst_qguiapplication.cpp @@ -1158,8 +1158,8 @@ void tst_QGuiApplication::layoutDirection() { qRegisterMetaType<Qt::LayoutDirection>(); - Qt::LayoutDirection oldDirection = QGuiApplication::layoutDirection(); - Qt::LayoutDirection newDirection = oldDirection == Qt::LeftToRight ? Qt::RightToLeft : Qt::LeftToRight; + const Qt::LayoutDirection oldDirection = QGuiApplication::layoutDirection(); + const Qt::LayoutDirection newDirection = oldDirection == Qt::LeftToRight ? Qt::RightToLeft : Qt::LeftToRight; QGuiApplication::setLayoutDirection(newDirection); QCOMPARE(QGuiApplication::layoutDirection(), newDirection); @@ -1177,8 +1177,64 @@ void tst_QGuiApplication::layoutDirection() QGuiApplication::setLayoutDirection(oldDirection); QCOMPARE(QGuiApplication::layoutDirection(), oldDirection); QCOMPARE(signalSpy.count(), 1); + + // with QGuiApplication instantiated, install a translator that gives us control + class LayoutDirectionTranslator : public QTranslator + { + public: + LayoutDirectionTranslator(Qt::LayoutDirection direction) + : direction(direction) + {} + + bool isEmpty() const override { return false; } + QString translate(const char *context, const char *sourceText, const char *disambiguation, int n) const override + { + if (QByteArrayView(sourceText) == "QT_LAYOUT_DIRECTION") + return direction == Qt::LeftToRight ? QLatin1String("LTR") : QLatin1String("RTL"); + return QTranslator::translate(context, sourceText, disambiguation, n); + } + + const Qt::LayoutDirection direction; + }; + + int layoutDirectionChangedCount = 0; + // reset to auto-detection, should be back to oldDirection now + QGuiApplication::setLayoutDirection(Qt::LayoutDirectionAuto); + QCOMPARE(QGuiApplication::layoutDirection(), oldDirection); + signalSpy.clear(); + { + // this translator doesn't change the direction + LayoutDirectionTranslator translator(oldDirection); + QGuiApplication::installTranslator(&translator); + QCOMPARE(QGuiApplication::layoutDirection(), translator.direction); + QCOMPARE(signalSpy.count(), layoutDirectionChangedCount); + } + QCOMPARE(signalSpy.count(), layoutDirectionChangedCount); // ltrTranslator removed, no change + + // install a new translator that changes the direction + { + LayoutDirectionTranslator translator(newDirection); + QGuiApplication::installTranslator(&translator); + QCOMPARE(QGuiApplication::layoutDirection(), translator.direction); + QCOMPARE(signalSpy.count(), ++layoutDirectionChangedCount); + } + // rtlTranslator removed + QCOMPARE(signalSpy.count(), ++layoutDirectionChangedCount); + + // override translation + QGuiApplication::setLayoutDirection(newDirection); + QCOMPARE(signalSpy.count(), ++layoutDirectionChangedCount); + { + // this translator will be ignored + LayoutDirectionTranslator translator(oldDirection); + QGuiApplication::installTranslator(&translator); + QCOMPARE(QGuiApplication::layoutDirection(), newDirection); + QCOMPARE(signalSpy.count(), layoutDirectionChangedCount); + } + QCOMPARE(signalSpy.count(), layoutDirectionChangedCount); } + void tst_QGuiApplication::globalShareContext() { #ifndef QT_NO_OPENGL |