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