d/control: Recommend gdb
[gammaray-debian.git] / objecttreemodel.cpp
blobb67aa16db242f016afc27004a1542b88a7de8346
1 /*
2 objecttreemodel.cpp
4 This file is part of GammaRay, the Qt application inspection and
5 manipulation tool.
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"
27 #include "probe.h"
29 #include <QtCore/QEvent>
30 #include <QtCore/QThread>
32 #include <iostream>
34 #define IF_DEBUG(x)
36 extern void dumpObject(QObject *);
38 using namespace std;
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;)
60 return;
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;)
67 return;
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
74 // parent if required
75 if (obj->parent()) {
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());
95 endInsertRows();
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());
103 IF_DEBUG(cout
104 << "tree removed: "
105 << hex << obj << " "
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));
112 return;
115 QObject *parentObj = m_childParentMap[ obj ];
116 const QModelIndex parentIndex = indexForObject(parentObj);
117 if (parentObj && !parentIndex.isValid()) {
118 return;
121 QVector<QObject*> &siblings = m_parentChildMap[ parentObj ];
123 int index = siblings.indexOf(obj);
125 if (index == -1) {
126 return;
129 beginRemoveRows(parentIndex, index, index);
131 siblings.remove(index);
132 m_childParentMap.remove(obj);
133 m_parentChildMap.remove(obj);
135 endRemoveRows();
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)) {
145 objectAdded(obj);
148 objectRemoved(obj);
151 QVariant ObjectTreeModel::data(const QModelIndex &index, int role) const
153 if (!index.isValid()) {
154 return QVariant();
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);
165 } else {
166 return tr("<deleted>");
170 return QVariant();
173 int ObjectTreeModel::rowCount(const QModelIndex &parent) const
175 if (parent.column() == 1) {
176 return 0;
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
200 if (!object) {
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);
209 if (row < 0) {
210 return QModelIndex();
212 return index(row, 0, parentIndex);
215 #include "objecttreemodel.moc"