This commit is a preparation for the upcoming feature that will make dynamically rearranging the lines of the TracePlot possible. All TracePlotLines can now be rearranged as wanted in the code.
684 lines
23 KiB
C++
684 lines
23 KiB
C++
/*
|
|
* Copyright (c) 2015, Technische Universität Kaiserslautern
|
|
* 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
|
|
*/
|
|
|
|
#include <qwt_plot_grid.h>
|
|
#include <QWheelEvent>
|
|
#include <QMessageBox>
|
|
#include <QMouseEvent>
|
|
#include <iostream>
|
|
#include <QMenu>
|
|
#include <cmath>
|
|
#include <QInputDialog>
|
|
#include <QKeySequence>
|
|
#include <QFileInfo>
|
|
#include <QPushButton>
|
|
#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),
|
|
customLabelScaleDraw(new CustomLabelScaleDraw(drawingProperties.getLabels()))
|
|
{
|
|
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()));
|
|
|
|
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);
|
|
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({setColorGroupingPhase, setColorGroupingTransaction, 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, selectNextActb, selectNextPreb, selectNextRefb});
|
|
contextMenu->addMenu(selectSubMenu);
|
|
|
|
contextMenu->addActions({showQueryEditor, insertComment, exportToPdf});
|
|
}
|
|
|
|
void TracePlot::init(TraceNavigator *navigator, QScrollBar *scrollBar)
|
|
{
|
|
Q_ASSERT(isInitialized == false);
|
|
isInitialized = true;
|
|
|
|
this->scrollBar = scrollBar;
|
|
|
|
this->navigator = navigator;
|
|
connectNavigatorQ_SIGNALS();
|
|
setUpDrawingProperties();
|
|
setUpAxis();
|
|
setUpGrid();
|
|
setUpTracePlotItem();
|
|
setUpZoom();
|
|
setUpQueryEditor();
|
|
mouseLabel = new TracePlotMouseLabel(this,
|
|
navigator->GeneralTraceInfo().clkPeriod, this->mouseDownData.zoomSpan);
|
|
getAndDrawComments();
|
|
setZoomLevel(1000);
|
|
|
|
updateScrollbar();
|
|
|
|
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()
|
|
{
|
|
drawingProperties.init(navigator->getTracePlotLines(), this);
|
|
|
|
drawingProperties.numberOfRanks = navigator->GeneralTraceInfo().numberOfRanks;
|
|
drawingProperties.numberOfBankgroups = navigator->GeneralTraceInfo().numberOfBankgroups;
|
|
drawingProperties.numberOfBanks = navigator->GeneralTraceInfo().numberOfBanks;
|
|
drawingProperties.banksPerRank = drawingProperties.numberOfBanks / drawingProperties.numberOfRanks;
|
|
drawingProperties.groupsPerRank = drawingProperties.numberOfBankgroups / drawingProperties.numberOfRanks;
|
|
drawingProperties.banksPerGroup = drawingProperties.numberOfBanks / drawingProperties.numberOfBankgroups;
|
|
|
|
drawingProperties.setUpTracePlotLines();
|
|
}
|
|
|
|
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;
|
|
|
|
if (maximum >= 0)
|
|
{
|
|
scrollBar->setMaximum(maximum);
|
|
scrollBar->show();
|
|
}
|
|
else
|
|
scrollBar->hide();
|
|
|
|
verticalScrollbarChanged(scrollBar->value());
|
|
}
|
|
|
|
void TracePlot::verticalScrollbarChanged(int value)
|
|
{
|
|
const int yMax = drawingProperties.getNumberOfDisplayedLines();
|
|
|
|
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);
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
CustomLabelScaleDraw *TracePlot::getCustomLabelScaleDraw() const
|
|
{
|
|
return customLabelScaleDraw;
|
|
}
|
|
|
|
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_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_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());
|
|
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();
|
|
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->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);
|
|
}
|
|
|
|
|