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