]> git.cworth.org Git - apitrace/blob - gui/mainwindow.cpp
Start working on trace editing
[apitrace] / gui / mainwindow.cpp
1 #include "mainwindow.h"
2
3 #include "apitrace.h"
4 #include "apitracecall.h"
5 #include "apicalldelegate.h"
6 #include "apitracemodel.h"
7 #include "apitracefilter.h"
8 #include "argumentseditor.h"
9 #include "imageviewer.h"
10 #include "jumpwidget.h"
11 #include "retracer.h"
12 #include "searchwidget.h"
13 #include "settingsdialog.h"
14 #include "shaderssourcewidget.h"
15 #include "tracedialog.h"
16 #include "traceprocess.h"
17 #include "ui_retracerdialog.h"
18 #include "vertexdatainterpreter.h"
19
20 #include <QAction>
21 #include <QDebug>
22 #include <QDesktopServices>
23 #include <QDir>
24 #include <QFileDialog>
25 #include <QLineEdit>
26 #include <QMessageBox>
27 #include <QProgressBar>
28 #include <QShortcut>
29 #include <QToolBar>
30 #include <QUrl>
31 #include <QVBoxLayout>
32 #include <QWebPage>
33 #include <QWebView>
34
35
36 MainWindow::MainWindow()
37     : QMainWindow(),
38       m_selectedEvent(0),
39       m_stateEvent(0)
40 {
41     m_ui.setupUi(this);
42     initObjects();
43     initConnections();
44 }
45
46 void MainWindow::createTrace()
47 {
48     TraceDialog dialog;
49
50     if (!m_traceProcess->canTrace()) {
51         QMessageBox::warning(
52             this,
53             tr("Unsupported"),
54             tr("Current configuration doesn't support tracing."));
55         return;
56     }
57
58     if (dialog.exec() == QDialog::Accepted) {
59         qDebug()<< "App : " <<dialog.applicationPath();
60         qDebug()<< "  Arguments: "<<dialog.arguments();
61         m_traceProcess->setExecutablePath(dialog.applicationPath());
62         m_traceProcess->setArguments(dialog.arguments());
63         m_traceProcess->start();
64     }
65 }
66
67 void MainWindow::openTrace()
68 {
69     QString fileName =
70         QFileDialog::getOpenFileName(
71             this,
72             tr("Open Trace"),
73             QDir::homePath(),
74             tr("Trace Files (*.trace)"));
75
76     qDebug()<< "File name : " <<fileName;
77
78     newTraceFile(fileName);
79 }
80
81 void MainWindow::loadTrace(const QString &fileName)
82 {
83     if (!QFile::exists(fileName)) {
84         QMessageBox::warning(this, tr("File Missing"),
85                              tr("File '%1' doesn't exist.").arg(fileName));
86         return;
87     }
88     qDebug()<< "Loading  : " <<fileName;
89
90     m_progressBar->setValue(0);
91     newTraceFile(fileName);
92 }
93
94 void MainWindow::callItemSelected(const QModelIndex &index)
95 {
96     ApiTraceEvent *event =
97         index.data(ApiTraceModel::EventRole).value<ApiTraceEvent*>();
98
99     if (event && event->type() == ApiTraceEvent::Call) {
100         ApiTraceCall *call = static_cast<ApiTraceCall*>(event);
101         m_ui.detailsWebView->setHtml(call->toHtml());
102         m_ui.detailsDock->show();
103         m_argsEditor->setCall(call);
104         if (call->hasBinaryData()) {
105             QByteArray data =
106                 call->argValues[call->binaryDataIndex()].toByteArray();
107             m_vdataInterpreter->setData(data);
108
109             for (int i = 0; i < call->argNames.count(); ++i) {
110                 QString name = call->argNames[i];
111                 if (name == QLatin1String("stride")) {
112                     int stride = call->argValues[i].toInt();
113                     m_ui.vertexStrideSB->setValue(stride);
114                 } else if (name == QLatin1String("size")) {
115                     int components = call->argValues[i].toInt();
116                     m_ui.vertexComponentsSB->setValue(components);
117                 } else if (name == QLatin1String("type")) {
118                     QString val = call->argValues[i].toString();
119                     int textIndex = m_ui.vertexTypeCB->findText(val);
120                     if (textIndex >= 0)
121                         m_ui.vertexTypeCB->setCurrentIndex(textIndex);
122                 }
123             }
124         }
125         m_ui.argsEditorDock->show();
126         m_ui.vertexDataDock->setVisible(call->hasBinaryData());
127         m_selectedEvent = call;
128     } else {
129         if (event && event->type() == ApiTraceEvent::Frame) {
130             m_selectedEvent = static_cast<ApiTraceFrame*>(event);
131         } else
132             m_selectedEvent = 0;
133         m_ui.detailsDock->hide();
134         m_ui.vertexDataDock->hide();
135     }
136     if (m_selectedEvent && !m_selectedEvent->state().isEmpty()) {
137         fillStateForFrame();
138     } else
139         m_ui.stateDock->hide();
140 }
141
142 void MainWindow::replayStart()
143 {
144     QDialog dlg;
145     Ui_RetracerDialog dlgUi;
146     dlgUi.setupUi(&dlg);
147
148     dlgUi.doubleBufferingCB->setChecked(
149         m_retracer->isDoubleBuffered());
150     dlgUi.benchmarkCB->setChecked(
151         m_retracer->isBenchmarking());
152
153     if (dlg.exec() == QDialog::Accepted) {
154         m_retracer->setDoubleBuffered(
155             dlgUi.doubleBufferingCB->isChecked());
156         m_retracer->setBenchmarking(
157             dlgUi.benchmarkCB->isChecked());
158         replayTrace(false);
159     }
160 }
161
162 void MainWindow::replayStop()
163 {
164     m_retracer->quit();
165     m_ui.actionStop->setEnabled(false);
166     m_ui.actionReplay->setEnabled(true);
167     m_ui.actionLookupState->setEnabled(true);
168 }
169
170 void MainWindow::newTraceFile(const QString &fileName)
171 {
172     m_traceFileName = fileName;
173     m_trace->setFileName(fileName);
174
175     if (m_traceFileName.isEmpty()) {
176         m_ui.actionReplay->setEnabled(false);
177         m_ui.actionLookupState->setEnabled(false);
178         setWindowTitle(tr("QApiTrace"));
179     } else {
180         QFileInfo info(fileName);
181         m_ui.actionReplay->setEnabled(true);
182         m_ui.actionLookupState->setEnabled(true);
183         setWindowTitle(
184             tr("QApiTrace - %1").arg(info.fileName()));
185     }
186 }
187
188 void MainWindow::replayFinished(const QString &output)
189 {
190     m_ui.actionStop->setEnabled(false);
191     m_ui.actionReplay->setEnabled(true);
192     m_ui.actionLookupState->setEnabled(true);
193
194     m_progressBar->hide();
195     if (output.length() < 80) {
196         statusBar()->showMessage(output);
197     }
198     m_stateEvent = 0;
199     statusBar()->showMessage(
200         tr("Replaying finished!"), 2000);
201 }
202
203 void MainWindow::replayError(const QString &message)
204 {
205     m_ui.actionStop->setEnabled(false);
206     m_ui.actionReplay->setEnabled(true);
207     m_ui.actionLookupState->setEnabled(true);
208     m_stateEvent = 0;
209
210     m_progressBar->hide();
211     statusBar()->showMessage(
212         tr("Replaying unsuccessful."), 2000);
213     QMessageBox::warning(
214         this, tr("Replay Failed"), message);
215 }
216
217 void MainWindow::startedLoadingTrace()
218 {
219     Q_ASSERT(m_trace);
220     m_progressBar->show();
221     QFileInfo info(m_trace->fileName());
222     statusBar()->showMessage(
223         tr("Loading %1...").arg(info.fileName()));
224 }
225
226 void MainWindow::finishedLoadingTrace()
227 {
228     m_progressBar->hide();
229     if (!m_trace) {
230         return;
231     }
232     QFileInfo info(m_trace->fileName());
233     statusBar()->showMessage(
234         tr("Loaded %1").arg(info.fileName()), 3000);
235 }
236
237 void MainWindow::replayTrace(bool dumpState)
238 {
239     if (m_traceFileName.isEmpty())
240         return;
241
242     m_retracer->setFileName(m_traceFileName);
243     m_retracer->setCaptureState(dumpState);
244     if (m_retracer->captureState() && m_selectedEvent) {
245         int index = 0;
246         if (m_selectedEvent->type() == ApiTraceEvent::Call) {
247             index = static_cast<ApiTraceCall*>(m_selectedEvent)->index;
248         } else if (m_selectedEvent->type() == ApiTraceEvent::Frame) {
249             ApiTraceFrame *frame =
250                 static_cast<ApiTraceFrame*>(m_selectedEvent);
251             if (frame->calls.isEmpty()) {
252                 //XXX i guess we could still get the current state
253                 qDebug()<<"tried to get a state for an empty frame";
254                 return;
255             }
256             index = frame->calls.first()->index;
257         } else {
258             qDebug()<<"Unknown event type";
259             return;
260         }
261         m_retracer->setCaptureAtCallNumber(index);
262     }
263     m_retracer->start();
264
265     m_ui.actionStop->setEnabled(true);
266     m_progressBar->show();
267     if (dumpState)
268         statusBar()->showMessage(
269             tr("Looking up the state..."));
270     else
271         statusBar()->showMessage(
272             tr("Replaying the trace file..."));
273 }
274
275 void MainWindow::lookupState()
276 {
277     if (!m_selectedEvent) {
278         QMessageBox::warning(
279             this, tr("Unknown Event"),
280             tr("To inspect the state select an event in the event list."));
281         return;
282     }
283     m_stateEvent = m_selectedEvent;
284     replayTrace(true);
285 }
286
287 MainWindow::~MainWindow()
288 {
289 }
290
291 static void
292 variantToString(const QVariant &var, QString &str)
293 {
294     if (var.type() == QVariant::List) {
295         QVariantList lst = var.toList();
296         str += QLatin1String("[");
297         for (int i = 0; i < lst.count(); ++i) {
298             QVariant val = lst[i];
299             variantToString(val, str);
300             if (i < lst.count() - 1)
301                 str += QLatin1String(", ");
302         }
303         str += QLatin1String("]");
304     } else if (var.type() == QVariant::Map) {
305         Q_ASSERT(!"unsupported state type");
306     } else if (var.type() == QVariant::Hash) {
307         Q_ASSERT(!"unsupported state type");
308     } else {
309         str += var.toString();
310     }
311 }
312
313 static QTreeWidgetItem *
314 variantToItem(const QString &key, const QVariant &var, const QVariant &defaultVar);
315
316 static void
317 variantMapToItems(const QVariantMap &map, const QVariantMap &defaultMap, QList<QTreeWidgetItem *> &items)
318 {
319     QVariantMap::const_iterator itr;
320     for (itr = map.constBegin(); itr != map.constEnd(); ++itr) {
321         QString key = itr.key();
322         QVariant var = itr.value();
323         QVariant defaultVar = defaultMap[key];
324
325         QTreeWidgetItem *item = variantToItem(key, var, defaultVar);
326         if (item) {
327             items.append(item);
328         }
329     }
330 }
331
332 static void
333 variantListToItems(const QVariantList &lst, const QVariantList &defaultLst, QList<QTreeWidgetItem *> &items)
334 {
335     for (int i = 0; i < lst.count(); ++i) {
336         QString key = QString::number(i);
337         QVariant var = lst[i];
338         QVariant defaultVar;
339         
340         if (i < defaultLst.count()) {
341             defaultVar = defaultLst[i];
342         }
343
344         QTreeWidgetItem *item = variantToItem(key, var, defaultVar);
345         if (item) {
346             items.append(item);
347         }
348     }
349 }
350
351 static bool
352 isVariantDeep(const QVariant &var)
353 {
354     if (var.type() == QVariant::List) {
355         QVariantList lst = var.toList();
356         for (int i = 0; i < lst.count(); ++i) {
357             if (isVariantDeep(lst[i])) {
358                 return true;
359             }
360         }
361         return false;
362     } else if (var.type() == QVariant::Map) {
363         return true;
364     } else if (var.type() == QVariant::Hash) {
365         return true;
366     } else {
367         return false;
368     }
369 }
370
371 static QTreeWidgetItem *
372 variantToItem(const QString &key, const QVariant &var, const QVariant &defaultVar)
373 {
374     if (var == defaultVar) {
375         return NULL;
376     }
377
378     QString val;
379
380     bool deep = isVariantDeep(var);
381     if (!deep) {
382         variantToString(var, val);
383     }
384
385     //qDebug()<<"key = "<<key;
386     //qDebug()<<"val = "<<val;
387     QStringList lst;
388     lst += key;
389     lst += val;
390
391     QTreeWidgetItem *item = new QTreeWidgetItem((QTreeWidgetItem *)0, lst);
392
393     if (deep) {
394         QList<QTreeWidgetItem *> children;
395         if (var.type() == QVariant::Map) {
396             QVariantMap map = var.toMap();
397             QVariantMap defaultMap = defaultVar.toMap();
398             variantMapToItems(map, defaultMap, children);
399         }
400         if (var.type() == QVariant::List) {
401             QVariantList lst = var.toList();
402             QVariantList defaultLst = defaultVar.toList();
403             variantListToItems(lst, defaultLst, children);
404         }
405         item->addChildren(children);
406     }
407
408     return item;
409 }
410
411 void MainWindow::fillStateForFrame()
412 {
413     QVariantMap params;
414
415     if (!m_selectedEvent || m_selectedEvent->state().isEmpty())
416         return;
417
418     bool nonDefaults = m_ui.nonDefaultsCB->isChecked();
419     QVariantMap defaultParams;
420     if (nonDefaults) {
421         ApiTraceState defaultState = m_trace->defaultState();
422         defaultParams = defaultState.parameters();
423     }
424
425     const ApiTraceState &state = m_selectedEvent->state();
426     m_ui.stateTreeWidget->clear();
427     params = state.parameters();
428     QList<QTreeWidgetItem *> items;
429     variantMapToItems(params, defaultParams, items);
430     m_ui.stateTreeWidget->insertTopLevelItems(0, items);
431
432     QMap<QString, QString> shaderSources = state.shaderSources();
433     if (shaderSources.isEmpty()) {
434         m_sourcesWidget->setShaders(shaderSources);
435     } else {
436         m_sourcesWidget->setShaders(shaderSources);
437     }
438
439     const QList<ApiTexture> &textures =
440         state.textures();
441     const QList<ApiFramebuffer> &fbos =
442         state.framebuffers();
443
444     m_ui.surfacesTreeWidget->clear();
445     if (textures.isEmpty() && fbos.isEmpty()) {
446         m_ui.surfacesTab->setDisabled(false);
447     } else {
448         m_ui.surfacesTreeWidget->setIconSize(QSize(64, 64));
449         if (!textures.isEmpty()) {
450             QTreeWidgetItem *textureItem =
451                 new QTreeWidgetItem(m_ui.surfacesTreeWidget);
452             textureItem->setText(0, tr("Textures"));
453             if (textures.count() <= 6)
454                 textureItem->setExpanded(true);
455
456             for (int i = 0; i < textures.count(); ++i) {
457                 const ApiTexture &texture =
458                     textures[i];
459                 QIcon icon(QPixmap::fromImage(texture.thumb()));
460                 QTreeWidgetItem *item = new QTreeWidgetItem(textureItem);
461                 item->setIcon(0, icon);
462                 int width = texture.size().width();
463                 int height = texture.size().height();
464                 QString descr =
465                     QString::fromLatin1("%1, %2 x %3")
466                     .arg(texture.target())
467                     .arg(width)
468                     .arg(height);
469                 item->setText(1, descr);
470
471                 item->setData(0, Qt::UserRole,
472                               texture.image());
473             }
474         }
475         if (!fbos.isEmpty()) {
476             QTreeWidgetItem *fboItem =
477                 new QTreeWidgetItem(m_ui.surfacesTreeWidget);
478             fboItem->setText(0, tr("Framebuffers"));
479             if (fbos.count() <= 6)
480                 fboItem->setExpanded(true);
481
482             for (int i = 0; i < fbos.count(); ++i) {
483                 const ApiFramebuffer &fbo =
484                     fbos[i];
485                 QIcon icon(QPixmap::fromImage(fbo.thumb()));
486                 QTreeWidgetItem *item = new QTreeWidgetItem(fboItem);
487                 item->setIcon(0, icon);
488                 int width = fbo.size().width();
489                 int height = fbo.size().height();
490                 QString descr =
491                     QString::fromLatin1("%1, %2 x %3")
492                     .arg(fbo.type())
493                     .arg(width)
494                     .arg(height);
495                 item->setText(1, descr);
496
497                 item->setData(0, Qt::UserRole,
498                               fbo.image());
499             }
500         }
501         m_ui.surfacesTab->setEnabled(true);
502     }
503     m_ui.stateDock->show();
504 }
505
506 void MainWindow::showSettings()
507 {
508     SettingsDialog dialog;
509     dialog.setFilterModel(m_proxyModel);
510
511     dialog.exec();
512 }
513
514 void MainWindow::openHelp(const QUrl &url)
515 {
516     QDesktopServices::openUrl(url);
517 }
518
519 void MainWindow::showSurfacesMenu(const QPoint &pos)
520 {
521     QTreeWidget *tree = m_ui.surfacesTreeWidget;
522     QTreeWidgetItem *item = tree->itemAt(pos);
523     if (!item)
524         return;
525
526     QMenu menu(tr("Surfaces"), this);
527     //add needed actions
528     QAction *act = menu.addAction(tr("View Image"));
529     act->setStatusTip(tr("View the currently selected surface"));
530     connect(act, SIGNAL(triggered()),
531             SLOT(showSelectedSurface()));
532
533     menu.exec(tree->viewport()->mapToGlobal(pos));
534 }
535
536 void MainWindow::showSelectedSurface()
537 {
538     QTreeWidgetItem *item =
539         m_ui.surfacesTreeWidget->currentItem();
540
541     if (!item)
542         return;
543
544     QVariant var = item->data(0, Qt::UserRole);
545     m_imageViewer->setImage(var.value<QImage>());
546     m_imageViewer->show();
547     m_imageViewer->raise();
548     m_imageViewer->activateWindow();
549 }
550
551 void MainWindow::initObjects()
552 {
553     m_ui.stateTreeWidget->sortByColumn(0, Qt::AscendingOrder);
554
555     m_sourcesWidget = new ShadersSourceWidget(m_ui.shadersTab);
556     QVBoxLayout *layout = new QVBoxLayout;
557     layout->addWidget(m_sourcesWidget);
558     m_ui.shadersTab->setLayout(layout);
559
560     m_trace = new ApiTrace();
561     m_retracer = new Retracer(this);
562
563     m_vdataInterpreter = new VertexDataInterpreter(this);
564     m_vdataInterpreter->setListWidget(m_ui.vertexDataListWidget);
565     m_vdataInterpreter->setStride(
566         m_ui.vertexStrideSB->value());
567     m_vdataInterpreter->setComponents(
568         m_ui.vertexComponentsSB->value());
569     m_vdataInterpreter->setStartingOffset(
570         m_ui.startingOffsetSB->value());
571     m_vdataInterpreter->setTypeFromString(
572         m_ui.vertexTypeCB->currentText());
573
574     m_imageViewer = new ImageViewer(this);
575
576     m_model = new ApiTraceModel();
577     m_model->setApiTrace(m_trace);
578     m_proxyModel = new ApiTraceFilter();
579     m_proxyModel->setSourceModel(m_model);
580     m_ui.callView->setModel(m_proxyModel);
581     m_ui.callView->setItemDelegate(new ApiCallDelegate);
582     m_ui.callView->resizeColumnToContents(0);
583     m_ui.callView->header()->swapSections(0, 1);
584     m_ui.callView->setColumnWidth(1, 42);
585
586     m_progressBar = new QProgressBar();
587     m_progressBar->setRange(0, 0);
588     statusBar()->addPermanentWidget(m_progressBar);
589     m_progressBar->hide();
590
591     m_argsEditor = new ArgumentsEditor(this);
592     m_ui.argsEditorLayout->addWidget(m_argsEditor);
593
594     m_ui.detailsDock->hide();
595     m_ui.vertexDataDock->hide();
596     m_ui.stateDock->hide();
597     m_ui.argsEditorDock->hide();
598     setDockOptions(dockOptions() | QMainWindow::ForceTabbedDocks);
599
600     tabifyDockWidget(m_ui.stateDock, m_ui.vertexDataDock);
601     tabifyDockWidget(m_ui.vertexDataDock, m_ui.argsEditorDock);
602
603     m_ui.surfacesTreeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
604
605     m_ui.detailsWebView->page()->setLinkDelegationPolicy(
606         QWebPage::DelegateExternalLinks);
607
608     m_jumpWidget = new JumpWidget(this);
609     m_ui.centralLayout->addWidget(m_jumpWidget);
610     m_jumpWidget->hide();
611
612     m_searchWidget = new SearchWidget(this);
613     m_ui.centralLayout->addWidget(m_searchWidget);
614     m_searchWidget->hide();
615
616     m_traceProcess = new TraceProcess(this);
617
618     new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_G),
619                   this, SLOT(slotGoTo()));
620     new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_F),
621                   this, SLOT(slotSearch()));
622 }
623
624 void MainWindow::initConnections()
625 {
626     connect(m_trace, SIGNAL(startedLoadingTrace()),
627             this, SLOT(startedLoadingTrace()));
628     connect(m_trace, SIGNAL(finishedLoadingTrace()),
629             this, SLOT(finishedLoadingTrace()));
630
631     connect(m_retracer, SIGNAL(finished(const QString&)),
632             this, SLOT(replayFinished(const QString&)));
633     connect(m_retracer, SIGNAL(error(const QString&)),
634             this, SLOT(replayError(const QString&)));
635     connect(m_retracer, SIGNAL(foundState(const ApiTraceState&)),
636             this, SLOT(replayStateFound(const ApiTraceState&)));
637
638     connect(m_ui.vertexInterpretButton, SIGNAL(clicked()),
639             m_vdataInterpreter, SLOT(interpretData()));
640     connect(m_ui.vertexTypeCB, SIGNAL(currentIndexChanged(const QString&)),
641             m_vdataInterpreter, SLOT(setTypeFromString(const QString&)));
642     connect(m_ui.vertexStrideSB, SIGNAL(valueChanged(int)),
643             m_vdataInterpreter, SLOT(setStride(int)));
644     connect(m_ui.vertexComponentsSB, SIGNAL(valueChanged(int)),
645             m_vdataInterpreter, SLOT(setComponents(int)));
646     connect(m_ui.startingOffsetSB, SIGNAL(valueChanged(int)),
647             m_vdataInterpreter, SLOT(setStartingOffset(int)));
648
649
650     connect(m_ui.actionNew, SIGNAL(triggered()),
651             this, SLOT(createTrace()));
652     connect(m_ui.actionOpen, SIGNAL(triggered()),
653             this, SLOT(openTrace()));
654     connect(m_ui.actionQuit, SIGNAL(triggered()),
655             this, SLOT(close()));
656
657     connect(m_ui.actionReplay, SIGNAL(triggered()),
658             this, SLOT(replayStart()));
659     connect(m_ui.actionStop, SIGNAL(triggered()),
660             this, SLOT(replayStop()));
661     connect(m_ui.actionLookupState, SIGNAL(triggered()),
662             this, SLOT(lookupState()));
663     connect(m_ui.actionOptions, SIGNAL(triggered()),
664             this, SLOT(showSettings()));
665
666     connect(m_ui.callView, SIGNAL(activated(const QModelIndex &)),
667             this, SLOT(callItemSelected(const QModelIndex &)));
668
669     connect(m_ui.surfacesTreeWidget,
670             SIGNAL(customContextMenuRequested(const QPoint &)),
671             SLOT(showSurfacesMenu(const QPoint &)));
672     connect(m_ui.surfacesTreeWidget,
673             SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)),
674             SLOT(showSelectedSurface()));
675
676     connect(m_ui.detailsWebView, SIGNAL(linkClicked(const QUrl&)),
677             this, SLOT(openHelp(const QUrl&)));
678
679     connect(m_ui.nonDefaultsCB, SIGNAL(toggled(bool)),
680             this, SLOT(fillState(bool)));
681
682     connect(m_jumpWidget, SIGNAL(jumpTo(int)),
683             SLOT(slotJumpTo(int)));
684
685     connect(m_searchWidget,
686             SIGNAL(searchNext(const QString&, Qt::CaseSensitivity)),
687             SLOT(slotSearchNext(const QString&, Qt::CaseSensitivity)));
688     connect(m_searchWidget,
689             SIGNAL(searchPrev(const QString&, Qt::CaseSensitivity)),
690             SLOT(slotSearchPrev(const QString&, Qt::CaseSensitivity)));
691
692     connect(m_traceProcess, SIGNAL(tracedFile(const QString&)),
693             SLOT(createdTrace(const QString&)));
694     connect(m_traceProcess, SIGNAL(error(const QString&)),
695             SLOT(traceError(const QString&)));
696 }
697
698 void MainWindow::replayStateFound(const ApiTraceState &state)
699 {
700     m_stateEvent->setState(state);
701     m_model->stateSetOnEvent(m_stateEvent);
702     if (m_selectedEvent == m_stateEvent) {
703         fillStateForFrame();
704     } else {
705         m_ui.stateDock->hide();
706     }
707 }
708
709 void MainWindow::slotGoTo()
710 {
711     m_searchWidget->hide();
712     m_jumpWidget->show();
713 }
714
715 void MainWindow::slotJumpTo(int callNum)
716 {
717     QModelIndex index = m_proxyModel->callIndex(callNum);
718     if (index.isValid()) {
719         m_ui.callView->setCurrentIndex(index);
720     }
721 }
722
723 void MainWindow::createdTrace(const QString &path)
724 {
725     qDebug()<<"Done tracing "<<path;
726     newTraceFile(path);
727 }
728
729 void MainWindow::traceError(const QString &msg)
730 {
731     QMessageBox::warning(
732             this,
733             tr("Tracing Error"),
734             msg);
735 }
736
737 void MainWindow::slotSearch()
738 {
739     m_jumpWidget->hide();
740     m_searchWidget->show();
741 }
742
743 void MainWindow::slotSearchNext(const QString &str, Qt::CaseSensitivity sensitivity)
744 {
745     QModelIndex index = m_ui.callView->currentIndex();
746     ApiTraceEvent *event = 0;
747
748
749     if (!index.isValid()) {
750         index = m_proxyModel->index(0, 0, QModelIndex());
751         if (!index.isValid()) {
752             qDebug()<<"no currently valid index";
753             m_searchWidget->setFound(false);
754             return;
755         }
756     }
757
758     event = index.data(ApiTraceModel::EventRole).value<ApiTraceEvent*>();
759     ApiTraceCall *call = 0;
760
761     if (event->type() == ApiTraceCall::Call)
762         call = static_cast<ApiTraceCall*>(event);
763     else {
764         Q_ASSERT(event->type() == ApiTraceCall::Frame);
765         ApiTraceFrame *frame = static_cast<ApiTraceFrame*>(event);
766         call = frame->calls.value(0);
767     }
768
769     if (!call) {
770         m_searchWidget->setFound(false);
771         return;
772     }
773     const QList<ApiTraceCall*> &calls = m_trace->calls();
774     int callNum = calls.indexOf(call);
775
776     for (int i = callNum + 1; i < calls.count(); ++i) {
777         ApiTraceCall *testCall = calls[i];
778         QString txt = testCall->filterText();
779         if (txt.contains(str, sensitivity)) {
780             QModelIndex index = m_proxyModel->indexForCall(testCall);
781             /* if it's not valid it means that the proxy model has already
782              * filtered it out */
783             if (index.isValid()) {
784                 m_ui.callView->setCurrentIndex(index);
785                 m_searchWidget->setFound(true);
786                 return;
787             }
788         }
789     }
790     m_searchWidget->setFound(false);
791 }
792
793 void MainWindow::slotSearchPrev(const QString &str, Qt::CaseSensitivity sensitivity)
794 {
795     QModelIndex index = m_ui.callView->currentIndex();
796     ApiTraceEvent *event = 0;
797
798
799     if (!index.isValid()) {
800         index = m_proxyModel->index(0, 0, QModelIndex());
801         if (!index.isValid()) {
802             qDebug()<<"no currently valid index";
803             m_searchWidget->setFound(false);
804             return;
805         }
806     }
807
808     event = index.data(ApiTraceModel::EventRole).value<ApiTraceEvent*>();
809     ApiTraceCall *call = 0;
810
811     if (event->type() == ApiTraceCall::Call)
812         call = static_cast<ApiTraceCall*>(event);
813     else {
814         Q_ASSERT(event->type() == ApiTraceCall::Frame);
815         ApiTraceFrame *frame = static_cast<ApiTraceFrame*>(event);
816         call = frame->calls.value(0);
817     }
818
819     if (!call) {
820         m_searchWidget->setFound(false);
821         return;
822     }
823     const QList<ApiTraceCall*> &calls = m_trace->calls();
824     int callNum = calls.indexOf(call);
825
826     for (int i = callNum - 1; i >= 0; --i) {
827         ApiTraceCall *testCall = calls[i];
828         QString txt = testCall->filterText();
829         if (txt.contains(str, sensitivity)) {
830             QModelIndex index = m_proxyModel->indexForCall(testCall);
831             /* if it's not valid it means that the proxy model has already
832              * filtered it out */
833             if (index.isValid()) {
834                 m_ui.callView->setCurrentIndex(index);
835                 m_searchWidget->setFound(true);
836                 return;
837             }
838         }
839     }
840     m_searchWidget->setFound(false);
841 }
842
843 void MainWindow::fillState(bool nonDefaults)
844 {
845     if (nonDefaults) {
846         ApiTraceState defaultState = m_trace->defaultState();
847         if (defaultState.isEmpty()) {
848             m_ui.nonDefaultsCB->blockSignals(true);
849             m_ui.nonDefaultsCB->setChecked(false);
850             m_ui.nonDefaultsCB->blockSignals(false);
851             int ret = QMessageBox::question(
852                 this, tr("Empty Default State"),
853                 tr("The applcation needs to figure out the "
854                    "default state for the current trace. "
855                    "This only has to be done once and "
856                    "afterwards you will be able to enable "
857                    "displaying of non default state for all calls."
858                    "\nDo you want to lookup the default state now?"),
859                 QMessageBox::Yes | QMessageBox::No);
860             if (ret != QMessageBox::Yes)
861                 return;
862             ApiTraceFrame *firstFrame =
863                 m_trace->frameAt(0);
864             ApiTraceEvent *oldSelected = m_selectedEvent;
865             if (!firstFrame)
866                 return;
867             m_selectedEvent = firstFrame;
868             lookupState();
869             m_selectedEvent = oldSelected;
870         }
871     }
872     fillStateForFrame();
873 }
874
875 #include "mainwindow.moc"