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
designerpropertymanager.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3// Qt-Security score:significant reason:default
4
8#include "pixmapeditor.h"
10#include "texteditor.h"
11#include "resetdecorator.h"
15
16#include <formwindowbase_p.h>
17#include <formwindowmanager.h>
18#include <formwindow.h>
19#include <propertysheet.h>
20#include <qextensionmanager.h>
21#include <formwindowcursor.h>
22#include <stylesheeteditor_p.h>
23#include <richtexteditor_p.h>
24#include <plaintexteditor_p.h>
25#include <iconloader_p.h>
26#include <iconselector_p.h>
27#include <abstractdialoggui_p.h>
28
29#include <QtWidgets/qapplication.h>
30#include <QtWidgets/qcombobox.h>
31#include <QtWidgets/qlabel.h>
32#include <QtWidgets/qtoolbutton.h>
33#include <QtWidgets/qboxlayout.h>
34#include <QtWidgets/qlineedit.h>
35#include <QtWidgets/qdialogbuttonbox.h>
36#include <QtWidgets/qpushbutton.h>
37#include <QtWidgets/qfiledialog.h>
38#include <QtWidgets/qmenu.h>
39#include <QtWidgets/qkeysequenceedit.h>
40
41#include <QtGui/qaction.h>
42#include <QtGui/qevent.h>
43
44#include <QtCore/qdebug.h>
45#include <QtCore/qfileinfo.h>
46#include <QtCore/qurl.h>
49
50using namespace Qt::StringLiterals;
52static constexpr auto resettableAttributeC = "resettable"_L1;
53static constexpr auto flagsAttributeC = "flags"_L1;
54static constexpr auto validationModesAttributeC = "validationMode"_L1;
55static constexpr auto superPaletteAttributeC = "superPalette"_L1;
56static constexpr auto defaultResourceAttributeC = "defaultResource"_L1;
57static constexpr auto fontAttributeC = "font"_L1;
58static constexpr auto themeAttributeC = "theme"_L1;
59static constexpr auto themeEnumAttributeC = "themeEnum"_L1;
60
64
65
69
70QT_END_NAMESPACE
71
72Q_DECLARE_METATYPE(DesignerFlagPropertyType)
73Q_DECLARE_METATYPE(DesignerAlignmentPropertyType)
74
75QT_BEGIN_NAMESPACE
76
77namespace qdesigner_internal {
78
79template <class PropertySheetValue>
80void TranslatablePropertyManager<PropertySheetValue>::initialize(QtVariantPropertyManager *m,
81 QtProperty *property,
82 const PropertySheetValue &value)
83{
84 m_values.insert(property, value);
85
86 QtVariantProperty *translatable = m->addProperty(QMetaType::Bool, DesignerPropertyManager::tr("translatable"));
87 translatable->setValue(value.translatable());
88 m_valueToTranslatable.insert(property, translatable);
89 m_translatableToValue.insert(translatable, property);
90 property->addSubProperty(translatable);
91
92 if (!DesignerPropertyManager::useIdBasedTranslations()) {
93 QtVariantProperty *disambiguation =
94 m->addProperty(QMetaType::QString, DesignerPropertyManager::tr("disambiguation"));
95 disambiguation->setValue(value.disambiguation());
96 m_valueToDisambiguation.insert(property, disambiguation);
97 m_disambiguationToValue.insert(disambiguation, property);
98 property->addSubProperty(disambiguation);
99 }
100
101 QtVariantProperty *comment = m->addProperty(QMetaType::QString, DesignerPropertyManager::tr("comment"));
102 comment->setValue(value.comment());
103 m_valueToComment.insert(property, comment);
104 m_commentToValue.insert(comment, property);
105 property->addSubProperty(comment);
106
107 if (DesignerPropertyManager::useIdBasedTranslations()) {
108 QtVariantProperty *id = m->addProperty(QMetaType::QString, DesignerPropertyManager::tr("id"));
109 id->setValue(value.id());
110 m_valueToId.insert(property, id);
111 m_idToValue.insert(id, property);
112 property->addSubProperty(id);
113 }
114}
115
116template <class PropertySheetValue>
117bool TranslatablePropertyManager<PropertySheetValue>::uninitialize(QtProperty *property)
118{
119 if (QtProperty *comment = m_valueToComment.value(property))
120 delete comment;
121 else
122 return false;
123 if (QtProperty *translatable = m_valueToTranslatable.value(property))
124 delete translatable;
125 if (QtProperty *disambiguation = m_valueToDisambiguation.value(property))
126 delete disambiguation;
127 if (QtProperty *id = m_valueToId.value(property))
128 delete id;
129
130 m_values.remove(property);
131 m_valueToComment.remove(property);
132 m_valueToTranslatable.remove(property);
133 m_valueToDisambiguation.remove(property);
134 m_valueToId.remove(property);
135 return true;
136}
137
138template <class PropertySheetValue>
139bool TranslatablePropertyManager<PropertySheetValue>::destroy(QtProperty *subProperty)
140{
141 const auto commentToValueIt = m_commentToValue.find(subProperty);
142 if (commentToValueIt != m_commentToValue.end()) {
143 m_valueToComment.remove(commentToValueIt.value());
144 m_commentToValue.erase(commentToValueIt);
145 return true;
146 }
147 const auto translatableToValueIt = m_translatableToValue.find(subProperty);
148 if (translatableToValueIt != m_translatableToValue.end()) {
149 m_valueToTranslatable.remove(translatableToValueIt.value());
150 m_translatableToValue.erase(translatableToValueIt);
151 return true;
152 }
153 const auto disambiguationToValueIt = m_disambiguationToValue.find(subProperty);
154 if (disambiguationToValueIt != m_disambiguationToValue.end()) {
155 m_valueToDisambiguation.remove(disambiguationToValueIt.value());
156 m_disambiguationToValue.erase(disambiguationToValueIt);
157 return true;
158 }
159 const auto idToValueIt = m_idToValue.find(subProperty);
160 if (idToValueIt != m_idToValue.end()) {
161 m_valueToId.remove(idToValueIt.value());
162 m_idToValue.erase(idToValueIt);
163 return true;
164 }
165 return false;
166}
167
168template <class PropertySheetValue>
169int TranslatablePropertyManager<PropertySheetValue>::valueChanged(QtVariantPropertyManager *m,
170 QtProperty *propertyIn,
171 const QVariant &value)
172{
173 if (QtProperty *property = m_translatableToValue.value(propertyIn, 0)) {
174 const PropertySheetValue oldValue = m_values.value(property);
175 PropertySheetValue newValue = oldValue;
176 newValue.setTranslatable(value.toBool());
177 if (newValue != oldValue) {
178 m->variantProperty(property)->setValue(QVariant::fromValue(newValue));
179 return DesignerPropertyManager::Changed;
180 }
181 return DesignerPropertyManager::Unchanged;
182 }
183 if (QtProperty *property = m_commentToValue.value(propertyIn)) {
184 const PropertySheetValue oldValue = m_values.value(property);
185 PropertySheetValue newValue = oldValue;
186 newValue.setComment(value.toString());
187 if (newValue != oldValue) {
188 m->variantProperty(property)->setValue(QVariant::fromValue(newValue));
189 return DesignerPropertyManager::Changed;
190 }
191 return DesignerPropertyManager::Unchanged;
192 }
193 if (QtProperty *property = m_disambiguationToValue.value(propertyIn, 0)) {
194 const PropertySheetValue oldValue = m_values.value(property);
195 PropertySheetValue newValue = oldValue;
196 newValue.setDisambiguation(value.toString());
197 if (newValue != oldValue) {
198 m->variantProperty(property)->setValue(QVariant::fromValue(newValue));
199 return DesignerPropertyManager::Changed;
200 }
201 return DesignerPropertyManager::Unchanged;
202 }
203 if (QtProperty *property = m_idToValue.value(propertyIn)) {
204 const PropertySheetValue oldValue = m_values.value(property);
205 PropertySheetValue newValue = oldValue;
206 newValue.setId(value.toString());
207 if (newValue != oldValue) {
208 m->variantProperty(property)->setValue(QVariant::fromValue(newValue));
209 return DesignerPropertyManager::Changed;
210 }
211 return DesignerPropertyManager::Unchanged;
212 }
213 return DesignerPropertyManager::NoMatch;
214}
215
216template <class PropertySheetValue>
217int TranslatablePropertyManager<PropertySheetValue>::setValue(QtVariantPropertyManager *m,
218 QtProperty *property,
219 int expectedTypeId,
220 const QVariant &variantValue)
221{
222 const auto it = m_values.find(property);
223 if (it == m_values.end())
224 return DesignerPropertyManager::NoMatch;
225 if (variantValue.userType() != expectedTypeId)
226 return DesignerPropertyManager::NoMatch;
227 const PropertySheetValue value = qvariant_cast<PropertySheetValue>(variantValue);
228 if (value == it.value())
229 return DesignerPropertyManager::Unchanged;
230 if (QtVariantProperty *comment = m->variantProperty(m_valueToComment.value(property)))
231 comment->setValue(value.comment());
232 if (QtVariantProperty *translatable = m->variantProperty(m_valueToTranslatable.value(property)))
233 translatable->setValue(value.translatable());
234 if (QtVariantProperty *disambiguation = m->variantProperty(m_valueToDisambiguation.value(property)))
235 disambiguation->setValue(value.disambiguation());
236 if (QtVariantProperty *id = m->variantProperty(m_valueToId.value(property)))
237 id->setValue(value.id());
238 it.value() = value;
239 return DesignerPropertyManager::Changed;
240}
241
242template <class PropertySheetValue>
243bool TranslatablePropertyManager<PropertySheetValue>::value(const QtProperty *property, QVariant *rc) const
244{
245 const auto it = m_values.constFind(property);
246 if (it == m_values.constEnd())
247 return false;
248 *rc = QVariant::fromValue(it.value());
249 return true;
250}
251
252// ------------ DesignerPropertyManager:
253
254DesignerPropertyManager::DesignerPropertyManager(QDesignerFormEditorInterface *core, QObject *parent) :
255 QtVariantPropertyManager(parent),
256 m_changingSubValue(false),
257 m_core(core),
258 m_object(nullptr),
259 m_sourceOfChange(nullptr)
260{
261 connect(this, &QtVariantPropertyManager::valueChanged,
262 this, &DesignerPropertyManager::slotValueChanged);
263 connect(this, & QtAbstractPropertyManager::propertyDestroyed,
264 this, &DesignerPropertyManager::slotPropertyDestroyed);
265}
266
267DesignerPropertyManager::~DesignerPropertyManager()
268{
269 clear();
270}
271
272bool DesignerPropertyManager::m_IdBasedTranslations = false;
273
274template <class IntT>
275static int bitCount(IntT mask)
276{
277 int count = 0;
278 for (; mask; count++)
279 mask &= mask - 1; // clear the least significant bit set
280 return count;
281}
282
283int DesignerPropertyManager::alignToIndexH(uint align) const
284{
285 if (align & Qt::AlignLeft)
286 return 0;
287 if (align & Qt::AlignHCenter)
288 return 1;
289 if (align & Qt::AlignRight)
290 return 2;
291 if (align & Qt::AlignJustify)
292 return 3;
293 return 0;
294}
295
296int DesignerPropertyManager::alignToIndexV(uint align) const
297{
298 if (align & Qt::AlignTop)
299 return 0;
300 if (align & Qt::AlignVCenter)
301 return 1;
302 if (align & Qt::AlignBottom)
303 return 2;
304 return 1;
305}
306
307uint DesignerPropertyManager::indexHToAlign(int idx) const
308{
309 switch (idx) {
310 case 0: return Qt::AlignLeft;
311 case 1: return Qt::AlignHCenter;
312 case 2: return Qt::AlignRight;
313 case 3: return Qt::AlignJustify;
314 default: break;
315 }
316 return Qt::AlignLeft;
317}
318
319uint DesignerPropertyManager::indexVToAlign(int idx) const
320{
321 switch (idx) {
322 case 0: return Qt::AlignTop;
323 case 1: return Qt::AlignVCenter;
324 case 2: return Qt::AlignBottom;
325 default: break;
326 }
327 return Qt::AlignVCenter;
328}
329
330QString DesignerPropertyManager::indexHToString(int idx) const
331{
332 switch (idx) {
333 case 0: return tr("AlignLeft");
334 case 1: return tr("AlignHCenter");
335 case 2: return tr("AlignRight");
336 case 3: return tr("AlignJustify");
337 default: break;
338 }
339 return tr("AlignLeft");
340}
341
342QString DesignerPropertyManager::indexVToString(int idx) const
343{
344 switch (idx) {
345 case 0: return tr("AlignTop");
346 case 1: return tr("AlignVCenter");
347 case 2: return tr("AlignBottom");
348 default: break;
349 }
350 return tr("AlignVCenter");
351}
352
353void DesignerPropertyManager::slotValueChanged(QtProperty *property, const QVariant &value)
354{
355 if (m_changingSubValue)
356 return;
357 bool enableSubPropertyHandling = true;
358
359 // Find a matching manager
360 int subResult = m_stringManager.valueChanged(this, property, value);
361 if (subResult == NoMatch)
362 subResult = m_keySequenceManager.valueChanged(this, property, value);
363 if (subResult == NoMatch)
364 subResult = m_stringListManager.valueChanged(this, property, value);
365 if (subResult == NoMatch)
366 subResult = m_brushManager.valueChanged(this, property, value);
367 if (subResult == NoMatch)
368 subResult = m_fontManager.valueChanged(this, property, value);
369 if (subResult != NoMatch) {
370 if (subResult == Changed)
371 emit valueChanged2(property, value, enableSubPropertyHandling);
372 return;
373 }
374
375 auto *parentItem = property->parentProperty();
376 if (m_flagValues.contains(parentItem)) {
377 auto *flagProperty = parentItem;
378 const auto subFlags = m_propertyToFlags.value(flagProperty);
379 const qsizetype subFlagCount = subFlags.size();
380 // flag changed
381 const bool subValue = variantProperty(property)->value().toBool();
382 const qsizetype subIndex = subFlags.indexOf(property);
383 if (subIndex < 0)
384 return;
385
386 uint newValue = 0;
387
388 m_changingSubValue = true;
389
390 FlagData data = m_flagValues.value(flagProperty);
391 const auto values = data.values;
392 // Compute new value, without including (additional) supermasks
393 if (values.at(subIndex) == 0) {
394 for (qsizetype i = 0; i < subFlagCount; ++i) {
395 QtVariantProperty *subFlag = variantProperty(subFlags.at(i));
396 subFlag->setValue(i == subIndex);
397 }
398 } else {
399 if (subValue)
400 newValue = values.at(subIndex); // value mask of subValue
401 for (qsizetype i = 0; i < subFlagCount; ++i) {
402 QtVariantProperty *subFlag = variantProperty(subFlags.at(i));
403 if (subFlag->value().toBool() && bitCount(values.at(i)) == 1)
404 newValue |= values.at(i);
405 }
406 if (newValue == 0) {
407 // Uncheck all items except 0-mask
408 for (qsizetype i = 0; i < subFlagCount; ++i) {
409 QtVariantProperty *subFlag = variantProperty(subFlags.at(i));
410 subFlag->setValue(values.at(i) == 0);
411 }
412 } else if (newValue == data.val) {
413 if (!subValue && bitCount(values.at(subIndex)) > 1) {
414 // We unchecked something, but the original value still holds
415 variantProperty(property)->setValue(true);
416 }
417 } else {
418 // Make sure 0-mask is not selected
419 for (qsizetype i = 0; i < subFlagCount; ++i) {
420 QtVariantProperty *subFlag = variantProperty(subFlags.at(i));
421 if (values.at(i) == 0)
422 subFlag->setValue(false);
423 }
424 // Check/uncheck proper masks
425 if (subValue) {
426 // Make sure submasks and supermasks are selected
427 for (qsizetype i = 0; i < subFlagCount; ++i) {
428 QtVariantProperty *subFlag = variantProperty(subFlags.at(i));
429 const uint vi = values.at(i);
430 if ((vi != 0) && ((vi & newValue) == vi) && !subFlag->value().toBool())
431 subFlag->setValue(true);
432 }
433 } else {
434 // Make sure supermasks are not selected if they're no longer valid
435 for (qsizetype i = 0; i < subFlagCount; ++i) {
436 QtVariantProperty *subFlag = variantProperty(subFlags.at(i));
437 const uint vi = values.at(i);
438 if (subFlag->value().toBool() && ((vi & newValue) != vi))
439 subFlag->setValue(false);
440 }
441 }
442 }
443 }
444 m_changingSubValue = false;
445 data.val = newValue;
446 QVariant v;
447 v.setValue(data.val);
448 variantProperty(flagProperty)->setValue(v);
449 } else if (QtProperty *alignProperty = m_alignHToProperty.value(property, 0)) {
450 const uint v = m_alignValues.value(alignProperty);
451 const uint newValue = indexHToAlign(value.toInt()) | indexVToAlign(alignToIndexV(v));
452 if (v == newValue)
453 return;
454
455 variantProperty(alignProperty)->setValue(newValue);
456 } else if (QtProperty *alignProperty = m_alignVToProperty.value(property, 0)) {
457 const uint v = m_alignValues.value(alignProperty);
458 const uint newValue = indexVToAlign(value.toInt()) | indexHToAlign(alignToIndexH(v));
459 if (v == newValue)
460 return;
461
462 variantProperty(alignProperty)->setValue(newValue);
463 } else if (m_iconValues.contains(parentItem)) {
464 QtProperty *iProperty = parentItem;
465 QtVariantProperty *iconProperty = variantProperty(iProperty);
466 PropertySheetIconValue icon = qvariant_cast<PropertySheetIconValue>(iconProperty->value());
467 const auto itState = m_iconSubPropertyToState.constFind(property);
468 if (itState != m_iconSubPropertyToState.constEnd()) {
469 const auto pair = m_iconSubPropertyToState.value(property);
470 icon.setPixmap(pair.first, pair.second, qvariant_cast<PropertySheetPixmapValue>(value));
471 } else if (attributeValue(property, themeEnumAttributeC).toBool()) {
472 icon.setThemeEnum(value.toInt());
473 } else { // must be theme property
474 icon.setTheme(value.toString());
475 }
476 QtProperty *origSourceOfChange = m_sourceOfChange;
477 if (!origSourceOfChange)
478 m_sourceOfChange = property;
479 iconProperty->setValue(QVariant::fromValue(icon));
480 if (!origSourceOfChange)
481 m_sourceOfChange = origSourceOfChange;
482 } else if (m_iconValues.contains(property)) {
483 enableSubPropertyHandling = m_sourceOfChange;
484 }
485 emit valueChanged2(property, value, enableSubPropertyHandling);
486}
487
488void DesignerPropertyManager::slotPropertyDestroyed(QtProperty *property)
489{
490 auto *parentItem = property->parentProperty();
491 if (m_flagValues.contains(parentItem)) {
492 auto *flagProperty = parentItem;
493 const auto it = m_propertyToFlags.find(flagProperty);
494 auto &propertyList = it.value();
495 propertyList.replace(propertyList.indexOf(property), 0);
496 } else if (QtProperty *alignProperty = m_alignHToProperty.value(property, 0)) {
497 m_propertyToAlignH.remove(alignProperty);
498 m_alignHToProperty.remove(property);
499 } else if (QtProperty *alignProperty = m_alignVToProperty.value(property, 0)) {
500 m_propertyToAlignV.remove(alignProperty);
501 m_alignVToProperty.remove(property);
502 } else if (m_stringManager.destroy(property)
503 || m_stringListManager.destroy(property)
504 || m_keySequenceManager.destroy(property)) {
505 } else if (m_iconValues.contains(parentItem)) {
506 auto *iconProperty = parentItem;
507 if (m_propertyToTheme.value(iconProperty) == property) {
508 m_propertyToTheme.remove(iconProperty);
509 } else if (m_propertyToThemeEnum.value(iconProperty) == property) {
510 m_propertyToThemeEnum.remove(iconProperty);
511 } else {
512 const auto it = m_propertyToIconSubProperties.find(iconProperty);
513 const auto state = m_iconSubPropertyToState.value(property);
514 auto &propertyList = it.value();
515 propertyList.remove(state);
516 m_iconSubPropertyToState.remove(property);
517 }
518 } else {
519 m_fontManager.slotPropertyDestroyed(property);
520 m_brushManager.slotPropertyDestroyed(property);
521 }
522 m_alignDefault.remove(property);
523}
524
525QStringList DesignerPropertyManager::attributes(int propertyType) const
526{
527 if (!isPropertyTypeSupported(propertyType))
528 return QStringList();
529
530 QStringList list = QtVariantPropertyManager::attributes(propertyType);
531 if (propertyType == designerFlagTypeId()) {
532 list.append(flagsAttributeC);
533 } else if (propertyType == designerPixmapTypeId()) {
534 list.append(defaultResourceAttributeC);
535 } else if (propertyType == designerIconTypeId()) {
536 list.append(defaultResourceAttributeC);
537 } else if (propertyType == designerStringTypeId() || propertyType == QMetaType::QString) {
538 list.append(validationModesAttributeC);
539 list.append(fontAttributeC);
540 list.append(themeAttributeC);
541 } else if (propertyType == QMetaType::QPalette) {
542 list.append(superPaletteAttributeC);
543 } else if (propertyType == QMetaType::Int) {
544 list.append(themeEnumAttributeC);
545 }
546 list.append(resettableAttributeC);
547 return list;
548}
549
550int DesignerPropertyManager::attributeType(int propertyType, const QString &attribute) const
551{
552 if (!isPropertyTypeSupported(propertyType))
553 return 0;
554
555 if (propertyType == designerFlagTypeId() && attribute == flagsAttributeC)
556 return designerFlagListTypeId();
557 if (propertyType == designerPixmapTypeId() && attribute == defaultResourceAttributeC)
558 return QMetaType::QPixmap;
559 if (propertyType == designerIconTypeId() && attribute == defaultResourceAttributeC)
560 return QMetaType::QIcon;
561 if (attribute == resettableAttributeC)
562 return QMetaType::Bool;
563 if (propertyType == designerStringTypeId() || propertyType == QMetaType::QString) {
564 if (attribute == validationModesAttributeC)
565 return QMetaType::Int;
566 if (attribute == fontAttributeC)
567 return QMetaType::QFont;
568 if (attribute == themeAttributeC)
569 return QMetaType::Bool;
570 }
571 if (propertyType == QMetaType::QPalette && attribute == superPaletteAttributeC)
572 return QMetaType::QPalette;
573
574 return QtVariantPropertyManager::attributeType(propertyType, attribute);
575}
576
577QVariant DesignerPropertyManager::attributeValue(const QtProperty *property, const QString &attribute) const
578{
579 if (attribute == resettableAttributeC) {
580 const auto it = m_resetMap.constFind(property);
581 if (it != m_resetMap.constEnd())
582 return it.value();
583 }
584
585 if (attribute == flagsAttributeC) {
586 const auto it = m_flagValues.constFind(property);
587 if (it != m_flagValues.constEnd()) {
588 QVariant v;
589 v.setValue(it.value().flags);
590 return v;
591 }
592 }
593 if (attribute == validationModesAttributeC) {
594 const auto it = m_stringAttributes.constFind(property);
595 if (it != m_stringAttributes.constEnd())
596 return it.value();
597 }
598
599 if (attribute == fontAttributeC) {
600 const auto it = m_stringFontAttributes.constFind(property);
601 if (it != m_stringFontAttributes.constEnd())
602 return it.value();
603 }
604
605 if (attribute == themeAttributeC) {
606 const auto it = m_stringThemeAttributes.constFind(property);
607 if (it != m_stringThemeAttributes.constEnd())
608 return it.value();
609 }
610
611 if (attribute == themeEnumAttributeC) {
612 const auto it = m_intThemeEnumAttributes.constFind(property);
613 if (it != m_intThemeEnumAttributes.constEnd())
614 return it.value();
615 }
616
617 if (attribute == superPaletteAttributeC) {
618 const auto it = m_paletteValues.constFind(property);
619 if (it != m_paletteValues.cend())
620 return it.value().superPalette;
621 }
622
623 if (attribute == defaultResourceAttributeC) {
624 const auto itPix = m_defaultPixmaps.constFind(property);
625 if (itPix != m_defaultPixmaps.constEnd())
626 return itPix.value();
627
628 const auto itIcon = m_defaultIcons.constFind(property);
629 if (itIcon != m_defaultIcons.constEnd())
630 return itIcon.value();
631 }
632
633 if (attribute == alignDefaultAttribute()) {
634 Qt::Alignment v = m_alignDefault.value(property,
635 Qt::Alignment(Qt::AlignLeading | Qt::AlignHCenter));
636 return QVariant(uint(v));
637 }
638
639 return QtVariantPropertyManager::attributeValue(property, attribute);
640}
641
642void DesignerPropertyManager::setAttribute(QtProperty *property,
643 const QString &attribute, const QVariant &value)
644{
645 if (attribute == resettableAttributeC && m_resetMap.contains(property)) {
646 if (value.userType() != QMetaType::Bool)
647 return;
648 const bool val = value.toBool();
649 const auto it = m_resetMap.find(property);
650 if (it.value() == val)
651 return;
652 it.value() = val;
653 emit attributeChanged(variantProperty(property), attribute, value);
654 return;
655 }
656 if (attribute == flagsAttributeC && m_flagValues.contains(property)) {
657 if (value.userType() != designerFlagListTypeId())
658 return;
659
660 const DesignerFlagList flags = qvariant_cast<DesignerFlagList>(value);
661 const auto fit = m_flagValues.find(property);
662 FlagData data = fit.value();
663 if (data.flags == flags)
664 return;
665
666 const auto pfit = m_propertyToFlags.find(property);
667 qDeleteAll(std::as_const(pfit.value()));
668 pfit.value().clear();
669
670 QList<uint> values;
671
672 for (const auto &pair : flags) {
673 const QString flagName = pair.first;
674 QtProperty *prop = addProperty(QMetaType::Bool);
675 prop->setPropertyName(flagName);
676 property->addSubProperty(prop);
677 m_propertyToFlags[property].append(prop);
678 values.append(pair.second);
679 }
680
681 data.val = 0;
682 data.flags = flags;
683 data.values = values;
684
685 fit.value() = data;
686
687 QVariant v;
688 v.setValue(flags);
689 emit attributeChanged(property, attribute, v);
690
691 emit propertyChanged(property);
692 emit QtVariantPropertyManager::valueChanged(property, data.val);
693 } else if (attribute == validationModesAttributeC && m_stringAttributes.contains(property)) {
694 if (value.userType() != QMetaType::Int)
695 return;
696
697 const auto it = m_stringAttributes.find(property);
698 const int oldValue = it.value();
699
700 const int newValue = value.toInt();
701
702 if (oldValue == newValue)
703 return;
704
705 it.value() = newValue;
706
707 emit attributeChanged(property, attribute, newValue);
708 } else if (attribute == fontAttributeC && m_stringFontAttributes.contains(property)) {
709 if (value.userType() != QMetaType::QFont)
710 return;
711
712 const auto it = m_stringFontAttributes.find(property);
713 const QFont oldValue = it.value();
714
715 const QFont newValue = qvariant_cast<QFont>(value);
716
717 if (oldValue == newValue)
718 return;
719
720 it.value() = newValue;
721
722 emit attributeChanged(property, attribute, newValue);
723 } else if (attribute == themeAttributeC && m_stringThemeAttributes.contains(property)) {
724 if (value.userType() != QMetaType::Bool)
725 return;
726
727 const auto it = m_stringThemeAttributes.find(property);
728 const bool oldValue = it.value();
729
730 const bool newValue = value.toBool();
731
732 if (oldValue == newValue)
733 return;
734
735 it.value() = newValue;
736
737 emit attributeChanged(property, attribute, newValue);
738 } else if (attribute == themeEnumAttributeC && m_intThemeEnumAttributes.contains(property)) {
739 if (value.userType() != QMetaType::Bool)
740 return;
741
742 const auto it = m_intThemeEnumAttributes.find(property);
743 const bool oldValue = it.value();
744
745 const bool newValue = value.toBool();
746
747 if (oldValue == newValue)
748 return;
749
750 it.value() = newValue;
751
752 emit attributeChanged(property, attribute, newValue);
753 } else if (attribute == superPaletteAttributeC && m_paletteValues.contains(property)) {
754 if (value.userType() != QMetaType::QPalette)
755 return;
756
757 QPalette superPalette = qvariant_cast<QPalette>(value);
758
759 const auto it = m_paletteValues.find(property);
760 PaletteData data = it.value();
761 if (data.superPalette == superPalette)
762 return;
763
764 data.superPalette = superPalette;
765 // resolve here
766 const auto mask = data.val.resolveMask();
767 data.val = data.val.resolve(superPalette);
768 data.val.setResolveMask(mask);
769
770 it.value() = data;
771
772 QVariant v;
773 v.setValue(superPalette);
774 emit attributeChanged(property, attribute, v);
775
776 emit propertyChanged(property);
777 emit QtVariantPropertyManager::valueChanged(property, data.val); // if resolve was done, this is also for consistency
778 } else if (attribute == defaultResourceAttributeC && m_defaultPixmaps.contains(property)) {
779 if (value.userType() != QMetaType::QPixmap)
780 return;
781
782 QPixmap defaultPixmap = qvariant_cast<QPixmap>(value);
783
784 const auto it = m_defaultPixmaps.find(property);
785 QPixmap oldDefaultPixmap = it.value();
786 if (defaultPixmap.cacheKey() == oldDefaultPixmap.cacheKey())
787 return;
788
789 it.value() = defaultPixmap;
790
791 QVariant v = QVariant::fromValue(defaultPixmap);
792 emit attributeChanged(property, attribute, v);
793
794 emit propertyChanged(property);
795 } else if (attribute == defaultResourceAttributeC && m_defaultIcons.contains(property)) {
796 if (value.userType() != QMetaType::QIcon)
797 return;
798
799 QIcon defaultIcon = qvariant_cast<QIcon>(value);
800
801 const auto it = m_defaultIcons.find(property);
802 QIcon oldDefaultIcon = it.value();
803 if (defaultIcon.cacheKey() == oldDefaultIcon.cacheKey())
804 return;
805
806 it.value() = defaultIcon;
807
808 qdesigner_internal::PropertySheetIconValue icon = m_iconValues.value(property);
809 if (icon.paths().isEmpty()) {
810 const auto &subIconProperties = m_propertyToIconSubProperties.value(property);
811 for (auto itSub = subIconProperties.cbegin(), end = subIconProperties.cend(); itSub != end; ++itSub) {
812 const auto pair = itSub.key();
813 QtProperty *subProp = itSub.value();
814 setAttribute(subProp, defaultResourceAttributeC,
815 defaultIcon.pixmap(16, 16, pair.first, pair.second));
816 }
817 }
818
819 QVariant v = QVariant::fromValue(defaultIcon);
820 emit attributeChanged(property, attribute, v);
821
822 emit propertyChanged(property);
823 } else if (attribute == alignDefaultAttribute()) {
824 m_alignDefault[property] = Qt::Alignment(value.toUInt());
825 }
826 QtVariantPropertyManager::setAttribute(property, attribute, value);
827}
828
829int DesignerPropertyManager::designerFlagTypeId()
830{
831 static const int rc = qMetaTypeId<DesignerFlagPropertyType>();
832 return rc;
833}
834
835int DesignerPropertyManager::designerFlagListTypeId()
836{
837 static const int rc = qMetaTypeId<DesignerFlagList>();
838 return rc;
839}
840
841int DesignerPropertyManager::designerAlignmentTypeId()
842{
843 static const int rc = qMetaTypeId<DesignerAlignmentPropertyType>();
844 return rc;
845}
846
847int DesignerPropertyManager::designerPixmapTypeId()
848{
849 return qMetaTypeId<PropertySheetPixmapValue>();
850}
851
852int DesignerPropertyManager::designerIconTypeId()
853{
854 return qMetaTypeId<PropertySheetIconValue>();
855}
856
857int DesignerPropertyManager::designerStringTypeId()
858{
859 return qMetaTypeId<PropertySheetStringValue>();
860}
861
862int DesignerPropertyManager::designerStringListTypeId()
863{
864 return qMetaTypeId<PropertySheetStringListValue>();
865}
866
867int DesignerPropertyManager::designerKeySequenceTypeId()
868{
869 return qMetaTypeId<PropertySheetKeySequenceValue>();
870}
871
872QString DesignerPropertyManager::alignDefaultAttribute()
873{
874 return u"alignDefault"_s;
875}
876
877uint DesignerPropertyManager::alignDefault(const QtVariantProperty *prop)
878{
879 return prop->attributeValue(DesignerPropertyManager::alignDefaultAttribute()).toUInt();
880}
881
882bool DesignerPropertyManager::isPropertyTypeSupported(int propertyType) const
883{
884 switch (propertyType) {
885 case QMetaType::QPalette:
886 case QMetaType::UInt:
887 case QMetaType::LongLong:
888 case QMetaType::ULongLong:
889 case QMetaType::QUrl:
890 case QMetaType::QByteArray:
891 case QMetaType::QStringList:
892 case QMetaType::QBrush:
893 return true;
894 default:
895 break;
896 }
897
898 if (propertyType == designerFlagTypeId())
899 return true;
900 if (propertyType == designerAlignmentTypeId())
901 return true;
902 if (propertyType == designerPixmapTypeId())
903 return true;
904 if (propertyType == designerIconTypeId())
905 return true;
906 if (propertyType == designerStringTypeId() || propertyType == designerStringListTypeId())
907 return true;
908 if (propertyType == designerKeySequenceTypeId())
909 return true;
910
911 return QtVariantPropertyManager::isPropertyTypeSupported(propertyType);
912}
913
914QString DesignerPropertyManager::valueText(const QtProperty *property) const
915{
916 if (m_flagValues.contains(property)) {
917 const FlagData data = m_flagValues.value(property);
918 const uint v = data.val;
919 QString valueStr;
920 for (const DesignerIntPair &p : data.flags) {
921 const uint val = p.second;
922 const bool checked = (val == 0) ? (v == 0) : ((val & v) == val);
923 if (checked) {
924 if (!valueStr.isEmpty())
925 valueStr += u'|';
926 valueStr += p.first;
927 }
928 }
929 return valueStr;
930 }
931 if (m_alignValues.contains(property)) {
932 const uint v = m_alignValues.value(property);
933 return tr("%1, %2").arg(indexHToString(alignToIndexH(v)),
934 indexVToString(alignToIndexV(v)));
935 }
936 if (m_paletteValues.contains(property)) {
937 const PaletteData data = m_paletteValues.value(property);
938 const auto mask = data.val.resolveMask();
939 if (mask)
940 return tr("Customized (%n roles)", nullptr, bitCount(mask));
941 static const QString inherited = tr("Inherited");
942 return inherited;
943 }
944 if (m_iconValues.contains(property))
945 return PixmapEditor::displayText(m_iconValues.value(property));
946 if (m_pixmapValues.contains(property)) {
947 const QString path = m_pixmapValues.value(property).path();
948 if (path.isEmpty())
949 return QString();
950 return QFileInfo(path).fileName();
951 }
952 if (m_intValues.contains(property)) {
953 const auto value = m_intValues.value(property);
954 if (m_intThemeEnumAttributes.value(property))
955 return IconThemeEnumEditor::iconName(value);
956 return QString::number(value);
957 }
958 if (m_uintValues.contains(property))
959 return QString::number(m_uintValues.value(property));
960 if (m_longLongValues.contains(property))
961 return QString::number(m_longLongValues.value(property));
962 if (m_uLongLongValues.contains(property))
963 return QString::number(m_uLongLongValues.value(property));
964 if (m_urlValues.contains(property))
965 return m_urlValues.value(property).toString();
966 if (m_byteArrayValues.contains(property))
967 return QString::fromUtf8(m_byteArrayValues.value(property));
968 const int vType = QtVariantPropertyManager::valueType(property);
969 if (vType == QMetaType::QString || vType == designerStringTypeId()) {
970 const QString str = (QtVariantPropertyManager::valueType(property) == QMetaType::QString)
971 ? value(property).toString() : qvariant_cast<PropertySheetStringValue>(value(property)).value();
972 const int validationMode = attributeValue(property, validationModesAttributeC).toInt();
973 return TextPropertyEditor::stringToEditorString(str, static_cast<TextPropertyValidationMode>(validationMode));
974 }
975 if (vType == QMetaType::QStringList || vType == designerStringListTypeId()) {
976 QVariant v = value(property);
977 const QStringList list = v.metaType().id() == QMetaType::QStringList
978 ? v.toStringList() : qvariant_cast<PropertySheetStringListValue>(v).value();
979 return list.join("; "_L1);
980 }
981 if (vType == designerKeySequenceTypeId()) {
982 return qvariant_cast<PropertySheetKeySequenceValue>(value(property)).value().toString(QKeySequence::NativeText);
983 }
984 if (vType == QMetaType::Bool) {
985 return QString();
986 }
987
988 QString rc;
989 if (m_brushManager.valueText(property, &rc))
990 return rc;
991 return QtVariantPropertyManager::valueText(property);
992}
993
994void DesignerPropertyManager::reloadResourceProperties()
995{
996 DesignerIconCache *iconCache = nullptr;
997 for (auto itIcon = m_iconValues.cbegin(), end = m_iconValues.cend(); itIcon!= end; ++itIcon) {
998 auto *property = itIcon.key();
999 const PropertySheetIconValue &icon = itIcon.value();
1000
1001 QIcon defaultIcon = m_defaultIcons.value(property);
1002 if (!icon.paths().isEmpty()) {
1003 if (!iconCache) {
1004 QDesignerFormWindowInterface *formWindow = QDesignerFormWindowInterface::findFormWindow(m_object);
1005 qdesigner_internal::FormWindowBase *fwb = qobject_cast<qdesigner_internal::FormWindowBase *>(formWindow);
1006 iconCache = fwb->iconCache();
1007 }
1008 if (iconCache)
1009 defaultIcon = iconCache->icon(icon);
1010 }
1011
1012 const auto &subProperties = m_propertyToIconSubProperties.value(property);
1013 for (auto itSub = subProperties.cbegin(), end = subProperties.cend(); itSub != end; ++itSub) {
1014 const auto pair = itSub.key();
1015 QtVariantProperty *subProperty = variantProperty(itSub.value());
1016 subProperty->setAttribute(defaultResourceAttributeC,
1017 defaultIcon.pixmap(16, 16, pair.first, pair.second));
1018 }
1019
1020 auto *ncProperty = const_cast<QtProperty *>(property);
1021 emit propertyChanged(ncProperty);
1022 emit QtVariantPropertyManager::valueChanged(ncProperty, QVariant::fromValue(itIcon.value()));
1023 }
1024 for (auto itPix = m_pixmapValues.cbegin(), end = m_pixmapValues.cend(); itPix != end; ++itPix) {
1025 auto *property = const_cast<QtProperty *>(itPix.key());
1026 emit propertyChanged(property);
1027 emit QtVariantPropertyManager::valueChanged(property, QVariant::fromValue(itPix.value()));
1028 }
1029}
1030
1031QIcon DesignerPropertyManager::valueIcon(const QtProperty *property) const
1032{
1033 if (m_iconValues.contains(property)) {
1034 if (!property->isModified())
1035 return m_defaultIcons.value(property).pixmap(16, 16);
1036 QDesignerFormWindowInterface *formWindow = QDesignerFormWindowInterface::findFormWindow(m_object);
1037 qdesigner_internal::FormWindowBase *fwb = qobject_cast<qdesigner_internal::FormWindowBase *>(formWindow);
1038 if (fwb)
1039 return fwb->iconCache()->icon(m_iconValues.value(property)).pixmap(16, 16);
1040 } else if (m_pixmapValues.contains(property)) {
1041 if (!property->isModified())
1042 return m_defaultPixmaps.value(property);
1043 QDesignerFormWindowInterface *formWindow = QDesignerFormWindowInterface::findFormWindow(m_object);
1044 qdesigner_internal::FormWindowBase *fwb = qobject_cast<qdesigner_internal::FormWindowBase *>(formWindow);
1045 if (fwb)
1046 return fwb->pixmapCache()->pixmap(m_pixmapValues.value(property));
1047 } else if (m_stringThemeAttributes.value(property, false)) {
1048 return QIcon::fromTheme(value(property).toString());
1049 } else {
1050 QIcon rc;
1051 if (m_brushManager.valueIcon(property, &rc))
1052 return rc;
1053 }
1054
1055 return QtVariantPropertyManager::valueIcon(property);
1056}
1057
1058QVariant DesignerPropertyManager::value(const QtProperty *property) const
1059{
1060 if (m_flagValues.contains(property))
1061 return m_flagValues.value(property).val;
1062 if (m_alignValues.contains(property))
1063 return m_alignValues.value(property);
1064 if (m_paletteValues.contains(property))
1065 return m_paletteValues.value(property).val;
1066 if (m_iconValues.contains(property))
1067 return QVariant::fromValue(m_iconValues.value(property));
1068 if (m_pixmapValues.contains(property))
1069 return QVariant::fromValue(m_pixmapValues.value(property));
1070 QVariant rc;
1071 if (m_stringManager.value(property, &rc)
1072 || m_keySequenceManager.value(property, &rc)
1073 || m_stringListManager.value(property, &rc)
1074 || m_brushManager.value(property, &rc))
1075 return rc;
1076 if (m_intValues.contains(property))
1077 return m_intValues.value(property);
1078 if (m_uintValues.contains(property))
1079 return m_uintValues.value(property);
1080 if (m_longLongValues.contains(property))
1081 return m_longLongValues.value(property);
1082 if (m_uLongLongValues.contains(property))
1083 return m_uLongLongValues.value(property);
1084 if (m_urlValues.contains(property))
1085 return m_urlValues.value(property);
1086 if (m_byteArrayValues.contains(property))
1087 return m_byteArrayValues.value(property);
1088
1089 return QtVariantPropertyManager::value(property);
1090}
1091
1092int DesignerPropertyManager::valueType(int propertyType) const
1093{
1094 switch (propertyType) {
1095 case QMetaType::QPalette:
1096 case QMetaType::UInt:
1097 case QMetaType::LongLong:
1098 case QMetaType::ULongLong:
1099 case QMetaType::QUrl:
1100 case QMetaType::QByteArray:
1101 case QMetaType::QStringList:
1102 case QMetaType::QBrush:
1103 return propertyType;
1104 default:
1105 break;
1106 }
1107 if (propertyType == designerFlagTypeId())
1108 return QMetaType::UInt;
1109 if (propertyType == designerAlignmentTypeId())
1110 return QMetaType::UInt;
1111 if (propertyType == designerPixmapTypeId())
1112 return propertyType;
1113 if (propertyType == designerIconTypeId())
1114 return propertyType;
1115 if (propertyType == designerStringTypeId() || propertyType == designerStringListTypeId())
1116 return propertyType;
1117 if (propertyType == designerKeySequenceTypeId())
1118 return propertyType;
1119 return QtVariantPropertyManager::valueType(propertyType);
1120}
1121
1122void DesignerPropertyManager::setValue(QtProperty *property, const QVariant &value)
1123{
1124 int subResult = m_stringManager.setValue(this, property, designerStringTypeId(), value);
1125 if (subResult == NoMatch)
1126 subResult = m_stringListManager.setValue(this, property, designerStringListTypeId(), value);
1127 if (subResult == NoMatch)
1128 subResult = m_keySequenceManager.setValue(this, property, designerKeySequenceTypeId(), value);
1129 if (subResult == NoMatch)
1130 subResult = m_brushManager.setValue(this, property, value);
1131 if (subResult != NoMatch) {
1132 if (subResult == Changed) {
1133 emit QtVariantPropertyManager::valueChanged(property, value);
1134 emit propertyChanged(property);
1135 }
1136 return;
1137 }
1138
1139 const auto fit = m_flagValues.find(property);
1140
1141 if (fit != m_flagValues.end()) {
1142 if (value.metaType().id() != QMetaType::UInt && !value.canConvert<uint>())
1143 return;
1144
1145 const uint v = value.toUInt();
1146
1147 FlagData data = fit.value();
1148 if (data.val == v)
1149 return;
1150
1151 // set Value
1152
1153 const auto values = data.values;
1154 const auto subFlags = m_propertyToFlags.value(property);
1155 const qsizetype subFlagCount = subFlags.size();
1156 for (qsizetype i = 0; i < subFlagCount; ++i) {
1157 QtVariantProperty *subFlag = variantProperty(subFlags.at(i));
1158 const uint val = values.at(i);
1159 const bool checked = (val == 0) ? (v == 0) : ((val & v) == val);
1160 subFlag->setValue(checked);
1161 }
1162
1163 for (qsizetype i = 0; i < subFlagCount; ++i) {
1164 QtVariantProperty *subFlag = variantProperty(subFlags.at(i));
1165 const uint val = values.at(i);
1166 const bool checked = (val == 0) ? (v == 0) : ((val & v) == val);
1167 bool enabled = true;
1168 if (val == 0) {
1169 if (checked)
1170 enabled = false;
1171 } else if (bitCount(val) > 1) {
1172 // Disabled if all flags contained in the mask are checked
1173 uint currentMask = 0;
1174 for (qsizetype j = 0; j < subFlagCount; ++j) {
1175 QtVariantProperty *subFlag = variantProperty(subFlags.at(j));
1176 if (bitCount(values.at(j)) == 1)
1177 currentMask |= subFlag->value().toBool() ? values.at(j) : 0;
1178 }
1179 if ((currentMask & values.at(i)) == values.at(i))
1180 enabled = false;
1181 }
1182 subFlag->setEnabled(enabled);
1183 }
1184
1185 data.val = v;
1186 fit.value() = data;
1187
1188 emit QtVariantPropertyManager::valueChanged(property, data.val);
1189 emit propertyChanged(property);
1190
1191 return;
1192 }
1193 if (m_alignValues.contains(property)) {
1194 if (value.metaType().id() != QMetaType::UInt && !value.canConvert<uint>())
1195 return;
1196
1197 const uint v = value.toUInt();
1198
1199 uint val = m_alignValues.value(property);
1200
1201 if (val == v)
1202 return;
1203
1204 QtVariantProperty *alignH = variantProperty(m_propertyToAlignH.value(property));
1205 QtVariantProperty *alignV = variantProperty(m_propertyToAlignV.value(property));
1206
1207 if (alignH)
1208 alignH->setValue(alignToIndexH(v));
1209 if (alignV)
1210 alignV->setValue(alignToIndexV(v));
1211
1212 m_alignValues[property] = v;
1213
1214 emit QtVariantPropertyManager::valueChanged(property, v);
1215 emit propertyChanged(property);
1216
1217 return;
1218 }
1219 if (m_paletteValues.contains(property)) {
1220 if (value.metaType().id() != QMetaType::QPalette && !value.canConvert<QPalette>())
1221 return;
1222
1223 QPalette p = qvariant_cast<QPalette>(value);
1224
1225 PaletteData data = m_paletteValues.value(property);
1226
1227 const auto mask = p.resolveMask();
1228 p = p.resolve(data.superPalette);
1229 p.setResolveMask(mask);
1230
1231 if (data.val == p && data.val.resolveMask() == p.resolveMask())
1232 return;
1233
1234 data.val = p;
1235 m_paletteValues[property] = data;
1236
1237 emit QtVariantPropertyManager::valueChanged(property, data.val);
1238 emit propertyChanged(property);
1239
1240 return;
1241 }
1242 if (m_iconValues.contains(property)) {
1243 if (value.userType() != designerIconTypeId())
1244 return;
1245
1246 const PropertySheetIconValue icon = qvariant_cast<PropertySheetIconValue>(value);
1247
1248 const PropertySheetIconValue oldIcon = m_iconValues.value(property);
1249 if (icon == oldIcon)
1250 return;
1251
1252 m_iconValues[property] = icon;
1253
1254 QIcon defaultIcon = m_defaultIcons.value(property);
1255 if (!icon.paths().isEmpty()) {
1256 QDesignerFormWindowInterface *formWindow = QDesignerFormWindowInterface::findFormWindow(m_object);
1257 qdesigner_internal::FormWindowBase *fwb = qobject_cast<qdesigner_internal::FormWindowBase *>(formWindow);
1258 if (fwb)
1259 defaultIcon = fwb->iconCache()->icon(icon);
1260 }
1261
1262 const auto &iconPaths = icon.paths();
1263
1264 const auto &subProperties = m_propertyToIconSubProperties.value(property);
1265 for (auto itSub = subProperties.cbegin(), end = subProperties.cend(); itSub != end; ++itSub) {
1266 const auto pair = itSub.key();
1267 QtVariantProperty *subProperty = variantProperty(itSub.value());
1268 bool hasPath = iconPaths.contains(pair);
1269 subProperty->setModified(hasPath);
1270 subProperty->setValue(QVariant::fromValue(iconPaths.value(pair)));
1271 subProperty->setAttribute(defaultResourceAttributeC,
1272 defaultIcon.pixmap(16, 16, pair.first, pair.second));
1273 }
1274 QtVariantProperty *themeSubProperty = variantProperty(m_propertyToTheme.value(property));
1275 if (themeSubProperty) {
1276 const QString theme = icon.theme();
1277 themeSubProperty->setModified(!theme.isEmpty());
1278 themeSubProperty->setValue(theme);
1279 }
1280 QtVariantProperty *themeEnumSubProperty = variantProperty(m_propertyToThemeEnum.value(property));
1281 if (themeEnumSubProperty) {
1282 const int themeEnum = icon.themeEnum();
1283 themeEnumSubProperty->setModified(themeEnum != -1);
1284 themeEnumSubProperty->setValue(QVariant(themeEnum));
1285 }
1286
1287 emit QtVariantPropertyManager::valueChanged(property, QVariant::fromValue(icon));
1288 emit propertyChanged(property);
1289
1290 QString toolTip;
1291 const auto itNormalOff = iconPaths.constFind({QIcon::Normal, QIcon::Off});
1292 if (itNormalOff != iconPaths.constEnd())
1293 toolTip = itNormalOff.value().path();
1294 // valueText() only show the file name; show full path as ToolTip.
1295 property->setToolTip(QDir::toNativeSeparators(toolTip));
1296
1297 return;
1298 }
1299 if (m_pixmapValues.contains(property)) {
1300 if (value.userType() != designerPixmapTypeId())
1301 return;
1302
1303 const PropertySheetPixmapValue pixmap = qvariant_cast<PropertySheetPixmapValue>(value);
1304
1305 const PropertySheetPixmapValue oldPixmap = m_pixmapValues.value(property);
1306 if (pixmap == oldPixmap)
1307 return;
1308
1309 m_pixmapValues[property] = pixmap;
1310
1311 emit QtVariantPropertyManager::valueChanged(property, QVariant::fromValue(pixmap));
1312 emit propertyChanged(property);
1313
1314 // valueText() only show the file name; show full path as ToolTip.
1315 property->setToolTip(QDir::toNativeSeparators(pixmap.path()));
1316
1317 return;
1318 }
1319 if (m_intValues.contains(property)) {
1320 if (value.metaType().id() != QMetaType::Int && !value.canConvert<int>())
1321 return;
1322
1323 const int v = value.toInt(nullptr);
1324
1325 const int oldValue = m_intValues.value(property);
1326 if (v == oldValue)
1327 return;
1328
1329 m_intValues[property] = v;
1330
1331 emit QtVariantPropertyManager::valueChanged(property, v);
1332 emit propertyChanged(property);
1333
1334 return;
1335 }
1336 if (m_uintValues.contains(property)) {
1337 if (value.metaType().id() != QMetaType::UInt && !value.canConvert<uint>())
1338 return;
1339
1340 const uint v = value.toUInt(nullptr);
1341
1342 const uint oldValue = m_uintValues.value(property);
1343 if (v == oldValue)
1344 return;
1345
1346 m_uintValues[property] = v;
1347
1348 emit QtVariantPropertyManager::valueChanged(property, v);
1349 emit propertyChanged(property);
1350
1351 return;
1352 }
1353 if (m_longLongValues.contains(property)) {
1354 if (value.metaType().id() != QMetaType::LongLong && !value.canConvert<qlonglong>())
1355 return;
1356
1357 const qlonglong v = value.toLongLong(nullptr);
1358
1359 const qlonglong oldValue = m_longLongValues.value(property);
1360 if (v == oldValue)
1361 return;
1362
1363 m_longLongValues[property] = v;
1364
1365 emit QtVariantPropertyManager::valueChanged(property, v);
1366 emit propertyChanged(property);
1367
1368 return;
1369 }
1370 if (m_uLongLongValues.contains(property)) {
1371 if (value.metaType().id() != QMetaType::ULongLong && !value.canConvert<qulonglong>())
1372 return;
1373
1374 qulonglong v = value.toULongLong(nullptr);
1375
1376 qulonglong oldValue = m_uLongLongValues.value(property);
1377 if (v == oldValue)
1378 return;
1379
1380 m_uLongLongValues[property] = v;
1381
1382 emit QtVariantPropertyManager::valueChanged(property, v);
1383 emit propertyChanged(property);
1384
1385 return;
1386 }
1387 if (m_urlValues.contains(property)) {
1388 if (value.metaType().id() != QMetaType::QUrl && !value.canConvert<QUrl>())
1389 return;
1390
1391 const QUrl v = value.toUrl();
1392
1393 const QUrl oldValue = m_urlValues.value(property);
1394 if (v == oldValue)
1395 return;
1396
1397 m_urlValues[property] = v;
1398
1399 emit QtVariantPropertyManager::valueChanged(property, v);
1400 emit propertyChanged(property);
1401
1402 return;
1403 }
1404 if (m_byteArrayValues.contains(property)) {
1405 if (value.metaType().id() != QMetaType::QByteArray && !value.canConvert<QByteArray>())
1406 return;
1407
1408 const QByteArray v = value.toByteArray();
1409
1410 const QByteArray oldValue = m_byteArrayValues.value(property);
1411 if (v == oldValue)
1412 return;
1413
1414 m_byteArrayValues[property] = v;
1415
1416 emit QtVariantPropertyManager::valueChanged(property, v);
1417 emit propertyChanged(property);
1418
1419 return;
1420 }
1421 m_fontManager.setValue(this, property, value);
1422 QtVariantPropertyManager::setValue(property, value);
1423 if (QtVariantPropertyManager::valueType(property) == QMetaType::Bool)
1424 property->setToolTip(QtVariantPropertyManager::valueText(property));
1425}
1426
1427void DesignerPropertyManager::initializeProperty(QtProperty *property)
1428{
1429 static bool creatingIconProperties = false;
1430
1431 m_resetMap[property] = false;
1432
1433 const int type = propertyType(property);
1434 m_fontManager.preInitializeProperty(property, type, m_resetMap);
1435 switch (type) {
1436 case QMetaType::QPalette:
1437 m_paletteValues[property] = PaletteData();
1438 break;
1439 case QMetaType::QString:
1440 m_stringAttributes[property] = ValidationSingleLine;
1441 m_stringFontAttributes[property] = QApplication::font();
1442 m_stringThemeAttributes[property] = false;
1443 break;
1444 case QMetaType::Int:
1445 if (creatingIconProperties) {
1446 m_intValues[property] = 0;
1447 m_intThemeEnumAttributes[property] = false;
1448 }
1449 break;
1450 case QMetaType::UInt:
1451 m_uintValues[property] = 0;
1452 break;
1453 case QMetaType::LongLong:
1454 m_longLongValues[property] = 0;
1455 break;
1456 case QMetaType::ULongLong:
1457 m_uLongLongValues[property] = 0;
1458 break;
1459 case QMetaType::QUrl:
1460 m_urlValues[property] = QUrl();
1461 break;
1462 case QMetaType::QByteArray:
1463 m_byteArrayValues[property] = QByteArray();
1464 break;
1465 case QMetaType::QBrush:
1466 m_brushManager.initializeProperty(this, property, enumTypeId());
1467 break;
1468 default:
1469 if (type == designerFlagTypeId()) {
1470 m_flagValues[property] = FlagData();
1471 m_propertyToFlags[property] = QList<QtProperty *>();
1472 } else if (type == designerAlignmentTypeId()) {
1473 const uint align = Qt::AlignLeft | Qt::AlignVCenter;
1474 m_alignValues[property] = align;
1475
1476 QtVariantProperty *alignH = addProperty(enumTypeId(), tr("Horizontal"));
1477 QStringList namesH;
1478 namesH << indexHToString(0) << indexHToString(1) << indexHToString(2) << indexHToString(3);
1479 alignH->setAttribute(u"enumNames"_s, namesH);
1480 alignH->setValue(alignToIndexH(align));
1481 m_propertyToAlignH[property] = alignH;
1482 m_alignHToProperty[alignH] = property;
1483 property->addSubProperty(alignH);
1484
1485 QtVariantProperty *alignV = addProperty(enumTypeId(), tr("Vertical"));
1486 QStringList namesV;
1487 namesV << indexVToString(0) << indexVToString(1) << indexVToString(2);
1488 alignV->setAttribute(u"enumNames"_s, namesV);
1489 alignV->setValue(alignToIndexV(align));
1490 m_propertyToAlignV[property] = alignV;
1491 m_alignVToProperty[alignV] = property;
1492 property->addSubProperty(alignV);
1493 } else if (type == designerPixmapTypeId()) {
1494 m_pixmapValues[property] = PropertySheetPixmapValue();
1495 m_defaultPixmaps[property] = QPixmap();
1496 } else if (type == designerIconTypeId()) {
1497 creatingIconProperties = true;
1498 m_iconValues[property] = PropertySheetIconValue();
1499 m_defaultIcons[property] = QIcon();
1500
1501 QtVariantProperty *themeEnumProp = addProperty(QMetaType::Int, tr("Theme"));
1502 m_intValues[themeEnumProp] = -1;
1503 themeEnumProp->setAttribute(themeEnumAttributeC, true);
1504 m_propertyToThemeEnum[property] = themeEnumProp;
1505 m_resetMap[themeEnumProp] = true;
1506 property->addSubProperty(themeEnumProp);
1507
1508 QtVariantProperty *themeProp = addProperty(QMetaType::QString, tr("XDG Theme"));
1509 themeProp->setAttribute(themeAttributeC, true);
1510 m_propertyToTheme[property] = themeProp;
1511 m_resetMap[themeProp] = true;
1512 property->addSubProperty(themeProp);
1513
1514 createIconSubProperty(property, QIcon::Normal, QIcon::Off, tr("Normal Off"));
1515 createIconSubProperty(property, QIcon::Normal, QIcon::On, tr("Normal On"));
1516 createIconSubProperty(property, QIcon::Disabled, QIcon::Off, tr("Disabled Off"));
1517 createIconSubProperty(property, QIcon::Disabled, QIcon::On, tr("Disabled On"));
1518 createIconSubProperty(property, QIcon::Active, QIcon::Off, tr("Active Off"));
1519 createIconSubProperty(property, QIcon::Active, QIcon::On, tr("Active On"));
1520 createIconSubProperty(property, QIcon::Selected, QIcon::Off, tr("Selected Off"));
1521 createIconSubProperty(property, QIcon::Selected, QIcon::On, tr("Selected On"));
1522 creatingIconProperties = false;
1523 } else if (type == designerStringTypeId()) {
1524 m_stringManager.initialize(this, property, PropertySheetStringValue());
1525 m_stringAttributes.insert(property, ValidationMultiLine);
1526 m_stringFontAttributes.insert(property, QApplication::font());
1527 m_stringThemeAttributes.insert(property, false);
1528 } else if (type == designerStringListTypeId()) {
1529 m_stringListManager.initialize(this, property, PropertySheetStringListValue());
1530 } else if (type == designerKeySequenceTypeId()) {
1531 m_keySequenceManager.initialize(this, property, PropertySheetKeySequenceValue());
1532 }
1533 }
1534
1535 QtVariantPropertyManager::initializeProperty(property);
1536 m_fontManager.postInitializeProperty(this, property, type, DesignerPropertyManager::enumTypeId());
1537 if (type == QMetaType::Double)
1538 setAttribute(property, u"decimals"_s, 6);
1539}
1540
1541void DesignerPropertyManager::createIconSubProperty(QtProperty *iconProperty, QIcon::Mode mode, QIcon::State state, const QString &subName)
1542{
1543 const auto pair = std::make_pair(mode, state);
1544 QtVariantProperty *subProp = addProperty(DesignerPropertyManager::designerPixmapTypeId(), subName);
1545 m_propertyToIconSubProperties[iconProperty][pair] = subProp;
1546 m_iconSubPropertyToState[subProp] = pair;
1547 m_resetMap[subProp] = true;
1548 iconProperty->addSubProperty(subProp);
1549}
1550
1551void DesignerPropertyManager::uninitializeProperty(QtProperty *property)
1552{
1553 m_resetMap.remove(property);
1554
1555 const auto pfit = m_propertyToFlags.find(property);
1556 if (pfit != m_propertyToFlags.end()) {
1557 qDeleteAll(std::as_const(pfit.value()));
1558 m_propertyToFlags.erase(pfit);
1559 }
1560 m_flagValues.remove(property);
1561
1562 if (QtProperty *alignH = m_propertyToAlignH.value(property))
1563 delete alignH;
1564 if (QtProperty *alignV = m_propertyToAlignV.value(property))
1565 delete alignV;
1566
1567 m_stringManager.uninitialize(property);
1568 m_stringListManager.uninitialize(property);
1569 m_keySequenceManager.uninitialize(property);
1570
1571 if (QtProperty *iconTheme = m_propertyToTheme.value(property))
1572 delete iconTheme;
1573
1574 if (QtProperty *iconThemeEnum = m_propertyToThemeEnum.value(property))
1575 delete iconThemeEnum;
1576
1577 m_propertyToAlignH.remove(property);
1578 m_propertyToAlignV.remove(property);
1579
1580 m_stringAttributes.remove(property);
1581 m_stringFontAttributes.remove(property);
1582
1583 m_paletteValues.remove(property);
1584
1585 m_iconValues.remove(property);
1586 m_defaultIcons.remove(property);
1587
1588 m_pixmapValues.remove(property);
1589 m_defaultPixmaps.remove(property);
1590
1591 const auto &iconSubProperties = m_propertyToIconSubProperties.value(property);
1592 for (auto itIcon = iconSubProperties.cbegin(), end = iconSubProperties.cend(); itIcon != end; ++itIcon)
1593 delete itIcon.value();
1594
1595 m_propertyToIconSubProperties.remove(property);
1596 m_iconSubPropertyToState.remove(property);
1597
1598 m_intValues.remove(property);
1599 m_uintValues.remove(property);
1600 m_longLongValues.remove(property);
1601 m_uLongLongValues.remove(property);
1602 m_urlValues.remove(property);
1603 m_byteArrayValues.remove(property);
1604
1605 m_fontManager.uninitializeProperty(property);
1606 m_brushManager.uninitializeProperty(property);
1607
1608 QtVariantPropertyManager::uninitializeProperty(property);
1609}
1610
1611bool DesignerPropertyManager::resetTextAlignmentProperty(QtProperty *property)
1612{
1613 const auto it = m_alignDefault.constFind(property);
1614 if (it == m_alignDefault.cend())
1615 return false;
1616 QtVariantProperty *alignProperty = variantProperty(property);
1617 alignProperty->setValue(DesignerPropertyManager::alignDefault(alignProperty));
1618 alignProperty->setModified(false);
1619 return true;
1620}
1621
1622bool DesignerPropertyManager::resetFontSubProperty(QtProperty *property)
1623{
1624 return m_fontManager.resetFontSubProperty(this, property);
1625}
1626
1627bool DesignerPropertyManager::resetIconSubProperty(QtProperty *property)
1628{
1629 auto *parentItem = property->parentProperty();
1630 if (!m_iconValues.contains(parentItem))
1631 return false;
1632
1633 if (m_pixmapValues.contains(property)) {
1634 QtVariantProperty *pixmapProperty = variantProperty(property);
1635 pixmapProperty->setValue(QVariant::fromValue(PropertySheetPixmapValue()));
1636 return true;
1637 }
1638 if (attributeValue(property, themeAttributeC).toBool()) {
1639 QtVariantProperty *themeProperty = variantProperty(property);
1640 themeProperty->setValue(QString());
1641 return true;
1642 }
1643 if (attributeValue(property, themeEnumAttributeC).toBool()) {
1644 QtVariantProperty *themeEnumProperty = variantProperty(property);
1645 themeEnumProperty->setValue(-1);
1646 return true;
1647 }
1648
1649 return false;
1650}
1651
1652// -------- DesignerEditorFactory
1653DesignerEditorFactory::DesignerEditorFactory(QDesignerFormEditorInterface *core, QObject *parent) :
1654 QtVariantEditorFactory(parent),
1655 m_core(core)
1656{
1657}
1658
1659DesignerEditorFactory::~DesignerEditorFactory() = default;
1660
1661void DesignerEditorFactory::setSpacing(int spacing)
1662{
1663 m_spacing = spacing;
1664}
1665
1666void DesignerEditorFactory::setFormWindowBase(qdesigner_internal::FormWindowBase *fwb)
1667{
1668 m_fwb = fwb;
1669 DesignerPixmapCache *cache = nullptr;
1670 if (fwb)
1671 cache = fwb->pixmapCache();
1672 for (auto it = m_pixmapPropertyToEditors.cbegin(), end = m_pixmapPropertyToEditors.cend(); it != end; ++it) {
1673 for (auto *e : it.value())
1674 e->setPixmapCache(cache);
1675 }
1676 for (auto it = m_iconPropertyToEditors.cbegin(), end = m_iconPropertyToEditors.cend(); it != end; ++it) {
1677 for (auto *e : it.value())
1678 e->setPixmapCache(cache);
1679 }
1680}
1681
1682void DesignerEditorFactory::connectPropertyManager(QtVariantPropertyManager *manager)
1683{
1684 connect(manager, &QtVariantPropertyManager::attributeChanged,
1685 this, &DesignerEditorFactory::slotAttributeChanged);
1686 connect(manager, &QtVariantPropertyManager::valueChanged,
1687 this, &DesignerEditorFactory::slotValueChanged);
1688 connect(manager, &QtVariantPropertyManager::propertyChanged,
1689 this, &DesignerEditorFactory::slotPropertyChanged);
1690 QtVariantEditorFactory::connectPropertyManager(manager);
1691}
1692
1693void DesignerEditorFactory::disconnectPropertyManager(QtVariantPropertyManager *manager)
1694{
1695 disconnect(manager, &QtVariantPropertyManager::attributeChanged,
1696 this, &DesignerEditorFactory::slotAttributeChanged);
1697 disconnect(manager, &QtVariantPropertyManager::valueChanged,
1698 this, &DesignerEditorFactory::slotValueChanged);
1699 disconnect(manager, &QtVariantPropertyManager::propertyChanged,
1700 this, &DesignerEditorFactory::slotPropertyChanged);
1701 QtVariantEditorFactory::disconnectPropertyManager(manager);
1702}
1703
1704// A helper that calls a setter with a value on a pointer list of editor objects.
1705// Could use QList<Editor*> instead of EditorContainer/Editor, but that crashes VS 6.
1706template <class EditorContainer, class Editor, class SetterParameter, class Value>
1707static inline void applyToEditors(const EditorContainer &list, void (Editor::*setter)(SetterParameter), const Value &value)
1708{
1709 if (list.isEmpty()) {
1710 return;
1711 }
1712 for (auto it = list.constBegin(), end = list.constEnd(); it != end; ++it) {
1713 Editor &editor = *(*it);
1714 (editor.*setter)(value);
1715 }
1716}
1717
1718void DesignerEditorFactory::slotAttributeChanged(QtProperty *property, const QString &attribute, const QVariant &value)
1719{
1720 QtVariantPropertyManager *manager = propertyManager(property);
1721 const int type = manager->propertyType(property);
1722 if (type == DesignerPropertyManager::designerPixmapTypeId() && attribute == defaultResourceAttributeC) {
1723 const QPixmap pixmap = qvariant_cast<QPixmap>(value);
1724 applyToEditors(m_pixmapPropertyToEditors.value(property), &PixmapEditor::setDefaultPixmap, pixmap);
1725 } else if (type == DesignerPropertyManager::designerStringTypeId() || type == QMetaType::QString) {
1726 if (attribute == validationModesAttributeC) {
1727 const TextPropertyValidationMode validationMode = static_cast<TextPropertyValidationMode>(value.toInt());
1728 applyToEditors(m_stringPropertyToEditors.value(property), &TextEditor::setTextPropertyValidationMode, validationMode);
1729 }
1730 if (attribute == fontAttributeC) {
1731 const QFont font = qvariant_cast<QFont>(value);
1732 applyToEditors(m_stringPropertyToEditors.value(property), &TextEditor::setRichTextDefaultFont, font);
1733 }
1734 if (attribute == themeAttributeC) {
1735 const bool themeEnabled = value.toBool();
1736 applyToEditors(m_stringPropertyToEditors.value(property), &TextEditor::setIconThemeModeEnabled, themeEnabled);
1737 }
1738 } else if (type == QMetaType::QPalette && attribute == superPaletteAttributeC) {
1739 const QPalette palette = qvariant_cast<QPalette>(value);
1740 applyToEditors(m_palettePropertyToEditors.value(property), &PaletteEditorButton::setSuperPalette, palette);
1741 }
1742}
1743
1744void DesignerEditorFactory::slotPropertyChanged(QtProperty *property)
1745{
1746 QtVariantPropertyManager *manager = propertyManager(property);
1747 const int type = manager->propertyType(property);
1748 if (type == DesignerPropertyManager::designerIconTypeId()) {
1749 QIcon defaultPixmap;
1750 if (!property->isModified()) {
1751 const auto attributeValue = manager->attributeValue(property, defaultResourceAttributeC);
1752 defaultPixmap = attributeValue.value<QIcon>();
1753 } else if (m_fwb) {
1754 const auto value = manager->value(property);
1755 defaultPixmap = m_fwb->iconCache()->icon(value.value<PropertySheetIconValue>());
1756 }
1757 const auto editors = m_iconPropertyToEditors.value(property);
1758 for (PixmapEditor *editor : editors)
1759 editor->setDefaultPixmapIcon(defaultPixmap);
1760 }
1761}
1762
1763void DesignerEditorFactory::slotValueChanged(QtProperty *property, const QVariant &value)
1764{
1765 if (m_changingPropertyValue)
1766 return;
1767
1768 QtVariantPropertyManager *manager = propertyManager(property);
1769 const int type = manager->propertyType(property);
1770 switch (type) {
1771 case QMetaType::QString:
1772 applyToEditors(m_stringPropertyToEditors.value(property), &TextEditor::setText, value.toString());
1773 break;
1774 case QMetaType::QPalette:
1775 applyToEditors(m_palettePropertyToEditors.value(property), &PaletteEditorButton::setPalette, qvariant_cast<QPalette>(value));
1776 break;
1777 case QMetaType::Int: {
1778 auto it = m_intPropertyToComboEditors.constFind(property);
1779 if (it != m_intPropertyToComboEditors.cend())
1780 applyToEditors(it.value(), &QComboBox::setCurrentIndex, value.toInt());
1781 }
1782 break;
1783 case QMetaType::UInt:
1784 applyToEditors(m_uintPropertyToEditors.value(property), &QLineEdit::setText, QString::number(value.toUInt()));
1785 break;
1786 case QMetaType::LongLong:
1787 applyToEditors(m_longLongPropertyToEditors.value(property), &QLineEdit::setText, QString::number(value.toLongLong()));
1788 break;
1789 case QMetaType::ULongLong:
1790 applyToEditors(m_uLongLongPropertyToEditors.value(property), &QLineEdit::setText, QString::number(value.toULongLong()));
1791 break;
1792 case QMetaType::QUrl:
1793 applyToEditors(m_urlPropertyToEditors.value(property), &TextEditor::setText, value.toUrl().toString());
1794 break;
1795 case QMetaType::QByteArray:
1796 applyToEditors(m_byteArrayPropertyToEditors.value(property), &TextEditor::setText, QString::fromUtf8(value.toByteArray()));
1797 break;
1798 case QMetaType::QStringList:
1799 applyToEditors(m_stringListPropertyToEditors.value(property), &StringListEditorButton::setStringList, value.toStringList());
1800 break;
1801 default:
1802 if (type == DesignerPropertyManager::designerIconTypeId()) {
1803 PropertySheetIconValue iconValue = qvariant_cast<PropertySheetIconValue>(value);
1804 applyToEditors(m_iconPropertyToEditors.value(property), &PixmapEditor::setTheme, iconValue.theme());
1805 applyToEditors(m_iconPropertyToEditors.value(property), &PixmapEditor::setThemeEnum, iconValue.themeEnum());
1806 applyToEditors(m_iconPropertyToEditors.value(property), &PixmapEditor::setPath, iconValue.pixmap(QIcon::Normal, QIcon::Off).path());
1807 } else if (type == DesignerPropertyManager::designerPixmapTypeId()) {
1808 applyToEditors(m_pixmapPropertyToEditors.value(property), &PixmapEditor::setPath, qvariant_cast<PropertySheetPixmapValue>(value).path());
1809 } else if (type == DesignerPropertyManager::designerStringTypeId()) {
1810 applyToEditors(m_stringPropertyToEditors.value(property), &TextEditor::setText, qvariant_cast<PropertySheetStringValue>(value).value());
1811 } else if (type == DesignerPropertyManager::designerStringListTypeId()) {
1812 applyToEditors(m_stringListPropertyToEditors.value(property), &StringListEditorButton::setStringList, qvariant_cast<PropertySheetStringListValue>(value).value());
1813 } else if (type == DesignerPropertyManager::designerKeySequenceTypeId()) {
1814 applyToEditors(m_keySequencePropertyToEditors.value(property), &QKeySequenceEdit::setKeySequence, qvariant_cast<PropertySheetKeySequenceValue>(value).value());
1815 }
1816 break;
1817 }
1818}
1819
1820TextEditor *DesignerEditorFactory::createTextEditor(QWidget *parent, TextPropertyValidationMode vm, const QString &value)
1821{
1822 TextEditor *rc = new TextEditor(m_core, parent);
1823 rc->setText(value);
1824 rc->setSpacing(m_spacing);
1825 rc->setTextPropertyValidationMode(vm);
1826 return rc;
1827}
1828
1829QWidget *DesignerEditorFactory::createEditor(QtVariantPropertyManager *manager, QtProperty *property,
1830 QWidget *parent)
1831{
1832 QWidget *editor = nullptr;
1833 const int type = manager->propertyType(property);
1834 switch (type) {
1835 case QMetaType::Bool: {
1836 editor = QtVariantEditorFactory::createEditor(manager, property, parent);
1837 QtBoolEdit *boolEdit = qobject_cast<QtBoolEdit *>(editor);
1838 if (boolEdit)
1839 boolEdit->setTextVisible(false);
1840 }
1841 break;
1842 case QMetaType::QString: {
1843 const int itvm = manager->attributeValue(property, validationModesAttributeC).toInt();
1844 const auto tvm = static_cast<TextPropertyValidationMode>(itvm);
1845 TextEditor *ed = createTextEditor(parent, tvm, manager->value(property).toString());
1846 const QVariant richTextDefaultFont = manager->attributeValue(property, fontAttributeC);
1847 if (richTextDefaultFont.metaType().id() == QMetaType::QFont)
1848 ed->setRichTextDefaultFont(qvariant_cast<QFont>(richTextDefaultFont));
1849 const bool themeEnabled = manager->attributeValue(property, themeAttributeC).toBool();
1850 ed->setIconThemeModeEnabled(themeEnabled);
1851 m_stringPropertyToEditors[property].append(ed);
1852 connect(ed, &QObject::destroyed, ed,
1853 [this, property] (QObject *o) { this->slotEditorDestroyed(property, o); });
1854 connect(ed, &TextEditor::textChanged, ed, [this, property](const QString &text) {
1855 this->slotStringTextChanged(property, text);
1856 });
1857 editor = ed;
1858 }
1859 break;
1860 case QMetaType::QPalette: {
1861 PaletteEditorButton *ed = new PaletteEditorButton(m_core, qvariant_cast<QPalette>(manager->value(property)), parent);
1862 ed->setSuperPalette(qvariant_cast<QPalette>(manager->attributeValue(property, superPaletteAttributeC)));
1863 m_palettePropertyToEditors[property].append(ed);
1864 connect(ed, &QObject::destroyed, ed,
1865 [this, property](QObject *o) { this->slotEditorDestroyed(property, o); });
1866 connect(ed, &PaletteEditorButton::paletteChanged, ed,
1867 [this, property](const QPalette &value) {
1868 this->slotPaletteChanged(property, value);
1869 });
1870 editor = ed;
1871 }
1872 break;
1873 case QMetaType::Int:
1874 if (manager->attributeValue(property, themeEnumAttributeC).toBool()) {
1875 auto *ed = IconThemeEnumEditor::createComboBox(parent);
1876 ed->setCurrentIndex(manager->value(property).toInt());
1877 connect(ed, &QObject::destroyed, ed,
1878 [this, property](QObject *o) { this->slotEditorDestroyed(property, o); });
1879 connect(ed, &QComboBox::currentIndexChanged, ed, [this, property](int value) {
1880 this->slotIntChanged(property, value);
1881 });
1882 m_intPropertyToComboEditors[property].append(ed);
1883 editor = ed;
1884 } else {
1885 editor = QtVariantEditorFactory::createEditor(manager, property, parent);
1886 }
1887 break;
1888 case QMetaType::UInt: {
1889 QLineEdit *ed = new QLineEdit(parent);
1890 ed->setValidator(new QULongLongValidator(0, UINT_MAX, ed));
1891 ed->setText(QString::number(manager->value(property).toUInt()));
1892 m_uintPropertyToEditors[property].append(ed);
1893 connect(ed, &QObject::destroyed, ed,
1894 [this, property](QObject *o) { this->slotEditorDestroyed(property, o); });
1895 connect(ed, &QLineEdit::textChanged, ed, [this, property](const QString &value) {
1896 this->slotUintChanged(property, value);
1897 });
1898 editor = ed;
1899 }
1900 break;
1901 case QMetaType::LongLong: {
1902 QLineEdit *ed = new QLineEdit(parent);
1903 ed->setValidator(new QLongLongValidator(ed));
1904 ed->setText(QString::number(manager->value(property).toLongLong()));
1905 m_longLongPropertyToEditors[property].append(ed);
1906 connect(ed, &QObject::destroyed, ed,
1907 [this, property](QObject *o) { this->slotEditorDestroyed(property, o); });
1908 connect(ed, &QLineEdit::textChanged, ed, [this, property](const QString &value) {
1909 this->slotLongLongChanged(property, value);
1910 });
1911 editor = ed;
1912 }
1913 break;
1914 case QMetaType::ULongLong: {
1915 QLineEdit *ed = new QLineEdit(parent);
1916 ed->setValidator(new QULongLongValidator(ed));
1917 ed->setText(QString::number(manager->value(property).toULongLong()));
1918 m_uLongLongPropertyToEditors[property].append(ed);
1919 connect(ed, &QObject::destroyed, ed,
1920 [this, property](QObject *o) { this->slotEditorDestroyed(property, o); });
1921 connect(ed, &QLineEdit::textChanged, ed, [this, property](const QString &value) {
1922 this->slotULongLongChanged(property, value);
1923 });
1924 editor = ed;
1925 }
1926 break;
1927 case QMetaType::QUrl: {
1928 TextEditor *ed = createTextEditor(parent, ValidationURL, manager->value(property).toUrl().toString());
1929 ed->setUpdateMode(TextPropertyEditor::UpdateOnFinished);
1930 m_urlPropertyToEditors[property].append(ed);
1931 connect(ed, &QObject::destroyed, ed,
1932 [this, property](QObject *o) { this->slotEditorDestroyed(property, o); });
1933 connect(ed, &TextEditor::textChanged, ed, [this, property](const QString &value) {
1934 this->slotUrlChanged(property, value);
1935 });
1936 editor = ed;
1937 }
1938 break;
1939 case QMetaType::QByteArray: {
1940 TextEditor *ed = createTextEditor(parent, ValidationMultiLine, QString::fromUtf8(manager->value(property).toByteArray()));
1941 m_byteArrayPropertyToEditors[property].append(ed);
1942 connect(ed, &QObject::destroyed, ed,
1943 [this, property](QObject *o) { this->slotEditorDestroyed(property, o); });
1944 connect(ed, &TextEditor::textChanged, ed, [this, property](const QString &value) {
1945 this->slotByteArrayChanged(property, value);
1946 });
1947 editor = ed;
1948 }
1949 break;
1950 default:
1951 if (type == DesignerPropertyManager::designerPixmapTypeId()) {
1952 PixmapEditor *ed = new PixmapEditor(m_core, parent);
1953 ed->setPixmapCache(m_fwb->pixmapCache());
1954 ed->setPath(qvariant_cast<PropertySheetPixmapValue>(manager->value(property)).path());
1955 ed->setDefaultPixmap(qvariant_cast<QPixmap>(manager->attributeValue(property, defaultResourceAttributeC)));
1956 ed->setSpacing(m_spacing);
1957 m_pixmapPropertyToEditors[property].append(ed);
1958 connect(ed, &QObject::destroyed, ed,
1959 [this, property](QObject *o) { this->slotEditorDestroyed(property, o); });
1960 connect(ed, &PixmapEditor::pathChanged, ed, [this, property](const QString &value) {
1961 this->slotPixmapChanged(property, value);
1962 });
1963 editor = ed;
1964 } else if (type == DesignerPropertyManager::designerIconTypeId()) {
1965 PixmapEditor *ed = new PixmapEditor(m_core, parent);
1966 ed->setPixmapCache(m_fwb->pixmapCache());
1967 ed->setIconThemeModeEnabled(true);
1968 PropertySheetIconValue value = qvariant_cast<PropertySheetIconValue>(manager->value(property));
1969 ed->setTheme(value.theme());
1970 ed->setThemeEnum(value.themeEnum());
1971 ed->setPath(value.pixmap(QIcon::Normal, QIcon::Off).path());
1972 QIcon defaultPixmap;
1973 if (!property->isModified())
1974 defaultPixmap = qvariant_cast<QIcon>(manager->attributeValue(property, defaultResourceAttributeC));
1975 else if (m_fwb)
1976 defaultPixmap = m_fwb->iconCache()->icon(value);
1977 ed->setDefaultPixmapIcon(defaultPixmap);
1978 ed->setSpacing(m_spacing);
1979 m_iconPropertyToEditors[property].append(ed);
1980 connect(ed, &QObject::destroyed, ed,
1981 [this, property](QObject *o) { this->slotEditorDestroyed(property, o); });
1982 connect(ed, &PixmapEditor::pathChanged, ed, [this, property](const QString &value) {
1983 this->slotIconChanged(property, value);
1984 });
1985 connect(ed, &PixmapEditor::themeChanged, ed, [this, property](const QString &value) {
1986 this->slotIconThemeChanged(property, value);
1987 });
1988 connect(ed, &PixmapEditor::themeEnumChanged, ed, [this, property](int value) {
1989 this->slotIconThemeEnumChanged(property, value);
1990 });
1991 editor = ed;
1992 } else if (type == DesignerPropertyManager::designerStringTypeId()) {
1993 const TextPropertyValidationMode tvm = static_cast<TextPropertyValidationMode>(manager->attributeValue(property, validationModesAttributeC).toInt());
1994 TextEditor *ed = createTextEditor(parent, tvm, qvariant_cast<PropertySheetStringValue>(manager->value(property)).value());
1995 const QVariant richTextDefaultFont = manager->attributeValue(property, fontAttributeC);
1996 if (richTextDefaultFont.metaType().id() == QMetaType::QFont)
1997 ed->setRichTextDefaultFont(qvariant_cast<QFont>(richTextDefaultFont));
1998 m_stringPropertyToEditors[property].append(ed);
1999 connect(ed, &QObject::destroyed, ed,
2000 [this, property] (QObject *o) { this->slotEditorDestroyed(property, o); });
2001 connect(ed, &TextEditor::textChanged, ed, [this, property](const QString &text) {
2002 this->slotStringTextChanged(property, text);
2003 });
2004 editor = ed;
2005 } else if (type == DesignerPropertyManager::designerStringListTypeId() || type == QMetaType::QStringList) {
2006 const QVariant variantValue = manager->value(property);
2007 const QStringList value = type == QMetaType::QStringList
2008 ? variantValue.toStringList() : qvariant_cast<PropertySheetStringListValue>(variantValue).value();
2009 StringListEditorButton *ed = new StringListEditorButton(value, parent);
2010 m_stringListPropertyToEditors[property].append(ed);
2011 connect(ed, &QObject::destroyed, ed,
2012 [this, property](QObject *o) { this->slotEditorDestroyed(property, o); });
2013 connect(ed, &StringListEditorButton::stringListChanged, ed, [this, property](const QStringList &value) {
2014 this->slotStringListChanged(property, value);
2015 });
2016 editor = ed;
2017 } else if (type == DesignerPropertyManager::designerKeySequenceTypeId()) {
2018 QKeySequenceEdit *ed = new QKeySequenceEdit(parent);
2019 ed->setKeySequence(qvariant_cast<PropertySheetKeySequenceValue>(manager->value(property)).value());
2020 m_keySequencePropertyToEditors[property].append(ed);
2021 connect(ed, &QObject::destroyed, ed,
2022 [this, property](QObject *o) { this->slotEditorDestroyed(property, o); });
2023 connect(ed, &QKeySequenceEdit::keySequenceChanged, ed,
2024 [this, property](const QKeySequence &value) {
2025 this->slotKeySequenceChanged(property, value);
2026 });
2027 editor = ed;
2028 } else {
2029 editor = QtVariantEditorFactory::createEditor(manager, property, parent);
2030 }
2031 break;
2032 }
2033
2034 // Note: editor may be null for parent properties of subproperties
2035 const bool resettable =
2036 manager->variantProperty(property)->attributeValue(resettableAttributeC).toBool();
2037 if (!resettable)
2038 return editor;
2039
2040 if (editor == nullptr) {
2041 // Resettable parent property of sub properties, merely displaying the value
2042 auto *dummyEditor = new DummyEditor(property);
2043 dummyEditor->setSpacing(m_spacing);
2044 dummyEditor->propertyChanged(property);
2045 connect(manager, &QtAbstractPropertyManager::propertyChanged,
2046 dummyEditor, &DummyEditor::propertyChanged);
2047 editor = dummyEditor;
2048 }
2049
2050 auto *resetWidget = new PropertyResetWidget(m_core, property, editor, parent);
2051 resetWidget->setSpacing(m_spacing);
2052 resetWidget->propertyChanged(property);
2053 connect(manager, &QtAbstractPropertyManager::propertyChanged, resetWidget,
2054 &PropertyResetWidget::propertyChanged);
2055 connect(resetWidget, &PropertyResetWidget::resetProperty, this,
2056 &DesignerEditorFactory::resetProperty);
2057 return resetWidget;
2058}
2059
2060template <class Editor>
2061bool removeEditor(const QtProperty *property, QObject *object,
2062 QHash<const QtProperty *, QList<Editor *>> *propertyToEditors)
2063{
2064 const auto p2eIt = propertyToEditors->find(property);
2065 if (p2eIt != propertyToEditors->end()) {
2066 auto &editorList = p2eIt.value();
2067 auto lit = std::find(editorList.cbegin(), editorList.cend(), object);
2068 if (lit != editorList.cend()) {
2069 editorList.erase(lit);
2070 if (editorList.isEmpty())
2071 propertyToEditors->erase(p2eIt);
2072 return true;
2073 }
2074 }
2075 return false;
2076}
2077
2078void DesignerEditorFactory::slotEditorDestroyed(QtProperty *property, QObject *object)
2079{
2080 if (removeEditor(property, object, &m_stringPropertyToEditors))
2081 return;
2082 if (removeEditor(property, object, &m_keySequencePropertyToEditors))
2083 return;
2084 if (removeEditor(property, object, &m_palettePropertyToEditors))
2085 return;
2086 if (removeEditor(property, object, &m_pixmapPropertyToEditors))
2087 return;
2088 if (removeEditor(property, object, &m_iconPropertyToEditors))
2089 return;
2090 if (removeEditor(property, object, &m_uintPropertyToEditors))
2091 return;
2092 if (removeEditor(property, object, &m_longLongPropertyToEditors))
2093 return;
2094 if (removeEditor(property, object, &m_intPropertyToComboEditors))
2095 return;
2096 if (removeEditor(property, object, &m_uLongLongPropertyToEditors))
2097 return;
2098 if (removeEditor(property, object, &m_urlPropertyToEditors))
2099 return;
2100 if (removeEditor(property, object, &m_byteArrayPropertyToEditors))
2101 return;
2102 if (removeEditor(property, object, &m_stringListPropertyToEditors))
2103 return;
2104}
2105
2106static void updateManager(QtVariantEditorFactory *factory, bool *changingPropertyValue,
2107 QtProperty *prop, const QVariant &value)
2108{
2109 QtVariantPropertyManager *manager = factory->propertyManager(prop);
2110 *changingPropertyValue = true;
2111 manager->variantProperty(prop)->setValue(value);
2112 *changingPropertyValue = false;
2113}
2114
2115void DesignerEditorFactory::slotUintChanged(QtProperty *prop, const QString &value)
2116{
2117 updateManager(this, &m_changingPropertyValue, prop, value.toUInt());
2118}
2119
2120void DesignerEditorFactory::slotLongLongChanged(QtProperty *prop, const QString &value)
2121{
2122 updateManager(this, &m_changingPropertyValue, prop, value.toLongLong());
2123}
2124
2125void DesignerEditorFactory::slotIntChanged(QtProperty *prop, int v)
2126{
2127 updateManager(this, &m_changingPropertyValue, prop, v);
2128}
2129
2130void DesignerEditorFactory::slotULongLongChanged(QtProperty *prop, const QString &value)
2131{
2132 updateManager(this, &m_changingPropertyValue, prop, value.toULongLong());
2133}
2134
2135void DesignerEditorFactory::slotUrlChanged(QtProperty *prop, const QString &value)
2136{
2137 updateManager(this, &m_changingPropertyValue, prop, QUrl(value));
2138}
2139
2140void DesignerEditorFactory::slotByteArrayChanged(QtProperty *prop, const QString &value)
2141{
2142 updateManager(this, &m_changingPropertyValue, prop, value.toUtf8());
2143}
2144
2145template <class Editor>
2146QtProperty *findPropertyForEditor(const QHash<Editor *, QtProperty *> &editorMap,
2147 const QObject *sender)
2148{
2149 for (auto it = editorMap.constBegin(), cend = editorMap.constEnd(); it != cend; ++it)
2150 if (it.key() == sender)
2151 return it.value();
2152 return nullptr;
2153}
2154
2155void DesignerEditorFactory::slotStringTextChanged(QtProperty *prop, const QString &value)
2156{
2157 QtVariantPropertyManager *manager = propertyManager(prop);
2158 QtVariantProperty *varProp = manager->variantProperty(prop);
2159 QVariant val = varProp->value();
2160 if (val.userType() == DesignerPropertyManager::designerStringTypeId()) {
2161 PropertySheetStringValue strVal = qvariant_cast<PropertySheetStringValue>(val);
2162 strVal.setValue(value);
2163 // Disable translation if no translation subproperties exist.
2164 if (varProp->subProperties().isEmpty())
2165 strVal.setTranslatable(false);
2166 val = QVariant::fromValue(strVal);
2167 } else {
2168 val = QVariant(value);
2169 }
2170 m_changingPropertyValue = true;
2171 manager->variantProperty(prop)->setValue(val);
2172 m_changingPropertyValue = false;
2173}
2174
2175void DesignerEditorFactory::slotKeySequenceChanged(QtProperty *prop, const QKeySequence &value)
2176{
2177 QtVariantPropertyManager *manager = propertyManager(prop);
2178 QtVariantProperty *varProp = manager->variantProperty(prop);
2179 QVariant val = varProp->value();
2180 if (val.userType() == DesignerPropertyManager::designerKeySequenceTypeId()) {
2181 PropertySheetKeySequenceValue keyVal = qvariant_cast<PropertySheetKeySequenceValue>(val);
2182 keyVal.setValue(value);
2183 val = QVariant::fromValue(keyVal);
2184 } else {
2185 val = QVariant::fromValue(value);
2186 }
2187 m_changingPropertyValue = true;
2188 manager->variantProperty(prop)->setValue(val);
2189 m_changingPropertyValue = false;
2190}
2191
2192void DesignerEditorFactory::slotPaletteChanged(QtProperty *prop, const QPalette &value)
2193{
2194 updateManager(this, &m_changingPropertyValue, prop, QVariant::fromValue(value));
2195}
2196
2197void DesignerEditorFactory::slotPixmapChanged(QtProperty *prop, const QString &value)
2198{
2199 updateManager(this, &m_changingPropertyValue, prop,
2200 QVariant::fromValue(PropertySheetPixmapValue(value)));
2201}
2202
2203void DesignerEditorFactory::slotIconChanged(QtProperty *prop, const QString &value)
2204{
2205 updateManager(this, &m_changingPropertyValue, prop,
2206 QVariant::fromValue(PropertySheetIconValue(PropertySheetPixmapValue(value))));
2207}
2208
2209void DesignerEditorFactory::slotIconThemeChanged(QtProperty *prop, const QString &value)
2210{
2211 PropertySheetIconValue icon;
2212 icon.setTheme(value);
2213 updateManager(this, &m_changingPropertyValue, prop, QVariant::fromValue(icon));
2214}
2215
2216void DesignerEditorFactory::slotIconThemeEnumChanged(QtProperty *prop, int value)
2217{
2218 PropertySheetIconValue icon;
2219 icon.setThemeEnum(value);
2220 updateManager(this, &m_changingPropertyValue, prop, QVariant::fromValue(icon));
2221}
2222
2223void DesignerEditorFactory::slotStringListChanged(QtProperty *prop, const QStringList &value)
2224{
2225 QtVariantPropertyManager *manager = propertyManager(prop);
2226 QtVariantProperty *varProp = manager->variantProperty(prop);
2227 QVariant val = varProp->value();
2228 if (val.userType() == DesignerPropertyManager::designerStringListTypeId()) {
2229 PropertySheetStringListValue listValue = qvariant_cast<PropertySheetStringListValue>(val);
2230 listValue.setValue(value);
2231 // Disable translation if no translation subproperties exist.
2232 if (varProp->subProperties().isEmpty())
2233 listValue.setTranslatable(false);
2234 val = QVariant::fromValue(listValue);
2235 } else {
2236 val = QVariant(value);
2237 }
2238 m_changingPropertyValue = true;
2239 manager->variantProperty(prop)->setValue(val);
2240 m_changingPropertyValue = false;
2241}
2242
2243}
2244
2245QT_END_NAMESPACE
static constexpr auto defaultResourceAttributeC
static constexpr auto themeEnumAttributeC
static constexpr auto flagsAttributeC
static constexpr auto validationModesAttributeC
static constexpr auto resettableAttributeC
static constexpr auto themeAttributeC
static constexpr auto superPaletteAttributeC
static constexpr auto fontAttributeC
Combined button and popup list for selecting options.