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