]> git.cworth.org Git - apitrace/blob - gui/apitrace.cpp
Remove ApiTrace::FrameMarker.
[apitrace] / gui / apitrace.cpp
1 #include "apitrace.h"
2
3 #include "traceloader.h"
4 #include "saverthread.h"
5
6 #include <QDebug>
7 #include <QDir>
8 #include <QThread>
9
10 ApiTrace::ApiTrace()
11     : m_needsSaving(false)
12 {
13     m_loader = new TraceLoader();
14
15     connect(this, SIGNAL(loadTrace(QString)),
16             m_loader, SLOT(loadTrace(QString)));
17     connect(this, SIGNAL(requestFrame(ApiTraceFrame*)),
18             m_loader, SLOT(loadFrame(ApiTraceFrame*)));
19     connect(m_loader, SIGNAL(framesLoaded(const QList<ApiTraceFrame*>)),
20             this, SLOT(addFrames(const QList<ApiTraceFrame*>)));
21     connect(m_loader,
22             SIGNAL(frameContentsLoaded(ApiTraceFrame*,QVector<ApiTraceCall*>,quint64)),
23             this,
24             SLOT(loaderFrameLoaded(ApiTraceFrame*,QVector<ApiTraceCall*>,quint64)));
25     connect(m_loader, SIGNAL(finishedParsing()),
26             this, SLOT(finishedParsing()));
27     connect(this, SIGNAL(loaderSearch(ApiTrace::SearchRequest)),
28             m_loader, SLOT(search(ApiTrace::SearchRequest)));
29     connect(m_loader,
30             SIGNAL(searchResult(ApiTrace::SearchRequest,ApiTrace::SearchResult,ApiTraceCall*)),
31             this,
32             SLOT(loaderSearchResult(ApiTrace::SearchRequest,ApiTrace::SearchResult,ApiTraceCall*)));
33     connect(this, SIGNAL(loaderFindFrameStart(ApiTraceFrame*)),
34             m_loader, SLOT(findFrameStart(ApiTraceFrame*)));
35     connect(this, SIGNAL(loaderFindFrameEnd(ApiTraceFrame*)),
36             m_loader, SLOT(findFrameEnd(ApiTraceFrame*)));
37     connect(m_loader, SIGNAL(foundFrameStart(ApiTraceFrame*)),
38             this, SIGNAL(foundFrameStart(ApiTraceFrame*)));
39     connect(m_loader, SIGNAL(foundFrameEnd(ApiTraceFrame*)),
40             this, SIGNAL(foundFrameEnd(ApiTraceFrame*)));
41     connect(this, SIGNAL(loaderFindCallIndex(int)),
42             m_loader, SLOT(findCallIndex(int)));
43     connect(m_loader, SIGNAL(foundCallIndex(ApiTraceCall*)),
44             this, SIGNAL(foundCallIndex(ApiTraceCall*)));
45
46
47     connect(m_loader, SIGNAL(startedParsing()),
48             this, SIGNAL(startedLoadingTrace()));
49     connect(m_loader, SIGNAL(parsed(int)),
50             this, SIGNAL(loaded(int)));
51     connect(m_loader, SIGNAL(finishedParsing()),
52             this, SIGNAL(finishedLoadingTrace()));
53
54
55     m_saver = new SaverThread(this);
56     connect(m_saver, SIGNAL(traceSaved()),
57             this, SLOT(slotSaved()));
58     connect(m_saver, SIGNAL(traceSaved()),
59             this, SIGNAL(saved()));
60
61     m_loaderThread = new QThread();
62     m_loader->moveToThread(m_loaderThread);
63     m_loaderThread->start();
64 }
65
66 ApiTrace::~ApiTrace()
67 {
68     m_loaderThread->quit();
69     m_loaderThread->deleteLater();
70     qDeleteAll(m_frames);
71     delete m_loader;
72     delete m_saver;
73 }
74
75 bool ApiTrace::isEmpty() const
76 {
77     return m_frames.isEmpty();
78 }
79
80 QString ApiTrace::fileName() const
81 {
82     if (edited()) {
83         return m_tempFileName;
84     }
85
86     return m_fileName;
87 }
88
89 const QList<ApiTraceFrame*> & ApiTrace::frames() const
90 {
91     return m_frames;
92 }
93
94 ApiTraceFrame * ApiTrace::frameAt(int idx) const
95 {
96     return m_frames.value(idx);
97 }
98
99 int ApiTrace::numFrames() const
100 {
101     return m_frames.count();
102 }
103
104 int ApiTrace::numCallsInFrame(int idx) const
105 {
106     const ApiTraceFrame *frame = frameAt(idx);
107     if (frame) {
108         return frame->numChildren();
109     } else {
110         return 0;
111     }
112 }
113
114 void ApiTrace::setFileName(const QString &name)
115 {
116     if (m_fileName != name) {
117         m_fileName = name;
118         m_tempFileName = QString();
119
120         m_frames.clear();
121         m_errors.clear();
122         m_editedCalls.clear();
123         m_queuedErrors.clear();
124         m_needsSaving = false;
125         emit invalidated();
126
127         emit loadTrace(m_fileName);
128     }
129 }
130
131 void ApiTrace::addFrames(const QList<ApiTraceFrame*> &frames)
132 {
133     int currentFrames = m_frames.count();
134     int numNewFrames = frames.count();
135
136     emit beginAddingFrames(currentFrames, numNewFrames);
137
138     m_frames += frames;
139
140     foreach(ApiTraceFrame *frame, frames) {
141         frame->setParentTrace(this);
142     }
143
144     emit endAddingFrames();
145 }
146
147 ApiTraceCall * ApiTrace::callWithIndex(int idx) const
148 {
149     for (int i = 0; i < m_frames.count(); ++i) {
150         ApiTraceCall *call = m_frames[i]->callWithIndex(idx);
151         if (call) {
152             return call;
153         }
154     }
155     return NULL;
156 }
157
158 ApiTraceState ApiTrace::defaultState() const
159 {
160     ApiTraceFrame *frame = frameAt(0);
161     if (!frame || !frame->isLoaded() || frame->isEmpty()) {
162         return ApiTraceState();
163     }
164
165     ApiTraceCall *firstCall = frame->calls().first();
166     if (!firstCall->hasState()) {
167         return ApiTraceState();
168     }
169
170     return *firstCall->state();
171 }
172
173 void ApiTrace::callEdited(ApiTraceCall *call)
174 {
175     if (!m_editedCalls.contains(call)) {
176         //lets generate a temp filename
177         QString tempPath = QDir::tempPath();
178         m_tempFileName = QString::fromLatin1("%1/%2.edited")
179                          .arg(tempPath)
180                          .arg(m_fileName);
181     }
182     m_editedCalls.insert(call);
183     m_needsSaving = true;
184
185     emit changed(call);
186 }
187
188 void ApiTrace::callReverted(ApiTraceCall *call)
189 {
190     m_editedCalls.remove(call);
191
192     if (m_editedCalls.isEmpty()) {
193         m_needsSaving = false;
194     }
195     emit changed(call);
196 }
197
198 bool ApiTrace::edited() const
199 {
200     return !m_editedCalls.isEmpty();
201 }
202
203 bool ApiTrace::needsSaving() const
204 {
205     return m_needsSaving;
206 }
207
208 void ApiTrace::save()
209 {
210     QFileInfo fi(m_tempFileName);
211     QDir dir;
212     emit startedSaving();
213     dir.mkpath(fi.absolutePath());
214     m_saver->saveFile(m_tempFileName,
215                       m_fileName,
216                       m_editedCalls);
217 }
218
219 void ApiTrace::slotSaved()
220 {
221     m_needsSaving = false;
222 }
223
224 bool ApiTrace::isSaving() const
225 {
226     return m_saver->isRunning();
227 }
228
229 bool ApiTrace::hasErrors() const
230 {
231     return !m_errors.isEmpty();
232 }
233
234 void ApiTrace::loadFrame(ApiTraceFrame *frame)
235 {
236     if (!isFrameLoading(frame)) {
237         Q_ASSERT(!frame->isLoaded());
238         m_loadingFrames.insert(frame);
239         emit requestFrame(frame);
240     }
241 }
242
243 void ApiTrace::finishedParsing()
244 {
245     if (!m_frames.isEmpty()) {
246         ApiTraceFrame *firstFrame = m_frames[0];
247         if (firstFrame && !firstFrame->isLoaded()) {
248             loadFrame(firstFrame);
249         }
250     }
251 }
252
253 void ApiTrace::loaderFrameLoaded(ApiTraceFrame *frame,
254                                  const QVector<ApiTraceCall*> &calls,
255                                  quint64 binaryDataSize)
256 {
257     Q_ASSERT(frame->numChildrenToLoad() == calls.size());
258
259     if (!frame->isLoaded()) {
260         emit beginLoadingFrame(frame, calls.size());
261         frame->setCalls(calls, binaryDataSize);
262         emit endLoadingFrame(frame);
263         m_loadingFrames.remove(frame);
264     }
265
266     if (!m_queuedErrors.isEmpty()) {
267         QList< QPair<ApiTraceFrame*, ApiTraceError> >::iterator itr;
268         for (itr = m_queuedErrors.begin(); itr != m_queuedErrors.end();
269              ++itr) {
270             const ApiTraceError &error = (*itr).second;
271             if ((*itr).first == frame) {
272                 ApiTraceCall *call = frame->callWithIndex(error.callIndex);
273
274                 if (!call) {
275                     continue;
276                 }
277
278                 call->setError(error.message);
279                 m_queuedErrors.erase(itr);
280
281                 if (call->hasError()) {
282                     m_errors.insert(call);
283                 } else {
284                     m_errors.remove(call);
285                 }
286                 emit changed(call);
287             }
288         }
289     }
290 }
291
292 void ApiTrace::findNext(ApiTraceFrame *frame,
293                         ApiTraceCall *from,
294                         const QString &str,
295                         Qt::CaseSensitivity sensitivity)
296 {
297     ApiTraceCall *foundCall = 0;
298     int frameIdx = m_frames.indexOf(frame);
299     SearchRequest request(SearchRequest::Next,
300                           frame, from, str, sensitivity);
301
302     if (frame->isLoaded()) {
303         foundCall = frame->findNextCall(from, str, sensitivity);
304         if (foundCall) {
305             emit findResult(request, SearchResult_Found, foundCall);
306             return;
307         }
308
309         //if the frame is loaded we already searched it above
310         // so skip it
311         frameIdx += 1;
312     }
313
314     //for the rest of the frames we search from beginning
315     request.from = 0;
316     for (int i = frameIdx; i < m_frames.count(); ++i) {
317         ApiTraceFrame *frame = m_frames[i];
318         request.frame = frame;
319         if (!frame->isLoaded()) {
320             emit loaderSearch(request);
321             return;
322         } else {
323             ApiTraceCall *call = frame->findNextCall(0, str, sensitivity);
324             if (call) {
325                 emit findResult(request, SearchResult_Found, call);
326                 return;
327             }
328         }
329     }
330     emit findResult(request, SearchResult_Wrapped, 0);
331 }
332
333 void ApiTrace::findPrev(ApiTraceFrame *frame,
334                         ApiTraceCall *from,
335                         const QString &str,
336                         Qt::CaseSensitivity sensitivity)
337 {
338     ApiTraceCall *foundCall = 0;
339     int frameIdx = m_frames.indexOf(frame);
340     SearchRequest request(SearchRequest::Prev,
341                           frame, from, str, sensitivity);
342
343     if (frame->isLoaded()) {
344         foundCall = frame->findPrevCall(from, str, sensitivity);
345         if (foundCall) {
346             emit findResult(request, SearchResult_Found, foundCall);
347             return;
348         }
349
350         //if the frame is loaded we already searched it above
351         // so skip it
352         frameIdx -= 1;
353     }
354
355     request.from = 0;
356     for (int i = frameIdx; i >= 0; --i) {
357         ApiTraceFrame *frame = m_frames[i];
358         request.frame = frame;
359         if (!frame->isLoaded()) {
360             emit loaderSearch(request);
361             return;
362         } else {
363             ApiTraceCall *call = frame->findPrevCall(0, str, sensitivity);
364             if (call) {
365                 emit findResult(request, SearchResult_Found, call);
366                 return;
367             }
368         }
369     }
370     emit findResult(request, SearchResult_Wrapped, 0);
371 }
372
373 void ApiTrace::loaderSearchResult(const ApiTrace::SearchRequest &request,
374                                   ApiTrace::SearchResult result,
375                                   ApiTraceCall *call)
376 {
377     //qDebug()<<"Search result = "<<result
378     //       <<", call is = "<<call;
379     emit findResult(request, result, call);
380 }
381
382 void ApiTrace::findFrameStart(ApiTraceFrame *frame)
383 {
384     if (frame->isLoaded()) {
385         emit foundFrameStart(frame);
386     } else {
387         emit loaderFindFrameStart(frame);
388     }
389 }
390
391 void ApiTrace::findFrameEnd(ApiTraceFrame *frame)
392 {
393     if (frame->isLoaded()) {
394         emit foundFrameEnd(frame);
395     } else {
396         emit loaderFindFrameEnd(frame);
397     }
398 }
399
400 void ApiTrace::findCallIndex(int index)
401 {
402     int frameIdx = callInFrame(index);
403     ApiTraceFrame *frame = 0;
404
405     if (frameIdx < 0) {
406         emit foundCallIndex(0);
407         return;
408     }
409
410     frame = m_frames[frameIdx];
411
412     if (frame) {
413         if (frame->isLoaded()) {
414             ApiTraceCall *call = frame->callWithIndex(index);
415             emit foundCallIndex(call);
416         } else {
417             emit loaderFindCallIndex(index);
418         }
419     }
420 }
421
422 int ApiTrace::callInFrame(int callIdx) const
423 {
424     unsigned numCalls = 0;
425
426     for (int frameIdx = 0; frameIdx < m_frames.size(); ++frameIdx) {
427         const ApiTraceFrame *frame = m_frames[frameIdx];
428         unsigned numCallsInFrame =  frame->isLoaded()
429                 ? frame->numChildren()
430                 : frame->numChildrenToLoad();
431         unsigned firstCall = numCalls;
432         unsigned endCall = numCalls + numCallsInFrame;
433         if (firstCall <= callIdx && endCall > callIdx) {
434             return frameIdx;
435         }
436         numCalls = endCall;
437     }
438
439     return -1;
440 }
441
442 void ApiTrace::setCallError(const ApiTraceError &error)
443 {
444     int frameIdx = callInFrame(error.callIndex);
445     ApiTraceFrame *frame = 0;
446
447     if (frameIdx < 0) {
448         return;
449     }
450     frame = m_frames[frameIdx];
451
452     if (frame->isLoaded()) {
453         ApiTraceCall *call = frame->callWithIndex(error.callIndex);
454         call->setError(error.message);
455         if (call->hasError()) {
456             m_errors.insert(call);
457         } else {
458             m_errors.remove(call);
459         }
460         emit changed(call);
461     } else {
462         loadFrame(frame);
463         m_queuedErrors.append(qMakePair(frame, error));
464     }
465 }
466
467 bool ApiTrace::isFrameLoading(ApiTraceFrame *frame) const
468 {
469     return m_loadingFrames.contains(frame);
470 }
471
472 void ApiTrace::bindThumbnailsToFrames(const QList<QImage> &thumbnails)
473 {
474     QList<ApiTraceFrame *> frames = m_frames;
475
476     QList<QImage>::const_iterator thumbnail = thumbnails.begin();
477
478     foreach (ApiTraceFrame *frame, frames) {
479         if (thumbnail != thumbnails.end()) {
480             frame->setThumbnail(*thumbnail);
481
482             ++thumbnail;
483
484             emit changed(frame);
485         }
486     }
487 }
488
489 #include "apitrace.moc"