File indexing completed on 2024-04-28 17:02:21
0001 /* 0002 This file is part of Massif Visualizer 0003 0004 Copyright 2010 Milian Wolff <mail@milianw.de> 0005 0006 This library is free software; you can redistribute it and/or 0007 modify it under the terms of the GNU Lesser General Public 0008 License as published by the Free Software Foundation; either 0009 version 2.1 of the License, or (at your option) version 3, or any 0010 later version accepted by the membership of KDE e.V. (or its 0011 successor approved by the membership of KDE e.V.), which shall 0012 act as a proxy defined in Section 6 of version 3 of the license. 0013 0014 This library is distributed in the hope that it will be useful, 0015 but WITHOUT ANY WARRANTY; without even the implied warranty of 0016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0017 Lesser General Public License for more details. 0018 0019 You should have received a copy of the GNU Lesser General Public 0020 License along with this library. If not, see <http://www.gnu.org/licenses/>. 0021 */ 0022 0023 #include "datatreemodel.h" 0024 0025 #include "massifdata/filedata.h" 0026 #include "massifdata/snapshotitem.h" 0027 #include "massifdata/treeleafitem.h" 0028 #include "massifdata/util.h" 0029 0030 #include <KLocalizedString> 0031 0032 #include <QtGui/QBrush> 0033 0034 using namespace Massif; 0035 0036 DataTreeModel::DataTreeModel(QObject* parent) 0037 : QAbstractItemModel(parent), m_data(0) 0038 { 0039 } 0040 0041 DataTreeModel::~DataTreeModel() 0042 { 0043 } 0044 0045 void DataTreeModel::setSource(const FileData* data) 0046 { 0047 if (m_data) { 0048 beginRemoveRows(QModelIndex(), 0, rowCount() - 1); 0049 m_data = 0; 0050 m_nodeToRow.clear(); 0051 m_heapRootToSnapshot.clear(); 0052 endRemoveRows(); 0053 } 0054 if (data) { 0055 beginInsertRows(QModelIndex(), 0, data->snapshots().size() - 1); 0056 m_data = data; 0057 int row = 0; 0058 foreach(const SnapshotItem* item, m_data->snapshots()) { 0059 if (item->heapTree()) { 0060 mapNodeToRow(item->heapTree(), row++); 0061 m_heapRootToSnapshot[item->heapTree()] = item; 0062 } else { 0063 row++; 0064 } 0065 } 0066 endInsertRows(); 0067 } 0068 } 0069 0070 void DataTreeModel::mapNodeToRow(const TreeLeafItem* node, const int row) 0071 { 0072 m_nodeToRow[node] = row; 0073 int r = 0; 0074 foreach(const TreeLeafItem* child, node->children()) { 0075 mapNodeToRow(child, r++); 0076 } 0077 } 0078 0079 QVariant DataTreeModel::headerData(int section, Qt::Orientation orientation, int role) const 0080 { 0081 Q_UNUSED(section) 0082 Q_UNUSED(orientation) 0083 Q_UNUSED(role) 0084 return i18n("Snapshots"); 0085 } 0086 0087 QVariant DataTreeModel::data(const QModelIndex& index, int role) const 0088 { 0089 // FIXME kdchart queries (-1, -1) for empty models 0090 if ( index.row() == -1 || index.column() == -1 ) { 0091 // qWarning() << "DataTreeModel::data: FIXME fix kdchart views to not query model data for invalid indices!"; 0092 return QVariant(); 0093 } 0094 0095 Q_ASSERT(index.row() >= 0 && index.row() < rowCount(index.parent())); 0096 Q_ASSERT(index.column() >= 0 && index.column() < columnCount(index.parent())); 0097 Q_ASSERT(m_data); 0098 0099 0100 // custom background for peak snapshot 0101 if ( role == Qt::BackgroundRole ) { 0102 // double maxValue = 1; 0103 const double maxValue = m_data->peak()->cost(); 0104 double currentValue = 0; 0105 if ( !index.parent().isValid() && m_data->peak() ) { 0106 // maxValue = m_data->peak()->memHeap(); 0107 const SnapshotItem* snapshot = m_data->snapshots().at(index.row()); 0108 currentValue = snapshot->cost(); 0109 } else if (index.parent().isValid()) { 0110 Q_ASSERT(index.internalPointer()); 0111 const TreeLeafItem* node = static_cast<TreeLeafItem*>(index.internalPointer()); 0112 currentValue = node->cost(); 0113 Q_ASSERT(node->parent()); 0114 /* 0115 TreeLeafItem* parent = node->parent(); 0116 while (parent->parent()) { 0117 parent = parent->parent(); 0118 } 0119 maxValue = parent->cost(); 0120 // normalize 0121 maxValue -= parent->children().last()->cost(); 0122 currentValue -= parent->children().last()->cost(); 0123 */ 0124 } 0125 if (currentValue > 0) { 0126 const double ratio = (currentValue / maxValue); 0127 QColor c = QColor::fromHsv(120 - ratio * 120, 255, 255, (-((ratio-1) * (ratio-1))) * 120 + 120); 0128 // QColor c = QColor::fromHsv(120 - ratio * 120, 255, 255, 120); 0129 return QBrush(c); 0130 } else { 0131 return QVariant(); 0132 } 0133 } 0134 0135 if (role == ModelItemRole) { 0136 return QVariant::fromValue(itemForIndex(index)); 0137 } 0138 0139 if (role != Qt::DisplayRole && role != Qt::ToolTipRole && role != RawLabelRole && role != TreeItemRole) 0140 { 0141 return QVariant(); 0142 } 0143 0144 if (!index.parent().isValid()) { 0145 const SnapshotItem* snapshot = m_data->snapshots().at(index.row()); 0146 if (role == Qt::ToolTipRole) { 0147 if (snapshot == m_data->peak()) { 0148 return i18n("Peak snapshot: heap cost of %1", prettyCost(snapshot->cost())); 0149 } else { 0150 return i18n("Snapshot #%1: heap cost of %2", snapshot->number(), prettyCost(snapshot->cost())); 0151 } 0152 } else if (role == RawLabelRole) { 0153 return i18nc("%1: snapshot number", "Snapshot #%1", snapshot->number()); 0154 } else if (role == TreeItemRole) { 0155 return QVariant::fromValue<const TreeLeafItem*>(0); 0156 } 0157 const QString costStr = prettyCost(snapshot->cost()); 0158 if (snapshot == m_data->peak()) { 0159 return i18nc("%1: cost, %2: snapshot number", 0160 "%1: Snapshot #%2 (peak)", costStr, snapshot->number()); 0161 } else { 0162 return i18nc("%1: cost, %2: snapshot number", 0163 "%1: Snapshot #%2", costStr, snapshot->number()); 0164 } 0165 } else { 0166 Q_ASSERT(index.internalPointer()); 0167 const TreeLeafItem* item = static_cast<const TreeLeafItem*>(index.internalPointer()); 0168 if (role == Qt::ToolTipRole) { 0169 return tooltipForTreeLeaf(item, snapshotForTreeLeaf(item), item->label()); 0170 } else if (role == RawLabelRole) { 0171 return item->label(); 0172 } else if (role == TreeItemRole) { 0173 return QVariant::fromValue<const TreeLeafItem*>(item); 0174 } 0175 return i18nc("%1: cost, %2: snapshot label (i.e. func name etc.)", "%1: %2", 0176 prettyCost(item->cost()), QString::fromLatin1(prettyLabel(item->label()))); 0177 } 0178 return QVariant(); 0179 } 0180 0181 int DataTreeModel::columnCount(const QModelIndex& parent) const 0182 { 0183 Q_UNUSED(parent) 0184 return 1; 0185 } 0186 0187 int DataTreeModel::rowCount(const QModelIndex& parent) const 0188 { 0189 if (!m_data || (parent.isValid() && parent.column() != 0)) { 0190 return 0; 0191 } 0192 0193 if (parent.isValid()) { 0194 if (!parent.internalPointer()) { 0195 // snapshot without detailed heaptree 0196 return 0; 0197 } 0198 return static_cast<const TreeLeafItem*>(parent.internalPointer())->children().size(); 0199 } else { 0200 return m_data->snapshots().size(); 0201 } 0202 } 0203 0204 QModelIndex DataTreeModel::index(int row, int column, const QModelIndex& parent) const 0205 { 0206 if (row < 0 || row >= rowCount(parent) || column < 0 || column >= columnCount(parent)) { 0207 // invalid 0208 return QModelIndex(); 0209 } 0210 0211 if (parent.isValid()) { 0212 if (parent.column() == 0) { 0213 Q_ASSERT(parent.internalPointer()); 0214 // parent is a tree leaf item 0215 return createIndex(row, column, static_cast<void*>(static_cast<const TreeLeafItem*>(parent.internalPointer())->children().at(row))); 0216 } else { 0217 return QModelIndex(); 0218 } 0219 } else { 0220 return createIndex(row, column, static_cast<void*>(m_data->snapshots().at(row)->heapTree())); 0221 } 0222 } 0223 0224 QModelIndex DataTreeModel::parent(const QModelIndex& child) const 0225 { 0226 if (child.internalPointer()) { 0227 const TreeLeafItem* item = static_cast<const TreeLeafItem*>(child.internalPointer()); 0228 if (item->parent()) { 0229 int row = m_nodeToRow.value(item->parent(), -1); 0230 Q_ASSERT(row != -1); 0231 // somewhere in the detailed heap tree 0232 return createIndex(row, 0, static_cast<void*>(item->parent())); 0233 } else { 0234 // snapshot item with heap tree 0235 return QModelIndex(); 0236 } 0237 } else { 0238 // snapshot item without detailed heap tree 0239 return QModelIndex(); 0240 } 0241 } 0242 0243 QModelIndex DataTreeModel::indexForSnapshot(const SnapshotItem* snapshot) const 0244 { 0245 int idx = m_data->snapshots().indexOf(const_cast<SnapshotItem*>(snapshot)); 0246 if ( idx == -1 ) { 0247 return QModelIndex(); 0248 } 0249 return index(idx, 0); 0250 } 0251 0252 QModelIndex DataTreeModel::indexForTreeLeaf(const TreeLeafItem* node) const 0253 { 0254 if (!m_data) { 0255 return QModelIndex(); 0256 } 0257 int row = m_nodeToRow.value(node, -1); 0258 if (row == -1) { 0259 return QModelIndex(); 0260 } 0261 return createIndex(row, 0, const_cast<void*>(static_cast<const void*>(node))); 0262 } 0263 0264 ModelItem DataTreeModel::itemForIndex(const QModelIndex& idx) const 0265 { 0266 if (!m_data || !idx.isValid() || idx.row() >= m_data->snapshots().count()) { 0267 return ModelItem(0, 0); 0268 } 0269 if (idx.parent().isValid()) { 0270 Q_ASSERT(idx.internalPointer()); 0271 return ModelItem(static_cast<const TreeLeafItem*>(idx.internalPointer()), 0); 0272 } else { 0273 return ModelItem(0, m_data->snapshots().at(idx.row())); 0274 } 0275 } 0276 0277 QModelIndex DataTreeModel::indexForItem(const ModelItem& item) const 0278 { 0279 if (!item.first && !item.second) { 0280 return QModelIndex(); 0281 } 0282 Q_ASSERT((item.first && !item.second) || (!item.first && item.second)); 0283 if (item.first) { 0284 return indexForTreeLeaf(item.first); 0285 } else { 0286 return indexForSnapshot(item.second); 0287 } 0288 } 0289 0290 const SnapshotItem* DataTreeModel::snapshotForTreeLeaf(const TreeLeafItem* node) const 0291 { 0292 while (node->parent()) { 0293 node = node->parent(); 0294 } 0295 return m_heapRootToSnapshot.value(node); 0296 }