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