objectcontroller.cpp
Go to the documentation of this file.
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#include "objectcontroller.h"
42
43#include <QMetaObject>
44#include <QMetaProperty>
45#include <QScrollArea>
46#include <QVBoxLayout>
47
49#include "qtpropertybrowser.h"
51#include "qtvariantproperty.h"
52
54{
55 ObjectController* q_ptr;
56 Q_DECLARE_PUBLIC(ObjectController)
57public:
58 void addClassProperties(const QMetaObject* metaObject);
59 void updateClassProperties(const QMetaObject* metaObject, bool recursive);
60 void saveExpandedState();
62 void slotValueChanged(QtProperty* property, const QVariant& value);
63 int enumToInt(const QMetaEnum& metaEnum, int enumValue) const;
64 int intToEnum(const QMetaEnum& metaEnum, int intValue) const;
65 int flagToInt(const QMetaEnum& metaEnum, int flagValue) const;
66 int intToFlag(const QMetaEnum& metaEnum, int intValue) const;
67 bool isSubValue(int value, int subValue) const;
68 bool isPowerOf2(int value) const;
69
70 QObject* m_object;
71
72 QMap<const QMetaObject*, QtProperty*> m_classToProperty;
73 QMap<QtProperty*, const QMetaObject*> m_propertyToClass;
74 QMap<QtProperty*, int> m_propertyToIndex;
75 QMap<const QMetaObject*, QMap<int, QtVariantProperty*>> m_classToIndexToProperty;
76
77 QMap<QtProperty*, bool> m_propertyToExpanded;
78
79 QList<QtProperty*> m_topLevelProperties;
80
84};
85
86int
87ObjectControllerPrivate::enumToInt(const QMetaEnum& metaEnum, int enumValue) const
88{
89 QMap<int, int> valueMap; // dont show multiple enum values which have the same values
90 int pos = 0;
91
92 for (int i = 0; i < metaEnum.keyCount(); i++)
93 {
94 int value = metaEnum.value(i);
95
96 if (!valueMap.contains(value))
97 {
98 if (value == enumValue)
99 {
100 return pos;
101 }
102
103 valueMap[value] = pos++;
104 }
105 }
106
107 return -1;
108}
109
110int
111ObjectControllerPrivate::intToEnum(const QMetaEnum& metaEnum, int intValue) const
112{
113 QMap<int, bool> valueMap; // dont show multiple enum values which have the same values
114 QList<int> values;
115
116 for (int i = 0; i < metaEnum.keyCount(); i++)
117 {
118 int value = metaEnum.value(i);
119
120 if (!valueMap.contains(value))
121 {
122 valueMap[value] = true;
123 values.append(value);
124 }
125 }
126
127 if (intValue >= values.count())
128 {
129 return -1;
130 }
131
132 return values.at(intValue);
133}
134
135bool
136ObjectControllerPrivate::isSubValue(int value, int subValue) const
137{
138 if (value == subValue)
139 {
140 return true;
141 }
142
143 int i = 0;
144
145 while (subValue)
146 {
147 if (!(value & (1 << i)))
148 {
149 if (subValue & 1)
150 {
151 return false;
152 }
153 }
154
155 i++;
156 subValue = subValue >> 1;
157 }
158
159 return true;
160}
161
162bool
164{
165 while (value)
166 {
167 if (value & 1)
168 {
169 return value == 1;
170 }
171
172 value = value >> 1;
173 }
174
175 return false;
176}
177
178int
179ObjectControllerPrivate::flagToInt(const QMetaEnum& metaEnum, int flagValue) const
180{
181 if (!flagValue)
182 {
183 return 0;
184 }
185
186 int intValue = 0;
187 QMap<int, int> valueMap; // dont show multiple enum values which have the same values
188 int pos = 0;
189
190 for (int i = 0; i < metaEnum.keyCount(); i++)
191 {
192 int value = metaEnum.value(i);
193
194 if (!valueMap.contains(value) && isPowerOf2(value))
195 {
196 if (isSubValue(flagValue, value))
197 {
198 intValue |= (1 << pos);
199 }
200
201 valueMap[value] = pos++;
202 }
203 }
204
205 return intValue;
206}
207
208int
209ObjectControllerPrivate::intToFlag(const QMetaEnum& metaEnum, int intValue) const
210{
211 QMap<int, bool> valueMap; // dont show multiple enum values which have the same values
212 QList<int> values;
213
214 for (int i = 0; i < metaEnum.keyCount(); i++)
215 {
216 int value = metaEnum.value(i);
217
218 if (!valueMap.contains(value) && isPowerOf2(value))
219 {
220 valueMap[value] = true;
221 values.append(value);
222 }
223 }
224
225 int flagValue = 0;
226 int temp = intValue;
227 int i = 0;
228
229 while (temp)
230 {
231 if (i >= values.count())
232 {
233 return -1;
234 }
235
236 if (temp & 1)
237 {
238 flagValue |= values.at(i);
239 }
240
241 i++;
242 temp = temp >> 1;
243 }
244
245 return flagValue;
246}
247
248void
249ObjectControllerPrivate::updateClassProperties(const QMetaObject* metaObject, bool recursive)
250{
251 if (!metaObject)
252 {
253 return;
254 }
255
256 if (recursive)
257 {
258 updateClassProperties(metaObject->superClass(), recursive);
259 }
260
261 QtProperty* classProperty = m_classToProperty.value(metaObject);
262
263 if (!classProperty)
264 {
265 return;
266 }
267
268 for (int idx = metaObject->propertyOffset(); idx < metaObject->propertyCount(); idx++)
269 {
270 QMetaProperty metaProperty = metaObject->property(idx);
271
272 if (metaProperty.isReadable())
273 {
274 if (m_classToIndexToProperty.contains(metaObject) &&
275 m_classToIndexToProperty[metaObject].contains(idx))
276 {
277 QtVariantProperty* subProperty = m_classToIndexToProperty[metaObject][idx];
278
279 if (metaProperty.isEnumType())
280 {
281 if (metaProperty.isFlagType())
282 {
283 subProperty->setValue(flagToInt(metaProperty.enumerator(),
284 metaProperty.read(m_object).toInt()));
285 }
286 else
287 {
288 subProperty->setValue(enumToInt(metaProperty.enumerator(),
289 metaProperty.read(m_object).toInt()));
290 }
291 }
292 else
293 {
294 subProperty->setValue(metaProperty.read(m_object));
295 }
296 }
297 }
298 }
299}
300
301void
303{
304 if (!metaObject)
305 {
306 return;
307 }
308
309 addClassProperties(metaObject->superClass());
310
311 QtProperty* classProperty = m_classToProperty.value(metaObject);
312
313 if (!classProperty)
314 {
315 QString className = QLatin1String(metaObject->className());
316 classProperty = m_manager->addProperty(QtVariantPropertyManager::groupTypeId(), className);
317 m_classToProperty[metaObject] = classProperty;
318 m_propertyToClass[classProperty] = metaObject;
319
320 for (int idx = metaObject->propertyOffset(); idx < metaObject->propertyCount(); idx++)
321 {
322 QMetaProperty metaProperty = metaObject->property(idx);
323 int type = metaProperty.userType();
324 QtVariantProperty* subProperty = 0;
325
326 if (!metaProperty.isReadable())
327 {
328 subProperty = m_readOnlyManager->addProperty(QVariant::String,
329 QLatin1String(metaProperty.name()));
330 subProperty->setValue(QLatin1String("< Non Readable >"));
331 }
332 else if (metaProperty.isEnumType())
333 {
334 if (metaProperty.isFlagType())
335 {
336 subProperty = m_manager->addProperty(QtVariantPropertyManager::flagTypeId(),
337 QLatin1String(metaProperty.name()));
338 QMetaEnum metaEnum = metaProperty.enumerator();
339 QMap<int, bool> valueMap;
340 QStringList flagNames;
341
342 for (int i = 0; i < metaEnum.keyCount(); i++)
343 {
344 int value = metaEnum.value(i);
345
346 if (!valueMap.contains(value) && isPowerOf2(value))
347 {
348 valueMap[value] = true;
349 flagNames.append(QLatin1String(metaEnum.key(i)));
350 }
351
352 subProperty->setAttribute(QLatin1String("flagNames"), flagNames);
353 subProperty->setValue(
354 flagToInt(metaEnum, metaProperty.read(m_object).toInt()));
355 }
356 }
357 else
358 {
359 subProperty = m_manager->addProperty(QtVariantPropertyManager::enumTypeId(),
360 QLatin1String(metaProperty.name()));
361 QMetaEnum metaEnum = metaProperty.enumerator();
362 QMap<int, bool>
363 valueMap; // dont show multiple enum values which have the same values
364 QStringList enumNames;
365
366 for (int i = 0; i < metaEnum.keyCount(); i++)
367 {
368 int value = metaEnum.value(i);
369
370 if (!valueMap.contains(value))
371 {
372 valueMap[value] = true;
373 enumNames.append(QLatin1String(metaEnum.key(i)));
374 }
375 }
376
377 subProperty->setAttribute(QLatin1String("enumNames"), enumNames);
378 subProperty->setValue(enumToInt(metaEnum, metaProperty.read(m_object).toInt()));
379 }
380 }
381 else if (m_manager->isPropertyTypeSupported(type))
382 {
383 if (!metaProperty.isWritable())
384 {
385 subProperty = m_readOnlyManager->addProperty(
386 type,
387 QLatin1String(metaProperty.name()) + QLatin1String(" (Non Writable)"));
388 }
389
390 if (!metaProperty.isDesignable())
391 {
392 subProperty = m_readOnlyManager->addProperty(
393 type,
394 QLatin1String(metaProperty.name()) + QLatin1String(" (Non Designable)"));
395 }
396 else
397 {
398 subProperty = m_manager->addProperty(type, QLatin1String(metaProperty.name()));
399 }
400
401 subProperty->setValue(metaProperty.read(m_object));
402 }
403 else
404 {
405 subProperty = m_readOnlyManager->addProperty(QVariant::String,
406 QLatin1String(metaProperty.name()));
407 subProperty->setValue(QLatin1String("< Unknown Type >"));
408 subProperty->setEnabled(false);
409 }
410
411 classProperty->addSubProperty(subProperty);
412 m_propertyToIndex[subProperty] = idx;
413 m_classToIndexToProperty[metaObject][idx] = subProperty;
414 }
415 }
416 else
417 {
418 updateClassProperties(metaObject, false);
419 }
420
421 m_topLevelProperties.append(classProperty);
422 m_browser->addProperty(classProperty);
423}
424
425void
429
430void
434
435void
437{
438 if (!m_propertyToIndex.contains(property))
439 {
440 return;
441 }
442
443 int idx = m_propertyToIndex.value(property);
444
445 const QMetaObject* metaObject = m_object->metaObject();
446 QMetaProperty metaProperty = metaObject->property(idx);
447
448 if (metaProperty.isEnumType())
449 {
450 if (metaProperty.isFlagType())
451 {
452 metaProperty.write(m_object, intToFlag(metaProperty.enumerator(), value.toInt()));
453 }
454 else
455 {
456 metaProperty.write(m_object, intToEnum(metaProperty.enumerator(), value.toInt()));
457 }
458 }
459 else
460 {
461 metaProperty.write(m_object, value);
462 }
463
464 updateClassProperties(metaObject, true);
465}
466
467///////////////////
468
469ObjectController::ObjectController(QWidget* parent) : QWidget(parent)
470{
471 d_ptr = new ObjectControllerPrivate;
472 d_ptr->q_ptr = this;
473
474 d_ptr->m_object = 0;
475 /*
476 QScrollArea *scroll = new QScrollArea(this);
477 scroll->setWidgetResizable(true);
478
479 d_ptr->m_browser = new QtGroupBoxPropertyBrowser(this);
480 QVBoxLayout *layout = new QVBoxLayout(this);
481 layout->setMargin(0);
482 layout->addWidget(scroll);
483 scroll->setWidget(d_ptr->m_browser);
484 */
485 QtTreePropertyBrowser* browser = new QtTreePropertyBrowser(this);
486 browser->setRootIsDecorated(false);
487 d_ptr->m_browser = browser;
488 QVBoxLayout* layout = new QVBoxLayout(this);
489 layout->setMargin(0);
490 layout->addWidget(d_ptr->m_browser);
491
492 d_ptr->m_readOnlyManager = new QtVariantPropertyManager(this);
493 d_ptr->m_manager = new QtVariantPropertyManager(this);
495 d_ptr->m_browser->setFactoryForManager(d_ptr->m_manager, factory);
496
497 connect(d_ptr->m_manager,
498 SIGNAL(valueChanged(QtProperty*, const QVariant&)),
499 this,
500 SLOT(slotValueChanged(QtProperty*, const QVariant&)));
501}
502
504{
505 delete d_ptr;
506}
507
508void
510{
511 if (d_ptr->m_object == object)
512 {
513 return;
514 }
515
516 if (d_ptr->m_object)
517 {
518 d_ptr->saveExpandedState();
519 QListIterator<QtProperty*> it(d_ptr->m_topLevelProperties);
520
521 while (it.hasNext())
522 {
523 d_ptr->m_browser->removeProperty(it.next());
524 }
525
526 d_ptr->m_topLevelProperties.clear();
527 }
528
529 d_ptr->m_object = object;
530
531 if (!d_ptr->m_object)
532 {
533 return;
534 }
535
536 d_ptr->addClassProperties(d_ptr->m_object->metaObject());
537
538 d_ptr->restoreExpandedState();
539}
540
541QObject*
543{
544 return d_ptr->m_object;
545}
546
547#include "moc_objectcontroller.cpp"
void addClassProperties(const QMetaObject *metaObject)
void slotValueChanged(QtProperty *property, const QVariant &value)
int intToEnum(const QMetaEnum &metaEnum, int intValue) const
QMap< QtProperty *, bool > m_propertyToExpanded
QMap< QtProperty *, int > m_propertyToIndex
QtVariantPropertyManager * m_manager
QtAbstractPropertyBrowser * m_browser
bool isPowerOf2(int value) const
QMap< QtProperty *, const QMetaObject * > m_propertyToClass
int flagToInt(const QMetaEnum &metaEnum, int flagValue) const
QMap< const QMetaObject *, QMap< int, QtVariantProperty * > > m_classToIndexToProperty
int enumToInt(const QMetaEnum &metaEnum, int enumValue) const
int intToFlag(const QMetaEnum &metaEnum, int intValue) const
QMap< const QMetaObject *, QtProperty * > m_classToProperty
void updateClassProperties(const QMetaObject *metaObject, bool recursive)
QList< QtProperty * > m_topLevelProperties
QtVariantPropertyManager * m_readOnlyManager
bool isSubValue(int value, int subValue) const
void setObject(QObject *object)
QObject * object() const
ObjectController(QWidget *parent=0)
QtAbstractPropertyBrowser provides a base class for implementing property browsers.
The QtProperty class encapsulates an instance of a property.
void setEnabled(bool enable)
void addSubProperty(QtProperty *property)
The QtTreePropertyBrowser class provides QTreeWidget based property browser.
The QtVariantEditorFactory class provides widgets for properties created by QtVariantPropertyManager ...
The QtVariantPropertyManager class provides and manages QVariant based properties.
The QtVariantProperty class is a convenience class handling QVariant based properties.
void setAttribute(const QString &attribute, const QVariant &value)
void setValue(const QVariant &value)