X-Git-Url: https://git.cworth.org/git?a=blobdiff_plain;f=gui%2Fmainwindow.cpp;h=d6ebd2f9e1ecbe3a107222b684cda6c1e826c7e3;hb=1af9409e5ade504829e8d3260921e5905cbf8f11;hp=9d8748d7699fe0c8e624d6bbdfaaa25259bf9425;hpb=218015c3e3523d563726c4c8e120ba4d460cf762;p=apitrace diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp index 9d8748d..d6ebd2f 100644 --- a/gui/mainwindow.cpp +++ b/gui/mainwindow.cpp @@ -8,14 +8,19 @@ #include "argumentseditor.h" #include "imageviewer.h" #include "jumpwidget.h" +#include "profiledialog.h" #include "retracer.h" #include "searchwidget.h" #include "settingsdialog.h" #include "shaderssourcewidget.h" #include "tracedialog.h" #include "traceprocess.h" +#include "trimprocess.h" +#include "thumbnail.h" #include "ui_retracerdialog.h" +#include "ui_profilereplaydialog.h" #include "vertexdatainterpreter.h" +#include "trace_profiler.hpp" #include #include @@ -36,19 +41,29 @@ MainWindow::MainWindow() : QMainWindow(), + m_api(trace::API_GL), + m_initalCallNum(-1), m_selectedEvent(0), m_stateEvent(0), m_nonDefaultsLookupEvent(0) { m_ui.setupUi(this); + updateActionsState(false); initObjects(); initConnections(); } -void MainWindow::createTrace() +MainWindow::~MainWindow() { - TraceDialog dialog; + delete m_trace; + m_trace = 0; + delete m_proxyModel; + delete m_model; +} + +void MainWindow::createTrace() +{ if (!m_traceProcess->canTrace()) { QMessageBox::warning( this, @@ -57,9 +72,11 @@ void MainWindow::createTrace() return; } + TraceDialog dialog; if (dialog.exec() == QDialog::Accepted) { qDebug()<< "App : " <setApi(dialog.api()); m_traceProcess->setExecutablePath(dialog.applicationPath()); m_traceProcess->setArguments(dialog.arguments()); m_traceProcess->start(); @@ -69,18 +86,18 @@ void MainWindow::createTrace() void MainWindow::openTrace() { QString fileName = - QFileDialog::getOpenFileName( - this, - tr("Open Trace"), - QDir::homePath(), - tr("Trace Files (*.trace)")); + QFileDialog::getOpenFileName( + this, + tr("Open Trace"), + QDir::homePath(), + tr("Trace Files (*.trace)")); if (!fileName.isEmpty() && QFile::exists(fileName)) { newTraceFile(fileName); } } -void MainWindow::loadTrace(const QString &fileName) +void MainWindow::loadTrace(const QString &fileName, int callNum) { if (!QFile::exists(fileName)) { QMessageBox::warning(this, tr("File Missing"), @@ -88,6 +105,7 @@ void MainWindow::loadTrace(const QString &fileName) return; } + m_initalCallNum = callNum; newTraceFile(fileName); } @@ -98,14 +116,18 @@ void MainWindow::callItemSelected(const QModelIndex &index) if (event && event->type() == ApiTraceEvent::Call) { ApiTraceCall *call = static_cast(event); + m_ui.detailsDock->setWindowTitle( + tr("Details View. Frame %1, Call %2") + .arg(call->parentFrame() ? call->parentFrame()->number : 0) + .arg(call->index())); m_ui.detailsWebView->setHtml(call->toHtml()); m_ui.detailsDock->show(); if (call->hasBinaryData()) { QByteArray data = call->arguments()[call->binaryDataIndex()].toByteArray(); m_vdataInterpreter->setData(data); - QVariantList args = call->arguments(); + QVector args = call->arguments(); for (int i = 0; i < call->argNames().count(); ++i) { QString name = call->argNames()[i]; if (name == QLatin1String("stride")) { @@ -117,8 +139,9 @@ void MainWindow::callItemSelected(const QModelIndex &index) } else if (name == QLatin1String("type")) { QString val = args[i].toString(); int textIndex = m_ui.vertexTypeCB->findText(val); - if (textIndex >= 0) + if (textIndex >= 0) { m_ui.vertexTypeCB->setCurrentIndex(textIndex); + } } } } @@ -127,15 +150,21 @@ void MainWindow::callItemSelected(const QModelIndex &index) } else { if (event && event->type() == ApiTraceEvent::Frame) { m_selectedEvent = static_cast(event); - } else + } else { m_selectedEvent = 0; + } m_ui.detailsDock->hide(); m_ui.vertexDataDock->hide(); } - if (m_selectedEvent && !m_selectedEvent->state().isEmpty()) { + if (m_selectedEvent && m_selectedEvent->hasState()) { fillStateForFrame(); - } else + } else { m_ui.stateDock->hide(); + } +} + +void MainWindow::callItemActivated(const QModelIndex &index) { + lookupState(); } void MainWindow::replayStart() @@ -148,30 +177,59 @@ void MainWindow::replayStart() "Please wait until it finishes and try again.")); return; } + QDialog dlg; Ui_RetracerDialog dlgUi; dlgUi.setupUi(&dlg); dlgUi.doubleBufferingCB->setChecked( m_retracer->isDoubleBuffered()); + dlgUi.errorCheckCB->setChecked( !m_retracer->isBenchmarking()); if (dlg.exec() == QDialog::Accepted) { m_retracer->setDoubleBuffered( dlgUi.doubleBufferingCB->isChecked()); + m_retracer->setBenchmarking( !dlgUi.errorCheckCB->isChecked()); - replayTrace(false); + + m_retracer->setProfiling(false, false, false); + + replayTrace(false, false); + } +} + +void MainWindow::replayProfile() +{ + 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_ProfileReplayDialog dlgUi; + dlgUi.setupUi(&dlg); + + if (dlg.exec() == QDialog::Accepted) { + m_retracer->setProfiling( + dlgUi.gpuTimesCB->isChecked(), + dlgUi.cpuTimesCB->isChecked(), + dlgUi.pixelsDrawnCB->isChecked()); + + replayTrace(false, false); } } void MainWindow::replayStop() { m_retracer->quit(); - m_ui.actionStop->setEnabled(false); - m_ui.actionReplay->setEnabled(true); - m_ui.actionLookupState->setEnabled(true); + updateActionsState(true, true); } void MainWindow::newTraceFile(const QString &fileName) @@ -182,43 +240,32 @@ void MainWindow::newTraceFile(const QString &fileName) m_trace->setFileName(fileName); if (fileName.isEmpty()) { - m_ui.actionReplay->setEnabled(false); - m_ui.actionLookupState->setEnabled(false); + updateActionsState(false); setWindowTitle(tr("QApiTrace")); } else { + updateActionsState(true); QFileInfo info(fileName); - m_ui.actionReplay->setEnabled(true); - m_ui.actionLookupState->setEnabled(true); setWindowTitle( tr("QApiTrace - %1").arg(info.fileName())); } } -void MainWindow::replayFinished(const QString &output) +void MainWindow::replayFinished(const QString &message) { - m_ui.actionStop->setEnabled(false); - m_ui.actionReplay->setEnabled(true); - m_ui.actionLookupState->setEnabled(true); - + updateActionsState(true); m_progressBar->hide(); - if (output.length() < 80) { - statusBar()->showMessage(output); - } + statusBar()->showMessage(message, 2000); m_stateEvent = 0; m_ui.actionShowErrorsDock->setEnabled(m_trace->hasErrors()); m_ui.errorsDock->setVisible(m_trace->hasErrors()); - if (!m_trace->hasErrors()) + if (!m_trace->hasErrors()) { m_ui.errorsTreeWidget->clear(); - - statusBar()->showMessage( - tr("Replaying finished!"), 2000); + } } void MainWindow::replayError(const QString &message) { - m_ui.actionStop->setEnabled(false); - m_ui.actionReplay->setEnabled(true); - m_ui.actionLookupState->setEnabled(true); + updateActionsState(true); m_stateEvent = 0; m_nonDefaultsLookupEvent = 0; @@ -244,18 +291,26 @@ void MainWindow::finishedLoadingTrace() if (!m_trace) { return; } + m_api = m_trace->api(); QFileInfo info(m_trace->fileName()); statusBar()->showMessage( tr("Loaded %1").arg(info.fileName()), 3000); + if (m_initalCallNum >= 0) { + m_trace->findCallIndex(m_initalCallNum); + m_initalCallNum = -1; + } } -void MainWindow::replayTrace(bool dumpState) +void MainWindow::replayTrace(bool dumpState, bool dumpThumbnails) { - if (m_trace->fileName().isEmpty()) + if (m_trace->fileName().isEmpty()) { return; + } m_retracer->setFileName(m_trace->fileName()); + m_retracer->setAPI(m_api); m_retracer->setCaptureState(dumpState); + m_retracer->setCaptureThumbnails(dumpThumbnails); if (m_retracer->captureState() && m_selectedEvent) { int index = 0; if (m_selectedEvent->type() == ApiTraceEvent::Call) { @@ -268,7 +323,7 @@ void MainWindow::replayTrace(bool dumpState) qDebug()<<"tried to get a state for an empty frame"; return; } - index = frame->calls().first()->index(); + index = frame->lastCallIndex(); } else { qDebug()<<"Unknown event type"; return; @@ -279,12 +334,43 @@ void MainWindow::replayTrace(bool dumpState) m_ui.actionStop->setEnabled(true); m_progressBar->show(); - if (dumpState) + if (dumpState || dumpThumbnails) { + if (dumpState && dumpThumbnails) { + statusBar()->showMessage( + tr("Looking up the state and capturing thumbnails...")); + } else if (dumpState) { + statusBar()->showMessage( + tr("Looking up the state...")); + } else if (dumpThumbnails) { + statusBar()->showMessage( + tr("Capturing thumbnails...")); + } + } else if (m_retracer->isProfiling()) { statusBar()->showMessage( - tr("Looking up the state...")); - else + tr("Profiling draw calls in trace file...")); + } else { statusBar()->showMessage( tr("Replaying the trace file...")); + } +} + +void MainWindow::trimEvent() +{ + + int trimIndex; + if (m_trimEvent->type() == ApiTraceEvent::Call) { + ApiTraceCall *call = static_cast(m_trimEvent); + trimIndex = call->index(); + } else if (m_trimEvent->type() == ApiTraceEvent::Frame) { + ApiTraceFrame *frame = static_cast(m_trimEvent); + const QList frames = m_trace->frames(); + trimIndex = frame->lastCallIndex(); + } + + m_trimProcess->setTracePath(m_trace->fileName()); + m_trimProcess->setTrimIndex(trimIndex); + + m_trimProcess->start(); } void MainWindow::lookupState() @@ -304,23 +390,31 @@ void MainWindow::lookupState() return; } m_stateEvent = m_selectedEvent; - replayTrace(true); + replayTrace(true, false); } -MainWindow::~MainWindow() +void MainWindow::showThumbnails() { - delete m_trace; - m_trace = 0; + replayTrace(false, true); +} - delete m_proxyModel; - delete m_model; +void MainWindow::trim() +{ + if (!m_selectedEvent) { + QMessageBox::warning( + this, tr("Unknown Event"), + tr("To trim select a frame or an event in the event list.")); + return; + } + m_trimEvent = m_selectedEvent; + trimEvent(); } static void variantToString(const QVariant &var, QString &str) { if (var.type() == QVariant::List) { - QVariantList lst = var.toList(); + QVector lst = var.toList().toVector(); str += QLatin1String("["); for (int i = 0; i < lst.count(); ++i) { QVariant val = lst[i]; @@ -339,10 +433,12 @@ variantToString(const QVariant &var, QString &str) } static QTreeWidgetItem * -variantToItem(const QString &key, const QVariant &var, const QVariant &defaultVar); +variantToItem(const QString &key, const QVariant &var, + const QVariant &defaultVar); static void -variantMapToItems(const QVariantMap &map, const QVariantMap &defaultMap, QList &items) +variantMapToItems(const QVariantMap &map, const QVariantMap &defaultMap, + QList &items) { QVariantMap::const_iterator itr; for (itr = map.constBegin(); itr != map.constEnd(); ++itr) { @@ -358,7 +454,9 @@ variantMapToItems(const QVariantMap &map, const QVariantMap &defaultMap, QList &items) +variantListToItems(const QVector &lst, + const QVector &defaultLst, + QList &items) { for (int i = 0; i < lst.count(); ++i) { QString key = QString::number(i); @@ -380,7 +478,7 @@ static bool isVariantDeep(const QVariant &var) { if (var.type() == QVariant::List) { - QVariantList lst = var.toList(); + QVector lst = var.toList().toVector(); for (int i = 0; i < lst.count(); ++i) { if (isVariantDeep(lst[i])) { return true; @@ -397,7 +495,8 @@ isVariantDeep(const QVariant &var) } static QTreeWidgetItem * -variantToItem(const QString &key, const QVariant &var, const QVariant &defaultVar) +variantToItem(const QString &key, const QVariant &var, + const QVariant &defaultVar) { if (var == defaultVar) { return NULL; @@ -426,8 +525,8 @@ variantToItem(const QString &key, const QVariant &var, const QVariant &defaultVa variantMapToItems(map, defaultMap, children); } if (var.type() == QVariant::List) { - QVariantList lst = var.toList(); - QVariantList defaultLst = defaultVar.toList(); + QVector lst = var.toList().toVector(); + QVector defaultLst = defaultVar.toList().toVector(); variantListToItems(lst, defaultLst, children); } item->addChildren(children); @@ -441,16 +540,16 @@ static void addSurfaceItem(const ApiSurface &surface, QTreeWidgetItem *parent, QTreeWidget *tree) { - int width = surface.size().width(); - int height = surface.size().height(); QIcon icon(QPixmap::fromImage(surface.thumb())); QTreeWidgetItem *item = new QTreeWidgetItem(parent); - item->setIcon(0, icon); + int width = surface.size().width(); + int height = surface.size().height(); QString descr = - QString::fromLatin1("%1, %2 x %3") + QString::fromLatin1("%1, %2, %3 x %4") .arg(label) + .arg(surface.formatName()) .arg(width) .arg(height); @@ -464,10 +563,9 @@ static void addSurfaceItem(const ApiSurface &surface, void MainWindow::fillStateForFrame() { - QVariantMap params; - - if (!m_selectedEvent || m_selectedEvent->state().isEmpty()) + if (!m_selectedEvent || !m_selectedEvent->hasState()) { return; + } if (m_nonDefaultsLookupEvent) { m_ui.nonDefaultsCB->blockSignals(true); @@ -482,11 +580,10 @@ void MainWindow::fillStateForFrame() defaultParams = defaultState.parameters(); } - const ApiTraceState &state = m_selectedEvent->state(); + const ApiTraceState &state = *m_selectedEvent->state(); m_ui.stateTreeWidget->clear(); - params = state.parameters(); QList items; - variantMapToItems(params, defaultParams, items); + variantMapToItems(state.parameters(), defaultParams, items); m_ui.stateTreeWidget->insertTopLevelItems(0, items); QMap shaderSources = state.shaderSources(); @@ -496,6 +593,11 @@ void MainWindow::fillStateForFrame() m_sourcesWidget->setShaders(shaderSources); } + m_ui.uniformsTreeWidget->clear(); + QList uniformsItems; + variantMapToItems(state.uniforms(), QVariantMap(), uniformsItems); + m_ui.uniformsTreeWidget->insertTopLevelItems(0, uniformsItems); + const QList &textures = state.textures(); const QList &fbos = @@ -505,13 +607,14 @@ void MainWindow::fillStateForFrame() if (textures.isEmpty() && fbos.isEmpty()) { m_ui.surfacesTab->setDisabled(false); } else { - m_ui.surfacesTreeWidget->setIconSize(QSize(64, 64)); + m_ui.surfacesTreeWidget->setIconSize(QSize(THUMBNAIL_SIZE, THUMBNAIL_SIZE)); if (!textures.isEmpty()) { QTreeWidgetItem *textureItem = new QTreeWidgetItem(m_ui.surfacesTreeWidget); textureItem->setText(0, tr("Textures")); - if (textures.count() <= 6) + if (textures.count() <= 6) { textureItem->setExpanded(true); + } for (int i = 0; i < textures.count(); ++i) { const ApiTexture &texture = @@ -525,8 +628,9 @@ void MainWindow::fillStateForFrame() QTreeWidgetItem *fboItem = new QTreeWidgetItem(m_ui.surfacesTreeWidget); fboItem->setText(0, tr("Framebuffers")); - if (fbos.count() <= 6) + if (fbos.count() <= 6) { fboItem->setExpanded(true); + } for (int i = 0; i < fbos.count(); ++i) { const ApiFramebuffer &fbo = @@ -558,16 +662,22 @@ void MainWindow::showSurfacesMenu(const QPoint &pos) { QTreeWidget *tree = m_ui.surfacesTreeWidget; QTreeWidgetItem *item = tree->itemAt(pos); - if (!item) + if (!item) { return; + } QMenu menu(tr("Surfaces"), this); - //add needed actions + QAction *act = menu.addAction(tr("View Image")); act->setStatusTip(tr("View the currently selected surface")); connect(act, SIGNAL(triggered()), SLOT(showSelectedSurface())); + act = menu.addAction(tr("Save Image")); + act->setStatusTip(tr("Save the currently selected surface")); + connect(act, SIGNAL(triggered()), + SLOT(saveSelectedSurface())); + menu.exec(tree->viewport()->mapToGlobal(pos)); } @@ -576,27 +686,28 @@ void MainWindow::showSelectedSurface() QTreeWidgetItem *item = m_ui.surfacesTreeWidget->currentItem(); - if (!item) + if (!item) { return; + } - QVariant var = item->data(0, Qt::UserRole); - QImage img = var.value(); ImageViewer *viewer = new ImageViewer(this); QString title; - if (currentCall()) { + if (selectedCall()) { title = tr("QApiTrace - Surface at %1 (%2)") - .arg(currentCall()->name()) - .arg(currentCall()->index()); + .arg(selectedCall()->name()) + .arg(selectedCall()->index()); } else { title = tr("QApiTrace - Surface Viewer"); } viewer->setWindowTitle(title); + viewer->setAttribute(Qt::WA_DeleteOnClose, true); + + QVariant var = item->data(0, Qt::UserRole); + QImage img = var.value(); 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(); @@ -605,6 +716,7 @@ void MainWindow::showSelectedSurface() void MainWindow::initObjects() { m_ui.stateTreeWidget->sortByColumn(0, Qt::AscendingOrder); + m_ui.uniformsTreeWidget->sortByColumn(0, Qt::AscendingOrder); m_sourcesWidget = new ShadersSourceWidget(m_ui.shadersTab); QVBoxLayout *layout = new QVBoxLayout; @@ -638,7 +750,7 @@ void MainWindow::initObjects() m_ui.callView->setContextMenuPolicy(Qt::CustomContextMenu); m_progressBar = new QProgressBar(); - m_progressBar->setRange(0, 0); + m_progressBar->setRange(0, 100); statusBar()->addPermanentWidget(m_progressBar); m_progressBar->hide(); @@ -667,29 +779,46 @@ void MainWindow::initObjects() m_searchWidget->hide(); m_traceProcess = new TraceProcess(this); + m_trimProcess = new TrimProcess(this); + + m_profileDialog = new ProfileDialog(); } void MainWindow::initConnections() { connect(m_trace, SIGNAL(startedLoadingTrace()), this, SLOT(startedLoadingTrace())); + connect(m_trace, SIGNAL(loaded(int)), + this, SLOT(loadProgess(int))); 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_trace, SIGNAL(changed(ApiTraceEvent*)), + this, SLOT(slotTraceChanged(ApiTraceEvent*))); + connect(m_trace, SIGNAL(findResult(ApiTrace::SearchRequest,ApiTrace::SearchResult,ApiTraceCall*)), + this, SLOT(slotSearchResult(ApiTrace::SearchRequest,ApiTrace::SearchResult,ApiTraceCall*))); + connect(m_trace, SIGNAL(foundFrameStart(ApiTraceFrame*)), + this, SLOT(slotFoundFrameStart(ApiTraceFrame*))); + connect(m_trace, SIGNAL(foundFrameEnd(ApiTraceFrame*)), + this, SLOT(slotFoundFrameEnd(ApiTraceFrame*))); + connect(m_trace, SIGNAL(foundCallIndex(ApiTraceCall*)), + this, SLOT(slotJumpToResult(ApiTraceCall*))); connect(m_retracer, SIGNAL(finished(const QString&)), this, SLOT(replayFinished(const QString&))); connect(m_retracer, SIGNAL(error(const QString&)), this, SLOT(replayError(const QString&))); - connect(m_retracer, SIGNAL(foundState(const ApiTraceState&)), - this, SLOT(replayStateFound(const ApiTraceState&))); - connect(m_retracer, SIGNAL(retraceErrors(const QList&)), - this, SLOT(slotRetraceErrors(const QList&))); + connect(m_retracer, SIGNAL(foundState(ApiTraceState*)), + this, SLOT(replayStateFound(ApiTraceState*))); + connect(m_retracer, SIGNAL(foundProfile(trace::Profile*)), + this, SLOT(replayProfileFound(trace::Profile*))); + connect(m_retracer, SIGNAL(foundThumbnails(const QList&)), + this, SLOT(replayThumbnailsFound(const QList&))); + connect(m_retracer, SIGNAL(retraceErrors(const QList&)), + this, SLOT(slotRetraceErrors(const QList&))); connect(m_ui.vertexInterpretButton, SIGNAL(clicked()), m_vdataInterpreter, SLOT(interpretData())); @@ -721,15 +850,23 @@ void MainWindow::initConnections() connect(m_ui.actionReplay, SIGNAL(triggered()), this, SLOT(replayStart())); + connect(m_ui.actionProfile, SIGNAL(triggered()), + this, SLOT(replayProfile())); connect(m_ui.actionStop, SIGNAL(triggered()), this, SLOT(replayStop())); connect(m_ui.actionLookupState, SIGNAL(triggered()), this, SLOT(lookupState())); + connect(m_ui.actionTrim, SIGNAL(triggered()), + this, SLOT(trim())); + connect(m_ui.actionShowThumbnails, SIGNAL(triggered()), + this, SLOT(showThumbnails())); connect(m_ui.actionOptions, SIGNAL(triggered()), this, SLOT(showSettings())); - connect(m_ui.callView, SIGNAL(activated(const QModelIndex &)), + connect(m_ui.callView->selectionModel(), SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)), this, SLOT(callItemSelected(const QModelIndex &))); + connect(m_ui.callView, SIGNAL(doubleClicked(const QModelIndex &)), + this, SLOT(callItemActivated(const QModelIndex &))); connect(m_ui.callView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(customContextMenuRequested(QPoint))); @@ -761,16 +898,82 @@ void MainWindow::initConnections() connect(m_traceProcess, SIGNAL(error(const QString&)), SLOT(traceError(const QString&))); + connect(m_trimProcess, SIGNAL(trimmedFile(const QString&)), + SLOT(createdTrim(const QString&))); + connect(m_trimProcess, SIGNAL(error(const QString&)), + SLOT(trimError(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*)), + SIGNAL(itemActivated(QTreeWidgetItem*, int)), this, SLOT(slotErrorSelected(QTreeWidgetItem*))); + + connect(m_ui.actionShowProfileDialog, SIGNAL(triggered(bool)), + m_profileDialog, SLOT(show())); + connect(m_profileDialog, SIGNAL(jumpToCall(int)), + this, SLOT(slotJumpTo(int))); +} + +void MainWindow::updateActionsState(bool traceLoaded, bool stopped) +{ + if (traceLoaded) { + /* Edit */ + m_ui.actionFind ->setEnabled(true); + m_ui.actionGo ->setEnabled(true); + m_ui.actionGoFrameStart ->setEnabled(true); + m_ui.actionGoFrameEnd ->setEnabled(true); + + /* Trace */ + if (stopped) { + m_ui.actionStop->setEnabled(false); + m_ui.actionReplay->setEnabled(true); + } + else { + m_ui.actionStop->setEnabled(true); + m_ui.actionReplay->setEnabled(false); + } + + m_ui.actionProfile ->setEnabled(true); + m_ui.actionLookupState ->setEnabled(true); + m_ui.actionShowThumbnails->setEnabled(true); + m_ui.actionTrim ->setEnabled(true); + } + else { + /* Edit */ + m_ui.actionFind ->setEnabled(false); + m_ui.actionGo ->setEnabled(false); + m_ui.actionGoFrameStart ->setEnabled(false); + m_ui.actionGoFrameEnd ->setEnabled(false); + + /* Trace */ + m_ui.actionReplay ->setEnabled(false); + m_ui.actionProfile ->setEnabled(false); + m_ui.actionStop ->setEnabled(false); + m_ui.actionLookupState ->setEnabled(false); + m_ui.actionShowThumbnails->setEnabled(false); + m_ui.actionTrim ->setEnabled(false); + } +} + +void MainWindow::closeEvent(QCloseEvent * event) +{ + m_profileDialog->close(); + QMainWindow::closeEvent(event); } -void MainWindow::replayStateFound(const ApiTraceState &state) +void MainWindow::replayProfileFound(trace::Profile *profile) +{ + m_ui.actionShowProfileDialog->setEnabled(true); + m_profileDialog->setProfile(profile); + m_profileDialog->show(); + m_profileDialog->activateWindow(); + m_profileDialog->setFocus(); +} + +void MainWindow::replayStateFound(ApiTraceState *state) { m_stateEvent->setState(state); m_model->stateSetOnEvent(m_stateEvent); @@ -783,6 +986,12 @@ void MainWindow::replayStateFound(const ApiTraceState &state) m_nonDefaultsLookupEvent = 0; } +void MainWindow::replayThumbnailsFound(const QList &thumbnails) +{ + m_ui.callView->setUniformRowHeights(false); + m_trace->bindThumbnailsToFrames(thumbnails); +} + void MainWindow::slotGoTo() { m_searchWidget->hide(); @@ -791,10 +1000,7 @@ void MainWindow::slotGoTo() void MainWindow::slotJumpTo(int callNum) { - QModelIndex index = m_proxyModel->callIndex(callNum); - if (index.isValid()) { - m_ui.callView->setCurrentIndex(index); - } + m_trace->findCallIndex(callNum); } void MainWindow::createdTrace(const QString &path) @@ -811,6 +1017,21 @@ void MainWindow::traceError(const QString &msg) msg); } +void MainWindow::createdTrim(const QString &path) +{ + qDebug()<<"Done trimming "<hide(); @@ -820,103 +1041,31 @@ void MainWindow::slotSearch() 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(); - ApiTraceCall *call = 0; - - if (event->type() == ApiTraceCall::Call) - call = static_cast(event); - else { - Q_ASSERT(event->type() == ApiTraceCall::Frame); - ApiTraceFrame *frame = static_cast(event); - call = frame->call(0); - } + ApiTraceCall *call = currentCall(); + ApiTraceFrame *frame = currentFrame(); - if (!call) { - m_searchWidget->setFound(false); - return; + Q_ASSERT(call || frame); + if (!frame) { + frame = call->parentFrame(); } - const QList &calls = m_trace->calls(); - int callNum = calls.indexOf(call); + Q_ASSERT(frame); - for (int i = callNum + 1; i < calls.count(); ++i) { - ApiTraceCall *testCall = calls[i]; - 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()) { - QString txt = testCall->filterText(); - if (txt.contains(str, sensitivity)) { - m_ui.callView->setCurrentIndex(index); - m_searchWidget->setFound(true); - return; - } - } - } - m_searchWidget->setFound(false); + m_trace->findNext(frame, call, str, sensitivity); } 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(); - ApiTraceCall *call = 0; - - if (event->type() == ApiTraceCall::Call) - call = static_cast(event); - else { - Q_ASSERT(event->type() == ApiTraceCall::Frame); - ApiTraceFrame *frame = static_cast(event); - call = frame->call(0); - } + ApiTraceCall *call = currentCall(); + ApiTraceFrame *frame = currentFrame(); - if (!call) { - m_searchWidget->setFound(false); - return; + Q_ASSERT(call || frame); + if (!frame) { + frame = call->parentFrame(); } - const QList &calls = m_trace->calls(); - int callNum = calls.indexOf(call); + Q_ASSERT(frame); - for (int i = callNum - 1; i >= 0; --i) { - ApiTraceCall *testCall = calls[i]; - 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()) { - QString txt = testCall->filterText(); - if (txt.contains(str, sensitivity)) { - m_ui.callView->setCurrentIndex(index); - m_searchWidget->setFound(true); - return; - } - } - } - m_searchWidget->setFound(false); + m_trace->findPrev(frame, call, str, sensitivity); } void MainWindow::fillState(bool nonDefaults) @@ -927,24 +1076,19 @@ void MainWindow::fillState(bool nonDefaults) 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) + if (!firstFrame) { + return; + } + if (!firstFrame->isLoaded()) { + m_trace->loadFrame(firstFrame); return; + } + ApiTraceCall *firstCall = firstFrame->calls().first(); + ApiTraceEvent *oldSelected = m_selectedEvent; m_nonDefaultsLookupEvent = m_selectedEvent; - m_selectedEvent = firstFrame; + m_selectedEvent = firstCall; lookupState(); m_selectedEvent = oldSelected; } @@ -954,18 +1098,20 @@ void MainWindow::fillState(bool nonDefaults) void MainWindow::customContextMenuRequested(QPoint pos) { - QMenu menu; QModelIndex index = m_ui.callView->indexAt(pos); callItemSelected(index); - if (!index.isValid()) + if (!index.isValid()) { return; + } ApiTraceEvent *event = index.data(ApiTraceModel::EventRole).value(); - if (!event) + if (!event) { return; + } + QMenu menu; menu.addAction(QIcon(":/resources/media-record.png"), tr("Lookup state"), this, SLOT(lookupState())); if (event->type() == ApiTraceEvent::Call) { @@ -1001,47 +1147,28 @@ void MainWindow::slotSaved() void MainWindow::slotGoFrameStart() { ApiTraceFrame *frame = currentFrame(); - if (!frame || frame->isEmpty()) { - return; - } - - QList::const_iterator itr; - QList calls = frame->calls(); + ApiTraceCall *call = currentCall(); - itr = calls.constBegin(); - while (itr != calls.constEnd()) { - ApiTraceCall *call = *itr; - QModelIndex idx = m_proxyModel->indexForCall(call); - if (idx.isValid()) { - m_ui.callView->setCurrentIndex(idx); - break; - } - ++itr; + if (!frame && call) { + frame = call->parentFrame(); } + + m_trace->findFrameStart(frame); } void MainWindow::slotGoFrameEnd() { ApiTraceFrame *frame = currentFrame(); - if (!frame || frame->isEmpty()) { - return; + ApiTraceCall *call = currentCall(); + + if (!frame && call) { + frame = call->parentFrame(); } - QList::const_iterator itr; - QList calls = frame->calls(); - itr = calls.constEnd(); - do { - --itr; - ApiTraceCall *call = *itr; - QModelIndex idx = m_proxyModel->indexForCall(call); - if (idx.isValid()) { - m_ui.callView->setCurrentIndex(idx); - break; - } - } while (itr != calls.constBegin()); + m_trace->findFrameEnd(frame); } -ApiTraceFrame * MainWindow::currentFrame() const +ApiTraceFrame * MainWindow::selectedFrame() const { if (m_selectedEvent) { if (m_selectedEvent->type() == ApiTraceEvent::Frame) { @@ -1055,28 +1182,28 @@ ApiTraceFrame * MainWindow::currentFrame() const return NULL; } -void MainWindow::slotTraceChanged(ApiTraceCall *call) +void MainWindow::slotTraceChanged(ApiTraceEvent *event) { - Q_ASSERT(call); - if (call == m_selectedEvent) { - m_ui.detailsWebView->setHtml(call->toHtml()); + Q_ASSERT(event); + if (event == m_selectedEvent) { + if (event->type() == ApiTraceEvent::Call) { + ApiTraceCall *call = static_cast(event); + m_ui.detailsWebView->setHtml(call->toHtml()); + } } } -void MainWindow::slotRetraceErrors(const QList &errors) +void MainWindow::slotRetraceErrors(const QList &errors) { m_ui.errorsTreeWidget->clear(); - foreach(RetraceError error, errors) { - ApiTraceCall *call = m_trace->callWithIndex(error.callIndex); - if (!call) - continue; - call->setError(error.message); + foreach(ApiTraceError error, errors) { + m_trace->setCallError(error); QTreeWidgetItem *item = new QTreeWidgetItem(m_ui.errorsTreeWidget); item->setData(0, Qt::DisplayRole, error.callIndex); - item->setData(0, Qt::UserRole, QVariant::fromValue(call)); + item->setData(0, Qt::UserRole, error.callIndex); QString type = error.type; type[0] = type[0].toUpper(); item->setData(1, Qt::DisplayRole, type); @@ -1087,25 +1214,230 @@ void MainWindow::slotRetraceErrors(const QList &errors) void MainWindow::slotErrorSelected(QTreeWidgetItem *current) { if (current) { - ApiTraceCall *call = - current->data(0, Qt::UserRole).value(); - Q_ASSERT(call); + int callIndex = + current->data(0, Qt::UserRole).toInt(); + m_trace->findCallIndex(callIndex); + } +} + +ApiTraceCall * MainWindow::selectedCall() const +{ + if (m_selectedEvent && + m_selectedEvent->type() == ApiTraceEvent::Call) { + return static_cast(m_selectedEvent); + } + return NULL; +} + +void MainWindow::saveSelectedSurface() +{ + QTreeWidgetItem *item = + m_ui.surfacesTreeWidget->currentItem(); + + if (!item || !m_trace) { + return; + } + + QVariant var = item->data(0, Qt::UserRole); + QImage img = var.value(); + + QString imageIndex; + if (selectedCall()) { + imageIndex = tr("_call_%1") + .arg(selectedCall()->index()); + } else if (selectedFrame()) { + ApiTraceCall *firstCall = selectedFrame()->call(0); + if (firstCall) { + imageIndex = tr("_frame_%1") + .arg(firstCall->index()); + } else { + qDebug()<<"unknown frame number"; + imageIndex = tr("_frame_%1") + .arg(firstCall->index()); + } + } + + //which of the surfaces are we saving + QTreeWidgetItem *parent = item->parent(); + int parentIndex = + m_ui.surfacesTreeWidget->indexOfTopLevelItem(parent); + if (parentIndex < 0) { + parentIndex = 0; + } + int childIndex = 0; + if (parent) { + childIndex = parent->indexOfChild(item); + } else { + childIndex = m_ui.surfacesTreeWidget->indexOfTopLevelItem(item); + } + + + QString fileName = + tr("%1%2-%3_%4.png") + .arg(m_trace->fileName()) + .arg(imageIndex) + .arg(parentIndex) + .arg(childIndex); + //qDebug()<<"save "<showMessage( tr("Saved '%1'").arg(fileName), 5000); +} + +void MainWindow::loadProgess(int percent) +{ + m_progressBar->setValue(percent); +} + +void MainWindow::slotSearchResult(const ApiTrace::SearchRequest &request, + ApiTrace::SearchResult result, + ApiTraceCall *call) +{ + switch (result) { + case ApiTrace::SearchResult_NotFound: + m_searchWidget->setFound(false); + break; + case ApiTrace::SearchResult_Found: { QModelIndex index = m_proxyModel->indexForCall(call); + if (index.isValid()) { m_ui.callView->setCurrentIndex(index); + m_searchWidget->setFound(true); } else { - statusBar()->showMessage(tr("Call has been filtered out.")); + //call is filtered out, so continue searching but from the + // filtered call + if (!call) { + qDebug()<<"Error: search success with no call"; + return; + } +// qDebug()<<"filtered! search from "<searchText() +// <<", call idx = "<index(); + + if (request.direction == ApiTrace::SearchRequest::Next) { + m_trace->findNext(call->parentFrame(), call, + request.text, request.cs); + } else { + m_trace->findNext(call->parentFrame(), call, + request.text, request.cs); + } } } + break; + case ApiTrace::SearchResult_Wrapped: + m_searchWidget->setFound(false); + break; + } +} + +ApiTraceFrame * MainWindow::currentFrame() const +{ + 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"; + return 0; + } + } + + event = index.data(ApiTraceModel::EventRole).value(); + Q_ASSERT(event); + if (!event) { + return 0; + } + + ApiTraceFrame *frame = 0; + if (event->type() == ApiTraceCall::Frame) { + frame = static_cast(event); + } + return frame; } ApiTraceCall * MainWindow::currentCall() const { - if (m_selectedEvent && - m_selectedEvent->type() == ApiTraceEvent::Call) { - return static_cast(m_selectedEvent); + 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"; + return 0; + } + } + + event = index.data(ApiTraceModel::EventRole).value(); + Q_ASSERT(event); + if (!event) { + return 0; + } + + ApiTraceCall *call = 0; + if (event->type() == ApiTraceCall::Call) { + call = static_cast(event); + } + + return call; + +} + +void MainWindow::slotFoundFrameStart(ApiTraceFrame *frame) +{ + Q_ASSERT(frame->isLoaded()); + if (!frame || frame->isEmpty()) { + return; + } + + QVector::const_iterator itr; + QVector calls = frame->calls(); + + itr = calls.constBegin(); + while (itr != calls.constEnd()) { + ApiTraceCall *call = *itr; + QModelIndex idx = m_proxyModel->indexForCall(call); + if (idx.isValid()) { + m_ui.callView->setCurrentIndex(idx); + m_ui.callView->scrollTo(idx, QAbstractItemView::PositionAtTop); + break; + } + ++itr; + } +} + +void MainWindow::slotFoundFrameEnd(ApiTraceFrame *frame) +{ + Q_ASSERT(frame->isLoaded()); + if (!frame || frame->isEmpty()) { + return; + } + QVector::const_iterator itr; + QVector calls = frame->calls(); + + itr = calls.constEnd(); + do { + --itr; + ApiTraceCall *call = *itr; + QModelIndex idx = m_proxyModel->indexForCall(call); + if (idx.isValid()) { + m_ui.callView->setCurrentIndex(idx); + m_ui.callView->scrollTo(idx, QAbstractItemView::PositionAtBottom); + break; + } + } while (itr != calls.constBegin()); +} + +void MainWindow::slotJumpToResult(ApiTraceCall *call) +{ + QModelIndex idx = m_proxyModel->indexForCall(call); + if (idx.isValid()) { + activateWindow(); + m_ui.callView->setFocus(); + m_ui.callView->setCurrentIndex(idx); + m_ui.callView->scrollTo(idx, QAbstractItemView::PositionAtCenter); + } else { + statusBar()->showMessage(tr("Call has been filtered out.")); } - return NULL; } #include "mainwindow.moc"