]> git.cworth.org Git - apitrace/blob - gui/apitracemodel.cpp
Make state lookups with on-demand loading work.
[apitrace] / gui / apitracemodel.cpp
1 #include "apitracemodel.h"
2
3 #include "apitracecall.h"
4 #include "traceloader.h"
5 #include "trace_parser.hpp"
6
7 #include <QDebug>
8 #include <QImage>
9 #include <QVariant>
10
11
12 ApiTraceModel::ApiTraceModel(QObject *parent)
13     : QAbstractItemModel(parent),
14       m_trace(0)
15 {
16 }
17
18 ApiTraceModel::~ApiTraceModel()
19 {
20     m_trace = 0;
21 }
22
23 QVariant ApiTraceModel::data(const QModelIndex &index, int role) const
24 {
25     if (!index.isValid())
26         return QVariant();
27
28     if (index.column() != 0)
29         return QVariant();
30
31     ApiTraceEvent *itm = item(index);
32     if (!itm) {
33         return QVariant();
34     }
35
36     switch (role) {
37     case Qt::DisplayRole:
38         return itm->staticText().text();
39     case Qt::DecorationRole:
40         return QImage();
41     case Qt::ToolTipRole: {
42         const QString stateText = tr("State info available.");
43         if (itm->type() == ApiTraceEvent::Call) {
44             ApiTraceCall *call = static_cast<ApiTraceCall*>(itm);
45             if (!call->hasState())
46                 return QString::fromLatin1("%1)&nbsp;<b>%2</b>")
47                     .arg(call->index())
48                     .arg(call->name());
49             else
50                 return QString::fromLatin1("%1)&nbsp;<b>%2</b><br/>%3")
51                     .arg(call->index())
52                     .arg(call->name())
53                     .arg(stateText);
54         } else {
55             ApiTraceFrame *frame = static_cast<ApiTraceFrame*>(itm);
56             QString text = QObject::tr("%1)&nbsp;Frame&nbsp;")
57                            .arg(frame->number);
58             int binaryDataSize = frame->binaryDataSize() / 1024;
59             if (!frame->hasState())
60                 return QObject::tr(
61                     "<b>%1&nbsp;</b>(binary&nbsp;data&nbsp;size&nbsp;=&nbsp;%2kB)")
62                     .arg(text)
63                     .arg(binaryDataSize);
64             else
65                 return QObject::tr(
66                     "<b>%1&nbsp;(binary&nbsp;data&nbsp;size&nbsp;=&nbsp;%2kB)</b>"
67                     "<br/>%3")
68                     .arg(text)
69                     .arg(binaryDataSize)
70                     .arg(stateText);
71         }
72     }
73     case ApiTraceModel::EventRole:
74         return QVariant::fromValue(itm);
75     }
76
77     return QVariant();
78 }
79
80 Qt::ItemFlags ApiTraceModel::flags(const QModelIndex &index) const
81 {
82     if (!index.isValid())
83         return 0;
84
85     return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
86 }
87
88 QVariant ApiTraceModel::headerData(int section, Qt::Orientation orientation,
89                                    int role ) const
90 {
91     if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
92         switch (section) {
93         case 0:
94             return tr("Events");
95         case 1:
96             return tr("Flags");
97         default:
98             //fall through
99             break;
100         }
101     }
102
103     return QVariant();
104 }
105
106 QModelIndex ApiTraceModel::index(int row, int column,
107                                  const QModelIndex &parent) const
108 {
109     if ((parent.isValid() && parent.column() != 0) || column != 0)
110         return QModelIndex();
111
112     ApiTraceEvent *event = item(parent);
113     if (event) {
114         if (event->type() != ApiTraceEvent::Frame) {
115             qDebug()<<"got a valid parent but it's not a frame "<<event->type();
116             return QModelIndex();
117         }
118         ApiTraceFrame *frame = static_cast<ApiTraceFrame*>(event);
119         ApiTraceCall *call = frame->call(row);
120         if (call)
121             return createIndex(row, column, call);
122         else
123             return QModelIndex();
124     } else {
125         ApiTraceFrame *frame = m_trace->frameAt(row);
126         if (frame)
127             return createIndex(row, column, frame);
128         else
129             return QModelIndex();
130     }
131     return QModelIndex();
132 }
133
134 bool ApiTraceModel::hasChildren(const QModelIndex &parent) const
135 {
136     if (parent.isValid()) {
137         ApiTraceEvent *event = item(parent);
138         if (event && event->type() == ApiTraceEvent::Frame) {
139             ApiTraceFrame *frame = static_cast<ApiTraceFrame*>(event);
140             return !frame->isEmpty();
141         } else
142             return false;
143     } else {
144         return (rowCount() > 0);
145     }
146 }
147
148 QModelIndex ApiTraceModel::parent(const QModelIndex &index) const
149 {
150     if (!index.isValid())
151         return QModelIndex();
152
153     ApiTraceEvent *event = item(index);
154     if (event && event->type() == ApiTraceEvent::Call) {
155         ApiTraceCall *call = static_cast<ApiTraceCall*>(event);
156         Q_ASSERT(call->parentFrame());
157         return createIndex(call->parentFrame()->number,
158                            0, call->parentFrame());
159     }
160     return QModelIndex();
161 }
162
163 int ApiTraceModel::rowCount(const QModelIndex &parent) const
164 {
165     if (!parent.isValid())
166         return m_trace->numFrames();
167
168     ApiTraceEvent *event = item(parent);
169     if (!event || event->type() == ApiTraceEvent::Call)
170         return 0;
171
172     ApiTraceFrame *frame = static_cast<ApiTraceFrame*>(event);
173     if (frame)
174         return frame->numChildren();
175
176     return 0;
177 }
178
179 int ApiTraceModel::columnCount(const QModelIndex &parent) const
180 {
181     return 1;
182 }
183
184 bool ApiTraceModel::insertRows(int position, int rows,
185                                const QModelIndex &parent)
186 {
187     return false;
188 }
189
190 bool ApiTraceModel::removeRows(int position, int rows,
191                                const QModelIndex &parent)
192 {
193     bool success = true;
194
195     Q_UNUSED(parent);
196
197     beginRemoveRows(parent, position, position + rows - 1);
198     //XXX remove it from ApiTrace
199     endRemoveRows();
200
201     return success;
202 }
203
204 void ApiTraceModel::setApiTrace(ApiTrace *trace)
205 {
206     if (m_trace == trace)
207         return;
208     if (m_trace)
209         disconnect(m_trace);
210     m_trace = trace;
211     connect(m_trace, SIGNAL(invalidated()),
212             this, SLOT(invalidateFrames()));
213     connect(m_trace, SIGNAL(framesInvalidated()),
214             this, SLOT(invalidateFrames()));
215     connect(m_trace, SIGNAL(beginAddingFrames(int, int)),
216             this, SLOT(beginAddingFrames(int, int)));
217     connect(m_trace, SIGNAL(endAddingFrames()),
218             this, SLOT(endAddingFrames()));
219     connect(m_trace, SIGNAL(changed(ApiTraceCall*)),
220             this, SLOT(callChanged(ApiTraceCall*)));
221     connect(m_trace, SIGNAL(beginLoadingFrame(ApiTraceFrame*,int)),
222             this, SLOT(beginLoadingFrame(ApiTraceFrame*,int)));
223     connect(m_trace, SIGNAL(endLoadingFrame(ApiTraceFrame*)),
224             this, SLOT(endLoadingFrame(ApiTraceFrame*)));
225
226 }
227
228 const ApiTrace * ApiTraceModel::apiTrace() const
229 {
230     return m_trace;
231 }
232
233 void ApiTraceModel::invalidateFrames()
234 {
235     beginResetModel();
236     endResetModel();
237 }
238
239 void ApiTraceModel::beginAddingFrames(int oldCount, int numAdded)
240 {
241     beginInsertRows(QModelIndex(), oldCount,
242                     oldCount + numAdded - 1);
243 }
244
245 ApiTraceEvent * ApiTraceModel::item(const QModelIndex &index) const
246 {
247     if (!index.isValid())
248         return 0;
249     return static_cast<ApiTraceEvent*>(index.internalPointer());
250 }
251
252 void ApiTraceModel::stateSetOnEvent(ApiTraceEvent *event)
253 {
254     if (!event)
255         return;
256
257     if (event->type() == ApiTraceEvent::Call) {
258         ApiTraceCall *call = static_cast<ApiTraceCall*>(event);
259         ApiTraceFrame *frame = call->parentFrame();
260         int row = frame->callIndex(call);
261         QModelIndex index = createIndex(row, 0, call);
262         emit dataChanged(index, index);
263     } else if (event->type() == ApiTraceEvent::Frame) {
264         ApiTraceFrame *frame = static_cast<ApiTraceFrame*>(event);
265         const QList<ApiTraceFrame*> frames = m_trace->frames();
266         int row = frames.indexOf(frame);
267         QModelIndex index = createIndex(row, 0, frame);
268         emit dataChanged(index, index);
269     }
270 }
271
272 QModelIndex ApiTraceModel::callIndex(int callNum) const
273 {
274     ApiTraceCall *call = m_trace->callWithIndex(callNum);
275     return indexForCall(call);
276 }
277
278 QModelIndex ApiTraceModel::indexForCall(ApiTraceCall *call) const
279 {
280     if (!call) {
281         return QModelIndex();
282     }
283
284     ApiTraceFrame *frame = call->parentFrame();
285     Q_ASSERT(frame);
286
287     int row = frame->callIndex(call);
288     if (row < 0) {
289         qDebug() << "Couldn't find call num "<<call->index()<<" inside parent!";
290         return QModelIndex();
291     }
292     return createIndex(row, 0, call);
293 }
294
295 void ApiTraceModel::callChanged(ApiTraceCall *call)
296 {
297     ApiTrace *trace = call->parentFrame()->parentTrace();
298
299 #if 0
300     qDebug()<<"Call changed = "<<call->edited();
301     qDebug()<<"\ttrace edited = "<<trace->edited();
302     qDebug()<<"\ttrace file = "<<trace->fileName();
303     qDebug()<<"\ttrace needs saving = "<<trace->needsSaving();
304 #endif
305
306     Q_ASSERT(trace);
307     if (trace->needsSaving())
308         trace->save();
309
310     ApiTraceFrame *frame = call->parentFrame();
311     int row = frame->callIndex(call);
312     QModelIndex index = createIndex(row, 0, call);
313     emit dataChanged(index, index);
314 }
315
316 void ApiTraceModel::endAddingFrames()
317 {
318     endInsertRows();
319 }
320
321 bool ApiTraceModel::canFetchMore(const QModelIndex &parent) const
322 {
323     if (parent.isValid()) {
324         ApiTraceEvent *event = item(parent);
325         if (event && event->type() == ApiTraceEvent::Frame) {
326             ApiTraceFrame *frame = static_cast<ApiTraceFrame*>(event);
327             return !frame->loaded() && !m_loadingFrames.contains(frame);
328         } else
329             return false;
330     } else {
331         return false;
332     }
333 }
334
335 void ApiTraceModel::fetchMore(const QModelIndex &parent)
336 {
337     if (parent.isValid()) {
338         ApiTraceEvent *event = item(parent);
339         if (event && event->type() == ApiTraceEvent::Frame) {
340             ApiTraceFrame *frame = static_cast<ApiTraceFrame*>(event);
341             QModelIndex index = createIndex(frame->number, 0, frame);
342
343             Q_ASSERT(!frame->loaded());
344             m_loadingFrames.insert(frame);
345
346             m_trace->loadFrame(frame);
347         }
348     }
349 }
350
351 void ApiTraceModel::beginLoadingFrame(ApiTraceFrame *frame, int numAdded)
352 {
353     QModelIndex index = createIndex(frame->number, 0, frame);
354     beginInsertRows(index, 0, numAdded - 1);
355 }
356
357 void ApiTraceModel::endLoadingFrame(ApiTraceFrame *frame)
358 {
359     QModelIndex index = createIndex(frame->number, 0, frame);
360 #if 0
361     qDebug()<<"Frame loaded = "<<frame->loaded();
362     qDebug()<<"\tframe idx = "<<frame->number;
363     qDebug()<<"\tis empty = "<<frame->isEmpty();
364     qDebug()<<"\tnum children = "<<frame->numChildren();
365     qDebug()<<"\tindex is "<<index;
366 #endif
367
368     endInsertRows();
369
370     emit dataChanged(index, index);
371
372     m_loadingFrames.remove(frame);
373 }
374
375 #include "apitracemodel.moc"