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
4#include "cppwriteinitialization.h"
5#include "customwidgetsinfo.h"
6#include "driver.h"
7#include "ui4.h"
8#include "utils.h"
9#include "uic.h"
10#include "databaseinfo.h"
11
12#include <language.h>
13
14#include <qtextstream.h>
15#include <qversionnumber.h>
16#include <qdebug.h>
17
18#include <algorithm>
19
20QT_BEGIN_NAMESPACE
21
22using namespace Qt::StringLiterals;
23
24namespace {
25
26 // Expand "Horizontal", "Qt::Horizontal" to "Qt::Orientation::Horizontal"
27 QString expandEnum(QString value, const QString &prefix)
28 {
29 if (value.startsWith(s: prefix))
30 return value;
31 const auto pos = value.lastIndexOf(s: "::"_L1);
32 if (pos == -1)
33 return prefix + "::"_L1 + value;
34 value.replace(i: 0, len: pos, after: prefix);
35 return value;
36 }
37
38 inline QString expandSizePolicyEnum(const QString &value)
39 {
40 return expandEnum(value, prefix: "QSizePolicy::Policy"_L1);
41 }
42
43 inline QString expandToolBarArea(const QString &value)
44 {
45 return expandEnum(value, prefix: "Qt::ToolBarArea"_L1);
46 }
47
48 inline QString expandDockWidgetArea(const QString &value)
49 {
50 return expandEnum(value, prefix: "Qt::DockWidgetArea"_L1);
51 }
52
53 // figure out the toolbar area of a DOM attrib list.
54 // By legacy, it is stored as an integer. As of 4.3.0, it is the enumeration value.
55 QString toolBarAreaStringFromDOMAttributes(const CPP::WriteInitialization::DomPropertyMap &attributes) {
56 const DomProperty *pstyle = attributes.value(key: "toolBarArea"_L1);
57 QString result;
58 if (!pstyle)
59 return result;
60 switch (pstyle->kind()) {
61 case DomProperty::Number:
62 result = language::toolbarArea(v: pstyle->elementNumber());
63 break;
64 case DomProperty::Enum:
65 result = pstyle->elementEnum();
66 break;
67 default:
68 break;
69 }
70 return expandToolBarArea(value: result) + ", "_L1;
71 }
72
73 // Write a statement to create a spacer item.
74 void writeSpacerItem(const DomSpacer *node, QTextStream &output) {
75 const QHash<QString, DomProperty *> properties = propertyMap(properties: node->elementProperty());
76 output << language::operatorNew << "QSpacerItem(";
77
78 int w = 0;
79 int h = 0;
80 if (const DomProperty *sh = properties.value(key: "sizeHint"_L1)) {
81 if (const DomSize *sizeHint = sh->elementSize()) {
82 w = sizeHint->elementWidth();
83 h = sizeHint->elementHeight();
84 }
85 }
86 output << w << ", " << h << ", ";
87
88 // size type
89 const DomProperty *st = properties.value(key: "sizeType"_L1);
90 QString horizType = st != nullptr ? st->elementEnum() : "Expanding"_L1;
91 QString vertType = "Minimum"_L1;
92
93 // orientation
94 const DomProperty *o = properties.value(key: "orientation"_L1);
95 if (o != nullptr && o->elementEnum().endsWith(s: "Vertical"_L1))
96 std::swap(a&: horizType, b&: vertType);
97
98 output << language::enumValue(value: expandSizePolicyEnum(value: horizType)) << ", "
99 << language::enumValue(value: expandSizePolicyEnum(value: vertType)) << ')';
100 }
101
102
103 // Helper for implementing comparison functions for integers.
104 int compareInt(int i1, int i2) {
105 if (i1 < i2) return -1;
106 if (i1 > i2) return 1;
107 return 0;
108 }
109
110 // Write object->setFoo(x);
111 template <class Value>
112 void writeSetter(const QString &indent, const QString &varName,const QString &setter, Value v, QTextStream &str) {
113 str << indent << varName << language::derefPointer
114 << setter << '(' << v << ')' << language::eol;
115 }
116
117 static inline bool iconHasStatePixmaps(const DomResourceIcon *i) {
118 return i->hasElementNormalOff() || i->hasElementNormalOn() ||
119 i->hasElementDisabledOff() || i->hasElementDisabledOn() ||
120 i->hasElementActiveOff() || i->hasElementActiveOn() ||
121 i->hasElementSelectedOff() || i->hasElementSelectedOn();
122 }
123
124 static inline bool isIconFormat44(const DomResourceIcon *i) {
125 return iconHasStatePixmaps(i) || !i->attributeTheme().isEmpty();
126 }
127
128 // An approximation of "Unicode Standard Annex #31" for checking property
129 // and enumeration identifiers to prevent code injection attacks.
130 // FIXME 6.9: Simplify according to QTBUG-126860
131 static bool isIdStart(QChar c)
132 {
133 bool result = false;
134 switch (c.category()) {
135 case QChar::Letter_Uppercase:
136 case QChar::Letter_Lowercase:
137 case QChar::Letter_Titlecase:
138 case QChar::Letter_Modifier:
139 case QChar::Letter_Other:
140 case QChar::Number_Letter:
141 result = true;
142 break;
143 default:
144 result = c == u'_';
145 break;
146 }
147 return result;
148 }
149
150 static bool isIdContinuation(QChar c)
151 {
152 bool result = false;
153 switch (c.category()) {
154 case QChar::Letter_Uppercase:
155 case QChar::Letter_Lowercase:
156 case QChar::Letter_Titlecase:
157 case QChar::Letter_Modifier:
158 case QChar::Letter_Other:
159 case QChar::Number_Letter:
160 case QChar::Mark_NonSpacing:
161 case QChar::Mark_SpacingCombining:
162 case QChar::Number_DecimalDigit:
163 case QChar::Punctuation_Connector: // '_'
164 result = true;
165 break;
166 default:
167 break;
168 }
169 return result;
170 }
171
172 static bool isEnumIdContinuation(QChar c)
173 {
174 return c == u':' || c == u'|' || c == u' ' || isIdContinuation(c);
175 }
176
177 bool checkPropertyName(QStringView name)
178 {
179 return !name.isEmpty() && isIdStart(c: name.at(n: 0))
180 && std::all_of(first: name.cbegin() + 1, last: name.cend(), pred: isIdContinuation);
181 }
182
183 bool checkEnumValue(QStringView name)
184 {
185 return !name.isEmpty() && isIdStart(c: name.at(n: 0))
186 && std::all_of(first: name.cbegin() + 1, last: name.cend(), pred: isEnumIdContinuation);
187 }
188
189 QString msgInvalidValue(const QString &name, const QString &value)
190 {
191 return "uic: Invalid property value: \""_L1 + name + "\": \""_L1 + value + u'"';
192 }
193
194 // Check on properties. Filter out empty legacy pixmap/icon properties
195 // as Designer pre 4.4 used to remove missing resource references.
196 // This can no longer be handled by the code as we have 'setIcon(QIcon())' as well as 'QIcon icon'
197 static bool checkProperty(const CustomWidgetsInfo *customWidgetsInfo,
198 const QString &fileName, const QString &className,
199 const DomProperty *p) {
200
201 const QString &name = p->attributeName();
202 const bool isDynamicProperty = p->hasAttributeStdset() && p->attributeStdset() == 0;
203 if (!isDynamicProperty && !checkPropertyName(name)) {
204 qWarning(msg: "uic: Invalid property name: \"%s\".", qPrintable(name));
205 return false;
206 }
207
208 switch (p->kind()) {
209 // ### fixme Qt 7 remove this: Exclude deprecated properties of Qt 5.
210 case DomProperty::Set:
211 if (!checkEnumValue(name: p->elementSet())) {
212 qWarning(msg: "%s", qPrintable(msgInvalidValue(name, p->elementSet())));
213 return false;
214 }
215 if (name == u"features"
216 && customWidgetsInfo->extends(className, baseClassName: "QDockWidget")
217 && p->elementSet() == u"QDockWidget::AllDockWidgetFeatures") {
218 const QString msg = fileName + ": Warning: Deprecated enum value QDockWidget::AllDockWidgetFeatures was encountered."_L1;
219 qWarning(msg: "%s", qPrintable(msg));
220 return false;
221 }
222 break;
223 case DomProperty::Enum:
224 if (!checkEnumValue(name: p->elementEnum())) {
225 qWarning(msg: "%s", qPrintable(msgInvalidValue(name, p->elementEnum())));
226 return false;
227 }
228 if (name == u"sizeAdjustPolicy"
229 && customWidgetsInfo->extends(className, baseClassName: "QComboBox")
230 && p->elementEnum() == u"QComboBox::AdjustToMinimumContentsLength") {
231 const QString msg = fileName + ": Warning: Deprecated enum value QComboBox::AdjustToMinimumContentsLength was encountered."_L1;
232 qWarning(msg: "%s", qPrintable(msg));
233 return false;
234 }
235 break;
236 case DomProperty::IconSet:
237 if (const DomResourceIcon *dri = p->elementIconSet()) {
238 if (!isIconFormat44(i: dri)) {
239 if (dri->text().isEmpty()) {
240 const QString msg = QString::fromLatin1(ba: "%1: Warning: An invalid icon property '%2' was encountered.")
241 .arg(args: fileName, args: name);
242 qWarning(msg: "%s", qPrintable(msg));
243 return false;
244 }
245 }
246 }
247 break;
248 case DomProperty::Pixmap:
249 if (const DomResourcePixmap *drp = p->elementPixmap())
250 if (drp->text().isEmpty()) {
251 const QString msg = QString::fromUtf8(utf8: "%1: Warning: An invalid pixmap property '%2' was encountered.")
252 .arg(args: fileName, args: name);
253 qWarning(msg: "%s", qPrintable(msg));
254 return false;
255 }
256 break;
257 default:
258 break;
259 }
260 return true;
261 }
262}
263
264// QtGui
265static inline QString accessibilityConfigKey() { return QStringLiteral("accessibility"); }
266static inline QString shortcutConfigKey() { return QStringLiteral("shortcut"); }
267static inline QString whatsThisConfigKey() { return QStringLiteral("whatsthis"); }
268// QtWidgets
269static inline QString statusTipConfigKey() { return QStringLiteral("statustip"); }
270static inline QString toolTipConfigKey() { return QStringLiteral("tooltip"); }
271
272namespace CPP {
273
274FontHandle::FontHandle(const DomFont *domFont) :
275 m_domFont(domFont)
276{
277}
278
279static QString fontWeight(const DomFont *domFont)
280{
281 if (domFont->hasElementFontWeight())
282 return domFont->elementFontWeight();
283 if (domFont->hasElementBold())
284 return domFont->elementBold() ? u"Bold"_s : u"Normal"_s;
285 return {};
286}
287
288int FontHandle::compare(const FontHandle &rhs) const
289{
290 const QString family = m_domFont->hasElementFamily() ? m_domFont->elementFamily() : QString();
291 const QString rhsFamily = rhs.m_domFont->hasElementFamily() ? rhs.m_domFont->elementFamily() : QString();
292
293 if (const int frc = family.compare(s: rhsFamily))
294 return frc;
295
296 const int pointSize = m_domFont->hasElementPointSize() ? m_domFont->elementPointSize() : -1;
297 const int rhsPointSize = rhs.m_domFont->hasElementPointSize() ? rhs.m_domFont->elementPointSize() : -1;
298
299 if (const int crc = compareInt(i1: pointSize, i2: rhsPointSize))
300 return crc;
301
302 const QString fontWeight = CPP::fontWeight(domFont: m_domFont);
303 const QString rhsFontWeight = CPP::fontWeight(domFont: rhs.m_domFont);
304 if (const int wrc = fontWeight.compare(s: rhsFontWeight))
305 return wrc;
306
307 const int italic = m_domFont->hasElementItalic() ? (m_domFont->elementItalic() ? 1 : 0) : -1;
308 const int rhsItalic = rhs.m_domFont->hasElementItalic() ? (rhs.m_domFont->elementItalic() ? 1 : 0) : -1;
309 if (const int crc = compareInt(i1: italic, i2: rhsItalic))
310 return crc;
311
312 const int underline = m_domFont->hasElementUnderline() ? (m_domFont->elementUnderline() ? 1 : 0) : -1;
313 const int rhsUnderline = rhs.m_domFont->hasElementUnderline() ? (rhs.m_domFont->elementUnderline() ? 1 : 0) : -1;
314 if (const int crc = compareInt(i1: underline, i2: rhsUnderline))
315 return crc;
316
317 const int strikeOut = m_domFont->hasElementStrikeOut() ? (m_domFont->elementStrikeOut() ? 1 : 0) : -1;
318 const int rhsStrikeOut = rhs.m_domFont->hasElementStrikeOut() ? (rhs.m_domFont->elementStrikeOut() ? 1 : 0) : -1;
319 if (const int crc = compareInt(i1: strikeOut, i2: rhsStrikeOut))
320 return crc;
321
322 const int kerning = m_domFont->hasElementKerning() ? (m_domFont->elementKerning() ? 1 : 0) : -1;
323 const int rhsKerning = rhs.m_domFont->hasElementKerning() ? (rhs.m_domFont->elementKerning() ? 1 : 0) : -1;
324 if (const int crc = compareInt(i1: kerning, i2: rhsKerning))
325 return crc;
326
327 const int antialiasing = m_domFont->hasElementAntialiasing() ? (m_domFont->elementAntialiasing() ? 1 : 0) : -1;
328 const int rhsAntialiasing = rhs.m_domFont->hasElementAntialiasing() ? (rhs.m_domFont->elementAntialiasing() ? 1 : 0) : -1;
329 if (const int crc = compareInt(i1: antialiasing, i2: rhsAntialiasing))
330 return crc;
331
332 const QString styleStrategy = m_domFont->hasElementStyleStrategy() ? m_domFont->elementStyleStrategy() : QString();
333 const QString rhsStyleStrategy = rhs.m_domFont->hasElementStyleStrategy() ? rhs.m_domFont->elementStyleStrategy() : QString();
334
335 if (const int src = styleStrategy.compare(s: rhsStyleStrategy))
336 return src;
337
338 const QString hintingPreference = m_domFont->hasElementHintingPreference()
339 ? m_domFont->elementHintingPreference() : QString();
340 const QString rhsHintingPreference = rhs.m_domFont->hasElementHintingPreference()
341 ? rhs.m_domFont->elementHintingPreference() : QString();
342 if (const int src = hintingPreference.compare(s: rhsHintingPreference))
343 return src;
344
345 return 0;
346}
347
348IconHandle::IconHandle(const DomResourceIcon *domIcon) :
349 m_domIcon(domIcon)
350{
351}
352
353int IconHandle::compare(const IconHandle &rhs) const
354{
355 if (const int comp = m_domIcon->attributeTheme().compare(s: rhs.m_domIcon->attributeTheme()))
356 return comp;
357
358 const QString normalOff = m_domIcon->hasElementNormalOff() ? m_domIcon->elementNormalOff()->text() : QString();
359 const QString rhsNormalOff = rhs.m_domIcon->hasElementNormalOff() ? rhs.m_domIcon->elementNormalOff()->text() : QString();
360 if (const int comp = normalOff.compare(s: rhsNormalOff))
361 return comp;
362
363 const QString normalOn = m_domIcon->hasElementNormalOn() ? m_domIcon->elementNormalOn()->text() : QString();
364 const QString rhsNormalOn = rhs.m_domIcon->hasElementNormalOn() ? rhs.m_domIcon->elementNormalOn()->text() : QString();
365 if (const int comp = normalOn.compare(s: rhsNormalOn))
366 return comp;
367
368 const QString disabledOff = m_domIcon->hasElementDisabledOff() ? m_domIcon->elementDisabledOff()->text() : QString();
369 const QString rhsDisabledOff = rhs.m_domIcon->hasElementDisabledOff() ? rhs.m_domIcon->elementDisabledOff()->text() : QString();
370 if (const int comp = disabledOff.compare(s: rhsDisabledOff))
371 return comp;
372
373 const QString disabledOn = m_domIcon->hasElementDisabledOn() ? m_domIcon->elementDisabledOn()->text() : QString();
374 const QString rhsDisabledOn = rhs.m_domIcon->hasElementDisabledOn() ? rhs.m_domIcon->elementDisabledOn()->text() : QString();
375 if (const int comp = disabledOn.compare(s: rhsDisabledOn))
376 return comp;
377
378 const QString activeOff = m_domIcon->hasElementActiveOff() ? m_domIcon->elementActiveOff()->text() : QString();
379 const QString rhsActiveOff = rhs.m_domIcon->hasElementActiveOff() ? rhs.m_domIcon->elementActiveOff()->text() : QString();
380 if (const int comp = activeOff.compare(s: rhsActiveOff))
381 return comp;
382
383 const QString activeOn = m_domIcon->hasElementActiveOn() ? m_domIcon->elementActiveOn()->text() : QString();
384 const QString rhsActiveOn = rhs.m_domIcon->hasElementActiveOn() ? rhs.m_domIcon->elementActiveOn()->text() : QString();
385 if (const int comp = activeOn.compare(s: rhsActiveOn))
386 return comp;
387
388 const QString selectedOff = m_domIcon->hasElementSelectedOff() ? m_domIcon->elementSelectedOff()->text() : QString();
389 const QString rhsSelectedOff = rhs.m_domIcon->hasElementSelectedOff() ? rhs.m_domIcon->elementSelectedOff()->text() : QString();
390 if (const int comp = selectedOff.compare(s: rhsSelectedOff))
391 return comp;
392
393 const QString selectedOn = m_domIcon->hasElementSelectedOn() ? m_domIcon->elementSelectedOn()->text() : QString();
394 const QString rhsSelectedOn = rhs.m_domIcon->hasElementSelectedOn() ? rhs.m_domIcon->elementSelectedOn()->text() : QString();
395 if (const int comp = selectedOn.compare(s: rhsSelectedOn))
396 return comp;
397 // Pre 4.4 Legacy
398 if (const int comp = m_domIcon->text().compare(s: rhs.m_domIcon->text()))
399 return comp;
400
401 return 0;
402}
403
404SizePolicyHandle::SizePolicyHandle(const DomSizePolicy *domSizePolicy) :
405 m_domSizePolicy(domSizePolicy)
406{
407}
408
409int SizePolicyHandle::compare(const SizePolicyHandle &rhs) const
410{
411
412 const int hSizeType = m_domSizePolicy->hasElementHSizeType() ? m_domSizePolicy->elementHSizeType() : -1;
413 const int rhsHSizeType = rhs.m_domSizePolicy->hasElementHSizeType() ? rhs.m_domSizePolicy->elementHSizeType() : -1;
414 if (const int crc = compareInt(i1: hSizeType, i2: rhsHSizeType))
415 return crc;
416
417 const int vSizeType = m_domSizePolicy->hasElementVSizeType() ? m_domSizePolicy->elementVSizeType() : -1;
418 const int rhsVSizeType = rhs.m_domSizePolicy->hasElementVSizeType() ? rhs.m_domSizePolicy->elementVSizeType() : -1;
419 if (const int crc = compareInt(i1: vSizeType, i2: rhsVSizeType))
420 return crc;
421
422 const int hStretch = m_domSizePolicy->hasElementHorStretch() ? m_domSizePolicy->elementHorStretch() : -1;
423 const int rhsHStretch = rhs.m_domSizePolicy->hasElementHorStretch() ? rhs.m_domSizePolicy->elementHorStretch() : -1;
424 if (const int crc = compareInt(i1: hStretch, i2: rhsHStretch))
425 return crc;
426
427 const int vStretch = m_domSizePolicy->hasElementVerStretch() ? m_domSizePolicy->elementVerStretch() : -1;
428 const int rhsVStretch = rhs.m_domSizePolicy->hasElementVerStretch() ? rhs.m_domSizePolicy->elementVerStretch() : -1;
429 if (const int crc = compareInt(i1: vStretch, i2: rhsVStretch))
430 return crc;
431
432 const QString attributeHSizeType = m_domSizePolicy->hasAttributeHSizeType() ? m_domSizePolicy->attributeHSizeType() : QString();
433 const QString rhsAttributeHSizeType = rhs.m_domSizePolicy->hasAttributeHSizeType() ? rhs.m_domSizePolicy->attributeHSizeType() : QString();
434
435 if (const int hrc = attributeHSizeType.compare(s: rhsAttributeHSizeType))
436 return hrc;
437
438 const QString attributeVSizeType = m_domSizePolicy->hasAttributeVSizeType() ? m_domSizePolicy->attributeVSizeType() : QString();
439 const QString rhsAttributeVSizeType = rhs.m_domSizePolicy->hasAttributeVSizeType() ? rhs.m_domSizePolicy->attributeVSizeType() : QString();
440
441 return attributeVSizeType.compare(s: rhsAttributeVSizeType);
442}
443
444// --- WriteInitialization: LayoutDefaultHandler
445
446WriteInitialization::LayoutDefaultHandler::LayoutDefaultHandler()
447{
448 std::fill_n(first: m_state, n: int(NumProperties), value: 0U);
449 std::fill_n(first: m_defaultValues, n: int(NumProperties), value: 0);
450}
451
452
453
454void WriteInitialization::LayoutDefaultHandler::acceptLayoutDefault(DomLayoutDefault *node)
455{
456 if (!node)
457 return;
458 if (node->hasAttributeMargin()) {
459 m_state[Margin] |= HasDefaultValue;
460 m_defaultValues[Margin] = node->attributeMargin();
461 }
462 if (node->hasAttributeSpacing()) {
463 m_state[Spacing] |= HasDefaultValue;
464 m_defaultValues[Spacing] = node->attributeSpacing();
465 }
466}
467
468void WriteInitialization::LayoutDefaultHandler::acceptLayoutFunction(DomLayoutFunction *node)
469{
470 if (!node)
471 return;
472 if (node->hasAttributeMargin()) {
473 m_state[Margin] |= HasDefaultFunction;
474 m_functions[Margin] = node->attributeMargin();
475 m_functions[Margin] += "()"_L1;
476 }
477 if (node->hasAttributeSpacing()) {
478 m_state[Spacing] |= HasDefaultFunction;
479 m_functions[Spacing] = node->attributeSpacing();
480 m_functions[Spacing] += "()"_L1;
481 }
482}
483
484static inline void writeContentsMargins(const QString &indent, const QString &objectName, int value, QTextStream &str)
485{
486 QString contentsMargins;
487 QTextStream(&contentsMargins) << value << ", " << value << ", " << value << ", " << value;
488 writeSetter(indent, varName: objectName, setter: "setContentsMargins"_L1, v: contentsMargins, str);
489 }
490
491void WriteInitialization::LayoutDefaultHandler::writeProperty(int p, const QString &indent, const QString &objectName,
492 const DomPropertyMap &properties, const QString &propertyName, const QString &setter,
493 int defaultStyleValue, bool suppressDefault, QTextStream &str) const
494{
495 // User value
496 if (const DomProperty *prop = properties.value(key: propertyName)) {
497 const int value = prop->elementNumber();
498 // Emulate the pre 4.3 behaviour: The value form default value was only used to determine
499 // the default value, layout properties were always written
500 const bool useLayoutFunctionPre43 = !suppressDefault && (m_state[p] == (HasDefaultFunction|HasDefaultValue)) && value == m_defaultValues[p];
501 if (!useLayoutFunctionPre43) {
502 bool ifndefMac = (!(m_state[p] & (HasDefaultFunction|HasDefaultValue))
503 && value == defaultStyleValue);
504 if (ifndefMac)
505 str << "#ifndef Q_OS_MAC\n";
506 if (p == Margin) { // Use setContentsMargins for numeric values
507 writeContentsMargins(indent, objectName, value, str);
508 } else {
509 writeSetter(indent, varName: objectName, setter, v: value, str);
510 }
511 if (ifndefMac)
512 str << "#endif\n";
513 return;
514 }
515 }
516 if (suppressDefault)
517 return;
518 // get default.
519 if (m_state[p] & HasDefaultFunction) {
520 // Do not use setContentsMargins to avoid repetitive evaluations.
521 writeSetter(indent, varName: objectName, setter, v: m_functions[p], str);
522 return;
523 }
524 if (m_state[p] & HasDefaultValue) {
525 if (p == Margin) { // Use setContentsMargins for numeric values
526 writeContentsMargins(indent, objectName, value: m_defaultValues[p], str);
527 } else {
528 writeSetter(indent, varName: objectName, setter, v: m_defaultValues[p], str);
529 }
530 }
531}
532
533
534void WriteInitialization::LayoutDefaultHandler::writeProperties(const QString &indent, const QString &varName,
535 const DomPropertyMap &properties, int marginType,
536 bool suppressMarginDefault,
537 QTextStream &str) const {
538 // Write out properties and ignore the ones found in
539 // subsequent writing of the property list.
540 int defaultSpacing = marginType == WriteInitialization::Use43UiFile ? -1 : 6;
541 writeProperty(p: Spacing, indent, objectName: varName, properties, propertyName: "spacing"_L1, setter: "setSpacing"_L1,
542 defaultStyleValue: defaultSpacing, suppressDefault: false, str);
543 // We use 9 as TopLevelMargin, since Designer seem to always use 9.
544 static const int layoutmargins[4] = {-1, 9, 9, 0};
545 writeProperty(p: Margin, indent, objectName: varName, properties, propertyName: "margin"_L1, setter: "setMargin"_L1,
546 defaultStyleValue: layoutmargins[marginType], suppressDefault: suppressMarginDefault, str);
547}
548
549template <class DomElement> // (DomString, DomStringList)
550static bool needsTranslation(const DomElement *element)
551{
552 if (!element)
553 return false;
554 return !element->hasAttributeNotr() || !toBool(element->attributeNotr());
555}
556
557// --- WriteInitialization
558WriteInitialization::WriteInitialization(Uic *uic) :
559 m_uic(uic),
560 m_driver(uic->driver()), m_output(uic->output()), m_option(uic->option()),
561 m_indent(m_option.indent + m_option.indent),
562 m_dindent(m_indent + m_option.indent),
563 m_delayedOut(&m_delayedInitialization, QIODevice::WriteOnly),
564 m_refreshOut(&m_refreshInitialization, QIODevice::WriteOnly),
565 m_actionOut(&m_delayedActionInitialization, QIODevice::WriteOnly)
566{
567}
568
569void WriteInitialization::acceptUI(DomUI *node)
570{
571 m_actionGroupChain.push(t: nullptr);
572 m_widgetChain.push(t: nullptr);
573 m_layoutChain.push(t: nullptr);
574
575 if (node->hasAttributeConnectslotsbyname())
576 m_connectSlotsByName = node->attributeConnectslotsbyname();
577
578 if (auto *customSlots = node->elementSlots()) {
579 m_customSlots = customSlots->elementSlot();
580 m_customSignals = customSlots->elementSignal();
581 }
582
583 acceptLayoutDefault(node: node->elementLayoutDefault());
584 acceptLayoutFunction(node: node->elementLayoutFunction());
585
586 if (node->elementCustomWidgets())
587 TreeWalker::acceptCustomWidgets(customWidgets: node->elementCustomWidgets());
588
589 if (m_option.generateImplemetation)
590 m_output << "#include <" << m_driver->headerFileName() << ">\n\n";
591
592 m_stdsetdef = true;
593 if (node->hasAttributeStdSetDef())
594 m_stdsetdef = node->attributeStdSetDef();
595
596 const QString className = node->elementClass() + m_option.postfix;
597 m_generatedClass = className;
598
599 const QString varName = m_driver->findOrInsertWidget(ui_widget: node->elementWidget());
600 m_mainFormVarName = varName;
601
602 const QString widgetClassName = node->elementWidget()->attributeClass();
603
604 const QString parameterType = widgetClassName + " *"_L1;
605 m_output << m_option.indent
606 << language::startFunctionDefinition1("setupUi", parameterType, varName, m_option.indent);
607
608 const QStringList connections = m_uic->databaseInfo()->connections();
609 for (const auto &connection : connections) {
610 if (connection == "(default)"_L1)
611 continue;
612
613 const QString varConn = connection + "Connection"_L1;
614 m_output << m_indent << varConn << " = QSqlDatabase::database("
615 << language::charliteral(connection, m_dindent) << ")" << language::eol;
616 }
617
618 acceptWidget(node: node->elementWidget());
619
620 if (!m_buddies.empty())
621 m_output << language::openQtConfig(shortcutConfigKey());
622 for (const Buddy &b : std::as_const(t&: m_buddies)) {
623 const QString buddyVarName = m_driver->widgetVariableName(attributeName: b.buddyAttributeName);
624 if (buddyVarName.isEmpty()) {
625 fprintf(stderr, format: "%s: Warning: Buddy assignment: '%s' is not a valid widget.\n",
626 qPrintable(m_option.messagePrefix()),
627 qPrintable(b.buddyAttributeName));
628 continue;
629 }
630
631 m_output << m_indent << b.labelVarName << language::derefPointer
632 << "setBuddy(" << buddyVarName << ')' << language::eol;
633 }
634 if (!m_buddies.empty())
635 m_output << language::closeQtConfig(shortcutConfigKey());
636
637 if (node->elementTabStops())
638 acceptTabStops(tabStops: node->elementTabStops());
639
640 if (!m_delayedActionInitialization.isEmpty())
641 m_output << "\n" << m_delayedActionInitialization;
642
643 m_output << "\n" << m_indent << language::self
644 << "retranslateUi(" << varName << ')' << language::eol;
645
646 if (node->elementConnections())
647 acceptConnections(connections: node->elementConnections());
648
649 if (!m_delayedInitialization.isEmpty())
650 m_output << "\n" << m_delayedInitialization << "\n";
651
652 if (m_option.autoConnection && m_connectSlotsByName) {
653 m_output << "\n" << m_indent << "QMetaObject" << language::qualifier
654 << "connectSlotsByName(" << varName << ')' << language::eol;
655 }
656
657 m_output << m_option.indent << language::endFunctionDefinition("setupUi");
658
659 if (!m_mainFormUsedInRetranslateUi) {
660 if (language::language() == Language::Cpp) {
661 // Mark varName as unused to avoid compiler warnings.
662 m_refreshInitialization += m_indent;
663 m_refreshInitialization += "(void)"_L1;
664 m_refreshInitialization += varName ;
665 m_refreshInitialization += language::eol;
666 } else if (language::language() == Language::Python) {
667 // output a 'pass' to have an empty function
668 m_refreshInitialization += m_indent;
669 m_refreshInitialization += "pass"_L1;
670 m_refreshInitialization += language::eol;
671 }
672 }
673
674 m_output << m_option.indent
675 << language::startFunctionDefinition1("retranslateUi", parameterType, varName, m_option.indent)
676 << m_refreshInitialization
677 << m_option.indent << language::endFunctionDefinition("retranslateUi");
678
679 m_layoutChain.pop();
680 m_widgetChain.pop();
681 m_actionGroupChain.pop();
682}
683
684void WriteInitialization::addWizardPage(const QString &pageVarName, const DomWidget *page, const QString &parentWidget)
685{
686 /* If the node has a (free-format) string "pageId" attribute (which could
687 * an integer or an enumeration value), use setPage(), else addPage(). */
688 QString id;
689 const auto &attributes = page->elementAttribute();
690 if (!attributes.empty()) {
691 for (const DomProperty *p : attributes) {
692 if (p->attributeName() == "pageId"_L1) {
693 if (const DomString *ds = p->elementString())
694 id = ds->text();
695 break;
696 }
697 }
698 }
699 if (id.isEmpty()) {
700 m_output << m_indent << parentWidget << language::derefPointer
701 << "addPage(" << pageVarName << ')' << language::eol;
702 } else {
703 m_output << m_indent << parentWidget << language::derefPointer
704 << "setPage(" << id << ", " << pageVarName << ')' << language::eol;
705 }
706}
707
708void WriteInitialization::acceptWidget(DomWidget *node)
709{
710 m_layoutMarginType = m_widgetChain.size() == 1 ? TopLevelMargin : ChildMargin;
711 const QString className = node->attributeClass();
712 const QString varName = m_driver->findOrInsertWidget(ui_widget: node);
713
714 QString parentWidget;
715 QString parentClass;
716 if (m_widgetChain.top()) {
717 parentWidget = m_driver->findOrInsertWidget(ui_widget: m_widgetChain.top());
718 parentClass = m_widgetChain.top()->attributeClass();
719 }
720
721 const QString savedParentWidget = parentWidget;
722
723 if (m_uic->isContainer(className: parentClass))
724 parentWidget.clear();
725
726 const auto *cwi = m_uic->customWidgetsInfo();
727
728 if (m_widgetChain.size() != 1) {
729 m_output << m_indent << varName << " = " << language::operatorNew
730 << language::fixClassName(className: CustomWidgetsInfo::realClassName(className))
731 << '(' << parentWidget << ')' << language::eol;
732 }
733
734 parentWidget = savedParentWidget;
735
736
737 if (cwi->extends(className, baseClassName: "QComboBox")) {
738 initializeComboBox(w: node);
739 } else if (cwi->extends(className, baseClassName: "QListWidget")) {
740 initializeListWidget(w: node);
741 } else if (cwi->extends(className, baseClassName: "QTreeWidget")) {
742 initializeTreeWidget(w: node);
743 } else if (cwi->extends(className, baseClassName: "QTableWidget")) {
744 initializeTableWidget(w: node);
745 }
746
747 if (m_uic->isButton(className))
748 addButtonGroup(node, varName);
749
750 writeProperties(varName, className, lst: node->elementProperty());
751
752 if (!parentWidget.isEmpty()
753 && cwi->extends(className, baseClassName: "QMenu")) {
754 initializeMenu(w: node, parentWidget);
755 }
756
757 if (node->elementLayout().isEmpty())
758 m_layoutChain.push(t: nullptr);
759
760 m_layoutWidget = false;
761 if (className == "QWidget"_L1 && !node->hasAttributeNative()) {
762 if (const DomWidget* parentWidget = m_widgetChain.top()) {
763 const QString parentClass = parentWidget->attributeClass();
764 if (parentClass != "QMainWindow"_L1
765 && !m_uic->customWidgetsInfo()->isCustomWidgetContainer(className: parentClass)
766 && !m_uic->isContainer(className: parentClass))
767 m_layoutWidget = true;
768 }
769 }
770 m_widgetChain.push(t: node);
771 m_layoutChain.push(t: nullptr);
772 TreeWalker::acceptWidget(widget: node);
773 m_layoutChain.pop();
774 m_widgetChain.pop();
775 m_layoutWidget = false;
776
777 const DomPropertyMap attributes = propertyMap(properties: node->elementAttribute());
778
779 const QString pageDefaultString = u"Page"_s;
780
781 if (cwi->extends(className: parentClass, baseClassName: "QMainWindow")) {
782 if (cwi->extends(className, baseClassName: "QMenuBar")) {
783 m_output << m_indent << parentWidget << language::derefPointer
784 << "setMenuBar(" << varName << ')' << language::eol;
785 } else if (cwi->extends(className, baseClassName: "QToolBar")) {
786 m_output << m_indent << parentWidget << language::derefPointer << "addToolBar("
787 << language::enumValue(value: toolBarAreaStringFromDOMAttributes(attributes)) << varName
788 << ')' << language::eol;
789
790 if (const DomProperty *pbreak = attributes.value(key: "toolBarBreak"_L1)) {
791 if (pbreak->elementBool() == "true"_L1) {
792 m_output << m_indent << parentWidget << language::derefPointer
793 << "insertToolBarBreak(" << varName << ')' << language::eol;
794 }
795 }
796
797 } else if (cwi->extends(className, baseClassName: "QDockWidget")) {
798 m_output << m_indent << parentWidget << language::derefPointer << "addDockWidget(";
799 if (DomProperty *pstyle = attributes.value(key: "dockWidgetArea"_L1)) {
800 QString a = expandDockWidgetArea(value: language::dockWidgetArea(v: pstyle->elementNumber()));
801 m_output << language::enumValue(value: a) << ", ";
802 }
803 m_output << varName << ")" << language::eol;
804 } else if (m_uic->customWidgetsInfo()->extends(className, baseClassName: "QStatusBar")) {
805 m_output << m_indent << parentWidget << language::derefPointer
806 << "setStatusBar(" << varName << ')' << language::eol;
807 } else {
808 m_output << m_indent << parentWidget << language::derefPointer
809 << "setCentralWidget(" << varName << ')' << language::eol;
810 }
811 }
812
813 // Check for addPageMethod of a custom plugin first
814 QString addPageMethod = cwi->customWidgetAddPageMethod(name: parentClass);
815 if (addPageMethod.isEmpty())
816 addPageMethod = cwi->simpleContainerAddPageMethod(name: parentClass);
817 if (!addPageMethod.isEmpty()) {
818 m_output << m_indent << parentWidget << language::derefPointer
819 << addPageMethod << '(' << varName << ')' << language::eol;
820 } else if (m_uic->customWidgetsInfo()->extends(className: parentClass, baseClassName: "QWizard")) {
821 addWizardPage(pageVarName: varName, page: node, parentWidget);
822 } else if (m_uic->customWidgetsInfo()->extends(className: parentClass, baseClassName: "QToolBox")) {
823 const DomProperty *plabel = attributes.value(key: "label"_L1);
824 DomString *plabelString = plabel ? plabel->elementString() : nullptr;
825 QString icon;
826 if (const DomProperty *picon = attributes.value(key: "icon"_L1))
827 icon = ", "_L1 + iconCall(prop: picon); // Side effect: Writes icon definition
828 m_output << m_indent << parentWidget << language::derefPointer << "addItem("
829 << varName << icon << ", " << noTrCall(str: plabelString, defaultString: pageDefaultString)
830 << ')' << language::eol;
831
832 autoTrOutput(str: plabelString, defaultString: pageDefaultString) << m_indent << parentWidget
833 << language::derefPointer << "setItemText(" << parentWidget
834 << language::derefPointer << "indexOf(" << varName << "), "
835 << autoTrCall(str: plabelString, defaultString: pageDefaultString) << ')' << language::eol;
836
837 if (DomProperty *ptoolTip = attributes.value(key: "toolTip"_L1)) {
838 autoTrOutput(str: ptoolTip->elementString())
839 << language::openQtConfig(toolTipConfigKey())
840 << m_indent << parentWidget << language::derefPointer << "setItemToolTip(" << parentWidget
841 << language::derefPointer << "indexOf(" << varName << "), "
842 << autoTrCall(str: ptoolTip->elementString()) << ')' << language::eol
843 << language::closeQtConfig(toolTipConfigKey());
844 }
845 } else if (m_uic->customWidgetsInfo()->extends(className: parentClass, baseClassName: "QTabWidget")) {
846 const DomProperty *ptitle = attributes.value(key: "title"_L1);
847 DomString *ptitleString = ptitle ? ptitle->elementString() : nullptr;
848 QString icon;
849 if (const DomProperty *picon = attributes.value(key: "icon"_L1))
850 icon = ", "_L1 + iconCall(prop: picon); // Side effect: Writes icon definition
851 m_output << m_indent << parentWidget << language::derefPointer << "addTab("
852 << varName << icon << ", " << language::emptyString << ')' << language::eol;
853
854 autoTrOutput(str: ptitleString, defaultString: pageDefaultString) << m_indent << parentWidget
855 << language::derefPointer << "setTabText(" << parentWidget
856 << language::derefPointer << "indexOf(" << varName << "), "
857 << autoTrCall(str: ptitleString, defaultString: pageDefaultString) << ')' << language::eol;
858
859 if (const DomProperty *ptoolTip = attributes.value(key: "toolTip"_L1)) {
860 autoTrOutput(str: ptoolTip->elementString())
861 << language::openQtConfig(toolTipConfigKey())
862 << m_indent << parentWidget << language::derefPointer << "setTabToolTip("
863 << parentWidget << language::derefPointer << "indexOf(" << varName
864 << "), " << autoTrCall(str: ptoolTip->elementString()) << ')' << language::eol
865 << language::closeQtConfig(toolTipConfigKey());
866 }
867 if (const DomProperty *pwhatsThis = attributes.value(key: "whatsThis"_L1)) {
868 autoTrOutput(str: pwhatsThis->elementString())
869 << language::openQtConfig(whatsThisConfigKey())
870 << m_indent << parentWidget << language::derefPointer << "setTabWhatsThis("
871 << parentWidget << language::derefPointer << "indexOf(" << varName
872 << "), " << autoTrCall(str: pwhatsThis->elementString()) << ')' << language::eol
873 << language::closeQtConfig(whatsThisConfigKey());
874 }
875 }
876
877 //
878 // Special handling for qtableview/qtreeview fake header attributes
879 //
880 static const QLatin1StringView realPropertyNames[] = {
881 "visible"_L1,
882 "cascadingSectionResizes"_L1,
883 "minimumSectionSize"_L1, // before defaultSectionSize
884 "defaultSectionSize"_L1,
885 "highlightSections"_L1,
886 "showSortIndicator"_L1,
887 "stretchLastSection"_L1,
888 };
889
890 static const QStringList trees = {
891 u"QTreeView"_s, u"QTreeWidget"_s
892 };
893 static const QStringList tables = {
894 u"QTableView"_s, u"QTableWidget"_s
895 };
896
897 if (cwi->extendsOneOf(className, baseClassNames: trees)) {
898 DomPropertyList headerProperties;
899 for (auto realPropertyName : realPropertyNames) {
900 const QString fakePropertyName = "header"_L1
901 + QChar(realPropertyName.at(i: 0)).toUpper() + realPropertyName.mid(pos: 1);
902 if (DomProperty *fakeProperty = attributes.value(key: fakePropertyName)) {
903 fakeProperty->setAttributeName(realPropertyName);
904 headerProperties << fakeProperty;
905 }
906 }
907 writeProperties(varName: varName + language::derefPointer + "header()"_L1,
908 className: "QHeaderView"_L1, lst: headerProperties,
909 flags: WritePropertyIgnoreObjectName);
910
911 } else if (cwi->extendsOneOf(className, baseClassNames: tables)) {
912 static const QLatin1StringView headerPrefixes[] = {
913 "horizontalHeader"_L1,
914 "verticalHeader"_L1,
915 };
916
917 for (auto headerPrefix : headerPrefixes) {
918 DomPropertyList headerProperties;
919 for (auto realPropertyName : realPropertyNames) {
920 const QString fakePropertyName = headerPrefix
921 + QChar(realPropertyName.at(i: 0)).toUpper() + realPropertyName.mid(pos: 1);
922 if (DomProperty *fakeProperty = attributes.value(key: fakePropertyName)) {
923 fakeProperty->setAttributeName(realPropertyName);
924 headerProperties << fakeProperty;
925 }
926 }
927 const QString headerVar = varName + language::derefPointer
928 + headerPrefix + "()"_L1;
929 writeProperties(varName: headerVar, className: "QHeaderView"_L1,
930 lst: headerProperties, flags: WritePropertyIgnoreObjectName);
931 }
932 }
933
934 if (node->elementLayout().isEmpty())
935 m_layoutChain.pop();
936
937 const QStringList zOrder = node->elementZOrder();
938 for (const QString &name : zOrder) {
939 const QString varName = m_driver->widgetVariableName(attributeName: name);
940 if (varName.isEmpty()) {
941 fprintf(stderr, format: "%s: Warning: Z-order assignment: '%s' is not a valid widget.\n",
942 qPrintable(m_option.messagePrefix()),
943 name.toLatin1().data());
944 } else {
945 m_output << m_indent << varName << language::derefPointer
946 << (language::language() != Language::Python ? "raise()" : "raise_()") << language::eol;
947 }
948 }
949}
950
951void WriteInitialization::addButtonGroup(const DomWidget *buttonNode, const QString &varName)
952{
953 const DomPropertyMap attributes = propertyMap(properties: buttonNode->elementAttribute());
954 // Look up the button group name as specified in the attribute and find the uniquified name
955 const DomProperty *prop = attributes.value(key: "buttonGroup"_L1);
956 if (!prop)
957 return;
958 const QString attributeName = toString(str: prop->elementString());
959 const DomButtonGroup *group = m_driver->findButtonGroup(attributeName);
960 // Legacy feature: Create missing groups on the fly as the UIC button group feature
961 // was present before the actual Designer support (4.5)
962 const bool createGroupOnTheFly = group == nullptr;
963 if (createGroupOnTheFly) {
964 auto *newGroup = new DomButtonGroup;
965 newGroup->setAttributeName(attributeName);
966 group = newGroup;
967 fprintf(stderr, format: "%s: Warning: Creating button group `%s'\n",
968 qPrintable(m_option.messagePrefix()),
969 attributeName.toLatin1().data());
970 }
971 const QString groupName = m_driver->findOrInsertButtonGroup(ui_group: group);
972 // Create on demand
973 if (!m_buttonGroups.contains(value: groupName)) {
974 const QString className = u"QButtonGroup"_s;
975 m_output << m_indent;
976 if (createGroupOnTheFly)
977 m_output << className << " *";
978 m_output << groupName << " = " << language::operatorNew
979 << className << '(' << m_mainFormVarName << ')' << language::eol;
980 m_buttonGroups.insert(value: groupName);
981 writeProperties(varName: groupName, className, lst: group->elementProperty());
982 }
983 m_output << m_indent << groupName << language::derefPointer << "addButton("
984 << varName << ')' << language::eol;
985}
986
987void WriteInitialization::acceptLayout(DomLayout *node)
988{
989 const QString className = node->attributeClass();
990 const QString varName = m_driver->findOrInsertLayout(ui_layout: node);
991
992 const DomPropertyMap properties = propertyMap(properties: node->elementProperty());
993 const bool oldLayoutProperties = properties.value(key: "margin"_L1) != nullptr;
994
995 bool isGroupBox = false;
996
997 m_output << m_indent << varName << " = " << language::operatorNew << className << '(';
998
999 if (!m_layoutChain.top() && !isGroupBox)
1000 m_output << m_driver->findOrInsertWidget(ui_widget: m_widgetChain.top());
1001
1002 m_output << ")" << language::eol;
1003
1004 // Suppress margin on a read child layout
1005 const bool suppressMarginDefault = m_layoutChain.top();
1006 int marginType = Use43UiFile;
1007 if (oldLayoutProperties)
1008 marginType = m_layoutMarginType;
1009 m_LayoutDefaultHandler.writeProperties(indent: m_indent, varName, properties, marginType, suppressMarginDefault, str&: m_output);
1010
1011 m_layoutMarginType = SubLayoutMargin;
1012
1013 DomPropertyList propList = node->elementProperty();
1014 DomPropertyList newPropList;
1015 if (m_layoutWidget) {
1016 bool left = false;
1017 bool top = false;
1018 bool right = false;
1019 bool bottom = false;
1020 for (const DomProperty *p : propList) {
1021 const QString propertyName = p->attributeName();
1022 if (propertyName == "leftMargin"_L1 && p->kind() == DomProperty::Number)
1023 left = true;
1024 else if (propertyName == "topMargin"_L1 && p->kind() == DomProperty::Number)
1025 top = true;
1026 else if (propertyName == "rightMargin"_L1 && p->kind() == DomProperty::Number)
1027 right = true;
1028 else if (propertyName == "bottomMargin"_L1 && p->kind() == DomProperty::Number)
1029 bottom = true;
1030 }
1031 if (!left) {
1032 auto *p = new DomProperty();
1033 p->setAttributeName("leftMargin"_L1);
1034 p->setElementNumber(0);
1035 newPropList.append(t: p);
1036 }
1037 if (!top) {
1038 auto *p = new DomProperty();
1039 p->setAttributeName("topMargin"_L1);
1040 p->setElementNumber(0);
1041 newPropList.append(t: p);
1042 }
1043 if (!right) {
1044 auto *p = new DomProperty();
1045 p->setAttributeName("rightMargin"_L1);
1046 p->setElementNumber(0);
1047 newPropList.append(t: p);
1048 }
1049 if (!bottom) {
1050 auto *p = new DomProperty();
1051 p->setAttributeName("bottomMargin"_L1);
1052 p->setElementNumber(0);
1053 newPropList.append(t: p);
1054 }
1055 m_layoutWidget = false;
1056 }
1057
1058 propList.append(l: newPropList);
1059
1060 writeProperties(varName, className, lst: propList, flags: WritePropertyIgnoreMargin|WritePropertyIgnoreSpacing);
1061
1062 // Clean up again:
1063 propList.clear();
1064 qDeleteAll(c: newPropList);
1065 newPropList.clear();
1066
1067 m_layoutChain.push(t: node);
1068 TreeWalker::acceptLayout(layout: node);
1069 m_layoutChain.pop();
1070
1071 // Stretch? (Unless we are compiling for UIC3)
1072 const QString numberNull(u'0');
1073 writePropertyList(varName, setFunction: "setStretch"_L1, value: node->attributeStretch(), defaultValue: numberNull);
1074 writePropertyList(varName, setFunction: "setRowStretch"_L1, value: node->attributeRowStretch(), defaultValue: numberNull);
1075 writePropertyList(varName, setFunction: "setColumnStretch"_L1, value: node->attributeColumnStretch(), defaultValue: numberNull);
1076 writePropertyList(varName, setFunction: "setColumnMinimumWidth"_L1, value: node->attributeColumnMinimumWidth(), defaultValue: numberNull);
1077 writePropertyList(varName, setFunction: "setRowMinimumHeight"_L1, value: node->attributeRowMinimumHeight(), defaultValue: numberNull);
1078}
1079
1080// Apply a comma-separated list of values using a function "setSomething(int idx, value)"
1081void WriteInitialization::writePropertyList(const QString &varName,
1082 const QString &setFunction,
1083 const QString &value,
1084 const QString &defaultValue)
1085{
1086 if (value.isEmpty())
1087 return;
1088 const auto list = QStringView{value}.split(sep: u',');
1089 for (qsizetype i = 0, count = list.size(); i < count; i++) {
1090 if (list.at(i) != defaultValue) {
1091 m_output << m_indent << varName << language::derefPointer << setFunction
1092 << '(' << i << ", " << list.at(i) << ')' << language::eol;
1093 }
1094 }
1095}
1096
1097void WriteInitialization::acceptSpacer(DomSpacer *node)
1098{
1099 m_output << m_indent << m_driver->findOrInsertSpacer(ui_spacer: node) << " = ";
1100 writeSpacerItem(node, output&: m_output);
1101 m_output << language::eol;
1102}
1103
1104static inline QString formLayoutRole(int column, int colspan)
1105{
1106 if (colspan > 1)
1107 return "QFormLayout::SpanningRole"_L1;
1108 return column == 0 ? "QFormLayout::LabelRole"_L1 : "QFormLayout::FieldRole"_L1;
1109}
1110
1111static QString layoutAddMethod(DomLayoutItem::Kind kind, const QString &layoutClass)
1112{
1113 const auto methodPrefix = layoutClass == "QFormLayout"_L1 ? "set"_L1 : "add"_L1;
1114 switch (kind) {
1115 case DomLayoutItem::Widget:
1116 return methodPrefix + "Widget"_L1;
1117 case DomLayoutItem::Layout:
1118 return methodPrefix + "Layout"_L1;
1119 case DomLayoutItem::Spacer:
1120 return methodPrefix + "Item"_L1;
1121 case DomLayoutItem::Unknown:
1122 Q_ASSERT( false );
1123 break;
1124 }
1125 Q_UNREACHABLE();
1126}
1127
1128void WriteInitialization::acceptLayoutItem(DomLayoutItem *node)
1129{
1130 TreeWalker::acceptLayoutItem(layoutItem: node);
1131
1132 DomLayout *layout = m_layoutChain.top();
1133
1134 if (!layout)
1135 return;
1136
1137 const QString layoutName = m_driver->findOrInsertLayout(ui_layout: layout);
1138 const QString itemName = m_driver->findOrInsertLayoutItem(ui_layoutItem: node);
1139
1140 m_output << "\n" << m_indent << layoutName << language::derefPointer << ""
1141 << layoutAddMethod(kind: node->kind(), layoutClass: layout->attributeClass()) << '(';
1142
1143 if (layout->attributeClass() == "QGridLayout"_L1) {
1144 const int row = node->attributeRow();
1145 const int col = node->attributeColumn();
1146
1147 const int rowSpan = node->hasAttributeRowSpan() ? node->attributeRowSpan() : 1;
1148 const int colSpan = node->hasAttributeColSpan() ? node->attributeColSpan() : 1;
1149 m_output << itemName << ", " << row << ", " << col << ", " << rowSpan << ", " << colSpan;
1150 if (!node->attributeAlignment().isEmpty())
1151 m_output << ", " << language::enumValue(value: node->attributeAlignment());
1152 } else if (layout->attributeClass() == "QFormLayout"_L1) {
1153 const int row = node->attributeRow();
1154 const int colSpan = node->hasAttributeColSpan() ? node->attributeColSpan() : 1;
1155 const QString role = formLayoutRole(column: node->attributeColumn(), colspan: colSpan);
1156 m_output << row << ", " << language::enumValue(value: role) << ", " << itemName;
1157 } else {
1158 m_output << itemName;
1159 if (layout->attributeClass().contains(s: "Box"_L1) && !node->attributeAlignment().isEmpty())
1160 m_output << ", 0, " << language::enumValue(value: node->attributeAlignment());
1161 }
1162 m_output << ")" << language::eol << "\n";
1163}
1164
1165void WriteInitialization::acceptActionGroup(DomActionGroup *node)
1166{
1167 const QString actionName = m_driver->findOrInsertActionGroup(ui_group: node);
1168 QString varName = m_driver->findOrInsertWidget(ui_widget: m_widgetChain.top());
1169
1170 if (m_actionGroupChain.top())
1171 varName = m_driver->findOrInsertActionGroup(ui_group: m_actionGroupChain.top());
1172
1173 m_output << m_indent << actionName << " = " << language::operatorNew
1174 << "QActionGroup(" << varName << ")" << language::eol;
1175 writeProperties(varName: actionName, className: "QActionGroup"_L1, lst: node->elementProperty());
1176
1177 m_actionGroupChain.push(t: node);
1178 TreeWalker::acceptActionGroup(actionGroup: node);
1179 m_actionGroupChain.pop();
1180}
1181
1182void WriteInitialization::acceptAction(DomAction *node)
1183{
1184 if (node->hasAttributeMenu())
1185 return;
1186
1187 const QString actionName = m_driver->findOrInsertAction(ui_action: node);
1188 QString varName = m_driver->findOrInsertWidget(ui_widget: m_widgetChain.top());
1189
1190 if (m_actionGroupChain.top())
1191 varName = m_driver->findOrInsertActionGroup(ui_group: m_actionGroupChain.top());
1192
1193 m_output << m_indent << actionName << " = " << language::operatorNew
1194 << "QAction(" << varName << ')' << language::eol;
1195 writeProperties(varName: actionName, className: "QAction"_L1, lst: node->elementProperty());
1196}
1197
1198void WriteInitialization::acceptActionRef(DomActionRef *node)
1199{
1200 QString actionName = node->attributeName();
1201 if (actionName.isEmpty() || !m_widgetChain.top()
1202 || m_driver->actionGroupByName(attributeName: actionName)) {
1203 return;
1204 }
1205
1206 const QString varName = m_driver->findOrInsertWidget(ui_widget: m_widgetChain.top());
1207
1208 if (m_widgetChain.top() && actionName == "separator"_L1) {
1209 // separator is always reserved!
1210 m_actionOut << m_indent << varName << language::derefPointer
1211 << "addSeparator()" << language::eol;
1212 return;
1213 }
1214
1215 const DomWidget *domWidget = m_driver->widgetByName(attributeName: actionName);
1216 if (domWidget && m_uic->isMenu(className: domWidget->attributeClass())) {
1217 m_actionOut << m_indent << varName << language::derefPointer
1218 << "addAction(" << m_driver->findOrInsertWidget(ui_widget: domWidget)
1219 << language::derefPointer << "menuAction())" << language::eol;
1220 return;
1221 }
1222
1223 const DomAction *domAction = m_driver->actionByName(attributeName: actionName);
1224 if (!domAction) {
1225 fprintf(stderr, format: "%s: Warning: action `%s' not declared\n",
1226 qPrintable(m_option.messagePrefix()), qPrintable(actionName));
1227 return;
1228 }
1229
1230 m_actionOut << m_indent << varName << language::derefPointer
1231 << "addAction(" << m_driver->findOrInsertAction(ui_action: domAction)
1232 << ')' << language::eol;
1233}
1234
1235QString WriteInitialization::writeStringListProperty(const DomStringList *list) const
1236{
1237 QString propertyValue;
1238 QTextStream str(&propertyValue);
1239 char trailingDelimiter = '}';
1240 switch (language::language()) {
1241 case Language::Cpp:
1242 str << "QStringList{";
1243 break;
1244 case Language::Python:
1245 str << '[';
1246 trailingDelimiter = ']';
1247 break;
1248 }
1249 const QStringList values = list->elementString();
1250 if (!values.isEmpty()) {
1251 if (needsTranslation(element: list)) {
1252 const QString comment = list->attributeComment();
1253 const qsizetype last = values.size() - 1;
1254 for (qsizetype i = 0; i <= last; ++i) {
1255 str << '\n' << m_indent << " " << trCall(str: values.at(i), comment);
1256 if (i != last)
1257 str << ',';
1258 }
1259 } else {
1260 for (qsizetype i = 0; i < values.size(); ++i) {
1261 if (i)
1262 str << ", ";
1263 str << language::qstring(values.at(i), m_dindent);
1264 }
1265 }
1266 }
1267 str << trailingDelimiter;
1268 return propertyValue;
1269}
1270
1271static QString configKeyForProperty(const QString &propertyName)
1272{
1273 if (propertyName == "toolTip"_L1)
1274 return toolTipConfigKey();
1275 if (propertyName == "whatsThis"_L1)
1276 return whatsThisConfigKey();
1277 if (propertyName == "statusTip"_L1)
1278 return statusTipConfigKey();
1279 if (propertyName == "shortcut"_L1)
1280 return shortcutConfigKey();
1281 if (propertyName == "accessibleName"_L1 || propertyName == "accessibleDescription"_L1)
1282 return accessibilityConfigKey();
1283 return {};
1284}
1285
1286void WriteInitialization::writeProperties(const QString &varName,
1287 const QString &className,
1288 const DomPropertyList &lst,
1289 unsigned flags)
1290{
1291 const bool isTopLevel = m_widgetChain.size() == 1;
1292
1293 if (m_uic->customWidgetsInfo()->extends(className, baseClassName: "QAxWidget")) {
1294 DomPropertyMap properties = propertyMap(properties: lst);
1295 if (DomProperty *p = properties.value(key: "control"_L1)) {
1296 m_output << m_indent << varName << language::derefPointer << "setControl("
1297 << language::qstring(toString(str: p->elementString()), m_dindent)
1298 << ')' << language::eol;
1299 }
1300 }
1301
1302 QString indent;
1303 if (!m_widgetChain.top()) {
1304 indent = m_option.indent;
1305 switch (language::language()) {
1306 case Language::Cpp:
1307 m_output << m_indent << "if (" << varName << "->objectName().isEmpty())\n";
1308 break;
1309 case Language::Python:
1310 m_output << m_indent << "if not " << varName << ".objectName():\n";
1311 break;
1312 }
1313 }
1314 if (!(flags & WritePropertyIgnoreObjectName)) {
1315 QString objectName = varName;
1316 if (!language::self.isEmpty() && objectName.startsWith(s: language::self))
1317 objectName.remove(i: 0, len: language::self.size());
1318 m_output << m_indent << indent
1319 << varName << language::derefPointer << "setObjectName("
1320 << language::charliteral(objectName, m_dindent) << ')' << language::eol;
1321 }
1322
1323 int leftMargin = -1;
1324 int topMargin = -1;
1325 int rightMargin = -1;
1326 int bottomMargin = -1;
1327 bool frameShadowEncountered = false;
1328
1329 for (const DomProperty *p : lst) {
1330 if (!checkProperty(customWidgetsInfo: m_uic->customWidgetsInfo(), fileName: m_option.inputFile, className, p))
1331 continue;
1332 QString propertyName = p->attributeName();
1333 QString propertyValue;
1334 bool delayProperty = false;
1335
1336 // special case for the property `geometry': Do not use position
1337 if (isTopLevel && propertyName == "geometry"_L1 && p->elementRect()) {
1338 const DomRect *r = p->elementRect();
1339 m_output << m_indent << varName << language::derefPointer << "resize("
1340 << r->elementWidth() << ", " << r->elementHeight() << ')' << language::eol;
1341 continue;
1342 }
1343 if (propertyName == "currentRow"_L1 // QListWidget::currentRow
1344 && m_uic->customWidgetsInfo()->extends(className, baseClassName: "QListWidget")) {
1345 m_delayedOut << m_indent << varName << language::derefPointer
1346 << "setCurrentRow(" << p->elementNumber() << ')' << language::eol;
1347 continue;
1348 }
1349 static const QStringList currentIndexWidgets = {
1350 u"QComboBox"_s, u"QStackedWidget"_s,
1351 u"QTabWidget"_s, u"QToolBox"_s
1352 };
1353 if (propertyName == "currentIndex"_L1 // set currentIndex later
1354 && (m_uic->customWidgetsInfo()->extendsOneOf(className, baseClassNames: currentIndexWidgets))) {
1355 m_delayedOut << m_indent << varName << language::derefPointer
1356 << "setCurrentIndex(" << p->elementNumber() << ')' << language::eol;
1357 continue;
1358 }
1359 if (propertyName == "tabSpacing"_L1
1360 && m_uic->customWidgetsInfo()->extends(className, baseClassName: "QToolBox")) {
1361 m_delayedOut << m_indent << varName << language::derefPointer
1362 << "layout()" << language::derefPointer << "setSpacing("
1363 << p->elementNumber() << ')' << language::eol;
1364 continue;
1365 }
1366 if (propertyName == "control"_L1 // ActiveQt support
1367 && m_uic->customWidgetsInfo()->extends(className, baseClassName: "QAxWidget")) {
1368 // already done ;)
1369 continue;
1370 }
1371 if (propertyName == "default"_L1
1372 && m_uic->customWidgetsInfo()->extends(className, baseClassName: "QPushButton")) {
1373 // QTBUG-44406: Setting of QPushButton::default needs to be delayed until the parent is set
1374 delayProperty = true;
1375 } else if (propertyName == "database"_L1
1376 && p->elementStringList()) {
1377 // Sql support
1378 continue;
1379 } else if (propertyName == "frameworkCode"_L1
1380 && p->kind() == DomProperty::Bool) {
1381 // Sql support
1382 continue;
1383 } else if (propertyName == "orientation"_L1
1384 && m_uic->customWidgetsInfo()->extends(className, baseClassName: "Line")) {
1385 // Line support
1386 QString shape = u"QFrame::Shape::HLine"_s;
1387 if (p->elementEnum().endsWith(s: "::Vertical"_L1))
1388 shape = u"QFrame::Shape::VLine"_s;
1389
1390 m_output << m_indent << varName << language::derefPointer << "setFrameShape("
1391 << language::enumValue(value: shape) << ')' << language::eol;
1392 // QFrame Default is 'Plain'. Make the line 'Sunken' unless otherwise specified
1393 if (!frameShadowEncountered) {
1394 m_output << m_indent << varName << language::derefPointer
1395 << "setFrameShadow("
1396 << language::enumValue(value: "QFrame::Shadow::Sunken"_L1)
1397 << ')' << language::eol;
1398 }
1399 continue;
1400 } else if ((flags & WritePropertyIgnoreMargin) && propertyName == "margin"_L1) {
1401 continue;
1402 } else if ((flags & WritePropertyIgnoreSpacing) && propertyName == "spacing"_L1) {
1403 continue;
1404 } else if (propertyName == "leftMargin"_L1 && p->kind() == DomProperty::Number) {
1405 leftMargin = p->elementNumber();
1406 continue;
1407 } else if (propertyName == "topMargin"_L1 && p->kind() == DomProperty::Number) {
1408 topMargin = p->elementNumber();
1409 continue;
1410 } else if (propertyName == "rightMargin"_L1 && p->kind() == DomProperty::Number) {
1411 rightMargin = p->elementNumber();
1412 continue;
1413 } else if (propertyName == "bottomMargin"_L1 && p->kind() == DomProperty::Number) {
1414 bottomMargin = p->elementNumber();
1415 continue;
1416 } else if (propertyName == "numDigits"_L1 // Deprecated in Qt 4, removed in Qt 5.
1417 && m_uic->customWidgetsInfo()->extends(className, baseClassName: "QLCDNumber")) {
1418 qWarning(msg: "Widget '%s': Deprecated property QLCDNumber::numDigits encountered. It has been replaced by QLCDNumber::digitCount.",
1419 qPrintable(varName));
1420 propertyName = "digitCount"_L1;
1421 } else if (propertyName == "frameShadow"_L1) {
1422 frameShadowEncountered = true;
1423 }
1424
1425 bool stdset = m_stdsetdef;
1426 if (p->hasAttributeStdset())
1427 stdset = p->attributeStdset();
1428
1429 QString setFunction;
1430
1431 {
1432 QTextStream str(&setFunction);
1433 if (stdset) {
1434 str << language::derefPointer <<"set" << propertyName.at(i: 0).toUpper()
1435 << QStringView{propertyName}.mid(pos: 1) << '(';
1436 } else {
1437 str << language::derefPointer << "setProperty("_L1
1438 << language::charliteral(propertyName) << ", ";
1439 if (language::language() == Language::Cpp) {
1440 str << "QVariant";
1441 if (p->kind() == DomProperty::Enum)
1442 str << "::fromValue";
1443 str << '(';
1444 }
1445 }
1446 } // QTextStream
1447
1448 QString varNewName = varName;
1449
1450 switch (p->kind()) {
1451 case DomProperty::Bool: {
1452 propertyValue = language::boolValue(v: p->elementBool() == language::cppTrue);
1453 break;
1454 }
1455 case DomProperty::Color:
1456 propertyValue = domColor2QString(c: p->elementColor());
1457 break;
1458 case DomProperty::Cstring:
1459 if (propertyName == "buddy"_L1 && m_uic->customWidgetsInfo()->extends(className, baseClassName: "QLabel")) {
1460 Buddy buddy = { .labelVarName: varName, .buddyAttributeName: p->elementCstring() };
1461 m_buddies.append(t: std::move(buddy));
1462 } else {
1463 const bool useQByteArray = !stdset && language::language() == Language::Cpp;
1464 QTextStream str(&propertyValue);
1465 if (useQByteArray)
1466 str << "QByteArray(";
1467 str << language::charliteral(p->elementCstring(), m_dindent);
1468 if (useQByteArray)
1469 str << ')';
1470 }
1471 break;
1472 case DomProperty::Cursor:
1473 propertyValue = QString::fromLatin1(ba: "QCursor(static_cast<Qt::CursorShape>(%1))")
1474 .arg(a: p->elementCursor());
1475 break;
1476 case DomProperty::CursorShape:
1477 if (p->hasAttributeStdset() && !p->attributeStdset())
1478 varNewName += language::derefPointer + "viewport()"_L1;
1479 propertyValue = "QCursor(Qt"_L1 + language::qualifier + "CursorShape"_L1
1480 + language::qualifier + p->elementCursorShape() + u')';
1481 break;
1482 case DomProperty::Enum:
1483 propertyValue = p->elementEnum();
1484 if (propertyValue.contains(s: language::cppQualifier))
1485 propertyValue = language::enumValue(value: propertyValue);
1486 else
1487 propertyValue.prepend(s: className + language::qualifier);
1488 break;
1489 case DomProperty::Set:
1490 propertyValue = language::enumValue(value: p->elementSet());
1491 break;
1492 case DomProperty::Font:
1493 propertyValue = writeFontProperties(f: p->elementFont());
1494 break;
1495 case DomProperty::IconSet:
1496 propertyValue = writeIconProperties(i: p->elementIconSet());
1497 break;
1498 case DomProperty::Pixmap:
1499 propertyValue = pixCall(prop: p);
1500 break;
1501 case DomProperty::Palette: {
1502 const DomPalette *pal = p->elementPalette();
1503 const QString paletteName = m_driver->unique(instanceName: "palette"_L1);
1504 m_output << m_indent << language::stackVariable("QPalette", paletteName)
1505 << language::eol;
1506 writeColorGroup(colorGroup: pal->elementActive(), group: "QPalette::Active"_L1, paletteName);
1507 writeColorGroup(colorGroup: pal->elementInactive(), group: "QPalette::Inactive"_L1, paletteName);
1508 writeColorGroup(colorGroup: pal->elementDisabled(), group: "QPalette::Disabled"_L1, paletteName);
1509
1510 propertyValue = paletteName;
1511 break;
1512 }
1513 case DomProperty::Point: {
1514 const DomPoint *po = p->elementPoint();
1515 propertyValue = QString::fromLatin1(ba: "QPoint(%1, %2)")
1516 .arg(a: po->elementX()).arg(a: po->elementY());
1517 break;
1518 }
1519 case DomProperty::PointF: {
1520 const DomPointF *pof = p->elementPointF();
1521 propertyValue = QString::fromLatin1(ba: "QPointF(%1, %2)")
1522 .arg(a: pof->elementX()).arg(a: pof->elementY());
1523 break;
1524 }
1525 case DomProperty::Rect: {
1526 const DomRect *r = p->elementRect();
1527 propertyValue = QString::fromLatin1(ba: "QRect(%1, %2, %3, %4)")
1528 .arg(a: r->elementX()).arg(a: r->elementY())
1529 .arg(a: r->elementWidth()).arg(a: r->elementHeight());
1530 break;
1531 }
1532 case DomProperty::RectF: {
1533 const DomRectF *rf = p->elementRectF();
1534 propertyValue = QString::fromLatin1(ba: "QRectF(%1, %2, %3, %4)")
1535 .arg(a: rf->elementX()).arg(a: rf->elementY())
1536 .arg(a: rf->elementWidth()).arg(a: rf->elementHeight());
1537 break;
1538 }
1539 case DomProperty::Locale: {
1540 const DomLocale *locale = p->elementLocale();
1541 QTextStream(&propertyValue) << "QLocale(QLocale" << language::qualifier
1542 << locale->attributeLanguage() << ", QLocale" << language::qualifier
1543 << locale->attributeCountry() << ')';
1544 break;
1545 }
1546 case DomProperty::SizePolicy: {
1547 const QString spName = writeSizePolicy( sp: p->elementSizePolicy());
1548 m_output << m_indent << spName << ".setHeightForWidth("
1549 << varName << language::derefPointer << "sizePolicy().hasHeightForWidth())"
1550 << language::eol;
1551
1552 propertyValue = spName;
1553 break;
1554 }
1555 case DomProperty::Size: {
1556 const DomSize *s = p->elementSize();
1557 propertyValue = QString::fromLatin1(ba: "QSize(%1, %2)")
1558 .arg(a: s->elementWidth()).arg(a: s->elementHeight());
1559 break;
1560 }
1561 case DomProperty::SizeF: {
1562 const DomSizeF *sf = p->elementSizeF();
1563 propertyValue = QString::fromLatin1(ba: "QSizeF(%1, %2)")
1564 .arg(a: sf->elementWidth()).arg(a: sf->elementHeight());
1565 break;
1566 }
1567 case DomProperty::String: {
1568 if (propertyName == "objectName"_L1) {
1569 const QString v = p->elementString()->text();
1570 if (v == varName)
1571 break;
1572
1573 // ### qWarning("Deprecated: the property `objectName' is different from the variable name");
1574 }
1575
1576 propertyValue = autoTrCall(str: p->elementString());
1577 break;
1578 }
1579 case DomProperty::Number:
1580 propertyValue = QString::number(p->elementNumber());
1581 break;
1582 case DomProperty::UInt:
1583 propertyValue = QString::number(p->elementUInt());
1584 propertyValue += u'u';
1585 break;
1586 case DomProperty::LongLong:
1587 propertyValue = "Q_INT64_C("_L1;
1588 propertyValue += QString::number(p->elementLongLong());
1589 propertyValue += u')';
1590 break;
1591 case DomProperty::ULongLong:
1592 propertyValue = "Q_UINT64_C("_L1;
1593 propertyValue += QString::number(p->elementULongLong());
1594 propertyValue += u')';
1595 break;
1596 case DomProperty::Float:
1597 propertyValue = QString::number(p->elementFloat(), format: 'f', precision: 8);
1598 break;
1599 case DomProperty::Double:
1600 propertyValue = QString::number(p->elementDouble(), format: 'f', precision: 15);
1601 break;
1602 case DomProperty::Char: {
1603 const DomChar *c = p->elementChar();
1604 propertyValue = QString::fromLatin1(ba: "QChar(%1)")
1605 .arg(a: c->elementUnicode());
1606 break;
1607 }
1608 case DomProperty::Date: {
1609 const DomDate *d = p->elementDate();
1610 propertyValue = QString::fromLatin1(ba: "QDate(%1, %2, %3)")
1611 .arg(a: d->elementYear())
1612 .arg(a: d->elementMonth())
1613 .arg(a: d->elementDay());
1614 break;
1615 }
1616 case DomProperty::Time: {
1617 const DomTime *t = p->elementTime();
1618 propertyValue = QString::fromLatin1(ba: "QTime(%1, %2, %3)")
1619 .arg(a: t->elementHour())
1620 .arg(a: t->elementMinute())
1621 .arg(a: t->elementSecond());
1622 break;
1623 }
1624 case DomProperty::DateTime: {
1625 const DomDateTime *dt = p->elementDateTime();
1626 propertyValue = QString::fromLatin1(ba: "QDateTime(QDate(%1, %2, %3), QTime(%4, %5, %6))")
1627 .arg(a: dt->elementYear())
1628 .arg(a: dt->elementMonth())
1629 .arg(a: dt->elementDay())
1630 .arg(a: dt->elementHour())
1631 .arg(a: dt->elementMinute())
1632 .arg(a: dt->elementSecond());
1633 break;
1634 }
1635 case DomProperty::StringList:
1636 propertyValue = writeStringListProperty(list: p->elementStringList());
1637 break;
1638
1639 case DomProperty::Url: {
1640 const DomUrl* u = p->elementUrl();
1641 QTextStream(&propertyValue) << "QUrl("
1642 << language::qstring(u->elementString()->text(), m_dindent) << ")";
1643 break;
1644 }
1645 case DomProperty::Brush:
1646 propertyValue = writeBrushInitialization(brush: p->elementBrush());
1647 break;
1648 case DomProperty::Unknown:
1649 break;
1650 }
1651
1652 if (!propertyValue.isEmpty()) {
1653 const QString configKey = configKeyForProperty(propertyName);
1654
1655 QTextStream &o = delayProperty ? m_delayedOut : autoTrOutput(str: p);
1656
1657 if (!configKey.isEmpty())
1658 o << language::openQtConfig(configKey);
1659 o << m_indent << varNewName << setFunction << propertyValue;
1660 if (!stdset && language::language() == Language::Cpp)
1661 o << ')';
1662 o << ')' << language::eol;
1663 if (!configKey.isEmpty())
1664 o << language::closeQtConfig(configKey);
1665
1666 if (varName == m_mainFormVarName && &o == &m_refreshOut) {
1667 // this is the only place (currently) where we output mainForm name to the retranslateUi().
1668 // Other places output merely instances of a certain class (which cannot be main form, e.g. QListWidget).
1669 m_mainFormUsedInRetranslateUi = true;
1670 }
1671 }
1672 }
1673 if (leftMargin != -1 || topMargin != -1 || rightMargin != -1 || bottomMargin != -1) {
1674 m_output << m_indent << varName << language::derefPointer << "setContentsMargins("
1675 << leftMargin << ", " << topMargin << ", "
1676 << rightMargin << ", " << bottomMargin << ")" << language::eol;
1677 }
1678}
1679
1680QString WriteInitialization::writeSizePolicy(const DomSizePolicy *sp)
1681{
1682
1683 // check cache
1684 const SizePolicyHandle sizePolicyHandle(sp);
1685 const SizePolicyNameMap::const_iterator it = m_sizePolicyNameMap.constFind(key: sizePolicyHandle);
1686 if ( it != m_sizePolicyNameMap.constEnd()) {
1687 return it.value();
1688 }
1689
1690
1691 // insert with new name
1692 const QString spName = m_driver->unique(instanceName: "sizePolicy"_L1);
1693 m_sizePolicyNameMap.insert(key: sizePolicyHandle, value: spName);
1694
1695 m_output << m_indent << language::stackVariableWithInitParameters("QSizePolicy", spName);
1696 QString horizPolicy;
1697 QString vertPolicy;
1698 if (sp->hasElementHSizeType() && sp->hasElementVSizeType()) {
1699 horizPolicy = language::sizePolicy(v: sp->elementHSizeType());
1700 vertPolicy = language::sizePolicy(v: sp->elementVSizeType());
1701 } else if (sp->hasAttributeHSizeType() && sp->hasAttributeVSizeType()) {
1702 horizPolicy = sp->attributeHSizeType();
1703 vertPolicy = sp->attributeVSizeType();
1704 }
1705 if (!horizPolicy.isEmpty() && !vertPolicy.isEmpty()) {
1706 m_output << language::enumValue(value: expandSizePolicyEnum(value: horizPolicy))
1707 << ", " << language::enumValue(value: expandSizePolicyEnum(value: vertPolicy));
1708 }
1709 m_output << ')' << language::eol;
1710
1711 m_output << m_indent << spName << ".setHorizontalStretch("
1712 << sp->elementHorStretch() << ")" << language::eol;
1713 m_output << m_indent << spName << ".setVerticalStretch("
1714 << sp->elementVerStretch() << ")" << language::eol;
1715 return spName;
1716}
1717// Check for a font with the given properties in the FontPropertiesNameMap
1718// or create a new one. Returns the name.
1719
1720QString WriteInitialization::writeFontProperties(const DomFont *f)
1721{
1722 // check cache
1723 const FontHandle fontHandle(f);
1724 const FontPropertiesNameMap::const_iterator it = m_fontPropertiesNameMap.constFind(key: fontHandle);
1725 if ( it != m_fontPropertiesNameMap.constEnd()) {
1726 return it.value();
1727 }
1728
1729 // insert with new name
1730 const QString fontName = m_driver->unique(instanceName: "font"_L1);
1731 m_fontPropertiesNameMap.insert(key: FontHandle(f), value: fontName);
1732
1733 m_output << m_indent << language::stackVariable("QFont", fontName)
1734 << language::eol;
1735 if (f->hasElementFamily() && !f->elementFamily().isEmpty()) {
1736 m_output << m_indent << fontName << ".setFamilies("
1737 << language::listStart
1738 << language::qstring(f->elementFamily(), m_dindent)
1739 << language::listEnd << ')' << language::eol;
1740 }
1741 if (f->hasElementPointSize() && f->elementPointSize() > 0) {
1742 m_output << m_indent << fontName << ".setPointSize(" << f->elementPointSize()
1743 << ")" << language::eol;
1744 }
1745
1746 if (f->hasElementFontWeight()) {
1747 m_output << m_indent << fontName << ".setWeight(QFont"
1748 << language::qualifier << f->elementFontWeight() << ')' << language::eol;
1749 } else if (f->hasElementBold()) {
1750 m_output << m_indent << fontName << ".setBold("
1751 << language::boolValue(v: f->elementBold()) << ')' << language::eol;
1752 }
1753
1754 if (f->hasElementItalic()) {
1755 m_output << m_indent << fontName << ".setItalic("
1756 << language::boolValue(v: f->elementItalic()) << ')' << language::eol;
1757 }
1758 if (f->hasElementUnderline()) {
1759 m_output << m_indent << fontName << ".setUnderline("
1760 << language::boolValue(v: f->elementUnderline()) << ')' << language::eol;
1761 }
1762 if (f->hasElementStrikeOut()) {
1763 m_output << m_indent << fontName << ".setStrikeOut("
1764 << language::boolValue(v: f->elementStrikeOut()) << ')' << language::eol;
1765 }
1766 if (f->hasElementKerning()) {
1767 m_output << m_indent << fontName << ".setKerning("
1768 << language::boolValue(v: f->elementKerning()) << ')' << language::eol;
1769 }
1770 if (f->hasElementAntialiasing()) {
1771 m_output << m_indent << fontName << ".setStyleStrategy(QFont"
1772 << language::qualifier
1773 << (f->elementAntialiasing() ? "PreferDefault" : "NoAntialias")
1774 << ')' << language::eol;
1775 }
1776 if (f->hasElementStyleStrategy()) {
1777 m_output << m_indent << fontName << ".setStyleStrategy(QFont"
1778 << language::qualifier << f->elementStyleStrategy() << ')' << language::eol;
1779 }
1780 if (f->hasElementHintingPreference()) {
1781 m_output << m_indent << fontName << ".setHintingPreference(QFont"
1782 << language::qualifier << f->elementHintingPreference() << ')' << language::eol;
1783 }
1784
1785 return fontName;
1786}
1787
1788static void writeIconAddFile(QTextStream &output, const QString &indent,
1789 const QString &iconName, const QString &fileName,
1790 const char *mode, const char *state)
1791{
1792 output << indent << iconName << ".addFile("
1793 << language::qstring(fileName, indent) << ", QSize(), QIcon"
1794 << language::qualifier << "Mode" << language::qualifier << mode
1795 << ", QIcon" << language::qualifier << "State" << language::qualifier << state
1796 << ')' << language::eol;
1797}
1798
1799// Post 4.4 write resource icon
1800static void writeResourceIcon(QTextStream &output,
1801 const QString &iconName,
1802 const QString &indent,
1803 const DomResourceIcon *i)
1804{
1805 if (i->hasElementNormalOff()) {
1806 writeIconAddFile(output, indent, iconName, fileName: i->elementNormalOff()->text(),
1807 mode: "Normal", state: "Off");
1808 }
1809 if (i->hasElementNormalOn()) {
1810 writeIconAddFile(output, indent, iconName, fileName: i->elementNormalOn()->text(),
1811 mode: "Normal", state: "On");
1812 }
1813 if (i->hasElementDisabledOff()) {
1814 writeIconAddFile(output, indent, iconName, fileName: i->elementDisabledOff()->text(),
1815 mode: "Disabled", state: "Off");
1816 }
1817 if (i->hasElementDisabledOn()) {
1818 writeIconAddFile(output, indent, iconName, fileName: i->elementDisabledOn()->text(),
1819 mode: "Disabled", state: "On");
1820 }
1821 if (i->hasElementActiveOff()) {
1822 writeIconAddFile(output, indent, iconName, fileName: i->elementActiveOff()->text(),
1823 mode: "Active", state: "Off");
1824 }
1825 if (i->hasElementActiveOn()) {
1826 writeIconAddFile(output, indent, iconName, fileName: i->elementActiveOn()->text(),
1827 mode: "Active", state: "On");
1828 }
1829 if (i->hasElementSelectedOff()) {
1830 writeIconAddFile(output, indent, iconName, fileName: i->elementSelectedOff()->text(),
1831 mode: "Selected", state: "Off");
1832 }
1833 if (i->hasElementSelectedOn()) {
1834 writeIconAddFile(output, indent, iconName, fileName: i->elementSelectedOn()->text(),
1835 mode: "Selected", state: "On");
1836 }
1837}
1838
1839static void writeIconAddPixmap(QTextStream &output, const QString &indent,
1840 const QString &iconName, const QString &call,
1841 const char *mode, const char *state)
1842{
1843 output << indent << iconName << ".addPixmap(" << call << ", QIcon"
1844 << language::qualifier << "Mode" << language::qualifier << mode
1845 << ", QIcon" << language::qualifier << "State" << language::qualifier
1846 << state << ')' << language::eol;
1847}
1848
1849void WriteInitialization::writePixmapFunctionIcon(QTextStream &output,
1850 const QString &iconName,
1851 const QString &indent,
1852 const DomResourceIcon *i) const
1853{
1854 if (i->hasElementNormalOff()) {
1855 writeIconAddPixmap(output, indent, iconName,
1856 call: pixCall(type: "QPixmap"_L1, text: i->elementNormalOff()->text()),
1857 mode: "Normal", state: "Off");
1858 }
1859 if (i->hasElementNormalOn()) {
1860 writeIconAddPixmap(output, indent, iconName,
1861 call: pixCall(type: "QPixmap"_L1, text: i->elementNormalOn()->text()),
1862 mode: "Normal", state: "On");
1863 }
1864 if (i->hasElementDisabledOff()) {
1865 writeIconAddPixmap(output, indent, iconName,
1866 call: pixCall(type: "QPixmap"_L1, text: i->elementDisabledOff()->text()),
1867 mode: "Disabled", state: "Off");
1868 }
1869 if (i->hasElementDisabledOn()) {
1870 writeIconAddPixmap(output, indent, iconName,
1871 call: pixCall(type: "QPixmap"_L1, text: i->elementDisabledOn()->text()),
1872 mode: "Disabled", state: "On");
1873 }
1874 if (i->hasElementActiveOff()) {
1875 writeIconAddPixmap(output, indent, iconName,
1876 call: pixCall(type: "QPixmap"_L1, text: i->elementActiveOff()->text()),
1877 mode: "Active", state: "Off");
1878 }
1879 if (i->hasElementActiveOn()) {
1880 writeIconAddPixmap(output, indent, iconName,
1881 call: pixCall(type: "QPixmap"_L1, text: i->elementActiveOn()->text()),
1882 mode: "Active", state: "On");
1883 }
1884 if (i->hasElementSelectedOff()) {
1885 writeIconAddPixmap(output, indent, iconName,
1886 call: pixCall(type: "QPixmap"_L1, text: i->elementSelectedOff()->text()),
1887 mode: "Selected", state: "Off");
1888 }
1889 if (i->hasElementSelectedOn()) {
1890 writeIconAddPixmap(output, indent, iconName,
1891 call: pixCall(type: "QPixmap"_L1, text: i->elementSelectedOn()->text()),
1892 mode: "Selected", state: "On");
1893 }
1894}
1895
1896// Write QIcon::fromTheme() (value from enum or variable)
1897struct iconFromTheme
1898{
1899 explicit iconFromTheme(const QString &theme) : m_theme(theme) {}
1900
1901 QString m_theme;
1902};
1903
1904QTextStream &operator<<(QTextStream &str, const iconFromTheme &i)
1905{
1906 str << "QIcon" << language::qualifier << "fromTheme(" << i.m_theme << ')';
1907 return str;
1908}
1909
1910// Write QIcon::fromTheme() for an XDG icon from string literal
1911struct iconFromThemeStringLiteral
1912{
1913 explicit iconFromThemeStringLiteral(const QString &theme) : m_theme(theme) {}
1914
1915 QString m_theme;
1916};
1917
1918QTextStream &operator<<(QTextStream &str, const iconFromThemeStringLiteral &i)
1919{
1920 str << "QIcon" << language::qualifier << "fromTheme(" << language::qstring(i.m_theme) << ')';
1921 return str;
1922}
1923
1924// Write QIcon::fromTheme() with a path as fallback, add a check using
1925// QIcon::hasThemeIcon().
1926void WriteInitialization::writeThemeIconCheckAssignment(const QString &themeValue,
1927 const QString &iconName,
1928 const DomResourceIcon *i)
1929
1930{
1931 const bool isCpp = language::language() == Language::Cpp;
1932 m_output << m_indent << "if ";
1933 if (isCpp)
1934 m_output << '(';
1935 m_output << "QIcon" << language::qualifier << "hasThemeIcon("
1936 << themeValue << ')' << (isCpp ? ") {" : ":") << '\n'
1937 << m_dindent << iconName << " = " << iconFromTheme(themeValue)
1938 << language::eol;
1939 m_output << m_indent << (isCpp ? "} else {" : "else:") << '\n';
1940 if (m_uic->pixmapFunction().isEmpty())
1941 writeResourceIcon(output&: m_output, iconName, indent: m_dindent, i);
1942 else
1943 writePixmapFunctionIcon(output&: m_output, iconName, indent: m_dindent, i);
1944 if (isCpp)
1945 m_output << m_indent << '}';
1946 m_output << '\n';
1947}
1948
1949QString WriteInitialization::writeIconProperties(const DomResourceIcon *i)
1950{
1951 // check cache
1952 const IconHandle iconHandle(i);
1953 const IconPropertiesNameMap::const_iterator it = m_iconPropertiesNameMap.constFind(key: iconHandle);
1954 if (it != m_iconPropertiesNameMap.constEnd())
1955 return it.value();
1956
1957 // insert with new name
1958 const QString iconName = m_driver->unique(instanceName: "icon"_L1);
1959 m_iconPropertiesNameMap.insert(key: IconHandle(i), value: iconName);
1960
1961 const bool isCpp = language::language() == Language::Cpp;
1962
1963 if (Q_UNLIKELY(!isIconFormat44(i))) { // pre-4.4 legacy
1964 m_output << m_indent;
1965 if (isCpp)
1966 m_output << "const QIcon ";
1967 m_output << iconName << " = " << pixCall(type: "QIcon"_L1, text: i->text())
1968 << language::eol;
1969 return iconName;
1970 }
1971
1972 // 4.4 onwards
1973 QString theme = i->attributeTheme();
1974 if (theme.isEmpty()) {
1975 // No theme: Write resource icon as is
1976 m_output << m_indent << language::stackVariable("QIcon", iconName)
1977 << language::eol;
1978 if (m_uic->pixmapFunction().isEmpty())
1979 writeResourceIcon(output&: m_output, iconName, indent: m_indent, i);
1980 else
1981 writePixmapFunctionIcon(output&: m_output, iconName, indent: m_indent, i);
1982 return iconName;
1983 }
1984
1985 const bool isThemeEnum = theme.startsWith(s: "QIcon::"_L1);
1986 if (isThemeEnum)
1987 theme = language::enumValue(value: theme);
1988
1989 // Theme: Generate code to check the theme and default to resource
1990 if (iconHasStatePixmaps(i)) {
1991 // Theme + default state pixmaps:
1992 // Generate code to check the theme and default to state pixmaps
1993 m_output << m_indent << language::stackVariable("QIcon", iconName) << language::eol;
1994 if (isThemeEnum) {
1995 writeThemeIconCheckAssignment(themeValue: theme, iconName, i);
1996 return iconName;
1997 }
1998
1999 static constexpr auto themeNameStringVariableC = "iconThemeName"_L1;
2000 // Store theme name in a variable
2001 m_output << m_indent;
2002 if (m_firstThemeIcon) { // Declare variable string
2003 if (isCpp)
2004 m_output << "QString ";
2005 m_firstThemeIcon = false;
2006 }
2007 m_output << themeNameStringVariableC << " = "
2008 << language::qstring(theme) << language::eol;
2009 writeThemeIconCheckAssignment(themeValue: themeNameStringVariableC, iconName, i);
2010 return iconName;
2011 }
2012
2013 // Theme, but no state pixmaps: Construct from theme directly.
2014 m_output << m_indent
2015 << language::stackVariableWithInitParameters("QIcon", iconName);
2016 if (isThemeEnum)
2017 m_output << iconFromTheme(theme);
2018 else
2019 m_output << iconFromThemeStringLiteral(theme);
2020 m_output << ')' << language::eol;
2021 return iconName;
2022}
2023
2024QString WriteInitialization::domColor2QString(const DomColor *c)
2025{
2026 if (c->hasAttributeAlpha())
2027 return QString::fromLatin1(ba: "QColor(%1, %2, %3, %4)")
2028 .arg(a: c->elementRed())
2029 .arg(a: c->elementGreen())
2030 .arg(a: c->elementBlue())
2031 .arg(a: c->attributeAlpha());
2032 return QString::fromLatin1(ba: "QColor(%1, %2, %3)")
2033 .arg(a: c->elementRed())
2034 .arg(a: c->elementGreen())
2035 .arg(a: c->elementBlue());
2036}
2037
2038static inline QVersionNumber colorRoleVersionAdded(const QString &roleName)
2039{
2040 if (roleName == "PlaceholderText"_L1)
2041 return {5, 12, 0};
2042 return {};
2043}
2044
2045void WriteInitialization::writeColorGroup(DomColorGroup *colorGroup, const QString &group, const QString &paletteName)
2046{
2047 if (!colorGroup)
2048 return;
2049
2050 // old format
2051 const auto &colors = colorGroup->elementColor();
2052 for (int i=0; i<colors.size(); ++i) {
2053 const DomColor *color = colors.at(i);
2054
2055 m_output << m_indent << paletteName << ".setColor(" << group
2056 << ", QPalette" << language::qualifier << language::paletteColorRole(v: i)
2057 << ", " << domColor2QString(c: color)
2058 << ")" << language::eol;
2059 }
2060
2061 // new format
2062 const auto &colorRoles = colorGroup->elementColorRole();
2063 for (const DomColorRole *colorRole : colorRoles) {
2064 if (colorRole->hasAttributeRole()) {
2065 const QString roleName = colorRole->attributeRole();
2066 const QVersionNumber versionAdded = colorRoleVersionAdded(roleName);
2067 const QString brushName = writeBrushInitialization(brush: colorRole->elementBrush());
2068 if (!versionAdded.isNull()) {
2069 m_output << "#if QT_VERSION >= QT_VERSION_CHECK("
2070 << versionAdded.majorVersion() << ", " << versionAdded.minorVersion()
2071 << ", " << versionAdded.microVersion() << ")\n";
2072 }
2073 m_output << m_indent << paletteName << ".setBrush("
2074 << language::enumValue(value: group) << ", "
2075 << "QPalette" << language::qualifier << roleName
2076 << ", " << brushName << ")" << language::eol;
2077 if (!versionAdded.isNull())
2078 m_output << "#endif\n";
2079 }
2080 }
2081}
2082
2083// Write initialization for brush unless it is found in the cache. Returns the name to use
2084// in an expression.
2085QString WriteInitialization::writeBrushInitialization(const DomBrush *brush)
2086{
2087 // Simple solid, colored brushes are cached
2088 const bool solidColoredBrush = !brush->hasAttributeBrushStyle() || brush->attributeBrushStyle() == "SolidPattern"_L1;
2089 uint rgb = 0;
2090 if (solidColoredBrush) {
2091 if (const DomColor *color = brush->elementColor()) {
2092 rgb = ((color->elementRed() & 0xFF) << 24) |
2093 ((color->elementGreen() & 0xFF) << 16) |
2094 ((color->elementBlue() & 0xFF) << 8) |
2095 ((color->attributeAlpha() & 0xFF));
2096 const ColorBrushHash::const_iterator cit = m_colorBrushHash.constFind(key: rgb);
2097 if (cit != m_colorBrushHash.constEnd())
2098 return cit.value();
2099 }
2100 }
2101 // Create and enter into cache if simple
2102 const QString brushName = m_driver->unique(instanceName: "brush"_L1);
2103 writeBrush(brush, brushName);
2104 if (solidColoredBrush)
2105 m_colorBrushHash.insert(key: rgb, value: brushName);
2106 return brushName;
2107}
2108
2109void WriteInitialization::writeBrush(const DomBrush *brush, const QString &brushName)
2110{
2111 QString style = u"SolidPattern"_s;
2112 if (brush->hasAttributeBrushStyle())
2113 style = brush->attributeBrushStyle();
2114
2115 if (style == "LinearGradientPattern"_L1 ||
2116 style == "RadialGradientPattern"_L1 ||
2117 style == "ConicalGradientPattern"_L1) {
2118 const DomGradient *gradient = brush->elementGradient();
2119 const QString gradientType = gradient->attributeType();
2120 const QString gradientName = m_driver->unique(instanceName: "gradient"_L1);
2121 if (gradientType == "LinearGradient"_L1) {
2122 m_output << m_indent
2123 << language::stackVariableWithInitParameters("QLinearGradient", gradientName)
2124 << gradient->attributeStartX()
2125 << ", " << gradient->attributeStartY()
2126 << ", " << gradient->attributeEndX()
2127 << ", " << gradient->attributeEndY() << ')' << language::eol;
2128 } else if (gradientType == "RadialGradient"_L1) {
2129 m_output << m_indent
2130 << language::stackVariableWithInitParameters("QRadialGradient", gradientName)
2131 << gradient->attributeCentralX()
2132 << ", " << gradient->attributeCentralY()
2133 << ", " << gradient->attributeRadius()
2134 << ", " << gradient->attributeFocalX()
2135 << ", " << gradient->attributeFocalY() << ')' << language::eol;
2136 } else if (gradientType == "ConicalGradient"_L1) {
2137 m_output << m_indent
2138 << language::stackVariableWithInitParameters("QConicalGradient", gradientName)
2139 << gradient->attributeCentralX()
2140 << ", " << gradient->attributeCentralY()
2141 << ", " << gradient->attributeAngle() << ')' << language::eol;
2142 }
2143
2144 m_output << m_indent << gradientName << ".setSpread(QGradient"
2145 << language::qualifier << gradient->attributeSpread()
2146 << ')' << language::eol;
2147
2148 if (gradient->hasAttributeCoordinateMode()) {
2149 m_output << m_indent << gradientName << ".setCoordinateMode(QGradient"
2150 << language::qualifier << gradient->attributeCoordinateMode()
2151 << ')' << language::eol;
2152 }
2153
2154 const auto &stops = gradient->elementGradientStop();
2155 for (const DomGradientStop *stop : stops) {
2156 const DomColor *color = stop->elementColor();
2157 m_output << m_indent << gradientName << ".setColorAt("
2158 << stop->attributePosition() << ", "
2159 << domColor2QString(c: color) << ')' << language::eol;
2160 }
2161 m_output << m_indent
2162 << language::stackVariableWithInitParameters("QBrush", brushName)
2163 << gradientName << ')' << language::eol;
2164 } else if (style == "TexturePattern"_L1) {
2165 const DomProperty *property = brush->elementTexture();
2166 const QString iconValue = iconCall(prop: property);
2167
2168 m_output << m_indent
2169 << language::stackVariableWithInitParameters("QBrush", brushName)
2170 << iconValue << ')' << language::eol;
2171 } else {
2172 const DomColor *color = brush->elementColor();
2173 m_output << m_indent
2174 << language::stackVariableWithInitParameters("QBrush", brushName)
2175 << domColor2QString(c: color) << ')' << language::eol;
2176
2177 m_output << m_indent << brushName << ".setStyle("
2178 << language::qtQualifier << style << ')' << language::eol;
2179 }
2180}
2181
2182void WriteInitialization::acceptCustomWidget(DomCustomWidget *node)
2183{
2184 Q_UNUSED(node);
2185}
2186
2187void WriteInitialization::acceptCustomWidgets(DomCustomWidgets *node)
2188{
2189 Q_UNUSED(node);
2190}
2191
2192void WriteInitialization::acceptTabStops(DomTabStops *tabStops)
2193{
2194 QString lastName;
2195
2196 const QStringList l = tabStops->elementTabStop();
2197 for (int i=0; i<l.size(); ++i) {
2198 const QString name = m_driver->widgetVariableName(attributeName: l.at(i));
2199
2200 if (name.isEmpty()) {
2201 fprintf(stderr, format: "%s: Warning: Tab-stop assignment: '%s' is not a valid widget.\n",
2202 qPrintable(m_option.messagePrefix()), qPrintable(l.at(i)));
2203 continue;
2204 }
2205
2206 if (i == 0) {
2207 lastName = name;
2208 continue;
2209 }
2210 if (name.isEmpty() || lastName.isEmpty())
2211 continue;
2212
2213 m_output << m_indent << "QWidget" << language::qualifier << "setTabOrder("
2214 << lastName << ", " << name << ')' << language::eol;
2215
2216 lastName = name;
2217 }
2218}
2219
2220QString WriteInitialization::iconCall(const DomProperty *icon)
2221{
2222 if (icon->kind() == DomProperty::IconSet)
2223 return writeIconProperties(i: icon->elementIconSet());
2224 return pixCall(prop: icon);
2225}
2226
2227QString WriteInitialization::pixCall(const DomProperty *p) const
2228{
2229 QLatin1StringView type;
2230 QString s;
2231 switch (p->kind()) {
2232 case DomProperty::IconSet:
2233 type = "QIcon"_L1;
2234 s = p->elementIconSet()->text();
2235 break;
2236 case DomProperty::Pixmap:
2237 type = "QPixmap"_L1;
2238 s = p->elementPixmap()->text();
2239 break;
2240 default:
2241 qWarning(msg: "%s: Warning: Unknown icon format encountered. The ui-file was generated with a too-recent version of Qt Widgets Designer.",
2242 qPrintable(m_option.messagePrefix()));
2243 return "QIcon()"_L1;
2244 break;
2245 }
2246 return pixCall(type, text: s);
2247}
2248
2249QString WriteInitialization::pixCall(QLatin1StringView t, const QString &text) const
2250{
2251 if (text.isEmpty())
2252 return t % "()"_L1;
2253
2254 QString result;
2255 QTextStream str(&result);
2256 str << t;
2257 str << '(';
2258 const QString pixFunc = m_uic->pixmapFunction();
2259 if (pixFunc.isEmpty())
2260 str << language::qstring(text, m_dindent);
2261 else
2262 str << pixFunc << '(' << language::charliteral(text, m_dindent) << ')';
2263 str << ')';
2264 return result;
2265}
2266
2267void WriteInitialization::initializeComboBox(DomWidget *w)
2268{
2269 const QString varName = m_driver->findOrInsertWidget(ui_widget: w);
2270
2271 const auto &items = w->elementItem();
2272
2273 if (items.isEmpty())
2274 return;
2275
2276 for (int i = 0; i < items.size(); ++i) {
2277 const DomItem *item = items.at(i);
2278 const DomPropertyMap properties = propertyMap(properties: item->elementProperty());
2279 const DomProperty *text = properties.value(key: "text"_L1);
2280 const DomProperty *icon = properties.value(key: "icon"_L1);
2281
2282 QString iconValue;
2283 if (icon)
2284 iconValue = iconCall(icon);
2285
2286 m_output << m_indent << varName << language::derefPointer << "addItem(";
2287 if (icon)
2288 m_output << iconValue << ", ";
2289
2290 if (needsTranslation(element: text->elementString())) {
2291 m_output << language::emptyString << ')' << language::eol;
2292 m_refreshOut << m_indent << varName << language::derefPointer
2293 << "setItemText(" << i << ", " << trCall(str: text->elementString())
2294 << ')' << language::eol;
2295 } else {
2296 m_output << noTrCall(str: text->elementString()) << ")" << language::eol;
2297 }
2298 }
2299 m_refreshOut << "\n";
2300}
2301
2302QString WriteInitialization::disableSorting(DomWidget *w, const QString &varName)
2303{
2304 // turn off sortingEnabled to force programmatic item order (setItem())
2305 QString tempName;
2306 if (!w->elementItem().isEmpty()) {
2307 tempName = m_driver->unique(instanceName: "__sortingEnabled"_L1);
2308 m_refreshOut << "\n";
2309 m_refreshOut << m_indent;
2310 if (language::language() == Language::Cpp)
2311 m_refreshOut << "const bool ";
2312 m_refreshOut << tempName << " = " << varName << language::derefPointer
2313 << "isSortingEnabled()" << language::eol
2314 << m_indent << varName << language::derefPointer
2315 << "setSortingEnabled(" << language::boolValue(v: false) << ')' << language::eol;
2316 }
2317 return tempName;
2318}
2319
2320void WriteInitialization::enableSorting(DomWidget *w, const QString &varName, const QString &tempName)
2321{
2322 if (!w->elementItem().isEmpty()) {
2323 m_refreshOut << m_indent << varName << language::derefPointer
2324 << "setSortingEnabled(" << tempName << ')' << language::eol << '\n';
2325 }
2326}
2327
2328/*
2329 * Initializers are just strings containing the function call and need to be prepended
2330 * the line indentation and the object they are supposed to initialize.
2331 * String initializers come with a preprocessor conditional (ifdef), so the code
2332 * compiles with QT_NO_xxx. A null pointer means no conditional. String initializers
2333 * are written to the retranslateUi() function, others to setupUi().
2334 */
2335
2336
2337/*!
2338 Create non-string inititializer.
2339 \param value the value to initialize the attribute with. May be empty, in which case
2340 the initializer is omitted.
2341 See above for other parameters.
2342*/
2343void WriteInitialization::addInitializer(Item *item, const QString &name,
2344 int column, const QString &value,
2345 const QString &directive, bool translatable)
2346{
2347 if (!value.isEmpty()) {
2348 QString setter;
2349 QTextStream str(&setter);
2350 str << language::derefPointer << "set" << name.at(i: 0).toUpper() << QStringView{name}.mid(pos: 1) << '(';
2351 if (column >= 0)
2352 str << column << ", ";
2353 str << value << ");";
2354 item->addSetter(setter, directive, translatable);
2355 }
2356}
2357
2358/*!
2359 Create string inititializer.
2360 \param initializers in/out list of inializers
2361 \param properties map property name -> property to extract data from
2362 \param name the property to extract
2363 \param col the item column to generate the initializer for. This is relevant for
2364 tree widgets only. If it is -1, no column index will be generated.
2365 \param ifdef preprocessor symbol for disabling compilation of this initializer
2366*/
2367void WriteInitialization::addStringInitializer(Item *item,
2368 const DomPropertyMap &properties, const QString &name, int column, const QString &directive) const
2369{
2370 if (const DomProperty *p = properties.value(key: name)) {
2371 DomString *str = p->elementString();
2372 QString text = toString(str);
2373 if (!text.isEmpty()) {
2374 bool translatable = needsTranslation(element: str);
2375 QString value = autoTrCall(str);
2376 addInitializer(item, name, column, value, directive, translatable);
2377 }
2378 }
2379}
2380
2381void WriteInitialization::addBrushInitializer(Item *item,
2382 const DomPropertyMap &properties, const QString &name, int column)
2383{
2384 if (const DomProperty *p = properties.value(key: name)) {
2385 if (p->elementBrush())
2386 addInitializer(item, name, column, value: writeBrushInitialization(brush: p->elementBrush()));
2387 else if (p->elementColor())
2388 addInitializer(item, name, column, value: domColor2QString(c: p->elementColor()));
2389 }
2390}
2391
2392/*!
2393 Create inititializer for a flag value in the Qt namespace.
2394 If the named property is not in the map, the initializer is omitted.
2395*/
2396void WriteInitialization::addQtFlagsInitializer(Item *item, const DomPropertyMap &properties,
2397 const QString &name, int column)
2398{
2399 if (const DomProperty *p = properties.value(key: name)) {
2400 const QString orOperator = u'|' + language::qtQualifier;
2401 QString v = p->elementSet();
2402 if (!v.isEmpty()) {
2403 v.replace(c: u'|', after: orOperator);
2404 addInitializer(item, name, column, value: language::qtQualifier + v);
2405 }
2406 }
2407}
2408
2409/*!
2410 Create inititializer for an enum value in the Qt namespace.
2411 If the named property is not in the map, the initializer is omitted.
2412*/
2413void WriteInitialization::addQtEnumInitializer(Item *item,
2414 const DomPropertyMap &properties, const QString &name, int column) const
2415{
2416 if (const DomProperty *p = properties.value(key: name)) {
2417 QString v = p->elementEnum();
2418 if (!v.isEmpty())
2419 addInitializer(item, name, column, value: language::qtQualifier + v);
2420 }
2421}
2422
2423/*!
2424 Create inititializers for all common properties that may be bound to a column.
2425*/
2426void WriteInitialization::addCommonInitializers(Item *item,
2427 const DomPropertyMap &properties, int column)
2428{
2429 if (const DomProperty *icon = properties.value(key: "icon"_L1))
2430 addInitializer(item, name: "icon"_L1, column, value: iconCall(icon));
2431 addBrushInitializer(item, properties, name: "foreground"_L1, column);
2432 addBrushInitializer(item, properties, name: "background"_L1, column);
2433 if (const DomProperty *font = properties.value(key: "font"_L1))
2434 addInitializer(item, name: "font"_L1, column, value: writeFontProperties(f: font->elementFont()));
2435 addQtFlagsInitializer(item, properties, name: "textAlignment"_L1, column);
2436 addQtEnumInitializer(item, properties, name: "checkState"_L1, column);
2437 addStringInitializer(item, properties, name: "text"_L1, column);
2438 addStringInitializer(item, properties, name: "toolTip"_L1, column,
2439 directive: toolTipConfigKey());
2440 addStringInitializer(item, properties, name: "whatsThis"_L1, column,
2441 directive: whatsThisConfigKey());
2442 addStringInitializer(item, properties, name: "statusTip"_L1, column,
2443 directive: statusTipConfigKey());
2444}
2445
2446void WriteInitialization::initializeListWidget(DomWidget *w)
2447{
2448 const QString varName = m_driver->findOrInsertWidget(ui_widget: w);
2449
2450 const auto &items = w->elementItem();
2451
2452 if (items.isEmpty())
2453 return;
2454
2455 QString tempName = disableSorting(w, varName);
2456 // items
2457 // TODO: the generated code should be data-driven to reduce its size
2458 for (int i = 0; i < items.size(); ++i) {
2459 const DomItem *domItem = items.at(i);
2460
2461 const DomPropertyMap properties = propertyMap(properties: domItem->elementProperty());
2462
2463 Item item("QListWidgetItem"_L1, m_indent, m_output, m_refreshOut, m_driver);
2464 addQtFlagsInitializer(item: &item, properties, name: "flags"_L1);
2465 addCommonInitializers(item: &item, properties);
2466
2467 item.writeSetupUi(parent: varName);
2468 QString parentPath;
2469 QTextStream(&parentPath) << varName << language::derefPointer << "item(" << i << ')';
2470 item.writeRetranslateUi(parentPath);
2471 }
2472 enableSorting(w, varName, tempName);
2473}
2474
2475void WriteInitialization::initializeTreeWidget(DomWidget *w)
2476{
2477 const QString varName = m_driver->findOrInsertWidget(ui_widget: w);
2478
2479 // columns
2480 Item item("QTreeWidgetItem"_L1, m_indent, m_output, m_refreshOut, m_driver);
2481
2482 const auto &columns = w->elementColumn();
2483 for (int i = 0; i < columns.size(); ++i) {
2484 const DomColumn *column = columns.at(i);
2485
2486 const DomPropertyMap properties = propertyMap(properties: column->elementProperty());
2487 addCommonInitializers(item: &item, properties, column: i);
2488
2489 if (const DomProperty *p = properties.value(key: "text"_L1)) {
2490 DomString *str = p->elementString();
2491 if (str && str->text().isEmpty()) {
2492 m_output << m_indent << varName << language::derefPointer
2493 << "headerItem()" << language::derefPointer << "setText("
2494 << i << ", " << language::emptyString << ')' << language::eol;
2495 }
2496 }
2497 }
2498 const QString itemName = item.writeSetupUi(parent: QString(), emptyItemPolicy: Item::DontConstruct);
2499 item.writeRetranslateUi(parentPath: varName + language::derefPointer + "headerItem()"_L1);
2500 if (!itemName.isNull()) {
2501 m_output << m_indent << varName << language::derefPointer
2502 << "setHeaderItem(" << itemName << ')' << language::eol;
2503 }
2504
2505 if (w->elementItem().empty())
2506 return;
2507
2508 QString tempName = disableSorting(w, varName);
2509
2510 const auto items = initializeTreeWidgetItems(domItems: w->elementItem());
2511 for (int i = 0; i < items.size(); i++) {
2512 Item *itm = items[i];
2513 itm->writeSetupUi(parent: varName);
2514 QString parentPath;
2515 QTextStream(&parentPath) << varName << language::derefPointer << "topLevelItem(" << i << ')';
2516 itm->writeRetranslateUi(parentPath);
2517 delete itm;
2518 }
2519
2520 enableSorting(w, varName, tempName);
2521}
2522
2523/*!
2524 Create and write out initializers for tree widget items.
2525 This function makes sure that only needed items are fetched (subject to preprocessor
2526 conditionals), that each item is fetched from its parent widget/item exactly once
2527 and that no temporary variables are created for items that are needed only once. As
2528 fetches are built top-down from the root, but determining how often and under which
2529 conditions an item is needed needs to be done bottom-up, the whole process makes
2530 two passes, storing the intermediate result in a recursive StringInitializerListMap.
2531*/
2532WriteInitialization::Items WriteInitialization::initializeTreeWidgetItems(const QList<DomItem *> &domItems)
2533{
2534 // items
2535 Items items;
2536 const qsizetype numDomItems = domItems.size();
2537 items.reserve(asize: numDomItems);
2538
2539 for (qsizetype i = 0; i < numDomItems; ++i) {
2540 const DomItem *domItem = domItems.at(i);
2541
2542 Item *item = new Item("QTreeWidgetItem"_L1, m_indent, m_output, m_refreshOut, m_driver);
2543 items << item;
2544
2545 QHash<QString, DomProperty *> map;
2546
2547 int col = -1;
2548 const DomPropertyList properties = domItem->elementProperty();
2549 for (DomProperty *p : properties) {
2550 if (p->attributeName() == "text"_L1) {
2551 if (!map.isEmpty()) {
2552 addCommonInitializers(item, properties: map, column: col);
2553 map.clear();
2554 }
2555 col++;
2556 }
2557 map.insert(key: p->attributeName(), value: p);
2558 }
2559 addCommonInitializers(item, properties: map, column: col);
2560 // AbstractFromBuilder saves flags last, so they always end up in the last column's map.
2561 addQtFlagsInitializer(item, properties: map, name: "flags"_L1);
2562
2563 const auto subItems = initializeTreeWidgetItems(domItems: domItem->elementItem());
2564 for (Item *subItem : subItems)
2565 item->addChild(child: subItem);
2566 }
2567 return items;
2568}
2569
2570void WriteInitialization::initializeTableWidget(DomWidget *w)
2571{
2572 const QString varName = m_driver->findOrInsertWidget(ui_widget: w);
2573
2574 // columns
2575 const auto &columns = w->elementColumn();
2576
2577 if (!columns.empty()) {
2578 m_output << m_indent << "if (" << varName << language::derefPointer
2579 << "columnCount() < " << columns.size() << ')';
2580 if (language::language() == Language::Python)
2581 m_output << ':';
2582 m_output << '\n' << m_dindent << varName << language::derefPointer << "setColumnCount("
2583 << columns.size() << ')' << language::eol;
2584 }
2585
2586 for (int i = 0; i < columns.size(); ++i) {
2587 const DomColumn *column = columns.at(i);
2588 if (!column->elementProperty().isEmpty()) {
2589 const DomPropertyMap properties = propertyMap(properties: column->elementProperty());
2590
2591 Item item("QTableWidgetItem"_L1, m_indent, m_output, m_refreshOut, m_driver);
2592 addCommonInitializers(item: &item, properties);
2593
2594 QString itemName = item.writeSetupUi(parent: QString(), emptyItemPolicy: Item::ConstructItemAndVariable);
2595 QString parentPath;
2596 QTextStream(&parentPath) << varName << language::derefPointer
2597 << "horizontalHeaderItem(" << i << ')';
2598 item.writeRetranslateUi(parentPath);
2599 m_output << m_indent << varName << language::derefPointer << "setHorizontalHeaderItem("
2600 << i << ", " << itemName << ')' << language::eol;
2601 }
2602 }
2603
2604 // rows
2605 const auto &rows = w->elementRow();
2606
2607 if (!rows.isEmpty()) {
2608 m_output << m_indent << "if (" << varName << language::derefPointer
2609 << "rowCount() < " << rows.size() << ')';
2610 if (language::language() == Language::Python)
2611 m_output << ':';
2612 m_output << '\n' << m_dindent << varName << language::derefPointer << "setRowCount("
2613 << rows.size() << ')' << language::eol;
2614 }
2615
2616 for (int i = 0; i < rows.size(); ++i) {
2617 const DomRow *row = rows.at(i);
2618 if (!row->elementProperty().isEmpty()) {
2619 const DomPropertyMap properties = propertyMap(properties: row->elementProperty());
2620
2621 Item item("QTableWidgetItem"_L1, m_indent, m_output, m_refreshOut, m_driver);
2622 addCommonInitializers(item: &item, properties);
2623
2624 QString itemName = item.writeSetupUi(parent: QString(), emptyItemPolicy: Item::ConstructItemAndVariable);
2625 QString parentPath;
2626 QTextStream(&parentPath) << varName << language::derefPointer << "verticalHeaderItem(" << i << ')';
2627 item.writeRetranslateUi(parentPath);
2628 m_output << m_indent << varName << language::derefPointer << "setVerticalHeaderItem("
2629 << i << ", " << itemName << ')' << language::eol;
2630 }
2631 }
2632
2633 // items
2634 QString tempName = disableSorting(w, varName);
2635
2636 const auto &items = w->elementItem();
2637
2638 for (const DomItem *cell : items) {
2639 if (cell->hasAttributeRow() && cell->hasAttributeColumn() && !cell->elementProperty().isEmpty()) {
2640 const int r = cell->attributeRow();
2641 const int c = cell->attributeColumn();
2642 const DomPropertyMap properties = propertyMap(properties: cell->elementProperty());
2643
2644 Item item("QTableWidgetItem"_L1, m_indent, m_output, m_refreshOut, m_driver);
2645 addQtFlagsInitializer(item: &item, properties, name: "flags"_L1);
2646 addCommonInitializers(item: &item, properties);
2647
2648 QString itemName = item.writeSetupUi(parent: QString(), emptyItemPolicy: Item::ConstructItemAndVariable);
2649 QString parentPath;
2650 QTextStream(&parentPath) << varName << language::derefPointer << "item(" << r
2651 << ", " << c << ')';
2652 item.writeRetranslateUi(parentPath);
2653 m_output << m_indent << varName << language::derefPointer << "setItem("
2654 << r << ", " << c << ", " << itemName << ')' << language::eol;
2655 }
2656 }
2657 enableSorting(w, varName, tempName);
2658}
2659
2660QString WriteInitialization::trCall(const QString &str, const QString &commentHint, const QString &id) const
2661{
2662 if (str.isEmpty())
2663 return language::emptyString;
2664
2665 QString result;
2666 QTextStream ts(&result);
2667
2668 const bool idBasedTranslations = m_driver->useIdBasedTranslations();
2669 if (m_option.translateFunction.isEmpty()) {
2670 if (idBasedTranslations || m_option.idBased) {
2671 ts << "qtTrId(";
2672 } else {
2673 ts << "QCoreApplication" << language::qualifier << "translate("
2674 << '"' << m_generatedClass << "\", ";
2675 }
2676 } else {
2677 ts << m_option.translateFunction << '(';
2678 }
2679
2680 ts << language::charliteral(idBasedTranslations ? id : str, m_dindent);
2681
2682 if (!idBasedTranslations && !m_option.idBased) {
2683 ts << ", ";
2684 if (commentHint.isEmpty())
2685 ts << language::nullPtr;
2686 else
2687 ts << language::charliteral(commentHint, m_dindent);
2688 }
2689
2690 ts << ')';
2691 return result;
2692}
2693
2694void WriteInitialization::initializeMenu(DomWidget *w, const QString &/*parentWidget*/)
2695{
2696 const QString menuName = m_driver->findOrInsertWidget(ui_widget: w);
2697 const QString menuAction = menuName + "Action"_L1;
2698
2699 const DomAction *action = m_driver->actionByName(attributeName: menuAction);
2700 if (action && action->hasAttributeMenu()) {
2701 m_output << m_indent << menuAction << " = " << menuName
2702 << language::derefPointer << "menuAction()" << language::eol;
2703 }
2704}
2705
2706QString WriteInitialization::trCall(DomString *str, const QString &defaultString) const
2707{
2708 QString value = defaultString;
2709 QString comment;
2710 QString id;
2711 if (str) {
2712 value = toString(str);
2713 comment = str->attributeComment();
2714 id = str->attributeId();
2715 }
2716 return trCall(str: value, commentHint: comment, id);
2717}
2718
2719QString WriteInitialization::noTrCall(DomString *str, const QString &defaultString) const
2720{
2721 QString value = defaultString;
2722 if (!str && defaultString.isEmpty())
2723 return {};
2724 if (str)
2725 value = str->text();
2726 QString ret;
2727 QTextStream ts(&ret);
2728 ts << language::qstring(value, m_dindent);
2729 return ret;
2730}
2731
2732QString WriteInitialization::autoTrCall(DomString *str, const QString &defaultString) const
2733{
2734 if ((!str && !defaultString.isEmpty()) || needsTranslation(element: str))
2735 return trCall(str, defaultString);
2736 return noTrCall(str, defaultString);
2737}
2738
2739QTextStream &WriteInitialization::autoTrOutput(const DomProperty *property)
2740{
2741 if (const DomString *str = property->elementString())
2742 return autoTrOutput(str);
2743 if (const DomStringList *list = property->elementStringList())
2744 if (needsTranslation(element: list))
2745 return m_refreshOut;
2746 return m_output;
2747}
2748
2749QTextStream &WriteInitialization::autoTrOutput(const DomString *str, const QString &defaultString)
2750{
2751 if ((!str && !defaultString.isEmpty()) || needsTranslation(element: str))
2752 return m_refreshOut;
2753 return m_output;
2754}
2755
2756WriteInitialization::Declaration WriteInitialization::findDeclaration(const QString &name)
2757{
2758 if (const DomWidget *widget = m_driver->widgetByName(attributeName: name))
2759 return {.name: m_driver->findOrInsertWidget(ui_widget: widget), .className: widget->attributeClass()};
2760 if (const DomAction *action = m_driver->actionByName(attributeName: name))
2761 return {.name: m_driver->findOrInsertAction(ui_action: action), QStringLiteral("QAction")};
2762 if (const DomButtonGroup *group = m_driver->findButtonGroup(attributeName: name))
2763 return {.name: m_driver->findOrInsertButtonGroup(ui_group: group), QStringLiteral("QButtonGroup")};
2764 return {};
2765}
2766
2767bool WriteInitialization::isCustomWidget(const QString &className) const
2768{
2769 return m_uic->customWidgetsInfo()->customWidget(name: className) != nullptr;
2770}
2771
2772ConnectionSyntax WriteInitialization::connectionSyntax(const language::SignalSlot &sender,
2773 const language::SignalSlot &receiver) const
2774{
2775 if (m_option.forceMemberFnPtrConnectionSyntax)
2776 return ConnectionSyntax::MemberFunctionPtr;
2777 if (m_option.forceStringConnectionSyntax)
2778 return ConnectionSyntax::StringBased;
2779 // Auto mode: Use Qt 5 connection syntax for Qt classes and parameterless
2780 // connections. QAxWidget is special though since it has a fake Meta object.
2781 static const QStringList requiresStringSyntax{QStringLiteral("QAxWidget")};
2782 if (requiresStringSyntax.contains(str: sender.className)
2783 || requiresStringSyntax.contains(str: receiver.className)) {
2784 return ConnectionSyntax::StringBased;
2785 }
2786
2787 if ((sender.name == m_mainFormVarName && m_customSignals.contains(str: sender.signature))
2788 || (receiver.name == m_mainFormVarName && m_customSlots.contains(str: receiver.signature))) {
2789 return ConnectionSyntax::StringBased;
2790 }
2791
2792 return sender.signature.endsWith(s: "()"_L1)
2793 || (!isCustomWidget(className: sender.className) && !isCustomWidget(className: receiver.className))
2794 ? ConnectionSyntax::MemberFunctionPtr : ConnectionSyntax::StringBased;
2795}
2796
2797void WriteInitialization::acceptConnection(DomConnection *connection)
2798{
2799 const QString senderName = connection->elementSender();
2800 const QString receiverName = connection->elementReceiver();
2801
2802 const auto senderDecl = findDeclaration(name: senderName);
2803 const auto receiverDecl = findDeclaration(name: receiverName);
2804
2805 if (senderDecl.name.isEmpty() || receiverDecl.name.isEmpty()) {
2806 QString message;
2807 QTextStream(&message) << m_option.messagePrefix()
2808 << ": Warning: Invalid signal/slot connection: \""
2809 << senderName << "\" -> \"" << receiverName << "\".";
2810 fprintf(stderr, format: "%s\n", qPrintable(message));
2811 return;
2812 }
2813 const QString senderSignature = connection->elementSignal();
2814 const QString slotSignature = connection->elementSlot();
2815 const bool senderAmbiguous = m_uic->customWidgetsInfo()->isAmbiguousSignal(className: senderDecl.className,
2816 signalSignature: senderSignature);
2817 const bool slotAmbiguous = m_uic->customWidgetsInfo()->isAmbiguousSlot(className: receiverDecl.className,
2818 slotSignature);
2819
2820 language::SignalSlotOptions signalOptions;
2821 signalOptions.setFlag(flag: language::SignalSlotOption::Ambiguous, on: senderAmbiguous);
2822 language::SignalSlotOptions slotOptions;
2823 slotOptions.setFlag(flag: language::SignalSlotOption::Ambiguous, on: slotAmbiguous);
2824
2825 language::SignalSlot theSignal{.name: senderDecl.name, .signature: senderSignature,
2826 .className: senderDecl.className, .options: signalOptions};
2827 language::SignalSlot theSlot{.name: receiverDecl.name, .signature: slotSignature,
2828 .className: receiverDecl.className, .options: slotOptions};
2829
2830 m_output << m_indent;
2831 language::formatConnection(str&: m_output, sender: theSignal, receiver: theSlot,
2832 connectionSyntax: connectionSyntax(sender: theSignal, receiver: theSlot));
2833 m_output << language::eol;
2834}
2835
2836static void generateMultiDirectiveBegin(QTextStream &outputStream, const QSet<QString> &directives)
2837{
2838 if (directives.isEmpty())
2839 return;
2840
2841 if (directives.size() == 1) {
2842 outputStream << language::openQtConfig(*directives.cbegin());
2843 return;
2844 }
2845
2846 auto list = directives.values();
2847 // sort (always generate in the same order):
2848 std::sort(first: list.begin(), last: list.end());
2849
2850 outputStream << "#if " << language::qtConfig(list.constFirst());
2851 for (qsizetype i = 1, size = list.size(); i < size; ++i)
2852 outputStream << " || " << language::qtConfig(list.at(i));
2853 outputStream << Qt::endl;
2854}
2855
2856static void generateMultiDirectiveEnd(QTextStream &outputStream, const QSet<QString> &directives)
2857{
2858 if (directives.isEmpty())
2859 return;
2860
2861 outputStream << "#endif" << Qt::endl;
2862}
2863
2864WriteInitialization::Item::Item(const QString &itemClassName, const QString &indent, QTextStream &setupUiStream, QTextStream &retranslateUiStream, Driver *driver)
2865 :
2866 m_itemClassName(itemClassName),
2867 m_indent(indent),
2868 m_setupUiStream(setupUiStream),
2869 m_retranslateUiStream(retranslateUiStream),
2870 m_driver(driver)
2871{
2872
2873}
2874
2875WriteInitialization::Item::~Item()
2876{
2877 qDeleteAll(c: m_children);
2878}
2879
2880QString WriteInitialization::Item::writeSetupUi(const QString &parent, Item::EmptyItemPolicy emptyItemPolicy)
2881{
2882 if (emptyItemPolicy == Item::DontConstruct && m_setupUiData.policy == ItemData::DontGenerate)
2883 return {};
2884
2885 bool generateMultiDirective = false;
2886 if (emptyItemPolicy == Item::ConstructItemOnly && m_children.isEmpty()) {
2887 if (m_setupUiData.policy == ItemData::DontGenerate) {
2888 m_setupUiStream << m_indent << language::operatorNew << m_itemClassName
2889 << '(' << parent << ')' << language::eol;
2890 return {};
2891 }
2892 if (m_setupUiData.policy == ItemData::GenerateWithMultiDirective)
2893 generateMultiDirective = true;
2894 }
2895
2896 if (generateMultiDirective)
2897 generateMultiDirectiveBegin(outputStream&: m_setupUiStream, directives: m_setupUiData.directives);
2898
2899 const QString uniqueName = m_driver->unique(instanceName: "__"_L1 + m_itemClassName.toLower());
2900 m_setupUiStream << m_indent;
2901 if (language::language() == Language::Cpp)
2902 m_setupUiStream << m_itemClassName << " *";
2903 m_setupUiStream << uniqueName
2904 << " = " << language::operatorNew << m_itemClassName << '(' << parent
2905 << ')' << language::eol;
2906
2907 if (generateMultiDirective) {
2908 m_setupUiStream << "#else\n";
2909 m_setupUiStream << m_indent << language::operatorNew << m_itemClassName
2910 << '(' << parent << ')' << language::eol;
2911 generateMultiDirectiveEnd(outputStream&: m_setupUiStream, directives: m_setupUiData.directives);
2912 }
2913
2914 QMultiMap<QString, QString>::ConstIterator it = m_setupUiData.setters.constBegin();
2915 while (it != m_setupUiData.setters.constEnd()) {
2916 if (!it.key().isEmpty())
2917 m_setupUiStream << language::openQtConfig(it.key());
2918 m_setupUiStream << m_indent << uniqueName << it.value() << Qt::endl;
2919 if (!it.key().isEmpty())
2920 m_setupUiStream << language::closeQtConfig(it.key());
2921 ++it;
2922 }
2923 for (Item *child : std::as_const(t&: m_children))
2924 child->writeSetupUi(parent: uniqueName);
2925 return uniqueName;
2926}
2927
2928void WriteInitialization::Item::writeRetranslateUi(const QString &parentPath)
2929{
2930 if (m_retranslateUiData.policy == ItemData::DontGenerate)
2931 return;
2932
2933 if (m_retranslateUiData.policy == ItemData::GenerateWithMultiDirective)
2934 generateMultiDirectiveBegin(outputStream&: m_retranslateUiStream, directives: m_retranslateUiData.directives);
2935
2936 const QString uniqueName = m_driver->unique(instanceName: "___"_L1 + m_itemClassName.toLower());
2937 m_retranslateUiStream << m_indent;
2938 if (language::language() == Language::Cpp)
2939 m_retranslateUiStream << m_itemClassName << " *";
2940 m_retranslateUiStream << uniqueName << " = " << parentPath << language::eol;
2941
2942 if (m_retranslateUiData.policy == ItemData::GenerateWithMultiDirective)
2943 generateMultiDirectiveEnd(outputStream&: m_retranslateUiStream, directives: m_retranslateUiData.directives);
2944
2945 QString oldDirective;
2946 QMultiMap<QString, QString>::ConstIterator it = m_retranslateUiData.setters.constBegin();
2947 while (it != m_retranslateUiData.setters.constEnd()) {
2948 const QString newDirective = it.key();
2949 if (oldDirective != newDirective) {
2950 if (!oldDirective.isEmpty())
2951 m_retranslateUiStream << language::closeQtConfig(oldDirective);
2952 if (!newDirective.isEmpty())
2953 m_retranslateUiStream << language::openQtConfig(newDirective);
2954 oldDirective = newDirective;
2955 }
2956 m_retranslateUiStream << m_indent << uniqueName << it.value() << Qt::endl;
2957 ++it;
2958 }
2959 if (!oldDirective.isEmpty())
2960 m_retranslateUiStream << language::closeQtConfig(oldDirective);
2961
2962 for (int i = 0; i < m_children.size(); i++) {
2963 QString method;
2964 QTextStream(&method) << uniqueName << language::derefPointer << "child(" << i << ')';
2965 m_children[i]->writeRetranslateUi(parentPath: method);
2966 }
2967}
2968
2969void WriteInitialization::Item::addSetter(const QString &setter, const QString &directive, bool translatable)
2970{
2971 const ItemData::TemporaryVariableGeneratorPolicy newPolicy = directive.isNull() ? ItemData::Generate : ItemData::GenerateWithMultiDirective;
2972 if (translatable) {
2973 m_retranslateUiData.setters.insert(key: directive, value: setter);
2974 if (ItemData::GenerateWithMultiDirective == newPolicy)
2975 m_retranslateUiData.directives << directive;
2976 if (m_retranslateUiData.policy < newPolicy)
2977 m_retranslateUiData.policy = newPolicy;
2978 } else {
2979 m_setupUiData.setters.insert(key: directive, value: setter);
2980 if (ItemData::GenerateWithMultiDirective == newPolicy)
2981 m_setupUiData.directives << directive;
2982 if (m_setupUiData.policy < newPolicy)
2983 m_setupUiData.policy = newPolicy;
2984 }
2985}
2986
2987void WriteInitialization::Item::addChild(Item *child)
2988{
2989 m_children << child;
2990 child->m_parent = this;
2991
2992 Item *c = child;
2993 Item *p = this;
2994 while (p) {
2995 p->m_setupUiData.directives |= c->m_setupUiData.directives;
2996 p->m_retranslateUiData.directives |= c->m_retranslateUiData.directives;
2997 if (p->m_setupUiData.policy < c->m_setupUiData.policy)
2998 p->m_setupUiData.policy = c->m_setupUiData.policy;
2999 if (p->m_retranslateUiData.policy < c->m_retranslateUiData.policy)
3000 p->m_retranslateUiData.policy = c->m_retranslateUiData.policy;
3001 c = p;
3002 p = p->m_parent;
3003 }
3004}
3005
3006
3007} // namespace CPP
3008
3009QT_END_NAMESPACE
3010

source code of qtbase/src/tools/uic/cpp/cppwriteinitialization.cpp