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