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