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