4 This file is part of GammaRay, the Qt application inspection and
7 Copyright (C) 2010-2011 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com
8 Author: Volker Krause <volker.krause@kdab.com>
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation, either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "objecttreemodel.h"
26 #include "readorwritelocker.h"
29 #include <QtCore/QEvent>
30 #include <QtCore/QThread>
36 extern void dumpObject(QObject
*);
39 using namespace GammaRay
;
41 ObjectTreeModel::ObjectTreeModel(Probe
*probe
)
42 : ObjectModelBase
< QAbstractItemModel
>(probe
)
44 connect(probe
, SIGNAL(objectCreated(QObject
*)),
45 this, SLOT(objectAdded(QObject
*)));
46 connect(probe
, SIGNAL(objectDestroyed(QObject
*)),
47 this, SLOT(objectRemoved(QObject
*)));
48 connect(probe
, SIGNAL(objectReparanted(QObject
*)),
49 this, SLOT(objectReparanted(QObject
*)));
52 void ObjectTreeModel::objectAdded(QObject
*obj
)
54 // slot, hence should always land in main thread due to auto connection
55 Q_ASSERT(thread() == QThread::currentThread());
57 ReadOrWriteLocker
objectLock(Probe::instance()->objectLock());
58 if (!Probe::instance()->isValidObject(obj
)) {
59 IF_DEBUG(cout
<< "tree invalid obj added: " << hex
<< obj
<< endl
;)
62 IF_DEBUG(cout
<< "tree obj added: " << hex
<< obj
<< " p: " << obj
->parent() << endl
;)
63 Q_ASSERT(!obj
->parent() || Probe::instance()->isValidObject(obj
->parent()));
65 if (indexForObject(obj
).isValid()) {
66 IF_DEBUG(cout
<< "tree double obj added: " << hex
<< obj
<< endl
;)
70 // this is ugly, but apparently it can happen
71 // that an object gets created without parent
72 // then later the delayed signal comes in
73 // so catch this gracefully by first adding the
76 const QModelIndex index
= indexForObject(obj
->parent());
77 if (!index
.isValid()) {
78 IF_DEBUG(cout
<< "tree: handle parent first" << endl
;)
79 objectAdded(obj
->parent());
83 const QModelIndex index
= indexForObject(obj
->parent());
85 // either we get a proper parent and hence valid index or there is no parent
86 Q_ASSERT(index
.isValid() || !obj
->parent());
88 QVector
<QObject
*> &children
= m_parentChildMap
[ obj
->parent() ];
90 beginInsertRows(index
, children
.size(), children
.size());
92 children
.push_back(obj
);
93 m_childParentMap
.insert(obj
, obj
->parent());
98 void ObjectTreeModel::objectRemoved(QObject
*obj
)
100 // slot, hence should always land in main thread due to auto connection
101 Q_ASSERT(thread() == QThread::currentThread());
106 << hex
<< obj
->parent() << dec
<< " "
107 << m_parentChildMap
.value(obj
->parent()).size() << " "
108 << m_parentChildMap
.contains(obj
) << endl
;)
110 if (!m_childParentMap
.contains(obj
)) {
111 Q_ASSERT(!m_parentChildMap
.contains(obj
));
115 QObject
*parentObj
= m_childParentMap
[ obj
];
116 const QModelIndex parentIndex
= indexForObject(parentObj
);
117 if (parentObj
&& !parentIndex
.isValid()) {
121 QVector
<QObject
*> &siblings
= m_parentChildMap
[ parentObj
];
123 int index
= siblings
.indexOf(obj
);
129 beginRemoveRows(parentIndex
, index
, index
);
131 siblings
.remove(index
);
132 m_childParentMap
.remove(obj
);
133 m_parentChildMap
.remove(obj
);
138 void ObjectTreeModel::objectReparanted(QObject
*obj
)
140 // slot, hence should always land in main thread due to auto connection
141 Q_ASSERT(thread() == QThread::currentThread());
143 ReadOrWriteLocker
objectLock(Probe::instance()->objectLock());
144 if (Probe::instance()->isValidObject(obj
)) {
151 QVariant
ObjectTreeModel::data(const QModelIndex
&index
, int role
) const
153 if (!index
.isValid()) {
157 QObject
*obj
= reinterpret_cast<QObject
*>(index
.internalPointer());
159 ReadOrWriteLocker
lock(Probe::instance()->objectLock());
160 if (Probe::instance()->isValidObject(obj
)) {
161 return dataForObject(obj
, index
, role
);
162 } else if (role
== Qt::DisplayRole
) {
163 if (index
.column() == 0) {
164 return Util::addressToString(obj
);
166 return tr("<deleted>");
173 int ObjectTreeModel::rowCount(const QModelIndex
&parent
) const
175 if (parent
.column() == 1) {
178 QObject
*parentObj
= reinterpret_cast<QObject
*>(parent
.internalPointer());
179 return m_parentChildMap
.value(parentObj
).size();
182 QModelIndex
ObjectTreeModel::parent(const QModelIndex
&child
) const
184 QObject
*childObj
= reinterpret_cast<QObject
*>(child
.internalPointer());
185 return indexForObject(m_childParentMap
.value(childObj
));
188 QModelIndex
ObjectTreeModel::index(int row
, int column
, const QModelIndex
&parent
) const
190 QObject
*parentObj
= reinterpret_cast<QObject
*>(parent
.internalPointer());
191 const QVector
<QObject
*> children
= m_parentChildMap
.value(parentObj
);
192 if (row
< 0 || column
< 0 || row
>= children
.size() || column
>= columnCount()) {
193 return QModelIndex();
195 return createIndex(row
, column
, children
.at(row
));
198 QModelIndex
ObjectTreeModel::indexForObject(QObject
*object
) const
201 return QModelIndex();
203 QObject
*parent
= m_childParentMap
.value(object
);
204 const QModelIndex parentIndex
= indexForObject(parent
);
205 if (!parentIndex
.isValid() && parent
) {
206 return QModelIndex();
208 int row
= m_parentChildMap
[ parent
].indexOf(object
);
210 return QModelIndex();
212 return index(row
, 0, parentIndex
);
215 #include "objecttreemodel.moc"