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

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