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 if (roleName == "Accent"_L1)
2043 return {6, 6, 0};
2044 return {};
2045}
2046
2047void WriteInitialization::writeColorGroup(DomColorGroup *colorGroup, const QString &group, const QString &paletteName)
2048{
2049 if (!colorGroup)
2050 return;
2051
2052 // old format
2053 const auto &colors = colorGroup->elementColor();
2054 for (int i=0; i<colors.size(); ++i) {
2055 const DomColor *color = colors.at(i);
2056
2057 m_output << m_indent << paletteName << ".setColor(" << group
2058 << ", QPalette" << language::qualifier << language::paletteColorRole(v: i)
2059 << ", " << domColor2QString(c: color)
2060 << ")" << language::eol;
2061 }
2062
2063 // new format
2064 const auto &colorRoles = colorGroup->elementColorRole();
2065 for (const DomColorRole *colorRole : colorRoles) {
2066 if (colorRole->hasAttributeRole()) {
2067 const QString roleName = colorRole->attributeRole();
2068 const QVersionNumber versionAdded = colorRoleVersionAdded(roleName);
2069 const QString brushName = writeBrushInitialization(brush: colorRole->elementBrush());
2070 if (!versionAdded.isNull()) {
2071 m_output << "#if QT_VERSION >= QT_VERSION_CHECK("
2072 << versionAdded.majorVersion() << ", " << versionAdded.minorVersion()
2073 << ", " << versionAdded.microVersion() << ")\n";
2074 }
2075 m_output << m_indent << paletteName << ".setBrush("
2076 << language::enumValue(value: group) << ", "
2077 << "QPalette" << language::qualifier << roleName
2078 << ", " << brushName << ")" << language::eol;
2079 if (!versionAdded.isNull())
2080 m_output << "#endif\n";
2081 }
2082 }
2083}
2084
2085// Write initialization for brush unless it is found in the cache. Returns the name to use
2086// in an expression.
2087QString WriteInitialization::writeBrushInitialization(const DomBrush *brush)
2088{
2089 // Simple solid, colored brushes are cached
2090 const bool solidColoredBrush = !brush->hasAttributeBrushStyle() || brush->attributeBrushStyle() == "SolidPattern"_L1;
2091 uint rgb = 0;
2092 if (solidColoredBrush) {
2093 if (const DomColor *color = brush->elementColor()) {
2094 rgb = ((color->elementRed() & 0xFF) << 24) |
2095 ((color->elementGreen() & 0xFF) << 16) |
2096 ((color->elementBlue() & 0xFF) << 8) |
2097 ((color->attributeAlpha() & 0xFF));
2098 const ColorBrushHash::const_iterator cit = m_colorBrushHash.constFind(key: rgb);
2099 if (cit != m_colorBrushHash.constEnd())
2100 return cit.value();
2101 }
2102 }
2103 // Create and enter into cache if simple
2104 const QString brushName = m_driver->unique(instanceName: "brush"_L1);
2105 writeBrush(brush, brushName);
2106 if (solidColoredBrush)
2107 m_colorBrushHash.insert(key: rgb, value: brushName);
2108 return brushName;
2109}
2110
2111void WriteInitialization::writeBrush(const DomBrush *brush, const QString &brushName)
2112{
2113 QString style = u"SolidPattern"_s;
2114 if (brush->hasAttributeBrushStyle())
2115 style = brush->attributeBrushStyle();
2116
2117 if (style == "LinearGradientPattern"_L1 ||
2118 style == "RadialGradientPattern"_L1 ||
2119 style == "ConicalGradientPattern"_L1) {
2120 const DomGradient *gradient = brush->elementGradient();
2121 const QString gradientType = gradient->attributeType();
2122 const QString gradientName = m_driver->unique(instanceName: "gradient"_L1);
2123 if (gradientType == "LinearGradient"_L1) {
2124 m_output << m_indent
2125 << language::stackVariableWithInitParameters("QLinearGradient", gradientName)
2126 << gradient->attributeStartX()
2127 << ", " << gradient->attributeStartY()
2128 << ", " << gradient->attributeEndX()
2129 << ", " << gradient->attributeEndY() << ')' << language::eol;
2130 } else if (gradientType == "RadialGradient"_L1) {
2131 m_output << m_indent
2132 << language::stackVariableWithInitParameters("QRadialGradient", gradientName)
2133 << gradient->attributeCentralX()
2134 << ", " << gradient->attributeCentralY()
2135 << ", " << gradient->attributeRadius()
2136 << ", " << gradient->attributeFocalX()
2137 << ", " << gradient->attributeFocalY() << ')' << language::eol;
2138 } else if (gradientType == "ConicalGradient"_L1) {
2139 m_output << m_indent
2140 << language::stackVariableWithInitParameters("QConicalGradient", gradientName)
2141 << gradient->attributeCentralX()
2142 << ", " << gradient->attributeCentralY()
2143 << ", " << gradient->attributeAngle() << ')' << language::eol;
2144 }
2145
2146 m_output << m_indent << gradientName << ".setSpread(QGradient"
2147 << language::qualifier << gradient->attributeSpread()
2148 << ')' << language::eol;
2149
2150 if (gradient->hasAttributeCoordinateMode()) {
2151 m_output << m_indent << gradientName << ".setCoordinateMode(QGradient"
2152 << language::qualifier << gradient->attributeCoordinateMode()
2153 << ')' << language::eol;
2154 }
2155
2156 const auto &stops = gradient->elementGradientStop();
2157 for (const DomGradientStop *stop : stops) {
2158 const DomColor *color = stop->elementColor();
2159 m_output << m_indent << gradientName << ".setColorAt("
2160 << stop->attributePosition() << ", "
2161 << domColor2QString(c: color) << ')' << language::eol;
2162 }
2163 m_output << m_indent
2164 << language::stackVariableWithInitParameters("QBrush", brushName)
2165 << gradientName << ')' << language::eol;
2166 } else if (style == "TexturePattern"_L1) {
2167 const DomProperty *property = brush->elementTexture();
2168 const QString iconValue = iconCall(prop: property);
2169
2170 m_output << m_indent
2171 << language::stackVariableWithInitParameters("QBrush", brushName)
2172 << iconValue << ')' << language::eol;
2173 } else {
2174 const DomColor *color = brush->elementColor();
2175 m_output << m_indent
2176 << language::stackVariableWithInitParameters("QBrush", brushName)
2177 << domColor2QString(c: color) << ')' << language::eol;
2178
2179 m_output << m_indent << brushName << ".setStyle("
2180 << language::qtQualifier << style << ')' << language::eol;
2181 }
2182}
2183
2184void WriteInitialization::acceptCustomWidget(DomCustomWidget *node)
2185{
2186 Q_UNUSED(node);
2187}
2188
2189void WriteInitialization::acceptCustomWidgets(DomCustomWidgets *node)
2190{
2191 Q_UNUSED(node);
2192}
2193
2194void WriteInitialization::acceptTabStops(DomTabStops *tabStops)
2195{
2196 QString lastName;
2197
2198 const QStringList l = tabStops->elementTabStop();
2199 for (int i=0; i<l.size(); ++i) {
2200 const QString name = m_driver->widgetVariableName(attributeName: l.at(i));
2201
2202 if (name.isEmpty()) {
2203 fprintf(stderr, format: "%s: Warning: Tab-stop assignment: '%s' is not a valid widget.\n",
2204 qPrintable(m_option.messagePrefix()), qPrintable(l.at(i)));
2205 continue;
2206 }
2207
2208 if (i == 0) {
2209 lastName = name;
2210 continue;
2211 }
2212 if (name.isEmpty() || lastName.isEmpty())
2213 continue;
2214
2215 m_output << m_indent << "QWidget" << language::qualifier << "setTabOrder("
2216 << lastName << ", " << name << ')' << language::eol;
2217
2218 lastName = name;
2219 }
2220}
2221
2222QString WriteInitialization::iconCall(const DomProperty *icon)
2223{
2224 if (icon->kind() == DomProperty::IconSet)
2225 return writeIconProperties(i: icon->elementIconSet());
2226 return pixCall(prop: icon);
2227}
2228
2229QString WriteInitialization::pixCall(const DomProperty *p) const
2230{
2231 QLatin1StringView type;
2232 QString s;
2233 switch (p->kind()) {
2234 case DomProperty::IconSet:
2235 type = "QIcon"_L1;
2236 s = p->elementIconSet()->text();
2237 break;
2238 case DomProperty::Pixmap:
2239 type = "QPixmap"_L1;
2240 s = p->elementPixmap()->text();
2241 break;
2242 default:
2243 qWarning(msg: "%s: Warning: Unknown icon format encountered. The ui-file was generated with a too-recent version of Qt Widgets Designer.",
2244 qPrintable(m_option.messagePrefix()));
2245 return "QIcon()"_L1;
2246 break;
2247 }
2248 return pixCall(type, text: s);
2249}
2250
2251QString WriteInitialization::pixCall(QLatin1StringView t, const QString &text) const
2252{
2253 if (text.isEmpty())
2254 return t % "()"_L1;
2255
2256 QString result;
2257 QTextStream str(&result);
2258 str << t;
2259 str << '(';
2260 const QString pixFunc = m_uic->pixmapFunction();
2261 if (pixFunc.isEmpty())
2262 str << language::qstring(text, m_dindent);
2263 else
2264 str << pixFunc << '(' << language::charliteral(text, m_dindent) << ')';
2265 str << ')';
2266 return result;
2267}
2268
2269void WriteInitialization::initializeComboBox(DomWidget *w)
2270{
2271 const QString varName = m_driver->findOrInsertWidget(ui_widget: w);
2272
2273 const auto &items = w->elementItem();
2274
2275 if (items.isEmpty())
2276 return;
2277
2278 for (int i = 0; i < items.size(); ++i) {
2279 const DomItem *item = items.at(i);
2280 const DomPropertyMap properties = propertyMap(properties: item->elementProperty());
2281 const DomProperty *text = properties.value(key: "text"_L1);
2282 const DomProperty *icon = properties.value(key: "icon"_L1);
2283
2284 QString iconValue;
2285 if (icon)
2286 iconValue = iconCall(icon);
2287
2288 m_output << m_indent << varName << language::derefPointer << "addItem(";
2289 if (icon)
2290 m_output << iconValue << ", ";
2291
2292 if (needsTranslation(element: text->elementString())) {
2293 m_output << language::emptyString << ')' << language::eol;
2294 m_refreshOut << m_indent << varName << language::derefPointer
2295 << "setItemText(" << i << ", " << trCall(str: text->elementString())
2296 << ')' << language::eol;
2297 } else {
2298 m_output << noTrCall(str: text->elementString()) << ")" << language::eol;
2299 }
2300 }
2301 m_refreshOut << "\n";
2302}
2303
2304QString WriteInitialization::disableSorting(DomWidget *w, const QString &varName)
2305{
2306 // turn off sortingEnabled to force programmatic item order (setItem())
2307 QString tempName;
2308 if (!w->elementItem().isEmpty()) {
2309 tempName = m_driver->unique(instanceName: "__sortingEnabled"_L1);
2310 m_refreshOut << "\n";
2311 m_refreshOut << m_indent;
2312 if (language::language() == Language::Cpp)
2313 m_refreshOut << "const bool ";
2314 m_refreshOut << tempName << " = " << varName << language::derefPointer
2315 << "isSortingEnabled()" << language::eol
2316 << m_indent << varName << language::derefPointer
2317 << "setSortingEnabled(" << language::boolValue(v: false) << ')' << language::eol;
2318 }
2319 return tempName;
2320}
2321
2322void WriteInitialization::enableSorting(DomWidget *w, const QString &varName, const QString &tempName)
2323{
2324 if (!w->elementItem().isEmpty()) {
2325 m_refreshOut << m_indent << varName << language::derefPointer
2326 << "setSortingEnabled(" << tempName << ')' << language::eol << '\n';
2327 }
2328}
2329
2330/*
2331 * Initializers are just strings containing the function call and need to be prepended
2332 * the line indentation and the object they are supposed to initialize.
2333 * String initializers come with a preprocessor conditional (ifdef), so the code
2334 * compiles with QT_NO_xxx. A null pointer means no conditional. String initializers
2335 * are written to the retranslateUi() function, others to setupUi().
2336 */
2337
2338
2339/*!
2340 Create non-string inititializer.
2341 \param value the value to initialize the attribute with. May be empty, in which case
2342 the initializer is omitted.
2343 See above for other parameters.
2344*/
2345void WriteInitialization::addInitializer(Item *item, const QString &name,
2346 int column, const QString &value,
2347 const QString &directive, bool translatable)
2348{
2349 if (!value.isEmpty()) {
2350 QString setter;
2351 QTextStream str(&setter);
2352 str << language::derefPointer << "set" << name.at(i: 0).toUpper() << QStringView{name}.mid(pos: 1) << '(';
2353 if (column >= 0)
2354 str << column << ", ";
2355 str << value << ");";
2356 item->addSetter(setter, directive, translatable);
2357 }
2358}
2359
2360/*!
2361 Create string inititializer.
2362 \param initializers in/out list of inializers
2363 \param properties map property name -> property to extract data from
2364 \param name the property to extract
2365 \param col the item column to generate the initializer for. This is relevant for
2366 tree widgets only. If it is -1, no column index will be generated.
2367 \param ifdef preprocessor symbol for disabling compilation of this initializer
2368*/
2369void WriteInitialization::addStringInitializer(Item *item,
2370 const DomPropertyMap &properties, const QString &name, int column, const QString &directive) const
2371{
2372 if (const DomProperty *p = properties.value(key: name)) {
2373 DomString *str = p->elementString();
2374 QString text = toString(str);
2375 if (!text.isEmpty()) {
2376 bool translatable = needsTranslation(element: str);
2377 QString value = autoTrCall(str);
2378 addInitializer(item, name, column, value, directive, translatable);
2379 }
2380 }
2381}
2382
2383void WriteInitialization::addBrushInitializer(Item *item,
2384 const DomPropertyMap &properties, const QString &name, int column)
2385{
2386 if (const DomProperty *p = properties.value(key: name)) {
2387 if (p->elementBrush())
2388 addInitializer(item, name, column, value: writeBrushInitialization(brush: p->elementBrush()));
2389 else if (p->elementColor())
2390 addInitializer(item, name, column, value: domColor2QString(c: p->elementColor()));
2391 }
2392}
2393
2394/*!
2395 Create inititializer for a flag value in the Qt namespace.
2396 If the named property is not in the map, the initializer is omitted.
2397*/
2398void WriteInitialization::addQtFlagsInitializer(Item *item, const DomPropertyMap &properties,
2399 const QString &name, int column)
2400{
2401 if (const DomProperty *p = properties.value(key: name)) {
2402 const QString orOperator = u'|' + language::qtQualifier;
2403 QString v = p->elementSet();
2404 if (!v.isEmpty()) {
2405 v.replace(c: u'|', after: orOperator);
2406 addInitializer(item, name, column, value: language::qtQualifier + v);
2407 }
2408 }
2409}
2410
2411/*!
2412 Create inititializer for an enum value in the Qt namespace.
2413 If the named property is not in the map, the initializer is omitted.
2414*/
2415void WriteInitialization::addQtEnumInitializer(Item *item,
2416 const DomPropertyMap &properties, const QString &name, int column) const
2417{
2418 if (const DomProperty *p = properties.value(key: name)) {
2419 QString v = p->elementEnum();
2420 if (!v.isEmpty())
2421 addInitializer(item, name, column, value: language::qtQualifier + v);
2422 }
2423}
2424
2425/*!
2426 Create inititializers for all common properties that may be bound to a column.
2427*/
2428void WriteInitialization::addCommonInitializers(Item *item,
2429 const DomPropertyMap &properties, int column)
2430{
2431 if (const DomProperty *icon = properties.value(key: "icon"_L1))
2432 addInitializer(item, name: "icon"_L1, column, value: iconCall(icon));
2433 addBrushInitializer(item, properties, name: "foreground"_L1, column);
2434 addBrushInitializer(item, properties, name: "background"_L1, column);
2435 if (const DomProperty *font = properties.value(key: "font"_L1))
2436 addInitializer(item, name: "font"_L1, column, value: writeFontProperties(f: font->elementFont()));
2437 addQtFlagsInitializer(item, properties, name: "textAlignment"_L1, column);
2438 addQtEnumInitializer(item, properties, name: "checkState"_L1, column);
2439 addStringInitializer(item, properties, name: "text"_L1, column);
2440 addStringInitializer(item, properties, name: "toolTip"_L1, column,
2441 directive: toolTipConfigKey());
2442 addStringInitializer(item, properties, name: "whatsThis"_L1, column,
2443 directive: whatsThisConfigKey());
2444 addStringInitializer(item, properties, name: "statusTip"_L1, column,
2445 directive: statusTipConfigKey());
2446}
2447
2448void WriteInitialization::initializeListWidget(DomWidget *w)
2449{
2450 const QString varName = m_driver->findOrInsertWidget(ui_widget: w);
2451
2452 const auto &items = w->elementItem();
2453
2454 if (items.isEmpty())
2455 return;
2456
2457 QString tempName = disableSorting(w, varName);
2458 // items
2459 // TODO: the generated code should be data-driven to reduce its size
2460 for (int i = 0; i < items.size(); ++i) {
2461 const DomItem *domItem = items.at(i);
2462
2463 const DomPropertyMap properties = propertyMap(properties: domItem->elementProperty());
2464
2465 Item item("QListWidgetItem"_L1, m_indent, m_output, m_refreshOut, m_driver);
2466 addQtFlagsInitializer(item: &item, properties, name: "flags"_L1);
2467 addCommonInitializers(item: &item, properties);
2468
2469 item.writeSetupUi(parent: varName);
2470 QString parentPath;
2471 QTextStream(&parentPath) << varName << language::derefPointer << "item(" << i << ')';
2472 item.writeRetranslateUi(parentPath);
2473 }
2474 enableSorting(w, varName, tempName);
2475}
2476
2477void WriteInitialization::initializeTreeWidget(DomWidget *w)
2478{
2479 const QString varName = m_driver->findOrInsertWidget(ui_widget: w);
2480
2481 // columns
2482 Item item("QTreeWidgetItem"_L1, m_indent, m_output, m_refreshOut, m_driver);
2483
2484 const auto &columns = w->elementColumn();
2485 for (int i = 0; i < columns.size(); ++i) {
2486 const DomColumn *column = columns.at(i);
2487
2488 const DomPropertyMap properties = propertyMap(properties: column->elementProperty());
2489 addCommonInitializers(item: &item, properties, column: i);
2490
2491 if (const DomProperty *p = properties.value(key: "text"_L1)) {
2492 DomString *str = p->elementString();
2493 if (str && str->text().isEmpty()) {
2494 m_output << m_indent << varName << language::derefPointer
2495 << "headerItem()" << language::derefPointer << "setText("
2496 << i << ", " << language::emptyString << ')' << language::eol;
2497 }
2498 }
2499 }
2500 const QString itemName = item.writeSetupUi(parent: QString(), emptyItemPolicy: Item::DontConstruct);
2501 item.writeRetranslateUi(parentPath: varName + language::derefPointer + "headerItem()"_L1);
2502 if (!itemName.isNull()) {
2503 m_output << m_indent << varName << language::derefPointer
2504 << "setHeaderItem(" << itemName << ')' << language::eol;
2505 }
2506
2507 if (w->elementItem().empty())
2508 return;
2509
2510 QString tempName = disableSorting(w, varName);
2511
2512 const auto items = initializeTreeWidgetItems(domItems: w->elementItem());
2513 for (int i = 0; i < items.size(); i++) {
2514 Item *itm = items[i];
2515 itm->writeSetupUi(parent: varName);
2516 QString parentPath;
2517 QTextStream(&parentPath) << varName << language::derefPointer << "topLevelItem(" << i << ')';
2518 itm->writeRetranslateUi(parentPath);
2519 delete itm;
2520 }
2521
2522 enableSorting(w, varName, tempName);
2523}
2524
2525/*!
2526 Create and write out initializers for tree widget items.
2527 This function makes sure that only needed items are fetched (subject to preprocessor
2528 conditionals), that each item is fetched from its parent widget/item exactly once
2529 and that no temporary variables are created for items that are needed only once. As
2530 fetches are built top-down from the root, but determining how often and under which
2531 conditions an item is needed needs to be done bottom-up, the whole process makes
2532 two passes, storing the intermediate result in a recursive StringInitializerListMap.
2533*/
2534WriteInitialization::Items WriteInitialization::initializeTreeWidgetItems(const QList<DomItem *> &domItems)
2535{
2536 // items
2537 Items items;
2538 const qsizetype numDomItems = domItems.size();
2539 items.reserve(asize: numDomItems);
2540
2541 for (qsizetype i = 0; i < numDomItems; ++i) {
2542 const DomItem *domItem = domItems.at(i);
2543
2544 Item *item = new Item("QTreeWidgetItem"_L1, m_indent, m_output, m_refreshOut, m_driver);
2545 items << item;
2546
2547 QHash<QString, DomProperty *> map;
2548
2549 int col = -1;
2550 const DomPropertyList properties = domItem->elementProperty();
2551 for (DomProperty *p : properties) {
2552 if (p->attributeName() == "text"_L1) {
2553 if (!map.isEmpty()) {
2554 addCommonInitializers(item, properties: map, column: col);
2555 map.clear();
2556 }
2557 col++;
2558 }
2559 map.insert(key: p->attributeName(), value: p);
2560 }
2561 addCommonInitializers(item, properties: map, column: col);
2562 // AbstractFromBuilder saves flags last, so they always end up in the last column's map.
2563 addQtFlagsInitializer(item, properties: map, name: "flags"_L1);
2564
2565 const auto subItems = initializeTreeWidgetItems(domItems: domItem->elementItem());
2566 for (Item *subItem : subItems)
2567 item->addChild(child: subItem);
2568 }
2569 return items;
2570}
2571
2572void WriteInitialization::initializeTableWidget(DomWidget *w)
2573{
2574 const QString varName = m_driver->findOrInsertWidget(ui_widget: w);
2575
2576 // columns
2577 const auto &columns = w->elementColumn();
2578
2579 if (!columns.empty()) {
2580 m_output << m_indent << "if (" << varName << language::derefPointer
2581 << "columnCount() < " << columns.size() << ')';
2582 if (language::language() == Language::Python)
2583 m_output << ':';
2584 m_output << '\n' << m_dindent << varName << language::derefPointer << "setColumnCount("
2585 << columns.size() << ')' << language::eol;
2586 }
2587
2588 for (int i = 0; i < columns.size(); ++i) {
2589 const DomColumn *column = columns.at(i);
2590 if (!column->elementProperty().isEmpty()) {
2591 const DomPropertyMap properties = propertyMap(properties: column->elementProperty());
2592
2593 Item item("QTableWidgetItem"_L1, m_indent, m_output, m_refreshOut, m_driver);
2594 addCommonInitializers(item: &item, properties);
2595
2596 QString itemName = item.writeSetupUi(parent: QString(), emptyItemPolicy: Item::ConstructItemAndVariable);
2597 QString parentPath;
2598 QTextStream(&parentPath) << varName << language::derefPointer
2599 << "horizontalHeaderItem(" << i << ')';
2600 item.writeRetranslateUi(parentPath);
2601 m_output << m_indent << varName << language::derefPointer << "setHorizontalHeaderItem("
2602 << i << ", " << itemName << ')' << language::eol;
2603 }
2604 }
2605
2606 // rows
2607 const auto &rows = w->elementRow();
2608
2609 if (!rows.isEmpty()) {
2610 m_output << m_indent << "if (" << varName << language::derefPointer
2611 << "rowCount() < " << rows.size() << ')';
2612 if (language::language() == Language::Python)
2613 m_output << ':';
2614 m_output << '\n' << m_dindent << varName << language::derefPointer << "setRowCount("
2615 << rows.size() << ')' << language::eol;
2616 }
2617
2618 for (int i = 0; i < rows.size(); ++i) {
2619 const DomRow *row = rows.at(i);
2620 if (!row->elementProperty().isEmpty()) {
2621 const DomPropertyMap properties = propertyMap(properties: row->elementProperty());
2622
2623 Item item("QTableWidgetItem"_L1, m_indent, m_output, m_refreshOut, m_driver);
2624 addCommonInitializers(item: &item, properties);
2625
2626 QString itemName = item.writeSetupUi(parent: QString(), emptyItemPolicy: Item::ConstructItemAndVariable);
2627 QString parentPath;
2628 QTextStream(&parentPath) << varName << language::derefPointer << "verticalHeaderItem(" << i << ')';
2629 item.writeRetranslateUi(parentPath);
2630 m_output << m_indent << varName << language::derefPointer << "setVerticalHeaderItem("
2631 << i << ", " << itemName << ')' << language::eol;
2632 }
2633 }
2634
2635 // items
2636 QString tempName = disableSorting(w, varName);
2637
2638 const auto &items = w->elementItem();
2639
2640 for (const DomItem *cell : items) {
2641 if (cell->hasAttributeRow() && cell->hasAttributeColumn() && !cell->elementProperty().isEmpty()) {
2642 const int r = cell->attributeRow();
2643 const int c = cell->attributeColumn();
2644 const DomPropertyMap properties = propertyMap(properties: cell->elementProperty());
2645
2646 Item item("QTableWidgetItem"_L1, m_indent, m_output, m_refreshOut, m_driver);
2647 addQtFlagsInitializer(item: &item, properties, name: "flags"_L1);
2648 addCommonInitializers(item: &item, properties);
2649
2650 QString itemName = item.writeSetupUi(parent: QString(), emptyItemPolicy: Item::ConstructItemAndVariable);
2651 QString parentPath;
2652 QTextStream(&parentPath) << varName << language::derefPointer << "item(" << r
2653 << ", " << c << ')';
2654 item.writeRetranslateUi(parentPath);
2655 m_output << m_indent << varName << language::derefPointer << "setItem("
2656 << r << ", " << c << ", " << itemName << ')' << language::eol;
2657 }
2658 }
2659 enableSorting(w, varName, tempName);
2660}
2661
2662QString WriteInitialization::trCall(const QString &str, const QString &commentHint, const QString &id) const
2663{
2664 if (str.isEmpty())
2665 return language::emptyString;
2666
2667 QString result;
2668 QTextStream ts(&result);
2669
2670 const bool idBasedTranslations = m_driver->useIdBasedTranslations();
2671 if (m_option.translateFunction.isEmpty()) {
2672 if (idBasedTranslations || m_option.idBased) {
2673 ts << "qtTrId(";
2674 } else {
2675 ts << "QCoreApplication" << language::qualifier << "translate("
2676 << '"' << m_generatedClass << "\", ";
2677 }
2678 } else {
2679 ts << m_option.translateFunction << '(';
2680 }
2681
2682 ts << language::charliteral(idBasedTranslations ? id : str, m_dindent);
2683
2684 if (!idBasedTranslations && !m_option.idBased) {
2685 ts << ", ";
2686 if (commentHint.isEmpty())
2687 ts << language::nullPtr;
2688 else
2689 ts << language::charliteral(commentHint, m_dindent);
2690 }
2691
2692 ts << ')';
2693 return result;
2694}
2695
2696void WriteInitialization::initializeMenu(DomWidget *w, const QString &/*parentWidget*/)
2697{
2698 const QString menuName = m_driver->findOrInsertWidget(ui_widget: w);
2699 const QString menuAction = menuName + "Action"_L1;
2700
2701 const DomAction *action = m_driver->actionByName(attributeName: menuAction);
2702 if (action && action->hasAttributeMenu()) {
2703 m_output << m_indent << menuAction << " = " << menuName
2704 << language::derefPointer << "menuAction()" << language::eol;
2705 }
2706}
2707
2708QString WriteInitialization::trCall(DomString *str, const QString &defaultString) const
2709{
2710 QString value = defaultString;
2711 QString comment;
2712 QString id;
2713 if (str) {
2714 value = toString(str);
2715 comment = str->attributeComment();
2716 id = str->attributeId();
2717 }
2718 return trCall(str: value, commentHint: comment, id);
2719}
2720
2721QString WriteInitialization::noTrCall(DomString *str, const QString &defaultString) const
2722{
2723 QString value = defaultString;
2724 if (!str && defaultString.isEmpty())
2725 return {};
2726 if (str)
2727 value = str->text();
2728 QString ret;
2729 QTextStream ts(&ret);
2730 ts << language::qstring(value, m_dindent);
2731 return ret;
2732}
2733
2734QString WriteInitialization::autoTrCall(DomString *str, const QString &defaultString) const
2735{
2736 if ((!str && !defaultString.isEmpty()) || needsTranslation(element: str))
2737 return trCall(str, defaultString);
2738 return noTrCall(str, defaultString);
2739}
2740
2741QTextStream &WriteInitialization::autoTrOutput(const DomProperty *property)
2742{
2743 if (const DomString *str = property->elementString())
2744 return autoTrOutput(str);
2745 if (const DomStringList *list = property->elementStringList())
2746 if (needsTranslation(element: list))
2747 return m_refreshOut;
2748 return m_output;
2749}
2750
2751QTextStream &WriteInitialization::autoTrOutput(const DomString *str, const QString &defaultString)
2752{
2753 if ((!str && !defaultString.isEmpty()) || needsTranslation(element: str))
2754 return m_refreshOut;
2755 return m_output;
2756}
2757
2758WriteInitialization::Declaration WriteInitialization::findDeclaration(const QString &name)
2759{
2760 if (const DomWidget *widget = m_driver->widgetByName(attributeName: name))
2761 return {.name: m_driver->findOrInsertWidget(ui_widget: widget), .className: widget->attributeClass()};
2762 if (const DomAction *action = m_driver->actionByName(attributeName: name))
2763 return {.name: m_driver->findOrInsertAction(ui_action: action), QStringLiteral("QAction")};
2764 if (const DomButtonGroup *group = m_driver->findButtonGroup(attributeName: name))
2765 return {.name: m_driver->findOrInsertButtonGroup(ui_group: group), QStringLiteral("QButtonGroup")};
2766 return {};
2767}
2768
2769bool WriteInitialization::isCustomWidget(const QString &className) const
2770{
2771 return m_uic->customWidgetsInfo()->customWidget(name: className) != nullptr;
2772}
2773
2774ConnectionSyntax WriteInitialization::connectionSyntax(const language::SignalSlot &sender,
2775 const language::SignalSlot &receiver) const
2776{
2777 if (m_option.forceMemberFnPtrConnectionSyntax)
2778 return ConnectionSyntax::MemberFunctionPtr;
2779 if (m_option.forceStringConnectionSyntax)
2780 return ConnectionSyntax::StringBased;
2781 // Auto mode: Use Qt 5 connection syntax for Qt classes and parameterless
2782 // connections. QAxWidget is special though since it has a fake Meta object.
2783 static const QStringList requiresStringSyntax{QStringLiteral("QAxWidget")};
2784 if (requiresStringSyntax.contains(str: sender.className)
2785 || requiresStringSyntax.contains(str: receiver.className)) {
2786 return ConnectionSyntax::StringBased;
2787 }
2788
2789 if ((sender.name == m_mainFormVarName && m_customSignals.contains(str: sender.signature))
2790 || (receiver.name == m_mainFormVarName && m_customSlots.contains(str: receiver.signature))) {
2791 return ConnectionSyntax::StringBased;
2792 }
2793
2794 return sender.signature.endsWith(s: "()"_L1)
2795 || (!isCustomWidget(className: sender.className) && !isCustomWidget(className: receiver.className))
2796 ? ConnectionSyntax::MemberFunctionPtr : ConnectionSyntax::StringBased;
2797}
2798
2799void WriteInitialization::acceptConnection(DomConnection *connection)
2800{
2801 const QString senderName = connection->elementSender();
2802 const QString receiverName = connection->elementReceiver();
2803
2804 const auto senderDecl = findDeclaration(name: senderName);
2805 const auto receiverDecl = findDeclaration(name: receiverName);
2806
2807 if (senderDecl.name.isEmpty() || receiverDecl.name.isEmpty()) {
2808 QString message;
2809 QTextStream(&message) << m_option.messagePrefix()
2810 << ": Warning: Invalid signal/slot connection: \""
2811 << senderName << "\" -> \"" << receiverName << "\".";
2812 fprintf(stderr, format: "%s\n", qPrintable(message));
2813 return;
2814 }
2815 const QString senderSignature = connection->elementSignal();
2816 const QString slotSignature = connection->elementSlot();
2817 const bool senderAmbiguous = m_uic->customWidgetsInfo()->isAmbiguousSignal(className: senderDecl.className,
2818 signalSignature: senderSignature);
2819 const bool slotAmbiguous = m_uic->customWidgetsInfo()->isAmbiguousSlot(className: receiverDecl.className,
2820 slotSignature);
2821
2822 language::SignalSlotOptions signalOptions;
2823 signalOptions.setFlag(flag: language::SignalSlotOption::Ambiguous, on: senderAmbiguous);
2824 language::SignalSlotOptions slotOptions;
2825 slotOptions.setFlag(flag: language::SignalSlotOption::Ambiguous, on: slotAmbiguous);
2826
2827 language::SignalSlot theSignal{.name: senderDecl.name, .signature: senderSignature,
2828 .className: senderDecl.className, .options: signalOptions};
2829 language::SignalSlot theSlot{.name: receiverDecl.name, .signature: slotSignature,
2830 .className: receiverDecl.className, .options: slotOptions};
2831
2832 m_output << m_indent;
2833 language::formatConnection(str&: m_output, sender: theSignal, receiver: theSlot,
2834 connectionSyntax: connectionSyntax(sender: theSignal, receiver: theSlot));
2835 m_output << language::eol;
2836}
2837
2838static void generateMultiDirectiveBegin(QTextStream &outputStream, const QSet<QString> &directives)
2839{
2840 if (directives.isEmpty())
2841 return;
2842
2843 if (directives.size() == 1) {
2844 outputStream << language::openQtConfig(*directives.cbegin());
2845 return;
2846 }
2847
2848 auto list = directives.values();
2849 // sort (always generate in the same order):
2850 std::sort(first: list.begin(), last: list.end());
2851
2852 outputStream << "#if " << language::qtConfig(list.constFirst());
2853 for (qsizetype i = 1, size = list.size(); i < size; ++i)
2854 outputStream << " || " << language::qtConfig(list.at(i));
2855 outputStream << Qt::endl;
2856}
2857
2858static void generateMultiDirectiveEnd(QTextStream &outputStream, const QSet<QString> &directives)
2859{
2860 if (directives.isEmpty())
2861 return;
2862
2863 outputStream << "#endif" << Qt::endl;
2864}
2865
2866WriteInitialization::Item::Item(const QString &itemClassName, const QString &indent, QTextStream &setupUiStream, QTextStream &retranslateUiStream, Driver *driver)
2867 :
2868 m_itemClassName(itemClassName),
2869 m_indent(indent),
2870 m_setupUiStream(setupUiStream),
2871 m_retranslateUiStream(retranslateUiStream),
2872 m_driver(driver)
2873{
2874
2875}
2876
2877WriteInitialization::Item::~Item()
2878{
2879 qDeleteAll(c: m_children);
2880}
2881
2882QString WriteInitialization::Item::writeSetupUi(const QString &parent, Item::EmptyItemPolicy emptyItemPolicy)
2883{
2884 if (emptyItemPolicy == Item::DontConstruct && m_setupUiData.policy == ItemData::DontGenerate)
2885 return {};
2886
2887 bool generateMultiDirective = false;
2888 if (emptyItemPolicy == Item::ConstructItemOnly && m_children.isEmpty()) {
2889 if (m_setupUiData.policy == ItemData::DontGenerate) {
2890 m_setupUiStream << m_indent << language::operatorNew << m_itemClassName
2891 << '(' << parent << ')' << language::eol;
2892 return {};
2893 }
2894 if (m_setupUiData.policy == ItemData::GenerateWithMultiDirective)
2895 generateMultiDirective = true;
2896 }
2897
2898 if (generateMultiDirective)
2899 generateMultiDirectiveBegin(outputStream&: m_setupUiStream, directives: m_setupUiData.directives);
2900
2901 const QString uniqueName = m_driver->unique(instanceName: "__"_L1 + m_itemClassName.toLower());
2902 m_setupUiStream << m_indent;
2903 if (language::language() == Language::Cpp)
2904 m_setupUiStream << m_itemClassName << " *";
2905 m_setupUiStream << uniqueName
2906 << " = " << language::operatorNew << m_itemClassName << '(' << parent
2907 << ')' << language::eol;
2908
2909 if (generateMultiDirective) {
2910 m_setupUiStream << "#else\n";
2911 m_setupUiStream << m_indent << language::operatorNew << m_itemClassName
2912 << '(' << parent << ')' << language::eol;
2913 generateMultiDirectiveEnd(outputStream&: m_setupUiStream, directives: m_setupUiData.directives);
2914 }
2915
2916 QMultiMap<QString, QString>::ConstIterator it = m_setupUiData.setters.constBegin();
2917 while (it != m_setupUiData.setters.constEnd()) {
2918 if (!it.key().isEmpty())
2919 m_setupUiStream << language::openQtConfig(it.key());
2920 m_setupUiStream << m_indent << uniqueName << it.value() << Qt::endl;
2921 if (!it.key().isEmpty())
2922 m_setupUiStream << language::closeQtConfig(it.key());
2923 ++it;
2924 }
2925 for (Item *child : std::as_const(t&: m_children))
2926 child->writeSetupUi(parent: uniqueName);
2927 return uniqueName;
2928}
2929
2930void WriteInitialization::Item::writeRetranslateUi(const QString &parentPath)
2931{
2932 if (m_retranslateUiData.policy == ItemData::DontGenerate)
2933 return;
2934
2935 if (m_retranslateUiData.policy == ItemData::GenerateWithMultiDirective)
2936 generateMultiDirectiveBegin(outputStream&: m_retranslateUiStream, directives: m_retranslateUiData.directives);
2937
2938 const QString uniqueName = m_driver->unique(instanceName: "___"_L1 + m_itemClassName.toLower());
2939 m_retranslateUiStream << m_indent;
2940 if (language::language() == Language::Cpp)
2941 m_retranslateUiStream << m_itemClassName << " *";
2942 m_retranslateUiStream << uniqueName << " = " << parentPath << language::eol;
2943
2944 if (m_retranslateUiData.policy == ItemData::GenerateWithMultiDirective)
2945 generateMultiDirectiveEnd(outputStream&: m_retranslateUiStream, directives: m_retranslateUiData.directives);
2946
2947 QString oldDirective;
2948 QMultiMap<QString, QString>::ConstIterator it = m_retranslateUiData.setters.constBegin();
2949 while (it != m_retranslateUiData.setters.constEnd()) {
2950 const QString newDirective = it.key();
2951 if (oldDirective != newDirective) {
2952 if (!oldDirective.isEmpty())
2953 m_retranslateUiStream << language::closeQtConfig(oldDirective);
2954 if (!newDirective.isEmpty())
2955 m_retranslateUiStream << language::openQtConfig(newDirective);
2956 oldDirective = newDirective;
2957 }
2958 m_retranslateUiStream << m_indent << uniqueName << it.value() << Qt::endl;
2959 ++it;
2960 }
2961 if (!oldDirective.isEmpty())
2962 m_retranslateUiStream << language::closeQtConfig(oldDirective);
2963
2964 for (int i = 0; i < m_children.size(); i++) {
2965 QString method;
2966 QTextStream(&method) << uniqueName << language::derefPointer << "child(" << i << ')';
2967 m_children[i]->writeRetranslateUi(parentPath: method);
2968 }
2969}
2970
2971void WriteInitialization::Item::addSetter(const QString &setter, const QString &directive, bool translatable)
2972{
2973 const ItemData::TemporaryVariableGeneratorPolicy newPolicy = directive.isNull() ? ItemData::Generate : ItemData::GenerateWithMultiDirective;
2974 if (translatable) {
2975 m_retranslateUiData.setters.insert(key: directive, value: setter);
2976 if (ItemData::GenerateWithMultiDirective == newPolicy)
2977 m_retranslateUiData.directives << directive;
2978 if (m_retranslateUiData.policy < newPolicy)
2979 m_retranslateUiData.policy = newPolicy;
2980 } else {
2981 m_setupUiData.setters.insert(key: directive, value: setter);
2982 if (ItemData::GenerateWithMultiDirective == newPolicy)
2983 m_setupUiData.directives << directive;
2984 if (m_setupUiData.policy < newPolicy)
2985 m_setupUiData.policy = newPolicy;
2986 }
2987}
2988
2989void WriteInitialization::Item::addChild(Item *child)
2990{
2991 m_children << child;
2992 child->m_parent = this;
2993
2994 Item *c = child;
2995 Item *p = this;
2996 while (p) {
2997 p->m_setupUiData.directives |= c->m_setupUiData.directives;
2998 p->m_retranslateUiData.directives |= c->m_retranslateUiData.directives;
2999 if (p->m_setupUiData.policy < c->m_setupUiData.policy)
3000 p->m_setupUiData.policy = c->m_setupUiData.policy;
3001 if (p->m_retranslateUiData.policy < c->m_retranslateUiData.policy)
3002 p->m_retranslateUiData.policy = c->m_retranslateUiData.policy;
3003 c = p;
3004 p = p->m_parent;
3005 }
3006}
3007
3008
3009} // namespace CPP
3010
3011QT_END_NAMESPACE
3012

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

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