blob: 12d46efa78403f2c8202df13d4c1500f368d06f7 [file] [log] [blame]
Zack Rusin601e8372011-03-24 22:23:21 -04001#include "mainwindow.h"
2
Zack Rusinf6667d12011-03-30 11:03:37 -04003#include "apitrace.h"
Zack Rusin96130ac2011-03-27 01:48:36 -04004#include "apitracecall.h"
Zack Rusin18eade52011-03-26 14:23:35 -04005#include "apicalldelegate.h"
Zack Rusin601e8372011-03-24 22:23:21 -04006#include "apitracemodel.h"
Zack Rusin91065372011-03-26 01:54:10 -04007#include "apitracefilter.h"
Zack Rusin601e8372011-03-24 22:23:21 -04008
Zack Rusine8685f62011-03-30 20:14:01 -04009#include <qjson/parser.h>
10
Zack Rusin601e8372011-03-24 22:23:21 -040011#include <QAction>
12#include <QDebug>
13#include <QDir>
14#include <QFileDialog>
Zack Rusin27cb2c42011-03-27 23:53:36 -040015#include <QLineEdit>
16#include <QMessageBox>
17#include <QProcess>
Zack Rusinde4ea412011-03-30 11:30:08 -040018#include <QProgressBar>
Zack Rusinea295452011-03-27 02:22:13 -040019#include <QToolBar>
Zack Rusin96130ac2011-03-27 01:48:36 -040020#include <QWebView>
Zack Rusin601e8372011-03-24 22:23:21 -040021
22
23MainWindow::MainWindow()
Zack Rusin27cb2c42011-03-27 23:53:36 -040024 : QMainWindow(),
Zack Rusin2caa06d2011-03-30 18:30:20 -040025 m_replayProcess(0),
Zack Rusin581e3ff2011-03-31 23:58:07 -040026 m_selectedEvent(0),
27 m_stateEvent(0),
Zack Rusin11f7e632011-03-30 22:47:51 -040028 m_findingState(false),
29 m_jsonParser(new QJson::Parser())
Zack Rusin601e8372011-03-24 22:23:21 -040030{
31 m_ui.setupUi(this);
José Fonsecaf2c40fb2011-04-01 10:05:53 +010032 m_ui.stateTreeWidget->sortByColumn(0, Qt::AscendingOrder);
Zack Rusin601e8372011-03-24 22:23:21 -040033
Zack Rusinf6667d12011-03-30 11:03:37 -040034 m_trace = new ApiTrace();
Zack Rusinde4ea412011-03-30 11:30:08 -040035 connect(m_trace, SIGNAL(startedLoadingTrace()),
36 this, SLOT(startedLoadingTrace()));
37 connect(m_trace, SIGNAL(finishedLoadingTrace()),
38 this, SLOT(finishedLoadingTrace()));
Zack Rusinf6667d12011-03-30 11:03:37 -040039
Zack Rusin601e8372011-03-24 22:23:21 -040040 m_model = new ApiTraceModel();
Zack Rusinf6667d12011-03-30 11:03:37 -040041 m_model->setApiTrace(m_trace);
Zack Rusin91065372011-03-26 01:54:10 -040042 m_proxyModel = new ApiTraceFilter();
43 m_proxyModel->setSourceModel(m_model);
Zack Rusin96130ac2011-03-27 01:48:36 -040044 m_ui.callView->setModel(m_proxyModel);
Zack Rusin18eade52011-03-26 14:23:35 -040045 m_ui.callView->setItemDelegate(new ApiCallDelegate);
Zack Rusin601e8372011-03-24 22:23:21 -040046 for (int column = 0; column < m_model->columnCount(); ++column)
47 m_ui.callView->resizeColumnToContents(column);
48
Zack Rusinea295452011-03-27 02:22:13 -040049 QToolBar *toolBar = addToolBar(tr("Navigation"));
50 m_filterEdit = new QLineEdit(toolBar);
51 toolBar->addWidget(m_filterEdit);
52
Zack Rusinde4ea412011-03-30 11:30:08 -040053 m_progressBar = new QProgressBar();
54 m_progressBar->setRange(0, 0);
55 statusBar()->addPermanentWidget(m_progressBar);
56 m_progressBar->hide();
57
Zack Rusin96130ac2011-03-27 01:48:36 -040058 m_ui.detailsDock->hide();
Zack Rusin11f7e632011-03-30 22:47:51 -040059 m_ui.stateDock->hide();
Zack Rusin96130ac2011-03-27 01:48:36 -040060
Zack Rusin601e8372011-03-24 22:23:21 -040061 connect(m_ui.actionOpen, SIGNAL(triggered()),
62 this, SLOT(openTrace()));
Zack Rusin27cb2c42011-03-27 23:53:36 -040063 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()));
Zack Rusin2caa06d2011-03-30 18:30:20 -040070 connect(m_ui.actionLookupState, SIGNAL(triggered()),
71 this, SLOT(lookupState()));
Zack Rusin27cb2c42011-03-27 23:53:36 -040072
Zack Rusin96130ac2011-03-27 01:48:36 -040073 connect(m_ui.callView, SIGNAL(activated(const QModelIndex &)),
74 this, SLOT(callItemSelected(const QModelIndex &)));
Zack Rusinea295452011-03-27 02:22:13 -040075 connect(m_filterEdit, SIGNAL(returnPressed()),
76 this, SLOT(filterTrace()));
Zack Rusin601e8372011-03-24 22:23:21 -040077}
78
79void 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
Zack Rusin27cb2c42011-03-27 23:53:36 -040090 newTraceFile(fileName);
Zack Rusin601e8372011-03-24 22:23:21 -040091}
92
93void MainWindow::loadTrace(const QString &fileName)
94{
Zack Rusin27cb2c42011-03-27 23:53:36 -040095 if (!QFile::exists(fileName)) {
96 QMessageBox::warning(this, tr("File Missing"),
97 tr("File '%1' doesn't exist.").arg(fileName));
98 return;
99 }
Zack Rusin601e8372011-03-24 22:23:21 -0400100 qDebug()<< "Loading : " <<fileName;
101
Zack Rusinde4ea412011-03-30 11:30:08 -0400102 m_progressBar->setValue(0);
Zack Rusin27cb2c42011-03-27 23:53:36 -0400103 newTraceFile(fileName);
Zack Rusin601e8372011-03-24 22:23:21 -0400104}
105
Zack Rusin96130ac2011-03-27 01:48:36 -0400106void MainWindow::callItemSelected(const QModelIndex &index)
107{
108 ApiTraceCall *call = index.data().value<ApiTraceCall*>();
109 if (call) {
Zack Rusin27cb2c42011-03-27 23:53:36 -0400110 m_ui.detailsWebView->setHtml(call->toHtml());
Zack Rusin96130ac2011-03-27 01:48:36 -0400111 m_ui.detailsDock->show();
Zack Rusin581e3ff2011-03-31 23:58:07 -0400112 m_selectedEvent = call;
Zack Rusin96130ac2011-03-27 01:48:36 -0400113 } else {
Zack Rusin581e3ff2011-03-31 23:58:07 -0400114 m_selectedEvent = index.data().value<ApiTraceFrame*>();
Zack Rusin96130ac2011-03-27 01:48:36 -0400115 m_ui.detailsDock->hide();
116 }
Zack Rusin581e3ff2011-03-31 23:58:07 -0400117 if (m_selectedEvent && !m_selectedEvent->state().isEmpty()) {
Zack Rusin11f7e632011-03-30 22:47:51 -0400118 fillStateForFrame();
119 } else
120 m_ui.stateDock->hide();
Zack Rusin96130ac2011-03-27 01:48:36 -0400121}
122
Zack Rusinea295452011-03-27 02:22:13 -0400123void MainWindow::filterTrace()
124{
125 m_proxyModel->setFilterString(m_filterEdit->text());
126}
127
Zack Rusin27cb2c42011-03-27 23:53:36 -0400128void MainWindow::replayStart()
129{
Zack Rusin2caa06d2011-03-30 18:30:20 -0400130 replayTrace(false);
Zack Rusin27cb2c42011-03-27 23:53:36 -0400131}
132
133void MainWindow::replayStop()
134{
135 if (m_replayProcess) {
136 m_replayProcess->kill();
137
138 m_ui.actionStop->setEnabled(false);
139 m_ui.actionReplay->setEnabled(true);
Zack Rusin2caa06d2011-03-30 18:30:20 -0400140 m_ui.actionLookupState->setEnabled(true);
Zack Rusin27cb2c42011-03-27 23:53:36 -0400141 }
142}
143
144void MainWindow::newTraceFile(const QString &fileName)
145{
146 m_traceFileName = fileName;
Zack Rusinf6667d12011-03-30 11:03:37 -0400147 m_trace->setFileName(fileName);
Zack Rusin27cb2c42011-03-27 23:53:36 -0400148
149 if (m_traceFileName.isEmpty()) {
150 m_ui.actionReplay->setEnabled(false);
Zack Rusin2caa06d2011-03-30 18:30:20 -0400151 m_ui.actionLookupState->setEnabled(false);
Zack Rusin27cb2c42011-03-27 23:53:36 -0400152 } else {
153 m_ui.actionReplay->setEnabled(true);
Zack Rusin2caa06d2011-03-30 18:30:20 -0400154 m_ui.actionLookupState->setEnabled(true);
Zack Rusin27cb2c42011-03-27 23:53:36 -0400155 }
156}
157
158void MainWindow::replayFinished()
159{
160 m_ui.actionStop->setEnabled(false);
161 m_ui.actionReplay->setEnabled(true);
Zack Rusin2caa06d2011-03-30 18:30:20 -0400162 m_ui.actionLookupState->setEnabled(true);
Zack Rusin27cb2c42011-03-27 23:53:36 -0400163
Zack Rusin2caa06d2011-03-30 18:30:20 -0400164 QByteArray output = m_replayProcess->readAllStandardOutput();
Zack Rusin27cb2c42011-03-27 23:53:36 -0400165
Zack Rusin11f7e632011-03-30 22:47:51 -0400166#if 0
Zack Rusin27cb2c42011-03-27 23:53:36 -0400167 qDebug()<<"Process finished = ";
168 qDebug()<<"\terr = "<<m_replayProcess->readAllStandardError();
169 qDebug()<<"\tout = "<<output;
170#endif
171
Zack Rusin2caa06d2011-03-30 18:30:20 -0400172 if (m_findingState) {
Zack Rusin11f7e632011-03-30 22:47:51 -0400173 bool ok = false;
174 QVariantMap parsedJson = m_jsonParser->parse(output, &ok).toMap();
175 parseState(parsedJson[QLatin1String("parameters")].toMap());
Zack Rusin2caa06d2011-03-30 18:30:20 -0400176 } else if (output.length() < 80) {
Zack Rusin27cb2c42011-03-27 23:53:36 -0400177 statusBar()->showMessage(output);
178 }
Zack Rusin581e3ff2011-03-31 23:58:07 -0400179 m_stateEvent = 0;
Zack Rusin11f7e632011-03-30 22:47:51 -0400180 m_findingState = false;
Zack Rusin27cb2c42011-03-27 23:53:36 -0400181}
182
183void MainWindow::replayError(QProcess::ProcessError err)
184{
185 m_ui.actionStop->setEnabled(false);
186 m_ui.actionReplay->setEnabled(true);
Zack Rusin2caa06d2011-03-30 18:30:20 -0400187 m_ui.actionLookupState->setEnabled(true);
188 m_findingState = false;
Zack Rusin581e3ff2011-03-31 23:58:07 -0400189 m_stateEvent = 0;
Zack Rusin27cb2c42011-03-27 23:53:36 -0400190
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
Zack Rusinde4ea412011-03-30 11:30:08 -0400199void 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
208void 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
Zack Rusin2caa06d2011-03-30 18:30:20 -0400219void 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 &&
Zack Rusin581e3ff2011-03-31 23:58:07 -0400247 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 }
Zack Rusin2caa06d2011-03-30 18:30:20 -0400263 arguments << QLatin1String("-D");
Zack Rusin581e3ff2011-03-31 23:58:07 -0400264 arguments << QString::number(index);
Zack Rusin2caa06d2011-03-30 18:30:20 -0400265 }
266 arguments << m_traceFileName;
267
268 m_replayProcess->start(QLatin1String("glretrace"),
269 arguments);
270
271 m_ui.actionStop->setEnabled(true);
272}
273
274void MainWindow::lookupState()
275{
Zack Rusin581e3ff2011-03-31 23:58:07 -0400276 if (!m_selectedEvent) {
Zack Rusin2caa06d2011-03-30 18:30:20 -0400277 QMessageBox::warning(
Zack Rusin581e3ff2011-03-31 23:58:07 -0400278 this, tr("Unknown Event"),
279 tr("To inspect the state select an event in the event list."));
Zack Rusin2caa06d2011-03-30 18:30:20 -0400280 return;
281 }
Zack Rusin581e3ff2011-03-31 23:58:07 -0400282 m_stateEvent = m_selectedEvent;
Zack Rusin2caa06d2011-03-30 18:30:20 -0400283 m_findingState = true;
284 replayTrace(true);
285}
286
Zack Rusin11f7e632011-03-30 22:47:51 -0400287MainWindow::~MainWindow()
288{
289 delete m_jsonParser;
290}
291
292void MainWindow::parseState(const QVariantMap &params)
293{
294 QVariantMap::const_iterator itr;
295
Zack Rusin581e3ff2011-03-31 23:58:07 -0400296 m_stateEvent->setState(params);
297 if (m_selectedEvent == m_stateEvent) {
Zack Rusin11f7e632011-03-30 22:47:51 -0400298 fillStateForFrame();
299 } else {
300 m_ui.stateDock->hide();
301 }
302}
303
304static void
305variantToString(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
326void MainWindow::fillStateForFrame()
327{
328 QVariantMap::const_iterator itr;
329 QVariantMap params;
330
Zack Rusin581e3ff2011-03-31 23:58:07 -0400331 if (!m_selectedEvent || m_selectedEvent->state().isEmpty())
Zack Rusin11f7e632011-03-30 22:47:51 -0400332 return;
333
334 m_ui.stateTreeWidget->clear();
Zack Rusin581e3ff2011-03-31 23:58:07 -0400335 params = m_selectedEvent->state();
Zack Rusin11f7e632011-03-30 22:47:51 -0400336 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
Zack Rusin601e8372011-03-24 22:23:21 -0400353#include "mainwindow.moc"