aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
authorTim Jenssen <tim.jenssen@qt.io>2020-02-07 08:13:41 +0100
committerMaximilian Goldstein <max.goldstein@qt.io>2021-04-26 13:13:44 +0200
commit784c62441333de8d13d31c719ac01e6096247c01 (patch)
treec9916e04f0e7d7ddf1cf6467f0f9ad643267e58a /src/plugins
parentf9b85604179e162c68ac8c42f97b1b3329c79b0a (diff)
Implement debugtranslationservice
- moves the language feature from the preview service to an own debugtranslationservice - with the help of a proxytranslator the service gets all translate requests Change-Id: Ic26677bb1706abbea2db23e6aafe7a3f00648962 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/qmltooling/qmldbg_messages/qdebugmessageservice.h2
-rw-r--r--src/plugins/qmltooling/qmldbg_preview/CMakeLists.txt9
-rw-r--r--src/plugins/qmltooling/qmldbg_preview/proxytranslator.cpp156
-rw-r--r--src/plugins/qmltooling/qmldbg_preview/proxytranslator.h97
-rw-r--r--src/plugins/qmltooling/qmldbg_preview/qqmldebugtranslationservice.cpp397
-rw-r--r--src/plugins/qmltooling/qmldbg_preview/qqmldebugtranslationservice.h44
-rw-r--r--src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.cpp39
-rw-r--r--src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.h12
-rw-r--r--src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservice.cpp13
-rw-r--r--src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservice.h6
-rw-r--r--src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservicefactory.cpp5
-rw-r--r--src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp2
12 files changed, 677 insertions, 105 deletions
diff --git a/src/plugins/qmltooling/qmldbg_messages/qdebugmessageservice.h b/src/plugins/qmltooling/qmldbg_messages/qdebugmessageservice.h
index 24fd27514b..eb78afe900 100644
--- a/src/plugins/qmltooling/qmldbg_messages/qdebugmessageservice.h
+++ b/src/plugins/qmltooling/qmldbg_messages/qdebugmessageservice.h
@@ -59,8 +59,6 @@
QT_BEGIN_NAMESPACE
-class QDebugMessageServicePrivate;
-
class QDebugMessageServiceImpl : public QDebugMessageService
{
Q_OBJECT
diff --git a/src/plugins/qmltooling/qmldbg_preview/CMakeLists.txt b/src/plugins/qmltooling/qmldbg_preview/CMakeLists.txt
index 2874580a03..2b3611b90d 100644
--- a/src/plugins/qmltooling/qmldbg_preview/CMakeLists.txt
+++ b/src/plugins/qmltooling/qmldbg_preview/CMakeLists.txt
@@ -8,7 +8,6 @@ qt_internal_add_plugin(QQmlPreviewServiceFactory
OUTPUT_NAME qmldbg_preview
TYPE qmltooling
SOURCES
- qqmldebugtranslationservice.cpp qqmldebugtranslationservice.h
qqmlpreviewblacklist.cpp qqmlpreviewblacklist.h
qqmlpreviewfileengine.cpp qqmlpreviewfileengine.h
qqmlpreviewfileloader.cpp qqmlpreviewfileloader.h
@@ -29,3 +28,11 @@ qt_internal_add_plugin(QQmlPreviewServiceFactory
#### Keys ignored in scope 1:.:.:qmldbg_preview.pro:<TRUE>:
# OTHER_FILES = "$$PWD/qqmlpreviewservice.json"
+
+qt_internal_extend_target(QQmlPreviewServiceFactory CONDITION QT_FEATURE_translation
+ SOURCES
+ proxytranslator.cpp proxytranslator.h
+ qqmldebugtranslationservice.cpp qqmldebugtranslationservice.h
+ PUBLIC_LIBRARIES
+ Qt::Gui
+)
diff --git a/src/plugins/qmltooling/qmldbg_preview/proxytranslator.cpp b/src/plugins/qmltooling/qmldbg_preview/proxytranslator.cpp
new file mode 100644
index 0000000000..7f5227296a
--- /dev/null
+++ b/src/plugins/qmltooling/qmldbg_preview/proxytranslator.cpp
@@ -0,0 +1,156 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "proxytranslator.h"
+
+#include <QtCore/qlibraryinfo.h>
+
+QT_BEGIN_NAMESPACE
+
+void ProxyTranslator::addEngine(QQmlEngine *engine)
+{
+ m_engines.append(engine);
+}
+
+void ProxyTranslator::removeEngine(QQmlEngine *engine)
+{
+ m_engines.removeOne(engine);
+}
+
+bool ProxyTranslator::hasTranslation(const TranslationBindingInformation &translationBindingInformation) const
+{
+ resetTranslationFound();
+ translationFromInformation(translationBindingInformation);
+ return translationFound();
+}
+
+QString ProxyTranslator::translationFromInformation(const TranslationBindingInformation &translationBindingInformation)
+{
+ return translationBindingInformation.compilationUnit->bindingValueAsString(
+ translationBindingInformation.compiledBinding);
+}
+
+
+QString ProxyTranslator::originStringFromInformation(const TranslationBindingInformation &translationBindingInformation)
+{
+ return translationBindingInformation.compilationUnit->stringAt(
+ translationBindingInformation.compiledBinding->stringIndex);
+}
+
+QQmlSourceLocation ProxyTranslator::sourceLocationFromInformation(const TranslationBindingInformation &translationBindingInformation)
+{
+ return QQmlSourceLocation(translationBindingInformation.compilationUnit->fileName(),
+ translationBindingInformation.compiledBinding->valueLocation.line,
+ translationBindingInformation.compiledBinding->valueLocation.column);
+}
+
+
+void ProxyTranslator::setLanguage(const QUrl &context, const QLocale &locale)
+{
+ m_enable = true;
+ m_currentUILanguages = locale.uiLanguages().join(QLatin1Char(' '));
+
+ m_qtTranslator.reset(new QTranslator());
+ if (!m_qtTranslator->load(locale, QLatin1String("qt"), QLatin1String("_"),
+ QLibraryInfo::path(QLibraryInfo::TranslationsPath))) {
+ m_qtTranslator.reset();
+ }
+
+ m_qmlTranslator.reset(new QTranslator(this));
+ if (!m_qmlTranslator->load(locale, QLatin1String("qml"), QLatin1String("_"),
+ context.toLocalFile() + QLatin1String("/i18n"))) {
+ m_qmlTranslator.reset();
+ }
+
+ // unfortunately setUiLanguage set new translators, so do this first
+ for (QQmlEngine *engine : qAsConst(m_engines))
+ engine->setUiLanguage(locale.bcp47Name());
+
+ // make sure proxy translator is the first used translator
+ QCoreApplication::removeTranslator(this);
+ QCoreApplication::installTranslator(this);
+
+ for (QQmlEngine *engine : qAsConst(m_engines)) {
+ // have two retranslate runs to get elided warning even the same language was set
+ m_enable = false;
+ engine->retranslate();
+ m_enable = true;
+ engine->retranslate();
+ }
+ emit languageChanged(locale);
+}
+
+QString ProxyTranslator::translate(const char *context, const char *sourceText, const char *disambiguation, int n) const
+{
+ if (!m_enable)
+ return {};
+ QString result;
+ if (result.isNull() && m_qtTranslator)
+ result = m_qtTranslator->translate(context, sourceText, disambiguation, n);
+ if (result.isNull() && m_qmlTranslator)
+ result = m_qmlTranslator->translate(context, sourceText, disambiguation, n);
+ m_translationFound = !result.isNull();
+ return result;
+}
+
+void ProxyTranslator::resetTranslationFound() const
+{
+ m_translationFound = false;
+}
+
+bool ProxyTranslator::translationFound() const
+{
+ return m_translationFound;
+}
+
+bool ProxyTranslator::isEmpty() const
+{
+ if (m_qtTranslator && m_qtTranslator->isEmpty())
+ return false;
+ if (m_qmlTranslator && m_qmlTranslator->isEmpty())
+ return false;
+ return true;
+}
+
+QString ProxyTranslator::currentUILanguages() const
+{
+ return m_currentUILanguages;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/qmltooling/qmldbg_preview/proxytranslator.h b/src/plugins/qmltooling/qmldbg_preview/proxytranslator.h
new file mode 100644
index 0000000000..b53f81105a
--- /dev/null
+++ b/src/plugins/qmltooling/qmldbg_preview/proxytranslator.h
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PROXYTRANSLATOR_H
+#define PROXYTRANSLATOR_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 <private/qqmldebugserviceinterfaces_p.h>
+#include <private/qqmlglobal_p.h>
+
+#include <QtCore/qstring.h>
+#include <QtCore/qurl.h>
+#include <QtCore/qtranslator.h>
+
+#include <memory>
+
+QT_BEGIN_NAMESPACE
+
+class ProxyTranslator : public QTranslator
+{
+ Q_OBJECT
+public:
+ QString translate(const char *context, const char *sourceText, const char *disambiguation, int n) const override;
+ bool isEmpty() const override;
+
+ QString currentUILanguages() const;
+ void setLanguage(const QUrl &context, const QLocale &locale);
+ void addEngine(QQmlEngine *engine);
+ void removeEngine(QQmlEngine *engine);
+
+ bool hasTranslation(const TranslationBindingInformation &translationBindingInformation) const;
+ static QString translationFromInformation(const TranslationBindingInformation &translationBindingInformation);
+ static QString originStringFromInformation(const TranslationBindingInformation &translationBindingInformation);
+ static QQmlSourceLocation sourceLocationFromInformation(const TranslationBindingInformation &translationBindingInformation);
+signals:
+ void languageChanged(const QLocale &locale);
+
+private:
+ void resetTranslationFound() const;
+ bool translationFound() const;
+ QList<QQmlEngine *> m_engines;
+ std::unique_ptr<QTranslator> m_qtTranslator;
+ std::unique_ptr<QTranslator> m_qmlTranslator;
+ bool m_enable = false;
+ QString m_currentUILanguages;
+ mutable bool m_translationFound = false;
+};
+
+QT_END_NAMESPACE
+
+#endif // PROXYTRANSLATOR_H
diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmldebugtranslationservice.cpp b/src/plugins/qmltooling/qmldbg_preview/qqmldebugtranslationservice.cpp
index 785fca6427..4f9d76432f 100644
--- a/src/plugins/qmltooling/qmldbg_preview/qqmldebugtranslationservice.cpp
+++ b/src/plugins/qmltooling/qmldbg_preview/qqmldebugtranslationservice.cpp
@@ -38,33 +38,406 @@
****************************************************************************/
#include "qqmldebugtranslationservice.h"
+#include "proxytranslator.h"
+
+#include <QtCore/qtranslator.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qlibraryinfo.h>
+#include <QtCore/qdir.h>
+#include <QtCore/qfile.h>
+#include <QtCore/qtimer.h>
+#include <QtCore/qhash.h>
+#include <QtCore/qpointer.h>
+
+#include <private/qqmldebugtranslationprotocol_p.h>
+#include <private/qqmldebugconnector_p.h>
+#include <private/qversionedpacket_p.h>
+
+#include <private/qqmlbinding_p.h>
+#include <private/qqmlbinding_p.h>
+#include <private/qquickstategroup_p.h>
+#include <private/qquickitem_p.h>
+#include <private/qdebug_p.h>
+
+#include <QtQuick/qquickitem.h>
+
+#include <qquickview.h>
QT_BEGIN_NAMESPACE
-QQmlDebugTranslationServiceImpl::QQmlDebugTranslationServiceImpl(QObject *parent) :
- QQmlDebugTranslationService(1, parent)
+Q_LOGGING_CATEGORY(lcQmlTooling, "qt.quick.qmltooling.debugtranslation")
+
+using namespace QQmlDebugTranslation;
+
+QDebug operator<<(QDebug debug, const TranslationBindingInformation &translationBindingInformation)
+{
+ QQmlError error;
+ error.setUrl(translationBindingInformation.compilationUnit->url());
+ error.setLine(translationBindingInformation.compiledBinding->valueLocation.line);
+ error.setColumn(translationBindingInformation.compiledBinding->valueLocation.column);
+ error.setDescription(
+ QString(QLatin1String(
+ "QDebug translation binding"
+ )));
+ return debug << qPrintable(error.toString());
+}
+
+class QQmlDebugTranslationServicePrivate : public QObject
+{
+ Q_OBJECT
+public:
+ QQmlDebugTranslationServicePrivate(QQmlDebugTranslationServiceImpl *parent)
+ : q(parent)
+ , proxyTranslator(new ProxyTranslator)
+ {
+ connect(&translatableTextOccurrenceTimer, &QTimer::timeout,
+ this, &QQmlDebugTranslationServicePrivate::sendTranslatableTextOccurrences);
+ }
+
+ void setState(const QString &stateName)
+ {
+ if (currentQuickView) {
+ QQuickItem *rootItem = currentQuickView->rootObject();
+ QQuickStateGroup *stateGroup = QQuickItemPrivate::get(rootItem)->_states();
+ if (stateGroup->findState(stateName)) {
+ connect(stateGroup, &QQuickStateGroup::stateChanged,
+ this, &QQmlDebugTranslationServicePrivate::sendStateChanged,
+ Qt::ConnectionType(Qt::QueuedConnection | Qt::UniqueConnection));
+ stateGroup->setState(stateName);
+ }
+ else
+ qWarning() << QString("Could not switch the state to %1").arg(stateName);
+ }
+ }
+
+ void sendStateChanged()
+ {
+ QString stateName;
+ if (QQuickStateGroup *stateGroup = qobject_cast<QQuickStateGroup*>(sender()))
+ stateName = stateGroup->state();
+ QVersionedPacket<QQmlDebugConnector> packet;
+ packet << Reply::StateChanged << stateName;
+ emit q->messageToClient(q->name(), packet.data());
+ }
+
+ void sendStateList()
+ {
+ QVersionedPacket<QQmlDebugConnector> packet;
+ packet << Reply::StateList;
+
+ QQuickItem *rootItem = currentQuickView->rootObject();
+ QQuickStateGroup *stateGroup = QQuickItemPrivate::get(rootItem)->_states();
+
+ QList<QQuickState *> states = stateGroup->states();
+ QVector<QmlState> qmlStates;
+
+ for (QQuickState *state : states) {
+ QmlState qmlState;
+ qmlState.name = state->name();
+ qmlStates.append(qmlState);
+ }
+
+ packet << qmlStates;
+ emit q->messageToClient(q->name(), packet.data());
+ }
+
+ void setWatchTextElides(bool s)
+ {
+ // TODO: for disabling we need to keep track which one were enabled
+ if (s == false)
+ qWarning() << "disable WatchTextElides is not implemented";
+ watchTextElides = s;
+ for (auto &&information : qAsConst(objectTranslationBindingMultiMap)) {
+ QObject *scopeObject = information.scopeObject;
+ int elideIndex = scopeObject->metaObject()->indexOfProperty("elide");
+ if (elideIndex >= 0) {
+ auto elideProperty = scopeObject->metaObject()->property(elideIndex);
+ elideProperty.write(scopeObject, Qt::ElideRight);
+ }
+ }
+ }
+
+ void sendTranslatableTextOccurrences()
+ {
+
+ QVersionedPacket<QQmlDebugConnector> packet;
+ packet << Reply::TranslatableTextOccurrences;
+
+ QVector<QmlElement> qmlElements;
+
+ for (auto &&information : qAsConst(objectTranslationBindingMultiMap)) {
+
+ QObject *scopeObject = information.scopeObject;
+ auto compilationUnit = information.compilationUnit;
+ auto binding = information.compiledBinding;
+ auto metaObject = scopeObject->metaObject();
+
+ const QString propertyName = compilationUnit->stringAt(binding->propertyNameIndex);
+
+ int textIndex = metaObject->indexOfProperty(propertyName.toLatin1());
+ if (textIndex >= 0) {
+
+ QmlElement qmlElement;
+
+ qmlElement.codeMarker = codeMarker(information);
+
+ auto textProperty = scopeObject->metaObject()->property(textIndex);
+ qmlElement.propertyName = textProperty.name();
+ qmlElement.translationId = compilationUnit->stringAt(
+ compilationUnit->data->translations()[binding->value.translationDataIndex]
+ .stringIndex);
+ qmlElement.translatedText = textProperty.read(scopeObject).toString();
+ qmlElement.elementId = qmlContext(scopeObject)->nameForObject(scopeObject);
+
+ QFont font = scopeObject->property("font").value<QFont>();
+ qmlElement.fontFamily = font.family();
+ qmlElement.fontPointSize = font.pointSize();
+ qmlElement.fontPixelSize = font.pixelSize();
+ qmlElement.fontStyleName = font.styleName();
+ qmlElement.horizontalAlignment =
+ scopeObject->property("horizontalAlignment").toInt();
+ qmlElement.verticalAlignment = scopeObject->property("verticalAlignment").toInt();
+
+ QQmlType qmlType = QQmlMetaType::qmlType(metaObject);
+ qmlElement.elementType = qmlType.qmlTypeName() + "/" + qmlType.typeName();
+ qmlElements.append(qmlElement);
+
+ } else {
+ QString warningMessage = "(QQmlDebugTranslationService can not resolve %1 - %2:"\
+ " this should never happen)";
+ const QString id = qmlContext(scopeObject)->nameForObject(scopeObject);
+ qWarning().noquote() << warningMessage.arg(id, propertyName);
+ }
+ }
+ std::sort(qmlElements.begin(), qmlElements.end(), [](const auto &l1, const auto &l2){
+ return l1.codeMarker < l2.codeMarker;
+ });
+
+ packet << qmlElements;
+ emit q->messageToClient(q->name(), packet.data());
+ }
+
+ void sendLanguageChanged()
+ {
+ QVersionedPacket<QQmlDebugConnector> packet;
+ packet << Reply::LanguageChanged;
+ emit q->messageToClient(q->name(), packet.data());
+ }
+
+ void sendMissingTranslations()
+ {
+ QVersionedPacket<QQmlDebugConnector> packet;
+ packet << Reply::MissingTranslations;
+
+ QVector<TranslationIssue> issues;
+ for (auto &&information : qAsConst(objectTranslationBindingMultiMap)) {
+ if (!proxyTranslator->hasTranslation(information)) {
+ TranslationIssue issue;
+ issue.type = TranslationIssue::Type::Missing;
+ issue.codeMarker = codeMarker(information);
+ issue.language = proxyTranslator->currentUILanguages();
+ issues.append(issue);
+ }
+ }
+ std::sort(issues.begin(), issues.end(), [](const auto &l1, const auto &l2){
+ return l1.codeMarker < l2.codeMarker;
+ });
+ packet << issues;
+ emit q->messageToClient(q->name(), packet.data());
+ }
+
+ void sendElidedTextWarning(const TranslationBindingInformation &information)
+ {
+ QVersionedPacket<QQmlDebugConnector> packet;
+ packet << Reply::TextElided;
+
+ TranslationIssue issue;
+ issue.type = TranslationIssue::Type::Elided;
+ issue.codeMarker = codeMarker(information);
+ issue.language = proxyTranslator->currentUILanguages();
+
+ packet << issue;
+ emit q->messageToClient(q->name(), packet.data());
+ }
+
+ QQmlDebugTranslationServiceImpl *q;
+
+ bool watchTextElides = false;
+ QMultiMap<QObject*, TranslationBindingInformation> objectTranslationBindingMultiMap;
+ QHash<QObject*, QVector<QMetaObject::Connection>> elideConnections;
+ ProxyTranslator *proxyTranslator;
+
+ bool enableWatchTranslations = false;
+ QTimer translatableTextOccurrenceTimer;
+ QList<QPointer<QQuickItem>> translatableTextOccurrences;
+
+ QPointer<QQuickView> currentQuickView;
+private:
+ CodeMarker codeMarker(const TranslationBindingInformation &information)
+ {
+ CodeMarker c;
+ c.url = information.compilationUnit->url();
+ c.line = information.compiledBinding->valueLocation.line;
+ c.column = information.compiledBinding->valueLocation.column;
+ return c;
+ }
+};
+
+QQmlDebugTranslationServiceImpl::QQmlDebugTranslationServiceImpl(QObject *parent)
+ : QQmlDebugTranslationService(1, parent)
{
+ d = new QQmlDebugTranslationServicePrivate(this);
+
+ connect(this, &QQmlDebugTranslationServiceImpl::watchTextElides,
+ d, &QQmlDebugTranslationServicePrivate::setWatchTextElides,
+ Qt::QueuedConnection);
+
+ connect(this, &QQmlDebugTranslationServiceImpl::language,
+ d->proxyTranslator, &ProxyTranslator::setLanguage,
+ Qt::QueuedConnection);
+
+ connect(this, &QQmlDebugTranslationServiceImpl::state,
+ d, &QQmlDebugTranslationServicePrivate::setState,
+ Qt::QueuedConnection);
+
+ connect(this, &QQmlDebugTranslationServiceImpl::stateList, d,
+ &QQmlDebugTranslationServicePrivate::sendStateList, Qt::QueuedConnection);
+
+ connect(d->proxyTranslator, &ProxyTranslator::languageChanged,
+ d, &QQmlDebugTranslationServicePrivate::sendLanguageChanged);
+
+ connect(this, &QQmlDebugTranslationServiceImpl::missingTranslations,
+ d, &QQmlDebugTranslationServicePrivate::sendMissingTranslations);
+
+ connect(this, &QQmlDebugTranslationServiceImpl::sendTranslatableTextOccurrences,
+ d, &QQmlDebugTranslationServicePrivate::sendTranslatableTextOccurrences,
+ Qt::QueuedConnection);
+}
+
+QQmlDebugTranslationServiceImpl::~QQmlDebugTranslationServiceImpl()
+{
+ delete d->proxyTranslator;
+ d->proxyTranslator = {};
}
void QQmlDebugTranslationServiceImpl::messageReceived(const QByteArray &message)
{
- Q_UNUSED(message);
+ QVersionedPacket<QQmlDebugConnector> packet(message);
+ QQmlDebugTranslation::Request command;
+
+ packet >> command;
+ switch (command) {
+ case QQmlDebugTranslation::Request::ChangeLanguage: {
+ QUrl context;
+ QString locale;
+ packet >> context >> locale;
+ emit language(context, QLocale(locale));
+ break;
+ }
+ case QQmlDebugTranslation::Request::ChangeState: {
+ QString stateName;
+ packet >> stateName;
+ emit state(stateName);
+ break;
+ }
+ case QQmlDebugTranslation::Request::StateList: {
+ emit stateList();
+ break;
+ }
+ case QQmlDebugTranslation::Request::MissingTranslations: {
+ emit missingTranslations();
+ break;
+ }
+ case QQmlDebugTranslation::Request::TranslatableTextOccurrences: {
+ emit sendTranslatableTextOccurrences();
+ break;
+ }
+ case QQmlDebugTranslation::Request::WatchTextElides: {
+ emit watchTextElides(true);
+ break;
+ }
+ case QQmlDebugTranslation::Request::DisableWatchTextElides: {
+ emit watchTextElides(false);
+ break;
+ }
+ default: {
+ qWarning() << "DebugTranslationService: received unknown command: " << static_cast<int>(command);
+ break;
+ }
+ } // switch (command)
+}
+
+void QQmlDebugTranslationServiceImpl::engineAboutToBeAdded(QJSEngine *engine)
+{
+ if (QQmlEngine *qmlEngine = qobject_cast<QQmlEngine *>(engine))
+ d->proxyTranslator->addEngine(qmlEngine);
+
+ if (engine->parent())
+ d->currentQuickView = qobject_cast<QQuickView*>(engine->parent());
+
+ emit attachedToEngine(engine);
+}
+
+void QQmlDebugTranslationServiceImpl::engineAboutToBeRemoved(QJSEngine *engine)
+{
+ if (QQmlEngine *qmlEngine = qobject_cast<QQmlEngine *>(engine))
+ d->proxyTranslator->removeEngine(qmlEngine);
+ emit detachedFromEngine(engine);
}
QString QQmlDebugTranslationServiceImpl::foundElidedText(QObject *textObject, const QString &layoutText, const QString &elideText)
{
- Q_UNUSED(textObject);
- Q_UNUSED(layoutText);
- return elideText;
+ Q_UNUSED(layoutText)
+ QString elidedTextResult = elideText;
+ // do the check only for text objects which have translation bindings
+ auto it = d->objectTranslationBindingMultiMap.find(textObject);
+ if (it != d->objectTranslationBindingMultiMap.end()) {
+ if (QQuickItem* quickItem = qobject_cast<QQuickItem*>(textObject)) {
+ //const QColor originColor = quickItem->color();
+ const TranslationBindingInformation information = d->objectTranslationBindingMultiMap.value(quickItem);
+ if (d->watchTextElides && d->proxyTranslator->hasTranslation(information)) {
+ d->sendElidedTextWarning(information);
+ }
+ if (!d->elideConnections.contains(quickItem)) {
+ // add "refresh" elide state connections which remove themself
+ auto clearElideInformation = [=]() {
+ //quickItem->setColor(originColor);
+ for (QMetaObject::Connection connection : d->elideConnections.value(quickItem))
+ quickItem->disconnect(connection);
+ d->elideConnections.remove(quickItem);
+ };
+
+ auto connectWithChangedWidthThreshold = [=] () {
+ return connect(quickItem, &QQuickItem::widthChanged, [=]() {
+ if (quickItem->implicitWidth() <= quickItem->width())
+ clearElideInformation();
+ });
+ };
+ auto connectImplicitWidthChangedThreshold = [=] () {
+ return connect(quickItem, &QQuickItem::implicitWidthChanged, [=]() {
+ if (quickItem->implicitWidth() <= quickItem->width())
+ clearElideInformation();
+ });
+ };
+
+ d->elideConnections.insert(quickItem,
+ {connectWithChangedWidthThreshold(),
+ connectImplicitWidthChangedThreshold()});
+ }
+ }
+ }
+ return elidedTextResult;
}
-void QQmlDebugTranslationServiceImpl::foundTranslationBinding(
- QQmlTranslationBinding *binding, QObject *scopeObject,
- const QQmlRefPointer<QQmlContextData> &contextData)
+void QQmlDebugTranslationServiceImpl::foundTranslationBinding(const TranslationBindingInformation &translationBindingInformation)
{
- Q_UNUSED(binding);
- Q_UNUSED(scopeObject);
- Q_UNUSED(contextData);
+ QObject *scopeObject = translationBindingInformation.scopeObject;
+ connect(scopeObject, &QObject::destroyed, [this, scopeObject] () {
+ this->d->objectTranslationBindingMultiMap.remove(scopeObject);
+ });
+ d->objectTranslationBindingMultiMap.insert(scopeObject, translationBindingInformation);
}
QT_END_NAMESPACE
+
+#include <qqmldebugtranslationservice.moc>
diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmldebugtranslationservice.h b/src/plugins/qmltooling/qmldbg_preview/qqmldebugtranslationservice.h
index 802f21ecce..72e70f4b29 100644
--- a/src/plugins/qmltooling/qmldbg_preview/qqmldebugtranslationservice.h
+++ b/src/plugins/qmltooling/qmldbg_preview/qqmldebugtranslationservice.h
@@ -36,9 +36,8 @@
** $QT_END_LICENSE$
**
****************************************************************************/
-
-#ifndef QDEBUGMESSAGESERVICE_H
-#define QDEBUGMESSAGESERVICE_H
+#ifndef QQMLDEBUGTRANSLATIONSERVICE_H
+#define QQMLDEBUGTRANSLATIONSERVICE_H
//
// W A R N I N G
@@ -50,39 +49,44 @@
//
// We mean it.
//
+#include <QtCore/qglobal.h>
#include <private/qqmldebugserviceinterfaces_p.h>
-#include <QtCore/qlogging.h>
-#include <QtCore/qmutex.h>
-#include <QtCore/qelapsedtimer.h>
+#include <QtCore/qbytearray.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qurl.h>
+#include <QtGui/qcolor.h>
QT_BEGIN_NAMESPACE
class QQmlDebugTranslationServicePrivate;
-
class QQmlDebugTranslationServiceImpl : public QQmlDebugTranslationService
{
Q_OBJECT
public:
- //needs to be in sync with QQmlDebugTranslationClient in qqmldebugtranslationclient_p.h
- enum Command {
- ChangeLanguage,
- ChangeWarningColor,
- ChangeElidedTextWarningString,
- SetDebugTranslationServiceLogFile,
- EnableElidedTextWarning,
- DisableElidedTextWarning,
- TestAllLanguages
- };
QQmlDebugTranslationServiceImpl(QObject *parent = 0);
+ ~QQmlDebugTranslationServiceImpl();
QString foundElidedText(QObject *textObject, const QString &layoutText, const QString &elideText) override;
- void foundTranslationBinding(QQmlTranslationBinding *binding, QObject *scopeObject,
- const QQmlRefPointer<QQmlContextData> &contextData) override;
+ void foundTranslationBinding(const TranslationBindingInformation &translationBindingInformation) override;
+
void messageReceived(const QByteArray &message) override;
+ void engineAboutToBeAdded(QJSEngine *engine) override;
+ void engineAboutToBeRemoved(QJSEngine *engine) override;
+
+signals:
+ void language(const QUrl &context, const QLocale &locale);
+ void state(const QString &stateName);
+ void stateList();
+ void watchTextElides(bool);
+ void missingTranslations();
+ void sendTranslatableTextOccurrences();
+
+private:
+ QQmlDebugTranslationServicePrivate *d;
};
QT_END_NAMESPACE
-#endif // QDEBUGMESSAGESERVICE_H
+#endif // QQMLDEBUGTRANSLATIONSERVICE_H
diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.cpp b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.cpp
index c9317edb44..b8453128d8 100644
--- a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.cpp
+++ b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.cpp
@@ -42,7 +42,6 @@
#include <QtCore/qtimer.h>
#include <QtCore/qsettings.h>
#include <QtCore/qlibraryinfo.h>
-#include <QtCore/qtranslator.h>
#include <QtGui/qwindow.h>
#include <QtGui/qguiapplication.h>
@@ -93,9 +92,6 @@ QQmlPreviewHandler::QQmlPreviewHandler(QObject *parent) : QObject(parent)
QQmlPreviewHandler::~QQmlPreviewHandler()
{
-#if QT_CONFIG(translation)
- removeTranslators();
-#endif
clear();
}
@@ -225,41 +221,6 @@ void QQmlPreviewHandler::doZoom()
m_lastPosition.initLastSavedWindowPosition(m_currentWindow);
}
-#if QT_CONFIG(translation)
-void QQmlPreviewHandler::removeTranslators()
-{
- if (!m_qtTranslator.isNull()) {
- QCoreApplication::removeTranslator(m_qtTranslator.get());
- m_qtTranslator.reset();
- }
-
- if (m_qmlTranslator.isNull()) {
- QCoreApplication::removeTranslator(m_qmlTranslator.get());
- m_qmlTranslator.reset();
- }
-}
-
-void QQmlPreviewHandler::language(const QUrl &context, const QLocale &locale)
-{
- removeTranslators();
-
- m_qtTranslator.reset(new QTranslator(this));
- if (m_qtTranslator->load(locale, QLatin1String("qt"), QLatin1String("_"),
- QLibraryInfo::path(QLibraryInfo::TranslationsPath))) {
- QCoreApplication::installTranslator(m_qtTranslator.get());
- }
-
- m_qmlTranslator.reset(new QTranslator(this));
- if (m_qmlTranslator->load(locale, QLatin1String("qml"), QLatin1String("_"),
- context.toLocalFile() + QLatin1String("/i18n"))) {
- QCoreApplication::installTranslator(m_qmlTranslator.get());
- }
-
- for (QQmlEngine *engine : qAsConst(m_engines))
- engine->retranslate();
-}
-#endif
-
void QQmlPreviewHandler::clear()
{
qDeleteAll(m_createdObjects);
diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.h b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.h
index 5dc867b763..b7ee8fa09b 100644
--- a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.h
+++ b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.h
@@ -66,7 +66,6 @@ class QQmlEngine;
class QQuickItem;
class QQmlPreviewUrlInterceptor;
class QQuickWindow;
-class QTranslator;
class QQmlPreviewHandler : public QObject
{
@@ -81,9 +80,6 @@ public:
void loadUrl(const QUrl &url);
void rerun();
void zoom(qreal newFactor);
-#if QT_CONFIG(translation)
- void language(const QUrl &context, const QLocale &locale);
-#endif
void clear();
@@ -117,9 +113,6 @@ private:
void frameSwapped();
void fpsTimerHit();
-#if QT_CONFIG(translation)
- void removeTranslators();
-#endif
QScopedPointer<QQuickItem> m_dummyItem;
QList<QQmlEngine *> m_engines;
@@ -148,11 +141,6 @@ private:
FrameTime m_rendering;
FrameTime m_synchronizing;
-
-#if QT_CONFIG(translation)
- QScopedPointer<QTranslator> m_qtTranslator;
- QScopedPointer<QTranslator> m_qmlTranslator;
-#endif
};
QT_END_NAMESPACE
diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservice.cpp b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservice.cpp
index 2e6aaa5858..b6d6a7a220 100644
--- a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservice.cpp
+++ b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservice.cpp
@@ -64,9 +64,6 @@ QQmlPreviewServiceImpl::QQmlPreviewServiceImpl(QObject *parent) :
connect(this, &QQmlPreviewServiceImpl::load, &m_handler, &QQmlPreviewHandler::loadUrl);
connect(this, &QQmlPreviewServiceImpl::rerun, &m_handler, &QQmlPreviewHandler::rerun);
connect(this, &QQmlPreviewServiceImpl::zoom, &m_handler, &QQmlPreviewHandler::zoom);
-#if QT_CONFIG(translation)
- connect(this, &QQmlPreviewServiceImpl::language, &m_handler, &QQmlPreviewHandler::language);
-#endif
connect(&m_handler, &QQmlPreviewHandler::error, this, &QQmlPreviewServiceImpl::forwardError,
Qt::DirectConnection);
connect(&m_handler, &QQmlPreviewHandler::fps, this, &QQmlPreviewServiceImpl::forwardFps,
@@ -137,16 +134,6 @@ void QQmlPreviewServiceImpl::messageReceived(const QByteArray &data)
emit zoom(static_cast<qreal>(factor));
break;
}
-#if QT_CONFIG(translation)
- case Language: {
- QUrl context;
- QString locale;
- packet >> context >> locale;
- emit language(context.isEmpty() ? m_currentUrl : context,
- locale.isEmpty() ? QLocale() : QLocale(locale));
- break;
- }
-#endif
default:
forwardError(QString::fromLatin1("Invalid command: %1").arg(command));
break;
diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservice.h b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservice.h
index de50e6fc61..56deb7f092 100644
--- a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservice.h
+++ b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservice.h
@@ -73,8 +73,7 @@ public:
Directory,
ClearCache,
Zoom,
- Fps,
- Language
+ Fps
};
static const QString s_key;
@@ -99,9 +98,6 @@ signals:
void rerun();
void clearCache();
void zoom(qreal factor);
-#if QT_CONFIG(translation)
- void language(const QUrl &context, const QLocale &locale);
-#endif
private:
QScopedPointer<QQmlPreviewFileEngineHandler> m_fileEngine;
diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservicefactory.cpp b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservicefactory.cpp
index 6ff9805bbe..23329dbcf2 100644
--- a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservicefactory.cpp
+++ b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservicefactory.cpp
@@ -39,7 +39,9 @@
#include "qqmlpreviewservicefactory.h"
#include "qqmlpreviewservice.h"
+#if QT_CONFIG(translation)
#include "qqmldebugtranslationservice.h"
+#endif
QT_BEGIN_NAMESPACE
@@ -47,9 +49,10 @@ QQmlDebugService *QQmlPreviewServiceFactory::create(const QString &key)
{
if (key == QQmlPreviewServiceImpl::s_key)
return new QQmlPreviewServiceImpl(this);
+#if QT_CONFIG(translation)
if (key == QQmlDebugTranslationServiceImpl::s_key)
return new QQmlDebugTranslationServiceImpl(this);
-
+#endif
return nullptr;
}
diff --git a/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp b/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp
index 13d5292eb2..0e4c90f987 100644
--- a/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp
+++ b/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp
@@ -422,11 +422,13 @@ void QQmlDebugServerImpl::parseArguments()
<< tr("Sends qDebug() and similar messages over the QML debug\n"
"\t\t connection. QtCreator uses this for showing debug\n"
"\t\t messages in the debugger console.") << '\n'
+#if QT_CONFIG(translation)
<< '\n' << QQmlDebugTranslationService::s_key << "\t- "
//: Please preserve the line breaks and formatting
<< tr("helps to see if a translated text\n"
"\t\t will result in an elided text\n"
"\t\t in QML elements.") << '\n'
+#endif //QT_CONFIG(translation)
<< tr("Other services offered by qmltooling plugins that implement "
"QQmlDebugServiceFactory and which can be found in the standard plugin "
"paths will also be available and can be specified. If no \"services\" "