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