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

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