1 /****************************************************************************
2 **
3 ** Copyright (C) 2018 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the Qt Designer of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:BSD$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** BSD License Usage
18 ** Alternatively, you may use this file under the terms of the BSD license
19 ** as follows:
20 **
21 ** "Redistribution and use in source and binary forms, with or without
22 ** modification, are permitted provided that the following conditions are
23 ** met:
24 **   * Redistributions of source code must retain the above copyright
25 **     notice, this list of conditions and the following disclaimer.
26 **   * Redistributions in binary form must reproduce the above copyright
27 **     notice, this list of conditions and the following disclaimer in
28 **     the documentation and/or other materials provided with the
29 **     distribution.
30 **   * Neither the name of The Qt Company Ltd nor the names of its
31 **     contributors may be used to endorse or promote products derived
32 **     from this software without specific prior written permission.
33 **
34 **
35 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
36 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
38 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
39 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
43 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
45 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
46 **
47 ** $QT_END_LICENSE$
48 **
49 ****************************************************************************/
50 
51 #include "formbuilderextra_p.h"
52 #include "abstractformbuilder.h"
53 #include "properties_p.h"
54 #include "resourcebuilder_p.h"
55 #include "textbuilder_p.h"
56 #include "ui4_p.h"
57 
58 #include <QtWidgets/qlabel.h>
59 #include <QtWidgets/qboxlayout.h>
60 #include <QtWidgets/qgridlayout.h>
61 
62 #include <QtCore/qvariant.h>
63 #include <QtCore/qdebug.h>
64 #include <QtCore/qtextstream.h>
65 #include <QtCore/qstringlist.h>
66 #include <QtCore/qcoreapplication.h>
67 #include <QtCore/qversionnumber.h>
68 
69 #include <limits.h>
70 
71 QT_BEGIN_NAMESPACE
72 
73 #ifdef QFORMINTERNAL_NAMESPACE
74 namespace QFormInternal {
75 #endif
76 
uiLibWarning(const QString & message)77 void uiLibWarning(const QString &message) {
78     qWarning("Designer: %s", qPrintable(message));
79 }
80 
81 
82 QFormBuilderExtra::CustomWidgetData::CustomWidgetData() = default;
83 
CustomWidgetData(const DomCustomWidget * dcw)84 QFormBuilderExtra::CustomWidgetData::CustomWidgetData(const DomCustomWidget *dcw) :
85     addPageMethod(dcw->elementAddPageMethod()),
86     baseClass(dcw->elementExtends()),
87     isContainer(dcw->hasElementContainer() && dcw->elementContainer() != 0)
88 {
89 }
90 
QFormBuilderExtra()91 QFormBuilderExtra::QFormBuilderExtra() :
92     m_defaultMargin(INT_MIN),
93     m_defaultSpacing(INT_MIN),
94     m_language(QStringLiteral("c++"))
95 {
96 }
97 
~QFormBuilderExtra()98 QFormBuilderExtra::~QFormBuilderExtra()
99 {
100     clearResourceBuilder();
101     clearTextBuilder();
102 }
103 
clear()104 void QFormBuilderExtra::clear()
105 {
106     m_buddies.clear();
107     m_parentWidget = nullptr;
108     m_parentWidgetIsSet = false;
109     m_customWidgetDataHash.clear();
110     m_buttonGroups.clear();
111 }
112 
msgXmlError(const QXmlStreamReader & reader)113 static inline QString msgXmlError(const QXmlStreamReader &reader)
114 {
115     return QCoreApplication::translate("QAbstractFormBuilder",
116                                        "An error has occurred while reading the UI file at line %1, column %2: %3")
117                                        .arg(reader.lineNumber()).arg(reader.columnNumber())
118                                        .arg(reader.errorString());
119 }
120 
121 // Read and check the  version and the (optional) language attribute
122 // of an <ui> element and leave reader positioned at <ui>.
readUiAttributes(QXmlStreamReader & reader,const QString & language,QString * errorMessage)123 static bool inline readUiAttributes(QXmlStreamReader &reader, const QString &language,
124                                     QString *errorMessage)
125 {
126     const QString uiElement = QStringLiteral("ui");
127     // Read up to first element
128     while (!reader.atEnd()) {
129         switch (reader.readNext()) {
130         case QXmlStreamReader::Invalid:
131             *errorMessage = msgXmlError(reader);
132             return false;
133         case QXmlStreamReader::StartElement:
134             if (reader.name().compare(uiElement, Qt::CaseInsensitive) == 0) {
135                 const QString versionAttribute = QStringLiteral("version");
136                 const QString languageAttribute = QStringLiteral("language");
137                 const QXmlStreamAttributes attributes = reader.attributes();
138                 if (attributes.hasAttribute(versionAttribute)) {
139                     const QVersionNumber version =
140                         QVersionNumber::fromString(attributes.value(versionAttribute));
141                     if (version < QVersionNumber(4)) {
142                         *errorMessage =
143                             QCoreApplication::translate("QAbstractFormBuilder",
144                                                         "This file was created using Designer from Qt-%1 and cannot be read.")
145                                                         .arg(attributes.value(versionAttribute));
146                         return false;
147                     } // version error
148                 }     // has version
149                 if (attributes.hasAttribute(languageAttribute)) {
150                     // Check on optional language (Jambi)
151                     const QString formLanguage = attributes.value(languageAttribute).toString();
152                     if (!formLanguage.isEmpty() && formLanguage.compare(language, Qt::CaseInsensitive)) {
153                         *errorMessage =
154                             QCoreApplication::translate("QAbstractFormBuilder",
155                                                         "This file cannot be read because it was created using %1.")
156                                                         .arg(formLanguage);
157                         return false;
158                     } // language error
159                 }    // has language
160                 return true;
161             }  // <ui> matched
162             break;
163         default:
164             break;
165         }
166     }
167     // No <ui> found.
168     *errorMessage = QCoreApplication::translate("QAbstractFormBuilder",
169                                                 "Invalid UI file: The root element <ui> is missing.");
170     return false;
171 }
172 
readUi(QIODevice * dev)173 DomUI *QFormBuilderExtra::readUi(QIODevice *dev)
174 {
175     QXmlStreamReader reader(dev);
176     m_errorString.clear();
177     if (!readUiAttributes(reader, m_language, &m_errorString)) {
178         uiLibWarning(m_errorString);
179         return nullptr;
180     }
181     DomUI *ui = new DomUI;
182     ui->read(reader);
183     if (reader.hasError()) {
184         m_errorString = msgXmlError(reader);
185         uiLibWarning(m_errorString);
186         delete ui;
187         return nullptr;
188     }
189     return ui;
190 }
191 
msgInvalidUiFile()192 QString QFormBuilderExtra::msgInvalidUiFile()
193 {
194     return QCoreApplication::translate("QAbstractFormBuilder", "Invalid UI file");
195 }
196 
applyPropertyInternally(QObject * o,const QString & propertyName,const QVariant & value)197 bool QFormBuilderExtra::applyPropertyInternally(QObject *o, const QString &propertyName, const QVariant &value)
198 {
199     // Store buddies and apply them later on as the widgets might not exist yet.
200     QLabel *label = qobject_cast<QLabel*>(o);
201     if (!label || propertyName != QFormBuilderStrings::instance().buddyProperty)
202         return false;
203 
204     m_buddies.insert(label, value.toString());
205     return true;
206 }
207 
applyInternalProperties() const208 void QFormBuilderExtra::applyInternalProperties() const
209 {
210     if (m_buddies.isEmpty())
211         return;
212 
213     const BuddyHash::const_iterator cend = m_buddies.constEnd();
214     for (BuddyHash::const_iterator it = m_buddies.constBegin(); it != cend; ++it )
215         applyBuddy(it.value(), BuddyApplyAll, it.key());
216 }
217 
applyBuddy(const QString & buddyName,BuddyMode applyMode,QLabel * label)218 bool QFormBuilderExtra::applyBuddy(const QString &buddyName, BuddyMode applyMode, QLabel *label)
219 {
220     if (buddyName.isEmpty()) {
221         label->setBuddy(nullptr);
222         return false;
223     }
224 
225     const QWidgetList widgets = label->topLevelWidget()->findChildren<QWidget*>(buddyName);
226     if (widgets.isEmpty()) {
227         label->setBuddy(nullptr);
228         return false;
229     }
230 
231     const QWidgetList::const_iterator cend = widgets.constEnd();
232     for ( QWidgetList::const_iterator it =  widgets.constBegin(); it !=  cend; ++it) {
233         if (applyMode == BuddyApplyAll || !(*it)->isHidden()) {
234             label->setBuddy(*it);
235             return true;
236         }
237     }
238 
239     label->setBuddy(nullptr);
240     return false;
241 }
242 
parentWidget() const243 const QPointer<QWidget> &QFormBuilderExtra::parentWidget() const
244 {
245     return m_parentWidget;
246 }
247 
parentWidgetIsSet() const248 bool QFormBuilderExtra::parentWidgetIsSet() const
249 {
250     return m_parentWidgetIsSet;
251 }
252 
setParentWidget(const QPointer<QWidget> & w)253 void QFormBuilderExtra::setParentWidget(const QPointer<QWidget> &w)
254 {
255     // Parent widget requires special handling of the geometry property.
256     m_parentWidget = w;
257     m_parentWidgetIsSet = true;
258 }
259 
storeCustomWidgetData(const QString & className,const DomCustomWidget * d)260 void QFormBuilderExtra::storeCustomWidgetData(const QString &className, const DomCustomWidget *d)
261 {
262     if (d)
263         m_customWidgetDataHash.insert(className, CustomWidgetData(d));
264 }
265 
customWidgetBaseClass(const QString & className) const266 QString QFormBuilderExtra::customWidgetBaseClass(const QString &className) const
267 {
268     const QHash<QString, CustomWidgetData>::const_iterator it = m_customWidgetDataHash.constFind(className);
269     if (it != m_customWidgetDataHash.constEnd())
270             return it.value().baseClass;
271     return QString();
272 }
273 
customWidgetAddPageMethod(const QString & className) const274 QString QFormBuilderExtra::customWidgetAddPageMethod(const QString &className) const
275 {
276     const QHash<QString, CustomWidgetData>::const_iterator it = m_customWidgetDataHash.constFind(className);
277     if (it != m_customWidgetDataHash.constEnd())
278         return it.value().addPageMethod;
279     return QString();
280 }
281 
isCustomWidgetContainer(const QString & className) const282 bool QFormBuilderExtra::isCustomWidgetContainer(const QString &className) const
283 {
284     const QHash<QString, CustomWidgetData>::const_iterator it = m_customWidgetDataHash.constFind(className);
285     if (it != m_customWidgetDataHash.constEnd())
286         return it.value().isContainer;
287     return false;
288 }
289 
setProcessingLayoutWidget(bool processing)290 void QFormBuilderExtra::setProcessingLayoutWidget(bool processing)
291 {
292     m_layoutWidget = processing;
293 }
294 
processingLayoutWidget() const295  bool QFormBuilderExtra::processingLayoutWidget() const
296 {
297     return m_layoutWidget;
298 }
setResourceBuilder(QResourceBuilder * builder)299 void QFormBuilderExtra::setResourceBuilder(QResourceBuilder *builder)
300 {
301     if (m_resourceBuilder == builder)
302         return;
303     clearResourceBuilder();
304     m_resourceBuilder = builder;
305 }
306 
resourceBuilder() const307 QResourceBuilder *QFormBuilderExtra::resourceBuilder() const
308 {
309     return m_resourceBuilder;
310 }
311 
clearResourceBuilder()312 void QFormBuilderExtra::clearResourceBuilder()
313 {
314     if (m_resourceBuilder) {
315         delete m_resourceBuilder;
316         m_resourceBuilder = nullptr;
317     }
318 }
319 
setTextBuilder(QTextBuilder * builder)320 void QFormBuilderExtra::setTextBuilder(QTextBuilder *builder)
321 {
322     if (m_textBuilder == builder)
323         return;
324     clearTextBuilder();
325     m_textBuilder = builder;
326 }
327 
textBuilder() const328 QTextBuilder *QFormBuilderExtra::textBuilder() const
329 {
330     return m_textBuilder;
331 }
332 
clearTextBuilder()333 void QFormBuilderExtra::clearTextBuilder()
334 {
335     if (m_textBuilder) {
336         delete m_textBuilder;
337         m_textBuilder = nullptr;
338     }
339 }
340 
registerButtonGroups(const DomButtonGroups * domGroups)341 void QFormBuilderExtra::registerButtonGroups(const DomButtonGroups *domGroups)
342 {
343     const auto &domGroupList = domGroups->elementButtonGroup();
344     for (DomButtonGroup *domGroup : domGroupList)
345         m_buttonGroups.insert(domGroup->attributeName(), ButtonGroupEntry(domGroup, nullptr));
346 }
347 
348 // Utilities for parsing per-cell integer properties that have setters and
349 //  getters of the form 'setX(int idx, int value)' and 'x(int index)'
350 // (converting them to comma-separated string lists and back).
351 // Used for layout stretch and grid per-row/column properties.
352 
353 // Format a list of cell-properties of one dimension as a ','-separated list
354 template <class Layout>
perCellPropertyToString(const Layout * l,int count,int (Layout::* getter)(int)const)355 inline QString perCellPropertyToString(const Layout *l, int count, int (Layout::*getter)(int) const)
356 {
357     if (count == 0)
358         return QString();
359     QString rc;
360     {
361         QTextStream str(&rc);
362         for (int i = 0; i < count; i++) {
363             if (i)
364                 str << QLatin1Char(',');
365             str << (l->*getter)(i);
366         }
367     }
368     return rc;
369 }
370 
371 // Clear the property, set all cells to 0
372 
373 template <class Layout>
clearPerCellValue(Layout * l,int count,void (Layout::* setter)(int,int),int value=0)374 inline void clearPerCellValue(Layout *l, int count, void (Layout::*setter)(int,int), int value = 0)
375 {
376     for (int i = 0; i < count; i++)
377         (l->*setter)(i, value);
378 }
379 
380 // Parse and set the property from a comma-separated list
381 
382 template <class Layout>
parsePerCellProperty(Layout * l,int count,void (Layout::* setter)(int,int),const QString & s,int defaultValue=0)383 inline bool parsePerCellProperty(Layout *l, int count, void (Layout::*setter)(int,int), const QString &s, int defaultValue = 0)
384 {
385     if (s.isEmpty()) {
386         clearPerCellValue(l, count, setter, defaultValue);
387         return true;
388     }
389     const auto list = s.splitRef(QLatin1Char(','));
390     if (list.isEmpty()) {
391         clearPerCellValue(l, count, setter, defaultValue);
392         return true;
393     }
394     // Apply all values contained in list
395     const int ac = qMin(count, list.size());
396     bool ok;
397     int i = 0;
398     for ( ; i < ac; i++) {
399         const int value = list.at(i).toInt(&ok);
400         if (!ok || value < 0)
401             return false;
402         (l->*setter)(i, value);
403     }
404     // Clear rest
405     for ( ; i < count; i++)
406         (l->*setter)(i, defaultValue);
407     return true;
408 }
409 
410 // Read and write stretch
msgInvalidStretch(const QString & objectName,const QString & stretch)411 static QString msgInvalidStretch(const QString &objectName, const QString &stretch)
412 {
413     //: Parsing layout stretch values
414     return QCoreApplication::translate("FormBuilder", "Invalid stretch value for '%1': '%2'").arg(objectName, stretch);
415 }
416 
boxLayoutStretch(const QBoxLayout * box)417 QString QFormBuilderExtra::boxLayoutStretch(const QBoxLayout *box)
418 {
419      return perCellPropertyToString(box, box->count(), &QBoxLayout::stretch);
420 }
421 
setBoxLayoutStretch(const QString & s,QBoxLayout * box)422 bool QFormBuilderExtra::setBoxLayoutStretch(const QString &s, QBoxLayout *box)
423 {
424     const bool rc = parsePerCellProperty(box, box->count(), &QBoxLayout::setStretch, s);
425     if (!rc)
426         uiLibWarning(msgInvalidStretch(box->objectName(), s));
427     return rc;
428 }
429 
clearBoxLayoutStretch(QBoxLayout * box)430 void QFormBuilderExtra::clearBoxLayoutStretch(QBoxLayout *box)
431 {
432     clearPerCellValue(box, box->count(), &QBoxLayout::setStretch);
433 }
434 
gridLayoutRowStretch(const QGridLayout * grid)435 QString QFormBuilderExtra::gridLayoutRowStretch(const QGridLayout *grid)
436 {
437     return perCellPropertyToString(grid, grid->rowCount(), &QGridLayout::rowStretch);
438 }
439 
setGridLayoutRowStretch(const QString & s,QGridLayout * grid)440 bool QFormBuilderExtra::setGridLayoutRowStretch(const QString &s, QGridLayout *grid)
441 {
442     const bool rc = parsePerCellProperty(grid, grid->rowCount(), &QGridLayout::setRowStretch, s);
443     if (!rc)
444         uiLibWarning(msgInvalidStretch(grid->objectName(), s));
445     return rc;
446 }
447 
clearGridLayoutRowStretch(QGridLayout * grid)448 void QFormBuilderExtra::clearGridLayoutRowStretch(QGridLayout *grid)
449 {
450     clearPerCellValue(grid, grid->rowCount(), &QGridLayout::setRowStretch);
451 }
452 
gridLayoutColumnStretch(const QGridLayout * grid)453 QString QFormBuilderExtra::gridLayoutColumnStretch(const QGridLayout *grid)
454 {
455     return perCellPropertyToString(grid, grid->columnCount(), &QGridLayout::columnStretch);
456 }
457 
setGridLayoutColumnStretch(const QString & s,QGridLayout * grid)458 bool QFormBuilderExtra::setGridLayoutColumnStretch(const QString &s, QGridLayout *grid)
459 {
460     const bool rc = parsePerCellProperty(grid, grid->columnCount(), &QGridLayout::setColumnStretch, s);
461     if (!rc)
462         uiLibWarning(msgInvalidStretch(grid->objectName(), s));
463     return rc;
464 }
465 
clearGridLayoutColumnStretch(QGridLayout * grid)466 void QFormBuilderExtra::clearGridLayoutColumnStretch(QGridLayout *grid)
467 {
468     clearPerCellValue(grid, grid->columnCount(), &QGridLayout::setColumnStretch);
469 }
470 
471 // Read and write grid layout row/column size limits
472 
msgInvalidMinimumSize(const QString & objectName,const QString & ms)473 static QString msgInvalidMinimumSize(const QString &objectName, const QString &ms)
474 {
475     //: Parsing grid layout minimum size values
476     return QCoreApplication::translate("FormBuilder", "Invalid minimum size for '%1': '%2'").arg(objectName, ms);
477 }
478 
gridLayoutRowMinimumHeight(const QGridLayout * grid)479 QString QFormBuilderExtra::gridLayoutRowMinimumHeight(const QGridLayout *grid)
480 {
481     return perCellPropertyToString(grid, grid->rowCount(), &QGridLayout::rowMinimumHeight);
482 }
483 
setGridLayoutRowMinimumHeight(const QString & s,QGridLayout * grid)484 bool QFormBuilderExtra::setGridLayoutRowMinimumHeight(const QString &s, QGridLayout *grid)
485 {
486     const bool rc = parsePerCellProperty(grid, grid->rowCount(), &QGridLayout::setRowMinimumHeight, s);
487     if (!rc)
488         uiLibWarning(msgInvalidMinimumSize(grid->objectName(), s));
489     return rc;
490 }
491 
clearGridLayoutRowMinimumHeight(QGridLayout * grid)492 void QFormBuilderExtra::clearGridLayoutRowMinimumHeight(QGridLayout *grid)
493 {
494      clearPerCellValue(grid, grid->rowCount(), &QGridLayout::setRowMinimumHeight);
495 }
496 
gridLayoutColumnMinimumWidth(const QGridLayout * grid)497 QString QFormBuilderExtra::gridLayoutColumnMinimumWidth(const QGridLayout *grid)
498 {
499     return perCellPropertyToString(grid, grid->columnCount(), &QGridLayout::columnMinimumWidth);
500 }
501 
setGridLayoutColumnMinimumWidth(const QString & s,QGridLayout * grid)502 bool QFormBuilderExtra::setGridLayoutColumnMinimumWidth(const QString &s, QGridLayout *grid)
503 {
504     const bool rc = parsePerCellProperty(grid, grid->columnCount(), &QGridLayout::setColumnMinimumWidth, s);
505     if (!rc)
506         uiLibWarning(msgInvalidMinimumSize(grid->objectName(), s));
507     return rc;
508 }
509 
clearGridLayoutColumnMinimumWidth(QGridLayout * grid)510 void QFormBuilderExtra::clearGridLayoutColumnMinimumWidth(QGridLayout *grid)
511 {
512     clearPerCellValue(grid, grid->columnCount(), &QGridLayout::setColumnMinimumWidth);
513 }
514 
setPixmapProperty(DomProperty * p,const QPair<QString,QString> & ip)515 void QFormBuilderExtra::setPixmapProperty(DomProperty *p, const QPair<QString, QString> &ip)
516 {
517     DomResourcePixmap *pix = new DomResourcePixmap;
518     if (!ip.second.isEmpty())
519         pix->setAttributeResource(ip.second);
520 
521     pix->setText(ip.first);
522 
523     p->setAttributeName(QFormBuilderStrings::instance().pixmapAttribute);
524     p->setElementPixmap(pix);
525 }
526 
setupColorGroup(QPalette * palette,QPalette::ColorGroup colorGroup,const DomColorGroup * group)527 void QFormBuilderExtra::setupColorGroup(QPalette *palette, QPalette::ColorGroup colorGroup,
528                                         const DomColorGroup *group)
529 {
530     // old format
531     const auto &colors = group->elementColor();
532     for (int role = 0; role < colors.size(); ++role) {
533         const DomColor *color = colors.at(role);
534         const QColor c(color->elementRed(), color->elementGreen(), color->elementBlue());
535         palette->setColor(colorGroup, QPalette::ColorRole(role), c);
536     }
537 
538     // new format
539     const QMetaEnum colorRole_enum = metaEnum<QAbstractFormBuilderGadget>("colorRole");
540 
541     const auto colorRoles = group->elementColorRole();
542     for (const DomColorRole *colorRole : colorRoles) {
543         if (colorRole->hasAttributeRole()) {
544             const int r = colorRole_enum.keyToValue(colorRole->attributeRole().toLatin1());
545             if (r != -1) {
546                 const QBrush br = setupBrush(colorRole->elementBrush());
547                 palette->setBrush(colorGroup, static_cast<QPalette::ColorRole>(r), br);
548             }
549         }
550     }
551 }
552 
saveColorGroup(const QPalette & palette,QPalette::ColorGroup colorGroup)553 DomColorGroup *QFormBuilderExtra::saveColorGroup(const QPalette &palette,
554                                                  QPalette::ColorGroup colorGroup)
555 {
556 
557     const QMetaEnum colorRole_enum = metaEnum<QAbstractFormBuilderGadget>("colorRole");
558 
559     DomColorGroup *group = new DomColorGroup();
560     QVector<DomColorRole *> colorRoles;
561 
562     const uint mask = palette.resolve();
563     for (int role = QPalette::WindowText; role < QPalette::NColorRoles; ++role) {
564         if (mask & (1 << role)) {
565             const QBrush &br = palette.brush(colorGroup, QPalette::ColorRole(role));
566 
567             DomColorRole *colorRole = new DomColorRole();
568             colorRole->setElementBrush(saveBrush(br));
569             colorRole->setAttributeRole(QLatin1String(colorRole_enum.valueToKey(role)));
570             colorRoles.append(colorRole);
571         }
572     }
573 
574     group->setElementColorRole(colorRoles);
575     return group;
576 }
577 
savePalette(const QPalette & palette)578 DomPalette *QFormBuilderExtra::savePalette(const QPalette &palette)
579 {
580     DomPalette *dom = new DomPalette();
581     dom->setElementActive(QFormBuilderExtra::saveColorGroup(palette, QPalette::Active));
582     dom->setElementInactive(QFormBuilderExtra::saveColorGroup(palette, QPalette::Inactive));
583     dom->setElementDisabled(QFormBuilderExtra::saveColorGroup(palette, QPalette::Disabled));
584 
585     return dom;
586 }
587 
loadPalette(const DomPalette * dom)588 QPalette QFormBuilderExtra::loadPalette(const DomPalette *dom)
589 {
590     QPalette palette;
591 
592     if (dom->elementActive())
593         QFormBuilderExtra::setupColorGroup(&palette, QPalette::Active, dom->elementActive());
594 
595     if (dom->elementInactive())
596         QFormBuilderExtra::setupColorGroup(&palette, QPalette::Inactive, dom->elementInactive());
597 
598     if (dom->elementDisabled())
599         QFormBuilderExtra::setupColorGroup(&palette, QPalette::Disabled, dom->elementDisabled());
600 
601     palette.setCurrentColorGroup(QPalette::Active);
602     return palette;
603 }
604 
setupBrush(const DomBrush * brush)605 QBrush QFormBuilderExtra::setupBrush(const DomBrush *brush)
606 {
607     QBrush br;
608     if (!brush->hasAttributeBrushStyle())
609         return br;
610 
611     const Qt::BrushStyle style = enumKeyOfObjectToValue<QAbstractFormBuilderGadget, Qt::BrushStyle>("brushStyle",
612                                                                                                     brush->attributeBrushStyle().toLatin1().constData());
613 
614     if (style == Qt::LinearGradientPattern ||
615             style == Qt::RadialGradientPattern ||
616             style == Qt::ConicalGradientPattern) {
617         const QMetaEnum gradientType_enum = metaEnum<QAbstractFormBuilderGadget>("gradientType");
618         const QMetaEnum gradientSpread_enum = metaEnum<QAbstractFormBuilderGadget>("gradientSpread");
619         const QMetaEnum gradientCoordinate_enum = metaEnum<QAbstractFormBuilderGadget>("gradientCoordinate");
620 
621         const DomGradient *gradient = brush->elementGradient();
622         const QGradient::Type type = enumKeyToValue<QGradient::Type>(gradientType_enum, gradient->attributeType().toLatin1());
623 
624 
625         QGradient *gr = nullptr;
626 
627         if (type == QGradient::LinearGradient) {
628             gr = new QLinearGradient(QPointF(gradient->attributeStartX(), gradient->attributeStartY()),
629                             QPointF(gradient->attributeEndX(), gradient->attributeEndY()));
630         } else if (type == QGradient::RadialGradient) {
631             gr = new QRadialGradient(QPointF(gradient->attributeCentralX(), gradient->attributeCentralY()),
632                             gradient->attributeRadius(),
633                             QPointF(gradient->attributeFocalX(), gradient->attributeFocalY()));
634         } else if (type == QGradient::ConicalGradient) {
635             gr = new QConicalGradient(QPointF(gradient->attributeCentralX(), gradient->attributeCentralY()),
636                             gradient->attributeAngle());
637         }
638         if (!gr)
639             return br;
640 
641         const QGradient::Spread spread = enumKeyToValue<QGradient::Spread>(gradientSpread_enum, gradient->attributeSpread().toLatin1());
642         gr->setSpread(spread);
643 
644         const QGradient::CoordinateMode coord = enumKeyToValue<QGradient::CoordinateMode>(gradientCoordinate_enum, gradient->attributeCoordinateMode().toLatin1());
645         gr->setCoordinateMode(coord);
646 
647         const auto &stops = gradient->elementGradientStop();
648         for (const DomGradientStop *stop : stops) {
649             const DomColor *color = stop->elementColor();
650             gr->setColorAt(stop->attributePosition(), QColor::fromRgb(color->elementRed(),
651                             color->elementGreen(), color->elementBlue(), color->attributeAlpha()));
652         }
653         br = QBrush(*gr);
654         delete gr;
655     } else if (style == Qt::TexturePattern) {
656         const DomProperty *texture = brush->elementTexture();
657         if (texture && texture->kind() == DomProperty::Pixmap) {
658             br.setTexture({});
659         }
660     } else {
661         const DomColor *color = brush->elementColor();
662         br.setColor(QColor::fromRgb(color->elementRed(),
663                             color->elementGreen(), color->elementBlue(), color->attributeAlpha()));
664         br.setStyle((Qt::BrushStyle)style);
665     }
666     return br;
667 }
668 
saveBrush(const QBrush & br)669 DomBrush *QFormBuilderExtra::saveBrush(const QBrush &br)
670 {
671     const QMetaEnum brushStyle_enum = metaEnum<QAbstractFormBuilderGadget>("brushStyle");
672 
673     DomBrush *brush = new DomBrush();
674     const Qt::BrushStyle style = br.style();
675     brush->setAttributeBrushStyle(QLatin1String(brushStyle_enum.valueToKey(style)));
676     if (style == Qt::LinearGradientPattern ||
677                 style == Qt::RadialGradientPattern ||
678                 style == Qt::ConicalGradientPattern) {
679         const QMetaEnum gradientType_enum = metaEnum<QAbstractFormBuilderGadget>("gradientType");
680         const QMetaEnum gradientSpread_enum = metaEnum<QAbstractFormBuilderGadget>("gradientSpread");
681         const QMetaEnum gradientCoordinate_enum = metaEnum<QAbstractFormBuilderGadget>("gradientCoordinate");
682 
683         DomGradient *gradient = new DomGradient();
684         const QGradient *gr = br.gradient();
685         const QGradient::Type type = gr->type();
686         gradient->setAttributeType(QLatin1String(gradientType_enum.valueToKey(type)));
687         gradient->setAttributeSpread(QLatin1String(gradientSpread_enum.valueToKey(gr->spread())));
688         gradient->setAttributeCoordinateMode(QLatin1String(gradientCoordinate_enum.valueToKey(gr->coordinateMode())));
689         QVector<DomGradientStop *> stops;
690         const QGradientStops st = gr->stops();
691         for (const QGradientStop &pair : st) {
692             DomGradientStop *stop = new DomGradientStop();
693             stop->setAttributePosition(pair.first);
694             DomColor *color = new DomColor();
695             color->setElementRed(pair.second.red());
696             color->setElementGreen(pair.second.green());
697             color->setElementBlue(pair.second.blue());
698             color->setAttributeAlpha(pair.second.alpha());
699             stop->setElementColor(color);
700             stops.append(stop);
701         }
702         gradient->setElementGradientStop(stops);
703         if (type == QGradient::LinearGradient) {
704             auto lgr = static_cast<const QLinearGradient *>(gr);
705             gradient->setAttributeStartX(lgr->start().x());
706             gradient->setAttributeStartY(lgr->start().y());
707             gradient->setAttributeEndX(lgr->finalStop().x());
708             gradient->setAttributeEndY(lgr->finalStop().y());
709         } else if (type == QGradient::RadialGradient) {
710             auto rgr = static_cast<const QRadialGradient *>(gr);
711             gradient->setAttributeCentralX(rgr->center().x());
712             gradient->setAttributeCentralY(rgr->center().y());
713             gradient->setAttributeFocalX(rgr->focalPoint().x());
714             gradient->setAttributeFocalY(rgr->focalPoint().y());
715             gradient->setAttributeRadius(rgr->radius());
716         } else if (type == QGradient::ConicalGradient) {
717             auto cgr = static_cast<const QConicalGradient *>(gr);
718             gradient->setAttributeCentralX(cgr->center().x());
719             gradient->setAttributeCentralY(cgr->center().y());
720             gradient->setAttributeAngle(cgr->angle());
721         }
722 
723         brush->setElementGradient(gradient);
724     } else if (style == Qt::TexturePattern) {
725         const QPixmap pixmap = br.texture();
726         if (!pixmap.isNull()) {
727             DomProperty *p = new DomProperty;
728             QFormBuilderExtra::setPixmapProperty(p, {});
729             brush->setElementTexture(p);
730         }
731     } else {
732         const QColor &c = br.color();
733         DomColor *color = new DomColor();
734         color->setElementRed(c.red());
735         color->setElementGreen(c.green());
736         color->setElementBlue(c.blue());
737         color->setAttributeAlpha(c.alpha());
738         brush->setElementColor(color);
739     }
740     return brush;
741 }
742 
743 // ------------ QFormBuilderStrings
744 
QFormBuilderStrings()745 QFormBuilderStrings::QFormBuilderStrings() :
746     buddyProperty(QStringLiteral("buddy")),
747     cursorProperty(QStringLiteral("cursor")),
748     objectNameProperty(QStringLiteral("objectName")),
749     trueValue(QStringLiteral("true")),
750     falseValue(QStringLiteral("false")),
751     horizontalPostFix(QStringLiteral("Horizontal")),
752     separator(QStringLiteral("separator")),
753     defaultTitle(QStringLiteral("Page")),
754     titleAttribute(QStringLiteral("title")),
755     labelAttribute(QStringLiteral("label")),
756     toolTipAttribute(QStringLiteral("toolTip")),
757     whatsThisAttribute(QStringLiteral("whatsThis")),
758     flagsAttribute(QStringLiteral("flags")),
759     iconAttribute(QStringLiteral("icon")),
760     pixmapAttribute(QStringLiteral("pixmap")),
761     textAttribute(QStringLiteral("text")),
762     currentIndexProperty(QStringLiteral("currentIndex")),
763     toolBarAreaAttribute(QStringLiteral("toolBarArea")),
764     toolBarBreakAttribute(QStringLiteral("toolBarBreak")),
765     dockWidgetAreaAttribute(QStringLiteral("dockWidgetArea")),
766     marginProperty(QStringLiteral("margin")),
767     spacingProperty(QStringLiteral("spacing")),
768     leftMarginProperty(QStringLiteral("leftMargin")),
769     topMarginProperty(QStringLiteral("topMargin")),
770     rightMarginProperty(QStringLiteral("rightMargin")),
771     bottomMarginProperty(QStringLiteral("bottomMargin")),
772     horizontalSpacingProperty(QStringLiteral("horizontalSpacing")),
773     verticalSpacingProperty(QStringLiteral("verticalSpacing")),
774     sizeHintProperty(QStringLiteral("sizeHint")),
775     sizeTypeProperty(QStringLiteral("sizeType")),
776     orientationProperty(QStringLiteral("orientation")),
777     styleSheetProperty(QStringLiteral("styleSheet")),
778     qtHorizontal(QStringLiteral("Qt::Horizontal")),
779     qtVertical(QStringLiteral("Qt::Vertical")),
780     currentRowProperty(QStringLiteral("currentRow")),
781     tabSpacingProperty(QStringLiteral("tabSpacing")),
782     qWidgetClass(QStringLiteral("QWidget")),
783     lineClass(QStringLiteral("Line")),
784     geometryProperty(QStringLiteral("geometry")),
785     scriptWidgetVariable(QStringLiteral("widget")),
786     scriptChildWidgetsVariable(QStringLiteral("childWidgets"))
787 {
788     itemRoles.append(qMakePair(Qt::FontRole, QString::fromLatin1("font")));
789     itemRoles.append(qMakePair(Qt::TextAlignmentRole, QString::fromLatin1("textAlignment")));
790     itemRoles.append(qMakePair(Qt::BackgroundRole, QString::fromLatin1("background")));
791     itemRoles.append(qMakePair(Qt::ForegroundRole, QString::fromLatin1("foreground")));
792     itemRoles.append(qMakePair(Qt::CheckStateRole, QString::fromLatin1("checkState")));
793 
794     for (const RoleNName &it : qAsConst(itemRoles))
795         treeItemRoleHash.insert(it.second, it.first);
796 
797     itemTextRoles.append(qMakePair(qMakePair(Qt::EditRole, Qt::DisplayPropertyRole),
798                                    textAttribute)); // This must be first for the loop below
799     itemTextRoles.append(qMakePair(qMakePair(Qt::ToolTipRole, Qt::ToolTipPropertyRole),
800                                    toolTipAttribute));
801     itemTextRoles.append(qMakePair(qMakePair(Qt::StatusTipRole, Qt::StatusTipPropertyRole),
802                                    QString::fromLatin1("statusTip")));
803     itemTextRoles.append(qMakePair(qMakePair(Qt::WhatsThisRole, Qt::WhatsThisPropertyRole),
804                                    whatsThisAttribute));
805 
806     // Note: this skips the first item!
807     auto it = itemTextRoles.constBegin();
808     const auto end = itemTextRoles.constEnd();
809     while (++it != end)
810         treeItemTextRoleHash.insert(it->second, it->first);
811 }
812 
instance()813 const QFormBuilderStrings &QFormBuilderStrings::instance()
814 {
815     static const QFormBuilderStrings rc;
816     return rc;
817 }
818 
819 #ifdef QFORMINTERNAL_NAMESPACE
820 } // namespace QFormInternal
821 #endif
822 
823 QT_END_NAMESPACE
824