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