KProperty

KPropertySet.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
3 Copyright (C) 2004 Alexander Dymo <cloudtemple@mskat.net>
4 Copyright (C) 2004-2017 Jarosław Staniek <staniek@kde.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to
18 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20*/
21
22#include "KPropertySet.h"
23#include "KPropertySet_p.h"
24#include "KProperty_p.h"
25
26#include <QByteArray>
27
28KPropertySetPrivate::KPropertySetPrivate(KPropertySet *set, bool isOwnProperty)
29 : q(set), m_ownProperty(isOwnProperty)
30{
31 m_groupCaptions.insert("common", QObject::tr("General", "General properties"));
32}
33
34KPropertySetPrivate::~KPropertySetPrivate()
35{
36}
37
38void KPropertySetPrivate::addProperty(KProperty *property, const QByteArray &group/*, bool updateSortingKey*/)
39{
40 if (!property) {
41 kprWarning() << "property == 0";
42 return;
43 }
44 if (property->isNull()) {
45 kprWarning() << "COULD NOT ADD NULL PROPERTY";
46 return;
47 }
48 const QByteArray realGroup(group.isEmpty() ? "common" : group);
49 KProperty *p = this->property(property->name());
50 if (p) {
51 addRelatedProperty(p, property);
52 }
53 else {
54 m_list.append(property);
55 m_hash.insert(property->name().toLower(), property);
56 if (property->isVisible()) {
57 m_visiblePropertiesCount++;
58 }
59 addToGroup(realGroup, property);
60 }
61
62 property->d->addSet(q);
63#if 0
64 if (updateSortingKey)
65 property->setSortingKey(count());
66#endif
67}
68
69void KPropertySetPrivate::removeProperty(KProperty *property)
70{
71 if (!property)
72 return;
73
74 if (!m_list.removeOne(property)) {
75 kprDebug() << "The property set does not contain property" << property;
76 return;
77 }
78 KProperty *p = m_hash.take(property->name().toLower());
79 if (p) {
80 removeFromGroup(p);
81 if (p->isVisible()) {
82 m_visiblePropertiesCount--;
83 }
84 if (m_ownProperty) {
85 emit q->aboutToDeleteProperty(*q, *p);
86 delete p;
87 }
88 }
89}
90
91void KPropertySetPrivate::clear()
92{
93 if (m_informAboutClearing) {
94 *m_informAboutClearing = true;
95 }
96 m_informAboutClearing = nullptr;
97 emit q->aboutToBeCleared();
98 m_visiblePropertiesCount = 0;
99 qDeleteAll(m_propertiesOfGroup);
100 m_propertiesOfGroup.clear();
101 m_groupNames.clear();
102 m_groupForProperties.clear();
103 m_groupCaptions.clear();
104 m_groupIconNames.clear();
105 qDeleteAll(m_list);
106 m_list.clear();
107 m_hash.clear();
108}
109
110void KPropertySetPrivate::copyAttributesFrom(const KPropertySetPrivate &other)
111{
112 KPropertySet *origSet = q;
113 *this = other;
114 q = origSet;
115 // do not copy too deeply
116 m_list.clear();
117 m_hash.clear();
118 m_propertiesOfGroup.clear();
119 m_groupForProperties.clear();
120 m_visiblePropertiesCount = 0;
121 m_informAboutClearing = nullptr;
122}
123
124void KPropertySetPrivate::copyPropertiesFrom(
125 const QList<KProperty*>::ConstIterator& constBegin,
126 const QList<KProperty*>::ConstIterator& constEnd, const KPropertySet & set)
127{
128 for (QList<KProperty*>::ConstIterator it(constBegin); it!=constEnd; ++it) {
129 KProperty *prop = new KProperty(*(*it));
130 addProperty(prop, set.d->groupForProperty( *it )
131#if 0
132 ,
133 false /* don't updateSortingKey, because the key is already
134 set in KProperty copy ctor.*/
135#endif
136 );
137 }
138}
139
140void KPropertySetPrivate::addToGroup(const QByteArray &group, KProperty *property)
141{
142 if (!property || group.isEmpty()) {
143 return;
144 }
145 //do not add the same property to the group twice
146 const QByteArray groupLower(group.toLower());
147 if (groupForProperty(property) == groupLower) {
148 kprWarning() << "Group" << group << "already contains property" << property->name();
149 return;
150 }
151 QList<QByteArray>* propertiesOfGroup = m_propertiesOfGroup.value(groupLower);
152 if (!propertiesOfGroup) {
153 propertiesOfGroup = new QList<QByteArray>();
154 m_propertiesOfGroup.insert(groupLower, propertiesOfGroup);
155 m_groupNames.append(groupLower);
156 }
157 propertiesOfGroup->append(property->name());
158 addPropertyToGroup(property, groupLower);
159}
160
161void KPropertySetPrivate::removeFromGroup(KProperty *property)
162{
163 if (!property) {
164 return;
165 }
166 const QByteArray group(groupForProperty(property));
167 if (group.isEmpty()) {
168 return;
169 }
170 QList<QByteArray>* propertiesOfGroup = m_propertiesOfGroup.value(group);
171 if (propertiesOfGroup) {
172 propertiesOfGroup->removeAt(propertiesOfGroup->indexOf(property->name()));
173 if (propertiesOfGroup->isEmpty()) {
174 //remove group as well
175 m_propertiesOfGroup.take(group);
176 delete propertiesOfGroup;
177 const int i = m_groupNames.indexOf(group);
178 if (i != -1) {
179 m_groupNames.removeAt(i);
180 }
181 }
182 }
183 removePropertyFromGroup(property);
184}
185
186bool KPropertySetPrivate::hasGroups() const
187{
188 return m_groupNames.count() > 1 || (m_groupNames.count() == 1 && m_groupNames.first() != "common");
189}
190
191void KPropertySetPrivate::informAboutClearing(bool* cleared)
192{
193 Q_ASSERT(cleared);
194 *cleared = false;
195 m_informAboutClearing = cleared;
196}
197
198void KPropertySetPrivate::addRelatedProperty(KProperty *p1, KProperty *p2) const
199{
200 p1->d->addRelatedProperty(p2);
201}
202
203int KPropertySetPrivate::indexOfProperty(const KProperty *property) const
204{
205 KProperty *parentProperty = property->parent();
206 if (parentProperty) {
207 const QList<KProperty*>* children = parentProperty->children();
208 Q_ASSERT(children);
209 const int index = children->indexOf(parentProperty);
210 Q_ASSERT(index != -1);
211 return index;
212 }
213 return indexOfPropertyInGroup(property);
214}
215
216int KPropertySetPrivate::indexOfPropertyInGroup(const KProperty *property) const
217{
218 const QByteArray group(m_groupForProperties.value(const_cast<KProperty *>(property)));
219 QList<QByteArray>* propertiesOfGroup = m_propertiesOfGroup.value(group);
220 if (!propertiesOfGroup) {
221 return -1;
222 }
223 return propertiesOfGroup->indexOf(property->name());
224}
225
226QString KPropertySetPrivate::groupCaption(const QByteArray &group) const
227{
228 const QString result(m_groupCaptions.value(group.toLower()));
229 if (!result.isEmpty())
230 return result;
231 return QLatin1String(group);
232}
233
234//////////////////////////////////////////////
235
236KPropertySelector::KPropertySelector()
237{
238}
239
240KPropertySelector::~KPropertySelector()
241{
242}
243
244//////////////////////////////////////////////
245
247
248static inline bool Iterator_propertyAndStringLessThan(
250{
251 return QString::compare(n1.second, n2.second, Qt::CaseInsensitive) < 0;
252}
253
254//////////////////////////////////////////////
255
256class Q_DECL_HIDDEN KPropertySetIterator::Private
257{
258public:
259 explicit Private(KPropertySetIterator *iter) : q(iter)
260 {
261 }
262 Private(KPropertySetIterator *iter, const Private &other)
263 : q(iter)
264 {
265 copy(other);
266 }
267 ~Private()
268 {
269 delete selector;
270 }
271
272#define KPropertySetIteratorPrivateArgs(o) std::tie(o.set, o.iterator, o.end, o.selector, o.order, o.sorted)
273 void copy(const Private &other) {
274 KPropertySetIteratorPrivateArgs((*this)) = KPropertySetIteratorPrivateArgs(other);
275 }
276 bool operator==(const Private &other) const {
277 return KPropertySetIteratorPrivateArgs((*this)) == KPropertySetIteratorPrivateArgs(other);
278 }
279
280 void skipNotAcceptable()
281 {
282 if (!selector)
283 return;
284 //kprDebug() << "FROM:" << *current();
285 if (q->current() && !(*selector)( *q->current() )) {
286 // skip first items that not are acceptable by the selector
287 ++(*q);
288 }
289 //kprDebug() << "TO:" << *current();
290 }
291
292 const KPropertySet *set;
295 KPropertySelector *selector;
297 QList<KProperty*> sorted; //!< for sorted order
298
299private:
300 KPropertySetIterator * const q;
301};
302
304 : d(new Private(this))
305{
306 d->set = &set;
307 d->iterator = KPropertySetPrivate::d(&set)->listConstIterator();
308 d->end = KPropertySetPrivate::d(&set)->listConstEnd();
309 d->selector = nullptr;
311}
312
314 const KPropertySelector &selector)
315 : d(new Private(this))
316{
317 d->set = &set;
318 d->iterator = KPropertySetPrivate::d(&set)->listConstIterator();
319 d->end = KPropertySetPrivate::d(&set)->listConstEnd();
320 d->selector = selector.clone();
322 d->skipNotAcceptable();
323}
324
326 : d(new Private(this, *set.d))
327{
328}
329
331{
332 if (this != &other) {
333 d->copy(*other.d);
334 }
335 return *this;
336}
337
339{
340 return *d == *other.d;
341}
342
343KPropertySetIterator::~KPropertySetIterator()
344{
345 delete d;
346}
347
349{
350 if (d->order == order)
351 return;
352 d->order = order;
353 switch (d->order) {
356 {
357 QList<Iterator_PropertyAndString> propertiesAndStrings;
358 d->iterator = KPropertySetPrivate::d(d->set)->listConstIterator();
359 d->end = KPropertySetPrivate::d(d->set)->listConstEnd();
360 for (; d->iterator!=d->end; ++d->iterator) {
361 KProperty *prop = *d->iterator;
362 QString captionOrName;
364 captionOrName = prop->caption();
365 }
366 if (captionOrName.isEmpty()) {
367 captionOrName = QLatin1String(prop->name());
368 }
369 propertiesAndStrings.append( qMakePair(prop, captionOrName) );
370 }
371 std::sort(propertiesAndStrings.begin(), propertiesAndStrings.end(),
372 Iterator_propertyAndStringLessThan);
373 d->sorted.clear();
374 foreach (const Iterator_PropertyAndString& propertyAndString, propertiesAndStrings) {
375 d->sorted.append(propertyAndString.first);
376 }
377 // restart the iterator
378 d->iterator = d->sorted.constBegin();
379 d->end = d->sorted.constEnd();
380 break;
381 }
382 default:
383 d->sorted.clear();
384 // restart the iterator
385 d->iterator = KPropertySetPrivate::d(d->set)->listConstIterator();
386 d->end = KPropertySetPrivate::d(d->set)->listConstEnd();
387 }
388 d->skipNotAcceptable();
389}
390
392{
393 return d->order;
394}
395
396KProperty* KPropertySetIterator::current() const
397{
398 return d->iterator == d->end ? nullptr : *d->iterator;
399}
400
401void KPropertySetIterator::operator ++()
402{
403 while (true) {
404 ++d->iterator;
405 if (!d->selector)
406 return;
407 // selector exists
408 if (!current()) // end encountered
409 return;
410 if ((*d->selector)( *current() ))
411 return;
412 }
413}
414
415//////////////////////////////////////////////
416
418 : QObject(parent)
419 , d(new KPropertySetPrivate(this, true))
420{
421}
422
423
425 : QObject(nullptr /* implicit sharing the parent is dangerous */)
426 , d(new KPropertySetPrivate(this, true))
427{
429 *this = set;
430}
431
432KPropertySet::KPropertySet(bool propertyOwner)
433 : QObject(nullptr)
434 , d(new KPropertySetPrivate(this, propertyOwner))
435{
436}
437
438KPropertySet::~KPropertySet()
439{
440 emit aboutToBeCleared();
441 emit aboutToBeDeleted();
442 clear();
443 delete d;
444}
445
446/////////////////////////////////////////////////////
447
448void
450{
451 d->addProperty(property, group);
452}
453
454void
456{
457 d->removeProperty(property);
458}
459
460void
462{
463 KProperty *p = d->property(name);
465}
466
467void
469{
470 d->clear();
471}
472
473/////////////////////////////////////////////////////
474
476{
477 const KProperty *property = d->property(propertyName);
478 return property ? groupNameForProperty(*property) : QByteArray();
479}
480
482{
483 return d->groupForProperty(&property);
484}
485
487{
488 return d->groupNames();
489}
490
492{
493 QList<QByteArray>* propertiesOfGroup = d->propertyNamesForGroup(group);
494 return propertiesOfGroup ? *propertiesOfGroup : QList<QByteArray>();
495}
496
497void KPropertySet::setGroupCaption(const QByteArray &group, const QString &caption)
498{
499 d->setGroupCaption(group, caption);
500}
501
503{
504 return d->groupCaption(group);
505}
506
507void KPropertySet::setGroupIconName(const QByteArray &group, const QString& iconName)
508{
509 d->setGroupIconName(group, iconName);
510}
511
513{
514 return d->groupIconName(group);
515}
516
517/////////////////////////////////////////////////////
518
520{
521 return d->count();
522}
523
524int KPropertySet::count(const KPropertySelector& selector) const
525{
526 int result = 0;
527 for (KPropertySetIterator it(*this, selector); it.current(); ++it, result++)
528 ;
529 return result;
530}
531
532bool
534{
535 return d->isEmpty();
536}
537
539{
540 return d->visiblePropertiesCount() > 0;
541}
542
544{
545 KPropertySetIterator it(*this, selector);
546 return it.current();
547}
548
549bool
551{
552 return d->readOnly;
553}
554
555void
557{
558 if (d->readOnly != readOnly) {
559 d->readOnly = readOnly;
560 emit readOnlyFlagChanged();
561 }
562}
563
564bool
566{
567 return d->property(name);
568}
569
572{
573 return d->propertyOrNull(name);
574}
575
577{
578 if (contains(property)) {
579 changeProperty(property, value);
580 }
581}
582
585{
586 return d->propertyOrNull(name);
587}
588
591{
592 if (&set == this)
593 return *this;
594
595 clear();
596 d->copyAttributesFrom(*set.d);
597 d->copyPropertiesFrom(set.d->listConstIterator(), set.d->listConstEnd(), set);
598 return *this;
599}
600
601QVariant KPropertySet::propertyValue(const QByteArray &name, const QVariant& defaultValue) const
602{
603 const KProperty *p = d->property(name);
604 return p ? p->value() : defaultValue;
605}
606
607void
609{
610 KProperty *p = d->property(property);
611 if (p)
612 p->setValue(value);
613}
614
616{
617 kprDebug() << *this;
618}
619
620KPROPERTYCORE_EXPORT QDebug operator<<(QDebug dbg, const KPropertySet &set)
621{
622 dbg.nospace() << "KPropertySet(";
623 if (set.isEmpty()) {
624 dbg.space() << "<EMPTY>)";
625 return dbg.space();
626 }
627 dbg.nospace() << " PROPERTIES(" << set.count() << "):\n";
628
629 KPropertySetIterator it(set);
631 bool first = true;
632 for ( ; it.current(); ++it) {
633 if (first) {
634 first = false;
635 }
636 else {
637 dbg.nospace() << "\n";
638 }
639 dbg.nospace() << *it.current();
640 }
641 dbg.nospace() << "\n)";
642 return dbg.space();
643}
644
646{
647 return d->previousSelection();
648}
649
651{
652 d->setPreviousSelection(prevSelection);
653}
654
656{
658 for (KPropertySetIterator it(*this); it.current(); ++it) {
659 result.insert(it.current()->name(), it.current()->value());
660 }
661 return result;
662}
663
665{
666 for (KPropertySetIterator it(*this); it.current(); ++it) {
667 it.current()->clearModifiedFlag();
668 }
669}
670
672{
673 for (KPropertySetIterator it(*this); it.current(); ++it) {
674 if (it.current()->isModified()) {
675 return true;
676 }
677 }
678 return false;
679}
An interface for functor selecting properties.
virtual KPropertySelector * clone() const =0
Creates a deep copy of the selector.
A class to iterate over a KPropertySet.
KPropertySetIterator(const KPropertySet &set)
Creates iterator for set set of properties.
void setOrder(Order order)
Sets order for properties. Restarts the iterator.
KPropertySetIterator & operator=(const KPropertySetIterator &other)
Assigns other to this KPropertySetIterator.
Order
Ordering options for properties.
@ AlphabeticalByName
alphabetical order (case-insensitively by name)
@ Insertion
insertion order
@ Alphabetical
alphabetical order (case-insensitively by captions)
bool operator==(const KPropertySetIterator &other) const
Set of properties.
QVariant propertyValue(const QByteArray &name, const QVariant &defaultValue=QVariant()) const
KPropertySet & operator=(const KPropertySet &set)
void addProperty(KProperty *property, const QByteArray &group="common")
bool isEmpty() const
void aboutToBeCleared()
bool hasProperties(const KPropertySelector &selector) const
KProperty & property(const QByteArray &name) const
void changeProperty(const QByteArray &property, const QVariant &value)
KPropertySet(QObject *parent=nullptr)
Constructs a new property set object.
void changePropertyIfExists(const QByteArray &property, const QVariant &value)
QByteArray previousSelection() const
QString groupCaption(const QByteArray &group) const
QString groupIconName(const QByteArray &group) const
QByteArray groupNameForProperty(const QByteArray &propertyName) const
int count() const
QMap< QByteArray, QVariant > propertyValues() const
void readOnlyFlagChanged()
void setGroupCaption(const QByteArray &group, const QString &caption)
bool hasVisibleProperties() const
bool isReadOnly() const
QList< QByteArray > propertyNamesForGroup(const QByteArray &group) const
void setGroupIconName(const QByteArray &group, const QString &iconName)
bool isModified() const
Returns true if at least one property in this set is modified, i.e.
void debug() const
QList< QByteArray > groupNames() const
void removeProperty(KProperty *property)
void clearModifiedFlags()
Clears "modified" flag of all properties in this set, i.e.
KProperty & operator[](const QByteArray &name) const
void setReadOnly(bool readOnly)
bool contains(const QByteArray &name) const
void aboutToBeDeleted()
void setPreviousSelection(const QByteArray &prevSelection)
Sets previous section.
The base class representing a single property.
Definition KProperty.h:96
bool isVisible() const
QVariant value() const
bool setValue(const QVariant &value, ValueOptions options=ValueOptions())
Sets value of the property.
QByteArray name() const
const QList< KProperty * > * children() const
QString caption() const
bool isNull() const
KProperty * parent() const
const QList< QKeySequence > & end()
const QList< QKeySequence > & copy()
bool isEmpty() const const
QByteArray toLower() const const
QDebug & nospace()
QDebug & space()
void append(const T &value)
QList::iterator begin()
void clear()
QList::const_iterator constBegin() const const
QList::const_iterator constEnd() const const
QList::iterator end()
int indexOf(const T &value, int from) const const
bool isEmpty() const const
void removeAt(int i)
T value(int i) const const
QMap::iterator insert(const Key &key, const T &value)
void setObjectName(const QString &name)
QString tr(const char *sourceText, const char *disambiguation, int n)
int compare(const QString &other, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
bool operator==(const Qt3DRender::QGraphicsApiFilter &reference, const Qt3DRender::QGraphicsApiFilter &sample)
CaseInsensitive
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sun Feb 25 2024 18:41:55 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.