]> git.cworth.org Git - apitrace/blobdiff - gui/mainwindow.cpp
Size the image widget more reasonably.
[apitrace] / gui / mainwindow.cpp
index 081f0bfe25baf382d55673cfb7d939c9be3442b8..9a50510ccbfaaeb5ac4bf0e6f6275001b33b795e 100644 (file)
 #include "vertexdatainterpreter.h"
 
 #include <QAction>
+#include <QApplication>
 #include <QDebug>
 #include <QDesktopServices>
+#include <QDesktopWidget>
 #include <QDir>
 #include <QFileDialog>
 #include <QLineEdit>
 #include <QMessageBox>
 #include <QProgressBar>
-#include <QShortcut>
 #include <QToolBar>
 #include <QUrl>
 #include <QVBoxLayout>
@@ -100,29 +101,28 @@ void MainWindow::callItemSelected(const QModelIndex &index)
         ApiTraceCall *call = static_cast<ApiTraceCall*>(event);
         m_ui.detailsWebView->setHtml(call->toHtml());
         m_ui.detailsDock->show();
-        m_argsEditor->setCall(call);
         if (call->hasBinaryData()) {
             QByteArray data =
-                call->argValues[call->binaryDataIndex()].toByteArray();
+                call->arguments()[call->binaryDataIndex()].toByteArray();
             m_vdataInterpreter->setData(data);
+            QVariantList args = call->arguments();
 
-            for (int i = 0; i < call->argNames.count(); ++i) {
-                QString name = call->argNames[i];
+            for (int i = 0; i < call->argNames().count(); ++i) {
+                QString name = call->argNames()[i];
                 if (name == QLatin1String("stride")) {
-                    int stride = call->argValues[i].toInt();
+                    int stride = args[i].toInt();
                     m_ui.vertexStrideSB->setValue(stride);
                 } else if (name == QLatin1String("size")) {
-                    int components = call->argValues[i].toInt();
+                    int components = args[i].toInt();
                     m_ui.vertexComponentsSB->setValue(components);
                 } else if (name == QLatin1String("type")) {
-                    QString val = call->argValues[i].toString();
+                    QString val = args[i].toString();
                     int textIndex = m_ui.vertexTypeCB->findText(val);
                     if (textIndex >= 0)
                         m_ui.vertexTypeCB->setCurrentIndex(textIndex);
                 }
             }
         }
-        m_ui.argsEditorDock->show();
         m_ui.vertexDataDock->setVisible(call->hasBinaryData());
         m_selectedEvent = call;
     } else {
@@ -141,20 +141,28 @@ void MainWindow::callItemSelected(const QModelIndex &index)
 
 void MainWindow::replayStart()
 {
+    if (m_trace->isSaving()) {
+        QMessageBox::warning(
+            this,
+            tr("Trace Saving"),
+            tr("QApiTrace is currently saving the edited trace file. "
+               "Please wait until it finishes and try again."));
+        return;
+    }
     QDialog dlg;
     Ui_RetracerDialog dlgUi;
     dlgUi.setupUi(&dlg);
 
     dlgUi.doubleBufferingCB->setChecked(
         m_retracer->isDoubleBuffered());
-    dlgUi.benchmarkCB->setChecked(
-        m_retracer->isBenchmarking());
+    dlgUi.errorCheckCB->setChecked(
+        !m_retracer->isBenchmarking());
 
     if (dlg.exec() == QDialog::Accepted) {
         m_retracer->setDoubleBuffered(
             dlgUi.doubleBufferingCB->isChecked());
         m_retracer->setBenchmarking(
-            dlgUi.benchmarkCB->isChecked());
+            !dlgUi.errorCheckCB->isChecked());
         replayTrace(false);
     }
 }
@@ -169,10 +177,9 @@ void MainWindow::replayStop()
 
 void MainWindow::newTraceFile(const QString &fileName)
 {
-    m_traceFileName = fileName;
     m_trace->setFileName(fileName);
 
-    if (m_traceFileName.isEmpty()) {
+    if (fileName.isEmpty()) {
         m_ui.actionReplay->setEnabled(false);
         m_ui.actionLookupState->setEnabled(false);
         setWindowTitle(tr("QApiTrace"));
@@ -196,6 +203,11 @@ void MainWindow::replayFinished(const QString &output)
         statusBar()->showMessage(output);
     }
     m_stateEvent = 0;
+    m_ui.actionShowErrorsDock->setEnabled(m_trace->hasErrors());
+    m_ui.errorsDock->setVisible(m_trace->hasErrors());
+    if (!m_trace->hasErrors())
+        m_ui.errorsTreeWidget->clear();
+
     statusBar()->showMessage(
         tr("Replaying finished!"), 2000);
 }
@@ -236,15 +248,15 @@ void MainWindow::finishedLoadingTrace()
 
 void MainWindow::replayTrace(bool dumpState)
 {
-    if (m_traceFileName.isEmpty())
+    if (m_trace->fileName().isEmpty())
         return;
 
-    m_retracer->setFileName(m_traceFileName);
+    m_retracer->setFileName(m_trace->fileName());
     m_retracer->setCaptureState(dumpState);
     if (m_retracer->captureState() && m_selectedEvent) {
         int index = 0;
         if (m_selectedEvent->type() == ApiTraceEvent::Call) {
-            index = static_cast<ApiTraceCall*>(m_selectedEvent)->index;
+            index = static_cast<ApiTraceCall*>(m_selectedEvent)->index();
         } else if (m_selectedEvent->type() == ApiTraceEvent::Frame) {
             ApiTraceFrame *frame =
                 static_cast<ApiTraceFrame*>(m_selectedEvent);
@@ -253,7 +265,7 @@ void MainWindow::replayTrace(bool dumpState)
                 qDebug()<<"tried to get a state for an empty frame";
                 return;
             }
-            index = frame->calls.first()->index;
+            index = frame->calls.first()->index();
         } else {
             qDebug()<<"Unknown event type";
             return;
@@ -280,6 +292,14 @@ void MainWindow::lookupState()
             tr("To inspect the state select an event in the event list."));
         return;
     }
+    if (m_trace->isSaving()) {
+        QMessageBox::warning(
+            this,
+            tr("Trace Saving"),
+            tr("QApiTrace is currently saving the edited trace file. "
+               "Please wait until it finishes and try again."));
+        return;
+    }
     m_stateEvent = m_selectedEvent;
     replayTrace(true);
 }
@@ -542,10 +562,16 @@ void MainWindow::showSelectedSurface()
         return;
 
     QVariant var = item->data(0, Qt::UserRole);
-    m_imageViewer->setImage(var.value<QImage>());
-    m_imageViewer->show();
-    m_imageViewer->raise();
-    m_imageViewer->activateWindow();
+    QImage img = var.value<QImage>();
+    ImageViewer *viewer = new ImageViewer(this);
+    viewer->setAttribute(Qt::WA_DeleteOnClose, true);
+    viewer->setImage(img);
+    QRect screenRect = QApplication::desktop()->availableGeometry();
+    viewer->resize(qMin(int(0.75 * screenRect.width()), img.width()) + 40,
+                   qMin(int(0.75 * screenRect.height()), img.height()) + 40);
+    viewer->show();
+    viewer->raise();
+    viewer->activateWindow();
 }
 
 void MainWindow::initObjects()
@@ -571,8 +597,6 @@ void MainWindow::initObjects()
     m_vdataInterpreter->setTypeFromString(
         m_ui.vertexTypeCB->currentText());
 
-    m_imageViewer = new ImageViewer(this);
-
     m_model = new ApiTraceModel();
     m_model->setApiTrace(m_trace);
     m_proxyModel = new ApiTraceFilter();
@@ -582,6 +606,7 @@ void MainWindow::initObjects()
     m_ui.callView->resizeColumnToContents(0);
     m_ui.callView->header()->swapSections(0, 1);
     m_ui.callView->setColumnWidth(1, 42);
+    m_ui.callView->setContextMenuPolicy(Qt::CustomContextMenu);
 
     m_progressBar = new QProgressBar();
     m_progressBar->setRange(0, 0);
@@ -589,16 +614,15 @@ void MainWindow::initObjects()
     m_progressBar->hide();
 
     m_argsEditor = new ArgumentsEditor(this);
-    m_ui.argsEditorLayout->addWidget(m_argsEditor);
 
     m_ui.detailsDock->hide();
+    m_ui.errorsDock->hide();
     m_ui.vertexDataDock->hide();
     m_ui.stateDock->hide();
-    m_ui.argsEditorDock->hide();
     setDockOptions(dockOptions() | QMainWindow::ForceTabbedDocks);
 
     tabifyDockWidget(m_ui.stateDock, m_ui.vertexDataDock);
-    tabifyDockWidget(m_ui.vertexDataDock, m_ui.argsEditorDock);
+    tabifyDockWidget(m_ui.detailsDock, m_ui.errorsDock);
 
     m_ui.surfacesTreeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
 
@@ -614,11 +638,6 @@ void MainWindow::initObjects()
     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()
@@ -627,6 +646,12 @@ void MainWindow::initConnections()
             this, SLOT(startedLoadingTrace()));
     connect(m_trace, SIGNAL(finishedLoadingTrace()),
             this, SLOT(finishedLoadingTrace()));
+    connect(m_trace, SIGNAL(startedSaving()),
+            this, SLOT(slotStartedSaving()));
+    connect(m_trace, SIGNAL(saved()),
+            this, SLOT(slotSaved()));
+    connect(m_trace, SIGNAL(changed(ApiTraceCall*)),
+            this, SLOT(slotTraceChanged(ApiTraceCall*)));
 
     connect(m_retracer, SIGNAL(finished(const QString&)),
             this, SLOT(replayFinished(const QString&)));
@@ -634,6 +659,8 @@ void MainWindow::initConnections()
             this, SLOT(replayError(const QString&)));
     connect(m_retracer, SIGNAL(foundState(const ApiTraceState&)),
             this, SLOT(replayStateFound(const ApiTraceState&)));
+    connect(m_retracer, SIGNAL(retraceErrors(const QList<RetraceError>&)),
+            this, SLOT(slotRetraceErrors(const QList<RetraceError>&)));
 
     connect(m_ui.vertexInterpretButton, SIGNAL(clicked()),
             m_vdataInterpreter, SLOT(interpretData()));
@@ -654,6 +681,15 @@ void MainWindow::initConnections()
     connect(m_ui.actionQuit, SIGNAL(triggered()),
             this, SLOT(close()));
 
+    connect(m_ui.actionFind, SIGNAL(triggered()),
+            this, SLOT(slotSearch()));
+    connect(m_ui.actionGo, SIGNAL(triggered()),
+            this, SLOT(slotGoTo()));
+    connect(m_ui.actionGoFrameStart, SIGNAL(triggered()),
+            this, SLOT(slotGoFrameStart()));
+    connect(m_ui.actionGoFrameEnd, SIGNAL(triggered()),
+            this, SLOT(slotGoFrameEnd()));
+
     connect(m_ui.actionReplay, SIGNAL(triggered()),
             this, SLOT(replayStart()));
     connect(m_ui.actionStop, SIGNAL(triggered()),
@@ -665,6 +701,8 @@ void MainWindow::initConnections()
 
     connect(m_ui.callView, SIGNAL(activated(const QModelIndex &)),
             this, SLOT(callItemSelected(const QModelIndex &)));
+    connect(m_ui.callView, SIGNAL(customContextMenuRequested(QPoint)),
+            this, SLOT(customContextMenuRequested(QPoint)));
 
     connect(m_ui.surfacesTreeWidget,
             SIGNAL(customContextMenuRequested(const QPoint &)),
@@ -693,6 +731,13 @@ void MainWindow::initConnections()
             SLOT(createdTrace(const QString&)));
     connect(m_traceProcess, SIGNAL(error(const QString&)),
             SLOT(traceError(const QString&)));
+
+    connect(m_ui.errorsDock, SIGNAL(visibilityChanged(bool)),
+            m_ui.actionShowErrorsDock, SLOT(setChecked(bool)));
+    connect(m_ui.actionShowErrorsDock, SIGNAL(triggered(bool)),
+            m_ui.errorsDock, SLOT(setVisible(bool)));
+    connect(m_ui.errorsTreeWidget, SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)),
+            this, SLOT(slotErrorSelected(QTreeWidgetItem*)));
 }
 
 void MainWindow::replayStateFound(const ApiTraceState &state)
@@ -872,4 +917,147 @@ void MainWindow::fillState(bool nonDefaults)
     fillStateForFrame();
 }
 
+void MainWindow::customContextMenuRequested(QPoint pos)
+{
+    QMenu menu;
+    QModelIndex index = m_ui.callView->indexAt(pos);
+
+    callItemSelected(index);
+    if (!index.isValid())
+        return;
+
+    ApiTraceEvent *event =
+        index.data(ApiTraceModel::EventRole).value<ApiTraceEvent*>();
+    if (!event || event->type() != ApiTraceEvent::Call)
+        return;
+
+    menu.addAction(QIcon(":/resources/media-record.png"),
+                   tr("Lookup state"), this, SLOT(lookupState()));
+    menu.addAction(tr("Edit"), this, SLOT(editCall()));
+
+    menu.exec(QCursor::pos());
+}
+
+void MainWindow::editCall()
+{
+    if (m_selectedEvent && m_selectedEvent->type() == ApiTraceEvent::Call) {
+        ApiTraceCall *call = static_cast<ApiTraceCall*>(m_selectedEvent);
+        m_argsEditor->setCall(call);
+        m_argsEditor->show();
+    }
+}
+
+void MainWindow::slotStartedSaving()
+{
+    m_progressBar->show();
+    statusBar()->showMessage(
+        tr("Saving to %1").arg(m_trace->fileName()));
+}
+
+void MainWindow::slotSaved()
+{
+    statusBar()->showMessage(
+        tr("Saved to %1").arg(m_trace->fileName()), 2000);
+    m_progressBar->hide();
+}
+
+void MainWindow::slotGoFrameStart()
+{
+    ApiTraceFrame *frame = currentFrame();
+    if (!frame || frame->calls.isEmpty()) {
+        return;
+    }
+
+    QList<ApiTraceCall*>::const_iterator itr;
+
+    itr = frame->calls.constBegin();
+    while (itr != frame->calls.constEnd()) {
+        ApiTraceCall *call = *itr;
+        QModelIndex idx = m_proxyModel->indexForCall(call);
+        if (idx.isValid()) {
+            m_ui.callView->setCurrentIndex(idx);
+            break;
+        }
+        ++itr;
+    }
+}
+
+void MainWindow::slotGoFrameEnd()
+{
+    ApiTraceFrame *frame = currentFrame();
+    if (!frame || frame->calls.isEmpty()) {
+        return;
+    }
+    QList<ApiTraceCall*>::const_iterator itr;
+
+    itr = frame->calls.constEnd();
+    do {
+        --itr;
+        ApiTraceCall *call = *itr;
+        QModelIndex idx = m_proxyModel->indexForCall(call);
+        if (idx.isValid()) {
+            m_ui.callView->setCurrentIndex(idx);
+            break;
+        }
+    } while (itr != frame->calls.constBegin());
+}
+
+ApiTraceFrame * MainWindow::currentFrame() const
+{
+    if (m_selectedEvent) {
+        if (m_selectedEvent->type() == ApiTraceEvent::Frame) {
+            return static_cast<ApiTraceFrame*>(m_selectedEvent);
+        } else {
+            Q_ASSERT(m_selectedEvent->type() == ApiTraceEvent::Call);
+            ApiTraceCall *call = static_cast<ApiTraceCall*>(m_selectedEvent);
+            return call->parentFrame();
+        }
+    }
+    return NULL;
+}
+
+void MainWindow::slotTraceChanged(ApiTraceCall *call)
+{
+    Q_ASSERT(call);
+    if (call == m_selectedEvent) {
+        m_ui.detailsWebView->setHtml(call->toHtml());
+    }
+}
+
+void MainWindow::slotRetraceErrors(const QList<RetraceError> &errors)
+{
+    m_ui.errorsTreeWidget->clear();
+
+    foreach(RetraceError error, errors) {
+        ApiTraceCall *call = m_trace->callWithIndex(error.callIndex);
+        if (!call)
+            continue;
+        call->setError(error.message);
+
+        QTreeWidgetItem *item =
+            new QTreeWidgetItem(m_ui.errorsTreeWidget);
+        item->setData(0, Qt::DisplayRole, error.callIndex);
+        item->setData(0, Qt::UserRole, QVariant::fromValue(call));
+        QString type = error.type;
+        type[0] = type[0].toUpper();
+        item->setData(1, Qt::DisplayRole, type);
+        item->setData(2, Qt::DisplayRole, error.message);
+    }
+}
+
+void MainWindow::slotErrorSelected(QTreeWidgetItem *current)
+{
+    if (current) {
+        ApiTraceCall *call =
+            current->data(0, Qt::UserRole).value<ApiTraceCall*>();
+        Q_ASSERT(call);
+        QModelIndex index = m_proxyModel->indexForCall(call);
+        if (index.isValid()) {
+            m_ui.callView->setCurrentIndex(index);
+        } else {
+            statusBar()->showMessage(tr("Call has been filtered out."));
+        }
+    }
+}
+
 #include "mainwindow.moc"