text: /****************************************************************************
  **
  ** Copyright (C) 2016 The Qt Company Ltd.
  ** Contact: https://www.qt.io/licensing/
  **
  ** This file is part of the tools applications of the Qt Toolkit.
  **
  ** $QT_BEGIN_LICENSE:GPL-EXCEPT$
  ** Commercial License Usage
  ** Licensees holding valid commercial Qt licenses may use this file in
  ** accordance with the commercial license agreement provided with the
  ** Software or, alternatively, in accordance with the terms contained in
  ** a written agreement between you and The Qt Company. For licensing terms
  ** and conditions see https://www.qt.io/terms-conditions. For further
  ** information use the contact form at https://www.qt.io/contact-us.
  **
  ** GNU General Public License Usage
  ** Alternatively, this file may be used under the terms of the GNU
  ** General Public License version 3 as published by the Free Software
  ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
  ** included in the packaging of this file. Please review the following
  ** information to ensure the GNU General Public License requirements will
  ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
  **
  ** $QT_END_LICENSE$
  **
  ****************************************************************************/
  
  #include "cppwriteinitialization.h"
  #include "cppwriteiconinitialization.h"
  #include "driver.h"
  #include "ui4.h"
  #include "utils.h"
  #include "uic.h"
  #include "databaseinfo.h"
  #include "globaldefs.h"
  
  #include <qtextstream.h>
  #include <qdebug.h>
  
  #include <algorithm>
  
  #include <ctype.h>
  
  QT_BEGIN_NAMESPACE
  
  namespace {
      // Fixup an enumeration name from class Qt.
      // They are currently stored as "BottomToolBarArea" instead of "Qt::BottomToolBarArea".
      // due to MO issues. This might be fixed in the future.
      QLatin1String qtEnumerationPrefix(const QString &name) {
          static const QLatin1String prefix("Qt::");
          if (name.indexOf(prefix) != 0)
              return prefix;
          return QLatin1String();
      }
      // figure out the toolbar area of a DOM attrib list.
      // By legacy, it is stored as an integer. As of 4.3.0, it is the enumeration value.
      QString toolBarAreaStringFromDOMAttributes(const CPP::WriteInitialization::DomPropertyMap &attributes) {
          const DomProperty *pstyle = attributes.value(QLatin1String("toolBarArea"));
          if (!pstyle)
              return QString();
  
          switch (pstyle->kind()) {
          case DomProperty::Number: {
              return QLatin1String("static_cast<Qt::ToolBarArea>(")
                     + QString::number(pstyle->elementNumber()) + QLatin1String("), ");
          }
          case DomProperty::Enum: {
              const QString area = pstyle->elementEnum();
              return qtEnumerationPrefix(area) + area + QLatin1String(", ");
          }
          default:
              break;
          }
          return QString();
      }
  
      // Write a statement to create a spacer item.
      void writeSpacerItem(const DomSpacer *node, QTextStream &output) {
          const QHash<QString, DomProperty *> properties = propertyMap(node->elementProperty());
                  output << "new QSpacerItem(";
  
          int w = 0;
          int h = 0;
          if (properties.contains(QLatin1String("sizeHint"))) {
              if (const DomSize *sizeHint = properties.value(QLatin1String("sizeHint"))->elementSize()) {
                  w = sizeHint->elementWidth();
                  h = sizeHint->elementHeight();
              }
          }
          output << w << ", " << h << ", ";
  
          // size type
          QString sizeType = properties.contains(QLatin1String("sizeType"))  ?
                             properties.value(QLatin1String("sizeType"))->elementEnum() :
                             QString::fromLatin1("Expanding");
  
          if (!sizeType.startsWith(QLatin1String("QSizePolicy::")))
              sizeType.prepend(QLatin1String("QSizePolicy::"));
          // orientation
          bool isVspacer = false;
          if (properties.contains(QLatin1String("orientation"))) {
              const QString orientation = properties.value(QLatin1String("orientation"))->elementEnum();
              if (orientation == QLatin1String("Qt::Vertical") || orientation == QLatin1String("Vertical"))  isVspacer = true;
          }
  
          if (isVspacer)
              output << "QSizePolicy::Minimum, " << sizeType << ')';
          else
              output << sizeType << ", QSizePolicy::Minimum)";
      }
  
  
      // Helper for implementing comparison functions for integers.
      int compareInt(int i1, int i2) {
          if (i1 < i2) return -1;
          if (i1 > i2) return  1;
          return  0;
      }
  
      // Write object->setFoo(x);
      template <class Value>
          void writeSetter(const QString &indent, const QString &varName,const QString &setter, Value v, QTextStream &str) {
              str << indent << varName << "->" << setter << '(' << v << ");\n";
          }
  
      void writeSetupUIScriptVariableDeclarations(const QString &indent, QTextStream &str)  {
          str << indent << "ScriptContext scriptContext;\n"
              << indent << "QWidgetList childWidgets;\n";
      }
  
      static inline bool iconHasStatePixmaps(const DomResourceIcon *i) {
          return i->hasElementNormalOff()   || i->hasElementNormalOn() ||
                 i->hasElementDisabledOff() || i->hasElementDisabledOn() ||
                 i->hasElementActiveOff()   || i->hasElementActiveOn() ||
                 i->hasElementSelectedOff() || i->hasElementSelectedOn();
      }
  
      static inline bool isIconFormat44(const DomResourceIcon *i) {
          return iconHasStatePixmaps(i) || !i->attributeTheme().isEmpty();
      }
  
      // Check on properties. Filter out empty legacy pixmap/icon properties
      // as Designer pre 4.4 used to remove missing resource references.
      // This can no longer be handled by the code as we have 'setIcon(QIcon())' as well as 'QIcon icon'
      static bool checkProperty(const QString &fileName, const DomProperty *p) {
          switch (p->kind()) {
          case DomProperty::IconSet:
              if (const DomResourceIcon *dri = p->elementIconSet()) {
                  if (!isIconFormat44(dri)) {
                      if (dri->text().isEmpty())  {
                          const QString msg = QString::fromLatin1("%1: Warning: An invalid icon property '%2' was encountered.")
                                              .arg(fileName, p->attributeName());
                          qWarning("%s", qPrintable(msg));
                          return false;
                      }
                  }
              }
              break;
          case DomProperty::Pixmap:
              if (const DomResourcePixmap *drp = p->elementPixmap())
                  if (drp->text().isEmpty()) {
                      const QString msg = QString::fromUtf8("%1: Warning: An invalid pixmap property '%2' was encountered.")
                                          .arg(fileName, p->attributeName());
                      qWarning("%s", qPrintable(msg));
                      return false;
                  }
              break;
          default:
              break;
          }
          return  true;
      }
  
      inline void openIfndef(QTextStream &str, const QString &symbol) { if (!symbol.isEmpty()) str << QLatin1String("#ifndef ") << symbol << endl;  }
      inline void closeIfndef(QTextStream &str, const QString &symbol) { if (!symbol.isEmpty()) str << QLatin1String("#endif // ") << symbol << endl; }
  
      const char *accessibilityDefineC = "QT_NO_ACCESSIBILITY";
      const char *toolTipDefineC = "QT_NO_TOOLTIP";
      const char *whatsThisDefineC = "QT_NO_WHATSTHIS";
      const char *statusTipDefineC = "QT_NO_STATUSTIP";
      const char *shortcutDefineC = "QT_NO_SHORTCUT";
  }
  
  namespace CPP {
  
  FontHandle::FontHandle(const DomFont *domFont) :
        m_domFont(domFont)
  {
  }
  
  int FontHandle::compare(const FontHandle &rhs) const
  {
      const QString family    = m_domFont->hasElementFamily()     ?     m_domFont->elementFamily() : QString();
      const QString rhsFamily = rhs.m_domFont->hasElementFamily() ? rhs.m_domFont->elementFamily() : QString();
  
      if (const int frc = family.compare(rhsFamily))
          return frc;
  
      const int pointSize    = m_domFont->hasElementPointSize()     ?     m_domFont->elementPointSize() : -1;
      const int rhsPointSize = rhs.m_domFont->hasElementPointSize() ? rhs.m_domFont->elementPointSize() : -1;
  
      if (const int crc = compareInt(pointSize, rhsPointSize))
          return crc;
  
      const int bold    = m_domFont->hasElementBold()     ? (m_domFont->elementBold()     ? 1 : 0) : -1;
      const int rhsBold = rhs.m_domFont->hasElementBold() ? (rhs.m_domFont->elementBold() ? 1 : 0) : -1;
      if (const int crc = compareInt(bold, rhsBold))
          return crc;
  
      const int italic    = m_domFont->hasElementItalic()     ? (m_domFont->elementItalic()     ? 1 : 0) : -1;
      const int rhsItalic = rhs.m_domFont->hasElementItalic() ? (rhs.m_domFont->elementItalic() ? 1 : 0) : -1;
      if (const int crc = compareInt(italic, rhsItalic))
          return crc;
  
      const int underline    = m_domFont->hasElementUnderline()     ? (m_domFont->elementUnderline()     ? 1 : 0) : -1;
      const int rhsUnderline = rhs.m_domFont->hasElementUnderline() ? (rhs.m_domFont->elementUnderline() ? 1 : 0) : -1;
      if (const int crc = compareInt(underline, rhsUnderline))
          return crc;
  
      const int weight    = m_domFont->hasElementWeight()     ?     m_domFont->elementWeight() : -1;
      const int rhsWeight = rhs.m_domFont->hasElementWeight() ? rhs.m_domFont->elementWeight() : -1;
      if (const int crc = compareInt(weight, rhsWeight))
          return crc;
  
      const int strikeOut    = m_domFont->hasElementStrikeOut()     ? (m_domFont->elementStrikeOut()     ? 1 : 0) : -1;
      const int rhsStrikeOut = rhs.m_domFont->hasElementStrikeOut() ? (rhs.m_domFont->elementStrikeOut() ? 1 : 0) : -1;
      if (const int crc = compareInt(strikeOut, rhsStrikeOut))
          return crc;
  
      const int kerning    = m_domFont->hasElementKerning()     ? (m_domFont->elementKerning()     ? 1 : 0) : -1;
      const int rhsKerning = rhs.m_domFont->hasElementKerning() ? (rhs.m_domFont->elementKerning() ? 1 : 0) : -1;
      if (const int crc = compareInt(kerning, rhsKerning))
          return crc;
  
      const int antialiasing    = m_domFont->hasElementAntialiasing()     ? (m_domFont->elementAntialiasing()     ? 1 : 0) : -1;
      const int rhsAntialiasing = rhs.m_domFont->hasElementAntialiasing() ? (rhs.m_domFont->elementAntialiasing() ? 1 : 0) : -1;
      if (const int crc = compareInt(antialiasing, rhsAntialiasing))
          return crc;
  
      const QString styleStrategy    = m_domFont->hasElementStyleStrategy()     ?     m_domFont->elementStyleStrategy() : QString();
      const QString rhsStyleStrategy = rhs.m_domFont->hasElementStyleStrategy() ? rhs.m_domFont->elementStyleStrategy() : QString();
  
      if (const int src = styleStrategy.compare(rhsStyleStrategy))
          return src;
  
      return 0;
  }
  
  IconHandle::IconHandle(const DomResourceIcon *domIcon) :
        m_domIcon(domIcon)
  {
  }
  
  int IconHandle::compare(const IconHandle &rhs) const
  {
      if (const int comp = m_domIcon->attributeTheme().compare(rhs.m_domIcon->attributeTheme()))
          return comp;
  
      const QString normalOff    =     m_domIcon->hasElementNormalOff() ?     m_domIcon->elementNormalOff()->text() : QString();
      const QString rhsNormalOff = rhs.m_domIcon->hasElementNormalOff() ? rhs.m_domIcon->elementNormalOff()->text() : QString();
      if (const int comp = normalOff.compare(rhsNormalOff))
          return comp;
  
      const QString normalOn    =     m_domIcon->hasElementNormalOn() ?     m_domIcon->elementNormalOn()->text() : QString();
      const QString rhsNormalOn = rhs.m_domIcon->hasElementNormalOn() ? rhs.m_domIcon->elementNormalOn()->text() : QString();
      if (const int comp = normalOn.compare(rhsNormalOn))
          return comp;
  
      const QString disabledOff    =     m_domIcon->hasElementDisabledOff() ?     m_domIcon->elementDisabledOff()->text() : QString();
      const QString rhsDisabledOff = rhs.m_domIcon->hasElementDisabledOff() ? rhs.m_domIcon->elementDisabledOff()->text() : QString();
      if (const int comp = disabledOff.compare(rhsDisabledOff))
          return comp;
  
      const QString disabledOn    =     m_domIcon->hasElementDisabledOn() ?     m_domIcon->elementDisabledOn()->text() : QString();
      const QString rhsDisabledOn = rhs.m_domIcon->hasElementDisabledOn() ? rhs.m_domIcon->elementDisabledOn()->text() : QString();
      if (const int comp = disabledOn.compare(rhsDisabledOn))
          return comp;
  
      const QString activeOff    =     m_domIcon->hasElementActiveOff() ?     m_domIcon->elementActiveOff()->text() : QString();
      const QString rhsActiveOff = rhs.m_domIcon->hasElementActiveOff() ? rhs.m_domIcon->elementActiveOff()->text() : QString();
      if (const int comp = activeOff.compare(rhsActiveOff))
          return comp;
  
      const QString activeOn    =     m_domIcon->hasElementActiveOn() ?     m_domIcon->elementActiveOn()->text() : QString();
      const QString rhsActiveOn = rhs.m_domIcon->hasElementActiveOn() ? rhs.m_domIcon->elementActiveOn()->text() : QString();
      if (const int comp = activeOn.compare(rhsActiveOn))
          return comp;
  
      const QString selectedOff    =     m_domIcon->hasElementSelectedOff() ?     m_domIcon->elementSelectedOff()->text() : QString();
      const QString rhsSelectedOff = rhs.m_domIcon->hasElementSelectedOff() ? rhs.m_domIcon->elementSelectedOff()->text() : QString();
      if (const int comp = selectedOff.compare(rhsSelectedOff))
          return comp;
  
      const QString selectedOn    =     m_domIcon->hasElementSelectedOn() ?     m_domIcon->elementSelectedOn()->text() : QString();
      const QString rhsSelectedOn = rhs.m_domIcon->hasElementSelectedOn() ? rhs.m_domIcon->elementSelectedOn()->text() : QString();
      if (const int comp = selectedOn.compare(rhsSelectedOn))
          return comp;
      // Pre 4.4 Legacy
      if (const int comp = m_domIcon->text().compare(rhs.m_domIcon->text()))
          return comp;
  
      return 0;
  }
  
  SizePolicyHandle::SizePolicyHandle(const DomSizePolicy *domSizePolicy) :
      m_domSizePolicy(domSizePolicy)
  {
  }
  
  int SizePolicyHandle::compare(const SizePolicyHandle &rhs) const
  {
  
      const int hSizeType    = m_domSizePolicy->hasElementHSizeType()     ? m_domSizePolicy->elementHSizeType()     : -1;
      const int rhsHSizeType = rhs.m_domSizePolicy->hasElementHSizeType() ? rhs.m_domSizePolicy->elementHSizeType() : -1;
      if (const int crc = compareInt(hSizeType, rhsHSizeType))
          return crc;
  
      const int vSizeType    = m_domSizePolicy->hasElementVSizeType()     ? m_domSizePolicy->elementVSizeType()     : -1;
      const int rhsVSizeType = rhs.m_domSizePolicy->hasElementVSizeType() ? rhs.m_domSizePolicy->elementVSizeType() : -1;
      if (const int crc = compareInt(vSizeType, rhsVSizeType))
          return crc;
  
      const int hStretch    =  m_domSizePolicy->hasElementHorStretch()     ? m_domSizePolicy->elementHorStretch()     : -1;
      const int rhsHStretch =  rhs.m_domSizePolicy->hasElementHorStretch() ? rhs.m_domSizePolicy->elementHorStretch() : -1;
      if (const int crc = compareInt(hStretch, rhsHStretch))
          return crc;
  
      const int vStretch    =  m_domSizePolicy->hasElementVerStretch()     ? m_domSizePolicy->elementVerStretch()     : -1;
      const int rhsVStretch =  rhs.m_domSizePolicy->hasElementVerStretch() ? rhs.m_domSizePolicy->elementVerStretch() : -1;
      if (const int crc = compareInt(vStretch, rhsVStretch))
          return crc;
  
      const QString attributeHSizeType    = m_domSizePolicy->hasAttributeHSizeType()     ? m_domSizePolicy->attributeHSizeType()     : QString();
      const QString rhsAttributeHSizeType = rhs.m_domSizePolicy->hasAttributeHSizeType() ? rhs.m_domSizePolicy->attributeHSizeType() : QString();
  
      if (const int hrc = attributeHSizeType.compare(rhsAttributeHSizeType))
          return hrc;
  
      const QString attributeVSizeType    = m_domSizePolicy->hasAttributeVSizeType()     ? m_domSizePolicy->attributeVSizeType()     : QString();
      const QString rhsAttributeVSizeType = rhs.m_domSizePolicy->hasAttributeVSizeType() ? rhs.m_domSizePolicy->attributeVSizeType() : QString();
  
      return attributeVSizeType.compare(rhsAttributeVSizeType);
  }
  
  // ---  WriteInitialization: LayoutDefaultHandler
  
  WriteInitialization::LayoutDefaultHandler::LayoutDefaultHandler()
  {
      std::fill_n(m_state, int(NumProperties), 0u);
      std::fill_n(m_defaultValues, int(NumProperties), 0);
  }
  
  
  
  void WriteInitialization::LayoutDefaultHandler::acceptLayoutDefault(DomLayoutDefault *node)
  {
      if (!node)
          return;
      if (node->hasAttributeMargin()) {
          m_state[Margin] |= HasDefaultValue;
          m_defaultValues[Margin] = node->attributeMargin();
      }
      if (node->hasAttributeSpacing()) {
          m_state[Spacing] |= HasDefaultValue;
          m_defaultValues[Spacing]  = node->attributeSpacing();
      }
  }
  
  void WriteInitialization::LayoutDefaultHandler::acceptLayoutFunction(DomLayoutFunction *node)
  {
      if (!node)
          return;
      if (node->hasAttributeMargin()) {
          m_state[Margin]     |= HasDefaultFunction;
          m_functions[Margin] =  node->attributeMargin();
          m_functions[Margin] += QLatin1String("()");
      }
      if (node->hasAttributeSpacing()) {
          m_state[Spacing]     |= HasDefaultFunction;
          m_functions[Spacing] =  node->attributeSpacing();
          m_functions[Spacing] += QLatin1String("()");
      }
  }
  
  static inline void writeContentsMargins(const QString &indent, const QString &objectName, int value, QTextStream &str)
  {
       QString contentsMargins;
       QTextStream(&contentsMargins) << value << ", " << value << ", " << value << ", " << value;
       writeSetter(indent, objectName, QLatin1String("setContentsMargins"), contentsMargins, str);
   }
  
  void WriteInitialization::LayoutDefaultHandler::writeProperty(int p, const QString &indent, const QString &objectName,
                                                                const DomPropertyMap &properties, const QString &propertyName, const QString &setter,
                                                                int defaultStyleValue, bool suppressDefault, QTextStream &str) const
  {
      // User value
      const DomPropertyMap::const_iterator mit = properties.constFind(propertyName);
      const bool found = mit != properties.constEnd();
      if (found) {
          const int value = mit.value()->elementNumber();
          // Emulate the pre 4.3 behaviour: The value form default value was only used to determine
          // the default value, layout properties were always written
          const bool useLayoutFunctionPre43 = !suppressDefault && (m_state[p] == (HasDefaultFunction|HasDefaultValue)) && value == m_defaultValues[p];
          if (!useLayoutFunctionPre43) {
              bool ifndefMac = (!(m_state[p] & (HasDefaultFunction|HasDefaultValue))
                               && value == defaultStyleValue);
              if (ifndefMac)
                  str << "#ifndef Q_OS_MAC\n";
              if (p == Margin) { // Use setContentsMargins for numeric values
                  writeContentsMargins(indent, objectName, value, str);
              } else {
                  writeSetter(indent, objectName, setter, value, str);
              }
              if (ifndefMac)
                  str << "#endif\n";
              return;
          }
      }
      if (suppressDefault)
          return;
      // get default.
      if (m_state[p] & HasDefaultFunction) {
          // Do not use setContentsMargins to avoid repetitive evaluations.
          writeSetter(indent, objectName, setter, m_functions[p], str);
          return;
      }
      if (m_state[p] & HasDefaultValue) {
          if (p == Margin) { // Use setContentsMargins for numeric values
              writeContentsMargins(indent, objectName, m_defaultValues[p], str);
          } else {
              writeSetter(indent, objectName, setter, m_defaultValues[p], str);
          }
      }
      return;
  }
  
  
  void WriteInitialization::LayoutDefaultHandler::writeProperties(const QString &indent, const QString &varName,
                                                                  const DomPropertyMap &properties, int marginType,
                                                                  bool suppressMarginDefault,
                                                                  QTextStream &str) const {
      // Write out properties and ignore the ones found in
      // subsequent writing of the property list.
      int defaultSpacing = marginType == WriteInitialization::Use43UiFile ? -1 : 6;
      writeProperty(Spacing, indent, varName, properties, QLatin1String("spacing"), QLatin1String("setSpacing"),
                    defaultSpacing, false, str);
      // We use 9 as TopLevelMargin, since Designer seem to always use 9.
      static const int layoutmargins[4] = {-1, 9, 9, 0};
      writeProperty(Margin,  indent, varName, properties, QLatin1String("margin"),  QLatin1String("setMargin"),
                    layoutmargins[marginType], suppressMarginDefault, str);
  }
  
  template <class DomElement> // (DomString, DomStringList)
  static bool needsTranslation(const DomElement *element)
  {
      if (!element)
          return false;
      return !element->hasAttributeNotr() || !toBool(element->attributeNotr());
  }
  
  // ---  WriteInitialization
  WriteInitialization::WriteInitialization(Uic *uic, bool activateScripts) :
        m_uic(uic),
        m_driver(uic->driver()), m_output(uic->output()), m_option(uic->option()),
        m_indent(m_option.indent + m_option.indent),
        m_dindent(m_indent + m_option.indent),
        m_stdsetdef(true),
        m_layoutMarginType(TopLevelMargin),
        m_mainFormUsedInRetranslateUi(false),
        m_delayedOut(&m_delayedInitialization, QIODevice::WriteOnly),
        m_refreshOut(&m_refreshInitialization, QIODevice::WriteOnly),
        m_actionOut(&m_delayedActionInitialization, QIODevice::WriteOnly),
        m_activateScripts(activateScripts), m_layoutWidget(false),
        m_firstThemeIcon(true)
  {
  }
  
  void WriteInitialization::acceptUI(DomUI *node)
  {
      m_registeredImages.clear();
      m_actionGroupChain.push(0);
      m_widgetChain.push(0);
      m_layoutChain.push(0);
  
      acceptLayoutDefault(node->elementLayoutDefault());
      acceptLayoutFunction(node->elementLayoutFunction());
  
      if (node->elementCustomWidgets())
          TreeWalker::acceptCustomWidgets(node->elementCustomWidgets());
  
      if (node->elementImages())
          TreeWalker::acceptImages(node->elementImages());
  
      if (m_option.generateImplemetation)
          m_output << "#include <" << m_driver->headerFileName() << ">\n\n";
  
      m_stdsetdef = true;
      if (node->hasAttributeStdSetDef())
          m_stdsetdef = node->attributeStdSetDef();
  
      const QString className = node->elementClass() + m_option.postfix;
      m_generatedClass = className;
  
      const QString varName = m_driver->findOrInsertWidget(node->elementWidget());
      m_mainFormVarName = varName;
      m_registeredWidgets.insert(varName, node->elementWidget()); // register the main widget
  
      const QString widgetClassName = node->elementWidget()->attributeClass();
  
      m_output << m_option.indent << "void " << "setupUi(" << widgetClassName << " *" << varName << ")\n"
             << m_option.indent << "{\n";
  
      if (m_activateScripts)
          writeSetupUIScriptVariableDeclarations(m_indent, m_output);
  
      const QStringList connections = m_uic->databaseInfo()->connections();
      for (int i=0; i<connections.size(); ++i) {
          QString connection = connections.at(i);
  
          if (connection == QLatin1String("(default)"))
              continue;
  
          const QString varConn = connection + QLatin1String("Connection");
          m_output << m_indent << varConn << " = QSqlDatabase::database(" << writeString(connection, m_dindent) << ");\n";
      }
  
      acceptWidget(node->elementWidget());
  
      if (m_buddies.size() > 0)
          openIfndef(m_output, QLatin1String(shortcutDefineC));
      for (int i=0; i<m_buddies.size(); ++i) {
          const Buddy &b = m_buddies.at(i);
  
          if (!m_registeredWidgets.contains(b.objName)) {
              fprintf(stderr, "%s: Warning: Buddy assignment: '%s' is not a valid widget.\n",
                      qPrintable(m_option.messagePrefix()),
                      b.objName.toLatin1().data());
              continue;
          } else if (!m_registeredWidgets.contains(b.buddy)) {
              fprintf(stderr, "%s: Warning: Buddy assignment: '%s' is not a valid widget.\n",
                      qPrintable(m_option.messagePrefix()),
                      b.buddy.toLatin1().data());
              continue;
          }
  
          m_output << m_indent << b.objName << "->setBuddy(" << b.buddy << ");\n";
      }
      if (m_buddies.size() > 0)
          closeIfndef(m_output, QLatin1String(shortcutDefineC));
  
      if (node->elementTabStops())
          acceptTabStops(node->elementTabStops());
  
      if (m_delayedActionInitialization.size())
          m_output << "\n" << m_delayedActionInitialization;
  
      m_output << "\n" << m_indent << "retranslateUi(" << varName << ");\n";
  
      if (node->elementConnections())
          acceptConnections(node->elementConnections());
  
      if (!m_delayedInitialization.isEmpty())
          m_output << "\n" << m_delayedInitialization << "\n";
  
      if (m_option.autoConnection)
          m_output << "\n" << m_indent << "QMetaObject::connectSlotsByName(" << varName << ");\n";
  
      m_output << m_option.indent << "} // setupUi\n\n";
  
      if (!m_mainFormUsedInRetranslateUi) {
          m_refreshInitialization += m_indent;
          m_refreshInitialization += QLatin1String("Q_UNUSED(");
          m_refreshInitialization += varName ;
          m_refreshInitialization += QLatin1String(");\n");
      }
  
      m_output << m_option.indent << "void " << "retranslateUi(" << widgetClassName << " *" << varName << ")\n"
             << m_option.indent << "{\n"
             << m_refreshInitialization
             << m_option.indent << "} // retranslateUi\n\n";
  
      m_layoutChain.pop();
      m_widgetChain.pop();
      m_actionGroupChain.pop();
  }
  
  void WriteInitialization::addWizardPage(const QString &pageVarName, const DomWidget *page, const QString &parentWidget)
  {
      /* If the node has a (free-format) string "pageId" attribute (which could
       * an integer or an enumeration value), use setPage(), else addPage(). */
      QString id;
      const DomPropertyList attributes = page->elementAttribute();
      if (!attributes.empty()) {
          const DomPropertyList::const_iterator acend = attributes.constEnd();
          for (DomPropertyList::const_iterator it = attributes.constBegin(); it != acend; ++it)
              if ((*it)->attributeName() == QLatin1String("pageId")) {
                  if (const DomString *ds = (*it)->elementString())
                      id = ds->text();
                  break;
              }
      }
      if (id.isEmpty()) {
          m_output << m_indent << parentWidget << "->addPage(" << pageVarName << ");\n";
      } else {
          m_output << m_indent << parentWidget << "->setPage(" << id << ", " << pageVarName << ");\n";
      }
  }
  
  void WriteInitialization::acceptWidget(DomWidget *node)
  {
      m_layoutMarginType = m_widgetChain.count() == 1 ? TopLevelMargin : ChildMargin;
      const QString className = node->attributeClass();
      const QString varName = m_driver->findOrInsertWidget(node);
      m_registeredWidgets.insert(varName, node); // register the current widget
  
      QString parentWidget, parentClass;
      if (m_widgetChain.top()) {
          parentWidget = m_driver->findOrInsertWidget(m_widgetChain.top());
          parentClass = m_widgetChain.top()->attributeClass();
      }
  
      const QString savedParentWidget = parentWidget;
  
      if (m_uic->isContainer(parentClass))
          parentWidget.clear();
  
      if (m_widgetChain.size() != 1)
          m_output << m_indent << varName << " = new " << m_uic->customWidgetsInfo()->realClassName(className) << '(' << parentWidget << ");\n";
  
      parentWidget = savedParentWidget;
  
      if (m_uic->customWidgetsInfo()->extends(className, QLatin1String("QComboBox"))) {
          initializeComboBox(node);
      } else if (m_uic->customWidgetsInfo()->extends(className, QLatin1String("QListWidget"))) {
          initializeListWidget(node);
      } else if (m_uic->customWidgetsInfo()->extends(className, QLatin1String("QTreeWidget"))) {
          initializeTreeWidget(node);
      } else if (m_uic->customWidgetsInfo()->extends(className, QLatin1String("QTableWidget"))) {
          initializeTableWidget(node);
      }
  
      if (m_uic->isButton(className))
          addButtonGroup(node, varName);
  
      writeProperties(varName, className, node->elementProperty());
  
      if (m_uic->customWidgetsInfo()->extends(className, QLatin1String("QMenu")) && parentWidget.size()) {
          initializeMenu(node, parentWidget);
      }
  
      if (node->elementLayout().isEmpty())
          m_layoutChain.push(0);
  
      m_layoutWidget = false;
      if (className == QLatin1String("QWidget") && !node->hasAttributeNative()) {
          if (const DomWidget* parentWidget = m_widgetChain.top()) {
              const QString parentClass = parentWidget->attributeClass();
              if (parentClass != QLatin1String("QMainWindow")
                  && !m_uic->isCustomWidgetContainer(parentClass)
                  && !m_uic->isContainer(parentClass))
              m_layoutWidget = true;
          }
      }
      m_widgetChain.push(node);
      m_layoutChain.push(0);
      TreeWalker::acceptWidget(node);
      m_layoutChain.pop();
      m_widgetChain.pop();
      m_layoutWidget = false;
  
      const DomPropertyMap attributes = propertyMap(node->elementAttribute());
  
      const QString pageDefaultString = QLatin1String("Page");
  
      if (m_uic->customWidgetsInfo()->extends(parentClass, QLatin1String("QMainWindow"))) {
          if (m_uic->customWidgetsInfo()->extends(className, QLatin1String("QMenuBar"))) {
              m_output << m_indent << parentWidget << "->setMenuBar(" << varName <<");\n";
          } else if (m_uic->customWidgetsInfo()->extends(className, QLatin1String("QToolBar"))) {
              m_output << m_indent << parentWidget << "->addToolBar("
                       << toolBarAreaStringFromDOMAttributes(attributes) << varName << ");\n";
  
              if (const DomProperty *pbreak = attributes.value(QLatin1String("toolBarBreak"))) {
                  if (pbreak->elementBool() == QLatin1String("true")) {
                      m_output << m_indent << parentWidget << "->insertToolBarBreak(" <<  varName << ");\n";
                  }
              }
  
          } else if (m_uic->customWidgetsInfo()->extends(className, QLatin1String("QDockWidget"))) {
              QString area;
              if (DomProperty *pstyle = attributes.value(QLatin1String("dockWidgetArea"))) {
                  area += QLatin1String("static_cast<Qt::DockWidgetArea>(");
                  area += QString::number(pstyle->elementNumber());
                  area += QLatin1String("), ");
              }
  
              m_output << m_indent << parentWidget << "->addDockWidget(" << area << varName << ");\n";
          } else if (m_uic->customWidgetsInfo()->extends(className, QLatin1String("QStatusBar"))) {
              m_output << m_indent << parentWidget << "->setStatusBar(" << varName << ");\n";
          } else {
                  m_output << m_indent << parentWidget << "->setCentralWidget(" << varName << ");\n";
          }
      }
  
      // Check for addPageMethod of a custom plugin first
      const QString addPageMethod = m_uic->customWidgetsInfo()->customWidgetAddPageMethod(parentClass);
      if (!addPageMethod.isEmpty()) {
          m_output << m_indent << parentWidget << "->" << addPageMethod << '(' << varName << ");\n";
      } else if (m_uic->customWidgetsInfo()->extends(parentClass, QLatin1String("QStackedWidget"))) {
          m_output << m_indent << parentWidget << "->addWidget(" << varName << ");\n";
      } else if (m_uic->customWidgetsInfo()->extends(parentClass, QLatin1String("QToolBar"))) {
          m_output << m_indent << parentWidget << "->addWidget(" << varName << ");\n";
      } else if (m_uic->customWidgetsInfo()->extends(parentClass, QLatin1String("QDockWidget"))) {
          m_output << m_indent << parentWidget << "->setWidget(" << varName << ");\n";
      } else if (m_uic->customWidgetsInfo()->extends(parentClass, QLatin1String("QScrollArea"))) {
          m_output << m_indent << parentWidget << "->setWidget(" << varName << ");\n";
      } else if (m_uic->customWidgetsInfo()->extends(parentClass, QLatin1String("QSplitter"))) {
          m_output << m_indent << parentWidget << "->addWidget(" << varName << ");\n";
      } else if (m_uic->customWidgetsInfo()->extends(parentClass, QLatin1String("QMdiArea"))) {
          m_output << m_indent << parentWidget << "->addSubWindow(" << varName << ");\n";
      } else if (m_uic->customWidgetsInfo()->extends(parentClass, QLatin1String("QWizard"))) {
          addWizardPage(varName, node, parentWidget);
      } else if (m_uic->customWidgetsInfo()->extends(parentClass, QLatin1String("QToolBox"))) {
          QString icon;
          if (const DomProperty *picon = attributes.value(QLatin1String("icon"))) {
              icon += QLatin1String(", ") ;
              icon += iconCall(picon);
          }
  
          const DomProperty *plabel = attributes.value(QLatin1String("label"));
          DomString *plabelString = plabel ? plabel->elementString() : 0;
  
          m_output << m_indent << parentWidget << "->addItem(" << varName << icon << ", " << noTrCall(plabelString, pageDefaultString) << ");\n";
  
          autoTrOutput(plabelString, pageDefaultString) << m_indent << parentWidget << "->setItemText("
                     << parentWidget << "->indexOf(" << varName << "), " << autoTrCall(plabelString, pageDefaultString) << ");\n";
  
  #ifndef QT_NO_TOOLTIP
          if (DomProperty *ptoolTip = attributes.value(QLatin1String("toolTip"))) {
              autoTrOutput(ptoolTip->elementString()) << m_indent << parentWidget << "->setItemToolTip("
                         << parentWidget << "->indexOf(" << varName << "), " << autoTrCall(ptoolTip->elementString()) << ");\n";
          }
  #endif // QT_NO_TOOLTIP
      } else if (m_uic->customWidgetsInfo()->extends(parentClass, QLatin1String("QTabWidget"))) {
          QString icon;
          if (const DomProperty *picon = attributes.value(QLatin1String("icon"))) {
              icon += QLatin1String(", ");
              icon += iconCall(picon);
          }
  
          const DomProperty *ptitle = attributes.value(QLatin1String("title"));
          DomString *ptitleString = ptitle ? ptitle->elementString() : 0;
  
          m_output << m_indent << parentWidget << "->addTab(" << varName << icon << ", " << "QString());\n";
  
          autoTrOutput(ptitleString, pageDefaultString) << m_indent << parentWidget << "->setTabText("
                     << parentWidget << "->indexOf(" << varName << "), " << autoTrCall(ptitleString, pageDefaultString) << ");\n";
  
  #ifndef QT_NO_TOOLTIP
          if (const DomProperty *ptoolTip = attributes.value(QLatin1String("toolTip"))) {
              autoTrOutput(ptoolTip->elementString()) << m_indent << parentWidget << "->setTabToolTip("
                         << parentWidget << "->indexOf(" << varName << "), " << autoTrCall(ptoolTip->elementString()) << ");\n";
          }
  #endif // QT_NO_TOOLTIP
  #ifndef QT_NO_WHATSTHIS
          if (const DomProperty *pwhatsThis = attributes.value(QLatin1String("whatsThis"))) {
              autoTrOutput(pwhatsThis->elementString()) << m_indent << parentWidget << "->setTabWhatsThis("
                         << parentWidget << "->indexOf(" << varName << "), " << autoTrCall(pwhatsThis->elementString()) << ");\n";
          }
  #endif // QT_NO_WHATSTHIS
      }
  
      //
      // Special handling for qtableview/qtreeview fake header attributes
      //
      static const QLatin1String realPropertyNames[] = {
          QLatin1String("visible"),
          QLatin1String("cascadingSectionResizes"),
          QLatin1String("defaultSectionSize"),
          QLatin1String("highlightSections"),
          QLatin1String("minimumSectionSize"),
          QLatin1String("showSortIndicator"),
          QLatin1String("stretchLastSection"),
      };
  
      if (m_uic->customWidgetsInfo()->extends(className, QLatin1String("QTreeView"))
                 || m_uic->customWidgetsInfo()->extends(className, QLatin1String("QTreeWidget"))) {
          DomPropertyList headerProperties;
          for (auto realPropertyName : realPropertyNames) {
              const QString fakePropertyName = QLatin1String("header")
                      + QChar(realPropertyName.at(0)).toUpper() + realPropertyName.mid(1);
              if (DomProperty *fakeProperty = attributes.value(fakePropertyName)) {
                  fakeProperty->setAttributeName(realPropertyName);
                  headerProperties << fakeProperty;
              }
          }
          writeProperties(varName + QLatin1String("->header()"), QLatin1String("QHeaderView"),
                          headerProperties, WritePropertyIgnoreObjectName);
  
      } else if (m_uic->customWidgetsInfo()->extends(className, QLatin1String("QTableView"))
                 || m_uic->customWidgetsInfo()->extends(className, QLatin1String("QTableWidget"))) {
  
          static const QLatin1String headerPrefixes[] = {
              QLatin1String("horizontalHeader"),
              QLatin1String("verticalHeader"),
          };
  
          for (auto headerPrefix : headerPrefixes) {
              DomPropertyList headerProperties;
              for (auto realPropertyName : realPropertyNames) {
                  const QString fakePropertyName = headerPrefix
                          + QChar(realPropertyName.at(0)).toUpper() + realPropertyName.mid(1);
                  if (DomProperty *fakeProperty = attributes.value(fakePropertyName)) {
                      fakeProperty->setAttributeName(realPropertyName);
                      headerProperties << fakeProperty;
                  }
              }
              writeProperties(varName + QLatin1String("->") + headerPrefix + QLatin1String("()"),
                              QLatin1String("QHeaderView"),
                              headerProperties, WritePropertyIgnoreObjectName);
          }
      }
  
      if (node->elementLayout().isEmpty())
          m_layoutChain.pop();
  
      const QStringList zOrder = node->elementZOrder();
      for (int i = 0; i < zOrder.size(); ++i) {
          const QString name = zOrder.at(i);
  
          if (!m_registeredWidgets.contains(name)) {
              fprintf(stderr, "%s: Warning: Z-order assignment: '%s' is not a valid widget.\n",
                      qPrintable(m_option.messagePrefix()),
                      name.toLatin1().data());
              continue;
          }
  
          if (name.isEmpty()) {
              continue;
          }
  
          m_output << m_indent << name << "->raise();\n";
      }
  }
  
  void WriteInitialization::addButtonGroup(const DomWidget *buttonNode, const QString &varName)
  {
      const DomPropertyMap attributes = propertyMap(buttonNode->elementAttribute());
      // Look up the button group name as specified in the attribute and find the uniquified name
      const DomProperty *prop = attributes.value(QLatin1String("buttonGroup"));
      if (!prop)
          return;
      const QString attributeName = toString(prop->elementString());
      const DomButtonGroup *group = m_driver->findButtonGroup(attributeName);
      // Legacy feature: Create missing groups on the fly as the UIC button group feature
      // was present before the actual Designer support (4.5)
      const bool createGroupOnTheFly = group == 0;
      if (createGroupOnTheFly) {
          DomButtonGroup *newGroup = new DomButtonGroup;
          newGroup->setAttributeName(attributeName);
          group = newGroup;
          fprintf(stderr, "%s: Warning: Creating button group `%s'\n",
                  qPrintable(m_option.messagePrefix()),
                  attributeName.toLatin1().data());
      }
      const QString groupName = m_driver->findOrInsertButtonGroup(group);
      // Create on demand
      if (!m_buttonGroups.contains(groupName)) {
          const QString className = QLatin1String("QButtonGroup");
          m_output << m_indent;
          if (createGroupOnTheFly)
              m_output << className << " *";
          m_output << groupName << " = new " << className << '(' << m_mainFormVarName << ");\n";
          m_buttonGroups.insert(groupName);
          writeProperties(groupName, className, group->elementProperty());
      }
      m_output << m_indent << groupName << "->addButton(" << varName << ");\n";
  }
  
  void WriteInitialization::acceptLayout(DomLayout *node)
  {
      const QString className = node->attributeClass();
      const QString varName = m_driver->findOrInsertLayout(node);
  
      const DomPropertyMap properties = propertyMap(node->elementProperty());
      const bool oldLayoutProperties = properties.constFind(QLatin1String("margin")) != properties.constEnd();
  
      bool isGroupBox = false;
  
      m_output << m_indent << varName << " = new " << className << '(';
  
      if (!m_layoutChain.top() && !isGroupBox)
          m_output << m_driver->findOrInsertWidget(m_widgetChain.top());
  
      m_output << ");\n";
  
      // Suppress margin on a read child layout
      const bool suppressMarginDefault = m_layoutChain.top();
      int marginType = Use43UiFile;
      if (oldLayoutProperties)
          marginType = m_layoutMarginType;
      m_LayoutDefaultHandler.writeProperties(m_indent, varName, properties, marginType, suppressMarginDefault, m_output);
  
      m_layoutMarginType = SubLayoutMargin;
  
      DomPropertyList propList = node->elementProperty();
      DomPropertyList newPropList;
      if (m_layoutWidget) {
          bool left, top, right, bottom;
          left = top = right = bottom = false;
          for (int i = 0; i < propList.size(); ++i) {
              const DomProperty *p = propList.at(i);
              const QString propertyName = p->attributeName();
              if (propertyName == QLatin1String("leftMargin") && p->kind() == DomProperty::Number)
                  left = true;
              else if (propertyName == QLatin1String("topMargin") && p->kind() == DomProperty::Number)
                  top = true;
              else if (propertyName == QLatin1String("rightMargin") && p->kind() == DomProperty::Number)
                  right = true;
              else if (propertyName == QLatin1String("bottomMargin") && p->kind() == DomProperty::Number)
                  bottom = true;
          }
          if (!left) {
              DomProperty *p = new DomProperty();
              p->setAttributeName(QLatin1String("leftMargin"));
              p->setElementNumber(0);
              newPropList.append(p);
          }
          if (!top) {
              DomProperty *p = new DomProperty();
              p->setAttributeName(QLatin1String("topMargin"));
              p->setElementNumber(0);
              newPropList.append(p);
          }
          if (!right) {
              DomProperty *p = new DomProperty();
              p->setAttributeName(QLatin1String("rightMargin"));
              p->setElementNumber(0);
              newPropList.append(p);
          }
          if (!bottom) {
              DomProperty *p = new DomProperty();
              p->setAttributeName(QLatin1String("bottomMargin"));
              p->setElementNumber(0);
              newPropList.append(p);
          }
          m_layoutWidget = false;
      }
  
      propList.append(newPropList);
  
      writeProperties(varName, className, propList, WritePropertyIgnoreMargin|WritePropertyIgnoreSpacing);
  
      // Clean up again:
      propList.clear();
      qDeleteAll(newPropList);
      newPropList.clear();
  
      m_layoutChain.push(node);
      TreeWalker::acceptLayout(node);
      m_layoutChain.pop();
  
      // Stretch? (Unless we are compiling for UIC3)
      const QString numberNull = QString(QLatin1Char('0'));
      writePropertyList(varName, QLatin1String("setStretch"), node->attributeStretch(), numberNull);
      writePropertyList(varName, QLatin1String("setRowStretch"), node->attributeRowStretch(), numberNull);
      writePropertyList(varName, QLatin1String("setColumnStretch"), node->attributeColumnStretch(), numberNull);
      writePropertyList(varName, QLatin1String("setColumnMinimumWidth"), node->attributeColumnMinimumWidth(), numberNull);
      writePropertyList(varName, QLatin1String("setRowMinimumHeight"), node->attributeRowMinimumHeight(), numberNull);
  }
  
  // Apply a comma-separated list of values using a function "setSomething(int idx, value)"
  void WriteInitialization::writePropertyList(const QString &varName,
                                              const QString &setFunction,
                                              const QString &value,
                                              const QString &defaultValue)
  {
      if (value.isEmpty())
          return;
      const QStringList list = value.split(QLatin1Char(','));
      const int count =  list.count();
      for (int i = 0; i < count; i++)
          if (list.at(i) != defaultValue)
              m_output << m_indent << varName << "->" << setFunction << '(' << i << ", " << list.at(i) << ");\n";
  }
  
  void WriteInitialization::acceptSpacer(DomSpacer *node)
  {
      m_output << m_indent << m_driver->findOrInsertSpacer(node) << " = ";
      writeSpacerItem(node, m_output);
      m_output << ";\n";
  }
  
  static inline QString formLayoutRole(int column, int colspan)
  {
      if (colspan > 1)
          return QLatin1String("QFormLayout::SpanningRole");
      return column == 0 ? QLatin1String("QFormLayout::LabelRole") : QLatin1String("QFormLayout::FieldRole");
  }
  
  void WriteInitialization::acceptLayoutItem(DomLayoutItem *node)
  {
      TreeWalker::acceptLayoutItem(node);
  
      DomLayout *layout = m_layoutChain.top();
  
      if (!layout)
          return;
  
      const QString layoutName = m_driver->findOrInsertLayout(layout);
      const QString itemName = m_driver->findOrInsertLayoutItem(node);
  
      QString addArgs;
      QString methodPrefix = QLatin1String("add"); //Consistent API-design galore!
      if (layout->attributeClass() == QLatin1String("QGridLayout")) {
          const int row = node->attributeRow();
          const int col = node->attributeColumn();
  
          const int rowSpan = node->hasAttributeRowSpan() ? node->attributeRowSpan() : 1;
          const int colSpan = node->hasAttributeColSpan() ? node->attributeColSpan() : 1;
  
          addArgs = QString::fromLatin1("%1, %2, %3, %4, %5").arg(itemName).arg(row).arg(col).arg(rowSpan).arg(colSpan);
          if (!node->attributeAlignment().isEmpty())
              addArgs += QLatin1String(", ") + node->attributeAlignment();
      } else {
          if (layout->attributeClass() == QLatin1String("QFormLayout")) {
              methodPrefix = QLatin1String("set");
              const int row = node->attributeRow();
              const int colSpan = node->hasAttributeColSpan() ? node->attributeColSpan() : 1;
              const QString role = formLayoutRole(node->attributeColumn(), colSpan);
              addArgs = QString::fromLatin1("%1, %2, %3").arg(row).arg(role, itemName);
          } else {
              addArgs = itemName;
              if (layout->attributeClass().contains(QLatin1String("Box")) && !node->attributeAlignment().isEmpty())
                  addArgs += QLatin1String(", 0, ") + node->attributeAlignment();
          }
      }
  
      // figure out "add" method
      m_output << "\n" << m_indent << layoutName << "->";
      switch (node->kind()) {
      case DomLayoutItem::Widget:
          m_output << methodPrefix << "Widget(" <<  addArgs;
          break;
      case DomLayoutItem::Layout:
          m_output <<  methodPrefix << "Layout(" << addArgs;
          break;
      case DomLayoutItem::Spacer:
          m_output << methodPrefix << "Item(" << addArgs;
          break;
      case DomLayoutItem::Unknown:
          Q_ASSERT( 0 );
          break;
      }
      m_output << ");\n\n";
  }
  
  void WriteInitialization::acceptActionGroup(DomActionGroup *node)
  {
      const QString actionName = m_driver->findOrInsertActionGroup(node);
      QString varName = m_driver->findOrInsertWidget(m_widgetChain.top());
  
      if (m_actionGroupChain.top())
          varName = m_driver->findOrInsertActionGroup(m_actionGroupChain.top());
  
      m_output << m_indent << actionName << " = new QActionGroup(" << varName << ");\n";
      writeProperties(actionName, QLatin1String("QActionGroup"), node->elementProperty());
  
      m_actionGroupChain.push(node);
      TreeWalker::acceptActionGroup(node);
      m_actionGroupChain.pop();
  }
  
  void WriteInitialization::acceptAction(DomAction *node)
  {
      if (node->hasAttributeMenu())
          return;
  
      const QString actionName = m_driver->findOrInsertAction(node);
      m_registeredActions.insert(actionName, node);
      QString varName = m_driver->findOrInsertWidget(m_widgetChain.top());
  
      if (m_actionGroupChain.top())
          varName = m_driver->findOrInsertActionGroup(m_actionGroupChain.top());
  
      m_output << m_indent << actionName << " = new QAction(" << varName << ");\n";
      writeProperties(actionName, QLatin1String("QAction"), node->elementProperty());
  }
  
  void WriteInitialization::acceptActionRef(DomActionRef *node)
  {
      QString actionName = node->attributeName();
      const bool isSeparator = actionName == QLatin1String("separator");
      bool isMenu = false;
  
      QString varName = m_driver->findOrInsertWidget(m_widgetChain.top());
  
      if (actionName.isEmpty() || !m_widgetChain.top()) {
          return;
      } else if (m_driver->actionGroupByName(actionName)) {
          return;
      } else if (const DomWidget *w = m_driver->widgetByName(actionName)) {
          isMenu = m_uic->isMenu(w->attributeClass());
      } else if (!(m_driver->actionByName(actionName) || isSeparator)) {
          fprintf(stderr, "%s: Warning: action `%s' not declared\n",
                  qPrintable(m_option.messagePrefix()),
                  actionName.toLatin1().data());
          return;
      }
  
      if (m_widgetChain.top() && isSeparator) {
          // separator is always reserved!
          m_actionOut << m_indent << varName << "->addSeparator();\n";
          return;
      }
  
      if (isMenu)
          actionName += QLatin1String("->menuAction()");
  
      m_actionOut << m_indent << varName << "->addAction(" << actionName << ");\n";
  }
  
  QString WriteInitialization::writeStringListProperty(const DomStringList *list) const
  {
      QString propertyValue;
      QTextStream str(&propertyValue);
      str << "QStringList()";
      const QStringList values = list->elementString();
      if (values.isEmpty())
          return propertyValue;
      if (needsTranslation(list)) {
          const QString comment = list->attributeComment();
          for (int i = 0; i < values.size(); ++i)
              str << '\n' << m_indent << "    << " << trCall(values.at(i), comment);
      } else {
          for (int i = 0; i < values.size(); ++i)
              str << " << " << writeString(values.at(i), m_dindent);
      }
      return propertyValue;
  }
  
  void WriteInitialization::writeProperties(const QString &varName,
                                            const QString &className,
                                            const DomPropertyList &lst,
                                            unsigned flags)
  {
      const bool isTopLevel = m_widgetChain.count() == 1;
  
      if (m_uic->customWidgetsInfo()->extends(className, QLatin1String("QAxWidget"))) {
          DomPropertyMap properties = propertyMap(lst);
          if (properties.contains(QLatin1String("control"))) {
              DomProperty *p = properties.value(QLatin1String("control"));
              Q_ASSERT( p );
              m_output << m_indent << varName << "->setControl("
                     << writeString(toString(p->elementString()), m_dindent) << ");\n";
          }
      }
  
      QString indent;
      if (!m_widgetChain.top()) {
          indent = m_option.indent;
          m_output << m_indent << "if (" << varName << "->objectName().isEmpty())\n";
      }
      if (!(flags & WritePropertyIgnoreObjectName))
          m_output << m_indent << indent << varName
                  << "->setObjectName(" << writeString(varName, m_dindent) << ");\n";
  
      int leftMargin, topMargin, rightMargin, bottomMargin;
      leftMargin = topMargin = rightMargin = bottomMargin = -1;
      bool frameShadowEncountered = false;
  
      for (int i=0; i<lst.size(); ++i) {
          const DomProperty *p = lst.at(i);
          if (!checkProperty(m_option.inputFile, p))
              continue;
          QString propertyName = p->attributeName();
          QString propertyValue;
          bool delayProperty = false;
  
          // special case for the property `geometry': Do not use position
          if (isTopLevel && propertyName == QLatin1String("geometry") && p->elementRect()) {
              const DomRect *r = p->elementRect();
              m_output << m_indent << varName << "->resize(" << r->elementWidth() << ", " << r->elementHeight() << ");\n";
              continue;
          } else if (propertyName == QLatin1String("currentRow") // QListWidget::currentRow
                      && m_uic->customWidgetsInfo()->extends(className, QLatin1String("QListWidget"))) {
              m_delayedOut << m_indent << varName << "->setCurrentRow("
                         << p->elementNumber() << ");\n";
              continue;
          } else if (propertyName == QLatin1String("currentIndex") // set currentIndex later
                      && (m_uic->customWidgetsInfo()->extends(className, QLatin1String("QComboBox"))
                      || m_uic->customWidgetsInfo()->extends(className, QLatin1String("QStackedWidget"))
                      || m_uic->customWidgetsInfo()->extends(className, QLatin1String("QTabWidget"))
                      || m_uic->customWidgetsInfo()->extends(className, QLatin1String("QToolBox")))) {
              m_delayedOut << m_indent << varName << "->setCurrentIndex("
                         << p->elementNumber() << ");\n";
              continue;
          } else if (propertyName == QLatin1String("tabSpacing")
                      && m_uic->customWidgetsInfo()->extends(className, QLatin1String("QToolBox"))) {
              m_delayedOut << m_indent << varName << "->layout()->setSpacing("
                         << p->elementNumber() << ");\n";
              continue;
          } else if (propertyName == QLatin1String("control") // ActiveQt support
                      && m_uic->customWidgetsInfo()->extends(className, QLatin1String("QAxWidget"))) {
              // already done ;)
              continue;
          } else if (propertyName == QLatin1String("default")
                     && m_uic->customWidgetsInfo()->extends(className, QLatin1String("QPushButton"))) {
              // QTBUG-44406: Setting of QPushButton::default needs to be delayed until the parent is set
              delayProperty = true;
          } else if (propertyName == QLatin1String("database")
                      && p->elementStringList()) {
              // Sql support
              continue;
          } else if (propertyName == QLatin1String("frameworkCode")
                      && p->kind() == DomProperty::Bool) {
              // Sql support
              continue;
          } else if (propertyName == QLatin1String("orientation")
                      && m_uic->customWidgetsInfo()->extends(className, QLatin1String("Line"))) {
              // Line support
              QString shape = QLatin1String("QFrame::HLine");
              if (p->elementEnum() == QLatin1String("Qt::Vertical"))
                  shape = QLatin1String("QFrame::VLine");
  
              m_output << m_indent << varName << "->setFrameShape(" << shape << ");\n";
              // QFrame Default is 'Plain'. Make the line 'Sunken' unless otherwise specified
              if (!frameShadowEncountered)
                  m_output << m_indent << varName << "->setFrameShadow(QFrame::Sunken);\n";
              continue;
          } else if ((flags & WritePropertyIgnoreMargin)  && propertyName == QLatin1String("margin")) {
              continue;
          } else if ((flags & WritePropertyIgnoreSpacing) && propertyName == QLatin1String("spacing")) {
              continue;
          } else if (propertyName == QLatin1String("leftMargin") && p->kind() == DomProperty::Number) {
              leftMargin = p->elementNumber();
              continue;
          } else if (propertyName == QLatin1String("topMargin") && p->kind() == DomProperty::Number) {
              topMargin = p->elementNumber();
              continue;
          } else if (propertyName == QLatin1String("rightMargin") && p->kind() == DomProperty::Number) {
              rightMargin = p->elementNumber();
              continue;
          } else if (propertyName == QLatin1String("bottomMargin") && p->kind() == DomProperty::Number) {
              bottomMargin = p->elementNumber();
              continue;
          } else if (propertyName == QLatin1String("numDigits") // Deprecated in Qt 4, removed in Qt 5.
                     && m_uic->customWidgetsInfo()->extends(className, QLatin1String("QLCDNumber"))) {
              qWarning("Widget '%s': Deprecated property QLCDNumber::numDigits encountered. It has been replaced by QLCDNumber::digitCount.",
                       qPrintable(varName));
              propertyName = QLatin1String("digitCount");
          } else if (propertyName == QLatin1String("frameShadow"))
              frameShadowEncountered = true;
  
          bool stdset = m_stdsetdef;
          if (p->hasAttributeStdset())
              stdset = p->attributeStdset();
  
          QString setFunction;
  
          if (stdset) {
              setFunction = QLatin1String("->set")
                          + propertyName.left(1).toUpper()
                          + propertyName.midRef(1)
                          + QLatin1Char('(');
          } else {
              setFunction += QLatin1String("->setProperty(\"")
                           + propertyName
                           + QLatin1String("\", QVariant");
              if (p->kind() == DomProperty::Enum)
                  setFunction += QLatin1String("::fromValue");
              setFunction += QLatin1Char('(');
          }
  
          QString varNewName = varName;
  
          switch (p->kind()) {
          case DomProperty::Bool: {
              propertyValue = p->elementBool();
              break;
          }
          case DomProperty::Color:
              propertyValue = domColor2QString(p->elementColor());
              break;
          case DomProperty::Cstring:
              if (propertyName == QLatin1String("buddy") && m_uic->customWidgetsInfo()->extends(className, QLatin1String("QLabel"))) {
                  Buddy buddy = { varName, p->elementCstring() };
                  m_buddies.append(std::move(buddy));
              } else {
                  if (stdset)
                      propertyValue = fixString(p->elementCstring(), m_dindent);
                  else {
                      propertyValue = QLatin1String("QByteArray(")
                                    + fixString(p->elementCstring(), m_dindent)
                                    + QLatin1Char(')');
                  }
              }
              break;
          case DomProperty::Cursor:
              propertyValue = QString::fromLatin1("QCursor(static_cast<Qt::CursorShape>(%1))")
                              .arg(p->elementCursor());
              break;
          case DomProperty::CursorShape:
              if (p->hasAttributeStdset() && !p->attributeStdset())
                  varNewName += QLatin1String("->viewport()");
              propertyValue = QString::fromLatin1("QCursor(Qt::%1)")
                              .arg(p->elementCursorShape());
              break;
          case DomProperty::Enum:
              propertyValue = p->elementEnum();
              if (!propertyValue.contains(QLatin1String("::")))
                  propertyValue = className + QLatin1String("::") + propertyValue;
              break;
          case DomProperty::Set:
              propertyValue = p->elementSet();
              break;
          case DomProperty::Font:
              propertyValue = writeFontProperties(p->elementFont());
              break;
          case DomProperty::IconSet:
              propertyValue = writeIconProperties(p->elementIconSet());
              break;
          case DomProperty::Pixmap:
              propertyValue = pixCall(p);
              break;
          case DomProperty::Palette: {
              const DomPalette *pal = p->elementPalette();
              const QString paletteName = m_driver->unique(QLatin1String("palette"));
              m_output << m_indent << "QPalette " << paletteName << ";\n";
  
              writeColorGroup(pal->elementActive(), QLatin1String("QPalette::Active"), paletteName);
              writeColorGroup(pal->elementInactive(), QLatin1String("QPalette::Inactive"), paletteName);
              writeColorGroup(pal->elementDisabled(), QLatin1String("QPalette::Disabled"), paletteName);
  
              propertyValue = paletteName;
              break;
          }
          case DomProperty::Point: {
              const DomPoint *po = p->elementPoint();
              propertyValue = QString::fromLatin1("QPoint(%1, %2)")
                              .arg(po->elementX()).arg(po->elementY());
              break;
          }
          case DomProperty::PointF: {
              const DomPointF *pof = p->elementPointF();
              propertyValue = QString::fromLatin1("QPointF(%1, %2)")
                              .arg(pof->elementX()).arg(pof->elementY());
              break;
          }
          case DomProperty::Rect: {
              const DomRect *r = p->elementRect();
              propertyValue = QString::fromLatin1("QRect(%1, %2, %3, %4)")
                              .arg(r->elementX()).arg(r->elementY())
                              .arg(r->elementWidth()).arg(r->elementHeight());
              break;
          }
          case DomProperty::RectF: {
              const DomRectF *rf = p->elementRectF();
              propertyValue = QString::fromLatin1("QRectF(%1, %2, %3, %4)")
                              .arg(rf->elementX()).arg(rf->elementY())
                              .arg(rf->elementWidth()).arg(rf->elementHeight());
              break;
          }
          case DomProperty::Locale: {
               const DomLocale *locale = p->elementLocale();
               propertyValue = QString::fromLatin1("QLocale(QLocale::%1, QLocale::%2)")
                               .arg(locale->attributeLanguage(), locale->attributeCountry());
              break;
          }
          case DomProperty::SizePolicy: {
              const QString spName = writeSizePolicy( p->elementSizePolicy());
              m_output << m_indent << spName << QString::fromLatin1(
                  ".setHeightForWidth(%1->sizePolicy().hasHeightForWidth());\n")
                  .arg(varName);
  
              propertyValue = spName;
              break;
          }
          case DomProperty::Size: {
               const DomSize *s = p->elementSize();
                propertyValue = QString::fromLatin1("QSize(%1, %2)")
                               .arg(s->elementWidth()).arg(s->elementHeight());
              break;
          }
          case DomProperty::SizeF: {
              const DomSizeF *sf = p->elementSizeF();
               propertyValue = QString::fromLatin1("QSizeF(%1, %2)")
                              .arg(sf->elementWidth()).arg(sf->elementHeight());
              break;
          }
          case DomProperty::String: {
              if (propertyName == QLatin1String("objectName")) {
                  const QString v = p->elementString()->text();
                  if (v == varName)
                      break;
  
                  // ### qWarning("Deprecated: the property `objectName' is different from the variable name");
              }
  
              propertyValue = autoTrCall(p->elementString());
              break;
          }
          case DomProperty::Number:
              propertyValue = QString::number(p->elementNumber());
              break;
          case DomProperty::UInt:
              propertyValue = QString::number(p->elementUInt());
              propertyValue += QLatin1Char('u');
              break;
          case DomProperty::LongLong:
              propertyValue = QLatin1String("Q_INT64_C(");
              propertyValue += QString::number(p->elementLongLong());
              propertyValue += QLatin1Char(')');;
              break;
          case DomProperty::ULongLong:
              propertyValue = QLatin1String("Q_UINT64_C(");
              propertyValue += QString::number(p->elementULongLong());
              propertyValue += QLatin1Char(')');
              break;
          case DomProperty::Float:
              propertyValue = QString::number(p->elementFloat());
              break;
          case DomProperty::Double:
              propertyValue = QString::number(p->elementDouble());
              break;
          case DomProperty::Char: {
              const DomChar *c = p->elementChar();
              propertyValue = QString::fromLatin1("QChar(%1)")
                              .arg(c->elementUnicode());
              break;
          }
          case DomProperty::Date: {
              const DomDate *d = p->elementDate();
              propertyValue = QString::fromLatin1("QDate(%1, %2, %3)")
                              .arg(d->elementYear())
                              .arg(d->elementMonth())
                              .arg(d->elementDay());
              break;
          }
          case DomProperty::Time: {
              const DomTime *t = p->elementTime();
              propertyValue = QString::fromLatin1("QTime(%1, %2, %3)")
                              .arg(t->elementHour())
                              .arg(t->elementMinute())
                              .arg(t->elementSecond());
              break;
          }
          case DomProperty::DateTime: {
              const DomDateTime *dt = p->elementDateTime();
              propertyValue = QString::fromLatin1("QDateTime(QDate(%1, %2, %3), QTime(%4, %5, %6))")
                              .arg(dt->elementYear())
                              .arg(dt->elementMonth())
                              .arg(dt->elementDay())
                              .arg(dt->elementHour())
                              .arg(dt->elementMinute())
                              .arg(dt->elementSecond());
              break;
          }
          case DomProperty::StringList:
              propertyValue = writeStringListProperty(p->elementStringList());
              break;
  
          case DomProperty::Url: {
              const DomUrl* u = p->elementUrl();
              propertyValue = QString::fromLatin1("QUrl(%1)")
                              .arg(writeString(u->elementString()->text(), m_dindent));
              break;
          }
          case DomProperty::Brush:
              propertyValue = writeBrushInitialization(p->elementBrush());
              break;
          case DomProperty::Unknown:
              break;
          }
  
          if (propertyValue.size()) {
              const char* defineC = 0;
              if (propertyName == QLatin1String("toolTip"))
                  defineC = toolTipDefineC;
              else if (propertyName == QLatin1String("whatsThis"))
                  defineC = whatsThisDefineC;
              else if (propertyName == QLatin1String("statusTip"))
                  defineC = statusTipDefineC;
              else if (propertyName == QLatin1String("shortcut"))
                  defineC = shortcutDefineC;
              else if (propertyName == QLatin1String("accessibleName") || propertyName == QLatin1String("accessibleDescription"))
                  defineC = accessibilityDefineC;
  
              QTextStream &o = delayProperty ? m_delayedOut : autoTrOutput(p);
  
              if (defineC)
                  openIfndef(o, QLatin1String(defineC));
              o << m_indent << varNewName << setFunction << propertyValue;
              if (!stdset)
                  o << ')';
              o << ");\n";
              if (defineC)
                  closeIfndef(o, QLatin1String(defineC));
  
              if (varName == m_mainFormVarName && &o == &m_refreshOut) {
                  // this is the only place (currently) where we output mainForm name to the retranslateUi().
                  // Other places output merely instances of a certain class (which cannot be main form, e.g. QListWidget).
                  m_mainFormUsedInRetranslateUi = true;
              }
          }
      }
      if (leftMargin != -1 || topMargin != -1 || rightMargin != -1 || bottomMargin != -1) {
          m_output << m_indent << varName << QLatin1String("->setContentsMargins(")
                   << leftMargin << QLatin1String(", ")
                   << topMargin << QLatin1String(", ")
                   << rightMargin << QLatin1String(", ")
                   << bottomMargin << QLatin1String(");\n");
      }
  }
  
  QString  WriteInitialization::writeSizePolicy(const DomSizePolicy *sp)
  {
  
      // check cache
      const SizePolicyHandle sizePolicyHandle(sp);
      const SizePolicyNameMap::const_iterator it = m_sizePolicyNameMap.constFind(sizePolicyHandle);
      if ( it != m_sizePolicyNameMap.constEnd()) {
          return it.value();
      }
  
  
      // insert with new name
      const QString spName = m_driver->unique(QLatin1String("sizePolicy"));
      m_sizePolicyNameMap.insert(sizePolicyHandle, spName);
  
      m_output << m_indent << "QSizePolicy " << spName;
      do {
          if (sp->hasElementHSizeType() && sp->hasElementVSizeType()) {
              m_output << "(static_cast<QSizePolicy::Policy>(" << sp->elementHSizeType()
                  << "), static_cast<QSizePolicy::Policy>(" << sp->elementVSizeType() << "));\n";
              break;
          }
          if (sp->hasAttributeHSizeType() && sp->hasAttributeVSizeType()) {
                  m_output << "(QSizePolicy::" << sp->attributeHSizeType() << ", QSizePolicy::"
                  << sp->attributeVSizeType() << ");\n";
              break;
          }
          m_output << ";\n";
      } while (false);
  
      m_output << m_indent << spName << ".setHorizontalStretch("
          << sp->elementHorStretch() << ");\n";
      m_output << m_indent << spName << ".setVerticalStretch("
          << sp->elementVerStretch() << ");\n";
      return spName;
  }
  // Check for a font with the given properties in the FontPropertiesNameMap
  // or create a new one. Returns the name.
  
  QString WriteInitialization::writeFontProperties(const DomFont *f)
  {
      // check cache
      const FontHandle fontHandle(f);
      const FontPropertiesNameMap::const_iterator it = m_fontPropertiesNameMap.constFind(fontHandle);
      if ( it != m_fontPropertiesNameMap.constEnd()) {
          return it.value();
      }
  
      // insert with new name
      const QString fontName = m_driver->unique(QLatin1String("font"));
      m_fontPropertiesNameMap.insert(FontHandle(f), fontName);
  
      m_output << m_indent << "QFont " << fontName << ";\n";
      if (f->hasElementFamily() && !f->elementFamily().isEmpty()) {
          m_output << m_indent << fontName << ".setFamily(" << writeString(f->elementFamily(), m_dindent)
              << ");\n";
      }
      if (f->hasElementPointSize() && f->elementPointSize() > 0) {
           m_output << m_indent << fontName << ".setPointSize(" << f->elementPointSize()
               << ");\n";
      }
  
      if (f->hasElementBold()) {
          m_output << m_indent << fontName << ".setBold("
              << (f->elementBold() ? "true" : "false") << ");\n";
      }
      if (f->hasElementItalic()) {
          m_output << m_indent << fontName << ".setItalic("
              <<  (f->elementItalic() ? "true" : "false") << ");\n";
      }
      if (f->hasElementUnderline()) {
          m_output << m_indent << fontName << ".setUnderline("
              << (f->elementUnderline() ? "true" : "false") << ");\n";
      }
      if (f->hasElementWeight() && f->elementWeight() > 0) {
          m_output << m_indent << fontName << ".setWeight("
              << f->elementWeight() << ");" << endl;
      }
      if (f->hasElementStrikeOut()) {
           m_output << m_indent << fontName << ".setStrikeOut("
              << (f->elementStrikeOut() ? "true" : "false") << ");\n";
      }
      if (f->hasElementKerning()) {
          m_output << m_indent << fontName << ".setKerning("
              << (f->elementKerning() ? "true" : "false") << ");\n";
      }
      if (f->hasElementAntialiasing()) {
          m_output << m_indent << fontName << ".setStyleStrategy("
              << (f->elementAntialiasing() ? "QFont::PreferDefault" : "QFont::NoAntialias") << ");\n";
      }
      if (f->hasElementStyleStrategy()) {
           m_output << m_indent << fontName << ".setStyleStrategy(QFont::"
              << f->elementStyleStrategy() << ");\n";
      }
      return  fontName;
  }
  
  // Post 4.4 write resource icon
  static void writeResourceIcon(QTextStream &output,
                                const QString &iconName,
                                const QString &indent,
                                const DomResourceIcon *i)
  {
      if (i->hasElementNormalOff())
          output << indent << iconName << ".addFile(" << writeString(i->elementNormalOff()->text(), indent) << ", QSize(), QIcon::Normal, QIcon::Off);\n";
      if (i->hasElementNormalOn())
          output << indent << iconName << ".addFile(" << writeString(i->elementNormalOn()->text(), indent) << ", QSize(), QIcon::Normal, QIcon::On);\n";
      if (i->hasElementDisabledOff())
          output << indent << iconName << ".addFile(" << writeString(i->elementDisabledOff()->text(), indent) << ", QSize(), QIcon::Disabled, QIcon::Off);\n";
      if (i->hasElementDisabledOn())
          output << indent << iconName << ".addFile(" << writeString(i->elementDisabledOn()->text(), indent) << ", QSize(), QIcon::Disabled, QIcon::On);\n";
      if (i->hasElementActiveOff())
          output << indent << iconName << ".addFile(" << writeString(i->elementActiveOff()->text(), indent) << ", QSize(), QIcon::Active, QIcon::Off);\n";
      if (i->hasElementActiveOn())
          output << indent << iconName << ".addFile(" << writeString(i->elementActiveOn()->text(), indent) << ", QSize(), QIcon::Active, QIcon::On);\n";
      if (i->hasElementSelectedOff())
          output << indent << iconName << ".addFile(" << writeString(i->elementSelectedOff()->text(), indent) << ", QSize(), QIcon::Selected, QIcon::Off);\n";
      if (i->hasElementSelectedOn())
          output << indent << iconName << ".addFile(" << writeString(i->elementSelectedOn()->text(), indent) << ", QSize(), QIcon::Selected, QIcon::On);\n";
  }
  
  QString WriteInitialization::writeIconProperties(const DomResourceIcon *i)
  {
      // check cache
      const IconHandle iconHandle(i);
      const IconPropertiesNameMap::const_iterator it = m_iconPropertiesNameMap.constFind(iconHandle);
      if (it != m_iconPropertiesNameMap.constEnd()) {
          return it.value();
      }
  
      // insert with new name
      const QString iconName = m_driver->unique(QLatin1String("icon"));
      m_iconPropertiesNameMap.insert(IconHandle(i), iconName);
      if (isIconFormat44(i)) {
          if (i->attributeTheme().isEmpty()) {
              // No theme: Write resource icon as is
              m_output << m_indent << "QIcon " << iconName << ";\n";
              writeResourceIcon(m_output, iconName, m_indent, i);
          } else {
              // Theme: Generate code to check the theme and default to resource
              const QString themeIconName = writeString(i->attributeTheme(), QString());
              if (iconHasStatePixmaps(i)) {
                  // Theme + default state pixmaps:
                  // Generate code to check the theme and default to state pixmaps
                  m_output << m_indent << "QIcon " << iconName << ";\n";
                  const char themeNameStringVariableC[] = "iconThemeName";
                  // Store theme name in a variable
                  m_output << m_indent;
                  if (m_firstThemeIcon) { // Declare variable string
                      m_output << "QString ";
                      m_firstThemeIcon = false;
                  }
                  m_output << themeNameStringVariableC << " = "
                           << themeIconName << ";\n";
                  m_output << m_indent << "if (QIcon::hasThemeIcon("
                           << themeNameStringVariableC
                           << ")) {\n"
                           << m_dindent << iconName << " = QIcon::fromTheme(" << themeNameStringVariableC << ");\n"
                           << m_indent << "} else {\n";
                  writeResourceIcon(m_output, iconName, m_dindent, i);
                  m_output << m_indent << "}\n";
              } else {
                  // Theme, but no state pixmaps: Construct from theme directly.
                  m_output << m_indent << "QIcon " << iconName
                           << "(QIcon::fromTheme("
                           << themeIconName << "));\n";
              } // Theme, but not state
          }     // >= 4.4
      } else {  // pre-4.4 legacy
          m_output <<  m_indent << "const QIcon " << iconName << " = " << pixCall(QLatin1String("QIcon"), i->text())<< ";\n";
      }
      return iconName;
  }
  
  QString WriteInitialization::domColor2QString(const DomColor *c)
  {
      if (c->hasAttributeAlpha())
          return QString::fromLatin1("QColor(%1, %2, %3, %4)")
              .arg(c->elementRed())
              .arg(c->elementGreen())
              .arg(c->elementBlue())
              .arg(c->attributeAlpha());
      return QString::fromLatin1("QColor(%1, %2, %3)")
          .arg(c->elementRed())
          .arg(c->elementGreen())
          .arg(c->elementBlue());
  }
  
  void WriteInitialization::writeColorGroup(DomColorGroup *colorGroup, const QString &group, const QString &paletteName)
  {
      if (!colorGroup)
          return;
  
      // old format
      const QList<DomColor*> colors = colorGroup->elementColor();
      for (int i=0; i<colors.size(); ++i) {
          const DomColor *color = colors.at(i);
  
          m_output << m_indent << paletteName << ".setColor(" << group
              << ", " << "static_cast<QPalette::ColorRole>(" << QString::number(i) << ')'
              << ", " << domColor2QString(color)
              << ");\n";
      }
  
      // new format
      const QList<DomColorRole *> colorRoles = colorGroup->elementColorRole();
      for (const DomColorRole *colorRole : colorRoles) {
          if (colorRole->hasAttributeRole()) {
              const QString brushName = writeBrushInitialization(colorRole->elementBrush());
              m_output << m_indent << paletteName << ".setBrush(" << group
                  << ", " << "QPalette::" << colorRole->attributeRole()
                  << ", " << brushName << ");\n";
          }
      }
  }
  
  // Write initialization for brush unless it is found in the cache. Returns the name to use
  // in an expression.
  QString WriteInitialization::writeBrushInitialization(const DomBrush *brush)
  {
      // Simple solid, colored  brushes are cached
      const bool solidColoredBrush = !brush->hasAttributeBrushStyle() || brush->attributeBrushStyle() == QLatin1String("SolidPattern");
      uint rgb = 0;
      if (solidColoredBrush) {
          if (const DomColor *color = brush->elementColor()) {
              rgb = ((color->elementRed() & 0xFF) << 24) |
                    ((color->elementGreen() & 0xFF) << 16) |
                    ((color->elementBlue() & 0xFF) << 8) |
                    ((color->attributeAlpha() & 0xFF));
              const ColorBrushHash::const_iterator cit = m_colorBrushHash.constFind(rgb);
              if (cit != m_colorBrushHash.constEnd())
                  return cit.value();
          }
      }
      // Create and enter into cache if simple
      const QString brushName = m_driver->unique(QLatin1String("brush"));
      writeBrush(brush, brushName);
      if (solidColoredBrush)
          m_colorBrushHash.insert(rgb, brushName);
      return brushName;
  }
  
  void WriteInitialization::writeBrush(const DomBrush *brush, const QString &brushName)
  {
      QString style = QLatin1String("SolidPattern");
      if (brush->hasAttributeBrushStyle())
          style = brush->attributeBrushStyle();
  
      if (style == QLatin1String("LinearGradientPattern") ||
              style == QLatin1String("RadialGradientPattern") ||
              style == QLatin1String("ConicalGradientPattern")) {
          const DomGradient *gradient = brush->elementGradient();
          const QString gradientType = gradient->attributeType();
          const QString gradientName = m_driver->unique(QLatin1String("gradient"));
          if (gradientType == QLatin1String("LinearGradient")) {
              m_output << m_indent << "QLinearGradient " << gradientName
                  << '(' << gradient->attributeStartX()
                  << ", " << gradient->attributeStartY()
                  << ", " << gradient->attributeEndX()
                  << ", " << gradient->attributeEndY() << ");\n";
          } else if (gradientType == QLatin1String("RadialGradient")) {
              m_output << m_indent << "QRadialGradient " << gradientName
                  << '(' << gradient->attributeCentralX()
                  << ", " << gradient->attributeCentralY()
                  << ", " << gradient->attributeRadius()
                  << ", " << gradient->attributeFocalX()
                  << ", " << gradient->attributeFocalY() << ");\n";
          } else if (gradientType == QLatin1String("ConicalGradient")) {
              m_output << m_indent << "QConicalGradient " << gradientName
                  << '(' << gradient->attributeCentralX()
                  << ", " << gradient->attributeCentralY()
                  << ", " << gradient->attributeAngle() << ");\n";
          }
  
          m_output << m_indent << gradientName << ".setSpread(QGradient::"
              << gradient->attributeSpread() << ");\n";
  
          if (gradient->hasAttributeCoordinateMode()) {
              m_output << m_indent << gradientName << ".setCoordinateMode(QGradient::"
                  << gradient->attributeCoordinateMode() << ");\n";
          }
  
         const  QList<DomGradientStop *> stops = gradient->elementGradientStop();
          for (const DomGradientStop *stop : stops) {
              const DomColor *color = stop->elementColor();
              m_output << m_indent << gradientName << ".setColorAt("
                  << stop->attributePosition() << ", "
                  << domColor2QString(color) << ");\n";
          }
          m_output << m_indent << "QBrush " << brushName << '('
              << gradientName << ");\n";
      } else if (style == QLatin1String("TexturePattern")) {
          const DomProperty *property = brush->elementTexture();
          const QString iconValue = iconCall(property);
  
          m_output << m_indent << "QBrush " << brushName << " = QBrush("
              << iconValue << ");\n";
      } else {
          const DomColor *color = brush->elementColor();
          m_output << m_indent << "QBrush " << brushName << '('
              << domColor2QString(color) << ");\n";
  
          m_output << m_indent << brushName << ".setStyle("
              << "Qt::" << style << ");\n";
      }
  }
  
  void WriteInitialization::acceptCustomWidget(DomCustomWidget *node)
  {
      Q_UNUSED(node);
  }
  
  void WriteInitialization::acceptCustomWidgets(DomCustomWidgets *node)
  {
      Q_UNUSED(node);
  }
  
  void WriteInitialization::acceptTabStops(DomTabStops *tabStops)
  {
      QString lastName;
  
      const QStringList l = tabStops->elementTabStop();
      for (int i=0; i<l.size(); ++i) {
          const QString name = l.at(i);
  
          if (!m_registeredWidgets.contains(name)) {
              fprintf(stderr, "%s: Warning: Tab-stop assignment: '%s' is not a valid widget.\n",
                      qPrintable(m_option.messagePrefix()),
                      name.toLatin1().data());
              continue;
          }
  
          if (i == 0) {
              lastName = name;
              continue;
          } else if (name.isEmpty() || lastName.isEmpty()) {
              continue;
          }
  
          m_output << m_indent << "QWidget::setTabOrder(" << lastName << ", " << name << ");\n";
  
          lastName = name;
      }
  }
  
  QString WriteInitialization::iconCall(const DomProperty *icon)
  {
      if (icon->kind() == DomProperty::IconSet)
          return writeIconProperties(icon->elementIconSet());
      return pixCall(icon);
  }
  
  QString WriteInitialization::pixCall(const DomProperty *p) const
  {
      QString type, s;
      switch (p->kind()) {
      case DomProperty::IconSet:
          type = QLatin1String("QIcon");
          s = p->elementIconSet()->text();
          break;
      case DomProperty::Pixmap:
          type = QLatin1String("QPixmap");
          s = p->elementPixmap()->text();
          break;
      default:
          qWarning("%s: Warning: Unknown icon format encountered. The ui-file was generated with a too-recent version of Designer.",
                   qPrintable(m_option.messagePrefix()));
          return QLatin1String("QIcon()");
          break;
      }
      return pixCall(type, s);
  }
  
  QString WriteInitialization::pixCall(const QString &t, const QString &text) const
  {
      QString type = t;
      if (text.isEmpty()) {
          type += QLatin1String("()");
          return type;
      }
      if (const DomImage *image = findImage(text)) {
          if (m_option.extractImages) {
              const QString format = image->elementData()->attributeFormat();
              const QString extension = format.left(format.indexOf(QLatin1Char('.'))).toLower();
              return QLatin1String("QPixmap(QString::fromUtf8(\":/")
                   + m_generatedClass
                   + QLatin1String("/images/")
                   + text
                   + QLatin1Char('.')
                   + extension
                   + QLatin1String("\"))");
          }
          return WriteIconInitialization::iconFromDataFunction()
               + QLatin1Char('(')
               + text
               + QLatin1String("_ID)");
      }
  
      QString pixFunc = m_uic->pixmapFunction();
      if (pixFunc.isEmpty())
          pixFunc = QLatin1String("QString::fromUtf8");
  
      type += QLatin1Char('(')
            + pixFunc
            + QLatin1Char('(')
            + fixString(text, m_dindent)
            + QLatin1String("))");
      return type;
  }
  
  void WriteInitialization::initializeComboBox(DomWidget *w)
  {
      const QString varName = m_driver->findOrInsertWidget(w);
      const QString className = w->attributeClass();
  
      const QList<DomItem*> items = w->elementItem();
  
      if (items.isEmpty())
          return;
  
      // If possible use qcombobox's addItems() which is much faster then a bunch of addItem() calls
      bool makeStringListCall = true;
      bool translatable = false;
      QStringList list;
      for (int i=0; i<items.size(); ++i) {
          const DomItem *item = items.at(i);
          const DomPropertyMap properties = propertyMap(item->elementProperty());
          const DomProperty *text = properties.value(QLatin1String("text"));
          const DomProperty *pixmap = properties.value(QLatin1String("icon"));
          bool needsTr = needsTranslation(text->elementString());
          if (pixmap != 0 || (i > 0 && translatable != needsTr)) {
              makeStringListCall = false;
              break;
          }
          translatable = needsTr;
          list.append(autoTrCall(text->elementString()));  // fix me here
      }
  
      if (makeStringListCall) {
          QTextStream &o = translatable ? m_refreshOut : m_output;
          if (translatable)
              o << m_indent << varName << "->clear();\n";
          o << m_indent << varName << "->insertItems(0, QStringList()" << '\n';
          for (int i = 0; i < list.size(); ++i)
              o << m_indent << " << " << list.at(i) << "\n";
          o << m_indent << ");\n";
      } else {
          for (int i = 0; i < items.size(); ++i) {
              const DomItem *item = items.at(i);
              const DomPropertyMap properties = propertyMap(item->elementProperty());
              const DomProperty *text = properties.value(QLatin1String("text"));
              const DomProperty *icon = properties.value(QLatin1String("icon"));
  
              QString iconValue;
              if (icon)
                  iconValue = iconCall(icon);
  
              m_output << m_indent << varName << "->addItem(";
              if (icon)
                  m_output << iconValue << ", ";
  
              if (needsTranslation(text->elementString())) {
                  m_output << "QString());\n";
                  m_refreshOut << m_indent << varName << "->setItemText(" << i << ", " << trCall(text->elementString()) << ");\n";
              } else {
                  m_output << noTrCall(text->elementString()) << ");\n";
              }
          }
          m_refreshOut << "\n";
      }
  }
  
  QString WriteInitialization::disableSorting(DomWidget *w, const QString &varName)
  {
      // turn off sortingEnabled to force programmatic item order (setItem())
      QString tempName;
      if (!w->elementItem().isEmpty()) {
          tempName = m_driver->unique(QLatin1String("__sortingEnabled"));
          m_refreshOut << "\n";
          m_refreshOut << m_indent << "const bool " << tempName
              << " = " << varName << "->isSortingEnabled();\n";
          m_refreshOut << m_indent << varName << "->setSortingEnabled(false);\n";
      }
      return tempName;
  }
  
  void WriteInitialization::enableSorting(DomWidget *w, const QString &varName, const QString &tempName)
  {
      if (!w->elementItem().isEmpty()) {
          m_refreshOut << m_indent << varName << "->setSortingEnabled(" << tempName << ");\n\n";
      }
  }
  
  /*
   * Initializers are just strings containing the function call and need to be prepended
   * the line indentation and the object they are supposed to initialize.
   * String initializers come with a preprocessor conditional (ifdef), so the code
   * compiles with QT_NO_xxx. A null pointer means no conditional. String initializers
   * are written to the retranslateUi() function, others to setupUi().
   */
  
  
  /*!
      Create non-string inititializer.
      \param value the value to initialize the attribute with. May be empty, in which case
          the initializer is omitted.
      See above for other parameters.
  */
  void WriteInitialization::addInitializer(Item *item,
          const QString &name, int column, const QString &value, const QString &directive, bool translatable) const
  {
      if (!value.isEmpty())
          item->addSetter(QLatin1String("->set") + name.at(0).toUpper() + name.midRef(1) +
                      QLatin1Char('(') + (column < 0 ? QString() : QString::number(column) +
                      QLatin1String(", ")) + value + QLatin1String(");"), directive, translatable);
  }
  
  /*!
      Create string inititializer.
      \param initializers in/out list of inializers
      \param properties map property name -> property to extract data from
      \param name the property to extract
      \param col the item column to generate the initializer for. This is relevant for
          tree widgets only. If it is -1, no column index will be generated.
      \param ifdef preprocessor symbol for disabling compilation of this initializer
  */
  void WriteInitialization::addStringInitializer(Item *item,
          const DomPropertyMap &properties, const QString &name, int column, const QString &directive) const
  {
      if (const DomProperty *p = properties.value(name)) {
          DomString *str = p->elementString();
          QString text = toString(str);
          if (!text.isEmpty()) {
              bool translatable = needsTranslation(str);
              QString value = autoTrCall(str);
              addInitializer(item, name, column, value, directive, translatable);
          }
      }
  }
  
  void WriteInitialization::addBrushInitializer(Item *item,
          const DomPropertyMap &properties, const QString &name, int column)
  {
      if (const DomProperty *p = properties.value(name)) {
          if (p->elementBrush())
              addInitializer(item, name, column, writeBrushInitialization(p->elementBrush()));
          else if (p->elementColor())
              addInitializer(item, name, column, domColor2QString(p->elementColor()));
      }
  }
  
  /*!
      Create inititializer for a flag value in the Qt namespace.
      If the named property is not in the map, the initializer is omitted.
  */
  void WriteInitialization::addQtFlagsInitializer(Item *item,
          const DomPropertyMap &properties, const QString &name, int column) const
  {
      if (const DomProperty *p = properties.value(name)) {
          QString v = p->elementSet();
          if (!v.isEmpty()) {
              v.replace(QLatin1Char('|'), QLatin1String("|Qt::"));
              addInitializer(item, name, column, QLatin1String("Qt::") + v);
          }
      }
  }
  
  /*!
      Create inititializer for an enum value in the Qt namespace.
      If the named property is not in the map, the initializer is omitted.
  */
  void WriteInitialization::addQtEnumInitializer(Item *item,
          const DomPropertyMap &properties, const QString &name, int column) const
  {
      if (const DomProperty *p = properties.value(name)) {
          QString v = p->elementEnum();
          if (!v.isEmpty())
              addInitializer(item, name, column, QLatin1String("Qt::") + v);
      }
  }
  
  /*!
      Create inititializers for all common properties that may be bound to a column.
  */
  void WriteInitialization::addCommonInitializers(Item *item,
          const DomPropertyMap &properties, int column)
  {
      if (const DomProperty *icon = properties.value(QLatin1String("icon")))
          addInitializer(item, QLatin1String("icon"), column, iconCall(icon));
      addBrushInitializer(item, properties, QLatin1String("foreground"), column);
      addBrushInitializer(item, properties, QLatin1String("background"), column);
      if (const DomProperty *font = properties.value(QLatin1String("font")))
          addInitializer(item, QLatin1String("font"), column, writeFontProperties(font->elementFont()));
      addQtFlagsInitializer(item, properties, QLatin1String("textAlignment"), column);
      addQtEnumInitializer(item, properties, QLatin1String("checkState"), column);
      addStringInitializer(item, properties, QLatin1String("text"), column);
      addStringInitializer(item, properties, QLatin1String("toolTip"), column, QLatin1String(toolTipDefineC));
      addStringInitializer(item, properties, QLatin1String("whatsThis"), column, QLatin1String(whatsThisDefineC));
      addStringInitializer(item, properties, QLatin1String("statusTip"), column, QLatin1String(statusTipDefineC));
  }
  
  void WriteInitialization::initializeListWidget(DomWidget *w)
  {
      const QString varName = m_driver->findOrInsertWidget(w);
      const QString className = w->attributeClass();
  
      const QList<DomItem*> items = w->elementItem();
  
      if (items.isEmpty())
          return;
  
      QString tempName = disableSorting(w, varName);
      // items
      // TODO: the generated code should be data-driven to reduce its size
      for (int i = 0; i < items.size(); ++i) {
          const DomItem *domItem = items.at(i);
  
          const DomPropertyMap properties = propertyMap(domItem->elementProperty());
  
          Item item(QLatin1String("QListWidgetItem"), m_indent, m_output, m_refreshOut, m_driver);
          addQtFlagsInitializer(&item, properties, QLatin1String("flags"));
          addCommonInitializers(&item, properties);
  
          item.writeSetupUi(varName);
          item.writeRetranslateUi(varName + QLatin1String("->item(") + QString::number(i) + QLatin1Char(')'));
      }
      enableSorting(w, varName, tempName);
  }
  
  void WriteInitialization::initializeTreeWidget(DomWidget *w)
  {
      const QString varName = m_driver->findOrInsertWidget(w);
  
      // columns
      Item item(QLatin1String("QTreeWidgetItem"), m_indent, m_output, m_refreshOut, m_driver);
  
      const QList<DomColumn*> columns = w->elementColumn();
      for (int i = 0; i < columns.size(); ++i) {
          const DomColumn *column = columns.at(i);
  
          const DomPropertyMap properties = propertyMap(column->elementProperty());
          addCommonInitializers(&item, properties, i);
  
          if (const DomProperty *p = properties.value(QLatin1String("text"))) {
              DomString *str = p->elementString();
              if (str && str->text().isEmpty())
                  m_output << m_indent << varName << "->headerItem()->setText(" << i << ", QString());\n";
          }
      }
      const QString itemName = item.writeSetupUi(QString(), Item::DontConstruct);
      item.writeRetranslateUi(varName + QLatin1String("->headerItem()"));
      if (!itemName.isNull())
          m_output << m_indent << varName << "->setHeaderItem(" << itemName << ");\n";
  
      if (w->elementItem().size() == 0)
          return;
  
      QString tempName = disableSorting(w, varName);
  
      QList<Item *> items = initializeTreeWidgetItems(w->elementItem());
      for (int i = 0; i < items.count(); i++) {
          Item *itm = items[i];
          itm->writeSetupUi(varName);
          itm->writeRetranslateUi(varName + QLatin1String("->topLevelItem(") + QString::number(i) + QLatin1Char(')'));
          delete itm;
      }
  
      enableSorting(w, varName, tempName);
  }
  
  /*!
      Create and write out initializers for tree widget items.
      This function makes sure that only needed items are fetched (subject to preprocessor
      conditionals), that each item is fetched from its parent widget/item exactly once
      and that no temporary variables are created for items that are needed only once. As
      fetches are built top-down from the root, but determining how often and under which
      conditions an item is needed needs to be done bottom-up, the whole process makes
      two passes, storing the intermediate result in a recursive StringInitializerListMap.
  */
  QList<WriteInitialization::Item *> WriteInitialization::initializeTreeWidgetItems(const QList<DomItem *> &domItems)
  {
      // items
      QList<Item *> items;
      const int numDomItems = domItems.size();
      items.reserve(numDomItems);
  
      for (int i = 0; i < numDomItems; ++i) {
          const DomItem *domItem = domItems.at(i);
  
          Item *item = new Item(QLatin1String("QTreeWidgetItem"), m_indent, m_output, m_refreshOut, m_driver);
          items << item;
  
          QHash<QString, DomProperty *> map;
  
          int col = -1;
          const DomPropertyList properties = domItem->elementProperty();
          for (int j = 0; j < properties.size(); ++j) {
              DomProperty *p = properties.at(j);
              if (p->attributeName() == QLatin1String("text")) {
                  if (!map.isEmpty()) {
                      addCommonInitializers(item, map, col);
                      map.clear();
                  }
                  col++;
              }
              map.insert(p->attributeName(), p);
          }
          addCommonInitializers(item, map, col);
          // AbstractFromBuilder saves flags last, so they always end up in the last column's map.
          addQtFlagsInitializer(item, map, QLatin1String("flags"));
  
          const QList<Item *> subItems = initializeTreeWidgetItems(domItem->elementItem());
          for (Item *subItem : subItems)
              item->addChild(subItem);
      }
      return items;
  }
  
  void WriteInitialization::initializeTableWidget(DomWidget *w)
  {
      const QString varName = m_driver->findOrInsertWidget(w);
  
      // columns
      const QList<DomColumn *> columns = w->elementColumn();
  
      if (columns.size() != 0) {
          m_output << m_indent << "if (" << varName << "->columnCount() < " << columns.size() << ")\n"
              << m_dindent << varName << "->setColumnCount(" << columns.size() << ");\n";
      }
  
      for (int i = 0; i < columns.size(); ++i) {
          const DomColumn *column = columns.at(i);
          if (!column->elementProperty().isEmpty()) {
              const DomPropertyMap properties = propertyMap(column->elementProperty());
  
              Item item(QLatin1String("QTableWidgetItem"), m_indent, m_output, m_refreshOut, m_driver);
              addCommonInitializers(&item, properties);
  
              QString itemName = item.writeSetupUi(QString(), Item::ConstructItemAndVariable);
              item.writeRetranslateUi(varName + QLatin1String("->horizontalHeaderItem(") + QString::number(i) + QLatin1Char(')'));
              m_output << m_indent << varName << "->setHorizontalHeaderItem(" << QString::number(i) << ", " << itemName << ");\n";
          }
      }
  
      // rows
      const QList<DomRow *> rows = w->elementRow();
  
      if (rows.size() != 0) {
          m_output << m_indent << "if (" << varName << "->rowCount() < " << rows.size() << ")\n"
              << m_dindent << varName << "->setRowCount(" << rows.size() << ");\n";
      }
  
      for (int i = 0; i < rows.size(); ++i) {
          const DomRow *row = rows.at(i);
          if (!row->elementProperty().isEmpty()) {
              const DomPropertyMap properties = propertyMap(row->elementProperty());
  
              Item item(QLatin1String("QTableWidgetItem"), m_indent, m_output, m_refreshOut, m_driver);
              addCommonInitializers(&item, properties);
  
              QString itemName = item.writeSetupUi(QString(), Item::ConstructItemAndVariable);
              item.writeRetranslateUi(varName + QLatin1String("->verticalHeaderItem(") + QString::number(i) + QLatin1Char(')'));
              m_output << m_indent << varName << "->setVerticalHeaderItem(" << QString::number(i) << ", " << itemName << ");\n";
          }
      }
  
      // items
      QString tempName = disableSorting(w, varName);
  
      const QList<DomItem *> items = w->elementItem();
  
      for (int i = 0; i < items.size(); ++i) {
          const DomItem *cell = items.at(i);
          if (cell->hasAttributeRow() && cell->hasAttributeColumn() && !cell->elementProperty().isEmpty()) {
              const int r = cell->attributeRow();
              const int c = cell->attributeColumn();
              const DomPropertyMap properties = propertyMap(cell->elementProperty());
  
              Item item(QLatin1String("QTableWidgetItem"), m_indent, m_output, m_refreshOut, m_driver);
              addQtFlagsInitializer(&item, properties, QLatin1String("flags"));
              addCommonInitializers(&item, properties);
  
              QString itemName = item.writeSetupUi(QString(), Item::ConstructItemAndVariable);
              item.writeRetranslateUi(varName + QLatin1String("->item(") + QString::number(r) + QLatin1String(", ") + QString::number(c) + QLatin1Char(')'));
              m_output << m_indent << varName << "->setItem(" << QString::number(r) << ", " << QString::number(c) << ", " << itemName << ");\n";
          }
      }
      enableSorting(w, varName, tempName);
  }
  
  QString WriteInitialization::trCall(const QString &str, const QString &commentHint) const
  {
      if (str.isEmpty())
          return QLatin1String("QString()");
  
      QString result;
      const QString comment = commentHint.isEmpty() ? QString(QLatin1String("Q_NULLPTR")) : fixString(commentHint, m_dindent);
  
      if (m_option.translateFunction.isEmpty()) {
          if (m_option.idBased) {
              result += QLatin1String("qtTrId(");
          } else {
              result += QLatin1String("QApplication::translate(\"")
                      + m_generatedClass
                      + QLatin1String("\", ");
          }
      } else {
          result += m_option.translateFunction + QLatin1Char('(');
      }
  
      result += fixString(str, m_dindent);
  
      if (!m_option.idBased) {
          result += QLatin1String(", ") + comment;
      }
  
      result += QLatin1Char(')');
      return result;
  }
  
  void WriteInitialization::initializeMenu(DomWidget *w, const QString &/*parentWidget*/)
  {
      const QString menuName = m_driver->findOrInsertWidget(w);
      const QString menuAction = menuName + QLatin1String("Action");
  
      const DomAction *action = m_driver->actionByName(menuAction);
      if (action && action->hasAttributeMenu()) {
          m_output << m_indent << menuAction << " = " << menuName << "->menuAction();\n";
      }
  }
  
  QString WriteInitialization::trCall(DomString *str, const QString &defaultString) const
  {
      QString value = defaultString;
      QString comment;
      if (str) {
          value = toString(str);
          comment = str->attributeComment();
      }
      return trCall(value, comment);
  }
  
  QString WriteInitialization::noTrCall(DomString *str, const QString &defaultString) const
  {
      QString value = defaultString;
      if (!str && defaultString.isEmpty())
          return QString();
      if (str)
          value = str->text();
      return writeString(value, m_dindent);
  }
  
  QString WriteInitialization::autoTrCall(DomString *str, const QString &defaultString) const
  {
      if ((!str && !defaultString.isEmpty()) || needsTranslation(str))
          return trCall(str, defaultString);
      return noTrCall(str, defaultString);
  }
  
  QTextStream &WriteInitialization::autoTrOutput(const DomProperty *property)
  {
      if (const DomString *str = property->elementString())
          return autoTrOutput(str);
      if (const DomStringList *list = property->elementStringList())
          if (needsTranslation(list))
              return m_refreshOut;
      return m_output;
  }
  
  QTextStream &WriteInitialization::autoTrOutput(const DomString *str, const QString &defaultString)
  {
      if ((!str && !defaultString.isEmpty()) || needsTranslation(str))
          return m_refreshOut;
      return m_output;
  }
  
  bool WriteInitialization::isValidObject(const QString &name) const
  {
      return m_registeredWidgets.contains(name)
          || m_registeredActions.contains(name);
  }
  
  QString WriteInitialization::findDeclaration(const QString &name)
  {
      const QString normalized = Driver::normalizedName(name);
  
      if (DomWidget *widget = m_driver->widgetByName(normalized))
          return m_driver->findOrInsertWidget(widget);
      if (DomAction *action = m_driver->actionByName(normalized))
          return m_driver->findOrInsertAction(action);
      if (const DomButtonGroup *group = m_driver->findButtonGroup(normalized))
          return m_driver->findOrInsertButtonGroup(group);
      return QString();
  }
  
  void WriteInitialization::acceptConnection(DomConnection *connection)
  {
      const QString sender = findDeclaration(connection->elementSender());
      const QString receiver = findDeclaration(connection->elementReceiver());
  
      if (sender.isEmpty() || receiver.isEmpty())
          return;
  
      m_output << m_indent << "QObject::connect("
          << sender
          << ", "
          << "SIGNAL("<<connection->elementSignal()<<')'
          << ", "
          << receiver
          << ", "
          << "SLOT("<<connection->elementSlot()<<')'
          << ");\n";
  }
  
  DomImage *WriteInitialization::findImage(const QString &name) const
  {
      return m_registeredImages.value(name);
  }
  
  DomWidget *WriteInitialization::findWidget(QLatin1String widgetClass)
  {
      for (int i = m_widgetChain.count() - 1; i >= 0; --i) {
          DomWidget *widget = m_widgetChain.at(i);
  
          if (widget && m_uic->customWidgetsInfo()->extends(widget->attributeClass(), widgetClass))
              return widget;
      }
  
      return 0;
  }
  
  void WriteInitialization::acceptImage(DomImage *image)
  {
      if (!image->hasAttributeName())
          return;
  
      m_registeredImages.insert(image->attributeName(), image);
  }
  
  void WriteInitialization::acceptWidgetScripts(const DomScripts &widgetScripts, DomWidget *node, const  DomWidgets &childWidgets)
  {
      // Add the per-class custom scripts to the per-widget ones.
      DomScripts scripts(widgetScripts);
  
      if (DomScript *customWidgetScript = m_uic->customWidgetsInfo()->customWidgetScript(node->attributeClass()))
          scripts.push_front(customWidgetScript);
  
      if (scripts.empty())
          return;
  
      // concatenate script snippets
      QString script;
      for (const DomScript *domScript : qAsConst(scripts)) {
          const QString snippet = domScript->text();
          if (!snippet.isEmpty())
              script += QStringRef(&snippet).trimmed() + QLatin1Char('\n');
      }
      if (script.isEmpty())
          return;
  
      // Build the list of children and insert call
      m_output << m_indent << "childWidgets.clear();\n";
      if (!childWidgets.empty()) {
          m_output << m_indent <<  "childWidgets";
          for (DomWidget *child : childWidgets)
              m_output << " << " << m_driver->findOrInsertWidget(child);
          m_output << ";\n";
      }
      m_output << m_indent << "scriptContext.run("
               << writeString(script, m_dindent) << ", "
               << m_driver->findOrInsertWidget(node) << ", childWidgets);\n";
  }
  
  
  static void generateMultiDirectiveBegin(QTextStream &outputStream, const QSet<QString> &directives)
  {
      if (directives.isEmpty())
          return;
  
      if (directives.size() == 1) {
          outputStream << "#ifndef " << *directives.cbegin() << endl;
          return;
      }
  
      auto list = directives.toList();
      // sort (always generate in the same order):
      std::sort(list.begin(), list.end());
  
      outputStream << "#if !defined(" << list.join(QLatin1String(") || !defined(")) << ')' << endl;
  }
  
  static void generateMultiDirectiveEnd(QTextStream &outputStream, const QSet<QString> &directives)
  {
      if (directives.isEmpty())
          return;
  
      outputStream << "#endif" << endl;
  }
  
  WriteInitialization::Item::Item(const QString &itemClassName, const QString &indent, QTextStream &setupUiStream, QTextStream &retranslateUiStream, Driver *driver)
      :
      m_parent(0),
      m_itemClassName(itemClassName),
      m_indent(indent),
      m_setupUiStream(setupUiStream),
      m_retranslateUiStream(retranslateUiStream),
      m_driver(driver)
  {
  
  }
  
  WriteInitialization::Item::~Item()
  {
      qDeleteAll(m_children);
  }
  
  QString WriteInitialization::Item::writeSetupUi(const QString &parent, Item::EmptyItemPolicy emptyItemPolicy)
  {
      if (emptyItemPolicy == Item::DontConstruct && m_setupUiData.policy == ItemData::DontGenerate)
          return QString();
  
      bool generateMultiDirective = false;
      if (emptyItemPolicy == Item::ConstructItemOnly && m_children.size() == 0) {
          if (m_setupUiData.policy == ItemData::DontGenerate) {
              m_setupUiStream << m_indent << "new " << m_itemClassName << '(' << parent << ");\n";
                  return QString();
          } else if (m_setupUiData.policy == ItemData::GenerateWithMultiDirective) {
              generateMultiDirective = true;
          }
      }
  
      if (generateMultiDirective)
          generateMultiDirectiveBegin(m_setupUiStream, m_setupUiData.directives);
  
      const QString uniqueName = m_driver->unique(QLatin1String("__") + m_itemClassName.toLower());
      m_setupUiStream << m_indent << m_itemClassName << " *" << uniqueName << " = new " << m_itemClassName << '(' << parent << ");\n";
  
      if (generateMultiDirective) {
          m_setupUiStream << "#else\n";
          m_setupUiStream << m_indent << "new " << m_itemClassName << '(' << parent << ");\n";
          generateMultiDirectiveEnd(m_setupUiStream, m_setupUiData.directives);
      }
  
      QMultiMap<QString, QString>::ConstIterator it = m_setupUiData.setters.constBegin();
      while (it != m_setupUiData.setters.constEnd()) {
          openIfndef(m_setupUiStream, it.key());
          m_setupUiStream << m_indent << uniqueName << it.value() << endl;
          closeIfndef(m_setupUiStream, it.key());
          ++it;
      }
      for (Item *child : qAsConst(m_children))
          child->writeSetupUi(uniqueName);
      return uniqueName;
  }
  
  void WriteInitialization::Item::writeRetranslateUi(const QString &parentPath)
  {
      if (m_retranslateUiData.policy == ItemData::DontGenerate)
          return;
  
      if (m_retranslateUiData.policy == ItemData::GenerateWithMultiDirective)
          generateMultiDirectiveBegin(m_retranslateUiStream, m_retranslateUiData.directives);
  
      const QString uniqueName = m_driver->unique(QLatin1String("___") + m_itemClassName.toLower());
      m_retranslateUiStream << m_indent << m_itemClassName << " *" << uniqueName << " = " << parentPath << ";\n";
  
      if (m_retranslateUiData.policy == ItemData::GenerateWithMultiDirective)
          generateMultiDirectiveEnd(m_retranslateUiStream, m_retranslateUiData.directives);
  
      QString oldDirective;
      QMultiMap<QString, QString>::ConstIterator it = m_retranslateUiData.setters.constBegin();
      while (it != m_retranslateUiData.setters.constEnd()) {
          const QString newDirective = it.key();
          if (oldDirective != newDirective) {
              closeIfndef(m_retranslateUiStream, oldDirective);
              openIfndef(m_retranslateUiStream, newDirective);
              oldDirective = newDirective;
          }
          m_retranslateUiStream << m_indent << uniqueName << it.value() << endl;
          ++it;
      }
      closeIfndef(m_retranslateUiStream, oldDirective);
  
      for (int i = 0; i < m_children.size(); i++)
          m_children[i]->writeRetranslateUi(uniqueName + QLatin1String("->child(") + QString::number(i) + QLatin1Char(')'));
  }
  
  void WriteInitialization::Item::addSetter(const QString &setter, const QString &directive, bool translatable)
  {
      const ItemData::TemporaryVariableGeneratorPolicy newPolicy = directive.isNull() ? ItemData::Generate : ItemData::GenerateWithMultiDirective;
      if (translatable) {
          m_retranslateUiData.setters.insert(directive, setter);
          if (ItemData::GenerateWithMultiDirective == newPolicy)
              m_retranslateUiData.directives << directive;
          if (m_retranslateUiData.policy < newPolicy)
              m_retranslateUiData.policy = newPolicy;
      } else {
          m_setupUiData.setters.insert(directive, setter);
          if (ItemData::GenerateWithMultiDirective == newPolicy)
              m_setupUiData.directives << directive;
          if (m_setupUiData.policy < newPolicy)
              m_setupUiData.policy = newPolicy;
      }
  }
  
  void WriteInitialization::Item::addChild(Item *child)
  {
      m_children << child;
      child->m_parent = this;
  
      Item *c = child;
      Item *p = this;
      while (p) {
          p->m_setupUiData.directives |= c->m_setupUiData.directives;
          p->m_retranslateUiData.directives |= c->m_retranslateUiData.directives;
          if (p->m_setupUiData.policy < c->m_setupUiData.policy)
              p->m_setupUiData.policy = c->m_setupUiData.policy;
          if (p->m_retranslateUiData.policy < c->m_retranslateUiData.policy)
              p->m_retranslateUiData.policy = c->m_retranslateUiData.policy;
          c = p;
          p = p->m_parent;
      }
  }
  
  
  } // namespace CPP
  
  QT_END_NAMESPACE
  