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