Files
DRAMSys/analyzer/analyzer/presentation/traceplot.cpp
2014-07-11 09:22:34 +02:00

547 lines
17 KiB
C++

#include <qwt_plot_grid.h>
#include <QWheelEvent>
#include <QMessageBox>
#include <QMouseEvent>
#include <iostream>
#include <QMenu>
#include <cmath>
#include <QInputDialog>
#include <QKeySequence>
#include <QFileInfo>
#include <qfiledialog.h>
#include <iostream>
#include <qwt_plot_renderer.h>
#include "tracePlotMouseLabel.h"
#include "traceplot.h"
#include "gototimedialog.h"
#include "tracedrawing.h"
#include "util/engineeringScaleDraw.h"
#include "util/clkgrid.h"
#include "util/customlabelscaledraw.h"
using namespace std;
TracePlot::TracePlot(QWidget *parent):
QwtPlot(parent),isInitialized(false)
{
canvas()->setCursor(Qt::ArrowCursor);
setUpActions();
}
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);
selectNextRefresh->setShortcut(QKeySequence("alt+r"));
addAction(selectNextRefresh);
QObject::connect(selectNextRefresh, SIGNAL(triggered()), this, SLOT(on_selectNextRefresh()));
selectNextActivate = new QAction("Select next activate",this);
selectNextActivate->setShortcut(QKeySequence("alt+a"));
addAction(selectNextActivate);
QObject::connect(selectNextActivate, SIGNAL(triggered()), this, SLOT(on_selectNextActivate()));
selectNextPrecharge = new QAction("Select next precharge",this);
selectNextPrecharge->setShortcut(QKeySequence("alt+p"));
addAction(selectNextPrecharge);
QObject::connect(selectNextPrecharge, SIGNAL(triggered()), this, SLOT(on_selectNextPrecharge()));
setColorGroupingPhase = new QAction("Group by Phase",this);
addAction(setColorGroupingPhase);
QObject::connect(setColorGroupingPhase, SIGNAL(triggered()), this, SLOT(on_colorGroupingPhase()));
setColorGroupingTransaction = new QAction("Group by Transaction",this);
addAction(setColorGroupingTransaction);
QObject::connect(setColorGroupingTransaction, SIGNAL(triggered()), this, SLOT(on_colorGroupingTransaction()));
setColorGroupingThread = new QAction("Group by Thread",this);
addAction(setColorGroupingThread);
QObject::connect(setColorGroupingThread, SIGNAL(triggered()), this, SLOT(on_colorGroupingThread()));
exportToPdf = new QAction("Export to SVG", this);
addAction(exportToPdf);
QObject::connect(exportToPdf, SIGNAL(triggered()), this, SLOT(on_exportToPDF()));
setUpContextMenu();
}
void TracePlot::setUpContextMenu()
{
contextMenu = new QMenu(this);
contextMenu->addActions({deselectAll});
QMenu* colorGroupingSubMenu = new QMenu("Group by",contextMenu);
colorGroupingSubMenu->addActions({setColorGroupingTransaction, setColorGroupingPhase, setColorGroupingThread});
contextMenu->addMenu(colorGroupingSubMenu);
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});
contextMenu->addMenu(selectSubMenu);
contextMenu->addActions({showQueryEditor, insertComment,exportToPdf});
}
void TracePlot::init(TraceNavigator* navigator)
{
Q_ASSERT(isInitialized == false);
isInitialized = true;
this->navigator = navigator;
connectNavigatorQ_SIGNALS();
setUpDrawingProperties();
setUpAxis();
setUpGrid();
setUpTracePlotItem();
setUpZoom();
setUpQueryEditor();
mouseLabel = new TracePlotMouseLabel(this,navigator->GeneralTraceInfo().clkPeriod,this->mouseDownData.zoomSpan);
getAndDrawComments();
setZoomLevel(1000);
replot();
}
void TracePlot::connectNavigatorQ_SIGNALS()
{
QObject::connect(navigator,SIGNAL(currentTraceTimeChanged()),this,SLOT(currentTraceTimeChanged()));
QObject::connect(navigator,SIGNAL(selectedTransactionsChanged()),this,SLOT(selectedTransactionsChanged()));
QObject::connect(navigator,SIGNAL(commentsChanged()),this,SLOT(commentsChanged()));
}
void TracePlot::setUpDrawingProperties()
{
unsigned int numberOfBanks = navigator -> GeneralTraceInfo().numberOfBanks;
drawingProperties.numberOfBanks = numberOfBanks;
drawingProperties.yValResponse = numberOfBanks;
drawingProperties.yValRequest = numberOfBanks + 1;
drawingProperties.yValCommandBus = -3;
drawingProperties.yValDataBus = -4;
}
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::setUpAxis()
{
int numberOfBanks = navigator -> GeneralTraceInfo().numberOfBanks;
setAxisScale(yLeft, -5, numberOfBanks + 2, 1.0);
setAxisScaleDraw(yLeft,new CustomLabelScaleDraw(drawingProperties.getLabels()));
setAxisTitle(xBottom, "Time in ns");
setAxisScaleDraw(xBottom, new EngineeringScaleDraw);
}
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;
}
void TracePlot::getAndDrawComments()
{
for(const auto &pair: navigator->getComments())
{
const Comment &comment = pair.second;
QwtPlotMarker *maker = new QwtPlotMarker();
maker->setLabel(comment.Text());
maker->setLabelOrientation(Qt::Vertical);
maker->setLabelAlignment(Qt::AlignLeft | Qt::AlignBottom);
maker->setXValue(static_cast<double>(comment.Time()));
maker->setLineStyle(QwtPlotMarker::LineStyle::VLine);
maker->setLinePen(QColor(Qt::blue),2);
maker->attach(this);
}
}
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));
}
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::currentTraceTimeChanged()
{
transactions = navigator->TraceFile().getTransactionsInTimespan(GetCurrentTimespan());
setAxisScale(xBottom,GetCurrentTimespan().Begin(),GetCurrentTimespan().End());
replot();
}
void TracePlot::selectedTransactionsChanged()
{
replot();
}
void TracePlot::commentsChanged()
{
detachItems(QwtPlotItem::Rtti_PlotMarker);
getAndDrawComments();
replot();
}
void TracePlot::on_executeQuery()
{
queryEditor->show();
}
void TracePlot::on_selectNextRefresh()
{
navigator->selectNextRefresh();
}
void TracePlot::on_selectNextActivate()
{
navigator->selectNextActivate();
}
void TracePlot::on_selectNextPrecharge()
{
navigator->selectNextPrecharge();
}
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_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 (0 - " + QString::number(maxID) + ")",0,0,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 (0 - " + QString::number(maxID) + ")",0,0,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());
bool ok;
QString text = QInputDialog::getText(this,QString("Insert comment"),QString("Insert comment at ") + prettyFormatTime(time),QLineEdit::Normal,QString(),&ok);
if(ok)
{
navigator->insertComment(Comment(time,text));
}
}
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));
}
}
/* 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();
}
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->x()));
(wheelEvent->delta() > 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());
}
return true;
}
else if(mouseEvent->button() == Qt::RightButton)
{
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)
{
double yVal = invTransform(yLeft, y);
traceTime time = invTransform(xBottom, x);
vector<shared_ptr<Transaction>> selectedTransactions = tracePlotItem->getSelectedTransactions(time,yVal);
if(selectedTransactions.size() > 0)
{
if(!keyPressData.ctrlPressed)
navigator->clearSelectedTransactions();
navigator->addSelectedTransactions(selectedTransactions);
}
}
void TracePlot::openContextMenu(const QPoint& pos,const QPoint& mouseDown)
{
contextMenuMouseDown = mouseDown;
contextMenu->exec(pos);
}