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