1 // *************************************************************************************************
3 // QPropertyEditor v 0.1
5 // --------------------------------------
6 // Copyright (C) 2007 Volker Wiendl
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU Lesser General Public
11 // License as published by the Free Software Foundation; either
12 // version 2.1 of the License, or any later version.
14 // This library is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 // Lesser General Public License for more details.
19 // You should have received a copy of the GNU Lesser General Public
20 // License along with this library; if not, write to the Free Software
21 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 // *************************************************************************************************
25 #include "QPropertyModel.h"
29 #include <Qt/qapplication.h>
30 #include <Qt/qmetaobject.h>
31 #include <Qt/qitemeditorfactory.h>
34 PropertyPair(const QMetaObject
* obj
, QMetaProperty property
) : Property(property
), Object(obj
) {}
36 QMetaProperty Property
;
37 const QMetaObject
* Object
;
39 bool operator==(const PropertyPair
& other
) const {
40 return QString(other
.Property
.name()) == QString(Property
.name());
45 QPropertyModel::QPropertyModel(QObject
* parent
/*= 0*/) : QAbstractItemModel(parent
), m_userCallback(0) {
46 m_rootItem
= new Property("Root",0, this);
50 QPropertyModel::~QPropertyModel() {}
52 QModelIndex
QPropertyModel::index ( int row
, int column
, const QModelIndex
& parent
/*= QModelIndex()*/ ) const {
53 Property
*parentItem
= m_rootItem
;
55 parentItem
= static_cast<Property
*>(parent
.internalPointer());
56 if (row
>= parentItem
->children().size())
58 return createIndex(row
, column
, parentItem
->children().at(row
));
62 QModelIndex
QPropertyModel::parent ( const QModelIndex
& index
) const {
66 Property
*childItem
= static_cast<Property
*>(index
.internalPointer());
67 Property
*parentItem
= qobject_cast
<Property
*>(childItem
->parent());
69 if (!parentItem
|| parentItem
== m_rootItem
)
72 return createIndex(parentItem
->row(), 0, parentItem
);
75 int QPropertyModel::rowCount ( const QModelIndex
& parent
/*= QModelIndex()*/ ) const {
76 Property
*parentItem
= m_rootItem
;
78 parentItem
= static_cast<Property
*>(parent
.internalPointer());
79 return parentItem
->children().size();
82 int QPropertyModel::columnCount ( const QModelIndex
& parent
/*= QModelIndex()*/ ) const {
87 QVariant
QPropertyModel::data ( const QModelIndex
& index
, int role
/*= Qt::DisplayRole*/ ) const {
91 Property
*item
= static_cast<Property
*>(index
.internalPointer());
94 case Qt::DecorationRole
:
97 if (index
.column() == 0)
98 return item
->objectName();
99 if (index
.column() == 1)
100 return item
->value(role
);
101 case Qt::BackgroundRole
:
102 if (item
->isRoot()) return QApplication::palette("QTreeView").brush(QPalette::Normal
, QPalette::Button
).color();
109 bool QPropertyModel::setData ( const QModelIndex
& index
, const QVariant
& value
, int role
/*= Qt::EditRole*/ ) {
110 if (index
.isValid() && role
== Qt::EditRole
) {
111 Property
*item
= static_cast<Property
*>(index
.internalPointer());
112 item
->setValue(value
);
113 emit
dataChanged(index
, index
);
119 Qt::ItemFlags
QPropertyModel::flags ( const QModelIndex
& index
) const {
120 if (!index
.isValid())
121 return Qt::ItemIsEnabled
;
122 Property
*item
= static_cast<Property
*>(index
.internalPointer());
123 // only allow change of value attribute
125 return Qt::ItemIsEnabled
;
126 else if (item
->isReadOnly())
127 return Qt::ItemIsDragEnabled
| Qt::ItemIsSelectable
;
129 return Qt::ItemIsDragEnabled
| Qt::ItemIsEnabled
| Qt::ItemIsSelectable
| Qt::ItemIsEditable
;
133 QVariant
QPropertyModel::headerData ( int section
, Qt::Orientation orientation
, int role
/*= Qt::DisplayRole*/ ) const {
134 if (orientation
== Qt::Horizontal
&& role
== Qt::DisplayRole
) {
145 QModelIndex
QPropertyModel::buddy ( const QModelIndex
& index
) const {
146 if (index
.isValid() && index
.column() == 0)
147 return createIndex(index
.row(), 1, index
.internalPointer());
151 void QPropertyModel::addItem(QObject
*propertyObject
) {
152 // first create property <-> class hierarchy
153 QList
<PropertyPair
> propertyMap
;
154 QList
<const QMetaObject
*> classList
;
155 const QMetaObject
* metaObject
= propertyObject
->metaObject();
157 int count
= metaObject
->propertyCount();
158 for (int i
=0; i
<count
; ++i
) {
159 QMetaProperty property
= metaObject
->property(i
);
160 if (property
.isUser()) // Hide Qt specific properties
162 PropertyPair
pair(metaObject
, property
);
163 int index
= propertyMap
.indexOf(pair
);
165 propertyMap
[index
] = pair
;
167 propertyMap
.push_back(pair
);
170 classList
.push_front(metaObject
);
171 } while ((metaObject
= metaObject
->superClass())!=0);
173 QList
<const QMetaObject
*> finalClassList
;
174 // remove empty classes from hierarchy list
175 foreach(const QMetaObject
* obj
, classList
) {
177 foreach(PropertyPair pair
, propertyMap
) {
178 if (pair
.Object
== obj
) {
184 finalClassList
.push_back(obj
);
187 // finally insert properties for classes containing them
189 beginInsertRows(QModelIndex(), i
, i
+ finalClassList
.count());
190 foreach(const QMetaObject
* metaObject
, finalClassList
) {
191 // Set default name of the hierarchy property to the class name
192 QString name
= metaObject
->className();
193 // Check if there is a special name for the class
194 int index
= metaObject
->indexOfClassInfo(qPrintable(name
));
196 name
= metaObject
->classInfo(index
).value();
197 // Create Property Item for class node
198 Property
* propertyItem
= new Property(name
, 0, m_rootItem
);
199 foreach(PropertyPair pair
, propertyMap
) {
200 // Check if the property is associated with the current class from the finalClassList
201 if (pair
.Object
== metaObject
) {
202 QMetaProperty
property(pair
.Property
);
204 if (property
.type() == QVariant::UserType
&& m_userCallback
)
205 p
= m_userCallback(property
.name(), propertyObject
, propertyItem
);
207 p
= new Property(property
.name(), propertyObject
, propertyItem
);
208 int index
= metaObject
->indexOfClassInfo(property
.name());
210 p
->setEditorHints(metaObject
->classInfo(index
).value());
217 void QPropertyModel::updateItem ( QObject
* propertyObject
, const QModelIndex
& parent
/*= QModelIndex() */ ) {
218 Property
*parentItem
= m_rootItem
;
219 if (parent
.isValid())
220 parentItem
= static_cast<Property
*>(parent
.internalPointer());
221 if (parentItem
->propertyObject() != propertyObject
)
222 parentItem
= parentItem
->findPropertyObject(propertyObject
);
223 if (parentItem
) // Indicate view that the data for the indices have changed
224 dataChanged(createIndex(parentItem
->row(), 0, static_cast<Property
*>(parentItem
)), createIndex(parentItem
->row(), 1, static_cast<Property
*>(parentItem
)));
227 void QPropertyModel::clear() {
228 beginRemoveRows(QModelIndex(), 0, rowCount());
230 m_rootItem
= new Property("Root",0, this);
234 void QPropertyModel::setCustomPropertyCB(QPropertyEditorWidget::UserTypeCB callback
) {
235 m_userCallback
= callback
;