blob: 6ba7f408ef48e2c4999e909f078387affda8cdc0 [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);
32
Zack Rusinf6667d12011-03-30 11:03:37 -040033 m_trace = new ApiTrace();
Zack Rusinde4ea412011-03-30 11:30:08 -040034 connect(m_trace, SIGNAL(startedLoadingTrace()),
35 this, SLOT(startedLoadingTrace()));
36 connect(m_trace, SIGNAL(finishedLoadingTrace()),
37 this, SLOT(finishedLoadingTrace()));
Zack Rusinf6667d12011-03-30 11:03:37 -040038
Zack Rusin601e8372011-03-24 22:23:21 -040039 m_model = new ApiTraceModel();
Zack Rusinf6667d12011-03-30 11:03:37 -040040 m_model->setApiTrace(m_trace);
Zack Rusin91065372011-03-26 01:54:10 -040041 m_proxyModel = new ApiTraceFilter();
42 m_proxyModel->setSourceModel(m_model);
Zack Rusin96130ac2011-03-27 01:48:36 -040043 m_ui.callView->setModel(m_proxyModel);
Zack Rusin18eade52011-03-26 14:23:35 -040044 m_ui.callView->setItemDelegate(new ApiCallDelegate);
Zack Rusin601e8372011-03-24 22:23:21 -040045 for (int column = 0; column < m_model->columnCount(); ++column)
46 m_ui.callView->resizeColumnToContents(column);
47
Zack Rusinea295452011-03-27 02:22:13 -040048 QToolBar *toolBar = addToolBar(tr("Navigation"));
49 m_filterEdit = new QLineEdit(toolBar);
50 toolBar->addWidget(m_filterEdit);
51
Zack Rusinde4ea412011-03-30 11:30:08 -040052 m_progressBar = new QProgressBar();
53 m_progressBar->setRange(0, 0);
54 statusBar()->addPermanentWidget(m_progressBar);
55 m_progressBar->hide();
56
Zack Rusin96130ac2011-03-27 01:48:36 -040057 m_ui.detailsDock->hide();
Zack Rusin11f7e632011-03-30 22:47:51 -040058 m_ui.stateDock->hide();
Zack Rusin96130ac2011-03-27 01:48:36 -040059
Zack Rusin601e8372011-03-24 22:23:21 -040060 connect(m_ui.actionOpen, SIGNAL(triggered()),
61 this, SLOT(openTrace()));
Zack Rusin27cb2c42011-03-27 23:53:36 -040062 connect(m_ui.actionQuit, SIGNAL(triggered()),
63 this, SLOT(close()));
64
65 connect(m_ui.actionReplay, SIGNAL(triggered()),
66 this, SLOT(replayStart()));
67 connect(m_ui.actionStop, SIGNAL(triggered()),
68 this, SLOT(replayStop()));
Zack Rusin2caa06d2011-03-30 18:30:20 -040069 connect(m_ui.actionLookupState, SIGNAL(triggered()),
70 this, SLOT(lookupState()));
Zack Rusin27cb2c42011-03-27 23:53:36 -040071
Zack Rusin96130ac2011-03-27 01:48:36 -040072 connect(m_ui.callView, SIGNAL(activated(const QModelIndex &)),
73 this, SLOT(callItemSelected(const QModelIndex &)));
Zack Rusinea295452011-03-27 02:22:13 -040074 connect(m_filterEdit, SIGNAL(returnPressed()),
75 this, SLOT(filterTrace()));
Zack Rusin601e8372011-03-24 22:23:21 -040076}
77
78void MainWindow::openTrace()
79{
80 QString fileName =
81 QFileDialog::getOpenFileName(
82 this,
83 tr("Open Trace"),
84 QDir::homePath(),
85 tr("Trace Files (*.trace)"));
86
87 qDebug()<< "File name : " <<fileName;
88
Zack Rusin27cb2c42011-03-27 23:53:36 -040089 newTraceFile(fileName);
Zack Rusin601e8372011-03-24 22:23:21 -040090}
91
92void MainWindow::loadTrace(const QString &fileName)
93{
Zack Rusin27cb2c42011-03-27 23:53:36 -040094 if (!QFile::exists(fileName)) {
95 QMessageBox::warning(this, tr("File Missing"),
96 tr("File '%1' doesn't exist.").arg(fileName));
97 return;
98 }
Zack Rusin601e8372011-03-24 22:23:21 -040099 qDebug()<< "Loading : " <<fileName;
100
Zack Rusinde4ea412011-03-30 11:30:08 -0400101 m_progressBar->setValue(0);
Zack Rusin27cb2c42011-03-27 23:53:36 -0400102 newTraceFile(fileName);
Zack Rusin601e8372011-03-24 22:23:21 -0400103}
104
Zack Rusin96130ac2011-03-27 01:48:36 -0400105void MainWindow::callItemSelected(const QModelIndex &index)
106{
107 ApiTraceCall *call = index.data().value<ApiTraceCall*>();
108 if (call) {
Zack Rusin27cb2c42011-03-27 23:53:36 -0400109 m_ui.detailsWebView->setHtml(call->toHtml());
Zack Rusin96130ac2011-03-27 01:48:36 -0400110 m_ui.detailsDock->show();
Zack Rusin581e3ff2011-03-31 23:58:07 -0400111 m_selectedEvent = call;
Zack Rusin96130ac2011-03-27 01:48:36 -0400112 } else {
Zack Rusin581e3ff2011-03-31 23:58:07 -0400113 m_selectedEvent = index.data().value<ApiTraceFrame*>();
Zack Rusin96130ac2011-03-27 01:48:36 -0400114 m_ui.detailsDock->hide();
115 }
Zack Rusin581e3ff2011-03-31 23:58:07 -0400116 if (m_selectedEvent && !m_selectedEvent->state().isEmpty()) {
Zack Rusin11f7e632011-03-30 22:47:51 -0400117 fillStateForFrame();
118 } else
119 m_ui.stateDock->hide();
Zack Rusin96130ac2011-03-27 01:48:36 -0400120}
121
Zack Rusinea295452011-03-27 02:22:13 -0400122void MainWindow::filterTrace()
123{
124 m_proxyModel->setFilterString(m_filterEdit->text());
125}
126
Zack Rusin27cb2c42011-03-27 23:53:36 -0400127void MainWindow::replayStart()
128{
Zack Rusin2caa06d2011-03-30 18:30:20 -0400129 replayTrace(false);
Zack Rusin27cb2c42011-03-27 23:53:36 -0400130}
131
132void MainWindow::replayStop()
133{
134 if (m_replayProcess) {
135 m_replayProcess->kill();
136
137 m_ui.actionStop->setEnabled(false);
138 m_ui.actionReplay->setEnabled(true);
Zack Rusin2caa06d2011-03-30 18:30:20 -0400139 m_ui.actionLookupState->setEnabled(true);
Zack Rusin27cb2c42011-03-27 23:53:36 -0400140 }
141}
142
143void MainWindow::newTraceFile(const QString &fileName)
144{
145 m_traceFileName = fileName;
Zack Rusinf6667d12011-03-30 11:03:37 -0400146 m_trace->setFileName(fileName);
Zack Rusin27cb2c42011-03-27 23:53:36 -0400147
148 if (m_traceFileName.isEmpty()) {
149 m_ui.actionReplay->setEnabled(false);
Zack Rusin2caa06d2011-03-30 18:30:20 -0400150 m_ui.actionLookupState->setEnabled(false);
Zack Rusin27cb2c42011-03-27 23:53:36 -0400151 } else {
152 m_ui.actionReplay->setEnabled(true);
Zack Rusin2caa06d2011-03-30 18:30:20 -0400153 m_ui.actionLookupState->setEnabled(true);
Zack Rusin27cb2c42011-03-27 23:53:36 -0400154 }
155}
156
157void MainWindow::replayFinished()
158{
159 m_ui.actionStop->setEnabled(false);
160 m_ui.actionReplay->setEnabled(true);
Zack Rusin2caa06d2011-03-30 18:30:20 -0400161 m_ui.actionLookupState->setEnabled(true);
Zack Rusin27cb2c42011-03-27 23:53:36 -0400162
Zack Rusin2caa06d2011-03-30 18:30:20 -0400163 QByteArray output = m_replayProcess->readAllStandardOutput();
Zack Rusin27cb2c42011-03-27 23:53:36 -0400164
Zack Rusin11f7e632011-03-30 22:47:51 -0400165#if 0
Zack Rusin27cb2c42011-03-27 23:53:36 -0400166 qDebug()<<"Process finished = ";
167 qDebug()<<"\terr = "<<m_replayProcess->readAllStandardError();
168 qDebug()<<"\tout = "<<output;
169#endif
170
Zack Rusin2caa06d2011-03-30 18:30:20 -0400171 if (m_findingState) {
Zack Rusin11f7e632011-03-30 22:47:51 -0400172 bool ok = false;
173 QVariantMap parsedJson = m_jsonParser->parse(output, &ok).toMap();
174 parseState(parsedJson[QLatin1String("parameters")].toMap());
Zack Rusin2caa06d2011-03-30 18:30:20 -0400175 } else if (output.length() < 80) {
Zack Rusin27cb2c42011-03-27 23:53:36 -0400176 statusBar()->showMessage(output);
177 }
Zack Rusin581e3ff2011-03-31 23:58:07 -0400178 m_stateEvent = 0;
Zack Rusin11f7e632011-03-30 22:47:51 -0400179 m_findingState = false;
Zack Rusin27cb2c42011-03-27 23:53:36 -0400180}
181
182void MainWindow::replayError(QProcess::ProcessError err)
183{
184 m_ui.actionStop->setEnabled(false);
185 m_ui.actionReplay->setEnabled(true);
Zack Rusin2caa06d2011-03-30 18:30:20 -0400186 m_ui.actionLookupState->setEnabled(true);
187 m_findingState = false;
Zack Rusin581e3ff2011-03-31 23:58:07 -0400188 m_stateEvent = 0;
Zack Rusin27cb2c42011-03-27 23:53:36 -0400189
190 qDebug()<<"Process error = "<<err;
191 qDebug()<<"\terr = "<<m_replayProcess->readAllStandardError();
192 qDebug()<<"\tout = "<<m_replayProcess->readAllStandardOutput();
193 QMessageBox::warning(
194 this, tr("Replay Failed"),
195 tr("Couldn't execute the replay file '%1'").arg(m_traceFileName));
196}
197
Zack Rusinde4ea412011-03-30 11:30:08 -0400198void MainWindow::startedLoadingTrace()
199{
200 Q_ASSERT(m_trace);
201 m_progressBar->show();
202 QFileInfo info(m_trace->fileName());
203 statusBar()->showMessage(
204 tr("Loading %1...").arg(info.fileName()));
205}
206
207void MainWindow::finishedLoadingTrace()
208{
209 m_progressBar->hide();
210 if (!m_trace) {
211 return;
212 }
213 QFileInfo info(m_trace->fileName());
214 statusBar()->showMessage(
215 tr("Loaded %1").arg(info.fileName()), 3000);
216}
217
Zack Rusin2caa06d2011-03-30 18:30:20 -0400218void MainWindow::replayTrace(bool dumpState)
219{
220 if (!m_replayProcess) {
221#ifdef Q_OS_WIN
222 QString format = QLatin1String("%1;");
223#else
224 QString format = QLatin1String("%1:");
225#endif
226 QString buildPath = format.arg(BUILD_DIR);
227 QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
228 env.insert("PATH", buildPath + env.value("PATH"));
229
230 qputenv("PATH", env.value("PATH").toLatin1());
231
232 m_replayProcess = new QProcess(this);
233 m_replayProcess->setProcessEnvironment(env);
234
235 connect(m_replayProcess, SIGNAL(finished(int, QProcess::ExitStatus)),
236 this, SLOT(replayFinished()));
237 connect(m_replayProcess, SIGNAL(error(QProcess::ProcessError)),
238 this, SLOT(replayError(QProcess::ProcessError)));
239 }
240
241 if (m_traceFileName.isEmpty())
242 return;
243
244 QStringList arguments;
245 if (dumpState &&
Zack Rusin581e3ff2011-03-31 23:58:07 -0400246 m_selectedEvent) {
247 int index = 0;
248 if (m_selectedEvent->type() == ApiTraceEvent::Call) {
249 index = static_cast<ApiTraceCall*>(m_selectedEvent)->index;
250 } else if (m_selectedEvent->type() == ApiTraceEvent::Frame) {
251 ApiTraceFrame *frame = static_cast<ApiTraceFrame*>(m_selectedEvent);
252 if (frame->calls.isEmpty()) {
253 //XXX i guess we could still get the current state
254 qDebug()<<"tried to get a state for an empty frame";
255 return;
256 }
257 index = frame->calls.first()->index;
258 } else {
259 qDebug()<<"Unknown event type";
260 return;
261 }
Zack Rusin2caa06d2011-03-30 18:30:20 -0400262 arguments << QLatin1String("-D");
Zack Rusin581e3ff2011-03-31 23:58:07 -0400263 arguments << QString::number(index);
Zack Rusin2caa06d2011-03-30 18:30:20 -0400264 }
265 arguments << m_traceFileName;
266
267 m_replayProcess->start(QLatin1String("glretrace"),
268 arguments);
269
270 m_ui.actionStop->setEnabled(true);
271}
272
273void MainWindow::lookupState()
274{
Zack Rusin581e3ff2011-03-31 23:58:07 -0400275 if (!m_selectedEvent) {
Zack Rusin2caa06d2011-03-30 18:30:20 -0400276 QMessageBox::warning(
Zack Rusin581e3ff2011-03-31 23:58:07 -0400277 this, tr("Unknown Event"),
278 tr("To inspect the state select an event in the event list."));
Zack Rusin2caa06d2011-03-30 18:30:20 -0400279 return;
280 }
Zack Rusin581e3ff2011-03-31 23:58:07 -0400281 m_stateEvent = m_selectedEvent;
Zack Rusin2caa06d2011-03-30 18:30:20 -0400282 m_findingState = true;
283 replayTrace(true);
284}
285
Zack Rusin11f7e632011-03-30 22:47:51 -0400286MainWindow::~MainWindow()
287{
288 delete m_jsonParser;
289}
290
291void MainWindow::parseState(const QVariantMap &params)
292{
293 QVariantMap::const_iterator itr;
294
Zack Rusin581e3ff2011-03-31 23:58:07 -0400295 m_stateEvent->setState(params);
296 if (m_selectedEvent == m_stateEvent) {
Zack Rusin11f7e632011-03-30 22:47:51 -0400297 fillStateForFrame();
298 } else {
299 m_ui.stateDock->hide();
300 }
301}
302
303static void
304variantToString(const QVariant &var, QString &str)
305{
306 if (var.type() == QVariant::List) {
307 QVariantList lst = var.toList();
308 str += QLatin1String("[");
309 for (int i = 0; i < lst.count(); ++i) {
310 QVariant val = lst[i];
311 variantToString(val, str);
312 if (i < lst.count() - 1)
313 str += QLatin1String(", ");
314 }
315 str += QLatin1String("]");
316 } else if (var.type() == QVariant::Map) {
317 Q_ASSERT(!"unsupported state type");
318 } else if (var.type() == QVariant::Hash) {
319 Q_ASSERT(!"unsupported state type");
320 } else {
321 str += var.toString();
322 }
323}
324
325void MainWindow::fillStateForFrame()
326{
327 QVariantMap::const_iterator itr;
328 QVariantMap params;
329
Zack Rusin581e3ff2011-03-31 23:58:07 -0400330 if (!m_selectedEvent || m_selectedEvent->state().isEmpty())
Zack Rusin11f7e632011-03-30 22:47:51 -0400331 return;
332
333 m_ui.stateTreeWidget->clear();
Zack Rusin581e3ff2011-03-31 23:58:07 -0400334 params = m_selectedEvent->state();
Zack Rusin11f7e632011-03-30 22:47:51 -0400335 QList<QTreeWidgetItem *> items;
336 for (itr = params.constBegin(); itr != params.constEnd(); ++itr) {
337 QString key = itr.key();
338 QString val;
339
340 variantToString(itr.value(), val);
341 //qDebug()<<"key = "<<key;
342 //qDebug()<<"val = "<<val;
343 QStringList lst;
344 lst += key;
345 lst += val;
346 items.append(new QTreeWidgetItem((QTreeWidget*)0, lst));
347 }
348 m_ui.stateTreeWidget->insertTopLevelItems(0, items);
349 m_ui.stateDock->show();
350}
351
Zack Rusin601e8372011-03-24 22:23:21 -0400352#include "mainwindow.moc"