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
propertyeditor.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
5
12
15#include "shared_enums_p.h"
16
17// sdk
18#include <QtDesigner/abstractformeditor.h>
19#include <QtDesigner/abstractformwindowmanager.h>
20#include <QtDesigner/qextensionmanager.h>
21#include <QtDesigner/propertysheet.h>
22#include <QtDesigner/abstractwidgetdatabase.h>
23#include <QtDesigner/abstractsettings.h>
24// shared
25#include <qdesigner_utils_p.h>
26#include <qdesigner_propertycommand_p.h>
27#include <metadatabase_p.h>
28#include <iconloader_p.h>
29#include <widgetfactory_p.h>
30
31#include <QtWidgets/qlabel.h>
32#include <QtWidgets/qlineedit.h>
33#include <QtWidgets/qmenu.h>
34#include <QtWidgets/qapplication.h>
35#include <QtWidgets/qboxlayout.h>
36#include <QtWidgets/qscrollarea.h>
37#include <QtWidgets/qstackedwidget.h>
38#include <QtWidgets/qtoolbar.h>
39#include <QtWidgets/qtoolbutton.h>
40
41#include <QtGui/qaction.h>
42#include <QtGui/qactiongroup.h>
43#include <QtGui/qpainter.h>
44
45#include <QtCore/qdebug.h>
46#include <QtCore/qtextstream.h>
47#include <QtCore/qtimezone.h>
48
49enum SettingsView { TreeView, ButtonView };
50
51QT_BEGIN_NAMESPACE
52
53using namespace Qt::StringLiterals;
54
55static constexpr auto SettingsGroupC = "PropertyEditor"_L1;
56static constexpr auto ViewKeyC = "View"_L1;
57static constexpr auto ColorKeyC = "Colored"_L1;
58static constexpr auto SortedKeyC = "Sorted"_L1;
59static constexpr auto ExpansionKeyC = "ExpandedItems"_L1;
60static constexpr auto SplitterPositionKeyC = "SplitterPosition"_L1;
61
62// ---------------------------------------------------------------------------------
63
64namespace qdesigner_internal {
65
66// ----------- ElidingLabel
67// QLabel does not support text eliding so we need a helper class
68
69class ElidingLabel : public QWidget
70{
71public:
72 explicit ElidingLabel(const QString &text = QString(),
73 QWidget *parent = nullptr) : QWidget(parent), m_text(text)
74 { setContentsMargins(3, 2, 3, 2); }
75
76 void setText(const QString &text) {
77 m_text = text;
78 updateGeometry();
79 }
80 void setElidemode(Qt::TextElideMode mode) {
81 m_mode = mode;
82 updateGeometry();
83 }
84
85protected:
86 QSize sizeHint() const override;
87 void paintEvent(QPaintEvent *e) override;
88
89private:
90 QString m_text;
91 Qt::TextElideMode m_mode = Qt::ElideRight;
92};
93
95{
96 QSize size = fontMetrics().boundingRect(m_text).size();
97 size += QSize(contentsMargins().left() + contentsMargins().right(),
98 contentsMargins().top() + contentsMargins().bottom());
99 return size;
100}
101
102void ElidingLabel::paintEvent(QPaintEvent *) {
103 QPainter painter(this);
104 painter.setPen(QColor(0, 0, 0, 60));
105 painter.setBrush(QColor(255, 255, 255, 40));
106 painter.drawRect(rect().adjusted(0, 0, -1, -1));
107 painter.setPen(palette().windowText().color());
108 painter.drawText(contentsRect(), Qt::AlignLeft,
109 fontMetrics().elidedText(m_text, Qt::ElideRight, width(), 0));
110}
111
112
113// ----------- PropertyEditor::Strings
114
115PropertyEditor::Strings::Strings() :
116 m_alignmentProperties{u"alignment"_s,
117 u"layoutLabelAlignment"_s, // QFormLayout
118 u"layoutFormAlignment"_s},
119 m_fontProperty(u"font"_s),
120 m_qLayoutWidget(u"QLayoutWidget"_s),
121 m_designerPrefix(u"QDesigner"_s),
122 m_layout(u"Layout"_s),
123 m_validationModeAttribute(u"validationMode"_s),
124 m_fontAttribute(u"font"_s),
125 m_superPaletteAttribute(u"superPalette"_s),
126 m_enumNamesAttribute(u"enumNames"_s),
127 m_resettableAttribute(u"resettable"_s),
128 m_flagsAttribute(u"flags"_s)
129{
130}
131
132// ----------- PropertyEditor
133
134QDesignerMetaDataBaseItemInterface* PropertyEditor::metaDataBaseItem() const
135{
136 QObject *o = object();
137 if (!o)
138 return nullptr;
139 QDesignerMetaDataBaseInterface *db = core()->metaDataBase();
140 if (!db)
141 return nullptr;
142 return db->item(o);
143}
144
145void PropertyEditor::setupStringProperty(QtVariantProperty *property, bool isMainContainer)
146{
147 const StringPropertyParameters params = textPropertyValidationMode(core(), m_object, property->propertyName(), isMainContainer);
148 // Does a meta DB entry exist - add comment
149 const bool hasComment = params.second;
150 property->setAttribute(m_strings.m_validationModeAttribute, params.first);
151 // assuming comment cannot appear or disappear for the same property in different object instance
152 if (!hasComment)
153 qDeleteAll(property->subProperties());
154}
155
156void PropertyEditor::setupPaletteProperty(QtVariantProperty *property)
157{
158 QPalette superPalette = QPalette();
159 QWidget *currentWidget = qobject_cast<QWidget *>(m_object);
160 if (currentWidget) {
161 if (currentWidget->isWindow())
162 superPalette = QApplication::palette(currentWidget);
163 else {
164 if (currentWidget->parentWidget())
165 superPalette = currentWidget->parentWidget()->palette();
166 }
167 }
168 m_updatingBrowser = true;
169 property->setAttribute(m_strings.m_superPaletteAttribute, superPalette);
170 m_updatingBrowser = false;
171}
172
180
181PropertyEditor::PropertyEditor(QDesignerFormEditorInterface *core, QWidget *parent, Qt::WindowFlags flags) :
182 QDesignerPropertyEditor(parent, flags),
183 m_core(core),
184 m_propertyManager(new DesignerPropertyManager(m_core, this)),
185 m_stackedWidget(new QStackedWidget),
186 m_filterWidget(new QLineEdit),
187 m_addDynamicAction(new QAction(createIconSet("plus.png"_L1), tr("Add Dynamic Property..."), this)),
188 m_removeDynamicAction(new QAction(createIconSet("minus.png"_L1), tr("Remove Dynamic Property"), this)),
189 m_sortingAction(new QAction(createIconSet("sort.png"_L1), tr("Sorting"), this)),
190 m_coloringAction(new QAction(createIconSet("color.png"_L1), tr("Color Groups"), this)),
191 m_treeAction(new QAction(tr("Tree View"), this)),
192 m_buttonAction(new QAction(tr("Drop Down Button View"), this)),
193 m_classLabel(new ElidingLabel)
194{
195 const QColor colors[] = {{255, 230, 191}, {255, 255, 191}, {191, 255, 191},
196 {199, 255, 255}, {234, 191, 255}, {255, 191, 239}};
197 const int darknessFactor = 250;
198 m_colors.reserve(std::size(colors));
199 for (const QColor &c : colors)
200 m_colors.append({c, c.darker(darknessFactor)});
201 QColor dynamicColor(191, 207, 255);
202 QColor layoutColor(255, 191, 191);
203 m_dynamicColor = {dynamicColor, dynamicColor.darker(darknessFactor)};
204 m_layoutColor = {layoutColor, layoutColor.darker(darknessFactor)};
205
206 updateForegroundBrightness();
207
208 QActionGroup *actionGroup = new QActionGroup(this);
209
210 m_treeAction->setCheckable(true);
211 m_treeAction->setIcon(createIconSet("widgets/listview.png"_L1));
212 m_buttonAction->setCheckable(true);
213 m_buttonAction->setIcon(createIconSet("dropdownbutton.png"_L1));
214
215 actionGroup->addAction(m_treeAction);
216 actionGroup->addAction(m_buttonAction);
217 connect(actionGroup, &QActionGroup::triggered,
218 this, &PropertyEditor::slotViewTriggered);
219
220 // Add actions
221 QActionGroup *addDynamicActionGroup = new QActionGroup(this);
222 connect(addDynamicActionGroup, &QActionGroup::triggered,
223 this, &PropertyEditor::slotAddDynamicProperty);
224
225 QMenu *addDynamicActionMenu = new QMenu(this);
226 m_addDynamicAction->setMenu(addDynamicActionMenu);
227 m_addDynamicAction->setEnabled(false);
228 QAction *addDynamicAction = addDynamicActionGroup->addAction(tr("String..."));
229 addDynamicAction->setData(static_cast<int>(QMetaType::QString));
230 addDynamicActionMenu->addAction(addDynamicAction);
231 addDynamicAction = addDynamicActionGroup->addAction(tr("Bool..."));
232 addDynamicAction->setData(static_cast<int>(QMetaType::Bool));
233 addDynamicActionMenu->addAction(addDynamicAction);
234 addDynamicActionMenu->addSeparator();
235 addDynamicAction = addDynamicActionGroup->addAction(tr("Other..."));
236 addDynamicAction->setData(static_cast<int>(QMetaType::UnknownType));
237 addDynamicActionMenu->addAction(addDynamicAction);
238 // remove
239 m_removeDynamicAction->setEnabled(false);
240 connect(m_removeDynamicAction, &QAction::triggered, this, &PropertyEditor::slotRemoveDynamicProperty);
241 // Configure
242 QAction *configureAction = new QAction(tr("Configure Property Editor"), this);
243 configureAction->setIcon(createIconSet("configure.png"_L1));
244 QMenu *configureMenu = new QMenu(this);
245 configureAction->setMenu(configureMenu);
246
247 m_sortingAction->setCheckable(true);
248 connect(m_sortingAction, &QAction::toggled, this, &PropertyEditor::slotSorting);
249
250 m_coloringAction->setCheckable(true);
251 connect(m_coloringAction, &QAction::toggled, this, &PropertyEditor::slotColoring);
252
253 configureMenu->addAction(m_sortingAction);
254 configureMenu->addAction(m_coloringAction);
255 configureMenu->addSeparator();
256 configureMenu->addAction(m_treeAction);
257 configureMenu->addAction(m_buttonAction);
258 // Assemble toolbar
259 QToolBar *toolBar = new QToolBar;
260 toolBar->addWidget(m_filterWidget);
261 toolBar->addWidget(createDropDownButton(m_addDynamicAction));
262 toolBar->addAction(m_removeDynamicAction);
263 toolBar->addWidget(createDropDownButton(configureAction));
264 // Views
265 QScrollArea *buttonScroll = new QScrollArea(m_stackedWidget);
266 m_buttonBrowser = new QtButtonPropertyBrowser(buttonScroll);
267 buttonScroll->setWidgetResizable(true);
268 buttonScroll->setWidget(m_buttonBrowser);
269 m_buttonIndex = m_stackedWidget->addWidget(buttonScroll);
270 connect(m_buttonBrowser, &QtAbstractPropertyBrowser::currentItemChanged,
271 this, &PropertyEditor::slotCurrentItemChanged);
272
273 m_treeBrowser = new QtTreePropertyBrowser(m_stackedWidget);
274 m_treeBrowser->setRootIsDecorated(false);
276 m_treeBrowser->setResizeMode(QtTreePropertyBrowser::Interactive);
277 m_treeIndex = m_stackedWidget->addWidget(m_treeBrowser);
278 connect(m_treeBrowser, &QtAbstractPropertyBrowser::currentItemChanged,
279 this, &PropertyEditor::slotCurrentItemChanged);
280 m_filterWidget->setPlaceholderText(tr("Filter"));
281 m_filterWidget->setClearButtonEnabled(true);
282 connect(m_filterWidget, &QLineEdit::textChanged, this, &PropertyEditor::setFilter);
283
284 QVBoxLayout *layout = new QVBoxLayout(this);
285 layout->addWidget(toolBar);
286 layout->addWidget(m_classLabel);
287 layout->addSpacerItem(new QSpacerItem(0,1));
288 layout->addWidget(m_stackedWidget);
289 layout->setContentsMargins(QMargins());
290 layout->setSpacing(0);
291
292 m_treeFactory = new DesignerEditorFactory(m_core, this);
293 m_treeFactory->setSpacing(0);
294 m_groupFactory = new DesignerEditorFactory(m_core, this);
295 QtVariantPropertyManager *variantManager = m_propertyManager;
296 m_buttonBrowser->setFactoryForManager(variantManager, m_groupFactory);
297 m_treeBrowser->setFactoryForManager(variantManager, m_treeFactory);
298
299 m_stackedWidget->setCurrentIndex(m_treeIndex);
300 m_currentBrowser = m_treeBrowser;
301 m_treeAction->setChecked(true);
302
303 connect(m_groupFactory, &DesignerEditorFactory::resetProperty,
304 this, &PropertyEditor::slotResetProperty);
305 connect(m_treeFactory, &DesignerEditorFactory::resetProperty,
306 this, &PropertyEditor::slotResetProperty);
307 connect(m_propertyManager, &DesignerPropertyManager::valueChanged,
308 this, &PropertyEditor::slotValueChanged);
309
310 // retrieve initial settings
311 QDesignerSettingsInterface *settings = m_core->settingsManager();
312 settings->beginGroup(SettingsGroupC);
313 const SettingsView view = settings->value(ViewKeyC, TreeView).toInt() == TreeView ? TreeView : ButtonView;
314 // Coloring not available unless treeview and not sorted
315 m_sorting = settings->value(SortedKeyC, false).toBool();
316 m_coloring = settings->value(ColorKeyC, true).toBool();
317 const QVariantMap expansionState = settings->value(ExpansionKeyC, QVariantMap()).toMap();
318 const int splitterPosition = settings->value(SplitterPositionKeyC, 150).toInt();
319 settings->endGroup();
320 // Apply settings
321 m_sortingAction->setChecked(m_sorting);
322 m_coloringAction->setChecked(m_coloring);
323 m_treeBrowser->setSplitterPosition(splitterPosition);
324 switch (view) {
325 case TreeView:
326 m_currentBrowser = m_treeBrowser;
327 m_stackedWidget->setCurrentIndex(m_treeIndex);
328 m_treeAction->setChecked(true);
329 break;
330 case ButtonView:
331 m_currentBrowser = m_buttonBrowser;
332 m_stackedWidget->setCurrentIndex(m_buttonIndex);
333 m_buttonAction->setChecked(true);
334 break;
335 }
336 // Restore expansionState from QVariant map
337 for (auto it = expansionState.cbegin(), cend = expansionState.cend(); it != cend; ++it)
338 m_expansionState.insert(it.key(), it.value().toBool());
339
340 updateActionsState();
341}
342
344{
345 // Prevent emission of QtTreePropertyBrowser::itemChanged() when deleting
346 // the current item, causing asserts.
347 m_treeBrowser->setCurrentItem(nullptr);
348 storeExpansionState();
349 saveSettings();
350}
351
352void PropertyEditor::saveSettings() const
353{
354 QDesignerSettingsInterface *settings = m_core->settingsManager();
355 settings->beginGroup(SettingsGroupC);
356 settings->setValue(ViewKeyC, QVariant(m_treeAction->isChecked() ? TreeView : ButtonView));
357 settings->setValue(ColorKeyC, QVariant(m_coloring));
358 settings->setValue(SortedKeyC, QVariant(m_sorting));
359 // Save last expansionState as QVariant map
360 QVariantMap expansionState;
361 for (auto it = m_expansionState.cbegin(), cend = m_expansionState.cend(); it != cend; ++it)
362 expansionState.insert(it.key(), QVariant(it.value()));
363 settings->setValue(ExpansionKeyC, expansionState);
364 settings->setValue(SplitterPositionKeyC, m_treeBrowser->splitterPosition());
365 settings->endGroup();
366}
367
368void PropertyEditor::setExpanded(QtBrowserItem *item, bool expanded)
369{
370 if (m_buttonBrowser == m_currentBrowser)
371 m_buttonBrowser->setExpanded(item, expanded);
372 else if (m_treeBrowser == m_currentBrowser)
373 m_treeBrowser->setExpanded(item, expanded);
374}
375
376bool PropertyEditor::isExpanded(QtBrowserItem *item) const
377{
378 if (m_buttonBrowser == m_currentBrowser)
379 return m_buttonBrowser->isExpanded(item);
380 if (m_treeBrowser == m_currentBrowser)
381 return m_treeBrowser->isExpanded(item);
382 return false;
383}
384
385void PropertyEditor::setItemVisible(QtBrowserItem *item, bool visible)
386{
387 if (m_currentBrowser == m_treeBrowser) {
388 m_treeBrowser->setItemVisible(item, visible);
389 } else {
390 qWarning("** WARNING %s is not implemented for this browser.", Q_FUNC_INFO);
391 }
392}
393
394bool PropertyEditor::isItemVisible(QtBrowserItem *item) const
395{
396 return m_currentBrowser == m_treeBrowser ? m_treeBrowser->isItemVisible(item) : true;
397}
398
399/* Default handling of items not found in the map:
400 * - Top-level items (classes) are assumed to be expanded
401 * - Anything below (properties) is assumed to be collapsed
402 * That is, the map is required, the state cannot be stored in a set */
403
404void PropertyEditor::storePropertiesExpansionState(const QList<QtBrowserItem *> &items)
405{
406 for (QtBrowserItem *propertyItem : items) {
407 if (!propertyItem->children().isEmpty()) {
408 QtProperty *property = propertyItem->property();
409 const QString propertyName = property->propertyName();
410 const auto itGroup = m_propertyToGroup.constFind(property);
411 if (itGroup != m_propertyToGroup.constEnd()) {
412 const QString key = itGroup.value() + u'|' + propertyName;
413 m_expansionState[key] = isExpanded(propertyItem);
414 }
415 }
416 }
417}
418
419void PropertyEditor::storeExpansionState()
420{
421 const auto items = m_currentBrowser->topLevelItems();
422 if (m_sorting) {
423 storePropertiesExpansionState(items);
424 } else {
425 for (QtBrowserItem *item : items) {
426 const QString groupName = item->property()->propertyName();
427 auto propertyItems = item->children();
428 if (!propertyItems.isEmpty())
429 m_expansionState[groupName] = isExpanded(item);
430
431 // properties stuff here
432 storePropertiesExpansionState(propertyItems);
433 }
434 }
435}
436
437void PropertyEditor::collapseAll()
438{
439 const auto items = m_currentBrowser->topLevelItems();
440 for (QtBrowserItem *group : items)
441 setExpanded(group, false);
442}
443
444void PropertyEditor::applyPropertiesExpansionState(const QList<QtBrowserItem *> &items)
445{
446 for (QtBrowserItem *propertyItem : items) {
447 const auto excend = m_expansionState.cend();
448 QtProperty *property = propertyItem->property();
449 const QString propertyName = property->propertyName();
450 const auto itGroup = m_propertyToGroup.constFind(property);
451 if (itGroup != m_propertyToGroup.constEnd()) {
452 const QString key = itGroup.value() + u'|' + propertyName;
453 const auto pit = m_expansionState.constFind(key);
454 if (pit != excend)
455 setExpanded(propertyItem, pit.value());
456 else
457 setExpanded(propertyItem, false);
458 }
459 }
460}
461
462void PropertyEditor::applyExpansionState()
463{
464 const auto items = m_currentBrowser->topLevelItems();
465 if (m_sorting) {
466 applyPropertiesExpansionState(items);
467 } else {
468 const auto excend = m_expansionState.cend();
469 for (QtBrowserItem *item : items) {
470 const QString groupName = item->property()->propertyName();
471 const auto git = m_expansionState.constFind(groupName);
472 if (git != excend)
473 setExpanded(item, git.value());
474 else
475 setExpanded(item, true);
476 // properties stuff here
477 applyPropertiesExpansionState(item->children());
478 }
479 }
480}
481
482int PropertyEditor::applyPropertiesFilter(const QList<QtBrowserItem *> &items)
483{
484 int showCount = 0;
485 const bool matchAll = m_filterPattern.isEmpty();
486 for (QtBrowserItem *propertyItem : items) {
487 QtProperty *property = propertyItem->property();
488 const QString propertyName = property->propertyName();
489 const bool showProperty = matchAll || propertyName.contains(m_filterPattern, Qt::CaseInsensitive);
490 setItemVisible(propertyItem, showProperty);
491 if (showProperty)
492 showCount++;
493 }
494 return showCount;
495}
496
497void PropertyEditor::applyFilter()
498{
499 const auto items = m_currentBrowser->topLevelItems();
500 if (m_sorting) {
501 applyPropertiesFilter(items);
502 } else {
503 for (QtBrowserItem *item : items)
504 setItemVisible(item, applyPropertiesFilter(item->children()));
505 }
506}
507
508void PropertyEditor::clearView()
509{
510 m_currentBrowser->clear();
511}
512
513bool PropertyEditor::event(QEvent *event)
514{
515 if (event->type() == QEvent::PaletteChange)
516 updateForegroundBrightness();
517
518 return QDesignerPropertyEditor::event(event);
519}
520
521void PropertyEditor::updateForegroundBrightness()
522{
523 QColor c = palette().color(QPalette::Text);
524 bool newBrightness = qRound(0.3 * c.redF() + 0.59 * c.greenF() + 0.11 * c.blueF());
525
526 if (m_brightness == newBrightness)
527 return;
528
529 m_brightness = newBrightness;
530
531 updateColors();
532}
533
534QColor PropertyEditor::propertyColor(QtProperty *property) const
535{
536 if (!m_coloring)
537 return QColor();
538
539 QtProperty *groupProperty = property;
540
541 const auto itProp = m_propertyToGroup.constFind(property);
542 if (itProp != m_propertyToGroup.constEnd())
543 groupProperty = m_nameToGroup.value(itProp.value());
544
545 const int groupIdx = m_groups.indexOf(groupProperty);
546 std::pair<QColor, QColor> pair;
547 if (groupIdx != -1) {
548 if (groupProperty == m_dynamicGroup)
549 pair = m_dynamicColor;
550 else if (isLayoutGroup(groupProperty))
551 pair = m_layoutColor;
552 else
553 pair = m_colors[groupIdx % m_colors.size()];
554 }
555 if (!m_brightness)
556 return pair.first;
557 return pair.second;
558}
559
560void PropertyEditor::fillView()
561{
562 if (m_sorting) {
563 for (auto itProperty = m_nameToProperty.cbegin(), end = m_nameToProperty.cend(); itProperty != end; ++itProperty)
564 m_currentBrowser->addProperty(itProperty.value());
565 } else {
566 for (QtProperty *group : std::as_const(m_groups)) {
567 QtBrowserItem *item = m_currentBrowser->addProperty(group);
568 if (m_currentBrowser == m_treeBrowser)
569 m_treeBrowser->setBackgroundColor(item, propertyColor(group));
570 group->setModified(m_currentBrowser == m_treeBrowser);
571 }
572 }
573}
574
575bool PropertyEditor::isLayoutGroup(QtProperty *group) const
576{
577 return group->propertyName() == m_strings.m_layout;
578}
579
580void PropertyEditor::updateActionsState()
581{
582 m_coloringAction->setEnabled(m_treeAction->isChecked() && !m_sortingAction->isChecked());
583}
584
585void PropertyEditor::slotViewTriggered(QAction *action)
586{
588 collapseAll();
589 {
590 UpdateBlocker ub(this);
591 clearView();
592 int idx = 0;
593 if (action == m_treeAction) {
596 } else if (action == m_buttonAction) {
599 }
600 fillView();
603 applyFilter();
604 }
606}
607
608void PropertyEditor::slotSorting(bool sort)
609{
610 if (sort == m_sorting)
611 return;
612
613 storeExpansionState();
614 m_sorting = sort;
615 collapseAll();
616 {
617 UpdateBlocker ub(this);
618 clearView();
619 m_treeBrowser->setRootIsDecorated(sort);
620 fillView();
621 applyExpansionState();
622 applyFilter();
623 }
624 updateActionsState();
625}
626
627void PropertyEditor::updateColors()
628{
629 if (m_treeBrowser && m_currentBrowser == m_treeBrowser) {
630 const auto items = m_treeBrowser->topLevelItems();
631 for (QtBrowserItem *item : items)
632 m_treeBrowser->setBackgroundColor(item, propertyColor(item->property()));
633 }
634}
635
636void PropertyEditor::slotColoring(bool coloring)
637{
638 if (coloring == m_coloring)
639 return;
640
641 m_coloring = coloring;
642
643 updateColors();
644}
645
646void PropertyEditor::slotAddDynamicProperty(QAction *action)
647{
648 if (!m_propertySheet)
649 return;
650
653
654 if (!dynamicSheet)
655 return;
656
659 { // Make sure the dialog is closed before the signal is emitted.
660 const int type = action->data().toInt();
662 if (type != QMetaType::UnknownType)
664
666 const int propertyCount = m_propertySheet->count();
667 for (int i = 0; i < propertyCount; i++) {
670 }
672 if (dlg.exec() == QDialog::Rejected)
673 return;
676 }
679}
680
681QDesignerFormEditorInterface *PropertyEditor::core() const
682{
683 return m_core;
684}
685
687{
688 return false;
689}
690
691void PropertyEditor::setReadOnly(bool /*readOnly*/)
692{
693 qDebug() << "PropertyEditor::setReadOnly() request";
694}
695
696void PropertyEditor::setPropertyValue(const QString &name, const QVariant &value, bool changed)
697{
698 const auto it = m_nameToProperty.constFind(name);
699 if (it == m_nameToProperty.constEnd())
700 return;
701 QtVariantProperty *property = it.value();
702 updateBrowserValue(property, value);
703 property->setModified(changed);
704}
705
706/* Quick update that assumes the actual count of properties has not changed
707 * N/A when for example executing a layout command and margin properties appear. */
709{
710 if (!m_propertySheet)
711 return;
712
713 updateToolBarLabel();
714
715 const int propertyCount = m_propertySheet->count();
716 const auto npcend = m_nameToProperty.cend();
717 for (int i = 0; i < propertyCount; ++i) {
718 const QString propertyName = m_propertySheet->propertyName(i);
719 const auto it = m_nameToProperty.constFind(propertyName);
720 if (it != npcend)
721 updateBrowserValue(it.value(), m_propertySheet->property(i));
722 }
723}
724
725static inline QLayout *layoutOfQLayoutWidget(QObject *o)
726{
727 if (o->isWidgetType() && !qstrcmp(o->metaObject()->className(), "QLayoutWidget"))
728 return static_cast<QWidget*>(o)->layout();
729 return nullptr;
730}
731
732void PropertyEditor::updateToolBarLabel()
733{
734 QString objectName;
735 QString className;
736 if (m_object) {
737 if (QLayout *l = layoutOfQLayoutWidget(m_object))
738 objectName = l->objectName();
739 else
740 objectName = m_object->objectName();
741 className = realClassName(m_object);
742 }
743
744 m_classLabel->setVisible(!objectName.isEmpty() || !className.isEmpty());
745 m_classLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
746
747 QString classLabelText;
748 if (!objectName.isEmpty())
749 classLabelText += objectName + " : "_L1;
750 classLabelText += className;
751
752 m_classLabel->setText(classLabelText);
753 m_classLabel->setToolTip(tr("Object: %1\nClass: %2")
754 .arg(objectName, className));
755}
756
757void PropertyEditor::updateBrowserValue(QtVariantProperty *property, const QVariant &value)
758{
759 QVariant v = value;
760 const int type = property->propertyType();
762 const PropertySheetEnumValue e = qvariant_cast<PropertySheetEnumValue>(v);
763 v = e.metaEnum.keys().indexOf(e.metaEnum.valueToKey(e.value));
765 const PropertySheetFlagValue f = qvariant_cast<PropertySheetFlagValue>(v);
766 v = QVariant(f.value);
768 const PropertySheetFlagValue f = qvariant_cast<PropertySheetFlagValue>(v);
769 v = QVariant(f.value);
770 }
771 QDesignerPropertySheet *sheet = qobject_cast<QDesignerPropertySheet*>(m_core->extensionManager()->extension(m_object, Q_TYPEID(QDesignerPropertySheetExtension)));
772 int index = -1;
773 if (sheet)
774 index = sheet->indexOf(property->propertyName());
775 if (sheet && m_propertyToGroup.contains(property)) { // don't do it for comments since property sheet doesn't keep them
776 property->setEnabled(sheet->isEnabled(index));
777 }
778
779 // Rich text string property with comment: Store/Update the font the rich text editor dialog starts out with
780 if (type == QMetaType::QString && !property->subProperties().isEmpty()) {
781 const int fontIndex = m_propertySheet->indexOf(m_strings.m_fontProperty);
782 if (fontIndex != -1)
783 property->setAttribute(m_strings.m_fontAttribute, m_propertySheet->property(fontIndex));
784 }
785
786 m_updatingBrowser = true;
787 property->setValue(v);
788 if (sheet && sheet->isResourceProperty(index))
789 property->setAttribute(u"defaultResource"_s, sheet->defaultResourceProperty(index));
790 m_updatingBrowser = false;
791}
792
793int PropertyEditor::toBrowserType(const QVariant &value, const QString &propertyName) const
794{
795 if (value.canConvert<PropertySheetFlagValue>()) {
796 if (m_strings.m_alignmentProperties.contains(propertyName))
799 }
800 if (value.canConvert<PropertySheetEnumValue>())
802
803 return value.userType();
804}
805
806QString PropertyEditor::realClassName(QObject *object) const
807{
808 if (!object)
809 return QString();
810
811 QString className = QLatin1StringView(object->metaObject()->className());
812 const QDesignerWidgetDataBaseInterface *db = core()->widgetDataBase();
813 if (QDesignerWidgetDataBaseItemInterface *widgetItem = db->item(db->indexOfObject(object, true))) {
814 className = widgetItem->name();
815
816 if (object->isWidgetType() && className == m_strings.m_qLayoutWidget
817 && static_cast<QWidget*>(object)->layout()) {
818 className = QLatin1StringView(static_cast<QWidget*>(object)->layout()->metaObject()->className());
819 }
820 }
821
822 if (className.startsWith(m_strings.m_designerPrefix))
823 className.remove(1, m_strings.m_designerPrefix.size() - 1);
824
825 return className;
826}
827
828static const char *typeName(int type)
829{
830 if (type == qMetaTypeId<PropertySheetStringValue>())
831 type = QMetaType::QString;
832 if (type < int(QMetaType::User))
833 return QMetaType(type).name();
834 if (type == qMetaTypeId<PropertySheetIconValue>())
835 return "QIcon";
836 if (type == qMetaTypeId<PropertySheetPixmapValue>())
837 return "QPixmap";
838 if (type == qMetaTypeId<PropertySheetKeySequenceValue>())
839 return "QKeySequence";
840 if (type == qMetaTypeId<PropertySheetFlagValue>())
841 return "QFlags";
842 if (type == qMetaTypeId<PropertySheetEnumValue>())
843 return "enum";
844 if (type == QMetaType::UnknownType)
845 return "invalid";
846 if (type == QMetaType::User)
847 return "user type";
848 const auto metaType = QMetaType(type);
849 if (metaType.isValid())
850 return metaType.name();
851 return nullptr;
852}
853
854static QString msgUnsupportedType(const QString &propertyName, int type)
855{
856 QString rc;
857 QTextStream str(&rc);
858 const char *typeS = typeName(type);
859 str << "The property \"" << propertyName << "\" of type ("
860 << (typeS ? typeS : "unknown") << ") is not supported yet.";
861 return rc;
862}
863
864static QString msgDeprecatedProperty(const QLatin1StringView version,
865 const QString &baseTip)
866{
867 return PropertyEditor::tr("Deprecated since Qt %1: %2").arg(version, baseTip);
868}
869
870static QString basePropertyToolTip(const QString &propertyName, int type)
871{
872 QString result;
873 if (const char *typeS = typeName(type))
874 result = propertyName + " ("_L1 + QLatin1StringView(typeS) + u')';
875 return result;
876}
877
878static QString propertyToolTip(const QDesignerFormEditorInterface *core,
879 const QString &className,
880 const QString &propertyName, int type)
881{
882 const QDesignerCustomWidgetData customData = core->pluginManager()->customWidgetData(className);
883 if (!customData.isNull()) {
884 if (QString customToolTip = customData.propertyToolTip(propertyName); !customToolTip.isEmpty())
885 return customToolTip;
886 }
887 const QString base = basePropertyToolTip(propertyName, type);
888 // QTBUG-108199, timeSpec deprecation
889 if (type == QtVariantPropertyManager::enumTypeId() && propertyName == "timeSpec"_L1)
890 return msgDeprecatedProperty("6.9"_L1, base);
891 return base;
892}
893
894void PropertyEditor::setObject(QObject *object)
895{
896 QDesignerFormWindowInterface *oldFormWindow = QDesignerFormWindowInterface::findFormWindow(m_object);
897 // In the first setObject() call following the addition of a dynamic property, focus and edit it.
898 const bool editNewDynamicProperty = object != nullptr && m_object == object && !m_recentlyAddedDynamicProperty.isEmpty();
899 m_object = object;
900 m_propertyManager->setObject(object);
901 QDesignerFormWindowInterface *formWindow = QDesignerFormWindowInterface::findFormWindow(m_object);
902 // QTBUG-68507: Form window can be null for objects in Morph Undo macros with buddies
903 if (object != nullptr && formWindow == nullptr) {
904 formWindow = m_core->formWindowManager()->activeFormWindow();
905 if (formWindow == nullptr) {
906 qWarning("PropertyEditor::setObject(): Unable to find form window for \"%s\".",
907 qPrintable(object->objectName()));
908 return;
909 }
910 }
911 FormWindowBase *fwb = qobject_cast<FormWindowBase *>(formWindow);
912 const bool idIdBasedTranslation = fwb && fwb->useIdBasedTranslations();
913 const bool idIdBasedTranslationUnchanged = (idIdBasedTranslation == DesignerPropertyManager::useIdBasedTranslations());
915 m_treeFactory->setFormWindowBase(fwb);
916 m_groupFactory->setFormWindowBase(fwb);
917
918 storeExpansionState();
919
920 UpdateBlocker ub(this);
921
922 updateToolBarLabel();
923
924 QMap<QString, QtVariantProperty *> toRemove = m_nameToProperty;
925
926 const QDesignerDynamicPropertySheetExtension *dynamicSheet =
927 qt_extension<QDesignerDynamicPropertySheetExtension*>(m_core->extensionManager(), m_object);
928 const QDesignerPropertySheet *sheet = qobject_cast<QDesignerPropertySheet*>(m_core->extensionManager()->extension(m_object, Q_TYPEID(QDesignerPropertySheetExtension)));
929
930 // Optimizization: Instead of rebuilding the complete list every time, compile a list of properties to remove,
931 // remove them, traverse the sheet, in case property exists just set a value, otherwise - create it.
932 QExtensionManager *m = m_core->extensionManager();
933
934 m_propertySheet = qobject_cast<QDesignerPropertySheetExtension*>(m->extension(object, Q_TYPEID(QDesignerPropertySheetExtension)));
935 if (m_propertySheet) {
936 const int stringTypeId = qMetaTypeId<PropertySheetStringValue>();
937 const int propertyCount = m_propertySheet->count();
938 for (int i = 0; i < propertyCount; ++i) {
939 if (!m_propertySheet->isVisible(i))
940 continue;
941
942 const QString propertyName = m_propertySheet->propertyName(i);
943 if (m_propertySheet->indexOf(propertyName) != i)
944 continue;
945 const QString groupName = m_propertySheet->propertyGroup(i);
946 const auto rit = toRemove.constFind(propertyName);
947 if (rit != toRemove.constEnd()) {
948 QtVariantProperty *property = rit.value();
949 const int propertyType = property->propertyType();
950 // Also remove string properties in case a change in translation mode
951 // occurred since different sub-properties are used (disambiguation/id).
952 if (m_propertyToGroup.value(property) == groupName
953 && (idIdBasedTranslationUnchanged || propertyType != stringTypeId)
954 && toBrowserType(m_propertySheet->property(i), propertyName) == propertyType) {
955 toRemove.remove(propertyName);
956 }
957 }
958 }
959 }
960
961 for (auto itRemove = toRemove.cbegin(), end = toRemove.cend(); itRemove != end; ++itRemove) {
962 QtVariantProperty *property = itRemove.value();
963 m_nameToProperty.remove(itRemove.key());
964 m_propertyToGroup.remove(property);
965 delete property;
966 }
967
968 if (oldFormWindow != formWindow)
970
971 bool isMainContainer = false;
972 if (QWidget *widget = qobject_cast<QWidget*>(object)) {
973 if (QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(widget)) {
974 isMainContainer = (fw->mainContainer() == widget);
975 }
976 }
977 m_groups.clear();
978
979 if (m_propertySheet) {
980 const QString className = WidgetFactory::classNameOf(formWindow->core(), m_object);
981
982 QtProperty *lastProperty = nullptr;
983 QtProperty *lastGroup = nullptr;
984 const int propertyCount = m_propertySheet->count();
985 for (int i = 0; i < propertyCount; ++i) {
986 if (!m_propertySheet->isVisible(i))
987 continue;
988
989 const QString propertyName = m_propertySheet->propertyName(i);
990 if (m_propertySheet->indexOf(propertyName) != i)
991 continue;
992 const QVariant value = m_propertySheet->property(i);
993
994 const int type = toBrowserType(value, propertyName);
995
996 QtVariantProperty *property = m_nameToProperty.value(propertyName, 0);
997 bool newProperty = property == nullptr;
998 if (newProperty) {
999 property = m_propertyManager->addProperty(type, propertyName);
1000 if (property) {
1001 newProperty = true;
1003 const PropertySheetEnumValue e = qvariant_cast<PropertySheetEnumValue>(value);
1004 m_updatingBrowser = true;
1005 property->setAttribute(m_strings.m_enumNamesAttribute, e.metaEnum.keys());
1006 m_updatingBrowser = false;
1008 const PropertySheetFlagValue f = qvariant_cast<PropertySheetFlagValue>(value);
1009 QList<std::pair<QString, uint>> flags;
1010 for (const QString &name : f.metaFlags.keys()) {
1011 const uint val = f.metaFlags.keyToValue(name);
1012 flags.append({name, val});
1013 }
1014 m_updatingBrowser = true;
1015 QVariant v;
1016 v.setValue(flags);
1017 property->setAttribute(m_strings.m_flagsAttribute, v);
1018 m_updatingBrowser = false;
1019 }
1020 }
1021 }
1022
1023 if (property != nullptr) {
1024 const bool dynamicProperty = (dynamicSheet && dynamicSheet->isDynamicProperty(i))
1025 || (sheet && sheet->isDefaultDynamicProperty(i));
1026 QString descriptionToolTip = dynamicProperty
1027 ? basePropertyToolTip(propertyName, type)
1028 : propertyToolTip(formWindow->core(), className, propertyName, type);
1029 if (!descriptionToolTip.isEmpty())
1030 property->setDescriptionToolTip(descriptionToolTip);
1031 switch (type) {
1032 case QMetaType::QPalette:
1033 setupPaletteProperty(property);
1034 break;
1035 case QMetaType::QKeySequence:
1036 //addCommentProperty(property, propertyName);
1037 break;
1038 default:
1039 break;
1040 }
1041 if (type == QMetaType::QString || type == qMetaTypeId<PropertySheetStringValue>())
1042 setupStringProperty(property, isMainContainer);
1043 property->setAttribute(m_strings.m_resettableAttribute, m_propertySheet->hasReset(i));
1044
1045 const QString groupName = m_propertySheet->propertyGroup(i);
1046 QtVariantProperty *groupProperty = nullptr;
1047
1048 if (newProperty) {
1049 auto itPrev = m_nameToProperty.insert(propertyName, property);
1050 m_propertyToGroup[property] = groupName;
1051 if (m_sorting) {
1052 QtProperty *previous = nullptr;
1053 if (itPrev != m_nameToProperty.begin())
1054 previous = (--itPrev).value();
1055 m_currentBrowser->insertProperty(property, previous);
1056 }
1057 }
1058 const auto gnit = m_nameToGroup.constFind(groupName);
1059 if (gnit != m_nameToGroup.constEnd()) {
1060 groupProperty = gnit.value();
1061 } else {
1062 groupProperty = m_propertyManager->addProperty(QtVariantPropertyManager::groupTypeId(), groupName);
1063 QtBrowserItem *item = nullptr;
1064 if (!m_sorting)
1065 item = m_currentBrowser->insertProperty(groupProperty, lastGroup);
1066 m_nameToGroup[groupName] = groupProperty;
1067 m_groups.append(groupProperty);
1068 if (dynamicProperty)
1069 m_dynamicGroup = groupProperty;
1070 if (m_currentBrowser == m_treeBrowser && item) {
1071 m_treeBrowser->setBackgroundColor(item, propertyColor(groupProperty));
1072 groupProperty->setModified(true);
1073 }
1074 }
1075 /* Group changed or new group. Append to last subproperty of
1076 * that group. Note that there are cases in which a derived
1077 * property sheet appends fake properties for the class
1078 * which will appear after the layout group properties
1079 * (QWizardPage). To make them appear at the end of the
1080 * actual class group, goto last element. */
1081 if (lastGroup != groupProperty) {
1082 lastGroup = groupProperty;
1083 lastProperty = nullptr; // Append at end
1084 const auto subProperties = lastGroup->subProperties();
1085 if (!subProperties.isEmpty())
1086 lastProperty = subProperties.constLast();
1087 lastGroup = groupProperty;
1088 }
1089 if (!m_groups.contains(groupProperty))
1090 m_groups.append(groupProperty);
1091 if (newProperty)
1092 groupProperty->insertSubProperty(property, lastProperty);
1093
1094 lastProperty = property;
1095
1096 updateBrowserValue(property, value);
1097
1098 property->setModified(m_propertySheet->isChanged(i));
1099 if (propertyName == "geometry"_L1 && type == QMetaType::QRect) {
1100 const auto &subProperties = property->subProperties();
1101 for (QtProperty *subProperty : subProperties) {
1102 const QString subPropertyName = subProperty->propertyName();
1103 if (subPropertyName == "X"_L1 || subPropertyName == "Y"_L1)
1104 subProperty->setEnabled(!isMainContainer);
1105 }
1106 }
1107 } else {
1108 // QTBUG-80417, suppress warning for QDateEdit::timeZone
1109 const int typeId = value.typeId();
1110 if (typeId != qMetaTypeId<QTimeZone>())
1111 qWarning("%s", qPrintable(msgUnsupportedType(propertyName, type)));
1112 }
1113 }
1114 }
1115 QMap<QString, QtVariantProperty *> groups = m_nameToGroup;
1116 for (auto itGroup = groups.cbegin(), end = groups.cend(); itGroup != end; ++itGroup) {
1117 QtVariantProperty *groupProperty = itGroup.value();
1118 if (groupProperty->subProperties().isEmpty()) {
1119 if (groupProperty == m_dynamicGroup)
1120 m_dynamicGroup = nullptr;
1121 delete groupProperty;
1122 m_nameToGroup.remove(itGroup.key());
1123 }
1124 }
1125 const bool addEnabled = dynamicSheet ? dynamicSheet->dynamicPropertiesAllowed() : false;
1126 m_addDynamicAction->setEnabled(addEnabled);
1127 m_removeDynamicAction->setEnabled(false);
1128 applyExpansionState();
1129 applyFilter();
1130 // In the first setObject() call following the addition of a dynamic property, focus and edit it.
1131 if (editNewDynamicProperty) {
1132 // Have QApplication process the events related to completely closing the modal 'add' dialog,
1133 // otherwise, we cannot focus the property editor in docked mode.
1134 QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
1135 editProperty(m_recentlyAddedDynamicProperty);
1136 }
1137 m_recentlyAddedDynamicProperty.clear();
1138 m_filterWidget->setEnabled(object);
1139}
1140
1142{
1143 m_updatingBrowser = true;
1144 m_propertyManager->reloadResourceProperties();
1145 m_updatingBrowser = false;
1146}
1147
1148QtBrowserItem *PropertyEditor::nonFakePropertyBrowserItem(QtBrowserItem *item) const
1149{
1150 // Top-level properties are QObject/QWidget groups, etc. Find first item property below
1151 // which should be nonfake
1152 const auto topLevelItems = m_currentBrowser->topLevelItems();
1153 do {
1154 if (topLevelItems.contains(item->parent()))
1155 return item;
1156 item = item->parent();
1157 } while (item);
1158 return nullptr;
1159}
1160
1162{
1163 if (QtBrowserItem *browserItem = m_currentBrowser->currentItem())
1164 if (QtBrowserItem *topLevelItem = nonFakePropertyBrowserItem(browserItem)) {
1165 return topLevelItem->property()->propertyName();
1166 }
1167 return QString();
1168}
1169
1170void PropertyEditor::slotResetProperty(QtProperty *property)
1171{
1172 QDesignerFormWindowInterface *form = m_core->formWindowManager()->activeFormWindow();
1173 if (!form)
1174 return;
1175
1176 if (m_propertyManager->resetFontSubProperty(property))
1177 return;
1178
1179 if (m_propertyManager->resetIconSubProperty(property))
1180 return;
1181
1182 if (m_propertyManager->resetTextAlignmentProperty(property))
1183 return;
1184
1185 if (!m_propertyToGroup.contains(property))
1186 return;
1187
1188 emit resetProperty(property->propertyName());
1189}
1190
1191void PropertyEditor::slotValueChanged(QtProperty *property, const QVariant &value, bool enableSubPropertyHandling)
1192{
1193 if (m_updatingBrowser)
1194 return;
1195
1196 if (!m_propertySheet)
1197 return;
1198
1199 QtVariantProperty *varProp = m_propertyManager->variantProperty(property);
1200
1201 if (!varProp)
1202 return;
1203
1204 if (!m_propertyToGroup.contains(property))
1205 return;
1206
1208 PropertySheetEnumValue e = qvariant_cast<PropertySheetEnumValue>(m_propertySheet->property(m_propertySheet->indexOf(property->propertyName())));
1209 const int val = value.toInt();
1210 const QString valName = varProp->attributeValue(m_strings.m_enumNamesAttribute).toStringList().at(val);
1211 bool ok = false;
1212 e.value = e.metaEnum.parseEnum(valName, &ok);
1213 Q_ASSERT(ok);
1214 QVariant v;
1215 v.setValue(e);
1216 emitPropertyValueChanged(property->propertyName(), v, true);
1217 return;
1218 }
1219
1220 emitPropertyValueChanged(property->propertyName(), value, enableSubPropertyHandling);
1221}
1222
1223bool PropertyEditor::isDynamicProperty(const QtBrowserItem* item) const
1224{
1225 if (!item)
1226 return false;
1227
1228 const QDesignerDynamicPropertySheetExtension *dynamicSheet =
1229 qt_extension<QDesignerDynamicPropertySheetExtension*>(m_core->extensionManager(), m_object);
1230
1231 if (!dynamicSheet)
1232 return false;
1233
1234 return m_propertyToGroup.contains(item->property())
1235 && dynamicSheet->isDynamicProperty(m_propertySheet->indexOf(item->property()->propertyName()));
1236}
1237
1238void PropertyEditor::editProperty(const QString &name)
1239{
1240 // find the browser item belonging to the property, make it current and edit it
1241 QtBrowserItem *browserItem = nullptr;
1242 if (QtVariantProperty *property = m_nameToProperty.value(name, 0)) {
1243 const auto items = m_currentBrowser->items(property);
1244 if (items.size() == 1)
1245 browserItem = items.constFirst();
1246 }
1247 if (browserItem == nullptr)
1248 return;
1249 m_currentBrowser->setFocus(Qt::OtherFocusReason);
1250 if (m_currentBrowser == m_treeBrowser) { // edit is currently only supported in tree view
1251 m_treeBrowser->editItem(browserItem);
1252 } else {
1253 m_currentBrowser->setCurrentItem(browserItem);
1254 }
1255}
1256
1257void PropertyEditor::slotCurrentItemChanged(QtBrowserItem *item)
1258{
1259 m_removeDynamicAction->setEnabled(isDynamicProperty(item));
1260
1261}
1262
1263void PropertyEditor::slotRemoveDynamicProperty()
1264{
1265 if (QtBrowserItem* item = m_currentBrowser->currentItem())
1266 if (isDynamicProperty(item))
1267 emit removeDynamicProperty(item->property()->propertyName());
1268}
1269
1270void PropertyEditor::setFilter(const QString &pattern)
1271{
1272 m_filterPattern = pattern;
1273 applyFilter();
1274}
1275}
1276
1277QT_END_NAMESPACE
virtual bool dynamicPropertiesAllowed() const =0
virtual bool isDynamicProperty(int index) const =0
The QDesignerMetaDataBaseItemInterface class provides an interface to individual items in \QD's meta ...
friend class QWidget
Definition qpainter.h:431
QtBrowserItem * currentItem() const
Returns the current item in the property browser.
QtBrowserItem * insertProperty(QtProperty *property, QtProperty *afterProperty)
Inserts the given property (and its subproperties) after the specified afterProperty in the browser's...
void setCurrentItem(QtBrowserItem *)
Sets the current item in the property browser to item.
void clear()
Removes all the properties from the editor, but does not delete them since they can still be used in ...
The QtBrowserItem class represents a property in a property browser instance.
QtProperty * property() const
Returns the property which is accosiated with this item.
QtBrowserItem * parent() const
Returns the parent item of this item.
The QtButtonPropertyBrowser class provides a drop down QToolButton based property browser.
bool isExpanded(QtBrowserItem *item) const
Returns true if the item is expanded; otherwise returns false.
void setExpanded(QtBrowserItem *item, bool expanded)
Sets the item to either collapse or expanded, depending on the value of expanded.
The QtProperty class encapsulates an instance of a property.
void setModified(bool modified)
Sets the property's modified state according to the passed modified value.
void setEnabled(bool enable)
Enables or disables the property according to the passed enable value.
void insertSubProperty(QtProperty *property, QtProperty *afterProperty)
Inserts the given property after the specified precedingProperty into this property's list of subprop...
bool isExpanded(QtBrowserItem *item) const
Returns true if the item is expanded; otherwise returns false.
void editItem(QtBrowserItem *item)
Sets the current item to item and opens the relevant editor for it.
void setItemVisible(QtBrowserItem *item, bool visible)
Sets the item to be visible, depending on the value of visible.
void setExpanded(QtBrowserItem *item, bool expanded)
Sets the item to either collapse or expanded, depending on the value of expanded.
bool isItemVisible(QtBrowserItem *item) const
Returns true if the item is visible; otherwise returns false.
void setSplitterPosition(int position)
void setPropertiesWithoutValueMarked(bool mark)
The QtVariantPropertyManager class provides and manages QVariant based properties.
static int groupTypeId()
Returns the type id for a group property.
static int enumTypeId()
Returns the type id for an enum property.
QtVariantProperty * variantProperty(const QtProperty *property) const
Returns the given property converted into a QtVariantProperty.
The QtVariantProperty class is a convenience class handling QVariant based properties.
int propertyType() const
Returns this property's type.
QSize sizeHint() const override
void setElidemode(Qt::TextElideMode mode)
void paintEvent(QPaintEvent *e) override
This event handler can be reimplemented in a subclass to receive paint events passed in event.
void setText(const QString &text)
ElidingLabel(const QString &text=QString(), QWidget *parent=nullptr)
QString currentPropertyName() const override
Returns the name of the currently selected property in the property editor.
bool event(QEvent *event) override
This virtual function receives events to an object and should return true if the event e was recogniz...
QDesignerFormEditorInterface * core() const override
Returns a pointer to \QD's current QDesignerFormEditorInterface object.
void setObject(QObject *object) override
Changes the currently selected object in \QD's workspace, to object.
void setReadOnly(bool readOnly) override
If readOnly is true, the property editor is made write protected; otherwise the write protection is r...
bool isReadOnly() const override
Returns true if the property editor is write protected; otherwise false.
Auxiliary methods to store/retrieve settings.
static QString basePropertyToolTip(const QString &propertyName, int type)
static const char * typeName(int type)
static QString propertyToolTip(const QDesignerFormEditorInterface *core, const QString &className, const QString &propertyName, int type)
static QString msgDeprecatedProperty(const QLatin1StringView version, const QString &baseTip)
static QToolButton * createDropDownButton(QAction *defaultAction, QWidget *parent=nullptr)
static QLayout * layoutOfQLayoutWidget(QObject *o)
static QString msgUnsupportedType(const QString &propertyName, int type)
static constexpr auto SplitterPositionKeyC
static constexpr auto SettingsGroupC
static constexpr auto ViewKeyC
static constexpr auto ColorKeyC
static constexpr auto ExpansionKeyC
static constexpr auto SortedKeyC