Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
uiformpreviewview.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
5#include "messagemodel.h"
6
7#include <quiloader.h>
8
9#include <QtWidgets/QApplication>
10#ifndef QT_NO_COMBOBOX
11# ifndef QT_NO_FONTCOMBOBOX
12# include <QtWidgets/QFontComboBox>
13# else
14# include <QtWidgets/QComboBox>
15# endif
16#endif // QT_NO_COMBOBOX
17#include <QtWidgets/QFrame>
18#include <QtWidgets/QGridLayout>
19#include <QtWidgets/QListWidget>
20#include <QtWidgets/QMdiArea>
21#include <QtWidgets/QMdiSubWindow>
22#include <QtWidgets/QMenu>
23#include <QtWidgets/QStackedLayout>
24#include <QtWidgets/QStackedWidget>
25#include <QtWidgets/QTableWidget>
26#include <QtWidgets/QTabWidget>
27#include <QtWidgets/QToolBox>
28#include <QtWidgets/QTreeWidget>
29#include <QtWidgets/QScrollArea>
30
31#include <QtGui/QAction>
32
33#include <QtCore/QDebug>
34#include <QtCore/QTime>
35
37
38#if defined(Q_CC_SUN) || defined(Q_CC_HPACC) || defined(Q_CC_XLC)
39size_t qHash(const QUiTranslatableStringValue &tsv)
40#else
41static size_t qHash(const QUiTranslatableStringValue &tsv)
42#endif
43{
44 return qHash(tsv.value()) ^ qHash(tsv.qualifier());
45}
46
47static bool operator==(const QUiTranslatableStringValue &tsv1, const QUiTranslatableStringValue &tsv2)
48{
49 return tsv1.value() == tsv2.value() && tsv1.qualifier() == tsv2.qualifier();
50}
51
52#define INSERT_TARGET(_tsv, _type, _target, _prop)
53 do {
54 target.type = _type;
55 target.target._target;
56 target.prop._prop;
57 (*targets)[qvariant_cast<QUiTranslatableStringValue>(_tsv)].append(target);
58 } while (0)
59
60static void registerTreeItem(QTreeWidgetItem *item, TargetsHash *targets)
61{
62 const QUiItemRolePair *irs = QFormInternal::qUiItemRoles;
63
64 int cnt = item->columnCount();
65 for (int i = 0; i < cnt; ++i) {
66 for (unsigned j = 0; irs[j].shadowRole >= 0; j++) {
67 QVariant v = item->data(i, irs[j].shadowRole);
68 if (v.isValid()) {
69 TranslatableEntry target;
70 target.prop.treeIndex.column = i;
71 INSERT_TARGET(v, TranslatableTreeWidgetItem, treeWidgetItem = item, treeIndex.index = j);
72 }
73 }
74 }
75
76 cnt = item->childCount();
77 for (int j = 0; j < cnt; ++j)
78 registerTreeItem(item->child(j), targets);
79}
80
81#define REGISTER_ITEM_CORE(item, propType, targetName)
82 const QUiItemRolePair *irs = QFormInternal::qUiItemRoles;
83 for (unsigned j = 0; irs[j].shadowRole >= 0; j++) {
84 QVariant v = item->data(irs[j].shadowRole);
85 if (v.isValid())
86 INSERT_TARGET(v, propType, targetName = item, index = j);
87 }
88
89static void registerListItem(QListWidgetItem *item, TargetsHash *targets)
90{
91 TranslatableEntry target;
93}
94
95static void registerTableItem(QTableWidgetItem *item, TargetsHash *targets)
96{
97 if (!item)
98 return;
99
100 TranslatableEntry target;
101 REGISTER_ITEM_CORE(item, TranslatableTableWidgetItem, tableWidgetItem);
102}
103
104#define REGISTER_SUBWIDGET_PROP(mainWidget, propType, propName)
105 do {
106 QVariant v = mainWidget->widget(i)->property(propName);
107 if (v.isValid())
108 INSERT_TARGET(v, propType, object = mainWidget, index = i);
109 } while (0)
110
111static void buildTargets(QObject *o, TargetsHash *targets)
112{
113 TranslatableEntry target;
114
115 const auto propNames = o->dynamicPropertyNames();
116 for (const QByteArray &prop : propNames) {
117 if (prop.startsWith(PROP_GENERIC_PREFIX)) {
118 const QByteArray propName = prop.mid(sizeof(PROP_GENERIC_PREFIX) - 1);
119 INSERT_TARGET(o->property(prop),
120 TranslatableProperty, object = o, name = qstrdup(propName.data()));
121 }
122 }
123 if (0) {
124#ifndef QT_NO_TABWIDGET
125 } else if (QTabWidget *tabw = qobject_cast<QTabWidget*>(o)) {
126 const int cnt = tabw->count();
127 for (int i = 0; i < cnt; ++i) {
128 REGISTER_SUBWIDGET_PROP(tabw, TranslatableTabPageText, PROP_TABPAGETEXT);
129# ifndef QT_NO_TOOLTIP
130 REGISTER_SUBWIDGET_PROP(tabw, TranslatableTabPageToolTip, PROP_TABPAGETOOLTIP);
131# endif
132# ifndef QT_NO_WHATSTHIS
133 REGISTER_SUBWIDGET_PROP(tabw, TranslatableTabPageWhatsThis, PROP_TABPAGEWHATSTHIS);
134# endif
135 }
136#endif
137#ifndef QT_NO_TOOLBOX
138 } else if (QToolBox *toolw = qobject_cast<QToolBox*>(o)) {
139 const int cnt = toolw->count();
140 for (int i = 0; i < cnt; ++i) {
141 REGISTER_SUBWIDGET_PROP(toolw, TranslatableToolItemText, PROP_TOOLITEMTEXT);
142# ifndef QT_NO_TOOLTIP
143 REGISTER_SUBWIDGET_PROP(toolw, TranslatableToolItemToolTip, PROP_TOOLITEMTOOLTIP);
144# endif
145 }
146#endif
147#ifndef QT_NO_COMBOBOX
148 } else if (QComboBox *combow = qobject_cast<QComboBox*>(o)) {
149# ifndef QT_NO_FONTCOMBOBOX
150 if (!qobject_cast<QFontComboBox*>(o)) {
151# else
152 {
153# endif
154 const int cnt = combow->count();
155 for (int i = 0; i < cnt; ++i) {
156 const QVariant v = combow->itemData(i, Qt::DisplayPropertyRole);
157 if (v.isValid())
158 INSERT_TARGET(v, TranslatableComboBoxItem, comboBox = combow, index = i);
159 }
160 }
161#endif // QT_NO_COMBOBOX
162#ifndef QT_NO_LISTWIDGET
163 } else if (QListWidget *listw = qobject_cast<QListWidget*>(o)) {
164 const int cnt = listw->count();
165 for (int i = 0; i < cnt; ++i)
166 registerListItem(listw->item(i), targets);
167#endif
168#ifndef QT_NO_TABLEWIDGET
169 } else if (QTableWidget *tablew = qobject_cast<QTableWidget*>(o)) {
170 const int row_cnt = tablew->rowCount();
171 const int col_cnt = tablew->columnCount();
172 for (int j = 0; j < col_cnt; ++j)
173 registerTableItem(tablew->horizontalHeaderItem(j), targets);
174 for (int i = 0; i < row_cnt; ++i) {
175 registerTableItem(tablew->verticalHeaderItem(i), targets);
176 for (int j = 0; j < col_cnt; ++j)
177 registerTableItem(tablew->item(i, j), targets);
178 }
179#endif
180#ifndef QT_NO_TREEWIDGET
181 } else if (QTreeWidget *treew = qobject_cast<QTreeWidget*>(o)) {
182 if (QTreeWidgetItem *item = treew->headerItem())
183 registerTreeItem(item, targets);
184 const int cnt = treew->topLevelItemCount();
185 for (int i = 0; i < cnt; ++i)
186 registerTreeItem(treew->topLevelItem(i), targets);
187#endif
188 }
189 for (QObject *co : o->children())
190 buildTargets(co, targets);
191}
192
193static void destroyTargets(TargetsHash *targets)
194{
195 for (const auto &targetList : std::as_const(*targets))
196 for (const TranslatableEntry &target : targetList)
197 if (target.type == TranslatableProperty)
198 delete target.prop.name;
199 targets->clear();
200}
201
202static void retranslateTarget(const TranslatableEntry &target, const QString &text)
203{
204 switch (target.type) {
206 target.target.object->setProperty(target.prop.name, text);
207 break;
208#ifndef QT_NO_TABWIDGET
210 target.target.tabWidget->setTabText(target.prop.index, text);
211 break;
212# ifndef QT_NO_TOOLTIP
214 target.target.tabWidget->setTabToolTip(target.prop.index, text);
215 break;
216# endif
217# ifndef QT_NO_WHATSTHIS
219 target.target.tabWidget->setTabWhatsThis(target.prop.index, text);
220 break;
221# endif
222#endif // QT_NO_TABWIDGET
223#ifndef QT_NO_TOOLBOX
225 target.target.toolBox->setItemText(target.prop.index, text);
226 break;
227# ifndef QT_NO_TOOLTIP
229 target.target.toolBox->setItemToolTip(target.prop.index, text);
230 break;
231# endif
232#endif // QT_NO_TOOLBOX
233#ifndef QT_NO_COMBOBOX
235 target.target.comboBox->setItemText(target.prop.index, text);
236 break;
237#endif
238#ifndef QT_NO_LISTWIDGET
240 target.target.listWidgetItem->setData(target.prop.index, text);
241 break;
242#endif
243#ifndef QT_NO_TABLEWIDGET
245 target.target.tableWidgetItem->setData(target.prop.index, text);
246 break;
247#endif
248#ifndef QT_NO_TREEWIDGET
250 target.target.treeWidgetItem->setData(target.prop.treeIndex.column,
251 target.prop.treeIndex.index, text);
252 break;
253#endif
254 }
255}
256
257static void retranslateTargets(const QList<TranslatableEntry> &targets,
258 const QUiTranslatableStringValue &tsv, const DataModel *dataModel,
259 const QString &className, const QString &labelName)
260{
261 QString sourceText = QString::fromUtf8(tsv.value());
262 QString text;
263 if (MessageItem *msg = dataModel->findMessage(className, labelName, sourceText,
264 QString::fromUtf8(tsv.qualifier())))
265 text = msg->translation();
266 if (text.isEmpty() && !tsv.value().isEmpty())
267 text = u'#' + sourceText;
268
269 for (const TranslatableEntry &target : targets)
270 retranslateTarget(target, text);
271}
272
273static void bringToFront(QWidget *w)
274{
275 for (; QWidget *pw = w->parentWidget(); w = pw) {
276#ifndef QT_NO_STACKEDWIDGET
277 if (QStackedWidget *stack = qobject_cast<QStackedWidget *>(pw)) {
278#ifndef QT_NO_TABWIDGET
279 // Updating QTabWidget's embedded QStackedWidget does not update its
280 // QTabBar, so handle tab widgets explicitly.
281 if (QTabWidget *tab = qobject_cast<QTabWidget *>(stack->parent()))
282 tab->setCurrentWidget(w);
283 else
284#endif
285 stack->setCurrentWidget(w);
286 continue;
287 }
288#endif
289#ifndef QT_NO_TOOLBOX
290 if (QScrollArea *sv = qobject_cast<QScrollArea *>(pw)) {
291 if (QToolBox *tb = qobject_cast<QToolBox *>(sv->parent()))
292 tb->setCurrentWidget(w);
293 }
294#endif
295 }
296}
297
298static void highlightTreeWidgetItem(QTreeWidgetItem *item, int col, bool on)
299{
300 QVariant br = item->data(col, Qt::BackgroundRole + 500);
301 QVariant fr = item->data(col, Qt::ForegroundRole + 500);
302 if (on) {
303 if (!br.isValid() && !fr.isValid()) {
304 item->setData(col, Qt::BackgroundRole + 500, item->data(col, Qt::BackgroundRole));
305 item->setData(col, Qt::ForegroundRole + 500, item->data(col, Qt::ForegroundRole));
306 QPalette pal = qApp->palette();
307 item->setData(col, Qt::BackgroundRole, pal.color(QPalette::Dark));
308 item->setData(col, Qt::ForegroundRole, pal.color(QPalette::Light));
309 }
310 } else {
311 if (br.isValid() || fr.isValid()) {
312 item->setData(col, Qt::BackgroundRole, br);
313 item->setData(col, Qt::ForegroundRole, fr);
314 item->setData(col, Qt::BackgroundRole + 500, QVariant());
315 item->setData(col, Qt::ForegroundRole + 500, QVariant());
316 }
317 }
318}
319
320template <class T>
321static void highlightWidgetItem(T *item, bool on)
322{
323 QVariant br = item->data(Qt::BackgroundRole + 500);
324 QVariant fr = item->data(Qt::ForegroundRole + 500);
325 if (on) {
326 if (!br.isValid() && !fr.isValid()) {
327 item->setData(Qt::BackgroundRole + 500, item->data(Qt::BackgroundRole));
328 item->setData(Qt::ForegroundRole + 500, item->data(Qt::ForegroundRole));
329 QPalette pal = qApp->palette();
330 item->setData(Qt::BackgroundRole, pal.color(QPalette::Dark));
331 item->setData(Qt::ForegroundRole, pal.color(QPalette::Light));
332 }
333 } else {
334 if (br.isValid() || fr.isValid()) {
335 item->setData(Qt::BackgroundRole, br);
336 item->setData(Qt::ForegroundRole, fr);
337 item->setData(Qt::BackgroundRole + 500, QVariant());
338 item->setData(Qt::ForegroundRole + 500, QVariant());
339 }
340 }
341}
342
343#define AUTOFILL_BACKUP_PROP "_q_linguist_autoFillBackup"
344#define PALETTE_BACKUP_PROP "_q_linguist_paletteBackup"
345#define FONT_BACKUP_PROP "_q_linguist_fontBackup"
346
347static void highlightWidget(QWidget *w, bool on);
348
349static void highlightAction(QAction *a, bool on)
350{
351 QVariant bak = a->property(FONT_BACKUP_PROP);
352 if (on) {
353 if (!bak.isValid()) {
354 QFont fnt = qApp->font();
355 a->setProperty(FONT_BACKUP_PROP, QVariant::fromValue(a->font().resolve(fnt)));
356 fnt.setBold(true);
357 fnt.setItalic(true);
358 a->setFont(fnt);
359 }
360 } else {
361 if (bak.isValid()) {
362 a->setFont(qvariant_cast<QFont>(bak));
363 a->setProperty(FONT_BACKUP_PROP, QVariant());
364 }
365 }
366 for (QObject *o : a->associatedObjects()) {
367 if (QWidget *w = qobject_cast<QWidget *>(o))
368 highlightWidget(w, on);
369 }
370}
371
372static void highlightWidget(QWidget *w, bool on)
373{
374 QVariant bak = w->property(PALETTE_BACKUP_PROP);
375 if (on) {
376 if (!bak.isValid()) {
377 QPalette pal = qApp->palette();
378 for (QObject *co : w->children())
379 if (QWidget *cw = qobject_cast<QWidget *>(co))
380 cw->setPalette(cw->palette().resolve(pal));
381 w->setProperty(PALETTE_BACKUP_PROP, QVariant::fromValue(w->palette().resolve(pal)));
382 w->setProperty(AUTOFILL_BACKUP_PROP, QVariant::fromValue(w->autoFillBackground()));
383 QColor col1 = pal.color(QPalette::Dark);
384 QColor col2 = pal.color(QPalette::Light);
385 pal.setColor(QPalette::Base, col1);
386 pal.setColor(QPalette::Window, col1);
387 pal.setColor(QPalette::Button, col1);
388 pal.setColor(QPalette::Text, col2);
389 pal.setColor(QPalette::WindowText, col2);
390 pal.setColor(QPalette::ButtonText, col2);
391 pal.setColor(QPalette::BrightText, col2);
392 w->setPalette(pal);
393 w->setAutoFillBackground(true);
394 }
395 } else {
396 if (bak.isValid()) {
397 w->setPalette(qvariant_cast<QPalette>(bak));
398 w->setAutoFillBackground(qvariant_cast<bool>(w->property(AUTOFILL_BACKUP_PROP)));
399 w->setProperty(PALETTE_BACKUP_PROP, QVariant());
400 w->setProperty(AUTOFILL_BACKUP_PROP, QVariant());
401 }
402 }
403 if (QMenu *m = qobject_cast<QMenu *>(w))
404 if (m->menuAction())
405 highlightAction(m->menuAction(), on);
406}
407
408static void highlightTarget(const TranslatableEntry &target, bool on)
409{
410 switch (target.type) {
412 if (QAction *a = qobject_cast<QAction *>(target.target.object)) {
414 } else if (QWidget *w = qobject_cast<QWidget *>(target.target.object)) {
417 }
418 break;
419#ifndef QT_NO_COMBOBOX
421 static_cast<QComboBox *>(target.target.object)->setCurrentIndex(target.prop.index);
422 goto frontAndHighlight;
423#endif
424#ifndef QT_NO_TABWIDGET
426 static_cast<QTabWidget *>(target.target.object)->setCurrentIndex(target.prop.index);
427 goto frontAndHighlight;
428# ifndef QT_NO_TOOLTIP
430# endif
431# ifndef QT_NO_WHATSTHIS
433# endif
434#endif // QT_NO_TABWIDGET
435#ifndef QT_NO_TOOLBOX
437# ifndef QT_NO_TOOLTIP
439# endif
440#endif // QT_NO_TOOLBOX
441#if !defined(QT_NO_COMBOBOX) || !defined(QT_NO_TABWIDGET)
442 frontAndHighlight:
443#endif
444 bringToFront(static_cast<QWidget *>(target.target.object));
445 highlightWidget(static_cast<QWidget *>(target.target.object), on);
446 break;
447#ifndef QT_NO_LISTWIDGET
449 bringToFront(target.target.listWidgetItem->listWidget());
450 highlightWidgetItem(target.target.listWidgetItem, on);
451 break;
452#endif
453#ifndef QT_NO_TABLEWIDGET
455 bringToFront(target.target.tableWidgetItem->tableWidget());
456 highlightWidgetItem(target.target.tableWidgetItem, on);
457 break;
458#endif
459#ifndef QT_NO_TREEWIDGET
461 bringToFront(target.target.treeWidgetItem->treeWidget());
462 highlightTreeWidgetItem(target.target.treeWidgetItem, target.prop.treeIndex.column, on);
463 break;
464#endif
465 }
466}
467
468static void highlightTargets(const QList<TranslatableEntry> &targets, bool on)
469{
470 for (const TranslatableEntry &target : targets)
471 highlightTarget(target, on);
472}
473
474UiFormPreviewView::UiFormPreviewView(QWidget *parent, MultiDataModel *dataModel)
475 : QMainWindow(parent), m_form(0), m_dataModel(dataModel)
476{
477 m_mdiSubWindow = new QMdiSubWindow;
478 m_mdiSubWindow->setWindowFlags(m_mdiSubWindow->windowFlags() & ~Qt::WindowSystemMenuHint);
479 m_mdiArea = new QMdiArea(this);
480 m_mdiArea->addSubWindow(m_mdiSubWindow);
481 setCentralWidget(m_mdiArea);
482 m_mdiArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
483 m_mdiArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
484}
485
486void UiFormPreviewView::setSourceContext(int model, MessageItem *messageItem)
487{
488 if (model < 0 || !messageItem) {
489 m_lastModel = -1;
490 return;
491 }
492
493 QDir dir = QFileInfo(m_dataModel->srcFileName(model)).dir();
494 QString fileName = QDir::cleanPath(dir.absoluteFilePath(messageItem->fileName()));
495 if (m_lastFormName != fileName) {
496 delete m_form;
497 m_form = 0;
498 m_lastFormName.clear();
499 m_highlights.clear();
500 destroyTargets(&m_targets);
501
502 static QUiLoader *uiLoader;
503 if (!uiLoader) {
504 uiLoader = new QUiLoader(this);
505 uiLoader->setLanguageChangeEnabled(true);
506 uiLoader->setTranslationEnabled(false);
507 }
508
509 QFile file(fileName);
510 if (!file.open(QIODevice::ReadOnly)) {
511 qDebug() << "CANNOT OPEN FORM" << fileName;
512 m_mdiSubWindow->hide();
513 return;
514 }
515 m_form = uiLoader->load(&file, m_mdiSubWindow);
516 if (!m_form) {
517 qDebug() << "CANNOT LOAD FORM" << fileName;
518 m_mdiSubWindow->hide();
519 return;
520 }
521 file.close();
522 buildTargets(m_form, &m_targets);
523
524 setToolTip(fileName);
525
526 m_form->setWindowFlags(Qt::Widget);
527 m_form->setWindowModality(Qt::NonModal);
528 m_form->setFocusPolicy(Qt::NoFocus);
529 m_form->show(); // needed, otherwide the Qt::NoFocus is not propagated.
530 m_mdiSubWindow->setWidget(m_form);
531 m_mdiSubWindow->setWindowTitle(m_form->windowTitle());
532 m_mdiSubWindow->show();
533 m_mdiArea->cascadeSubWindows();
534 m_lastFormName = fileName;
535 m_lastClassName = messageItem->context();
536 m_lastLabelName = messageItem->label();
537 m_lastModel = -1;
538 } else {
539 highlightTargets(m_highlights, false);
540 }
541 QUiTranslatableStringValue tsv;
542 tsv.setValue(messageItem->text().toUtf8());
543 tsv.setQualifier(messageItem->comment().toUtf8());
544 m_highlights = m_targets.value(tsv);
545 if (m_lastModel != model) {
546 for (auto it = m_targets.cbegin(), end = m_targets.cend(); it != end; ++it)
547 retranslateTargets(*it, it.key(), m_dataModel->model(model), m_lastClassName,
548 m_lastLabelName);
549 m_lastModel = model;
550 } else {
551 retranslateTargets(m_highlights, tsv, m_dataModel->model(model), m_lastClassName,
552 m_lastLabelName);
553 }
554 highlightTargets(m_highlights, true);
555}
556
557QT_END_NAMESPACE
friend class QWidget
Definition qpainter.h:431
void setSourceContext(int model, MessageItem *messageItem)
TranslatableEntryType type
static void registerTreeItem(QTreeWidgetItem *item, TargetsHash *targets)
static void highlightWidget(QWidget *w, bool on)
static void highlightTarget(const TranslatableEntry &target, bool on)
static void destroyTargets(TargetsHash *targets)
#define REGISTER_SUBWIDGET_PROP(mainWidget, propType, propName)
#define REGISTER_ITEM_CORE(item, propType, targetName)
static void highlightWidgetItem(T *item, bool on)
static void buildTargets(QObject *o, TargetsHash *targets)
static void bringToFront(QWidget *w)
static void retranslateTarget(const TranslatableEntry &target, const QString &text)
#define FONT_BACKUP_PROP
#define AUTOFILL_BACKUP_PROP
static void highlightTargets(const QList< TranslatableEntry > &targets, bool on)
static bool operator==(const QUiTranslatableStringValue &tsv1, const QUiTranslatableStringValue &tsv2)
static void registerListItem(QListWidgetItem *item, TargetsHash *targets)
static void highlightTreeWidgetItem(QTreeWidgetItem *item, int col, bool on)
static void registerTableItem(QTableWidgetItem *item, TargetsHash *targets)
#define INSERT_TARGET(_tsv, _type, _target, _prop)
static void highlightAction(QAction *a, bool on)
static void retranslateTargets(const QList< TranslatableEntry > &targets, const QUiTranslatableStringValue &tsv, const DataModel *dataModel, const QString &className, const QString &labelName)
#define PALETTE_BACKUP_PROP
static QT_BEGIN_NAMESPACE size_t qHash(const QUiTranslatableStringValue &tsv)
@ TranslatableTabPageWhatsThis
@ TranslatableTableWidgetItem
@ TranslatableListWidgetItem
@ TranslatableTreeWidgetItem
@ TranslatableComboBoxItem
@ TranslatableTabPageToolTip
@ TranslatableToolItemToolTip
@ TranslatableProperty
@ TranslatableToolItemText
@ TranslatableTabPageText