Qmldebugtranslator: report elide issues correctly inside layouts

Task-number: QTBUG-96991
Pick-to: 6.2
Change-Id: I911044893fb6eac54c6fb8f2b236f422bd04a7ae
Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
This commit is contained in:
Tim Jenssen 2021-10-12 13:38:44 +02:00
parent a5f0361622
commit dd96e919c1
9 changed files with 87 additions and 180 deletions

View File

@ -241,10 +241,10 @@ public:
emit q->messageToClient(q->name(), packet.data());
}
void sendMissingTranslations()
void sendTranslationIssues()
{
QVersionedPacket<QQmlDebugConnector> packet;
packet << Reply::MissingTranslations;
packet << Reply::TranslationIssues;
QVector<TranslationIssue> issues;
for (auto &&information : qAsConst(objectTranslationBindingMultiMap)) {
@ -255,6 +255,18 @@ public:
issue.language = proxyTranslator->currentUILanguages();
issues.append(issue);
}
QObject *scopeObject = information.scopeObject;
QQuickText *quickText = static_cast<QQuickText*>(scopeObject);
if (quickText) {
if (quickText->truncated()) {
TranslationIssue issue;
issue.type = TranslationIssue::Type::Elided;
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;
@ -263,20 +275,6 @@ public:
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;
@ -335,8 +333,8 @@ QQmlDebugTranslationServiceImpl::QQmlDebugTranslationServiceImpl(QObject *parent
d, &QQmlDebugTranslationServicePrivate::sendLanguageChanged,
Qt::QueuedConnection);
connect(this, &QQmlDebugTranslationServiceImpl::missingTranslations,
d, &QQmlDebugTranslationServicePrivate::sendMissingTranslations,
connect(this, &QQmlDebugTranslationServiceImpl::translationIssues,
d, &QQmlDebugTranslationServicePrivate::sendTranslationIssues,
Qt::QueuedConnection);
connect(this, &QQmlDebugTranslationServiceImpl::sendTranslatableTextOccurrences,
@ -374,8 +372,8 @@ void QQmlDebugTranslationServiceImpl::messageReceived(const QByteArray &message)
emit stateList();
break;
}
case QQmlDebugTranslation::Request::MissingTranslations: {
emit missingTranslations();
case QQmlDebugTranslation::Request::TranslationIssues: {
emit translationIssues();
break;
}
case QQmlDebugTranslation::Request::TranslatableTextOccurrences: {
@ -415,57 +413,6 @@ void QQmlDebugTranslationServiceImpl::engineAboutToBeRemoved(QJSEngine *engine)
emit detachedFromEngine(engine);
}
QString QQmlDebugTranslationServiceImpl::foundElidedText(QObject *textObject, const QString &layoutText, const QString &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 TranslationBindingInformation information = d->objectTranslationBindingMultiMap.value(quickItem);
QQuickItem* parentItem = quickItem->parentItem();
QString parentTypeName = parentItem->metaObject()->className();
// Currently text fields inside a layout give false signals about elides
// so we just omit them
if (d->watchTextElides && !parentTypeName.endsWith("Layout")) {
d->sendElidedTextWarning(information);
}
if (!d->elideConnections.contains(quickItem)) {
// add "refresh" elide state connections which remove themself
auto clearElideInformation = [this, quickItem]() {
//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(const TranslationBindingInformation &translationBindingInformation)
{
QObject *scopeObject = translationBindingInformation.scopeObject;

View File

@ -68,7 +68,6 @@ public:
QQmlDebugTranslationServiceImpl(QObject *parent = 0);
~QQmlDebugTranslationServiceImpl();
QString foundElidedText(QObject *textObject, const QString &layoutText, const QString &elideText) override;
void foundTranslationBinding(const TranslationBindingInformation &translationBindingInformation) override;
void messageReceived(const QByteArray &message) override;
@ -80,7 +79,8 @@ signals:
void state(const QString &stateName);
void stateList();
void watchTextElides(bool);
void missingTranslations();
void translationIssues();
void elidedTranslations();
void sendTranslatableTextOccurrences();
private:

View File

@ -108,7 +108,6 @@ class QQmlEngineControlService {};
class QQmlNativeDebugService {};
class QQmlDebugTranslationService {
public:
virtual QString foundElidedText(QObject *, const QString &, const QString &) {return {};}
virtual void foundTranslationBinding(const TranslationBindingInformation &) {}
};
@ -186,7 +185,6 @@ class Q_QML_PRIVATE_EXPORT QQmlDebugTranslationService : public QQmlDebugService
public:
static const QString s_key;
virtual QString foundElidedText(QObject *qQuickTextObject, const QString &layoutText, const QString &elideText) = 0;
virtual void foundTranslationBinding(const TranslationBindingInformation &translationBindingInformation) = 0;
protected:
friend class QQmlDebugConnector;

View File

@ -64,19 +64,23 @@ enum class Request {
ChangeLanguage = 1,
StateList,
ChangeState,
MissingTranslations,
TranslationIssues,
TranslatableTextOccurrences,
WatchTextElides,
DisableWatchTextElides,
// following are obsolete, just provided for compilation compatibility
MissingTranslations
};
enum class Reply {
LanguageChanged = 101,
StateList,
StateChanged,
MissingTranslations,
TranslationIssues,
TranslatableTextOccurrences,
TextElided,
// following are obsolete, just provided for compilation compatibility
MissingTranslations,
TextElided
};
inline QDataStream &operator<<(QDataStream &ds, Request r)
@ -124,6 +128,12 @@ inline QByteArray createMissingTranslationsRequest(QDataStream &packet)
return qobject_cast<QBuffer *>(packet.device())->data();
}
inline QByteArray createTranslationIssuesRequest(QDataStream &packet)
{
packet << Request::TranslationIssues;
return qobject_cast<QBuffer *>(packet.device())->data();
}
inline QByteArray createTranslatableTextOccurrencesRequest(QDataStream &packet)
{
packet << Request::TranslatableTextOccurrences;

View File

@ -59,7 +59,7 @@ void QQmlDebugTranslationClient::messageReceived(const QByteArray &message)
packet >> type;
switch (type) {
case QQmlDebugTranslation::Reply::MissingTranslations: {
case QQmlDebugTranslation::Reply::TranslationIssues: {
packet >> translationIssues;
break;
}

View File

@ -1159,12 +1159,6 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline)
elideLayout->setFont(layout.font());
elideLayout->setTextOption(layout.textOption());
#if QT_CONFIG(translation) && QT_CONFIG(qml_debug)
if (QQmlDebugTranslationService *service
= QQmlDebugConnector::service<QQmlDebugTranslationService>()) {
elideText = service->foundElidedText(q, layoutText, elideText);
}
#endif //QT_CONFIG(translation)
elideLayout->setText(elideText);
elideLayout->beginLayout();

View File

@ -75,7 +75,7 @@ private slots:
{
QVersionedPacket<QQmlDebugConnector> packet;
m_debugTranslationClient->sendMessage(
QQmlDebugTranslation::createMissingTranslationsRequest(packet));
QQmlDebugTranslation::createTranslationIssuesRequest(packet));
QTRY_VERIFY(m_debugTranslationClient->translationIssues.size() > 0);
}

View File

@ -30,7 +30,7 @@ import QtQuick
Rectangle {
id: root
width: 200
width: 130
height: 200
property int widthFactor: 7
@ -68,15 +68,6 @@ Rectangle {
}
}
// this is necessary to have the test working for different font sizes and dpi settings
Text {
id: originHelloTextToGetTheNecessaryWidth
text: "short"
opacity: 0
anchors.bottom: root.bottom
onWidthChanged: root.width = originHelloTextToGetTheNecessaryWidth.width * widthFactor
}
states: [
State {
name: "BiggerFontState"
@ -96,10 +87,6 @@ Rectangle {
font.pointSize: 20
}
PropertyChanges {
target: originHelloTextToGetTheNecessaryWidth
font.pointSize: 20
}
},
State {
name: "WayBiggerFontState"
@ -118,11 +105,6 @@ Rectangle {
target: text3
font.pointSize: 30
}
PropertyChanges {
target: originHelloTextToGetTheNecessaryWidth
font.pointSize: 30
}
}
]
}

View File

@ -84,24 +84,23 @@ private slots:
QVERIFY(currentDebugServiceMessage().isEmpty());
}
void verifyMissingAllTranslationsForMissingLanguage()
{
changeLanguage("ru");
auto missingTranslations = getMissingTranslations();
auto translationIssues = getTranslationIssues();
QCOMPARE(missingTranslations.length(), getTranslatableTextOccurrences().count());
QCOMPARE(missingTranslations.at(0).language, "ru ru-RU ru-Cyrl-RU");
QCOMPARE(translationIssues.length(), getTranslatableTextOccurrences().count());
QCOMPARE(translationIssues.at(0).language, "ru ru-RU ru-Cyrl-RU");
}
void verifyCorrectNumberOfMissingTranslations()
{
changeLanguage("fr");
auto missingTranslations = getMissingTranslations();
auto translationIssues = getTranslationIssues();
QCOMPARE(missingTranslations.length(), 3);
QCOMPARE(missingTranslations.at(0).language, "fr fr-FR fr-Latn-FR");
QCOMPARE(translationIssues.length(), 3);
QCOMPARE(translationIssues.at(0).language, "fr fr-FR fr-Latn-FR");
}
void verifyCorrectNumberOfTranslatableTextOccurrences()
@ -114,6 +113,43 @@ private slots:
QCOMPARE(getStates().length(), 2);
}
void getElideWarnings()
{
QVersionedPacket<QQmlDebugConnector> packet;
sendMessageToService(createWatchTextElidesRequest(packet));
changeLanguage("es");
auto translationIssues = getTranslationIssues();
int elideWarningCount = 0;
for (auto issue : translationIssues) {
if (issue.type == TranslationIssue::Type::Elided) {
elideWarningCount++;
}
}
QCOMPARE(elideWarningCount, 1);
}
void getElideWarningsWhenStateChanged()
{
QVersionedPacket<QQmlDebugConnector> packet;
sendMessageToService(createWatchTextElidesRequest(packet));
changeLanguage("es");
sendMessageToService(createChangeStateRequest(packet, "WayBiggerFontState"));
auto translationIssues = getTranslationIssues();
int elideWarningCount = 0;
for (auto issue : translationIssues) {
if (issue.type == TranslationIssue::Type::Elided) {
elideWarningCount++;
}
}
QCOMPARE(elideWarningCount, 1);
}
void loopThroughAllStates()
{
QVector<QmlState> stateList = getStates();
@ -137,59 +173,6 @@ private slots:
}
}
void getElideWarnings()
{
QVersionedPacket<QQmlDebugConnector> packet;
sendMessageToService(createWatchTextElidesRequest(packet));
changeLanguage("fr");
// after language changes, we get elide warnings
auto replies = currentReply();
int elideCount = 0;
for (auto reply : replies) {
QVersionedPacket<QQmlDebugConnector> readPacket(reply);
TranslationIssue issue;
Reply replyType;
readPacket >> replyType;
if (replyType == Reply::TextElided) {
readPacket >> issue;
QCOMPARE(issue.codeMarker.line, 47);
QCOMPARE(issue.language, "fr fr-FR fr-Latn-FR");
elideCount++;
}
}
}
void getElideWarningsWhenStateChanged()
{
QVersionedPacket<QQmlDebugConnector> packet;
sendMessageToService(createWatchTextElidesRequest(packet));
changeLanguage("fr");
const QString stateName("BiggerFontState");
sendMessageToService(createChangeStateRequest(packet, stateName));
auto replies = currentReply();
int elideCount = 0;
for (auto reply : replies) {
QVersionedPacket<QQmlDebugConnector> readPacket(reply);
TranslationIssue issue;
Reply replyType;
readPacket >> replyType;
if (replyType == Reply::TextElided) {
readPacket >> issue;
QCOMPARE(issue.codeMarker.line, 47);
elideCount++;
}
}
}
private:
QVector<QmlElement> getTranslatableTextOccurrences()
@ -231,18 +214,18 @@ private:
// QTest::qWait(500);
}
QVector<TranslationIssue> getMissingTranslations()
QVector<TranslationIssue> getTranslationIssues()
{
QVersionedPacket<QQmlDebugConnector> packet;
sendMessageToService(createMissingTranslationsRequest(packet));
sendMessageToService(createTranslationIssuesRequest(packet));
QVersionedPacket<QQmlDebugConnector> readPacket(currentReply().at(0));
Reply replyType;
QVector<TranslationIssue> missingTranslations;
QVector<TranslationIssue> translationIssues;
readPacket >> replyType;
readPacket >> missingTranslations;
readPacket >> translationIssues;
return missingTranslations;
return translationIssues;
}
QByteArray debugServiceMessage(const QByteArray &data)
@ -323,12 +306,10 @@ private:
return "LanguageChanged";
case Reply::StateChanged:
return "StateChanged";
case Reply::MissingTranslations:
return "MissingTranslations";
case Reply::TranslationIssues:
return "TranslationIssues";
case Reply::TranslatableTextOccurrences:
return "TranslatableTextOccurrences";
case Reply::TextElided:
return "TextElided";
default:
Q_ASSERT_X(false, "not implemented", "not implemented");
}
@ -341,7 +322,7 @@ private:
QVersionedPacket<QQmlDebugConnector> readPacket(message);
readPacket >> replyType;
debugString.append(replyTypeToString(replyType));
if (replyType == Reply::MissingTranslations) {
if (replyType == Reply::TranslationIssues) {
QVector<TranslationIssue> translationIssues;
readPacket >> translationIssues;
QStringList translationIssueStrings;
@ -356,11 +337,6 @@ private:
debugString.append(translationIssuesString.arg(QString::number(translationIssues.size()),
translationIssueStrings.join("; ")));
}
if (replyType == Reply::TextElided) {
TranslationIssue translationIssue;
readPacket >> translationIssue;
debugString.append(QString(" %1 ").arg(translationIssue.toDebugString()));
}
}
return debugString;
}