]> git.cworth.org Git - apitrace/blobdiff - gui/mainwindow.cpp
Fix a few more arrays args in D3D9.
[apitrace] / gui / mainwindow.cpp
index e2d58b6cb55bf0f6d967dbadc2e79f6b83b134e9..f63b87e0600323632a3612cbc85da8ee628cf881 100644 (file)
@@ -6,10 +6,13 @@
 #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"
 
@@ -21,6 +24,7 @@
 #include <QLineEdit>
 #include <QMessageBox>
 #include <QProgressBar>
+#include <QShortcut>
 #include <QToolBar>
 #include <QUrl>
 #include <QVBoxLayout>
@@ -42,9 +46,20 @@ void MainWindow::createTrace()
 {
     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();
     }
 }
 
@@ -121,11 +136,6 @@ void MainWindow::callItemSelected(const QModelIndex &index)
         m_ui.stateDock->hide();
 }
 
-void MainWindow::filterTrace()
-{
-    m_proxyModel->setFilterString(m_filterEdit->text());
-}
-
 void MainWindow::replayStart()
 {
     QDialog dlg;
@@ -297,33 +307,126 @@ variantToString(const QVariant &var, QString &str)
     }
 }
 
-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 {
@@ -344,6 +447,9 @@ void MainWindow::fillStateForFrame()
             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];
@@ -367,6 +473,9 @@ void MainWindow::fillStateForFrame()
             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];
@@ -394,11 +503,9 @@ void MainWindow::fillStateForFrame()
 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)
@@ -473,10 +580,6 @@ void MainWindow::initObjects()
     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);
@@ -493,6 +596,21 @@ void MainWindow::initObjects()
 
     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()
@@ -539,8 +657,6 @@ 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 &)),
@@ -551,6 +667,24 @@ void MainWindow::initConnections()
 
     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)
@@ -564,4 +698,170 @@ 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"