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