]> git.cworth.org Git - apitrace/blob - gui/mainwindow.cpp
Add name of the file in the window bar.
[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 "retracer.h"
9 #include "settingsdialog.h"
10
11 #include <qjson/parser.h>
12
13 #include <QAction>
14 #include <QDebug>
15 #include <QDir>
16 #include <QFileDialog>
17 #include <QLineEdit>
18 #include <QMessageBox>
19 #include <QProgressBar>
20 #include <QToolBar>
21 #include <QWebView>
22
23
24 MainWindow::MainWindow()
25     : QMainWindow(),
26       m_selectedEvent(0),
27       m_stateEvent(0),
28       m_jsonParser(new QJson::Parser())
29 {
30     m_ui.setupUi(this);
31     m_ui.stateTreeWidget->sortByColumn(0, Qt::AscendingOrder);
32
33     m_trace = new ApiTrace();
34     connect(m_trace, SIGNAL(startedLoadingTrace()),
35             this, SLOT(startedLoadingTrace()));
36     connect(m_trace, SIGNAL(finishedLoadingTrace()),
37             this, SLOT(finishedLoadingTrace()));
38
39     m_retracer = new Retracer(this);
40     connect(m_retracer, SIGNAL(finished(const QByteArray&)),
41             this, SLOT(replayFinished(const QByteArray&)));
42     connect(m_retracer, SIGNAL(error(const QString&)),
43             this, SLOT(replayError(const QString&)));
44
45     m_model = new ApiTraceModel();
46     m_model->setApiTrace(m_trace);
47     m_proxyModel = new ApiTraceFilter();
48     m_proxyModel->setSourceModel(m_model);
49     m_ui.callView->setModel(m_proxyModel);
50     m_ui.callView->setItemDelegate(new ApiCallDelegate);
51     m_ui.callView->resizeColumnToContents(0);
52     m_ui.callView->header()->swapSections(0, 1);
53     m_ui.callView->setColumnWidth(1, 42);
54
55     QToolBar *toolBar = addToolBar(tr("Navigation"));
56     m_filterEdit = new QLineEdit(toolBar);
57     toolBar->addWidget(m_filterEdit);
58
59     m_progressBar = new QProgressBar();
60     m_progressBar->setRange(0, 0);
61     statusBar()->addPermanentWidget(m_progressBar);
62     m_progressBar->hide();
63
64     m_ui.detailsDock->hide();
65     m_ui.stateDock->hide();
66
67     connect(m_ui.actionOpen, SIGNAL(triggered()),
68             this, SLOT(openTrace()));
69     connect(m_ui.actionQuit, SIGNAL(triggered()),
70             this, SLOT(close()));
71
72     connect(m_ui.actionReplay, SIGNAL(triggered()),
73             this, SLOT(replayStart()));
74     connect(m_ui.actionStop, SIGNAL(triggered()),
75             this, SLOT(replayStop()));
76     connect(m_ui.actionLookupState, SIGNAL(triggered()),
77             this, SLOT(lookupState()));
78        connect(m_ui.actionOptions, SIGNAL(triggered()),
79             this, SLOT(showSettings()));
80
81     connect(m_ui.callView, SIGNAL(activated(const QModelIndex &)),
82             this, SLOT(callItemSelected(const QModelIndex &)));
83     connect(m_filterEdit, SIGNAL(returnPressed()),
84             this, SLOT(filterTrace()));
85 }
86
87 void MainWindow::openTrace()
88 {
89     QString fileName =
90         QFileDialog::getOpenFileName(
91             this,
92             tr("Open Trace"),
93             QDir::homePath(),
94             tr("Trace Files (*.trace)"));
95
96     qDebug()<< "File name : " <<fileName;
97
98     newTraceFile(fileName);
99 }
100
101 void MainWindow::loadTrace(const QString &fileName)
102 {
103     if (!QFile::exists(fileName)) {
104         QMessageBox::warning(this, tr("File Missing"),
105                              tr("File '%1' doesn't exist.").arg(fileName));
106         return;
107     }
108     qDebug()<< "Loading  : " <<fileName;
109
110     m_progressBar->setValue(0);
111     newTraceFile(fileName);
112 }
113
114 void MainWindow::callItemSelected(const QModelIndex &index)
115 {
116     ApiTraceEvent *event =
117         index.data(ApiTraceModel::EventRole).value<ApiTraceEvent*>();
118
119     if (event && event->type() == ApiTraceEvent::Call) {
120         ApiTraceCall *call = static_cast<ApiTraceCall*>(event);
121         m_ui.detailsWebView->setHtml(call->toHtml());
122         m_ui.detailsDock->show();
123         m_selectedEvent = call;
124     } else {
125         if (event && event->type() == ApiTraceEvent::Frame) {
126             m_selectedEvent = static_cast<ApiTraceFrame*>(event);
127         } else
128             m_selectedEvent = 0;
129         m_ui.detailsDock->hide();
130     }
131     if (m_selectedEvent && !m_selectedEvent->state().isEmpty()) {
132         fillStateForFrame();
133     } else
134         m_ui.stateDock->hide();
135 }
136
137 void MainWindow::filterTrace()
138 {
139     m_proxyModel->setFilterString(m_filterEdit->text());
140 }
141
142 void MainWindow::replayStart()
143 {
144     replayTrace(false);
145 }
146
147 void MainWindow::replayStop()
148 {
149     m_retracer->terminate();
150     m_ui.actionStop->setEnabled(false);
151     m_ui.actionReplay->setEnabled(true);
152     m_ui.actionLookupState->setEnabled(true);
153 }
154
155 void MainWindow::newTraceFile(const QString &fileName)
156 {
157     m_traceFileName = fileName;
158     m_trace->setFileName(fileName);
159
160     if (m_traceFileName.isEmpty()) {
161         m_ui.actionReplay->setEnabled(false);
162         m_ui.actionLookupState->setEnabled(false);
163         setWindowTitle(tr("QApiTrace"));
164     } else {
165         QFileInfo info(fileName);
166         m_ui.actionReplay->setEnabled(true);
167         m_ui.actionLookupState->setEnabled(true);
168         setWindowTitle(
169             tr("QApiTrace - %1").arg(info.fileName()));
170     }
171 }
172
173 void MainWindow::replayFinished(const QByteArray &output)
174 {
175     m_ui.actionStop->setEnabled(false);
176     m_ui.actionReplay->setEnabled(true);
177     m_ui.actionLookupState->setEnabled(true);
178
179     if (m_retracer->captureState()) {
180         bool ok = false;
181         QVariantMap parsedJson = m_jsonParser->parse(output, &ok).toMap();
182         parseState(parsedJson[QLatin1String("parameters")].toMap());
183     } else if (output.length() < 80) {
184         statusBar()->showMessage(output);
185     }
186     m_stateEvent = 0;
187 }
188
189 void MainWindow::replayError(const QString &message)
190 {
191     m_ui.actionStop->setEnabled(false);
192     m_ui.actionReplay->setEnabled(true);
193     m_ui.actionLookupState->setEnabled(true);
194     m_stateEvent = 0;
195
196     QMessageBox::warning(
197         this, tr("Replay Failed"), message);
198 }
199
200 void MainWindow::startedLoadingTrace()
201 {
202     Q_ASSERT(m_trace);
203     m_progressBar->show();
204     QFileInfo info(m_trace->fileName());
205     statusBar()->showMessage(
206         tr("Loading %1...").arg(info.fileName()));
207 }
208
209 void MainWindow::finishedLoadingTrace()
210 {
211     m_progressBar->hide();
212     if (!m_trace) {
213         return;
214     }
215     QFileInfo info(m_trace->fileName());
216     statusBar()->showMessage(
217         tr("Loaded %1").arg(info.fileName()), 3000);
218 }
219
220 void MainWindow::replayTrace(bool dumpState)
221 {
222     if (m_traceFileName.isEmpty())
223         return;
224
225     m_retracer->setFileName(m_traceFileName);
226     m_retracer->setCaptureState(dumpState);
227     if (m_retracer->captureState() && m_selectedEvent) {
228         int index = 0;
229         if (m_selectedEvent->type() == ApiTraceEvent::Call) {
230             index = static_cast<ApiTraceCall*>(m_selectedEvent)->index;
231         } else if (m_selectedEvent->type() == ApiTraceEvent::Frame) {
232             ApiTraceFrame *frame = static_cast<ApiTraceFrame*>(m_selectedEvent);
233             if (frame->calls.isEmpty()) {
234                 //XXX i guess we could still get the current state
235                 qDebug()<<"tried to get a state for an empty frame";
236                 return;
237             }
238             index = frame->calls.first()->index;
239         } else {
240             qDebug()<<"Unknown event type";
241             return;
242         }
243         m_retracer->setCaptureAtCallNumber(index);
244     }
245     m_retracer->start();
246
247     m_ui.actionStop->setEnabled(true);
248 }
249
250 void MainWindow::lookupState()
251 {
252     if (!m_selectedEvent) {
253         QMessageBox::warning(
254             this, tr("Unknown Event"),
255             tr("To inspect the state select an event in the event list."));
256         return;
257     }
258     m_stateEvent = m_selectedEvent;
259     replayTrace(true);
260 }
261
262 MainWindow::~MainWindow()
263 {
264     delete m_jsonParser;
265 }
266
267 void MainWindow::parseState(const QVariantMap &params)
268 {
269     QVariantMap::const_iterator itr;
270
271     m_stateEvent->setState(params);
272     m_model->stateSetOnEvent(m_stateEvent);
273     if (m_selectedEvent == m_stateEvent) {
274         fillStateForFrame();
275     } else {
276         m_ui.stateDock->hide();
277     }
278 }
279
280 static void
281 variantToString(const QVariant &var, QString &str)
282 {
283     if (var.type() == QVariant::List) {
284         QVariantList lst = var.toList();
285         str += QLatin1String("[");
286         for (int i = 0; i < lst.count(); ++i) {
287             QVariant val = lst[i];
288             variantToString(val, str);
289             if (i < lst.count() - 1)
290                 str += QLatin1String(", ");
291         }
292         str += QLatin1String("]");
293     } else if (var.type() == QVariant::Map) {
294         Q_ASSERT(!"unsupported state type");
295     } else if (var.type() == QVariant::Hash) {
296         Q_ASSERT(!"unsupported state type");
297     } else {
298         str += var.toString();
299     }
300 }
301
302 void MainWindow::fillStateForFrame()
303 {
304     QVariantMap::const_iterator itr;
305     QVariantMap params;
306
307     if (!m_selectedEvent || m_selectedEvent->state().isEmpty())
308         return;
309
310     m_ui.stateTreeWidget->clear();
311     params = m_selectedEvent->state();
312     QList<QTreeWidgetItem *> items;
313     for (itr = params.constBegin(); itr != params.constEnd(); ++itr) {
314         QString key = itr.key();
315         QString val;
316
317         variantToString(itr.value(), val);
318         //qDebug()<<"key = "<<key;
319         //qDebug()<<"val = "<<val;
320         QStringList lst;
321         lst += key;
322         lst += val;
323         items.append(new QTreeWidgetItem((QTreeWidget*)0, lst));
324     }
325     m_ui.stateTreeWidget->insertTopLevelItems(0, items);
326     m_ui.stateDock->show();
327 }
328
329 void MainWindow::showSettings()
330 {
331     SettingsDialog dialog;
332     dialog.setFilterOptions(m_proxyModel->filterOptions());
333
334     if (dialog.exec() == QDialog::Accepted) {
335         m_proxyModel->setFilterOptions(dialog.filterOptions());
336     }
337 }
338
339 #include "mainwindow.moc"