Files
DRAMSys/extensions/apps/traceAnalyzer/presentation/traceplot.cpp
2023-05-25 15:15:52 +02:00

931 lines
32 KiB
C++

/*
* Copyright (c) 2015, RPTU Kaiserslautern-Landau
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors:
* Janik Schlemminger
* Robert Gernhardt
* Matthias Jung
* Derek Christ
* Iron Prando da Silva
*/
#include "traceplot.h"
#include "businessObjects/commentmodel.h"
#include "businessObjects/traceplotlinemodel.h"
#include "gototimedialog.h"
#include "tracePlotMouseLabel.h"
#include "tracedrawing.h"
#include "util/clkgrid.h"
#include "util/customlabelscaledraw.h"
#include "util/engineeringScaleDraw.h"
#include <QFileInfo>
#include <QInputDialog>
#include <QItemSelectionModel>
#include <QKeySequence>
#include <QMenu>
#include <QMessageBox>
#include <QMouseEvent>
#include <QPushButton>
#include <QWheelEvent>
#include <cmath>
#include <iostream>
#include <qfiledialog.h>
#include <qwt_plot_grid.h>
#include <qwt_plot_renderer.h>
TracePlot::TracePlot(QWidget *parent):
QwtPlot(parent), isInitialized(false),
customLabelScaleDraw(new CustomLabelScaleDraw(drawingProperties.getLabels()))
{
canvas()->setCursor(Qt::ArrowCursor);
setUpActions();
}
void TracePlot::init(TraceNavigator *navigator, QScrollBar *scrollBar, TracePlotLineDataSource *tracePlotLineDataSource,
CommentModel *commentModel)
{
Q_ASSERT(isInitialized == false);
isInitialized = true;
this->navigator = navigator;
this->scrollBar = scrollBar;
this->commentModel = commentModel;
this->tracePlotLineDataSource = tracePlotLineDataSource;
installEventFilter(commentModel);
QObject::connect(commentModel, &CommentModel::dataChanged, this, &TracePlot::commentsChanged);
QObject::connect(commentModel, &CommentModel::rowsRemoved, this, &TracePlot::commentsChanged);
QObject::connect(commentModel->selectionModel(), &QItemSelectionModel::selectionChanged, this,
&TracePlot::commentsChanged);
auto selectedTracePlotLineModel = tracePlotLineDataSource->getSelectedModel();
QObject::connect(selectedTracePlotLineModel, &QAbstractItemModel::rowsInserted, this,
&TracePlot::recreateCollapseButtons);
QObject::connect(selectedTracePlotLineModel, &QAbstractItemModel::rowsRemoved, this,
&TracePlot::recreateCollapseButtons);
connectNavigatorQ_SIGNALS();
setUpDrawingProperties();
setUpAxis();
setUpGrid();
setUpTracePlotItem();
setUpZoom();
setUpQueryEditor();
mouseLabel = new TracePlotMouseLabel(this, navigator->GeneralTraceInfo().clkPeriod, this->mouseDownData.zoomSpan);
getAndDrawComments();
setZoomLevel(1000);
updateScrollbar();
recreateCollapseButtons();
dependenciesSubMenu->setEnabled(navigator->TraceFile().checkDependencyTableExists());
replot();
}
void TracePlot::setUpActions()
{
insertComment = new QAction("Insert comment", this);
QObject::connect(insertComment, SIGNAL(triggered()), this,
SLOT(on_insertComment()));
goToTime = new QAction("Go to time", this);
QObject::connect(goToTime, SIGNAL(triggered()), this, SLOT(on_goToTime()));
goToTransaction = new QAction("Go to transaction", this);
QObject::connect(goToTransaction, SIGNAL(triggered()), this,
SLOT(on_goToTransaction()));
deselectAll = new QAction("Deselect all", this);
QObject::connect(deselectAll, SIGNAL(triggered()), this,
SLOT(on_deselectAll()));
goToPhase = new QAction("Go to phase", this);
QObject::connect(goToPhase, SIGNAL(triggered()), this, SLOT(on_goToPhase()));
showQueryEditor = new QAction("Execute query", this);
showQueryEditor->setShortcut(QKeySequence("ctrl+e"));
addAction(showQueryEditor);
QObject::connect(showQueryEditor, SIGNAL(triggered()), this,
SLOT(on_executeQuery()));
selectNextRefresh = new QAction("Select next refresh", this);
addAction(selectNextRefresh);
QObject::connect(selectNextRefresh, SIGNAL(triggered()), this,
SLOT(on_selectNextRefresh()));
selectNextActivate = new QAction("Select next activate", this);
addAction(selectNextActivate);
QObject::connect(selectNextActivate, SIGNAL(triggered()), this,
SLOT(on_selectNextActivate()));
selectNextPrecharge = new QAction("Select next precharge", this);
addAction(selectNextPrecharge);
QObject::connect(selectNextPrecharge, SIGNAL(triggered()), this,
SLOT(on_selectNextPrecharge()));
selectNextCommand = new QAction("Select next command", this);
addAction(selectNextCommand);
QObject::connect(selectNextCommand, SIGNAL(triggered()), this,
SLOT(on_selectNextCommand()));
// selectNextActb = new QAction("Select next atcb", this);
// selectNextActb->setShortcut(QKeySequence("alt+b"));
// addAction(selectNextActb);
// QObject::connect(selectNextActb, SIGNAL(triggered()), this,
// SLOT(on_selectNextActb()));
//
// selectNextPreb = new QAction("Select next preb", this);
// selectNextPreb->setShortcut(QKeySequence("alt+q"));
// addAction(selectNextPreb);
// QObject::connect(selectNextPreb, SIGNAL(triggered()), this,
// SLOT(on_selectNextPreb()));
//
// selectNextRefb = new QAction("Select next refb", this);
// selectNextRefb->setShortcut(QKeySequence("alt+s"));
// addAction(selectNextRefb);
// QObject::connect(selectNextRefb, SIGNAL(triggered()), this,
// SLOT(on_selectNextRefb()));
setColorGroupingPhase = new QAction("Group by Phase", this);
setColorGroupingPhase->setCheckable(true);
setColorGroupingPhase->setChecked(true);
addAction(setColorGroupingPhase);
QObject::connect(setColorGroupingPhase, SIGNAL(triggered()), this,
SLOT(on_colorGroupingPhase()));
setColorGroupingTransaction = new QAction("Group by Transaction", this);
setColorGroupingTransaction->setCheckable(true);
addAction(setColorGroupingTransaction);
QObject::connect(setColorGroupingTransaction, SIGNAL(triggered()), this,
SLOT(on_colorGroupingTransaction()));
setColorGroupingRainbowTransaction = new QAction("Group by Transaction - Rainbow Colored", this);
setColorGroupingRainbowTransaction->setCheckable(true);
addAction(setColorGroupingRainbowTransaction);
QObject::connect(setColorGroupingRainbowTransaction, SIGNAL(triggered()), this,
SLOT(on_colorGroupingRainbowTransaction()));
setColorGroupingThread = new QAction("Group by Thread", this);
setColorGroupingThread->setCheckable(true);
addAction(setColorGroupingThread);
QObject::connect(setColorGroupingThread, SIGNAL(triggered()), this,
SLOT(on_colorGroupingThread()));
QActionGroup *colorGroupingGroup = new QActionGroup(this);
colorGroupingGroup->addAction(setColorGroupingPhase);
colorGroupingGroup->addAction(setColorGroupingTransaction);
colorGroupingGroup->addAction(setColorGroupingRainbowTransaction);
colorGroupingGroup->addAction(setColorGroupingThread);
exportToPdf = new QAction("Export to SVG", this);
addAction(exportToPdf);
QObject::connect(exportToPdf, SIGNAL(triggered()), this,
SLOT(on_exportToPDF()));
toggleCollapsedState = new ToggleCollapsedAction(this);
addAction(toggleCollapsedState);
QObject::connect(toggleCollapsedState, SIGNAL(triggered()), this,
SLOT(on_toggleCollapsedState()));
toggleCollapsedState->setShortcut(Qt::CTRL + Qt::Key_X);
disabledDependencies = new QAction("Disabled", this);
selectedDependencies = new QAction("Selected transactions", this);
allDependencies = new QAction("All transactions", this);
switchDrawDependencyTextsOption = new QAction("Draw Texts", this);
disabledDependencies->setCheckable(true);
selectedDependencies->setCheckable(true);
allDependencies->setCheckable(true);
switchDrawDependencyTextsOption->setCheckable(true);
switchDrawDependencyTextsOption->setChecked(true);
disabledDependencies->setChecked(true);
QObject::connect(disabledDependencies, &QAction::triggered, this, [&]() {
drawingProperties.drawDependenciesOption.draw = DependencyOption::Disabled;
currentTraceTimeChanged();
});
QObject::connect(selectedDependencies, &QAction::triggered, this, [&]() {
drawingProperties.drawDependenciesOption.draw = DependencyOption::Selected;
currentTraceTimeChanged();
});
QObject::connect(allDependencies, &QAction::triggered, this, [&]() {
drawingProperties.drawDependenciesOption.draw = DependencyOption::All;
currentTraceTimeChanged();
});
QObject::connect(switchDrawDependencyTextsOption, &QAction::triggered, this, [&]() {
if (drawingProperties.drawDependenciesOption.text == DependencyTextOption::Disabled)
{
drawingProperties.drawDependenciesOption.text = DependencyTextOption::Enabled;
switchDrawDependencyTextsOption->setChecked(true);
}
else
{
drawingProperties.drawDependenciesOption.text = DependencyTextOption::Disabled;
switchDrawDependencyTextsOption->setChecked(false);
}
currentTraceTimeChanged();
});
QActionGroup *dependenciesGroup = new QActionGroup(this);
dependenciesGroup->addAction(disabledDependencies);
dependenciesGroup->addAction(selectedDependencies);
dependenciesGroup->addAction(allDependencies);
setUpContextMenu();
}
void TracePlot::setUpContextMenu()
{
contextMenu = new QMenu(this);
contextMenu->addActions({deselectAll});
QMenu *colorGroupingSubMenu = new QMenu("Group by", contextMenu);
colorGroupingSubMenu->addActions(
{setColorGroupingPhase, setColorGroupingTransaction, setColorGroupingRainbowTransaction, setColorGroupingThread});
contextMenu->addMenu(colorGroupingSubMenu);
dependenciesSubMenu = new QMenu("Show dependencies", contextMenu);
dependenciesSubMenu->addActions(
{disabledDependencies, selectedDependencies, allDependencies, switchDrawDependencyTextsOption});
contextMenu->addMenu(dependenciesSubMenu);
QMenu *goToSubMenu = new QMenu("Go to", contextMenu);
goToSubMenu->addActions({goToPhase, goToTransaction, goToTime});
contextMenu->addMenu(goToSubMenu);
QMenu *selectSubMenu = new QMenu("Select", contextMenu);
selectSubMenu->addActions({selectNextRefresh, selectNextActivate, selectNextPrecharge, selectNextCommand /*, selectNextActb, selectNextPreb, selectNextRefb */});
contextMenu->addMenu(selectSubMenu);
contextMenu->addActions({showQueryEditor, insertComment, exportToPdf, toggleCollapsedState});
}
void TracePlot::connectNavigatorQ_SIGNALS()
{
QObject::connect(navigator, SIGNAL(currentTraceTimeChanged()), this,
SLOT(currentTraceTimeChanged()));
QObject::connect(navigator, SIGNAL(selectedTransactionsChanged()), this,
SLOT(selectedTransactionsChanged()));
}
void TracePlot::setUpDrawingProperties()
{
connect(this, &TracePlot::tracePlotLinesChanged, &drawingProperties, &TraceDrawingProperties::updateLabels);
connect(&drawingProperties, &TraceDrawingProperties::labelsUpdated, this, &TracePlot::updateScrollbar);
drawingProperties.init(tracePlotLineDataSource);
drawingProperties.textColor = palette().text().color();
drawingProperties.numberOfRanks = navigator->GeneralTraceInfo().numberOfRanks;
drawingProperties.numberOfBankGroups = navigator->GeneralTraceInfo().numberOfBankGroups;
drawingProperties.numberOfBanks = navigator->GeneralTraceInfo().numberOfBanks;
drawingProperties.banksPerRank = navigator->GeneralTraceInfo().banksPerRank;
drawingProperties.groupsPerRank = navigator->GeneralTraceInfo().groupsPerRank;
drawingProperties.banksPerGroup = navigator->GeneralTraceInfo().banksPerGroup;
drawingProperties.per2BankOffset = navigator->GeneralTraceInfo().per2BankOffset;
}
void TracePlot::setUpQueryEditor()
{
queryEditor = new QueryEditor(this);
queryEditor->setWindowFlags(Qt::Window);
queryEditor->setWindowTitle("Query " + QFileInfo(
navigator->TraceFile().getPathToDB()).baseName());
queryEditor->init(navigator);
}
void TracePlot::setUpTracePlotItem()
{
tracePlotItem = new TracePlotItem(transactions, *navigator, drawingProperties);
tracePlotItem->setZ(1);
tracePlotItem->attach(this);
}
void TracePlot::setUpGrid()
{
unsigned int clk = navigator->GeneralTraceInfo().clkPeriod;
QwtPlotGrid *grid = new ClkGrid(clk, GridVisiblityClks * clk);
grid->setZ(0);
grid->attach(this);
}
void TracePlot::setUpZoom()
{
minZoomLevel = minZoomClks * navigator->GeneralTraceInfo().clkPeriod;
maxZoomLevel = maxZoomClks * navigator->GeneralTraceInfo().clkPeriod;
textVisibilityZoomLevel = textVisibilityClks *
navigator->GeneralTraceInfo().clkPeriod;
zoomZone = new QwtPlotZoneItem();
zoomZone->setZ(2);
zoomZone->attach(this);
zoomZone->setVisible(false);
}
void TracePlot::updateScrollbar()
{
// The maximum number of displayed lines determined by the pageStep of the scroll bar.
const unsigned int maxDisplayedLines = scrollBar->pageStep();
const int maximum = drawingProperties.getNumberOfDisplayedLines() - maxDisplayedLines - 1;
if (maximum >= 0)
{
scrollBar->setMaximum(maximum);
scrollBar->show();
}
else
scrollBar->hide();
verticalScrollbarChanged(scrollBar->value());
}
void TracePlot::verticalScrollbarChanged(int value)
{
const int yMax = drawingProperties.getNumberOfDisplayedLines() - 1;
if (scrollBar->isHidden())
{
setAxisScale(yLeft, -1, yMax + 1, 1.0);
}
else
{
setAxisScale(yLeft, scrollBar->maximum() - 1 - value, yMax + 1 - value, 1.0);
}
replot();
}
void TracePlot::setUpAxis()
{
// Set up y axis.
setAxisScaleDraw(yLeft, customLabelScaleDraw);
customLabelScaleDraw->setMinimumExtent(135.0);
// Set up x axis.
setAxisTitle(xBottom, "Time in ns");
setAxisScaleDraw(xBottom, new EngineeringScaleDraw);
}
void TracePlot::updateToggleCollapsedAction()
{
ToggleCollapsedAction::CollapsedState state = getCollapsedState();
toggleCollapsedState->updateCollapsedState(state);
}
Timespan TracePlot::GetCurrentTimespan()
{
Timespan span(navigator->CurrentTraceTime() - zoomLevel / 2,
navigator->CurrentTraceTime() + zoomLevel / 2);
if (span.Begin() < 0)
span.shift(-span.Begin());
else if (span.End() > navigator->GeneralTraceInfo().span.End())
span.shift(navigator->GeneralTraceInfo().span.End() - span.End());
return span;
}
ToggleCollapsedAction::CollapsedState TracePlot::getCollapsedState() const
{
using CollapsedState = ToggleCollapsedAction::CollapsedState;
CollapsedState state = CollapsedState::Collapsed;
unsigned int notCollapsedCount = 0;
unsigned int rankCount = 0;
auto selectedModel = tracePlotLineDataSource->getSelectedModel();
for (unsigned int i = 0; i < selectedModel->rowCount(); i++)
{
QModelIndex index = selectedModel->index(i, 0);
auto type = static_cast<AbstractTracePlotLineModel::LineType>(
selectedModel->data(index, AbstractTracePlotLineModel::TypeRole).toInt());
if (type != AbstractTracePlotLineModel::RankGroup)
continue;
bool isCollapsed = selectedModel->data(index, AbstractTracePlotLineModel::CollapsedRole).toBool();
if (!isCollapsed)
{
notCollapsedCount++;
state = CollapsedState::Mixed;
}
rankCount++;
}
if (notCollapsedCount == rankCount)
state = CollapsedState::Expanded;
return state;
}
void TracePlot::collapseOrExpandAllRanks(ToggleCollapsedAction::CollapseAction collapseAction)
{
using CollapseAction = ToggleCollapsedAction::CollapseAction;
auto selectedModel = tracePlotLineDataSource->getSelectedModel();
for (unsigned int i = 0; i < selectedModel->rowCount(); i++)
{
QModelIndex index = selectedModel->index(i, 0);
auto type = static_cast<AbstractTracePlotLineModel::LineType>(
selectedModel->data(index, AbstractTracePlotLineModel::TypeRole).toInt());
if (type != AbstractTracePlotLineModel::RankGroup)
continue;
switch (collapseAction)
{
case CollapseAction::CollapseAllRanks:
selectedModel->setData(index, true, AbstractTracePlotLineModel::CollapsedRole);
break;
case CollapseAction::ExpandAllRanks:
selectedModel->setData(index, false, AbstractTracePlotLineModel::CollapsedRole);
break;
}
}
recreateCollapseButtons();
}
void TracePlot::getAndDrawComments()
{
QList<QModelIndex> selectedRows = commentModel->selectionModel()->selectedRows();
for (int row = 0; row < commentModel->rowCount(); row++)
{
QModelIndex timeIndex = commentModel->index(row, static_cast<int>(CommentModel::Column::Time));
QModelIndex textIndex = commentModel->index(row, static_cast<int>(CommentModel::Column::Comment));
bool selected = std::find(selectedRows.begin(), selectedRows.end(), commentModel->index(row, 0)) != selectedRows.end();
QwtPlotMarker *marker = new QwtPlotMarker();
marker->setLabel(textIndex.data().toString());
marker->setLabelOrientation(Qt::Vertical);
marker->setLabelAlignment(Qt::AlignLeft | Qt::AlignBottom);
marker->setXValue(static_cast<double>(timeIndex.data(Qt::UserRole).toLongLong()));
marker->setLineStyle(QwtPlotMarker::LineStyle::VLine);
marker->setLinePen(QColor(selected ? Qt::red : Qt::blue), 2);
marker->attach(this);
}
}
CustomLabelScaleDraw *TracePlot::getCustomLabelScaleDraw() const
{
return customLabelScaleDraw;
}
const TraceDrawingProperties &TracePlot::getDrawingProperties() const
{
return drawingProperties;
}
void TracePlot::enterZoomMode()
{
mouseDownData.mouseIsDownForZooming = true;
mouseLabel->setMode(MouseLabelMode::Timedifference);
zoomZone->setVisible(true);
zoomZone->setInterval(mouseDownData.zoomSpan.Begin(),
mouseDownData.zoomSpan.End());
}
void TracePlot::exitZoomMode()
{
mouseDownData.mouseIsDownForZooming = false;
mouseLabel->setMode(MouseLabelMode::AbsoluteTime);
zoomZone->setVisible(false);
}
void TracePlot::zoomIn(traceTime zoomCenter)
{
setZoomLevel(zoomLevel * zoomFactor);
traceTime time = zoomCenter + (GetCurrentTimespan().Middle() - zoomCenter) *
zoomFactor;
Q_EMIT tracePlotZoomChanged();
navigator->navigateToTime(time);
}
void TracePlot::zoomOut(traceTime zoomCenter)
{
setZoomLevel(zoomLevel / zoomFactor);
Q_EMIT tracePlotZoomChanged();
navigator->navigateToTime(static_cast<traceTime>(zoomCenter +
(GetCurrentTimespan().Middle() - zoomCenter) / zoomFactor));
}
traceTime TracePlot::ZoomLevel() const
{
return zoomLevel;
}
void TracePlot::setZoomLevel(traceTime newZoomLevel)
{
zoomLevel = newZoomLevel;
if (zoomLevel < minZoomLevel)
zoomLevel = minZoomLevel;
if (zoomLevel > navigator->GeneralTraceInfo().span.timeCovered())
zoomLevel = navigator->GeneralTraceInfo().span.timeCovered();
if (zoomLevel > maxZoomLevel)
zoomLevel = maxZoomLevel;
if (zoomLevel < textVisibilityZoomLevel)
drawingProperties.drawText = true;
if (zoomLevel > textVisibilityZoomLevel)
drawingProperties.drawText = false;
}
/* Q_SLOTS
*
*
*/
void TracePlot::recreateCollapseButtons()
{
drawingProperties.updateLabels();
auto selectedModel = tracePlotLineDataSource->getSelectedModel();
selectedModel->recreateCollapseButtons(this, customLabelScaleDraw);
}
void TracePlot::currentTraceTimeChanged()
{
bool drawDependencies = getDrawingProperties().drawDependenciesOption.draw != DependencyOption::Disabled;
transactions = navigator->TraceFile().getTransactionsInTimespan(GetCurrentTimespan(), drawDependencies);
if (drawDependencies)
{
navigator->TraceFile().updateDependenciesInTimespan(GetCurrentTimespan());
}
setAxisScale(xBottom, GetCurrentTimespan().Begin(), GetCurrentTimespan().End());
dependenciesSubMenu->setEnabled(navigator->TraceFile().checkDependencyTableExists());
replot();
}
void TracePlot::selectedTransactionsChanged()
{
replot();
}
void TracePlot::commentsChanged()
{
detachItems(QwtPlotItem::Rtti_PlotMarker);
getAndDrawComments();
replot();
}
void TracePlot::on_executeQuery()
{
queryEditor->show();
}
void TracePlot::on_selectNextRefresh()
{
traceTime time = invTransform(xBottom, contextMenuMouseDown.x());
navigator->selectNextRefresh(time);
}
void TracePlot::on_selectNextActivate()
{
traceTime time = invTransform(xBottom, contextMenuMouseDown.x());
navigator->selectNextActivate(time);
}
void TracePlot::on_selectNextPrecharge()
{
traceTime time = invTransform(xBottom, contextMenuMouseDown.x());
navigator->selectNextPrecharge(time);
}
void TracePlot::on_selectNextCommand()
{
traceTime time = invTransform(xBottom, contextMenuMouseDown.x());
navigator->selectNextCommand(time);
}
// void TracePlot::on_selectNextActb()
// {
// navigator->selectNextActb();
// }
//
// void TracePlot::on_selectNextPreb()
// {
// navigator->selectNextPreb();
// }
//
// void TracePlot::on_selectNextRefb()
// {
// navigator->selectNextRefb();
// }
void TracePlot::on_colorGroupingPhase()
{
drawingProperties.colorGrouping = ColorGrouping::PhaseType;
Q_EMIT(colorGroupingChanged(ColorGrouping::PhaseType));
replot();
}
void TracePlot::on_colorGroupingTransaction()
{
drawingProperties.colorGrouping = ColorGrouping::Transaction;
Q_EMIT(colorGroupingChanged(ColorGrouping::Transaction));
replot();
}
void TracePlot::on_colorGroupingRainbowTransaction()
{
drawingProperties.colorGrouping = ColorGrouping::RainbowTransaction;
Q_EMIT(colorGroupingChanged(ColorGrouping::RainbowTransaction));
replot();
}
void TracePlot::on_colorGroupingThread()
{
drawingProperties.colorGrouping = ColorGrouping::Thread;
Q_EMIT(colorGroupingChanged(ColorGrouping::Thread));
replot();
}
void TracePlot::on_goToTransaction()
{
bool ok;
int maxID = navigator->GeneralTraceInfo().numberOfTransactions;
int transactionID = QInputDialog::getInt(this, "Go to transaction",
"Enter transaction ID (1 - " + QString::number(maxID) + ")", 0, 1, maxID, 1,
&ok);
if (ok) {
navigator->clearSelectedTransactions();
navigator->selectTransaction(transactionID);
}
}
void TracePlot::on_goToPhase()
{
bool ok;
int maxID = navigator->GeneralTraceInfo().numberOfPhases;
int phaseID = QInputDialog::getInt(this, "Go to phase",
"Enter phase ID (1 - " + QString::number(maxID) + ")", 0, 1, maxID, 1, &ok);
if (ok) {
navigator->clearSelectedTransactions();
navigator->selectTransaction(navigator->TraceFile().getTransactionIDFromPhaseID(
phaseID));
}
}
void TracePlot::on_deselectAll()
{
navigator->clearSelectedTransactions();
}
void TracePlot::on_insertComment()
{
traceTime time = invTransform(xBottom, contextMenuMouseDown.x());
commentModel->addComment(time);
}
void TracePlot::on_goToTime()
{
double goToTime;
GoToTimeDialog dialog(&goToTime, this);
int dialogCode = dialog.exec();
if (dialogCode == QDialog::Accepted) {
traceTime time = static_cast<traceTime>(goToTime) * 1000;
navigator->navigateToTime(time);
}
}
void TracePlot::on_exportToPDF()
{
QwtPlotRenderer renderer;
QString filename = QFileDialog::getSaveFileName(this, "Export to SVG", "",
"Portable Document Format(*.svg)");
if (filename != "") {
QBrush saved = this->canvasBackground();
this->setCanvasBackground(QBrush(Qt::white));
renderer.renderDocument(this, filename, "svg", QSizeF(this->widthMM(),
this->heightMM()));
this->setCanvasBackground(QBrush(saved));
}
}
void TracePlot::on_toggleCollapsedState()
{
collapseOrExpandAllRanks(toggleCollapsedState->getCollapseAction());
updateToggleCollapsedAction();
}
/* Keyboard and mouse events
*
*
*/
void TracePlot::keyPressEvent(QKeyEvent *keyPressedEvent)
{
int key = keyPressedEvent->key();
if (Qt::Key_Control == key)
keyPressData.ctrlPressed = true;
else if (Qt::Key_Shift == key)
keyPressData.shiftPressed = true;
else if (Qt::Key_Right == key)
navigator->selectNextTransaction();
else if (Qt::Key_Left == key)
navigator->selectPreviousTransaction();
else if (Qt::Key_Minus == key) {
zoomOut(GetCurrentTimespan().Middle());
} else if (Qt::Key_Plus == key) {
zoomIn(GetCurrentTimespan().Middle());
}
}
void TracePlot::keyReleaseEvent(QKeyEvent *keyReleasedEvent)
{
int key = keyReleasedEvent->key();
if (Qt::Key_Control == key)
keyPressData.ctrlPressed = false;
else if (Qt::Key_Shift == key) {
keyPressData.shiftPressed = false;
exitZoomMode();
replot();
}
}
bool TracePlot::eventFilter(QObject *object, QEvent *event)
{
if (object == canvas()) {
switch (event->type()) {
case QEvent::Wheel : {
QWheelEvent *wheelEvent = static_cast<QWheelEvent *>(event);
traceTime zoomCenter = static_cast<traceTime>(this->invTransform(xBottom,
wheelEvent->position().x()));
(wheelEvent->angleDelta().y() > 0) ? zoomIn(zoomCenter) : zoomOut(zoomCenter);
return true;
}
case QEvent::MouseButtonPress: {
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
if (mouseEvent->button() == Qt::LeftButton) {
if (keyPressData.shiftPressed) {
mouseDownData.zoomSpan.setBegin(alignToClk(invTransform(xBottom,
mouseEvent->x()), navigator->GeneralTraceInfo().clkPeriod));
mouseDownData.zoomSpan.setEnd(alignToClk(invTransform(xBottom, mouseEvent->x()),
navigator->GeneralTraceInfo().clkPeriod));
enterZoomMode();
} else {
mouseDownData.mouseDownX = mouseEvent->x();
mouseDownData.mouseDownTime = GetCurrentTimespan().Middle();
mouseDownData.mouseIsDownForDragging = true;
canvas()->setCursor(Qt::ClosedHandCursor);
SelectTransaction(mouseEvent->x(), mouseEvent->y());
SelectComment(mouseEvent->x());
}
return true;
} else if (mouseEvent->button() == Qt::RightButton) {
// Also select comments to make it more obvious.
SelectComment(mouseEvent->x());
openContextMenu(this->canvas()->mapToGlobal(mouseEvent->pos()),
mouseEvent->pos());
return true;
}
break;
}
case QEvent::MouseButtonRelease: {
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
if (mouseEvent->button() == Qt::LeftButton) {
if (mouseDownData.mouseIsDownForDragging) {
mouseDownData.mouseIsDownForDragging = false;
canvas()->setCursor(Qt::ArrowCursor);
return true;
} else if (mouseDownData.mouseIsDownForZooming) {
exitZoomMode();
traceTime newCenter = mouseDownData.zoomSpan.Middle();
setZoomLevel(mouseDownData.zoomSpan.timeCovered());
navigator->navigateToTime(newCenter);
replot();
return true;
}
}
break;
}
case QEvent::MouseMove: {
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
if (mouseDownData.mouseIsDownForDragging) {
traceTime deltaTime = invTransform(xBottom,
mouseDownData.mouseDownX) - invTransform(xBottom, mouseEvent->x());
navigator->navigateToTime(mouseDownData.mouseDownTime + deltaTime);
return true;
} else if (mouseDownData.mouseIsDownForZooming) {
mouseDownData.zoomSpan.setEnd(alignToClk(invTransform(xBottom, mouseEvent->x()),
navigator->GeneralTraceInfo().clkPeriod));
if (mouseDownData.zoomSpan.Begin() < mouseDownData.zoomSpan.End())
zoomZone->setInterval(mouseDownData.zoomSpan.Begin(),
mouseDownData.zoomSpan.End());
else
zoomZone->setInterval(mouseDownData.zoomSpan.End(),
mouseDownData.zoomSpan.Begin());
replot();
}
break;
}
default:
break;
}
}
return false;
}
void TracePlot::SelectTransaction(int x, int y) const
{
double yVal = invTransform(yLeft, y);
Timespan timespan = hoveredTimespan(x);
auto selectedTransactions = tracePlotItem->getSelectedTransactions(timespan, yVal);
if (selectedTransactions.size() > 0)
{
if (!keyPressData.ctrlPressed)
navigator->clearSelectedTransactions();
navigator->addSelectedTransactions(selectedTransactions);
}
}
void TracePlot::SelectComment(int x) const
{
Timespan timespan = hoveredTimespan(x);
QModelIndex index = commentModel->hoveredComment(timespan);
if (!index.isValid())
return;
if (keyPressData.ctrlPressed)
commentModel->selectionModel()->setCurrentIndex(index, QItemSelectionModel::Toggle | QItemSelectionModel::Rows);
else
commentModel->selectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
}
Timespan TracePlot::hoveredTimespan(int x) const
{
traceTime time = invTransform(xBottom, x);
traceTime offset = 0.005 * zoomLevel;
return Timespan(time - offset, time + offset);
}
void TracePlot::openContextMenu(const QPoint &pos, const QPoint &mouseDown)
{
contextMenuMouseDown = mouseDown;
Timespan timespan = hoveredTimespan(mouseDown.x());
if (commentModel->hoveredComment(timespan).isValid())
commentModel->openContextMenu();
else
{
updateToggleCollapsedAction();
contextMenu->exec(pos);
}
}