Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
formbuilderextra.cpp
Go to the documentation of this file.
1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
7#include "properties_p.h"
10#include "ui4_p.h"
11
12#include <QtWidgets/qlabel.h>
13#include <QtWidgets/qboxlayout.h>
14#include <QtWidgets/qgridlayout.h>
15#if QT_CONFIG(fontcombobox)
16# include <QtWidgets/qfontcombobox.h>
17#endif
18
19#include <QtCore/qvariant.h>
20#include <QtCore/qdebug.h>
21#include <QtCore/qtextstream.h>
22#include <QtCore/qstringlist.h>
23#include <QtCore/qcoreapplication.h>
24#include <QtCore/qversionnumber.h>
25
26#include <climits>
27
29
30using namespace Qt::StringLiterals;
31
32#ifdef QFORMINTERNAL_NAMESPACE
33namespace QFormInternal {
34#endif
35
36void uiLibWarning(const QString &message) {
37 qWarning("Designer: %s", qPrintable(message));
38}
39
40QFormBuilderExtra::CustomWidgetData::CustomWidgetData() = default;
41
42QFormBuilderExtra::CustomWidgetData::CustomWidgetData(const DomCustomWidget *dcw) :
43 addPageMethod(dcw->elementAddPageMethod()),
44 baseClass(dcw->elementExtends()),
45 isContainer(dcw->hasElementContainer() && dcw->elementContainer() != 0)
46{
47}
48
49QFormBuilderExtra::QFormBuilderExtra() :
50 m_defaultMargin(INT_MIN),
51 m_defaultSpacing(INT_MIN),
52 m_language(u"c++"_s)
53{
54}
55
56QFormBuilderExtra::~QFormBuilderExtra()
57{
58 clearResourceBuilder();
59 clearTextBuilder();
60}
61
62void QFormBuilderExtra::clear()
63{
64 m_buddies.clear();
65 m_parentWidget = nullptr;
66 m_parentWidgetIsSet = false;
67 m_customWidgetDataHash.clear();
68 m_buttonGroups.clear();
69}
70
71static inline QString msgXmlError(const QXmlStreamReader &reader)
72{
73 return QCoreApplication::translate("QAbstractFormBuilder",
74 "An error has occurred while reading the UI file at line %1, column %2: %3")
75 .arg(reader.lineNumber()).arg(reader.columnNumber())
76 .arg(reader.errorString());
77}
78
79// Read and check the version and the (optional) language attribute
80// of an <ui> element and leave reader positioned at <ui>.
81static bool inline readUiAttributes(QXmlStreamReader &reader, const QString &language,
82 QString *errorMessage)
83{
84 // Read up to first element
85 while (!reader.atEnd()) {
86 switch (reader.readNext()) {
87 case QXmlStreamReader::Invalid:
88 *errorMessage = msgXmlError(reader);
89 return false;
90 case QXmlStreamReader::StartElement:
91 if (reader.name().compare("ui"_L1, Qt::CaseInsensitive) == 0) {
92 const QString versionAttribute = u"version"_s;
93 const QString languageAttribute = u"language"_s;
94 const QXmlStreamAttributes attributes = reader.attributes();
95 if (attributes.hasAttribute(versionAttribute)) {
96 const QVersionNumber version =
97 QVersionNumber::fromString(attributes.value(versionAttribute));
98 if (version < QVersionNumber(4)) {
99 *errorMessage =
100 QCoreApplication::translate("QAbstractFormBuilder",
101 "This file was created using Designer from Qt-%1 and cannot be read.")
102 .arg(attributes.value(versionAttribute));
103 return false;
104 } // version error
105 } // has version
106 if (attributes.hasAttribute(languageAttribute)) {
107 // Check on optional language (Jambi)
108 const QString formLanguage = attributes.value(languageAttribute).toString();
109 if (!formLanguage.isEmpty() && formLanguage.compare(language, Qt::CaseInsensitive)) {
110 *errorMessage =
111 QCoreApplication::translate("QAbstractFormBuilder",
112 "This file cannot be read because it was created using %1.")
113 .arg(formLanguage);
114 return false;
115 } // language error
116 } // has language
117 return true;
118 } // <ui> matched
119 break;
120 default:
121 break;
122 }
123 }
124 // No <ui> found.
125 *errorMessage = QCoreApplication::translate("QAbstractFormBuilder",
126 "Invalid UI file: The root element <ui> is missing.");
127 return false;
128}
129
130DomUI *QFormBuilderExtra::readUi(QIODevice *dev)
131{
132 QXmlStreamReader reader(dev);
133 m_errorString.clear();
134 if (!readUiAttributes(reader, m_language, &m_errorString)) {
135 uiLibWarning(m_errorString);
136 return nullptr;
137 }
138 auto *ui = new DomUI;
139 ui->read(reader);
140 if (reader.hasError()) {
141 m_errorString = msgXmlError(reader);
142 uiLibWarning(m_errorString);
143 delete ui;
144 return nullptr;
145 }
146 return ui;
147}
148
149QString QFormBuilderExtra::msgInvalidUiFile()
150{
151 return QCoreApplication::translate("QAbstractFormBuilder", "Invalid UI file");
152}
153
154bool QFormBuilderExtra::applyPropertyInternally(QObject *o, const QString &propertyName, const QVariant &value)
155{
156 // Store buddies and apply them later on as the widgets might not exist yet.
157 auto *label = qobject_cast<QLabel*>(o);
158 if (label == nullptr || propertyName != "buddy"_L1)
159 return false;
160
161 m_buddies.insert(label, value.toString());
162 return true;
163}
164
165void QFormBuilderExtra::applyInternalProperties() const
166{
167 for (auto it = m_buddies.cbegin(), cend = m_buddies.cend(); it != cend; ++it )
168 applyBuddy(it.value(), BuddyApplyAll, it.key());
169}
170
171bool QFormBuilderExtra::applyBuddy(const QString &buddyName, BuddyMode applyMode, QLabel *label)
172{
173 if (buddyName.isEmpty()) {
174 label->setBuddy(nullptr);
175 return false;
176 }
177
178 // QTBUG-96693: Because the same form can be instantiated on multiple
179 // widgets, when for example using a form for custom widgets, there can
180 // exist multiple widgets with the same buddy name in the window. Since
181 // the buddy closest to the label is the correct one to use, we search
182 // for the buddy bottom-up rather than top-down.
183 QWidgetList widgets;
184 QWidget *parent = label->parentWidget();
185 while (parent && widgets.isEmpty()) {
186 widgets = parent->findChildren<QWidget*>(buddyName);
187 parent = parent->parentWidget();
188 }
189
190 if (widgets.isEmpty()) {
191 label->setBuddy(nullptr);
192 return false;
193 }
194
195 for (auto *w : std::as_const(widgets)) {
196 if (applyMode == BuddyApplyAll || !w->isHidden()) {
197 label->setBuddy(w);
198 return true;
199 }
200 }
201
202 label->setBuddy(nullptr);
203 return false;
204}
205
206const QPointer<QWidget> &QFormBuilderExtra::parentWidget() const
207{
208 return m_parentWidget;
209}
210
211bool QFormBuilderExtra::parentWidgetIsSet() const
212{
213 return m_parentWidgetIsSet;
214}
215
216void QFormBuilderExtra::setParentWidget(const QPointer<QWidget> &w)
217{
218 // Parent widget requires special handling of the geometry property.
219 m_parentWidget = w;
220 m_parentWidgetIsSet = true;
221}
222
223void QFormBuilderExtra::storeCustomWidgetData(const QString &className, const DomCustomWidget *d)
224{
225 if (d)
226 m_customWidgetDataHash.insert(className, CustomWidgetData(d));
227}
228
229QString QFormBuilderExtra::customWidgetBaseClass(const QString &className) const
230{
231 const auto it = m_customWidgetDataHash.constFind(className);
232 if (it != m_customWidgetDataHash.constEnd())
233 return it.value().baseClass;
234 return {};
235}
236
237QString QFormBuilderExtra::customWidgetAddPageMethod(const QString &className) const
238{
239 const auto it = m_customWidgetDataHash.constFind(className);
240 if (it != m_customWidgetDataHash.constEnd())
241 return it.value().addPageMethod;
242 return {};
243}
244
245bool QFormBuilderExtra::isCustomWidgetContainer(const QString &className) const
246{
247 const auto it = m_customWidgetDataHash.constFind(className);
248 if (it != m_customWidgetDataHash.constEnd())
249 return it.value().isContainer;
250 return false;
251}
252
253void QFormBuilderExtra::setProcessingLayoutWidget(bool processing)
254{
255 m_layoutWidget = processing;
256}
257
258 bool QFormBuilderExtra::processingLayoutWidget() const
259{
260 return m_layoutWidget;
261}
262void QFormBuilderExtra::setResourceBuilder(QResourceBuilder *builder)
263{
264 if (m_resourceBuilder == builder)
265 return;
266 clearResourceBuilder();
267 m_resourceBuilder = builder;
268}
269
270QResourceBuilder *QFormBuilderExtra::resourceBuilder() const
271{
272 return m_resourceBuilder;
273}
274
275void QFormBuilderExtra::clearResourceBuilder()
276{
277 if (m_resourceBuilder) {
278 delete m_resourceBuilder;
279 m_resourceBuilder = nullptr;
280 }
281}
282
283void QFormBuilderExtra::setTextBuilder(QTextBuilder *builder)
284{
285 if (m_textBuilder == builder)
286 return;
287 clearTextBuilder();
288 m_textBuilder = builder;
289}
290
291QTextBuilder *QFormBuilderExtra::textBuilder() const
292{
293 return m_textBuilder;
294}
295
296void QFormBuilderExtra::clearTextBuilder()
297{
298 if (m_textBuilder) {
299 delete m_textBuilder;
300 m_textBuilder = nullptr;
301 }
302}
303
304void QFormBuilderExtra::registerButtonGroups(const DomButtonGroups *domGroups)
305{
306 const auto &domGroupList = domGroups->elementButtonGroup();
307 for (DomButtonGroup *domGroup : domGroupList)
308 m_buttonGroups.insert(domGroup->attributeName(), ButtonGroupEntry(domGroup, nullptr));
309}
310
311// Utilities for parsing per-cell integer properties that have setters and
312// getters of the form 'setX(int idx, int value)' and 'x(int index)'
313// (converting them to comma-separated string lists and back).
314// Used for layout stretch and grid per-row/column properties.
315
316// Format a list of cell-properties of one dimension as a ','-separated list
317template <class Layout>
318inline QString perCellPropertyToString(const Layout *l, int count, int (Layout::*getter)(int) const)
319{
320 if (count == 0)
321 return {};
322 QString rc;
323 {
324 QTextStream str(&rc);
325 for (int i = 0; i < count; i++) {
326 if (i)
327 str << ',';
328 str << (l->*getter)(i);
329 }
330 }
331 return rc;
332}
333
334// Clear the property, set all cells to 0
335
336template <class Layout>
337inline void clearPerCellValue(Layout *l, int count, void (Layout::*setter)(int,int), int value = 0)
338{
339 for (int i = 0; i < count; i++)
340 (l->*setter)(i, value);
341}
342
343// Parse and set the property from a comma-separated list
344
345template <class Layout>
346inline bool parsePerCellProperty(Layout *l, int count, void (Layout::*setter)(int,int), const QString &s, int defaultValue = 0)
347{
348 if (s.isEmpty()) {
349 clearPerCellValue(l, count, setter, defaultValue);
350 return true;
351 }
352 const auto list = QStringView{s}.split(u',');
353 if (list.isEmpty()) {
354 clearPerCellValue(l, count, setter, defaultValue);
355 return true;
356 }
357 // Apply all values contained in list
358 const int ac = qMin(count, list.size());
359 bool ok = false;
360 int i = 0;
361 for ( ; i < ac; i++) {
362 const int value = list.at(i).toInt(&ok);
363 if (!ok || value < 0)
364 return false;
365 (l->*setter)(i, value);
366 }
367 // Clear rest
368 for ( ; i < count; i++)
369 (l->*setter)(i, defaultValue);
370 return true;
371}
372
373// Read and write stretch
374static QString msgInvalidStretch(const QString &objectName, const QString &stretch)
375{
376 //: Parsing layout stretch values
377 return QCoreApplication::translate("FormBuilder", "Invalid stretch value for '%1': '%2'").arg(objectName, stretch);
378}
379
380void QFormBuilderExtra::getLayoutMargins(const QList<DomProperty*> &properties,
381 int *left, int *top, int *right, int *bottom)
382{
383 if (const auto *p = propertyByName(properties, "leftMargin"))
384 *left = p->elementNumber();
385 if (const auto *p = propertyByName(properties, "topMargin"))
386 *top = p->elementNumber();
387 if (const auto *p = propertyByName(properties, "rightMargin"))
388 *right = p->elementNumber();
389 if (const auto *p = propertyByName(properties, "bottomMargin"))
390 *bottom = p->elementNumber();
391}
392
393bool QFormBuilderExtra::isQFontComboBox(const QWidget *w)
394{
395#if QT_CONFIG(fontcombobox)
396 return qobject_cast<const QFontComboBox*>(w) != nullptr;
397#else
398 Q_UNUSED(w);
399 return false;
400#endif
401}
402
403QString QFormBuilderExtra::boxLayoutStretch(const QBoxLayout *box)
404{
405 return perCellPropertyToString(box, box->count(), &QBoxLayout::stretch);
406}
407
408bool QFormBuilderExtra::setBoxLayoutStretch(const QString &s, QBoxLayout *box)
409{
410 const bool rc = parsePerCellProperty(box, box->count(), &QBoxLayout::setStretch, s);
411 if (!rc)
412 uiLibWarning(msgInvalidStretch(box->objectName(), s));
413 return rc;
414}
415
416void QFormBuilderExtra::clearBoxLayoutStretch(QBoxLayout *box)
417{
418 clearPerCellValue(box, box->count(), &QBoxLayout::setStretch);
419}
420
421QString QFormBuilderExtra::gridLayoutRowStretch(const QGridLayout *grid)
422{
423 return perCellPropertyToString(grid, grid->rowCount(), &QGridLayout::rowStretch);
424}
425
426bool QFormBuilderExtra::setGridLayoutRowStretch(const QString &s, QGridLayout *grid)
427{
428 const bool rc = parsePerCellProperty(grid, grid->rowCount(), &QGridLayout::setRowStretch, s);
429 if (!rc)
430 uiLibWarning(msgInvalidStretch(grid->objectName(), s));
431 return rc;
432}
433
434void QFormBuilderExtra::clearGridLayoutRowStretch(QGridLayout *grid)
435{
436 clearPerCellValue(grid, grid->rowCount(), &QGridLayout::setRowStretch);
437}
438
439QString QFormBuilderExtra::gridLayoutColumnStretch(const QGridLayout *grid)
440{
441 return perCellPropertyToString(grid, grid->columnCount(), &QGridLayout::columnStretch);
442}
443
444bool QFormBuilderExtra::setGridLayoutColumnStretch(const QString &s, QGridLayout *grid)
445{
446 const bool rc = parsePerCellProperty(grid, grid->columnCount(), &QGridLayout::setColumnStretch, s);
447 if (!rc)
448 uiLibWarning(msgInvalidStretch(grid->objectName(), s));
449 return rc;
450}
451
452void QFormBuilderExtra::clearGridLayoutColumnStretch(QGridLayout *grid)
453{
454 clearPerCellValue(grid, grid->columnCount(), &QGridLayout::setColumnStretch);
455}
456
457// Read and write grid layout row/column size limits
458
459static QString msgInvalidMinimumSize(const QString &objectName, const QString &ms)
460{
461 //: Parsing grid layout minimum size values
462 return QCoreApplication::translate("FormBuilder", "Invalid minimum size for '%1': '%2'").arg(objectName, ms);
463}
464
465QString QFormBuilderExtra::gridLayoutRowMinimumHeight(const QGridLayout *grid)
466{
467 return perCellPropertyToString(grid, grid->rowCount(), &QGridLayout::rowMinimumHeight);
468}
469
470bool QFormBuilderExtra::setGridLayoutRowMinimumHeight(const QString &s, QGridLayout *grid)
471{
472 const bool rc = parsePerCellProperty(grid, grid->rowCount(), &QGridLayout::setRowMinimumHeight, s);
473 if (!rc)
474 uiLibWarning(msgInvalidMinimumSize(grid->objectName(), s));
475 return rc;
476}
477
478void QFormBuilderExtra::clearGridLayoutRowMinimumHeight(QGridLayout *grid)
479{
480 clearPerCellValue(grid, grid->rowCount(), &QGridLayout::setRowMinimumHeight);
481}
482
483QString QFormBuilderExtra::gridLayoutColumnMinimumWidth(const QGridLayout *grid)
484{
485 return perCellPropertyToString(grid, grid->columnCount(), &QGridLayout::columnMinimumWidth);
486}
487
488bool QFormBuilderExtra::setGridLayoutColumnMinimumWidth(const QString &s, QGridLayout *grid)
489{
490 const bool rc = parsePerCellProperty(grid, grid->columnCount(), &QGridLayout::setColumnMinimumWidth, s);
491 if (!rc)
492 uiLibWarning(msgInvalidMinimumSize(grid->objectName(), s));
493 return rc;
494}
495
496void QFormBuilderExtra::clearGridLayoutColumnMinimumWidth(QGridLayout *grid)
497{
498 clearPerCellValue(grid, grid->columnCount(), &QGridLayout::setColumnMinimumWidth);
499}
500
501void QFormBuilderExtra::setPixmapProperty(DomProperty *p, const std::pair<QString, QString> &ip)
502{
503 auto *pix = new DomResourcePixmap;
504 if (!ip.second.isEmpty())
505 pix->setAttributeResource(ip.second);
506
507 pix->setText(ip.first);
508
509 p->setAttributeName("pixmap"_L1);
510 p->setElementPixmap(pix);
511}
512
513void QFormBuilderExtra::setupColorGroup(QPalette *palette, QPalette::ColorGroup colorGroup,
514 const DomColorGroup *group)
515{
516 // old format
517 const auto &colors = group->elementColor();
518 for (int role = 0; role < colors.size(); ++role) {
519 const DomColor *color = colors.at(role);
520 const QColor c(color->elementRed(), color->elementGreen(), color->elementBlue());
521 palette->setColor(colorGroup, QPalette::ColorRole(role), c);
522 }
523
524 // new format
525 const QMetaEnum colorRole_enum = metaEnum<QAbstractFormBuilderGadget>("colorRole");
526
527 const auto colorRoles = group->elementColorRole();
528 for (const DomColorRole *colorRole : colorRoles) {
529 if (colorRole->hasAttributeRole()) {
530 const auto &roleName = colorRole->attributeRole().toLatin1();
531 const int r = colorRole_enum.keyToValue(roleName.constData());
532 if (r != -1) {
533 const QBrush br = setupBrush(colorRole->elementBrush());
534 palette->setBrush(colorGroup, static_cast<QPalette::ColorRole>(r), br);
535 }
536 }
537 }
538}
539
540DomColorGroup *QFormBuilderExtra::saveColorGroup(const QPalette &palette,
541 QPalette::ColorGroup colorGroup)
542{
543
544 const QMetaEnum colorRole_enum = metaEnum<QAbstractFormBuilderGadget>("colorRole");
545
546 auto *group = new DomColorGroup();
547 QList<DomColorRole *> colorRoles;
548
549 for (int r = QPalette::WindowText; r < QPalette::NColorRoles; ++r) {
550 const auto role = static_cast<QPalette::ColorRole>(r);
551 if (palette.isBrushSet(colorGroup, role)) {
552 const QBrush &br = palette.brush(colorGroup, role);
553 auto *colorRole = new DomColorRole();
554 colorRole->setElementBrush(saveBrush(br));
555 colorRole->setAttributeRole(QLatin1StringView(colorRole_enum.valueToKey(role)));
556 colorRoles.append(colorRole);
557 }
558 }
559
560 group->setElementColorRole(colorRoles);
561 return group;
562}
563
564DomPalette *QFormBuilderExtra::savePalette(const QPalette &palette)
565{
566 auto *dom = new DomPalette();
567 dom->setElementActive(QFormBuilderExtra::saveColorGroup(palette, QPalette::Active));
568 dom->setElementInactive(QFormBuilderExtra::saveColorGroup(palette, QPalette::Inactive));
569 dom->setElementDisabled(QFormBuilderExtra::saveColorGroup(palette, QPalette::Disabled));
570
571 return dom;
572}
573
574QPalette QFormBuilderExtra::loadPalette(const DomPalette *dom)
575{
576 QPalette palette;
577
578 if (dom->elementActive())
579 QFormBuilderExtra::setupColorGroup(&palette, QPalette::Active, dom->elementActive());
580
581 if (dom->elementInactive())
582 QFormBuilderExtra::setupColorGroup(&palette, QPalette::Inactive, dom->elementInactive());
583
584 if (dom->elementDisabled())
585 QFormBuilderExtra::setupColorGroup(&palette, QPalette::Disabled, dom->elementDisabled());
586
587 palette.setCurrentColorGroup(QPalette::Active);
588 return palette;
589}
590
591QBrush QFormBuilderExtra::setupBrush(const DomBrush *brush)
592{
593 QBrush br;
594 if (!brush->hasAttributeBrushStyle())
595 return br;
596
597 const Qt::BrushStyle style = enumKeyOfObjectToValue<QAbstractFormBuilderGadget, Qt::BrushStyle>("brushStyle",
598 brush->attributeBrushStyle().toLatin1().constData());
599
600 if (style == Qt::LinearGradientPattern ||
601 style == Qt::RadialGradientPattern ||
602 style == Qt::ConicalGradientPattern) {
603 const QMetaEnum gradientType_enum = metaEnum<QAbstractFormBuilderGadget>("gradientType");
604 const QMetaEnum gradientSpread_enum = metaEnum<QAbstractFormBuilderGadget>("gradientSpread");
605 const QMetaEnum gradientCoordinate_enum = metaEnum<QAbstractFormBuilderGadget>("gradientCoordinate");
606
607 const DomGradient *gradient = brush->elementGradient();
608 const auto type = enumKeyToValue<QGradient::Type>(
609 gradientType_enum, gradient->attributeType().toLatin1().constData());
610
611 QGradient *gr = nullptr;
612
613 if (type == QGradient::LinearGradient) {
614 gr = new QLinearGradient(QPointF(gradient->attributeStartX(), gradient->attributeStartY()),
615 QPointF(gradient->attributeEndX(), gradient->attributeEndY()));
616 } else if (type == QGradient::RadialGradient) {
617 gr = new QRadialGradient(QPointF(gradient->attributeCentralX(), gradient->attributeCentralY()),
618 gradient->attributeRadius(),
619 QPointF(gradient->attributeFocalX(), gradient->attributeFocalY()));
620 } else if (type == QGradient::ConicalGradient) {
621 gr = new QConicalGradient(QPointF(gradient->attributeCentralX(), gradient->attributeCentralY()),
622 gradient->attributeAngle());
623 }
624 if (!gr)
625 return br;
626
627 const auto spread = enumKeyToValue<QGradient::Spread>(
628 gradientSpread_enum, gradient->attributeSpread().toLatin1().constData());
629 gr->setSpread(spread);
630
631 const auto coord = enumKeyToValue<QGradient::CoordinateMode>(
632 gradientCoordinate_enum,
633 gradient->attributeCoordinateMode().toLatin1().constData());
634 gr->setCoordinateMode(coord);
635
636 const auto &stops = gradient->elementGradientStop();
637 for (const DomGradientStop *stop : stops) {
638 const DomColor *color = stop->elementColor();
639 gr->setColorAt(stop->attributePosition(), QColor::fromRgb(color->elementRed(),
640 color->elementGreen(), color->elementBlue(), color->attributeAlpha()));
641 }
642 br = QBrush(*gr);
643 delete gr;
644 } else if (style == Qt::TexturePattern) {
645 const DomProperty *texture = brush->elementTexture();
646 if (texture && texture->kind() == DomProperty::Pixmap) {
647 br.setTexture({});
648 }
649 } else {
650 const DomColor *color = brush->elementColor();
651 br.setColor(QColor::fromRgb(color->elementRed(),
652 color->elementGreen(), color->elementBlue(), color->attributeAlpha()));
653 br.setStyle((Qt::BrushStyle)style);
654 }
655 return br;
656}
657
658DomBrush *QFormBuilderExtra::saveBrush(const QBrush &br)
659{
660 const QMetaEnum brushStyle_enum = metaEnum<QAbstractFormBuilderGadget>("brushStyle");
661
662 auto *brush = new DomBrush();
663 const Qt::BrushStyle style = br.style();
664 brush->setAttributeBrushStyle(QLatin1StringView(brushStyle_enum.valueToKey(style)));
665 if (style == Qt::LinearGradientPattern ||
666 style == Qt::RadialGradientPattern ||
667 style == Qt::ConicalGradientPattern) {
668 const QMetaEnum gradientType_enum = metaEnum<QAbstractFormBuilderGadget>("gradientType");
669 const QMetaEnum gradientSpread_enum = metaEnum<QAbstractFormBuilderGadget>("gradientSpread");
670 const QMetaEnum gradientCoordinate_enum = metaEnum<QAbstractFormBuilderGadget>("gradientCoordinate");
671
672 auto *gradient = new DomGradient();
673 const QGradient *gr = br.gradient();
674 const QGradient::Type type = gr->type();
675 gradient->setAttributeType(QLatin1StringView(gradientType_enum.valueToKey(type)));
676 gradient->setAttributeSpread(QLatin1StringView(gradientSpread_enum.valueToKey(gr->spread())));
677 gradient->setAttributeCoordinateMode(QLatin1StringView(gradientCoordinate_enum.valueToKey(gr->coordinateMode())));
678 QList<DomGradientStop *> stops;
679 const QGradientStops st = gr->stops();
680 for (const QGradientStop &pair : st) {
681 auto *stop = new DomGradientStop();
682 stop->setAttributePosition(pair.first);
683 auto *color = new DomColor();
684 color->setElementRed(pair.second.red());
685 color->setElementGreen(pair.second.green());
686 color->setElementBlue(pair.second.blue());
687 color->setAttributeAlpha(pair.second.alpha());
688 stop->setElementColor(color);
689 stops.append(stop);
690 }
691 gradient->setElementGradientStop(stops);
692 if (type == QGradient::LinearGradient) {
693 const auto *lgr = static_cast<const QLinearGradient *>(gr);
694 gradient->setAttributeStartX(lgr->start().x());
695 gradient->setAttributeStartY(lgr->start().y());
696 gradient->setAttributeEndX(lgr->finalStop().x());
697 gradient->setAttributeEndY(lgr->finalStop().y());
698 } else if (type == QGradient::RadialGradient) {
699 const auto *rgr = static_cast<const QRadialGradient *>(gr);
700 gradient->setAttributeCentralX(rgr->center().x());
701 gradient->setAttributeCentralY(rgr->center().y());
702 gradient->setAttributeFocalX(rgr->focalPoint().x());
703 gradient->setAttributeFocalY(rgr->focalPoint().y());
704 gradient->setAttributeRadius(rgr->radius());
705 } else if (type == QGradient::ConicalGradient) {
706 const auto *cgr = static_cast<const QConicalGradient *>(gr);
707 gradient->setAttributeCentralX(cgr->center().x());
708 gradient->setAttributeCentralY(cgr->center().y());
709 gradient->setAttributeAngle(cgr->angle());
710 }
711
712 brush->setElementGradient(gradient);
713 } else if (style == Qt::TexturePattern) {
714 const QPixmap pixmap = br.texture();
715 if (!pixmap.isNull()) {
716 auto *p = new DomProperty;
717 QFormBuilderExtra::setPixmapProperty(p, {});
718 brush->setElementTexture(p);
719 }
720 } else {
721 const QColor &c = br.color();
722 auto *color = new DomColor();
723 color->setElementRed(c.red());
724 color->setElementGreen(c.green());
725 color->setElementBlue(c.blue());
726 color->setAttributeAlpha(c.alpha());
727 brush->setElementColor(color);
728 }
729 return brush;
730}
731
732DomProperty *QFormBuilderExtra::propertyByName(const QList<DomProperty*> &properties,
733 QAnyStringView needle)
734{
735 auto it = std::find_if(properties.cbegin(), properties.cend(),
736 [needle](const DomProperty *p) {
737 return p->attributeName() == needle; });
738 return it != properties.cend() ? *it : nullptr;
739}
740
741// ------------ QFormBuilderStrings
742
743QFormBuilderStrings::QFormBuilderStrings() :
744 itemRoles {
745 {Qt::FontRole, "font"_L1},
746 {Qt::TextAlignmentRole, "textAlignment"_L1},
747 {Qt::BackgroundRole, "background"_L1},
748 {Qt::ForegroundRole, "foreground"_L1},
749 {Qt::CheckStateRole, "checkState"_L1}
750 },
751 itemTextRoles { // This must be first for the loop below
752 { {Qt::EditRole, Qt::DisplayPropertyRole}, textAttribute},
753 { {Qt::ToolTipRole, Qt::ToolTipPropertyRole}, toolTipAttribute},
754 { {Qt::StatusTipRole, Qt::StatusTipPropertyRole}, "statusTip"_L1},
755 { {Qt::WhatsThisRole, Qt::WhatsThisPropertyRole}, whatsThisAttribute}
756 }
757{
758 for (const RoleNName &it : std::as_const(itemRoles))
759 treeItemRoleHash.insert(it.second, it.first);
760
761 // Note: this skips the first item!
762 auto it = itemTextRoles.constBegin();
763 const auto end = itemTextRoles.constEnd();
764 while (++it != end)
765 treeItemTextRoleHash.insert(it->second, it->first);
766}
767
768const QFormBuilderStrings &QFormBuilderStrings::instance()
769{
770 static const QFormBuilderStrings rc;
771 return rc;
772}
773
774#ifdef QFORMINTERNAL_NAMESPACE
775} // namespace QFormInternal
776#endif
777
778QT_END_NAMESPACE
static QString msgInvalidMinimumSize(const QString &objectName, const QString &ms)
void clearPerCellValue(Layout *l, int count, void(Layout::*setter)(int, int), int value=0)
bool parsePerCellProperty(Layout *l, int count, void(Layout::*setter)(int, int), const QString &s, int defaultValue=0)
static QString msgInvalidStretch(const QString &objectName, const QString &stretch)
QString perCellPropertyToString(const Layout *l, int count, int(Layout::*getter)(int) const)
static bool readUiAttributes(QXmlStreamReader &reader, const QString &language, QString *errorMessage)
void uiLibWarning(const QString &message)
static QString msgXmlError(const QXmlStreamReader &reader)
Combined button and popup list for selecting options.
const QString & asString(const QString &s)
Definition qstring.h:1678
#define qPrintable(string)
Definition qstring.h:1683