#include "apitracemodel.h"
#include "apitracefilter.h"
#include "imageviewer.h"
+#include "jumpwidget.h"
#include "retracer.h"
+#include "searchwidget.h"
#include "settingsdialog.h"
#include "shaderssourcewidget.h"
#include "tracedialog.h"
+#include "traceprocess.h"
#include "ui_retracerdialog.h"
#include "vertexdatainterpreter.h"
#include <QLineEdit>
#include <QMessageBox>
#include <QProgressBar>
+#include <QShortcut>
#include <QToolBar>
#include <QUrl>
#include <QVBoxLayout>
{
TraceDialog dialog;
+ if (!m_traceProcess->canTrace()) {
+ QMessageBox::warning(
+ this,
+ tr("Unsupported"),
+ tr("Current configuration doesn't support tracing."));
+ return;
+ }
+
if (dialog.exec() == QDialog::Accepted) {
qDebug()<< "App : " <<dialog.applicationPath();
qDebug()<< " Arguments: "<<dialog.arguments();
+ m_traceProcess->setExecutablePath(dialog.applicationPath());
+ m_traceProcess->setArguments(dialog.arguments());
+ m_traceProcess->start();
}
}
m_ui.stateDock->hide();
}
-void MainWindow::filterTrace()
-{
- m_proxyModel->setFilterString(m_filterEdit->text());
-}
-
void MainWindow::replayStart()
{
QDialog dlg;
}
}
-void MainWindow::fillStateForFrame()
+static QTreeWidgetItem *
+variantToItem(const QString &key, const QVariant &var, const QVariant &defaultVar);
+
+static void
+variantMapToItems(const QVariantMap &map, const QVariantMap &defaultMap, QList<QTreeWidgetItem *> &items)
{
QVariantMap::const_iterator itr;
+ for (itr = map.constBegin(); itr != map.constEnd(); ++itr) {
+ QString key = itr.key();
+ QVariant var = itr.value();
+ QVariant defaultVar = defaultMap[key];
+
+ QTreeWidgetItem *item = variantToItem(key, var, defaultVar);
+ if (item) {
+ items.append(item);
+ }
+ }
+}
+
+static void
+variantListToItems(const QVariantList &lst, const QVariantList &defaultLst, QList<QTreeWidgetItem *> &items)
+{
+ for (int i = 0; i < lst.count(); ++i) {
+ QString key = QString::number(i);
+ QVariant var = lst[i];
+ QVariant defaultVar;
+
+ if (i < defaultLst.count()) {
+ defaultVar = defaultLst[i];
+ }
+
+ QTreeWidgetItem *item = variantToItem(key, var, defaultVar);
+ if (item) {
+ items.append(item);
+ }
+ }
+}
+
+static bool
+isVariantDeep(const QVariant &var)
+{
+ if (var.type() == QVariant::List) {
+ QVariantList lst = var.toList();
+ for (int i = 0; i < lst.count(); ++i) {
+ if (isVariantDeep(lst[i])) {
+ return true;
+ }
+ }
+ return false;
+ } else if (var.type() == QVariant::Map) {
+ return true;
+ } else if (var.type() == QVariant::Hash) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+static QTreeWidgetItem *
+variantToItem(const QString &key, const QVariant &var, const QVariant &defaultVar)
+{
+ if (var == defaultVar) {
+ return NULL;
+ }
+
+ QString val;
+
+ bool deep = isVariantDeep(var);
+ if (!deep) {
+ variantToString(var, val);
+ }
+
+ //qDebug()<<"key = "<<key;
+ //qDebug()<<"val = "<<val;
+ QStringList lst;
+ lst += key;
+ lst += val;
+
+ QTreeWidgetItem *item = new QTreeWidgetItem((QTreeWidgetItem *)0, lst);
+
+ if (deep) {
+ QList<QTreeWidgetItem *> children;
+ if (var.type() == QVariant::Map) {
+ QVariantMap map = var.toMap();
+ QVariantMap defaultMap = defaultVar.toMap();
+ variantMapToItems(map, defaultMap, children);
+ }
+ if (var.type() == QVariant::List) {
+ QVariantList lst = var.toList();
+ QVariantList defaultLst = defaultVar.toList();
+ variantListToItems(lst, defaultLst, children);
+ }
+ item->addChildren(children);
+ }
+
+ return item;
+}
+
+void MainWindow::fillStateForFrame()
+{
QVariantMap params;
if (!m_selectedEvent || m_selectedEvent->state().isEmpty())
return;
+ bool nonDefaults = m_ui.nonDefaultsCB->isChecked();
+ QVariantMap defaultParams;
+ if (nonDefaults) {
+ ApiTraceState defaultState = m_trace->defaultState();
+ defaultParams = defaultState.parameters();
+ }
+
const ApiTraceState &state = m_selectedEvent->state();
m_ui.stateTreeWidget->clear();
params = state.parameters();
QList<QTreeWidgetItem *> items;
- for (itr = params.constBegin(); itr != params.constEnd(); ++itr) {
- QString key = itr.key();
- QString val;
-
- variantToString(itr.value(), val);
- //qDebug()<<"key = "<<key;
- //qDebug()<<"val = "<<val;
- QStringList lst;
- lst += key;
- lst += val;
- items.append(new QTreeWidgetItem((QTreeWidget*)0, lst));
- }
+ variantMapToItems(params, defaultParams, items);
m_ui.stateTreeWidget->insertTopLevelItems(0, items);
- QStringList shaderSources = state.shaderSources();
+ QMap<QString, QString> shaderSources = state.shaderSources();
if (shaderSources.isEmpty()) {
m_sourcesWidget->setShaders(shaderSources);
} else {
QTreeWidgetItem *textureItem =
new QTreeWidgetItem(m_ui.surfacesTreeWidget);
textureItem->setText(0, tr("Textures"));
+ if (textures.count() <= 6)
+ textureItem->setExpanded(true);
+
for (int i = 0; i < textures.count(); ++i) {
const ApiTexture &texture =
textures[i];
QTreeWidgetItem *fboItem =
new QTreeWidgetItem(m_ui.surfacesTreeWidget);
fboItem->setText(0, tr("Framebuffers"));
+ if (fbos.count() <= 6)
+ fboItem->setExpanded(true);
+
for (int i = 0; i < fbos.count(); ++i) {
const ApiFramebuffer &fbo =
fbos[i];
void MainWindow::showSettings()
{
SettingsDialog dialog;
- dialog.setFilterOptions(m_proxyModel->filterOptions());
+ dialog.setFilterModel(m_proxyModel);
- if (dialog.exec() == QDialog::Accepted) {
- m_proxyModel->setFilterOptions(dialog.filterOptions());
- }
+ dialog.exec();
}
void MainWindow::openHelp(const QUrl &url)
m_ui.callView->header()->swapSections(0, 1);
m_ui.callView->setColumnWidth(1, 42);
- QToolBar *toolBar = addToolBar(tr("Navigation"));
- m_filterEdit = new QLineEdit(toolBar);
- toolBar->addWidget(m_filterEdit);
-
m_progressBar = new QProgressBar();
m_progressBar->setRange(0, 0);
statusBar()->addPermanentWidget(m_progressBar);
m_ui.detailsWebView->page()->setLinkDelegationPolicy(
QWebPage::DelegateExternalLinks);
+
+ m_jumpWidget = new JumpWidget(this);
+ m_ui.centralLayout->addWidget(m_jumpWidget);
+ m_jumpWidget->hide();
+
+ m_searchWidget = new SearchWidget(this);
+ m_ui.centralLayout->addWidget(m_searchWidget);
+ m_searchWidget->hide();
+
+ m_traceProcess = new TraceProcess(this);
+
+ new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_G),
+ this, SLOT(slotGoTo()));
+ new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_F),
+ this, SLOT(slotSearch()));
}
void MainWindow::initConnections()
connect(m_ui.callView, SIGNAL(activated(const QModelIndex &)),
this, SLOT(callItemSelected(const QModelIndex &)));
- connect(m_filterEdit, SIGNAL(returnPressed()),
- this, SLOT(filterTrace()));
connect(m_ui.surfacesTreeWidget,
SIGNAL(customContextMenuRequested(const QPoint &)),
connect(m_ui.detailsWebView, SIGNAL(linkClicked(const QUrl&)),
this, SLOT(openHelp(const QUrl&)));
+
+ connect(m_ui.nonDefaultsCB, SIGNAL(toggled(bool)),
+ this, SLOT(fillState(bool)));
+
+ connect(m_jumpWidget, SIGNAL(jumpTo(int)),
+ SLOT(slotJumpTo(int)));
+
+ connect(m_searchWidget,
+ SIGNAL(searchNext(const QString&, Qt::CaseSensitivity)),
+ SLOT(slotSearchNext(const QString&, Qt::CaseSensitivity)));
+ connect(m_searchWidget,
+ SIGNAL(searchPrev(const QString&, Qt::CaseSensitivity)),
+ SLOT(slotSearchPrev(const QString&, Qt::CaseSensitivity)));
+
+ connect(m_traceProcess, SIGNAL(tracedFile(const QString&)),
+ SLOT(createdTrace(const QString&)));
+ connect(m_traceProcess, SIGNAL(error(const QString&)),
+ SLOT(traceError(const QString&)));
}
void MainWindow::replayStateFound(const ApiTraceState &state)
}
}
+void MainWindow::slotGoTo()
+{
+ m_searchWidget->hide();
+ m_jumpWidget->show();
+}
+
+void MainWindow::slotJumpTo(int callNum)
+{
+ QModelIndex index = m_proxyModel->callIndex(callNum);
+ if (index.isValid()) {
+ m_ui.callView->setCurrentIndex(index);
+ }
+}
+
+void MainWindow::createdTrace(const QString &path)
+{
+ qDebug()<<"Done tracing "<<path;
+ newTraceFile(path);
+}
+
+void MainWindow::traceError(const QString &msg)
+{
+ QMessageBox::warning(
+ this,
+ tr("Tracing Error"),
+ msg);
+}
+
+void MainWindow::slotSearch()
+{
+ m_jumpWidget->hide();
+ m_searchWidget->show();
+}
+
+void MainWindow::slotSearchNext(const QString &str, Qt::CaseSensitivity sensitivity)
+{
+ QModelIndex index = m_ui.callView->currentIndex();
+ ApiTraceEvent *event = 0;
+
+
+ if (!index.isValid()) {
+ index = m_proxyModel->index(0, 0, QModelIndex());
+ if (!index.isValid()) {
+ qDebug()<<"no currently valid index";
+ m_searchWidget->setFound(false);
+ return;
+ }
+ }
+
+ event = index.data(ApiTraceModel::EventRole).value<ApiTraceEvent*>();
+ ApiTraceCall *call = 0;
+
+ if (event->type() == ApiTraceCall::Call)
+ call = static_cast<ApiTraceCall*>(event);
+ else {
+ Q_ASSERT(event->type() == ApiTraceCall::Frame);
+ ApiTraceFrame *frame = static_cast<ApiTraceFrame*>(event);
+ call = frame->calls.value(0);
+ }
+
+ if (!call) {
+ m_searchWidget->setFound(false);
+ return;
+ }
+ const QList<ApiTraceCall*> &calls = m_trace->calls();
+ int callNum = calls.indexOf(call);
+
+ for (int i = callNum + 1; i < calls.count(); ++i) {
+ ApiTraceCall *testCall = calls[i];
+ QString txt = testCall->filterText();
+ if (txt.contains(str, sensitivity)) {
+ QModelIndex index = m_proxyModel->indexForCall(testCall);
+ /* if it's not valid it means that the proxy model has already
+ * filtered it out */
+ if (index.isValid()) {
+ m_ui.callView->setCurrentIndex(index);
+ m_searchWidget->setFound(true);
+ return;
+ }
+ }
+ }
+ m_searchWidget->setFound(false);
+}
+
+void MainWindow::slotSearchPrev(const QString &str, Qt::CaseSensitivity sensitivity)
+{
+ QModelIndex index = m_ui.callView->currentIndex();
+ ApiTraceEvent *event = 0;
+
+
+ if (!index.isValid()) {
+ index = m_proxyModel->index(0, 0, QModelIndex());
+ if (!index.isValid()) {
+ qDebug()<<"no currently valid index";
+ m_searchWidget->setFound(false);
+ return;
+ }
+ }
+
+ event = index.data(ApiTraceModel::EventRole).value<ApiTraceEvent*>();
+ ApiTraceCall *call = 0;
+
+ if (event->type() == ApiTraceCall::Call)
+ call = static_cast<ApiTraceCall*>(event);
+ else {
+ Q_ASSERT(event->type() == ApiTraceCall::Frame);
+ ApiTraceFrame *frame = static_cast<ApiTraceFrame*>(event);
+ call = frame->calls.value(0);
+ }
+
+ if (!call) {
+ m_searchWidget->setFound(false);
+ return;
+ }
+ const QList<ApiTraceCall*> &calls = m_trace->calls();
+ int callNum = calls.indexOf(call);
+
+ for (int i = callNum - 1; i >= 0; --i) {
+ ApiTraceCall *testCall = calls[i];
+ QString txt = testCall->filterText();
+ if (txt.contains(str, sensitivity)) {
+ QModelIndex index = m_proxyModel->indexForCall(testCall);
+ /* if it's not valid it means that the proxy model has already
+ * filtered it out */
+ if (index.isValid()) {
+ m_ui.callView->setCurrentIndex(index);
+ m_searchWidget->setFound(true);
+ return;
+ }
+ }
+ }
+ m_searchWidget->setFound(false);
+}
+
+void MainWindow::fillState(bool nonDefaults)
+{
+ if (nonDefaults) {
+ ApiTraceState defaultState = m_trace->defaultState();
+ if (defaultState.isEmpty()) {
+ m_ui.nonDefaultsCB->blockSignals(true);
+ m_ui.nonDefaultsCB->setChecked(false);
+ m_ui.nonDefaultsCB->blockSignals(false);
+ int ret = QMessageBox::question(
+ this, tr("Empty Default State"),
+ tr("The applcation needs to figure out the "
+ "default state for the current trace. "
+ "This only has to be done once and "
+ "afterwards you will be able to enable "
+ "displaying of non default state for all calls."
+ "\nDo you want to lookup the default state now?"),
+ QMessageBox::Yes | QMessageBox::No);
+ if (ret != QMessageBox::Yes)
+ return;
+ ApiTraceFrame *firstFrame =
+ m_trace->frameAt(0);
+ ApiTraceEvent *oldSelected = m_selectedEvent;
+ if (!firstFrame)
+ return;
+ m_selectedEvent = firstFrame;
+ lookupState();
+ m_selectedEvent = oldSelected;
+ }
+ }
+ fillStateForFrame();
+}
+
#include "mainwindow.moc"