1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qtpropertybrowser_p.h"
5#include <QtCore/QHash>
6#include <QtGui/QIcon>
7
8#if defined(Q_CC_MSVC)
9# pragma warning(disable: 4786) /* MS VS 6: truncating debug info after 255 characters */
10#endif
11
12QT_BEGIN_NAMESPACE
13
14class QtPropertyPrivate
15{
16public:
17 explicit QtPropertyPrivate(QtAbstractPropertyManager *manager) : m_manager(manager) {}
18
19 QtProperty *q_ptr;
20
21 QtProperty *m_parentItem = nullptr;
22 QList<QtProperty *> m_subItems;
23
24 QString m_valueToolTip;
25 QString m_descriptionToolTip;
26 QString m_statusTip;
27 QString m_whatsThis;
28 QString m_name;
29 bool m_enabled = true;
30 bool m_modified = false;
31
32 QtAbstractPropertyManager * const m_manager;
33};
34
35class QtAbstractPropertyManagerPrivate
36{
37 QtAbstractPropertyManager *q_ptr;
38 Q_DECLARE_PUBLIC(QtAbstractPropertyManager)
39public:
40 void propertyDestroyed(QtProperty *property);
41 void propertyChanged(QtProperty *property) const;
42 void propertyRemoved(QtProperty *property,
43 QtProperty *parentProperty) const;
44 void propertyInserted(QtProperty *property, QtProperty *parentProperty,
45 QtProperty *afterProperty) const;
46
47 QSet<QtProperty *> m_properties;
48};
49
50/*!
51 \class QtProperty
52 \internal
53 \inmodule QtDesigner
54 \since 4.4
55
56 \brief The QtProperty class encapsulates an instance of a property.
57
58 Properties are created by objects of QtAbstractPropertyManager
59 subclasses; a manager can create properties of a given type, and
60 is used in conjunction with the QtAbstractPropertyBrowser class. A
61 property is always owned by the manager that created it, which can
62 be retrieved using the propertyManager() function.
63
64 QtProperty contains the most common property attributes, and
65 provides functions for retrieving as well as setting their values:
66
67 \table
68 \header \li Getter \li Setter
69 \row
70 \li propertyName() \li setPropertyName()
71 \row
72 \li statusTip() \li setStatusTip()
73 \row
74 \li descriptionToolTip() \li setDescriptionToolTip()
75 \row
76 \li valueToolTip() \li setValueToolTip()
77 \row
78 \li toolTip() \deprecated in 5.6 \li setToolTip() \deprecated in 5.6
79 \row
80 \li whatsThis() \li setWhatsThis()
81 \row
82 \li isEnabled() \li setEnabled()
83 \row
84 \li isModified() \li setModified()
85 \row
86 \li valueText() \li Nop
87 \row
88 \li valueIcon() \li Nop
89 \endtable
90
91 It is also possible to nest properties: QtProperty provides the
92 addSubProperty(), insertSubProperty() and removeSubProperty() functions to
93 manipulate the set of subproperties. Use the subProperties()
94 function to retrieve a property's current set of subproperties.
95 Note that nested properties are not owned by the parent property,
96 i.e. each subproperty is owned by the manager that created it.
97
98 \sa QtAbstractPropertyManager, QtBrowserItem
99*/
100
101/*!
102 Creates a property with the given \a manager.
103
104 This constructor is only useful when creating a custom QtProperty
105 subclass (e.g. QtVariantProperty). To create a regular QtProperty
106 object, use the QtAbstractPropertyManager::addProperty()
107 function instead.
108
109 \sa QtAbstractPropertyManager::addProperty()
110*/
111QtProperty::QtProperty(QtAbstractPropertyManager *manager)
112 : d_ptr(new QtPropertyPrivate(manager))
113{
114 d_ptr->q_ptr = this;
115}
116
117/*!
118 Destroys this property.
119
120 Note that subproperties are detached but not destroyed, i.e. they
121 can still be used in another context.
122
123 \sa QtAbstractPropertyManager::clear()
124
125*/
126QtProperty::~QtProperty()
127{
128 auto *parent = d_ptr->m_parentItem;
129 if (parent)
130 parent->d_ptr->m_manager->d_ptr->propertyRemoved(property: this, parentProperty: parent);
131
132 d_ptr->m_manager->d_ptr->propertyDestroyed(property: this);
133
134 for (QtProperty *property : std::as_const(t&: d_ptr->m_subItems))
135 property->d_ptr->m_parentItem = nullptr;
136
137 if (parent)
138 parent->d_ptr->m_subItems.removeAll(t: this);
139}
140
141/*!
142 Returns the set of subproperties.
143
144 Note that subproperties are not owned by \e this property, but by
145 the manager that created them.
146
147 \sa insertSubProperty(), removeSubProperty()
148*/
149QList<QtProperty *> QtProperty::subProperties() const
150{
151 return d_ptr->m_subItems;
152}
153
154QtProperty *QtProperty::parentProperty() const
155{
156 return d_ptr->m_parentItem;
157}
158
159/*!
160 Returns a pointer to the manager that owns this property.
161*/
162QtAbstractPropertyManager *QtProperty::propertyManager() const
163{
164 return d_ptr->m_manager;
165}
166
167/* Note: As of 17.7.2015 for Qt 5.6, the existing 'toolTip' of the Property
168 * Browser solution was split into valueToolTip() and descriptionToolTip()
169 * to be able to implement custom tool tip for QTBUG-45442. This could
170 * be back-ported to the solution. */
171
172/*!
173 Returns the property value's tool tip.
174
175 This is suitable for tool tips over the value (item delegate).
176
177 \since 5.6
178 \sa setValueToolTip()
179*/
180QString QtProperty::valueToolTip() const
181{
182 return d_ptr->m_valueToolTip;
183}
184
185/*!
186 Returns the property description's tool tip.
187
188 This is suitable for tool tips over the description (label).
189
190 \since 5.6
191 \sa setDescriptionToolTip()
192*/
193QString QtProperty::descriptionToolTip() const
194{
195 return d_ptr->m_descriptionToolTip;
196}
197
198/*!
199 Returns the property's status tip.
200
201 \sa setStatusTip()
202*/
203QString QtProperty::statusTip() const
204{
205 return d_ptr->m_statusTip;
206}
207
208/*!
209 Returns the property's "What's This" help text.
210
211 \sa setWhatsThis()
212*/
213QString QtProperty::whatsThis() const
214{
215 return d_ptr->m_whatsThis;
216}
217
218/*!
219 Returns the property's name.
220
221 \sa setPropertyName()
222*/
223QString QtProperty::propertyName() const
224{
225 return d_ptr->m_name;
226}
227
228/*!
229 Returns whether the property is enabled.
230
231 \sa setEnabled()
232*/
233bool QtProperty::isEnabled() const
234{
235 return d_ptr->m_enabled;
236}
237
238/*!
239 Returns whether the property is modified.
240
241 \sa setModified()
242*/
243bool QtProperty::isModified() const
244{
245 return d_ptr->m_modified;
246}
247
248/*!
249 Returns whether the property has a value.
250
251 \sa QtAbstractPropertyManager::hasValue()
252*/
253bool QtProperty::hasValue() const
254{
255 return d_ptr->m_manager->hasValue(property: this);
256}
257
258/*!
259 Returns an icon representing the current state of this property.
260
261 If the given property type can not generate such an icon, this
262 function returns an invalid icon.
263
264 \sa QtAbstractPropertyManager::valueIcon()
265*/
266QIcon QtProperty::valueIcon() const
267{
268 return d_ptr->m_manager->valueIcon(property: this);
269}
270
271/*!
272 Returns a string representing the current state of this property.
273
274 If the given property type can not generate such a string, this
275 function returns an empty string.
276
277 \sa QtAbstractPropertyManager::valueText()
278*/
279QString QtProperty::valueText() const
280{
281 return d_ptr->m_manager->valueText(property: this);
282}
283
284/*!
285 Sets the property value's tool tip to the given \a text.
286
287 \since 5.6
288 \sa valueToolTip()
289*/
290void QtProperty::setValueToolTip(const QString &text)
291{
292 if (d_ptr->m_valueToolTip == text)
293 return;
294
295 d_ptr->m_valueToolTip = text;
296 propertyChanged();
297}
298
299/*!
300 Sets the property description's tool tip to the given \a text.
301
302 \since 5.6
303 \sa descriptionToolTip()
304*/
305void QtProperty::setDescriptionToolTip(const QString &text)
306{
307 if (d_ptr->m_descriptionToolTip == text)
308 return;
309
310 d_ptr->m_descriptionToolTip = text;
311 propertyChanged();
312}
313
314/*!
315 Sets the property's status tip to the given \a text.
316
317 \sa statusTip()
318*/
319void QtProperty::setStatusTip(const QString &text)
320{
321 if (d_ptr->m_statusTip == text)
322 return;
323
324 d_ptr->m_statusTip = text;
325 propertyChanged();
326}
327
328/*!
329 Sets the property's "What's This" help text to the given \a text.
330
331 \sa whatsThis()
332*/
333void QtProperty::setWhatsThis(const QString &text)
334{
335 if (d_ptr->m_whatsThis == text)
336 return;
337
338 d_ptr->m_whatsThis = text;
339 propertyChanged();
340}
341
342/*!
343 \fn void QtProperty::setPropertyName(const QString &name)
344
345 Sets the property's name to the given \a name.
346
347 \sa propertyName()
348*/
349void QtProperty::setPropertyName(const QString &text)
350{
351 if (d_ptr->m_name == text)
352 return;
353
354 d_ptr->m_name = text;
355 propertyChanged();
356}
357
358/*!
359 Enables or disables the property according to the passed \a enable value.
360
361 \sa isEnabled()
362*/
363void QtProperty::setEnabled(bool enable)
364{
365 if (d_ptr->m_enabled == enable)
366 return;
367
368 d_ptr->m_enabled = enable;
369 propertyChanged();
370}
371
372/*!
373 Sets the property's modified state according to the passed \a modified value.
374
375 \sa isModified()
376*/
377void QtProperty::setModified(bool modified)
378{
379 if (d_ptr->m_modified == modified)
380 return;
381
382 d_ptr->m_modified = modified;
383 propertyChanged();
384}
385
386/*!
387 Appends the given \a property to this property's subproperties.
388
389 If the given \a property already is added, this function does
390 nothing.
391
392 \sa insertSubProperty(), removeSubProperty()
393*/
394void QtProperty::addSubProperty(QtProperty *property)
395{
396 QtProperty *after = nullptr;
397 if (d_ptr->m_subItems.size() > 0)
398 after = d_ptr->m_subItems.last();
399 insertSubProperty(property, afterProperty: after);
400}
401
402/*!
403 \fn void QtProperty::insertSubProperty(QtProperty *property, QtProperty *precedingProperty)
404
405 Inserts the given \a property after the specified \a
406 precedingProperty into this property's list of subproperties. If
407 \a precedingProperty is 0, the specified \a property is inserted
408 at the beginning of the list.
409
410 If the given \a property already is inserted, this function does
411 nothing.
412
413 \sa addSubProperty(), removeSubProperty()
414*/
415void QtProperty::insertSubProperty(QtProperty *property,
416 QtProperty *afterProperty)
417{
418 if (!property)
419 return;
420
421 if (property == this)
422 return;
423
424 // traverse all children of item. if this item is a child of item then cannot add.
425 auto pendingList = property->subProperties();
426 QHash<QtProperty *, bool> visited;
427 while (!pendingList.isEmpty()) {
428 QtProperty *i = pendingList.first();
429 if (i == this)
430 return;
431 pendingList.removeFirst();
432 if (visited.contains(key: i))
433 continue;
434 visited[i] = true;
435 pendingList += i->subProperties();
436 }
437
438 pendingList = subProperties();
439 int pos = 0;
440 int newPos = 0;
441 QtProperty *properAfterProperty = nullptr;
442 while (pos < pendingList.size()) {
443 QtProperty *i = pendingList.at(i: pos);
444 if (i == property)
445 return; // if item is already inserted in this item then cannot add.
446 if (i == afterProperty) {
447 newPos = pos + 1;
448 properAfterProperty = afterProperty;
449 }
450 pos++;
451 }
452
453 d_ptr->m_subItems.insert(i: newPos, t: property);
454 Q_ASSERT(property->d_ptr->m_parentItem == nullptr);
455 property->d_ptr->m_parentItem = this;
456
457 d_ptr->m_manager->d_ptr->propertyInserted(property, parentProperty: this, afterProperty: properAfterProperty);
458}
459
460/*!
461 Removes the given \a property from the list of subproperties
462 without deleting it.
463
464 \sa addSubProperty(), insertSubProperty()
465*/
466void QtProperty::removeSubProperty(QtProperty *property)
467{
468 if (!property)
469 return;
470
471 d_ptr->m_manager->d_ptr->propertyRemoved(property, parentProperty: this);
472
473 auto pendingList = subProperties();
474 int pos = 0;
475 while (pos < pendingList.size()) {
476 if (pendingList.at(i: pos) == property) {
477 d_ptr->m_subItems.removeAt(i: pos);
478
479 property->d_ptr->m_parentItem = nullptr;
480 return;
481 }
482 pos++;
483 }
484}
485
486/*!
487 \internal
488*/
489void QtProperty::propertyChanged()
490{
491 d_ptr->m_manager->d_ptr->propertyChanged(property: this);
492}
493
494////////////////////////////////
495
496void QtAbstractPropertyManagerPrivate::propertyDestroyed(QtProperty *property)
497{
498 if (m_properties.contains(value: property)) {
499 emit q_ptr->propertyDestroyed(property);
500 q_ptr->uninitializeProperty(property);
501 m_properties.remove(value: property);
502 }
503}
504
505void QtAbstractPropertyManagerPrivate::propertyChanged(QtProperty *property) const
506{
507 emit q_ptr->propertyChanged(property);
508}
509
510void QtAbstractPropertyManagerPrivate::propertyRemoved(QtProperty *property,
511 QtProperty *parentProperty) const
512{
513 emit q_ptr->propertyRemoved(property, parent: parentProperty);
514}
515
516void QtAbstractPropertyManagerPrivate::propertyInserted(QtProperty *property,
517 QtProperty *parentProperty, QtProperty *afterProperty) const
518{
519 emit q_ptr->propertyInserted(property, parent: parentProperty, after: afterProperty);
520}
521
522/*!
523 \class QtAbstractPropertyManager
524 \internal
525 \inmodule QtDesigner
526 \since 4.4
527
528 \brief The QtAbstractPropertyManager provides an interface for
529 property managers.
530
531 A manager can create and manage properties of a given type, and is
532 used in conjunction with the QtAbstractPropertyBrowser class.
533
534 When using a property browser widget, the properties are created
535 and managed by implementations of the QtAbstractPropertyManager
536 class. To ensure that the properties' values will be displayed
537 using suitable editing widgets, the managers are associated with
538 objects of QtAbstractEditorFactory subclasses. The property browser
539 will use these associations to determine which factories it should
540 use to create the preferred editing widgets.
541
542 The QtAbstractPropertyManager class provides common functionality
543 like creating a property using the addProperty() function, and
544 retrieving the properties created by the manager using the
545 properties() function. The class also provides signals that are
546 emitted when the manager's properties change: propertyInserted(),
547 propertyRemoved(), propertyChanged() and propertyDestroyed().
548
549 QtAbstractPropertyManager subclasses are supposed to provide their
550 own type specific API. Note that several ready-made
551 implementations are available:
552
553 \list
554 \li QtBoolPropertyManager
555 \li QtColorPropertyManager
556 \li QtDatePropertyManager
557 \li QtDateTimePropertyManager
558 \li QtDoublePropertyManager
559 \li QtEnumPropertyManager
560 \li QtFlagPropertyManager
561 \li QtFontPropertyManager
562 \li QtGroupPropertyManager
563 \li QtIntPropertyManager
564 \li QtPointPropertyManager
565 \li QtRectPropertyManager
566 \li QtSizePropertyManager
567 \li QtSizePolicyPropertyManager
568 \li QtStringPropertyManager
569 \li QtTimePropertyManager
570 \li QtVariantPropertyManager
571 \endlist
572
573 \sa QtAbstractEditorFactoryBase, QtAbstractPropertyBrowser, QtProperty
574*/
575
576/*!
577 \fn void QtAbstractPropertyManager::propertyInserted(QtProperty *newProperty,
578 QtProperty *parentProperty, QtProperty *precedingProperty)
579
580 This signal is emitted when a new subproperty is inserted into an
581 existing property, passing pointers to the \a newProperty, \a
582 parentProperty and \a precedingProperty as parameters.
583
584 If \a precedingProperty is 0, the \a newProperty was inserted at
585 the beginning of the \a parentProperty's subproperties list.
586
587 Note that signal is emitted only if the \a parentProperty is created
588 by this manager.
589
590 \sa QtAbstractPropertyBrowser::itemInserted()
591*/
592
593/*!
594 \fn void QtAbstractPropertyManager::propertyChanged(QtProperty *property)
595
596 This signal is emitted whenever a property's data changes, passing
597 a pointer to the \a property as parameter.
598
599 Note that signal is only emitted for properties that are created by
600 this manager.
601
602 \sa QtAbstractPropertyBrowser::itemChanged()
603*/
604
605/*!
606 \fn void QtAbstractPropertyManager::propertyRemoved(QtProperty *property, QtProperty *parent)
607
608 This signal is emitted when a subproperty is removed, passing
609 pointers to the removed \a property and the \a parent property as
610 parameters.
611
612 Note that signal is emitted only when the \a parent property is
613 created by this manager.
614
615 \sa QtAbstractPropertyBrowser::itemRemoved()
616*/
617
618/*!
619 \fn void QtAbstractPropertyManager::propertyDestroyed(QtProperty *property)
620
621 This signal is emitted when the specified \a property is about to
622 be destroyed.
623
624 Note that signal is only emitted for properties that are created
625 by this manager.
626
627 \sa clear(), uninitializeProperty()
628*/
629
630/*!
631 \fn void QtAbstractPropertyBrowser::currentItemChanged(QtBrowserItem *current)
632
633 This signal is emitted when the current item changes. The current item is specified by \a current.
634
635 \sa QtAbstractPropertyBrowser::setCurrentItem()
636*/
637
638/*!
639 Creates an abstract property manager with the given \a parent.
640*/
641QtAbstractPropertyManager::QtAbstractPropertyManager(QObject *parent)
642 : QObject(parent), d_ptr(new QtAbstractPropertyManagerPrivate)
643{
644 d_ptr->q_ptr = this;
645
646}
647
648/*!
649 Destroys the manager. All properties created by the manager are
650 destroyed.
651*/
652QtAbstractPropertyManager::~QtAbstractPropertyManager()
653{
654 clear();
655}
656
657/*!
658 Destroys all the properties that this manager has created.
659
660 \sa propertyDestroyed(), uninitializeProperty()
661*/
662void QtAbstractPropertyManager::clear() const
663{
664 while (!d_ptr->m_properties.isEmpty())
665 delete *d_ptr->m_properties.cbegin();
666}
667
668/*!
669 Returns the set of properties created by this manager.
670
671 \sa addProperty()
672*/
673QSet<QtProperty *> QtAbstractPropertyManager::properties() const
674{
675 return d_ptr->m_properties;
676}
677
678/*!
679 Returns whether the given \a property has a value.
680
681 The default implementation of this function returns true.
682
683 \sa QtProperty::hasValue()
684*/
685bool QtAbstractPropertyManager::hasValue(const QtProperty *property) const
686{
687 Q_UNUSED(property);
688 return true;
689}
690
691/*!
692 Returns an icon representing the current state of the given \a
693 property.
694
695 The default implementation of this function returns an invalid
696 icon.
697
698 \sa QtProperty::valueIcon()
699*/
700QIcon QtAbstractPropertyManager::valueIcon(const QtProperty *property) const
701{
702 Q_UNUSED(property);
703 return {};
704}
705
706/*!
707 Returns a string representing the current state of the given \a
708 property.
709
710 The default implementation of this function returns an empty
711 string.
712
713 \sa QtProperty::valueText()
714*/
715QString QtAbstractPropertyManager::valueText(const QtProperty *property) const
716{
717 Q_UNUSED(property);
718 return {};
719}
720
721/*!
722 Creates a property with the given \a name which then is owned by this manager.
723
724 Internally, this function calls the createProperty() and
725 initializeProperty() functions.
726
727 \sa initializeProperty(), properties()
728*/
729QtProperty *QtAbstractPropertyManager::addProperty(const QString &name)
730{
731 QtProperty *property = createProperty();
732 if (property) {
733 property->setPropertyName(name);
734 d_ptr->m_properties.insert(value: property);
735 initializeProperty(property);
736 }
737 return property;
738}
739
740/*!
741 Creates a property.
742
743 The base implementation produce QtProperty instances; Reimplement
744 this function to make this manager produce objects of a QtProperty
745 subclass.
746
747 \sa addProperty(), initializeProperty()
748*/
749QtProperty *QtAbstractPropertyManager::createProperty()
750{
751 return new QtProperty(this);
752}
753
754/*!
755 \fn void QtAbstractPropertyManager::initializeProperty(QtProperty *property) = 0
756
757 This function is called whenever a new valid property pointer has
758 been created, passing the pointer as parameter.
759
760 The purpose is to let the manager know that the \a property has
761 been created so that it can provide additional attributes for the
762 new property, e.g. QtIntPropertyManager adds \l
763 {QtIntPropertyManager::value()}{value}, \l
764 {QtIntPropertyManager::minimum()}{minimum} and \l
765 {QtIntPropertyManager::maximum()}{maximum} attributes. Since each manager
766 subclass adds type specific attributes, this function is pure
767 virtual and must be reimplemented when deriving from the
768 QtAbstractPropertyManager class.
769
770 \sa addProperty(), createProperty()
771*/
772
773/*!
774 This function is called just before the specified \a property is destroyed.
775
776 The purpose is to let the property manager know that the \a
777 property is being destroyed so that it can remove the property's
778 additional attributes.
779
780 \sa clear(), propertyDestroyed()
781*/
782void QtAbstractPropertyManager::uninitializeProperty(QtProperty *property)
783{
784 Q_UNUSED(property);
785}
786
787////////////////////////////////////
788
789/*!
790 \class QtAbstractEditorFactoryBase
791 \internal
792 \inmodule QtDesigner
793 \since 4.4
794
795 \brief The QtAbstractEditorFactoryBase provides an interface for
796 editor factories.
797
798 An editor factory is a class that is able to create an editing
799 widget of a specified type (e.g. line edits or comboboxes) for a
800 given QtProperty object, and it is used in conjunction with the
801 QtAbstractPropertyManager and QtAbstractPropertyBrowser classes.
802
803 When using a property browser widget, the properties are created
804 and managed by implementations of the QtAbstractPropertyManager
805 class. To ensure that the properties' values will be displayed
806 using suitable editing widgets, the managers are associated with
807 objects of QtAbstractEditorFactory subclasses. The property browser
808 will use these associations to determine which factories it should
809 use to create the preferred editing widgets.
810
811 Typically, an editor factory is created by subclassing the
812 QtAbstractEditorFactory template class which inherits
813 QtAbstractEditorFactoryBase. But note that several ready-made
814 implementations are available:
815
816 \list
817 \li QtCheckBoxFactory
818 \li QtDateEditFactory
819 \li QtDateTimeEditFactory
820 \li QtDoubleSpinBoxFactory
821 \li QtEnumEditorFactory
822 \li QtLineEditFactory
823 \li QtScrollBarFactory
824 \li QtSliderFactory
825 \li QtSpinBoxFactory
826 \li QtTimeEditFactory
827 \li QtVariantEditorFactory
828 \endlist
829
830 \sa QtAbstractPropertyManager, QtAbstractPropertyBrowser
831*/
832
833/*!
834 \fn virtual QWidget *QtAbstractEditorFactoryBase::createEditor(QtProperty *property,
835 QWidget *parent) = 0
836
837 Creates an editing widget (with the given \a parent) for the given
838 \a property.
839
840 This function is reimplemented in QtAbstractEditorFactory template class
841 which also provides a pure virtual convenience overload of this
842 function enabling access to the property's manager.
843
844 \sa QtAbstractEditorFactory::createEditor()
845*/
846
847/*!
848 \fn QtAbstractEditorFactoryBase::QtAbstractEditorFactoryBase(QObject *parent = 0)
849
850 Creates an abstract editor factory with the given \a parent.
851*/
852
853/*!
854 \fn virtual void QtAbstractEditorFactoryBase::breakConnection(QtAbstractPropertyManager *manager) = 0
855
856 \internal
857
858 Detaches property manager from factory.
859 This method is reimplemented in QtAbstractEditorFactory template subclass.
860 You don't need to reimplement it in your subclasses. Instead implement more convenient
861 QtAbstractEditorFactory::disconnectPropertyManager() which gives you access to particular manager subclass.
862*/
863
864/*!
865 \fn virtual void QtAbstractEditorFactoryBase::managerDestroyed(QObject *manager) = 0
866
867 \internal
868
869 This method is called when property manager is being destroyed.
870 Basically it notifies factory not to produce editors for properties owned by \a manager.
871 You don't need to reimplement it in your subclass. This method is implemented in
872 QtAbstractEditorFactory template subclass.
873*/
874
875/*!
876 \class QtAbstractEditorFactory
877 \internal
878 \inmodule QtDesigner
879 \since 4.4
880
881 \brief The QtAbstractEditorFactory is the base template class for editor
882 factories.
883
884 An editor factory is a class that is able to create an editing
885 widget of a specified type (e.g. line edits or comboboxes) for a
886 given QtProperty object, and it is used in conjunction with the
887 QtAbstractPropertyManager and QtAbstractPropertyBrowser classes.
888
889 Note that the QtAbstractEditorFactory functions are using the
890 PropertyManager template argument class which can be any
891 QtAbstractPropertyManager subclass. For example:
892
893 \snippet doc/src/snippets/code/tools_shared_qtpropertybrowser_qtpropertybrowser.cpp 0
894
895 Note that QtSpinBoxFactory by definition creates editing widgets
896 \e only for properties created by QtIntPropertyManager.
897
898 When using a property browser widget, the properties are created
899 and managed by implementations of the QtAbstractPropertyManager
900 class. To ensure that the properties' values will be displayed
901 using suitable editing widgets, the managers are associated with
902 objects of QtAbstractEditorFactory subclasses. The property browser will
903 use these associations to determine which factories it should use
904 to create the preferred editing widgets.
905
906 A QtAbstractEditorFactory object is capable of producing editors for
907 several property managers at the same time. To create an
908 association between this factory and a given manager, use the
909 addPropertyManager() function. Use the removePropertyManager() function to make
910 this factory stop producing editors for a given property
911 manager. Use the propertyManagers() function to retrieve the set of
912 managers currently associated with this factory.
913
914 Several ready-made implementations of the QtAbstractEditorFactory class
915 are available:
916
917 \list
918 \li QtCheckBoxFactory
919 \li QtDateEditFactory
920 \li QtDateTimeEditFactory
921 \li QtDoubleSpinBoxFactory
922 \li QtEnumEditorFactory
923 \li QtLineEditFactory
924 \li QtScrollBarFactory
925 \li QtSliderFactory
926 \li QtSpinBoxFactory
927 \li QtTimeEditFactory
928 \li QtVariantEditorFactory
929 \endlist
930
931 When deriving from the QtAbstractEditorFactory class, several pure virtual
932 functions must be implemented: the connectPropertyManager() function is
933 used by the factory to connect to the given manager's signals, the
934 createEditor() function is supposed to create an editor for the
935 given property controlled by the given manager, and finally the
936 disconnectPropertyManager() function is used by the factory to disconnect
937 from the specified manager's signals.
938
939 \sa QtAbstractEditorFactoryBase, QtAbstractPropertyManager
940*/
941
942/*!
943 \fn QtAbstractEditorFactory::QtAbstractEditorFactory(QObject *parent = 0)
944
945 Creates an editor factory with the given \a parent.
946
947 \sa addPropertyManager()
948*/
949
950/*!
951 \fn QWidget *QtAbstractEditorFactory::createEditor(QtProperty *property, QWidget *parent)
952
953 Creates an editing widget (with the given \a parent) for the given
954 \a property.
955*/
956
957/*!
958 \fn void QtAbstractEditorFactory::addPropertyManager(PropertyManager *manager)
959
960 Adds the given \a manager to this factory's set of managers,
961 making this factory produce editing widgets for properties created
962 by the given manager.
963
964 The PropertyManager type is a template argument class, and represents the chosen
965 QtAbstractPropertyManager subclass.
966
967 \sa propertyManagers(), removePropertyManager()
968*/
969
970/*!
971 \fn void QtAbstractEditorFactory::removePropertyManager(PropertyManager *manager)
972
973 Removes the given \a manager from this factory's set of
974 managers. The PropertyManager type is a template argument class, and may be
975 any QtAbstractPropertyManager subclass.
976
977 \sa propertyManagers(), addPropertyManager()
978*/
979
980/*!
981 \fn virtual void QtAbstractEditorFactory::connectPropertyManager(PropertyManager *manager) = 0
982
983 Connects this factory to the given \a manager's signals. The
984 PropertyManager type is a template argument class, and represents
985 the chosen QtAbstractPropertyManager subclass.
986
987 This function is used internally by the addPropertyManager() function, and
988 makes it possible to update an editing widget when the associated
989 property's data changes. This is typically done in custom slots
990 responding to the signals emitted by the property's manager,
991 e.g. QtIntPropertyManager::valueChanged() and
992 QtIntPropertyManager::rangeChanged().
993
994 \sa propertyManagers(), disconnectPropertyManager()
995*/
996
997/*!
998 \fn virtual QWidget *QtAbstractEditorFactory::createEditor(PropertyManager *manager, QtProperty *property,
999 QWidget *parent) = 0
1000
1001 Creates an editing widget with the given \a parent for the
1002 specified \a property created by the given \a manager. The
1003 PropertyManager type is a template argument class, and represents
1004 the chosen QtAbstractPropertyManager subclass.
1005
1006 This function must be implemented in derived classes: It is
1007 recommended to store a pointer to the widget and map it to the
1008 given \a property, since the widget must be updated whenever the
1009 associated property's data changes. This is typically done in
1010 custom slots responding to the signals emitted by the property's
1011 manager, e.g. QtIntPropertyManager::valueChanged() and
1012 QtIntPropertyManager::rangeChanged().
1013
1014 \sa connectPropertyManager()
1015*/
1016
1017/*!
1018 \fn virtual void QtAbstractEditorFactory::disconnectPropertyManager(PropertyManager *manager) = 0
1019
1020 Disconnects this factory from the given \a manager's signals. The
1021 PropertyManager type is a template argument class, and represents
1022 the chosen QtAbstractPropertyManager subclass.
1023
1024 This function is used internally by the removePropertyManager() function.
1025
1026 \sa propertyManagers(), connectPropertyManager()
1027*/
1028
1029/*!
1030 \fn QSet<PropertyManager *> QtAbstractEditorFactory::propertyManagers() const
1031
1032 Returns the factory's set of associated managers. The
1033 PropertyManager type is a template argument class, and represents
1034 the chosen QtAbstractPropertyManager subclass.
1035
1036 \sa addPropertyManager(), removePropertyManager()
1037*/
1038
1039/*!
1040 \fn PropertyManager *QtAbstractEditorFactory::propertyManager(QtProperty *property) const
1041
1042 Returns the property manager for the given \a property, or 0 if
1043 the given \a property doesn't belong to any of this factory's
1044 registered managers.
1045
1046 The PropertyManager type is a template argument class, and represents the chosen
1047 QtAbstractPropertyManager subclass.
1048
1049 \sa propertyManagers()
1050*/
1051
1052/*!
1053 \fn virtual void QtAbstractEditorFactory::managerDestroyed(QObject *manager)
1054
1055 \internal
1056*/
1057
1058////////////////////////////////////
1059class QtBrowserItemPrivate
1060{
1061public:
1062 QtBrowserItemPrivate(QtAbstractPropertyBrowser *browser, QtProperty *property, QtBrowserItem *parent)
1063 : m_browser(browser), m_property(property), m_parent(parent), q_ptr(0) {}
1064
1065 void addChild(QtBrowserItem *index, QtBrowserItem *after);
1066 void removeChild(QtBrowserItem *index);
1067
1068 QtAbstractPropertyBrowser * const m_browser;
1069 QtProperty *m_property;
1070 QtBrowserItem *m_parent;
1071
1072 QtBrowserItem *q_ptr;
1073
1074 QList<QtBrowserItem *> m_children;
1075
1076};
1077
1078void QtBrowserItemPrivate::addChild(QtBrowserItem *index, QtBrowserItem *after)
1079{
1080 if (m_children.contains(t: index))
1081 return;
1082 int idx = m_children.indexOf(t: after) + 1; // we insert after returned idx, if it was -1 then we set idx to 0;
1083 m_children.insert(i: idx, t: index);
1084}
1085
1086void QtBrowserItemPrivate::removeChild(QtBrowserItem *index)
1087{
1088 m_children.removeAll(t: index);
1089}
1090
1091
1092/*!
1093 \class QtBrowserItem
1094 \internal
1095 \inmodule QtDesigner
1096 \since 4.4
1097
1098 \brief The QtBrowserItem class represents a property in
1099 a property browser instance.
1100
1101 Browser items are created whenever a QtProperty is inserted to the
1102 property browser. A QtBrowserItem uniquely identifies a
1103 browser's item. Thus, if the same QtProperty is inserted multiple
1104 times, each occurrence gets its own unique QtBrowserItem. The
1105 items are owned by QtAbstractPropertyBrowser and automatically
1106 deleted when they are removed from the browser.
1107
1108 You can traverse a browser's properties by calling parent() and
1109 children(). The property and the browser associated with an item
1110 are available as property() and browser().
1111
1112 \sa QtAbstractPropertyBrowser, QtProperty
1113*/
1114
1115/*!
1116 Returns the property which is accosiated with this item. Note that
1117 several items can be associated with the same property instance in
1118 the same property browser.
1119
1120 \sa QtAbstractPropertyBrowser::items()
1121*/
1122
1123QtProperty *QtBrowserItem::property() const
1124{
1125 return d_ptr->m_property;
1126}
1127
1128/*!
1129 Returns the parent item of \e this item. Returns 0 if \e this item
1130 is associated with top-level property in item's property browser.
1131
1132 \sa children()
1133*/
1134
1135QtBrowserItem *QtBrowserItem::parent() const
1136{
1137 return d_ptr->m_parent;
1138}
1139
1140/*!
1141 Returns the children items of \e this item. The properties
1142 reproduced from children items are always the same as
1143 reproduced from associated property' children, for example:
1144
1145 \snippet doc/src/snippets/code/tools_shared_qtpropertybrowser_qtpropertybrowser.cpp 1
1146
1147 The \e childrenItems list represents the same list as \e childrenProperties.
1148*/
1149
1150QList<QtBrowserItem *> QtBrowserItem::children() const
1151{
1152 return d_ptr->m_children;
1153}
1154
1155/*!
1156 Returns the property browser which owns \e this item.
1157*/
1158
1159QtAbstractPropertyBrowser *QtBrowserItem::browser() const
1160{
1161 return d_ptr->m_browser;
1162}
1163
1164QtBrowserItem::QtBrowserItem(QtAbstractPropertyBrowser *browser, QtProperty *property, QtBrowserItem *parent)
1165 : d_ptr(new QtBrowserItemPrivate(browser, property, parent))
1166{
1167 d_ptr->q_ptr = this;
1168}
1169
1170QtBrowserItem::~QtBrowserItem()
1171{
1172}
1173
1174
1175////////////////////////////////////
1176
1177using Map1 = QHash<QtAbstractPropertyBrowser *,
1178 QHash<QtAbstractPropertyManager *, QtAbstractEditorFactoryBase *>>;
1179using Map2 = QHash<QtAbstractPropertyManager *,
1180 QHash<QtAbstractEditorFactoryBase *, QList<QtAbstractPropertyBrowser *>>>;
1181
1182Q_GLOBAL_STATIC(Map1, m_viewToManagerToFactory)
1183Q_GLOBAL_STATIC(Map2, m_managerToFactoryToViews)
1184
1185class QtAbstractPropertyBrowserPrivate
1186{
1187 QtAbstractPropertyBrowser *q_ptr;
1188 Q_DECLARE_PUBLIC(QtAbstractPropertyBrowser)
1189public:
1190 QtAbstractPropertyBrowserPrivate();
1191
1192 void insertSubTree(QtProperty *property,
1193 QtProperty *parentProperty);
1194 void removeSubTree(QtProperty *property,
1195 QtProperty *parentProperty);
1196 void createBrowserIndexes(QtProperty *property, QtProperty *parentProperty, QtProperty *afterProperty);
1197 void removeBrowserIndexes(QtProperty *property, QtProperty *parentProperty);
1198 QtBrowserItem *createBrowserIndex(QtProperty *property, QtBrowserItem *parentIndex, QtBrowserItem *afterIndex);
1199 void removeBrowserIndex(QtBrowserItem *index);
1200 void clearIndex(QtBrowserItem *index);
1201
1202 void slotPropertyInserted(QtProperty *property,
1203 QtProperty *parentProperty, QtProperty *afterProperty);
1204 void slotPropertyRemoved(QtProperty *property, QtProperty *parentProperty);
1205 void slotPropertyDestroyed(QtProperty *property);
1206 void slotPropertyDataChanged(QtProperty *property);
1207
1208 QList<QtProperty *> m_subItems;
1209 QHash<QtAbstractPropertyManager *, QList<QtProperty *> > m_managerToProperties;
1210 QHash<QtProperty *, QList<QtProperty *> > m_propertyToParents;
1211
1212 QHash<QtProperty *, QtBrowserItem *> m_topLevelPropertyToIndex;
1213 QList<QtBrowserItem *> m_topLevelIndexes;
1214 QHash<QtProperty *, QList<QtBrowserItem *> > m_propertyToIndexes;
1215
1216 QtBrowserItem *m_currentItem;
1217};
1218
1219QtAbstractPropertyBrowserPrivate::QtAbstractPropertyBrowserPrivate() :
1220 m_currentItem(0)
1221{
1222}
1223
1224void QtAbstractPropertyBrowserPrivate::insertSubTree(QtProperty *property,
1225 QtProperty *parentProperty)
1226{
1227 if (m_propertyToParents.contains(key: property)) {
1228 // property was already inserted, so its manager is connected
1229 // and all its children are inserted and theirs managers are connected
1230 // we just register new parent (parent has to be new).
1231 m_propertyToParents[property].append(t: parentProperty);
1232 // don't need to update m_managerToProperties map since
1233 // m_managerToProperties[manager] already contains property.
1234 return;
1235 }
1236 QtAbstractPropertyManager *manager = property->propertyManager();
1237 if (m_managerToProperties[manager].isEmpty()) {
1238 // connect manager's signals
1239 q_ptr->connect(sender: manager, signal: &QtAbstractPropertyManager::propertyInserted,
1240 context: q_ptr, slot: [this](QtProperty *property, QtProperty *parent, QtProperty *after)
1241 { slotPropertyInserted(property, parentProperty: parent, afterProperty: after); });
1242 q_ptr->connect(sender: manager, signal: &QtAbstractPropertyManager::propertyRemoved,
1243 context: q_ptr, slot: [this](QtProperty *property, QtProperty *parent)
1244 { slotPropertyRemoved(property, parentProperty: parent); });
1245 q_ptr->connect(sender: manager, signal: &QtAbstractPropertyManager::propertyDestroyed,
1246 context: q_ptr, slot: [this](QtProperty *property) { slotPropertyDestroyed(property); });
1247 q_ptr->connect(sender: manager, signal: &QtAbstractPropertyManager::propertyChanged,
1248 context: q_ptr, slot: [this](QtProperty *property) { slotPropertyDataChanged(property); });
1249 }
1250 m_managerToProperties[manager].append(t: property);
1251 m_propertyToParents[property].append(t: parentProperty);
1252
1253 const auto subList = property->subProperties();
1254 for (QtProperty *subProperty : subList)
1255 insertSubTree(property: subProperty, parentProperty: property);
1256}
1257
1258void QtAbstractPropertyBrowserPrivate::removeSubTree(QtProperty *property,
1259 QtProperty *parentProperty)
1260{
1261 if (!m_propertyToParents.contains(key: property)) {
1262 // ASSERT
1263 return;
1264 }
1265
1266 m_propertyToParents[property].removeAll(t: parentProperty);
1267 if (!m_propertyToParents[property].isEmpty())
1268 return;
1269
1270 m_propertyToParents.remove(key: property);
1271 QtAbstractPropertyManager *manager = property->propertyManager();
1272 m_managerToProperties[manager].removeAll(t: property);
1273 if (m_managerToProperties[manager].isEmpty()) {
1274 // disconnect manager's signals
1275 q_ptr->disconnect(sender: manager, signal: &QtAbstractPropertyManager::propertyInserted, receiver: q_ptr, zero: nullptr);
1276 q_ptr->disconnect(sender: manager, signal: &QtAbstractPropertyManager::propertyRemoved, receiver: q_ptr, zero: nullptr);
1277 q_ptr->disconnect(sender: manager, signal: &QtAbstractPropertyManager::propertyDestroyed, receiver: q_ptr, zero: nullptr);
1278 q_ptr->disconnect(sender: manager, signal: &QtAbstractPropertyManager::propertyChanged, receiver: q_ptr, zero: nullptr);
1279
1280 m_managerToProperties.remove(key: manager);
1281 }
1282
1283 const auto subList = property->subProperties();
1284 for (QtProperty *subProperty : subList)
1285 removeSubTree(property: subProperty, parentProperty: property);
1286}
1287
1288void QtAbstractPropertyBrowserPrivate::createBrowserIndexes(QtProperty *property, QtProperty *parentProperty, QtProperty *afterProperty)
1289{
1290 QHash<QtBrowserItem *, QtBrowserItem *> parentToAfter;
1291 if (afterProperty) {
1292 const auto it = m_propertyToIndexes.constFind(key: afterProperty);
1293 if (it == m_propertyToIndexes.constEnd())
1294 return;
1295
1296 for (QtBrowserItem *idx : it.value()) {
1297 QtBrowserItem *parentIdx = idx->parent();
1298 if ((parentProperty && parentIdx && parentIdx->property() == parentProperty) || (!parentProperty && !parentIdx))
1299 parentToAfter[idx->parent()] = idx;
1300 }
1301 } else if (parentProperty) {
1302 const auto it = m_propertyToIndexes.find(key: parentProperty);
1303 if (it == m_propertyToIndexes.constEnd())
1304 return;
1305
1306 for (QtBrowserItem *idx : it.value())
1307 parentToAfter[idx] = nullptr;
1308 } else {
1309 parentToAfter[nullptr] = nullptr;
1310 }
1311
1312 for (auto it = parentToAfter.cbegin(), pcend = parentToAfter.cend(); it != pcend; ++it)
1313 createBrowserIndex(property, parentIndex: it.key(), afterIndex: it.value());
1314}
1315
1316QtBrowserItem *QtAbstractPropertyBrowserPrivate::createBrowserIndex(QtProperty *property,
1317 QtBrowserItem *parentIndex, QtBrowserItem *afterIndex)
1318{
1319 auto *newIndex = new QtBrowserItem(q_ptr, property, parentIndex);
1320 if (parentIndex) {
1321 parentIndex->d_ptr->addChild(index: newIndex, after: afterIndex);
1322 } else {
1323 m_topLevelPropertyToIndex[property] = newIndex;
1324 m_topLevelIndexes.insert(i: m_topLevelIndexes.indexOf(t: afterIndex) + 1, t: newIndex);
1325 }
1326 m_propertyToIndexes[property].append(t: newIndex);
1327
1328 q_ptr->itemInserted(item: newIndex, afterItem: afterIndex);
1329
1330 const auto subItems = property->subProperties();
1331 QtBrowserItem *afterChild = nullptr;
1332 for (QtProperty *child : subItems)
1333 afterChild = createBrowserIndex(property: child, parentIndex: newIndex, afterIndex: afterChild);
1334 return newIndex;
1335}
1336
1337void QtAbstractPropertyBrowserPrivate::removeBrowserIndexes(QtProperty *property, QtProperty *parentProperty)
1338{
1339 QList<QtBrowserItem *> toRemove;
1340 const auto it = m_propertyToIndexes.constFind(key: property);
1341 if (it == m_propertyToIndexes.constEnd())
1342 return;
1343
1344 for (QtBrowserItem *idx : it.value()) {
1345 QtBrowserItem *parentIdx = idx->parent();
1346 if ((parentProperty && parentIdx && parentIdx->property() == parentProperty) || (!parentProperty && !parentIdx))
1347 toRemove.append(t: idx);
1348 }
1349
1350 for (QtBrowserItem *index : std::as_const(t&: toRemove))
1351 removeBrowserIndex(index);
1352}
1353
1354void QtAbstractPropertyBrowserPrivate::removeBrowserIndex(QtBrowserItem *index)
1355{
1356 const auto children = index->children();
1357 for (int i = children.size(); i > 0; i--) {
1358 removeBrowserIndex(index: children.at(i: i - 1));
1359 }
1360
1361 q_ptr->itemRemoved(item: index);
1362
1363 if (index->parent()) {
1364 index->parent()->d_ptr->removeChild(index);
1365 } else {
1366 m_topLevelPropertyToIndex.remove(key: index->property());
1367 m_topLevelIndexes.removeAll(t: index);
1368 }
1369
1370 QtProperty *property = index->property();
1371
1372 m_propertyToIndexes[property].removeAll(t: index);
1373 if (m_propertyToIndexes[property].isEmpty())
1374 m_propertyToIndexes.remove(key: property);
1375
1376 delete index;
1377}
1378
1379void QtAbstractPropertyBrowserPrivate::clearIndex(QtBrowserItem *index)
1380{
1381 const auto children = index->children();
1382 for (QtBrowserItem *item : children)
1383 clearIndex(index: item);
1384 delete index;
1385}
1386
1387void QtAbstractPropertyBrowserPrivate::slotPropertyInserted(QtProperty *property,
1388 QtProperty *parentProperty, QtProperty *afterProperty)
1389{
1390 if (!m_propertyToParents.contains(key: parentProperty))
1391 return;
1392 createBrowserIndexes(property, parentProperty, afterProperty);
1393 insertSubTree(property, parentProperty);
1394 //q_ptr->propertyInserted(property, parentProperty, afterProperty);
1395}
1396
1397void QtAbstractPropertyBrowserPrivate::slotPropertyRemoved(QtProperty *property,
1398 QtProperty *parentProperty)
1399{
1400 if (!m_propertyToParents.contains(key: parentProperty))
1401 return;
1402 removeSubTree(property, parentProperty); // this line should be probably moved down after propertyRemoved call
1403 //q_ptr->propertyRemoved(property, parentProperty);
1404 removeBrowserIndexes(property, parentProperty);
1405}
1406
1407void QtAbstractPropertyBrowserPrivate::slotPropertyDestroyed(QtProperty *property)
1408{
1409 if (!m_subItems.contains(t: property))
1410 return;
1411 q_ptr->removeProperty(property);
1412}
1413
1414void QtAbstractPropertyBrowserPrivate::slotPropertyDataChanged(QtProperty *property)
1415{
1416 if (!m_propertyToParents.contains(key: property))
1417 return;
1418
1419 const auto it = m_propertyToIndexes.constFind(key: property);
1420 if (it == m_propertyToIndexes.constEnd())
1421 return;
1422
1423 const auto indexes = it.value();
1424 for (QtBrowserItem *idx : indexes)
1425 q_ptr->itemChanged(item: idx);
1426 //q_ptr->propertyChanged(property);
1427}
1428
1429/*!
1430 \class QtAbstractPropertyBrowser
1431 \internal
1432 \inmodule QtDesigner
1433 \since 4.4
1434
1435 \brief QtAbstractPropertyBrowser provides a base class for
1436 implementing property browsers.
1437
1438 A property browser is a widget that enables the user to edit a
1439 given set of properties. Each property is represented by a label
1440 specifying the property's name, and an editing widget (e.g. a line
1441 edit or a combobox) holding its value. A property can have zero or
1442 more subproperties.
1443
1444 \image qtpropertybrowser.png
1445
1446 The top level properties can be retrieved using the
1447 properties() function. To traverse each property's
1448 subproperties, use the QtProperty::subProperties() function. In
1449 addition, the set of top level properties can be manipulated using
1450 the addProperty(), insertProperty() and removeProperty()
1451 functions. Note that the QtProperty class provides a corresponding
1452 set of functions making it possible to manipulate the set of
1453 subproperties as well.
1454
1455 To remove all the properties from the property browser widget, use
1456 the clear() function. This function will clear the editor, but it
1457 will not delete the properties since they can still be used in
1458 other editors.
1459
1460 The properties themselves are created and managed by
1461 implementations of the QtAbstractPropertyManager class. A manager
1462 can handle (i.e. create and manage) properties of a given type. In
1463 the property browser the managers are associated with
1464 implementations of the QtAbstractEditorFactory: A factory is a
1465 class able to create an editing widget of a specified type.
1466
1467 When using a property browser widget, managers must be created for
1468 each of the required property types before the properties
1469 themselves can be created. To ensure that the properties' values
1470 will be displayed using suitable editing widgets, the managers
1471 must be associated with objects of the preferred factory
1472 implementations using the setFactoryForManager() function. The
1473 property browser will use these associations to determine which
1474 factory it should use to create the preferred editing widget.
1475
1476 Note that a factory can be associated with many managers, but a
1477 manager can only be associated with one single factory within the
1478 context of a single property browser. The associations between
1479 managers and factories can at any time be removed using the
1480 unsetFactoryForManager() function.
1481
1482 Whenever the property data changes or a property is inserted or
1483 removed, the itemChanged(), itemInserted() or
1484 itemRemoved() functions are called, respectively. These
1485 functions must be reimplemented in derived classes in order to
1486 update the property browser widget. Be aware that some property
1487 instances can appear several times in an abstract tree
1488 structure. For example:
1489
1490 \table 100%
1491 \row
1492 \li
1493 \snippet doc/src/snippets/code/tools_shared_qtpropertybrowser_qtpropertybrowser.cpp 2
1494 \li \image qtpropertybrowser-duplicate.png
1495 \endtable
1496
1497 The addProperty() function returns a QtBrowserItem that uniquely
1498 identifies the created item.
1499
1500 To make a property editable in the property browser, the
1501 createEditor() function must be called to provide the
1502 property with a suitable editing widget.
1503
1504 Note that there are two ready-made property browser
1505 implementations:
1506
1507 \list
1508 \li QtGroupBoxPropertyBrowser
1509 \li QtTreePropertyBrowser
1510 \endlist
1511
1512 \sa QtAbstractPropertyManager, QtAbstractEditorFactoryBase
1513*/
1514
1515/*!
1516 \fn void QtAbstractPropertyBrowser::setFactoryForManager(PropertyManager *manager,
1517 QtAbstractEditorFactory<PropertyManager> *factory)
1518
1519 Connects the given \a manager to the given \a factory, ensuring
1520 that properties of the \a manager's type will be displayed with an
1521 editing widget suitable for their value.
1522
1523 For example:
1524
1525 \snippet doc/src/snippets/code/tools_shared_qtpropertybrowser_qtpropertybrowser.cpp 3
1526
1527 In this example the \c myInteger property's value is displayed
1528 with a QSpinBox widget, while the \c myDouble property's value is
1529 displayed with a QDoubleSpinBox widget.
1530
1531 Note that a factory can be associated with many managers, but a
1532 manager can only be associated with one single factory. If the
1533 given \a manager already is associated with another factory, the
1534 old association is broken before the new one established.
1535
1536 This function ensures that the given \a manager and the given \a
1537 factory are compatible, and it automatically calls the
1538 QtAbstractEditorFactory::addPropertyManager() function if necessary.
1539
1540 \sa unsetFactoryForManager()
1541*/
1542
1543/*!
1544 \fn virtual void QtAbstractPropertyBrowser::itemInserted(QtBrowserItem *insertedItem,
1545 QtBrowserItem *precedingItem) = 0
1546
1547 This function is called to update the widget whenever a property
1548 is inserted or added to the property browser, passing pointers to
1549 the \a insertedItem of property and the specified
1550 \a precedingItem as parameters.
1551
1552 If \a precedingItem is 0, the \a insertedItem was put at
1553 the beginning of its parent item's list of subproperties. If
1554 the parent of \a insertedItem is 0, the \a insertedItem was added as a top
1555 level property of \e this property browser.
1556
1557 This function must be reimplemented in derived classes. Note that
1558 if the \a insertedItem's property has subproperties, this
1559 method will be called for those properties as soon as the current call is finished.
1560
1561 \sa insertProperty(), addProperty()
1562*/
1563
1564/*!
1565 \fn virtual void QtAbstractPropertyBrowser::itemRemoved(QtBrowserItem *item) = 0
1566
1567 This function is called to update the widget whenever a property
1568 is removed from the property browser, passing the pointer to the
1569 \a item of the property as parameters. The passed \a item is
1570 deleted just after this call is finished.
1571
1572 If the parent of \a item is 0, the removed \a item was a
1573 top level property in this editor.
1574
1575 This function must be reimplemented in derived classes. Note that
1576 if the removed \a item's property has subproperties, this
1577 method will be called for those properties just before the current call is started.
1578
1579 \sa removeProperty()
1580*/
1581
1582/*!
1583 \fn virtual void QtAbstractPropertyBrowser::itemChanged(QtBrowserItem *item) = 0
1584
1585 This function is called whenever a property's data changes,
1586 passing a pointer to the \a item of property as parameter.
1587
1588 This function must be reimplemented in derived classes in order to
1589 update the property browser widget whenever a property's name,
1590 tool tip, status tip, "what's this" text, value text or value icon
1591 changes.
1592
1593 Note that if the property browser contains several occurrences of
1594 the same property, this method will be called once for each
1595 occurrence (with a different item each time).
1596
1597 \sa QtProperty, items()
1598*/
1599
1600/*!
1601 Creates an abstract property browser with the given \a parent.
1602*/
1603QtAbstractPropertyBrowser::QtAbstractPropertyBrowser(QWidget *parent)
1604 : QWidget(parent), d_ptr(new QtAbstractPropertyBrowserPrivate)
1605{
1606 d_ptr->q_ptr = this;
1607
1608}
1609
1610/*!
1611 Destroys the property browser, and destroys all the items that were
1612 created by this property browser.
1613
1614 Note that the properties that were displayed in the editor are not
1615 deleted since they still can be used in other editors. Neither
1616 does the destructor delete the property managers and editor
1617 factories that were used by this property browser widget unless
1618 this widget was their parent.
1619
1620 \sa QtAbstractPropertyManager::~QtAbstractPropertyManager()
1621*/
1622QtAbstractPropertyBrowser::~QtAbstractPropertyBrowser()
1623{
1624 const auto indexes = topLevelItems();
1625 for (QtBrowserItem *item : indexes)
1626 d_ptr->clearIndex(index: item);
1627}
1628
1629/*!
1630 Returns the property browser's list of top level properties.
1631
1632 To traverse the subproperties, use the QtProperty::subProperties()
1633 function.
1634
1635 \sa addProperty(), insertProperty(), removeProperty()
1636*/
1637QList<QtProperty *> QtAbstractPropertyBrowser::properties() const
1638{
1639 return d_ptr->m_subItems;
1640}
1641
1642/*!
1643 Returns the property browser's list of all items associated
1644 with the given \a property.
1645
1646 There is one item per instance of the property in the browser.
1647
1648 \sa topLevelItem()
1649*/
1650
1651QList<QtBrowserItem *> QtAbstractPropertyBrowser::items(QtProperty *property) const
1652{
1653 return d_ptr->m_propertyToIndexes.value(key: property);
1654}
1655
1656/*!
1657 Returns the top-level items associated with the given \a property.
1658
1659 Returns 0 if \a property wasn't inserted into this property
1660 browser or isn't a top-level one.
1661
1662 \sa topLevelItems(), items()
1663*/
1664
1665QtBrowserItem *QtAbstractPropertyBrowser::topLevelItem(QtProperty *property) const
1666{
1667 return d_ptr->m_topLevelPropertyToIndex.value(key: property);
1668}
1669
1670/*!
1671 Returns the list of top-level items.
1672
1673 \sa topLevelItem()
1674*/
1675
1676QList<QtBrowserItem *> QtAbstractPropertyBrowser::topLevelItems() const
1677{
1678 return d_ptr->m_topLevelIndexes;
1679}
1680
1681/*!
1682 Removes all the properties from the editor, but does not delete
1683 them since they can still be used in other editors.
1684
1685 \sa removeProperty(), QtAbstractPropertyManager::clear()
1686*/
1687void QtAbstractPropertyBrowser::clear()
1688{
1689 const auto subList = properties();
1690 for (auto rit = subList.crbegin(), rend = subList.crend(); rit != rend; ++rit)
1691 removeProperty(property: *rit);
1692}
1693
1694/*!
1695 Appends the given \a property (and its subproperties) to the
1696 property browser's list of top level properties. Returns the item
1697 created by property browser which is associated with the \a property.
1698 In order to get all children items created by the property
1699 browser in this call, the returned item should be traversed.
1700
1701 If the specified \a property is already added, this function does
1702 nothing and returns 0.
1703
1704 \sa insertProperty(), QtProperty::addSubProperty(), properties()
1705*/
1706QtBrowserItem *QtAbstractPropertyBrowser::addProperty(QtProperty *property)
1707{
1708 QtProperty *afterProperty = nullptr;
1709 if (d_ptr->m_subItems.size() > 0)
1710 afterProperty = d_ptr->m_subItems.last();
1711 return insertProperty(property, afterProperty);
1712}
1713
1714/*!
1715 \fn QtBrowserItem *QtAbstractPropertyBrowser::insertProperty(QtProperty *property,
1716 QtProperty *afterProperty)
1717
1718 Inserts the given \a property (and its subproperties) after
1719 the specified \a afterProperty in the browser's list of top
1720 level properties. Returns item created by property browser which
1721 is associated with the \a property. In order to get all children items
1722 created by the property browser in this call returned item should be traversed.
1723
1724 If the specified \a afterProperty is 0, the given \a property is
1725 inserted at the beginning of the list. If \a property is
1726 already inserted, this function does nothing and returns 0.
1727
1728 \sa addProperty(), QtProperty::insertSubProperty(), properties()
1729*/
1730QtBrowserItem *QtAbstractPropertyBrowser::insertProperty(QtProperty *property,
1731 QtProperty *afterProperty)
1732{
1733 if (!property)
1734 return nullptr;
1735
1736 // if item is already inserted in this item then cannot add.
1737 auto pendingList = properties();
1738 int pos = 0;
1739 int newPos = 0;
1740 while (pos < pendingList.size()) {
1741 QtProperty *prop = pendingList.at(i: pos);
1742 if (prop == property)
1743 return nullptr;
1744 if (prop == afterProperty) {
1745 newPos = pos + 1;
1746 }
1747 pos++;
1748 }
1749 d_ptr->createBrowserIndexes(property, parentProperty: 0, afterProperty);
1750
1751 // traverse inserted subtree and connect to manager's signals
1752 d_ptr->insertSubTree(property, parentProperty: 0);
1753
1754 d_ptr->m_subItems.insert(i: newPos, t: property);
1755 //propertyInserted(property, 0, properAfterProperty);
1756 return topLevelItem(property);
1757}
1758
1759/*!
1760 Removes the specified \a property (and its subproperties) from the
1761 property browser's list of top level properties. All items
1762 that were associated with the given \a property and its children
1763 are deleted.
1764
1765 Note that the properties are \e not deleted since they can still
1766 be used in other editors.
1767
1768 \sa clear(), QtProperty::removeSubProperty(), properties()
1769*/
1770void QtAbstractPropertyBrowser::removeProperty(QtProperty *property)
1771{
1772 if (!property)
1773 return;
1774
1775 auto pendingList = properties();
1776 int pos = 0;
1777 while (pos < pendingList.size()) {
1778 if (pendingList.at(i: pos) == property) {
1779 d_ptr->m_subItems.removeAt(i: pos); //perhaps this two lines
1780 d_ptr->removeSubTree(property, parentProperty: 0); //should be moved down after propertyRemoved call.
1781 //propertyRemoved(property, 0);
1782
1783 d_ptr->removeBrowserIndexes(property, parentProperty: 0);
1784
1785 // when item is deleted, item will call removeItem for top level items,
1786 // and itemRemoved for nested items.
1787
1788 return;
1789 }
1790 pos++;
1791 }
1792}
1793
1794/*!
1795 Creates an editing widget (with the given \a parent) for the given
1796 \a property according to the previously established associations
1797 between property managers and editor factories.
1798
1799 If the property is created by a property manager which was not
1800 associated with any of the existing factories in \e this property
1801 editor, the function returns 0.
1802
1803 To make a property editable in the property browser, the
1804 createEditor() function must be called to provide the
1805 property with a suitable editing widget.
1806
1807 Reimplement this function to provide additional decoration for the
1808 editing widgets created by the installed factories.
1809
1810 \sa setFactoryForManager()
1811*/
1812QWidget *QtAbstractPropertyBrowser::createEditor(QtProperty *property,
1813 QWidget *parent)
1814{
1815 QtAbstractEditorFactoryBase *factory = nullptr;
1816 QtAbstractPropertyManager *manager = property->propertyManager();
1817
1818 if (m_viewToManagerToFactory()->contains(key: this) &&
1819 (*m_viewToManagerToFactory())[this].contains(key: manager)) {
1820 factory = (*m_viewToManagerToFactory())[this][manager];
1821 }
1822
1823 if (!factory)
1824 return nullptr;
1825 QWidget *w = factory->createEditor(property, parent);
1826 // Since some editors can be QComboBoxes, and we changed their focus policy in Qt 5
1827 // to make them feel more native on Mac, we need to relax the focus policy to something
1828 // more permissive to keep the combo box from losing focus, allowing it to stay alive,
1829 // when the user clicks on it to show the popup.
1830 if (w)
1831 w->setFocusPolicy(Qt::WheelFocus);
1832 return w;
1833}
1834
1835bool QtAbstractPropertyBrowser::addFactory(QtAbstractPropertyManager *abstractManager,
1836 QtAbstractEditorFactoryBase *abstractFactory)
1837{
1838 bool connectNeeded = false;
1839 if (!m_managerToFactoryToViews()->contains(key: abstractManager) ||
1840 !(*m_managerToFactoryToViews())[abstractManager].contains(key: abstractFactory)) {
1841 connectNeeded = true;
1842 } else if ((*m_managerToFactoryToViews())[abstractManager][abstractFactory]
1843 .contains(t: this)) {
1844 return connectNeeded;
1845 }
1846
1847 if (m_viewToManagerToFactory()->contains(key: this) &&
1848 (*m_viewToManagerToFactory())[this].contains(key: abstractManager)) {
1849 unsetFactoryForManager(manager: abstractManager);
1850 }
1851
1852 (*m_managerToFactoryToViews())[abstractManager][abstractFactory].append(t: this);
1853 (*m_viewToManagerToFactory())[this][abstractManager] = abstractFactory;
1854
1855 return connectNeeded;
1856}
1857
1858/*!
1859 Removes the association between the given \a manager and the
1860 factory bound to it, automatically calling the
1861 QtAbstractEditorFactory::removePropertyManager() function if necessary.
1862
1863 \sa setFactoryForManager()
1864*/
1865void QtAbstractPropertyBrowser::unsetFactoryForManager(QtAbstractPropertyManager *manager)
1866{
1867 if (!m_viewToManagerToFactory()->contains(key: this) ||
1868 !(*m_viewToManagerToFactory())[this].contains(key: manager)) {
1869 return;
1870 }
1871
1872 QtAbstractEditorFactoryBase *abstractFactory =
1873 (*m_viewToManagerToFactory())[this][manager];
1874 (*m_viewToManagerToFactory())[this].remove(key: manager);
1875 if ((*m_viewToManagerToFactory())[this].isEmpty()) {
1876 (*m_viewToManagerToFactory()).remove(key: this);
1877 }
1878
1879 (*m_managerToFactoryToViews())[manager][abstractFactory].removeAll(t: this);
1880 if ((*m_managerToFactoryToViews())[manager][abstractFactory].isEmpty()) {
1881 (*m_managerToFactoryToViews())[manager].remove(key: abstractFactory);
1882 abstractFactory->breakConnection(manager);
1883 if ((*m_managerToFactoryToViews())[manager].isEmpty()) {
1884 (*m_managerToFactoryToViews()).remove(key: manager);
1885 }
1886 }
1887}
1888
1889/*!
1890 Returns the current item in the property browser.
1891
1892 \sa setCurrentItem()
1893*/
1894QtBrowserItem *QtAbstractPropertyBrowser::currentItem() const
1895{
1896 return d_ptr->m_currentItem;
1897}
1898
1899/*!
1900 Sets the current item in the property browser to \a item.
1901
1902 \sa currentItem(), currentItemChanged()
1903*/
1904void QtAbstractPropertyBrowser::setCurrentItem(QtBrowserItem *item)
1905{
1906 QtBrowserItem *oldItem = d_ptr->m_currentItem;
1907 d_ptr->m_currentItem = item;
1908 if (oldItem != item)
1909 emit currentItemChanged(item);
1910}
1911
1912QT_END_NAMESPACE
1913
1914#include "moc_qtpropertybrowser_p.cpp"
1915

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

source code of qttools/src/shared/qtpropertybrowser/qtpropertybrowser.cpp