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