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