From ccab0b3cfbecdcae136ed57c2eabba8ce6829e1b Mon Sep 17 00:00:00 2001 From: Derek Christ Date: Fri, 13 Aug 2021 12:17:35 +0200 Subject: [PATCH 1/9] Insert old comment text in change comment dialog. --- DRAMSys/traceAnalyzer/presentation/commenttreewidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DRAMSys/traceAnalyzer/presentation/commenttreewidget.cpp b/DRAMSys/traceAnalyzer/presentation/commenttreewidget.cpp index 519e04e4..ebdf84db 100644 --- a/DRAMSys/traceAnalyzer/presentation/commenttreewidget.cpp +++ b/DRAMSys/traceAnalyzer/presentation/commenttreewidget.cpp @@ -64,7 +64,7 @@ CommentTreeWidget::CommentTreeWidget(QWidget *parent) : QTreeWidget(parent), bool ok; QString newText = QInputDialog::getText(this, QString("Change comment text"), QString("Change comment text"), QLineEdit::Normal, - QString(), &ok); + commentItem->Text(), &ok); if (ok) { From f6b987f7777349537f8984d41b7fd6dc446ab518 Mon Sep 17 00:00:00 2001 From: Derek Christ Date: Mon, 30 Aug 2021 14:32:05 +0200 Subject: [PATCH 2/9] Add functionality to select comments and directly delete/edit them It's now possible to select comments directly in the traceplot instead of selecting them in the CommentTreeWidget. Selections from the TreeWidget are synchronized to the plot but not vice versa. It would generally be the better to introduce a Model/View based approach instead of trying to synchronize selections and QActions. --- .../traceAnalyzer/businessObjects/comment.h | 10 +++ .../presentation/commenttreewidget.cpp | 48 +++++------ .../presentation/commenttreewidget.h | 20 +++-- .../presentation/tracenavigator.cpp | 62 +++++++++++++- .../presentation/tracenavigator.h | 17 +++- .../traceAnalyzer/presentation/traceplot.cpp | 85 ++++++++++++++++--- .../traceAnalyzer/presentation/traceplot.h | 4 +- .../presentation/tracescroller.cpp | 10 ++- DRAMSys/traceAnalyzer/tracefiletab.cpp | 3 + 9 files changed, 207 insertions(+), 52 deletions(-) diff --git a/DRAMSys/traceAnalyzer/businessObjects/comment.h b/DRAMSys/traceAnalyzer/businessObjects/comment.h index c52753f8..91d8860b 100644 --- a/DRAMSys/traceAnalyzer/businessObjects/comment.h +++ b/DRAMSys/traceAnalyzer/businessObjects/comment.h @@ -59,6 +59,16 @@ public: { text = newText; } + bool isSelected(traceTime mouseTime, traceTime clk) + { + // Increase selectable area of comments + traceTime offset = static_cast(0.35 * clk); + + if (time >= (mouseTime - offset) && time <= (mouseTime + offset)) + return true; + + return false; + } }; #endif // COMMENT_H diff --git a/DRAMSys/traceAnalyzer/presentation/commenttreewidget.cpp b/DRAMSys/traceAnalyzer/presentation/commenttreewidget.cpp index ebdf84db..399354a2 100644 --- a/DRAMSys/traceAnalyzer/presentation/commenttreewidget.cpp +++ b/DRAMSys/traceAnalyzer/presentation/commenttreewidget.cpp @@ -41,12 +41,10 @@ #include #include #include -#include -#include CommentTreeWidget::CommentTreeWidget(QWidget *parent) : QTreeWidget(parent), deleteComment(new QAction("Delete comment", this)), - changeCommentText(new QAction("Change comment text", this)) + editCommentText(new QAction("Edit comment text", this)) { connect(deleteComment, &QAction::triggered, this, [this](){ for (QTreeWidgetItem *item : selectedItems()) @@ -56,25 +54,25 @@ CommentTreeWidget::CommentTreeWidget(QWidget *parent) : QTreeWidget(parent), } }); - connect(changeCommentText, &QAction::triggered, this, [this](){ + connect(editCommentText, &QAction::triggered, this, [this](){ for (QTreeWidgetItem *item : selectedItems()) { CommentTreeItem *commentItem = static_cast(item); - - bool ok; - QString newText = QInputDialog::getText(this, QString("Change comment text"), - QString("Change comment text"), QLineEdit::Normal, - commentItem->Text(), &ok); - - if (ok) - { - deleteComment->trigger(); - navigator->insertComment({commentItem->Time(), newText}); - } - - commentsChanged(); + navigator->editCommentAtTime(commentItem->Time()); } }); + + connect(this, &QTreeWidget::itemSelectionChanged, this, [this](){ + std::vector> selectedComments; + + for (auto &item : selectedItems()) + { + CommentTreeItem *commentItem = static_cast(item); + selectedComments.push_back(commentItem->getComment()); + } + + Q_EMIT selectedCommentsChanged(selectedComments); + }); } void CommentTreeWidget::init(TraceNavigator *navigator) @@ -103,7 +101,7 @@ void CommentTreeWidget::commentsChanged() void CommentTreeWidget::printComments() { for (const auto &pair : navigator->getComments()) { - const Comment &comment = pair.second; + const std::shared_ptr comment = pair.second; QTreeWidgetItem *item = new CommentTreeItem(this, comment); addTopLevelItem(item); } @@ -118,17 +116,19 @@ void CommentTreeWidget::itemDoubleClicked(QTreeWidgetItem *item, int /*column*/) void CommentTreeWidget::ContextMenuRequested(QPoint point) { + if (selectedItems().isEmpty()) + return; + QMenu contextMenu(this); - contextMenu.addActions({deleteComment, changeCommentText}); + contextMenu.addActions({editCommentText, deleteComment}); contextMenu.exec(mapToGlobal(point)); } - CommentTreeWidget::CommentTreeItem::CommentTreeItem(QTreeWidget *parent, - const Comment &comment): QTreeWidgetItem(parent), comment(comment) + const std::shared_ptr comment): QTreeWidgetItem(parent), comment(comment) { - this->setText(0, prettyFormatTime(comment.Time())); - this->setText(1, comment.Text()); + this->setText(0, prettyFormatTime(comment->Time())); + this->setText(1, comment->Text()); } void CommentTreeWidget::keyPressEvent(QKeyEvent *event) @@ -136,7 +136,7 @@ void CommentTreeWidget::keyPressEvent(QKeyEvent *event) if (event->key() == Qt::Key_Delete) deleteComment->trigger(); else if (event->key() == Qt::Key_F2) - changeCommentText->trigger(); + editCommentText->trigger(); QTreeWidget::keyPressEvent(event); } diff --git a/DRAMSys/traceAnalyzer/presentation/commenttreewidget.h b/DRAMSys/traceAnalyzer/presentation/commenttreewidget.h index 7429f75e..c5c63bad 100644 --- a/DRAMSys/traceAnalyzer/presentation/commenttreewidget.h +++ b/DRAMSys/traceAnalyzer/presentation/commenttreewidget.h @@ -43,6 +43,7 @@ #include #include "businessObjects/comment.h" #include "tracenavigator.h" +#include "businessObjects/tracetime.h" class CommentTreeWidget : public QTreeWidget { @@ -55,6 +56,9 @@ public: protected: void keyPressEvent(QKeyEvent *event) override; +Q_SIGNALS: + void selectedCommentsChanged(std::vector> comments); + private Q_SLOTS: void commentsChanged(); void ContextMenuRequested(QPoint point); @@ -65,27 +69,29 @@ private: TraceNavigator *navigator; void printComments(); QAction *deleteComment; - QAction *changeCommentText; + QAction *editCommentText; class CommentTreeItem : public QTreeWidgetItem { private: - Comment comment; + const std::shared_ptr comment; public: - CommentTreeItem(QTreeWidget *parent, const Comment &comment); + CommentTreeItem(QTreeWidget *parent, const std::shared_ptr comment); QString Text() { - return comment.Text(); + return comment->Text(); } traceTime Time() { - return comment.Time(); + return comment->Time(); } - void changeText(QString newText) + const std::shared_ptr getComment() { - comment.changeText(newText); + return comment; } }; + + CommentTreeItem *getTreeItemFromTime(traceTime time); }; #endif // COMMENTTREEWIDGET_H diff --git a/DRAMSys/traceAnalyzer/presentation/tracenavigator.cpp b/DRAMSys/traceAnalyzer/presentation/tracenavigator.cpp index 13b0526c..0758cd01 100644 --- a/DRAMSys/traceAnalyzer/presentation/tracenavigator.cpp +++ b/DRAMSys/traceAnalyzer/presentation/tracenavigator.cpp @@ -39,6 +39,8 @@ #include "tracenavigator.h" #include "util/traceplotlinecache.h" #include "vector" +#include +#include using namespace std; @@ -85,7 +87,7 @@ void TraceNavigator::navigateToTransaction(ID id) */ void TraceNavigator::insertComment(const Comment &comment) { - comments.emplace(comment.Time(), comment); + comments.emplace(comment.Time(), std::make_shared(comment)); changesToCommitExist = true; Q_EMIT commentsChanged(); } @@ -93,6 +95,7 @@ void TraceNavigator::insertComment(const Comment &comment) void TraceNavigator::removeCommentAtTime(traceTime time) { auto found = comments.find(time); + if (found != comments.end()) { comments.erase(found); changesToCommitExist = true; @@ -100,7 +103,60 @@ void TraceNavigator::removeCommentAtTime(traceTime time) } } +void TraceNavigator::editCommentAtTime(traceTime time) +{ + auto found = comments.find(time); + if (found != comments.end()) { + comments.erase(found); + auto comment = found->second; + + bool ok; + QString newText = QInputDialog::getText(nullptr, QString("Edit comment text"), + QString("Edit comment text"), QLineEdit::Normal, + comment->Text(), &ok); + + if (ok) + { + removeCommentAtTime(time); + insertComment({comment->Time(), newText}); + changesToCommitExist = true; + Q_EMIT commentsChanged(); + } + } +} + +void TraceNavigator::addSelectedComments(const std::vector> + &comments) +{ + for (auto &comment : comments) + selectedComments.push_back(comment); + + Q_EMIT selectedCommentsChanged(); +} + +void TraceNavigator::clearSelectedComments() +{ + selectedComments.clear(); + Q_EMIT selectedCommentsChanged(); +} + +void TraceNavigator::updateCommentSelection(std::vector> comments) +{ + selectedComments.clear(); + addSelectedComments(comments); +} + +bool TraceNavigator::commentIsSelected(const std::shared_ptr comment) const +{ + for (auto &selectedComment : selectedComments) + { + if (comment == selectedComment) + return true; + } + + return false; +} /* DB * @@ -110,7 +166,7 @@ void TraceNavigator::commitChangesToDB() { vector commentsToInsert; for (const auto &pair : comments) { - commentsToInsert.push_back(pair.second); + commentsToInsert.push_back(*pair.second.get()); } traceFile.updateComments(commentsToInsert); @@ -120,7 +176,7 @@ void TraceNavigator::commitChangesToDB() void TraceNavigator::getCommentsFromDB() { for (const Comment &comment : traceFile.getComments()) { - comments.emplace(comment.Time(), comment); + comments.emplace(comment.Time(), std::make_shared(comment)); } } diff --git a/DRAMSys/traceAnalyzer/presentation/tracenavigator.h b/DRAMSys/traceAnalyzer/presentation/tracenavigator.h index 28bc8af7..00c76294 100644 --- a/DRAMSys/traceAnalyzer/presentation/tracenavigator.h +++ b/DRAMSys/traceAnalyzer/presentation/tracenavigator.h @@ -56,7 +56,7 @@ class TracePlotLineCache; class TraceNavigator : public QObject { Q_OBJECT - using CommentMap = std::map; + using CommentMap = std::map>; public: TraceNavigator(QString path, QObject *parent = 0); @@ -117,6 +117,16 @@ public: return comments; } void removeCommentAtTime(traceTime time); + void editCommentAtTime(traceTime time); + void addSelectedComments(const std::vector> + &comments); + void clearSelectedComments(); + const std::vector> &SelectedComments() + { + return selectedComments; + } + + bool commentIsSelected(const std::shared_ptr comment) const; void commitChangesToDB(); void refreshData(); @@ -127,8 +137,12 @@ public: Q_SIGNALS: void currentTraceTimeChanged(); void selectedTransactionsChanged(); + void selectedCommentsChanged(); void commentsChanged(); +public Q_SLOTS: + void updateCommentSelection(std::vector> comments); + private: TraceDB traceFile; @@ -136,6 +150,7 @@ private: //components drawing the tracefile center around that time traceTime currentTraceTime = 0; std::vector> selectedTransactions; + std::vector> selectedComments; CommentMap comments; void getCommentsFromDB(); bool changesToCommitExist; diff --git a/DRAMSys/traceAnalyzer/presentation/traceplot.cpp b/DRAMSys/traceAnalyzer/presentation/traceplot.cpp index fef381a1..64fbf582 100644 --- a/DRAMSys/traceAnalyzer/presentation/traceplot.cpp +++ b/DRAMSys/traceAnalyzer/presentation/traceplot.cpp @@ -216,6 +216,8 @@ void TracePlot::connectNavigatorQ_SIGNALS() SLOT(currentTraceTimeChanged())); QObject::connect(navigator, SIGNAL(selectedTransactionsChanged()), this, SLOT(selectedTransactionsChanged())); + QObject::connect(navigator, SIGNAL(selectedCommentsChanged()), this, + SLOT(commentsChanged())); QObject::connect(navigator, SIGNAL(commentsChanged()), this, SLOT(commentsChanged())); } @@ -344,15 +346,17 @@ Timespan TracePlot::GetCurrentTimespan() 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(comment.Time())); - maker->setLineStyle(QwtPlotMarker::LineStyle::VLine); - maker->setLinePen(QColor(Qt::blue), 2); - maker->attach(this); + const std::shared_ptr comment = pair.second; + bool highlight = navigator->commentIsSelected(comment); + + QwtPlotMarker *marker = new QwtPlotMarker(); + marker->setLabel(comment->Text()); + marker->setLabelOrientation(Qt::Vertical); + marker->setLabelAlignment(Qt::AlignLeft | Qt::AlignBottom); + marker->setXValue(static_cast(comment->Time())); + marker->setLineStyle(QwtPlotMarker::LineStyle::VLine); + marker->setLinePen(QColor(highlight ? Qt::red : Qt::blue), 2); + marker->attach(this); } } @@ -646,9 +650,13 @@ bool TracePlot::eventFilter(QObject *object, QEvent *event) 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; @@ -704,7 +712,7 @@ bool TracePlot::eventFilter(QObject *object, QEvent *event) return false; } -void TracePlot::SelectTransaction(int x, int y) +void TracePlot::SelectTransaction(int x, int y) const { double yVal = invTransform(yLeft, y); traceTime time = invTransform(xBottom, x); @@ -717,10 +725,61 @@ void TracePlot::SelectTransaction(int x, int y) } } +void TracePlot::SelectComment(int x) const +{ + traceTime time = invTransform(xBottom, x); + + auto selectedComments = hoveredComments(time); + + if (selectedComments.size() > 0) { + if (!keyPressData.ctrlPressed) + navigator->clearSelectedComments(); + + navigator->addSelectedComments(selectedComments); + } else { + navigator->clearSelectedComments(); + } +} + +const std::vector> TracePlot::hoveredComments(traceTime time) const +{ + std::vector> hoveredComments; + + for (const auto &commentPair : navigator->getComments()) + { + auto comment = commentPair.second; + if (comment->isSelected(time, navigator->GeneralTraceInfo().clkPeriod)) + hoveredComments.push_back(comment); + } + + return hoveredComments; +} + void TracePlot::openContextMenu(const QPoint &pos, const QPoint &mouseDown) { contextMenuMouseDown = mouseDown; - contextMenu->exec(pos); + + traceTime time = invTransform(xBottom, mouseDown.x()); + auto comments = hoveredComments(time); + + if (comments.size() == 0) + contextMenu->exec(pos); + else + { + QMenu commentContextMenu(this); + QAction editCommentText("Edit comment text", this); + QAction deleteComment("Delete comment", this); + + auto commentTime = comments[0]->Time(); + connect(&editCommentText, &QAction::triggered, this, [=](){ + navigator->editCommentAtTime(commentTime); + }); + + connect(&deleteComment, &QAction::triggered, this, [=](){ + navigator->removeCommentAtTime(commentTime); + }); + + commentContextMenu.addActions({&editCommentText, &deleteComment}); + commentContextMenu.exec(pos); + } } - - diff --git a/DRAMSys/traceAnalyzer/presentation/traceplot.h b/DRAMSys/traceAnalyzer/presentation/traceplot.h index 2676988d..10dd534d 100644 --- a/DRAMSys/traceAnalyzer/presentation/traceplot.h +++ b/DRAMSys/traceAnalyzer/presentation/traceplot.h @@ -186,7 +186,9 @@ private: void openContextMenu(const QPoint &pos, const QPoint &mouseDown); QPoint contextMenuMouseDown; - void SelectTransaction(int x, int y); + void SelectTransaction(int x, int y) const; + void SelectComment(int x) const; + const std::vector> hoveredComments(traceTime time) const; void keyPressEvent(QKeyEvent *keyPressedEvent); void keyReleaseEvent(QKeyEvent *keyReleasedEvent); diff --git a/DRAMSys/traceAnalyzer/presentation/tracescroller.cpp b/DRAMSys/traceAnalyzer/presentation/tracescroller.cpp index ae9906a1..91b8b3a2 100644 --- a/DRAMSys/traceAnalyzer/presentation/tracescroller.cpp +++ b/DRAMSys/traceAnalyzer/presentation/tracescroller.cpp @@ -121,6 +121,8 @@ void TraceScroller::connectNavigatorQ_SIGNALS() SLOT(currentTraceTimeChanged())); QObject::connect(navigator, SIGNAL(commentsChanged()), this, SLOT(commentsChanged())); + QObject::connect(navigator, SIGNAL(selectedCommentsChanged()), this, + SLOT(commentsChanged())); QObject::connect(navigator, SIGNAL(selectedTransactionsChanged()), this, SLOT(selectedTransactionsChanged())); } @@ -148,11 +150,13 @@ Timespan TraceScroller::GetCurrentTimespan() void TraceScroller::getAndDrawComments() { for (const auto &pair : navigator->getComments()) { - const Comment &comment = pair.second; + const std::shared_ptr comment = pair.second; + bool highlight = navigator->commentIsSelected(comment); + QwtPlotMarker *maker = new QwtPlotMarker(); - maker->setXValue(static_cast(comment.Time())); + maker->setXValue(static_cast(comment->Time())); maker->setLineStyle(QwtPlotMarker::LineStyle::VLine); - maker->setLinePen(QColor(Qt::blue), 2); + maker->setLinePen(QColor(highlight ? Qt::red : Qt::blue), 2); maker->attach(this); } } diff --git a/DRAMSys/traceAnalyzer/tracefiletab.cpp b/DRAMSys/traceAnalyzer/tracefiletab.cpp index 36c95509..1fe452d0 100644 --- a/DRAMSys/traceAnalyzer/tracefiletab.cpp +++ b/DRAMSys/traceAnalyzer/tracefiletab.cpp @@ -89,6 +89,9 @@ TraceFileTab::TraceFileTab(QWidget *parent, const QString &path) : ui->memSpecView->setModel(memSpecModel); ui->memSpecView->header()->setSectionResizeMode(QHeaderView::ResizeToContents); + connect(ui->commentTree, &CommentTreeWidget::selectedCommentsChanged, + navigator, &TraceNavigator::updateCommentSelection); + tracefileChanged(); } From d40324821fd9cd35b6867988b757fd6d8115cc51 Mon Sep 17 00:00:00 2001 From: Derek Christ Date: Wed, 8 Sep 2021 12:30:29 +0200 Subject: [PATCH 3/9] Fix a bug in comment editing. --- DRAMSys/traceAnalyzer/presentation/tracenavigator.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/DRAMSys/traceAnalyzer/presentation/tracenavigator.cpp b/DRAMSys/traceAnalyzer/presentation/tracenavigator.cpp index 0758cd01..89448111 100644 --- a/DRAMSys/traceAnalyzer/presentation/tracenavigator.cpp +++ b/DRAMSys/traceAnalyzer/presentation/tracenavigator.cpp @@ -108,7 +108,6 @@ void TraceNavigator::editCommentAtTime(traceTime time) auto found = comments.find(time); if (found != comments.end()) { - comments.erase(found); auto comment = found->second; bool ok; From 3157f6a14573e0b11b264de0cf9a657811cb5048 Mon Sep 17 00:00:00 2001 From: Derek Christ Date: Wed, 8 Sep 2021 20:06:59 +0200 Subject: [PATCH 4/9] Complete rewrite of the comment system The new comment system uses one central CommentModel that provides the whole application with the comment data. Also, a new goto comment action has been added. --- DRAMSys/traceAnalyzer/CMakeLists.txt | 2 +- .../traceAnalyzer/businessObjects/comment.h | 74 ----- .../businessObjects/commentmodel.cpp | 282 ++++++++++++++++++ .../businessObjects/commentmodel.h | 114 +++++++ DRAMSys/traceAnalyzer/data/tracedb.cpp | 24 +- DRAMSys/traceAnalyzer/data/tracedb.h | 12 +- .../presentation/commenttreewidget.cpp | 142 --------- .../presentation/commenttreewidget.h | 97 ------ .../presentation/debugmessagetreewidget.cpp | 12 +- .../presentation/debugmessagetreewidget.h | 4 +- .../presentation/tracenavigator.cpp | 102 +------ .../presentation/tracenavigator.h | 34 +-- .../traceAnalyzer/presentation/traceplot.cpp | 101 +++---- .../traceAnalyzer/presentation/traceplot.h | 8 +- .../presentation/tracescroller.cpp | 26 +- .../presentation/tracescroller.h | 1 - DRAMSys/traceAnalyzer/tracefiletab.cpp | 29 +- DRAMSys/traceAnalyzer/tracefiletab.h | 4 + DRAMSys/traceAnalyzer/tracefiletab.ui | 33 +- 19 files changed, 562 insertions(+), 539 deletions(-) delete mode 100644 DRAMSys/traceAnalyzer/businessObjects/comment.h create mode 100644 DRAMSys/traceAnalyzer/businessObjects/commentmodel.cpp create mode 100644 DRAMSys/traceAnalyzer/businessObjects/commentmodel.h delete mode 100644 DRAMSys/traceAnalyzer/presentation/commenttreewidget.cpp delete mode 100644 DRAMSys/traceAnalyzer/presentation/commenttreewidget.h diff --git a/DRAMSys/traceAnalyzer/CMakeLists.txt b/DRAMSys/traceAnalyzer/CMakeLists.txt index ae70b48c..96594a93 100644 --- a/DRAMSys/traceAnalyzer/CMakeLists.txt +++ b/DRAMSys/traceAnalyzer/CMakeLists.txt @@ -75,7 +75,6 @@ add_executable(TraceAnalyzer presentation/tracescroller.cpp traceanalyzer.cpp presentation/transactiontreewidget.cpp - presentation/commenttreewidget.cpp presentation/util/clkgrid.cpp queryeditor.cpp presentation/selectedtransactiontreewidget.cpp @@ -97,6 +96,7 @@ add_executable(TraceAnalyzer presentation/util/customlabelscaledraw.cpp presentation/traceselector.cpp businessObjects/configmodels.cpp + businessObjects/commentmodel.cpp selectmetrics.ui preferences.ui diff --git a/DRAMSys/traceAnalyzer/businessObjects/comment.h b/DRAMSys/traceAnalyzer/businessObjects/comment.h deleted file mode 100644 index 91d8860b..00000000 --- a/DRAMSys/traceAnalyzer/businessObjects/comment.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * 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 - */ - -#ifndef COMMENT_H -#define COMMENT_H -#include -#include "timespan.h" - -class Comment -{ - traceTime time; - QString text; -public: - Comment(traceTime time, QString text): time(time), text(text) {} - traceTime Time() const - { - return time; - } - const QString &Text() const - { - return text; - } - void changeText(QString newText) - { - text = newText; - } - bool isSelected(traceTime mouseTime, traceTime clk) - { - // Increase selectable area of comments - traceTime offset = static_cast(0.35 * clk); - - if (time >= (mouseTime - offset) && time <= (mouseTime + offset)) - return true; - - return false; - } -}; - -#endif // COMMENT_H diff --git a/DRAMSys/traceAnalyzer/businessObjects/commentmodel.cpp b/DRAMSys/traceAnalyzer/businessObjects/commentmodel.cpp new file mode 100644 index 00000000..940cd07e --- /dev/null +++ b/DRAMSys/traceAnalyzer/businessObjects/commentmodel.cpp @@ -0,0 +1,282 @@ +/* + * Copyright (c) 2021, 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: + * Derek Christ + */ + +#include "commentmodel.h" + +#include +#include +#include + +CommentModel::CommentModel(QObject *parent) : QAbstractTableModel(parent), + gotoAction(new QAction("Goto comment", this)), + editAction(new QAction("Edit comment", this)), + deleteAction(new QAction("Delete comment", this)), + internalSelectionModel(new QItemSelectionModel(this, this)) +{ + setUpActions(); +} + +void CommentModel::setUpActions() +{ + QObject::connect(gotoAction, &QAction::triggered, this, [=](){ + const QModelIndexList indexes = internalSelectionModel->selectedRows(); + for (const QModelIndex ¤tIndex : indexes) + { + emit gotoCommentTriggered(currentIndex); + } + }); + + QObject::connect(editAction, &QAction::triggered, this, [=](){ + const QModelIndexList indexes = internalSelectionModel->selectedRows(); + for (const QModelIndex ¤tIndex : indexes) + emit editTriggered(index(currentIndex.row(), static_cast(Column::Comment))); + }); + + QObject::connect(deleteAction, &QAction::triggered, this, [=](){ + const QModelIndexList indexes = internalSelectionModel->selectedRows(); + for (const QModelIndex ¤tIndex : indexes) + removeComment(currentIndex); + }); +} + +int CommentModel::rowCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent) + + return comments.size(); +} + +int CommentModel::columnCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent) + + return static_cast(Column::COLUMNCOUNT); +} + +QVariant CommentModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + // Qt::UserRole is used to get the raw time without pretty formatting. + if (role != Qt::DisplayRole && role != Qt::EditRole && role != Qt::UserRole) + return QVariant(); + + const Comment &comment = comments.at(index.row()); + + if (role == Qt::UserRole && static_cast(index.column()) == Column::Time) + return QVariant(comment.time); + + switch (static_cast(index.column())) { + case Column::Time: + return QVariant(prettyFormatTime(comment.time)); + case Column::Comment: + return QVariant(comment.text); + default: + break; + } + + return QVariant(); +} + +bool CommentModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + if (!index.isValid()) + return false; + + if (role != Qt::EditRole) + return false; + + if (static_cast(index.column()) != Column::Comment) + return false; + + QString newText = value.toString(); + + Comment &comment = comments.at(index.row()); + comment.text = newText; + + emit dataChanged(index, index); + return true; +} + +QVariant CommentModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (role != Qt::DisplayRole) + return QVariant(); + + if (orientation == Qt::Horizontal) + { + switch (static_cast(section)) { + case Column::Time: + return "Time"; + case Column::Comment: + return "Comment"; + default: + break; + } + } + + return QVariant(); +} + +Qt::ItemFlags CommentModel::flags(const QModelIndex &index) const +{ + Qt::ItemFlags flags = QAbstractItemModel::flags(index); + + if (index.isValid() && index.column() == static_cast(Column::Comment)) + flags |= Qt::ItemIsEditable; + + return flags; +} + +void CommentModel::openContextMenu() +{ + if (!internalSelectionModel->hasSelection()) + return; + + QMenu *menu = new QMenu(); + menu->addActions({gotoAction, editAction, deleteAction}); + + QObject::connect(menu, &QMenu::aboutToHide, [=]() { + menu->deleteLater(); + }); + + menu->popup(QCursor::pos()); +} + +QItemSelectionModel *CommentModel::selectionModel() const +{ + return internalSelectionModel; +} + +void CommentModel::addComment(traceTime time) +{ + auto commentIt = std::find_if(comments.rbegin(), comments.rend(), [time](const Comment &comment){ + return comment.time <= time; + }); + + int insertIndex = std::distance(comments.begin(), commentIt.base()); + + beginInsertRows(QModelIndex(), insertIndex, insertIndex); + comments.insert(comments.begin() + insertIndex, {time, "Enter comment text..."}); + endInsertRows(); + + internalSelectionModel->setCurrentIndex(index(insertIndex, 0), + QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); + + emit editTriggered(index(insertIndex, 1)); +} + +void CommentModel::addComment(traceTime time, QString text) +{ + auto commentIt = std::find_if(comments.rbegin(), comments.rend(), [time](const Comment &comment){ + return comment.time <= time; + }); + + int insertIndex = std::distance(comments.begin(), commentIt.base()); + + beginInsertRows(QModelIndex(), insertIndex, insertIndex); + comments.insert(comments.begin() + insertIndex, {time, text}); + endInsertRows(); +} + +void CommentModel::removeComment(traceTime time) +{ + auto commentIt = std::find_if(comments.begin(), comments.end(), [time](const Comment &comment){ + return comment.time == time; + }); + + if (commentIt == comments.end()) + return; + + int removeIndex = std::distance(comments.begin(), commentIt); + + beginRemoveRows(QModelIndex(), removeIndex, removeIndex); + comments.erase(commentIt); + endRemoveRows(); +} + +void CommentModel::removeComment(const QModelIndex &index) +{ + beginRemoveRows(QModelIndex(), index.row(), index.row()); + comments.erase(comments.begin() + index.row()); + endRemoveRows(); +} + +const std::vector &CommentModel::getComments() const +{ + return comments; +} + +traceTime CommentModel::getTimeFromIndex(const QModelIndex &index) const +{ + Q_ASSERT(comments.size() > index.row()); + + return comments[index.row()].time; +} + +QModelIndex CommentModel::hoveredComment(Timespan timespan) const +{ + auto commentIt = std::find_if(comments.begin(), comments.end(), [timespan](const Comment &comment){ + return timespan.Begin() < comment.time && comment.time < timespan.End(); + }); + + if (commentIt == comments.end()) + return QModelIndex(); + + int commentIndex = std::distance(comments.begin(), commentIt); + + return index(commentIndex, 0); +} + +bool CommentModel::eventFilter(QObject *object, QEvent *event) +{ + Q_UNUSED(object) + + if (event->type() == QEvent::KeyPress) + { + QKeyEvent *keyEvent = static_cast(event); + if (keyEvent->key() == Qt::Key_Delete) + { + const QModelIndexList indexes = internalSelectionModel->selectedRows(); + for (const QModelIndex ¤tIndex : indexes) + { + removeComment(currentIndex); + } + } + } + + return false; +} diff --git a/DRAMSys/traceAnalyzer/businessObjects/commentmodel.h b/DRAMSys/traceAnalyzer/businessObjects/commentmodel.h new file mode 100644 index 00000000..f540663a --- /dev/null +++ b/DRAMSys/traceAnalyzer/businessObjects/commentmodel.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2021, 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: + * Derek Christ + */ + +#ifndef COMMENTMODEL_H +#define COMMENTMODEL_H + +#include "tracetime.h" +#include "timespan.h" + +#include +#include + +class QAction; +class QItemSelectionModel; + +class CommentModel : public QAbstractTableModel +{ + Q_OBJECT + +public: + explicit CommentModel(QObject *parent = nullptr); + + struct Comment { + traceTime time; + QString text; + }; + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; + + Qt::ItemFlags flags(const QModelIndex &index) const override; + + enum class Column { + Time = 0, + Comment, + COLUMNCOUNT + }; + + void openContextMenu(); + + QItemSelectionModel *selectionModel() const; + + void addComment(traceTime time); + void addComment(traceTime time, QString text); + + void removeComment(traceTime time); + void removeComment(const QModelIndex &index); + + const std::vector &getComments() const; + + traceTime getTimeFromIndex(const QModelIndex &index) const; + + QModelIndex hoveredComment(Timespan timespan) const; + +protected: + bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; + + /** + * The eventFilter is used to delete comments using the delete key. + */ + bool eventFilter(QObject *object, QEvent *event) override; + +Q_SIGNALS: + void editTriggered(const QModelIndex &index); + void gotoCommentTriggered(const QModelIndex &index); + +private: + void setUpActions(); + + std::vector comments; + + QAction *gotoAction; + QAction *editAction; + QAction *deleteAction; + + QItemSelectionModel *internalSelectionModel; +}; + +#endif // COMMENTMODEL_H diff --git a/DRAMSys/traceAnalyzer/data/tracedb.cpp b/DRAMSys/traceAnalyzer/data/tracedb.cpp index a7061a70..ff37a88f 100644 --- a/DRAMSys/traceAnalyzer/data/tracedb.cpp +++ b/DRAMSys/traceAnalyzer/data/tracedb.cpp @@ -44,7 +44,6 @@ #include #include #include "data/tracedb.h" -#include "businessObjects/comment.h" #include "businessObjects/phases/phasefactory.h" @@ -87,7 +86,7 @@ void TraceDB::prepareQueries() selectDebugMessagesByTimespanWithLimit.prepare("SELECT time, Message FROM DebugMessages WHERE :begin <= time AND time <= :end LIMIT :limit"); } -void TraceDB::updateComments(vector comments) +void TraceDB::updateComments(const std::vector &comments) { QSqlQuery query(database); @@ -95,9 +94,10 @@ void TraceDB::updateComments(vector comments) executeQuery(query); query.prepare("insert into Comments values(:time,:text)"); - for (const Comment &comment : comments) { - query.bindValue(":time", comment.Time()); - query.bindValue(":text", comment.Text()); + for (const auto &comment : comments) + { + query.bindValue(":time", comment.time); + query.bindValue(":text", comment.text); executeQuery(query); } } @@ -341,7 +341,7 @@ unsigned int TraceDB::getNumberOfPhases() return query.value(0).toInt(); } -vector TraceDB::getComments() +vector TraceDB::getComments() { QSqlQuery query(database); query.prepare("SELECT Time,Text From Comments"); @@ -350,7 +350,7 @@ vector TraceDB::getComments() } -vector TraceDB::getDebugMessagesInTimespan(const Timespan &span) +vector TraceDB::getDebugMessagesInTimespan(const Timespan &span) { selectDebugMessagesByTimespan.bindValue(":begin", span.Begin()); selectDebugMessagesByTimespan.bindValue(":end", span.End()); @@ -359,7 +359,7 @@ vector TraceDB::getDebugMessagesInTimespan(const Timespan &span) return parseCommentsFromQuery(selectDebugMessagesByTimespan); } -vector TraceDB::getDebugMessagesInTimespan(const Timespan &span, +vector TraceDB::getDebugMessagesInTimespan(const Timespan &span, unsigned int limit = 50) { selectDebugMessagesByTimespanWithLimit.bindValue(":begin", span.Begin()); @@ -432,12 +432,12 @@ vector> TraceDB::parseTransactionsFromQuery( return result; } -vector TraceDB::parseCommentsFromQuery(QSqlQuery &query) +vector TraceDB::parseCommentsFromQuery(QSqlQuery &query) { - vector result; + vector result; while (query.next()) { - result.push_back(Comment(query.value(0).toLongLong(), - query.value(1).toString())); + result.push_back(CommentModel::Comment{query.value(0).toLongLong(), + query.value(1).toString()}); } return result; } diff --git a/DRAMSys/traceAnalyzer/data/tracedb.h b/DRAMSys/traceAnalyzer/data/tracedb.h index 5df215b1..511be6b0 100644 --- a/DRAMSys/traceAnalyzer/data/tracedb.h +++ b/DRAMSys/traceAnalyzer/data/tracedb.h @@ -50,7 +50,7 @@ #include "businessObjects/generalinfo.h" #include "businessObjects/commandlengths.h" #include "businessObjects/phases/phasefactory.h" -#include "businessObjects/comment.h" +#include "businessObjects/commentmodel.h" #include "QueryTexts.h" /* TraceDB handles the connection to a SQLLite database containing trace data. @@ -68,7 +68,7 @@ public: return pathToDB; } - void updateComments(std::vector comments); + void updateComments(const std::vector &comments); void updateFileDescription(const QString &description); void refreshData(); @@ -98,9 +98,9 @@ public: std::shared_ptr getTransactionByID(ID id); ID getTransactionIDFromPhaseID(ID phaseID); - std::vector getComments(); - std::vector getDebugMessagesInTimespan(const Timespan &span); - std::vector getDebugMessagesInTimespan(const Timespan &span, + std::vector getComments(); + std::vector getDebugMessagesInTimespan(const Timespan &span); + std::vector getDebugMessagesInTimespan(const Timespan &span, unsigned int limit); QSqlDatabase getDatabase() const; @@ -125,7 +125,7 @@ private: std::shared_ptr parseTransactionFromQuery(QSqlQuery &query); std::vector> parseTransactionsFromQuery( QSqlQuery &query); - std::vector parseCommentsFromQuery(QSqlQuery &query); + std::vector parseCommentsFromQuery(QSqlQuery &query); void executeScriptFile(QString fileName); void dropAndCreateTables(); diff --git a/DRAMSys/traceAnalyzer/presentation/commenttreewidget.cpp b/DRAMSys/traceAnalyzer/presentation/commenttreewidget.cpp deleted file mode 100644 index 399354a2..00000000 --- a/DRAMSys/traceAnalyzer/presentation/commenttreewidget.cpp +++ /dev/null @@ -1,142 +0,0 @@ -/* - * 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 "commenttreewidget.h" -#include -#include -#include -#include - -CommentTreeWidget::CommentTreeWidget(QWidget *parent) : QTreeWidget(parent), - deleteComment(new QAction("Delete comment", this)), - editCommentText(new QAction("Edit comment text", this)) -{ - connect(deleteComment, &QAction::triggered, this, [this](){ - for (QTreeWidgetItem *item : selectedItems()) - { - CommentTreeItem *commentItem = static_cast(item); - navigator->removeCommentAtTime(commentItem->Time()); - } - }); - - connect(editCommentText, &QAction::triggered, this, [this](){ - for (QTreeWidgetItem *item : selectedItems()) - { - CommentTreeItem *commentItem = static_cast(item); - navigator->editCommentAtTime(commentItem->Time()); - } - }); - - connect(this, &QTreeWidget::itemSelectionChanged, this, [this](){ - std::vector> selectedComments; - - for (auto &item : selectedItems()) - { - CommentTreeItem *commentItem = static_cast(item); - selectedComments.push_back(commentItem->getComment()); - } - - Q_EMIT selectedCommentsChanged(selectedComments); - }); -} - -void CommentTreeWidget::init(TraceNavigator *navigator) -{ - Q_ASSERT(isInitialized == false); - isInitialized = true; - this->navigator = navigator; - setColumnCount(2); - setHeaderLabels(QStringList({"Time", "Comment"})); - QObject::connect(navigator, SIGNAL(commentsChanged()), this, - SLOT(commentsChanged())); - QObject::connect(this, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), this, - SLOT(itemDoubleClicked(QTreeWidgetItem *, int))); - QObject::connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, - SLOT(ContextMenuRequested(QPoint))); - setContextMenuPolicy(Qt::CustomContextMenu); - printComments(); -} - -void CommentTreeWidget::commentsChanged() -{ - clear(); - printComments(); -} - -void CommentTreeWidget::printComments() -{ - for (const auto &pair : navigator->getComments()) { - const std::shared_ptr comment = pair.second; - QTreeWidgetItem *item = new CommentTreeItem(this, comment); - addTopLevelItem(item); - } - resizeColumnToContents(0); -} - -void CommentTreeWidget::itemDoubleClicked(QTreeWidgetItem *item, int /*column*/) -{ - CommentTreeItem *commentItem = static_cast(item); - navigator->navigateToTime(commentItem->Time()); -} - -void CommentTreeWidget::ContextMenuRequested(QPoint point) -{ - if (selectedItems().isEmpty()) - return; - - QMenu contextMenu(this); - contextMenu.addActions({editCommentText, deleteComment}); - contextMenu.exec(mapToGlobal(point)); -} - -CommentTreeWidget::CommentTreeItem::CommentTreeItem(QTreeWidget *parent, - const std::shared_ptr comment): QTreeWidgetItem(parent), comment(comment) -{ - this->setText(0, prettyFormatTime(comment->Time())); - this->setText(1, comment->Text()); -} - -void CommentTreeWidget::keyPressEvent(QKeyEvent *event) -{ - if (event->key() == Qt::Key_Delete) - deleteComment->trigger(); - else if (event->key() == Qt::Key_F2) - editCommentText->trigger(); - - QTreeWidget::keyPressEvent(event); -} diff --git a/DRAMSys/traceAnalyzer/presentation/commenttreewidget.h b/DRAMSys/traceAnalyzer/presentation/commenttreewidget.h deleted file mode 100644 index c5c63bad..00000000 --- a/DRAMSys/traceAnalyzer/presentation/commenttreewidget.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * 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 - */ - -#ifndef COMMENTTREEWIDGET_H -#define COMMENTTREEWIDGET_H -#include -#include -#include -#include "businessObjects/comment.h" -#include "tracenavigator.h" -#include "businessObjects/tracetime.h" - -class CommentTreeWidget : public QTreeWidget -{ - Q_OBJECT - -public: - CommentTreeWidget(QWidget *parent = nullptr); - void init(TraceNavigator *navigator); - -protected: - void keyPressEvent(QKeyEvent *event) override; - -Q_SIGNALS: - void selectedCommentsChanged(std::vector> comments); - -private Q_SLOTS: - void commentsChanged(); - void ContextMenuRequested(QPoint point); - void itemDoubleClicked(QTreeWidgetItem *item, int column); - -private: - bool isInitialized = false; - TraceNavigator *navigator; - void printComments(); - QAction *deleteComment; - QAction *editCommentText; - - class CommentTreeItem : public QTreeWidgetItem - { - private: - const std::shared_ptr comment; - public: - CommentTreeItem(QTreeWidget *parent, const std::shared_ptr comment); - QString Text() - { - return comment->Text(); - } - traceTime Time() - { - return comment->Time(); - } - const std::shared_ptr getComment() - { - return comment; - } - }; - - CommentTreeItem *getTreeItemFromTime(traceTime time); -}; - -#endif // COMMENTTREEWIDGET_H diff --git a/DRAMSys/traceAnalyzer/presentation/debugmessagetreewidget.cpp b/DRAMSys/traceAnalyzer/presentation/debugmessagetreewidget.cpp index df4bdee1..13f1cc7c 100644 --- a/DRAMSys/traceAnalyzer/presentation/debugmessagetreewidget.cpp +++ b/DRAMSys/traceAnalyzer/presentation/debugmessagetreewidget.cpp @@ -84,19 +84,19 @@ void DebugMessageTreeWidget::currentTraceTimeChanged() traceplot->GetCurrentTimespan())); } -void DebugMessageTreeWidget::showDebugMessages(const vector &comments) +void DebugMessageTreeWidget::showDebugMessages(const vector &comments) { clear(); if (comments.empty()) return; traceTime currentTime = -1; - for (Comment comment : comments) { - if (currentTime != comment.Time()) { - addTopLevelItem(new QTreeWidgetItem({prettyFormatTime(comment.Time()), formatDebugMessage(comment.Text())})); - currentTime = comment.Time(); + for (const auto &comment : comments) { + if (currentTime != comment.time) { + addTopLevelItem(new QTreeWidgetItem({prettyFormatTime(comment.time), formatDebugMessage(comment.text)})); + currentTime = comment.time; } else { - addTopLevelItem(new QTreeWidgetItem({"", formatDebugMessage(comment.Text())})); + addTopLevelItem(new QTreeWidgetItem({"", formatDebugMessage(comment.text)})); } } diff --git a/DRAMSys/traceAnalyzer/presentation/debugmessagetreewidget.h b/DRAMSys/traceAnalyzer/presentation/debugmessagetreewidget.h index 906188c6..225a5bf0 100644 --- a/DRAMSys/traceAnalyzer/presentation/debugmessagetreewidget.h +++ b/DRAMSys/traceAnalyzer/presentation/debugmessagetreewidget.h @@ -42,7 +42,7 @@ #include #include #include -#include "businessObjects/comment.h" +#include "businessObjects/commentmodel.h" #include "tracenavigator.h" #include "traceplot.h" @@ -56,7 +56,7 @@ public: hexAdressMatcher(QString("0x[0-9,a-f]+")) {} void init(TraceNavigator *navigator, TracePlot *traceplot); - void showDebugMessages(const std::vector &comments); + void showDebugMessages(const std::vector &comments); void arrangeUiSettings(); public Q_SLOTS: diff --git a/DRAMSys/traceAnalyzer/presentation/tracenavigator.cpp b/DRAMSys/traceAnalyzer/presentation/tracenavigator.cpp index 89448111..47ef74cf 100644 --- a/DRAMSys/traceAnalyzer/presentation/tracenavigator.cpp +++ b/DRAMSys/traceAnalyzer/presentation/tracenavigator.cpp @@ -39,16 +39,21 @@ #include "tracenavigator.h" #include "util/traceplotlinecache.h" #include "vector" +#include "businessObjects/commentmodel.h" #include #include using namespace std; -TraceNavigator::TraceNavigator(QString path, QObject *parent) - : QObject(parent), traceFile(path, true), changesToCommitExist(false) +TraceNavigator::TraceNavigator(QString path, CommentModel *commentModel, QObject *parent) + : QObject(parent), traceFile(path, true), commentModel(commentModel), changesToCommitExist(false) { getCommentsFromDB(); + QObject::connect(commentModel, &CommentModel::gotoCommentTriggered, this, [=](const QModelIndex &index){ + navigateToTime(commentModel->getTimeFromIndex(index)); + }); + tracePlotLineCache = std::make_shared(getTracePlotLines(), GeneralTraceInfo().numberOfRanks, GeneralTraceInfo().groupsPerRank, GeneralTraceInfo().banksPerGroup); @@ -81,102 +86,20 @@ void TraceNavigator::navigateToTransaction(ID id) navigateToTime(traceFile.getTransactionByID(id)->span.Begin()); } - -/* Comment and debug messages - * - */ -void TraceNavigator::insertComment(const Comment &comment) -{ - comments.emplace(comment.Time(), std::make_shared(comment)); - changesToCommitExist = true; - Q_EMIT commentsChanged(); -} - -void TraceNavigator::removeCommentAtTime(traceTime time) -{ - auto found = comments.find(time); - - if (found != comments.end()) { - comments.erase(found); - changesToCommitExist = true; - Q_EMIT commentsChanged(); - } -} - -void TraceNavigator::editCommentAtTime(traceTime time) -{ - auto found = comments.find(time); - - if (found != comments.end()) { - auto comment = found->second; - - bool ok; - QString newText = QInputDialog::getText(nullptr, QString("Edit comment text"), - QString("Edit comment text"), QLineEdit::Normal, - comment->Text(), &ok); - - if (ok) - { - removeCommentAtTime(time); - insertComment({comment->Time(), newText}); - changesToCommitExist = true; - Q_EMIT commentsChanged(); - } - } -} - -void TraceNavigator::addSelectedComments(const std::vector> - &comments) -{ - for (auto &comment : comments) - selectedComments.push_back(comment); - - Q_EMIT selectedCommentsChanged(); -} - -void TraceNavigator::clearSelectedComments() -{ - selectedComments.clear(); - Q_EMIT selectedCommentsChanged(); -} - -void TraceNavigator::updateCommentSelection(std::vector> comments) -{ - selectedComments.clear(); - addSelectedComments(comments); -} - -bool TraceNavigator::commentIsSelected(const std::shared_ptr comment) const -{ - for (auto &selectedComment : selectedComments) - { - if (comment == selectedComment) - return true; - } - - return false; -} - /* DB * */ void TraceNavigator::commitChangesToDB() { - vector commentsToInsert; - for (const auto &pair : comments) { - commentsToInsert.push_back(*pair.second.get()); - } - - traceFile.updateComments(commentsToInsert); + traceFile.updateComments(commentModel->getComments()); changesToCommitExist = false; } void TraceNavigator::getCommentsFromDB() { - for (const Comment &comment : traceFile.getComments()) { - comments.emplace(comment.Time(), std::make_shared(comment)); - } + for (const auto &comment : traceFile.getComments()) + commentModel->addComment(comment.time, comment.text); } void TraceNavigator::refreshData() @@ -389,3 +312,8 @@ std::shared_ptr TraceNavigator::getTracePlotLineCache() { return tracePlotLineCache; } + +const CommentModel *TraceNavigator::getCommentModel() const +{ + return commentModel; +} diff --git a/DRAMSys/traceAnalyzer/presentation/tracenavigator.h b/DRAMSys/traceAnalyzer/presentation/tracenavigator.h index 00c76294..d72e1f52 100644 --- a/DRAMSys/traceAnalyzer/presentation/tracenavigator.h +++ b/DRAMSys/traceAnalyzer/presentation/tracenavigator.h @@ -43,10 +43,10 @@ #include "data/tracedb.h" #include "businessObjects/generalinfo.h" #include "businessObjects/transaction.h" -#include "businessObjects/comment.h" #include "memory" class TracePlotLineCache; +class CommentModel; /* Class to navigate through a tracefile * @@ -56,10 +56,9 @@ class TracePlotLineCache; class TraceNavigator : public QObject { Q_OBJECT - using CommentMap = std::map>; public: - TraceNavigator(QString path, QObject *parent = 0); + TraceNavigator(QString path, CommentModel *commentModel, QObject *parent = 0); ~TraceNavigator(); traceTime CurrentTraceTime() const @@ -111,37 +110,17 @@ public: bool transactionIsSelected(const std::shared_ptr &Transaction) const; - void insertComment(const Comment &comment); - const CommentMap &getComments() - { - return comments; - } - void removeCommentAtTime(traceTime time); - void editCommentAtTime(traceTime time); - void addSelectedComments(const std::vector> - &comments); - void clearSelectedComments(); - const std::vector> &SelectedComments() - { - return selectedComments; - } - - bool commentIsSelected(const std::shared_ptr comment) const; - void commitChangesToDB(); void refreshData(); std::shared_ptr getTracePlotLines(); std::shared_ptr getTracePlotLineCache(); + const CommentModel *getCommentModel() const; + Q_SIGNALS: void currentTraceTimeChanged(); void selectedTransactionsChanged(); - void selectedCommentsChanged(); - void commentsChanged(); - -public Q_SLOTS: - void updateCommentSelection(std::vector> comments); private: TraceDB traceFile; @@ -150,8 +129,9 @@ private: //components drawing the tracefile center around that time traceTime currentTraceTime = 0; std::vector> selectedTransactions; - std::vector> selectedComments; - CommentMap comments; + + CommentModel *commentModel; + void getCommentsFromDB(); bool changesToCommitExist; diff --git a/DRAMSys/traceAnalyzer/presentation/traceplot.cpp b/DRAMSys/traceAnalyzer/presentation/traceplot.cpp index 64fbf582..905088a7 100644 --- a/DRAMSys/traceAnalyzer/presentation/traceplot.cpp +++ b/DRAMSys/traceAnalyzer/presentation/traceplot.cpp @@ -55,6 +55,7 @@ #include "traceplot.h" #include "gototimedialog.h" #include "tracedrawing.h" +#include "businessObjects/commentmodel.h" #include "util/engineeringScaleDraw.h" #include "util/clkgrid.h" #include "util/customlabelscaledraw.h" @@ -184,12 +185,24 @@ void TracePlot::setUpContextMenu() contextMenu->addActions({showQueryEditor, insertComment, exportToPdf, toggleCollapsedState}); } -void TracePlot::init(TraceNavigator *navigator, QScrollBar *scrollBar) +void TracePlot::init(TraceNavigator *navigator, QScrollBar *scrollBar, CommentModel *commentModel) { Q_ASSERT(isInitialized == false); isInitialized = true; this->scrollBar = scrollBar; + this->commentModel = commentModel; + + 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); this->navigator = navigator; connectNavigatorQ_SIGNALS(); @@ -216,10 +229,6 @@ void TracePlot::connectNavigatorQ_SIGNALS() SLOT(currentTraceTimeChanged())); QObject::connect(navigator, SIGNAL(selectedTransactionsChanged()), this, SLOT(selectedTransactionsChanged())); - QObject::connect(navigator, SIGNAL(selectedCommentsChanged()), this, - SLOT(commentsChanged())); - QObject::connect(navigator, SIGNAL(commentsChanged()), this, - SLOT(commentsChanged())); } void TracePlot::setUpDrawingProperties() @@ -345,17 +354,22 @@ Timespan TracePlot::GetCurrentTimespan() void TracePlot::getAndDrawComments() { - for (const auto &pair : navigator->getComments()) { - const std::shared_ptr comment = pair.second; - bool highlight = navigator->commentIsSelected(comment); + QList selectedRows = commentModel->selectionModel()->selectedRows(); + + for (int row = 0; row < commentModel->rowCount(); row++) + { + QModelIndex timeIndex = commentModel->index(row, static_cast(CommentModel::Column::Time)); + QModelIndex textIndex = commentModel->index(row, static_cast(CommentModel::Column::Comment)); + + bool selected = std::find(selectedRows.begin(), selectedRows.end(), commentModel->index(row, 0)) != selectedRows.end(); QwtPlotMarker *marker = new QwtPlotMarker(); - marker->setLabel(comment->Text()); + marker->setLabel(textIndex.data().toString()); marker->setLabelOrientation(Qt::Vertical); marker->setLabelAlignment(Qt::AlignLeft | Qt::AlignBottom); - marker->setXValue(static_cast(comment->Time())); + marker->setXValue(static_cast(timeIndex.data(Qt::UserRole).toLongLong())); marker->setLineStyle(QwtPlotMarker::LineStyle::VLine); - marker->setLinePen(QColor(highlight ? Qt::red : Qt::blue), 2); + marker->setLinePen(QColor(selected ? Qt::red : Qt::blue), 2); marker->attach(this); } } @@ -545,13 +559,7 @@ void TracePlot::on_deselectAll() 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)); - } + commentModel->addComment(time); } void TracePlot::on_goToTime() @@ -727,59 +735,32 @@ void TracePlot::SelectTransaction(int x, int y) const void TracePlot::SelectComment(int x) const { - traceTime time = invTransform(xBottom, x); + Timespan timespan = hoveredTimespan(x); + QModelIndex index = commentModel->hoveredComment(timespan); - auto selectedComments = hoveredComments(time); + if (!index.isValid()) + commentModel->selectionModel()->clearSelection(); - if (selectedComments.size() > 0) { - if (!keyPressData.ctrlPressed) - navigator->clearSelectedComments(); - - navigator->addSelectedComments(selectedComments); - } else { - navigator->clearSelectedComments(); - } + if (keyPressData.ctrlPressed) + commentModel->selectionModel()->setCurrentIndex(index, QItemSelectionModel::Toggle | QItemSelectionModel::Rows); + else + commentModel->selectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); } -const std::vector> TracePlot::hoveredComments(traceTime time) const +Timespan TracePlot::hoveredTimespan(int x) const { - std::vector> hoveredComments; + traceTime time = invTransform(xBottom, x); + traceTime offset = 0.01 * zoomLevel; - for (const auto &commentPair : navigator->getComments()) - { - auto comment = commentPair.second; - if (comment->isSelected(time, navigator->GeneralTraceInfo().clkPeriod)) - hoveredComments.push_back(comment); - } - - return hoveredComments; + return Timespan(time - offset, time + offset); } void TracePlot::openContextMenu(const QPoint &pos, const QPoint &mouseDown) { contextMenuMouseDown = mouseDown; - traceTime time = invTransform(xBottom, mouseDown.x()); - auto comments = hoveredComments(time); - - if (comments.size() == 0) - contextMenu->exec(pos); + if (commentModel->selectionModel()->hasSelection()) + commentModel->openContextMenu(); else - { - QMenu commentContextMenu(this); - QAction editCommentText("Edit comment text", this); - QAction deleteComment("Delete comment", this); - - auto commentTime = comments[0]->Time(); - connect(&editCommentText, &QAction::triggered, this, [=](){ - navigator->editCommentAtTime(commentTime); - }); - - connect(&deleteComment, &QAction::triggered, this, [=](){ - navigator->removeCommentAtTime(commentTime); - }); - - commentContextMenu.addActions({&editCommentText, &deleteComment}); - commentContextMenu.exec(pos); - } + contextMenu->exec(pos); } diff --git a/DRAMSys/traceAnalyzer/presentation/traceplot.h b/DRAMSys/traceAnalyzer/presentation/traceplot.h index 10dd534d..bea93693 100644 --- a/DRAMSys/traceAnalyzer/presentation/traceplot.h +++ b/DRAMSys/traceAnalyzer/presentation/traceplot.h @@ -63,6 +63,7 @@ class TracePlotMouseLabel; class CustomLabelScaleDraw; class ToggleCollapsedAction; +class CommentModel; class TracePlot : public QwtPlot { @@ -71,7 +72,7 @@ class TracePlot : public QwtPlot public: TracePlot(QWidget *parent = NULL); - void init(TraceNavigator *navigator, QScrollBar *scrollBar); + void init(TraceNavigator *navigator, QScrollBar *scrollBar, CommentModel *commentModel); Timespan GetCurrentTimespan(); traceTime ZoomLevel() const { @@ -97,6 +98,7 @@ Q_SIGNALS: void tracePlotZoomChanged(); void tracePlotLinesChanged(); void colorGroupingChanged(ColorGrouping colorgrouping); + // void editComment private Q_SLOTS: void on_executeQuery(); @@ -129,6 +131,7 @@ private: QMenu *contextMenu; QScrollBar *scrollBar; CustomLabelScaleDraw *customLabelScaleDraw; + CommentModel *commentModel; void setUpTracePlotItem(); void setUpDrawingProperties(); @@ -188,7 +191,8 @@ private: QPoint contextMenuMouseDown; void SelectTransaction(int x, int y) const; void SelectComment(int x) const; - const std::vector> hoveredComments(traceTime time) const; + //const std::vector> hoveredComments(traceTime time) const; + Timespan hoveredTimespan(int x) const; void keyPressEvent(QKeyEvent *keyPressedEvent); void keyReleaseEvent(QKeyEvent *keyReleasedEvent); diff --git a/DRAMSys/traceAnalyzer/presentation/tracescroller.cpp b/DRAMSys/traceAnalyzer/presentation/tracescroller.cpp index 91b8b3a2..ef412d89 100644 --- a/DRAMSys/traceAnalyzer/presentation/tracescroller.cpp +++ b/DRAMSys/traceAnalyzer/presentation/tracescroller.cpp @@ -62,6 +62,17 @@ void TraceScroller::init(TraceNavigator *navigator, TracePlot *tracePlot) this -> navigator = navigator; connectNavigatorQ_SIGNALS(); + const CommentModel *commentModel = navigator->getCommentModel(); + + QObject::connect(commentModel, &CommentModel::dataChanged, + this, &TraceScroller::commentsChanged); + + QObject::connect(commentModel, &CommentModel::rowsRemoved, + this, &TraceScroller::commentsChanged); + + QObject::connect(commentModel->selectionModel(), &QItemSelectionModel::selectionChanged, + this, &TraceScroller::commentsChanged); + setUpDrawingProperties(); setUpAxis(); setUpTracePlotItem(); @@ -149,14 +160,19 @@ Timespan TraceScroller::GetCurrentTimespan() void TraceScroller::getAndDrawComments() { - for (const auto &pair : navigator->getComments()) { - const std::shared_ptr comment = pair.second; - bool highlight = navigator->commentIsSelected(comment); + const CommentModel *commentModel = navigator->getCommentModel(); + QList selectedRows = commentModel->selectionModel()->selectedRows(); + + for (int row = 0; row < commentModel->rowCount(); row++) + { + QModelIndex timeIndex = commentModel->index(row, static_cast(CommentModel::Column::Time)); + + bool selected = std::find(selectedRows.begin(), selectedRows.end(), commentModel->index(row, 0)) != selectedRows.end(); QwtPlotMarker *maker = new QwtPlotMarker(); - maker->setXValue(static_cast(comment->Time())); + maker->setXValue(static_cast(timeIndex.data(Qt::UserRole).toLongLong())); maker->setLineStyle(QwtPlotMarker::LineStyle::VLine); - maker->setLinePen(QColor(highlight ? Qt::red : Qt::blue), 2); + maker->setLinePen(QColor(selected ? Qt::red : Qt::blue), 2); maker->attach(this); } } diff --git a/DRAMSys/traceAnalyzer/presentation/tracescroller.h b/DRAMSys/traceAnalyzer/presentation/tracescroller.h index 8a5d8583..310d46d1 100644 --- a/DRAMSys/traceAnalyzer/presentation/tracescroller.h +++ b/DRAMSys/traceAnalyzer/presentation/tracescroller.h @@ -60,7 +60,6 @@ private: void setUpAxis(); void connectNavigatorQ_SIGNALS(); - void getAndDrawComments(); QwtPlotZoneItem *canvasClip; traceTime zoomLevel; diff --git a/DRAMSys/traceAnalyzer/tracefiletab.cpp b/DRAMSys/traceAnalyzer/tracefiletab.cpp index 1fe452d0..bca568d4 100644 --- a/DRAMSys/traceAnalyzer/tracefiletab.cpp +++ b/DRAMSys/traceAnalyzer/tracefiletab.cpp @@ -60,6 +60,7 @@ #include "qwt_plot_panner.h" #include "presentation/traceselector.h" #include "businessObjects/configmodels.h" +#include "businessObjects/commentmodel.h" #include @@ -67,7 +68,7 @@ TraceFileTab::TraceFileTab(QWidget *parent, const QString &path) : QWidget(parent), ui(new Ui::TraceFileTab), navigator(new TraceNavigator(path, this)), mcConfigModel(new McConfigModel(navigator->TraceFile(), this)), memSpecModel(new MemSpecModel(navigator->TraceFile(), this)), - savingChangesToDB(false) + commentModel(new CommentModel(this)), savingChangesToDB(false) { ui->setupUi(this); this->path = path; @@ -79,6 +80,7 @@ TraceFileTab::TraceFileTab(QWidget *parent, const QString &path) : setUpFileWatcher(path); setUpTraceplotScrollbar(); setUpTraceSelector(); + setUpCommentView(); ui->fileDescriptionEdit->setPlainText( navigator->GeneralTraceInfo().description); @@ -89,9 +91,6 @@ TraceFileTab::TraceFileTab(QWidget *parent, const QString &path) : ui->memSpecView->setModel(memSpecModel); ui->memSpecView->header()->setSectionResizeMode(QHeaderView::ResizeToContents); - connect(ui->commentTree, &CommentTreeWidget::selectedCommentsChanged, - navigator, &TraceNavigator::updateCommentSelection); - tracefileChanged(); } @@ -135,7 +134,9 @@ void TraceFileTab::setUpTraceplotScrollbar() void TraceFileTab::initNavigatorAndItsDependentWidgets(QString path) { - ui->traceplot->init(navigator, ui->traceplotScrollbar); + navigator = new TraceNavigator(path, commentModel, this); + + ui->traceplot->init(navigator, ui->traceplotScrollbar, commentModel); ui->traceScroller->init(navigator, ui->traceplot); connect(this, SIGNAL(colorGroupingChanged(ColorGrouping)), @@ -143,7 +144,6 @@ void TraceFileTab::initNavigatorAndItsDependentWidgets(QString path) ui->selectedTransactionTree->init(navigator); //ui->debugMessages->init(navigator,ui->traceplot); - ui->commentTree->init(navigator); } void TraceFileTab::setUpFileWatcher(QString path) @@ -161,6 +161,23 @@ void TraceFileTab::setUpTraceSelector() selector->init(ui->traceplot); } +void TraceFileTab::setUpCommentView() +{ + ui->commentView->setModel(commentModel); + ui->commentView->setSelectionModel(commentModel->selectionModel()); + ui->commentView->installEventFilter(commentModel); + ui->commentView->setContextMenuPolicy(Qt::CustomContextMenu); + + QObject::connect(ui->commentView, &QTableView::customContextMenuRequested, + commentModel, &CommentModel::openContextMenu); + + QObject::connect(commentModel, &CommentModel::editTriggered, ui->commentView, [=](const QModelIndex &index){ + ui->tabWidget->setCurrentWidget(ui->tabSelectedTrans); + ui->commentView->edit(index); + ui->commentView->scrollTo(index); + }); +} + void TraceFileTab::tracefileChanged() { if (savingChangesToDB == true) { diff --git a/DRAMSys/traceAnalyzer/tracefiletab.h b/DRAMSys/traceAnalyzer/tracefiletab.h index 966d5784..58329853 100644 --- a/DRAMSys/traceAnalyzer/tracefiletab.h +++ b/DRAMSys/traceAnalyzer/tracefiletab.h @@ -47,6 +47,8 @@ #include "presentation/tracescroller.h" #include "businessObjects/configmodels.h" +class CommentModel; + namespace Ui { class TraceFileTab; } @@ -62,6 +64,7 @@ public: void setUpFileWatcher(QString filename); void setUpTraceplotScrollbar(); void setUpTraceSelector(); + void setUpCommentView(); void initNavigatorAndItsDependentWidgets(QString path); QString getPathToTraceFile() { @@ -78,6 +81,7 @@ private: QAbstractItemModel *mcConfigModel; QAbstractItemModel *memSpecModel; + CommentModel *commentModel; void setUpQueryEditor(QString path); bool savingChangesToDB; diff --git a/DRAMSys/traceAnalyzer/tracefiletab.ui b/DRAMSys/traceAnalyzer/tracefiletab.ui index 64693bdb..647a3b50 100644 --- a/DRAMSys/traceAnalyzer/tracefiletab.ui +++ b/DRAMSys/traceAnalyzer/tracefiletab.ui @@ -170,7 +170,7 @@ - + 2 @@ -189,11 +189,27 @@ 16777215 - - - 1 - - + + QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed + + + true + + + QAbstractItemView::SelectRows + + + Qt::NoPen + + + false + + + true + + + false + @@ -402,11 +418,6 @@ QListView
presentation/tracescroller.h
- - CommentTreeWidget - QTreeWidget -
presentation/commenttreewidget.h
-
SelectedTransactionTreeWidget QTreeWidget From 1ad53a354f3770aa5762bc3ef646cdf0b157e7dd Mon Sep 17 00:00:00 2001 From: Derek Christ Date: Mon, 13 Sep 2021 10:34:10 +0200 Subject: [PATCH 5/9] Add ability to goto comment by double-clicking time. Also remove some legacy signal-slot connections. --- DRAMSys/traceAnalyzer/businessObjects/commentmodel.cpp | 9 +++++++++ DRAMSys/traceAnalyzer/businessObjects/commentmodel.h | 3 +++ DRAMSys/traceAnalyzer/presentation/tracescroller.cpp | 6 ------ DRAMSys/traceAnalyzer/tracefiletab.cpp | 3 +++ 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/DRAMSys/traceAnalyzer/businessObjects/commentmodel.cpp b/DRAMSys/traceAnalyzer/businessObjects/commentmodel.cpp index 940cd07e..ebe15216 100644 --- a/DRAMSys/traceAnalyzer/businessObjects/commentmodel.cpp +++ b/DRAMSys/traceAnalyzer/businessObjects/commentmodel.cpp @@ -280,3 +280,12 @@ bool CommentModel::eventFilter(QObject *object, QEvent *event) return false; } + +void CommentModel::rowDoubleClicked(const QModelIndex &index) +{ + if (!index.isValid()) + return; + + if (static_cast(index.column()) == Column::Time) + Q_EMIT gotoCommentTriggered(index); +} diff --git a/DRAMSys/traceAnalyzer/businessObjects/commentmodel.h b/DRAMSys/traceAnalyzer/businessObjects/commentmodel.h index f540663a..93249781 100644 --- a/DRAMSys/traceAnalyzer/businessObjects/commentmodel.h +++ b/DRAMSys/traceAnalyzer/businessObjects/commentmodel.h @@ -87,6 +87,9 @@ public: QModelIndex hoveredComment(Timespan timespan) const; +public Q_SLOTS: + void rowDoubleClicked(const QModelIndex &index); + protected: bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; diff --git a/DRAMSys/traceAnalyzer/presentation/tracescroller.cpp b/DRAMSys/traceAnalyzer/presentation/tracescroller.cpp index ef412d89..feaab60e 100644 --- a/DRAMSys/traceAnalyzer/presentation/tracescroller.cpp +++ b/DRAMSys/traceAnalyzer/presentation/tracescroller.cpp @@ -130,12 +130,6 @@ void TraceScroller::connectNavigatorQ_SIGNALS() { QObject::connect(navigator, SIGNAL(currentTraceTimeChanged()), this, SLOT(currentTraceTimeChanged())); - QObject::connect(navigator, SIGNAL(commentsChanged()), this, - SLOT(commentsChanged())); - QObject::connect(navigator, SIGNAL(selectedCommentsChanged()), this, - SLOT(commentsChanged())); - QObject::connect(navigator, SIGNAL(selectedTransactionsChanged()), this, - SLOT(selectedTransactionsChanged())); } Timespan TraceScroller::GetCurrentTimespan() diff --git a/DRAMSys/traceAnalyzer/tracefiletab.cpp b/DRAMSys/traceAnalyzer/tracefiletab.cpp index bca568d4..324a1a2a 100644 --- a/DRAMSys/traceAnalyzer/tracefiletab.cpp +++ b/DRAMSys/traceAnalyzer/tracefiletab.cpp @@ -176,6 +176,9 @@ void TraceFileTab::setUpCommentView() ui->commentView->edit(index); ui->commentView->scrollTo(index); }); + + QObject::connect(ui->commentView, &QTableView::doubleClicked, + commentModel, &CommentModel::rowDoubleClicked); } void TraceFileTab::tracefileChanged() From 5b75b8cb7e166304355b8ad52039a10a997b480b Mon Sep 17 00:00:00 2001 From: Derek Christ Date: Tue, 14 Sep 2021 12:11:30 +0200 Subject: [PATCH 6/9] Fix a bug in TraceScroller and improve comment selection. Comments will now stay selected when dragging the view. Deselection can be achieved by triggering the deselectAll action in the context menu, by deselecting the comments in the comment view or by right-clicking a specific comment in the plot. --- .../traceAnalyzer/businessObjects/commentmodel.cpp | 14 ++++++++++++++ .../traceAnalyzer/businessObjects/commentmodel.h | 2 ++ DRAMSys/traceAnalyzer/presentation/traceplot.cpp | 5 +++-- .../traceAnalyzer/presentation/tracescroller.cpp | 3 +++ 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/DRAMSys/traceAnalyzer/businessObjects/commentmodel.cpp b/DRAMSys/traceAnalyzer/businessObjects/commentmodel.cpp index ebe15216..c6cdad28 100644 --- a/DRAMSys/traceAnalyzer/businessObjects/commentmodel.cpp +++ b/DRAMSys/traceAnalyzer/businessObjects/commentmodel.cpp @@ -43,6 +43,8 @@ CommentModel::CommentModel(QObject *parent) : QAbstractTableModel(parent), gotoAction(new QAction("Goto comment", this)), editAction(new QAction("Edit comment", this)), deleteAction(new QAction("Delete comment", this)), + selectAllAction(new QAction("Select all comments", this)), + deselectAllAction(new QAction("Deselect all comments", this)), internalSelectionModel(new QItemSelectionModel(this, this)) { setUpActions(); @@ -69,6 +71,16 @@ void CommentModel::setUpActions() for (const QModelIndex ¤tIndex : indexes) removeComment(currentIndex); }); + + QObject::connect(selectAllAction, &QAction::triggered, this, [=](){ + QModelIndex topLeft = index(0, 0); + QModelIndex bottomRight = index(rowCount() - 1, columnCount() - 1); + internalSelectionModel->select(QItemSelection(topLeft, bottomRight), + QItemSelectionModel::Select | QItemSelectionModel::Rows); + }); + + QObject::connect(deselectAllAction, &QAction::triggered, + internalSelectionModel, &QItemSelectionModel::clearSelection); } int CommentModel::rowCount(const QModelIndex &parent) const @@ -168,6 +180,8 @@ void CommentModel::openContextMenu() QMenu *menu = new QMenu(); menu->addActions({gotoAction, editAction, deleteAction}); + menu->addSeparator(); + menu->addActions({selectAllAction, deselectAllAction}); QObject::connect(menu, &QMenu::aboutToHide, [=]() { menu->deleteLater(); diff --git a/DRAMSys/traceAnalyzer/businessObjects/commentmodel.h b/DRAMSys/traceAnalyzer/businessObjects/commentmodel.h index 93249781..a9e165a6 100644 --- a/DRAMSys/traceAnalyzer/businessObjects/commentmodel.h +++ b/DRAMSys/traceAnalyzer/businessObjects/commentmodel.h @@ -110,6 +110,8 @@ private: QAction *gotoAction; QAction *editAction; QAction *deleteAction; + QAction *selectAllAction; + QAction *deselectAllAction; QItemSelectionModel *internalSelectionModel; }; diff --git a/DRAMSys/traceAnalyzer/presentation/traceplot.cpp b/DRAMSys/traceAnalyzer/presentation/traceplot.cpp index 905088a7..c6d4133e 100644 --- a/DRAMSys/traceAnalyzer/presentation/traceplot.cpp +++ b/DRAMSys/traceAnalyzer/presentation/traceplot.cpp @@ -739,7 +739,7 @@ void TracePlot::SelectComment(int x) const QModelIndex index = commentModel->hoveredComment(timespan); if (!index.isValid()) - commentModel->selectionModel()->clearSelection(); + return; if (keyPressData.ctrlPressed) commentModel->selectionModel()->setCurrentIndex(index, QItemSelectionModel::Toggle | QItemSelectionModel::Rows); @@ -758,8 +758,9 @@ Timespan TracePlot::hoveredTimespan(int x) const void TracePlot::openContextMenu(const QPoint &pos, const QPoint &mouseDown) { contextMenuMouseDown = mouseDown; + Timespan timespan = hoveredTimespan(mouseDown.x()); - if (commentModel->selectionModel()->hasSelection()) + if (commentModel->hoveredComment(timespan).isValid()) commentModel->openContextMenu(); else contextMenu->exec(pos); diff --git a/DRAMSys/traceAnalyzer/presentation/tracescroller.cpp b/DRAMSys/traceAnalyzer/presentation/tracescroller.cpp index feaab60e..12d34018 100644 --- a/DRAMSys/traceAnalyzer/presentation/tracescroller.cpp +++ b/DRAMSys/traceAnalyzer/presentation/tracescroller.cpp @@ -130,6 +130,9 @@ void TraceScroller::connectNavigatorQ_SIGNALS() { QObject::connect(navigator, SIGNAL(currentTraceTimeChanged()), this, SLOT(currentTraceTimeChanged())); + + QObject::connect(navigator, SIGNAL(selectedTransactionsChanged()), this, + SLOT(selectedTransactionsChanged())); } Timespan TraceScroller::GetCurrentTimespan() From 2ccfc4abf5b3d29870f3f19457950d43f16759d5 Mon Sep 17 00:00:00 2001 From: Derek Christ Date: Tue, 14 Sep 2021 19:17:34 +0200 Subject: [PATCH 7/9] Introduce QMessageBox that asks the user to save a changed TraceFile The TraceAnalyzer now asks the user to save the changed TraceFile (eg. modified comments, etc.) when closing the tab. --- .../presentation/tracenavigator.cpp | 13 +++ .../presentation/tracenavigator.h | 5 ++ DRAMSys/traceAnalyzer/traceanalyzer.cpp | 53 ++++++++---- DRAMSys/traceAnalyzer/traceanalyzer.h | 3 + DRAMSys/traceAnalyzer/tracefiletab.cpp | 82 +++++++++++++------ DRAMSys/traceAnalyzer/tracefiletab.h | 8 +- 6 files changed, 121 insertions(+), 43 deletions(-) diff --git a/DRAMSys/traceAnalyzer/presentation/tracenavigator.cpp b/DRAMSys/traceAnalyzer/presentation/tracenavigator.cpp index 47ef74cf..f5ab5a0b 100644 --- a/DRAMSys/traceAnalyzer/presentation/tracenavigator.cpp +++ b/DRAMSys/traceAnalyzer/presentation/tracenavigator.cpp @@ -54,6 +54,9 @@ TraceNavigator::TraceNavigator(QString path, CommentModel *commentModel, QObject navigateToTime(commentModel->getTimeFromIndex(index)); }); + QObject::connect(commentModel, &CommentModel::dataChanged, this, &TraceNavigator::traceFileModified); + QObject::connect(commentModel, &CommentModel::rowsRemoved, this, &TraceNavigator::traceFileModified); + tracePlotLineCache = std::make_shared(getTracePlotLines(), GeneralTraceInfo().numberOfRanks, GeneralTraceInfo().groupsPerRank, GeneralTraceInfo().banksPerGroup); @@ -317,3 +320,13 @@ const CommentModel *TraceNavigator::getCommentModel() const { return commentModel; } + +bool TraceNavigator::existChangesToCommit() const +{ + return changesToCommitExist; +} + +void TraceNavigator::traceFileModified() +{ + changesToCommitExist = true; +} diff --git a/DRAMSys/traceAnalyzer/presentation/tracenavigator.h b/DRAMSys/traceAnalyzer/presentation/tracenavigator.h index d72e1f52..f8a89bf1 100644 --- a/DRAMSys/traceAnalyzer/presentation/tracenavigator.h +++ b/DRAMSys/traceAnalyzer/presentation/tracenavigator.h @@ -118,10 +118,15 @@ public: const CommentModel *getCommentModel() const; + bool existChangesToCommit() const; + Q_SIGNALS: void currentTraceTimeChanged(); void selectedTransactionsChanged(); +public Q_SLOTS: + void traceFileModified(); + private: TraceDB traceFile; diff --git a/DRAMSys/traceAnalyzer/traceanalyzer.cpp b/DRAMSys/traceAnalyzer/traceanalyzer.cpp index 02103ce7..0a3454fb 100644 --- a/DRAMSys/traceAnalyzer/traceanalyzer.cpp +++ b/DRAMSys/traceAnalyzer/traceanalyzer.cpp @@ -37,12 +37,13 @@ */ #include "traceanalyzer.h" -#include "ui_traceanalyzer.h" +#include "QMessageBox" #include "tracefiletab.h" +#include "ui_traceanalyzer.h" +#include +#include #include #include -#include -#include "QMessageBox" #include void TraceAnalyzer::setUpStatusBar() @@ -137,15 +138,21 @@ void TraceAnalyzer::on_traceFileTabs_tabCloseRequested(int index) { TraceFileTab *traceFileTab = static_cast (ui->traceFileTabs->widget(index)); - openedTraceFiles.remove(traceFileTab->getPathToTraceFile()); - ui->traceFileTabs->removeTab(index); - delete traceFileTab; + + if (traceFileTab->close()) + { + openedTraceFiles.remove(traceFileTab->getPathToTraceFile()); + ui->traceFileTabs->removeTab(index); + delete traceFileTab; + } } void TraceAnalyzer::on_actionClose_all_triggered() { - while (ui->traceFileTabs->count()) - on_traceFileTabs_tabCloseRequested(0); + for (unsigned int i = ui->traceFileTabs->count(); i--;) + { + on_traceFileTabs_tabCloseRequested(i); + } // All files closed. Disable actions except for "Open". ui->actionReload_all->setEnabled(false); @@ -163,23 +170,24 @@ void TraceAnalyzer::on_actionReload_all_triggered() TraceFileTab *traceFileTab; // Remove all tabs - int tabIndex = 0; - while (ui->traceFileTabs->count() != 0) { + for (unsigned int i = ui->traceFileTabs->count(); i--;) + { traceFileTab = static_cast(ui->traceFileTabs->widget(0)); - std::cout << "Closing tab #" << tabIndex << " \"" << - traceFileTab->getPathToTraceFile().toStdString() << "\"" << std::endl; + std::cout << "Closing tab #" << i << " \"" << traceFileTab->getPathToTraceFile().toStdString() << "\"" + << std::endl; + + if (!traceFileTab->close()) + return; ui->traceFileTabs->removeTab(0); delete traceFileTab; - - tabIndex++; } QList list = openedTraceFiles.toList(); qSort(list); // Recreate all tabs - tabIndex = 0; + int tabIndex = 0; for (auto path : list) { std::cout << "Reopening tab# " << tabIndex << " \"" << path.toStdString() << "\"" << std::endl; @@ -231,3 +239,18 @@ void TraceAnalyzer::on_actionMetrics_triggered() evaluationTool.activateWindow(); evaluationTool.showAndEvaluateMetrics(openedTraceFiles.toList()); } + +void TraceAnalyzer::closeEvent(QCloseEvent *event) +{ + for (unsigned int i = 0; i < ui->traceFileTabs->count(); i++) + { + QWidget *tab = ui->traceFileTabs->widget(i); + if (!tab->close()) + { + event->ignore(); + return; + } + } + + event->accept(); +} diff --git a/DRAMSys/traceAnalyzer/traceanalyzer.h b/DRAMSys/traceAnalyzer/traceanalyzer.h index f28ae7e2..cfcf9e58 100644 --- a/DRAMSys/traceAnalyzer/traceanalyzer.h +++ b/DRAMSys/traceAnalyzer/traceanalyzer.h @@ -67,6 +67,9 @@ public: void setUpStatusBar(); void setUpGui(); +protected: + void closeEvent(QCloseEvent *event) override; + private: void openTracefile(const QString &path); QLabel *statusLabel; diff --git a/DRAMSys/traceAnalyzer/tracefiletab.cpp b/DRAMSys/traceAnalyzer/tracefiletab.cpp index 324a1a2a..db6d3f62 100644 --- a/DRAMSys/traceAnalyzer/tracefiletab.cpp +++ b/DRAMSys/traceAnalyzer/tracefiletab.cpp @@ -37,38 +37,37 @@ */ #include "tracefiletab.h" -#include "ui_tracefiletab.h" -#include "queryeditor.h" #include "QFileInfo" -#include "qmessagebox.h" +#include "businessObjects/commentmodel.h" +#include "businessObjects/configmodels.h" #include "businessObjects/pythoncaller.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include "qwt_plot_histogram.h" -#include "qwt_plot_curve.h" -#include "qwt_plot_layout.h" -#include "qwt_scale_draw.h" -#include "qwt_scale_widget.h" +#include "presentation/traceselector.h" +#include "qmessagebox.h" +#include "queryeditor.h" #include "qwt_legend.h" +#include "qwt_plot_curve.h" +#include "qwt_plot_histogram.h" +#include "qwt_plot_layout.h" #include "qwt_plot_magnifier.h" #include "qwt_plot_panner.h" -#include "presentation/traceselector.h" -#include "businessObjects/configmodels.h" -#include "businessObjects/commentmodel.h" +#include "qwt_scale_draw.h" +#include "qwt_scale_widget.h" +#include "ui_tracefiletab.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include -#include - -TraceFileTab::TraceFileTab(QWidget *parent, const QString &path) : - QWidget(parent), ui(new Ui::TraceFileTab), navigator(new TraceNavigator(path, this)), - mcConfigModel(new McConfigModel(navigator->TraceFile(), this)), - memSpecModel(new MemSpecModel(navigator->TraceFile(), this)), - commentModel(new CommentModel(this)), savingChangesToDB(false) +TraceFileTab::TraceFileTab(QWidget *parent, const QString &path) + : QWidget(parent), ui(new Ui::TraceFileTab), commentModel(new CommentModel(this)), + navigator(new TraceNavigator(path, commentModel, this)), + mcConfigModel(new McConfigModel(navigator->TraceFile(), this)), + memSpecModel(new MemSpecModel(navigator->TraceFile(), this)), savingChangesToDB(false) { ui->setupUi(this); this->path = path; @@ -199,6 +198,37 @@ void TraceFileTab::tracefileChanged() navigator->refreshData(); } +void TraceFileTab::closeEvent(QCloseEvent *event) +{ + if (navigator->existChangesToCommit()) + { + QMessageBox saveDialog; + saveDialog.setWindowTitle(QFileInfo(path).baseName()); + saveDialog.setText("The trace file has been modified."); + saveDialog.setInformativeText("Do you want to save your changes?
Unsaved changes will be lost."); + saveDialog.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); + saveDialog.setDefaultButton(QMessageBox::Save); + saveDialog.setIcon(QMessageBox::Warning); + int returnCode = saveDialog.exec(); + + switch (returnCode) + { + case QMessageBox::Cancel: + event->ignore(); + break; + case QMessageBox::Discard: + event->accept(); + break; + case QMessageBox::Save: + commitChangesToDB(); + event->accept(); + break; + }; + } + else + event->accept(); +} + class ItemDelegate: public QItemDelegate { public: diff --git a/DRAMSys/traceAnalyzer/tracefiletab.h b/DRAMSys/traceAnalyzer/tracefiletab.h index 58329853..1962088d 100644 --- a/DRAMSys/traceAnalyzer/tracefiletab.h +++ b/DRAMSys/traceAnalyzer/tracefiletab.h @@ -73,15 +73,19 @@ public: void commitChangesToDB(void); void exportAsVCD(); +protected: + void closeEvent(QCloseEvent *event) override; + private: QString path; Ui::TraceFileTab *ui; - TraceNavigator *navigator; QFileSystemWatcher *fileWatcher; + CommentModel *commentModel; + TraceNavigator *navigator; + QAbstractItemModel *mcConfigModel; QAbstractItemModel *memSpecModel; - CommentModel *commentModel; void setUpQueryEditor(QString path); bool savingChangesToDB; From 5abdc19cfa68aac572b800546f47651e458ee9de Mon Sep 17 00:00:00 2001 From: Derek Christ Date: Thu, 16 Sep 2021 16:05:53 +0200 Subject: [PATCH 8/9] Improve bugprone enabling/disabling of menu items in TraceAnalyzer --- DRAMSys/traceAnalyzer/traceanalyzer.cpp | 41 +++++++++---------------- DRAMSys/traceAnalyzer/traceanalyzer.h | 5 +-- 2 files changed, 18 insertions(+), 28 deletions(-) diff --git a/DRAMSys/traceAnalyzer/traceanalyzer.cpp b/DRAMSys/traceAnalyzer/traceanalyzer.cpp index 0a3454fb..dda259b9 100644 --- a/DRAMSys/traceAnalyzer/traceanalyzer.cpp +++ b/DRAMSys/traceAnalyzer/traceanalyzer.cpp @@ -65,13 +65,6 @@ TraceAnalyzer::TraceAnalyzer(QWidget *parent) : ui(new Ui::TraceAnalyzer) { setUpGui(); - // Disable actions except for "Open" until some file is open. - ui->actionReload_all->setEnabled(false); - ui->actionSaveChangesToDB->setEnabled(false); - ui->actionExportAsVCD->setEnabled(false); - ui->actionClose_all->setEnabled(false); - ui->actionTest->setEnabled(false); - ui->actionMetrics->setEnabled(false); } TraceAnalyzer::TraceAnalyzer(QSet paths, StartupOption option, @@ -120,20 +113,24 @@ void TraceAnalyzer::openTracefile(const QString &path) ui->traceFileTabs->addTab(tab, QFileInfo(path).baseName()); openedTraceFiles.insert(path); - // Enable actions - ui->actionReload_all->setEnabled(true); - ui->actionSaveChangesToDB->setEnabled(true); - - if (PythonCaller::instance().vcdExportDependenciesAvailable()) - ui->actionExportAsVCD->setEnabled(true); - - ui->actionClose_all->setEnabled(true); - ui->actionTest->setEnabled(true); - ui->actionMetrics->setEnabled(true); - statusLabel->clear(); } +void TraceAnalyzer::on_menuFile_aboutToShow() +{ + ui->actionOpen->setEnabled(true); + + bool tabsOpen = ui->traceFileTabs->count() > 0; + bool exportAsVcdAvailable = PythonCaller::instance().vcdExportDependenciesAvailable(); + + ui->actionReload_all->setEnabled(tabsOpen); + ui->actionSaveChangesToDB->setEnabled(tabsOpen); + ui->actionExportAsVCD->setEnabled(tabsOpen && exportAsVcdAvailable); + ui->actionClose_all->setEnabled(tabsOpen); + ui->actionTest->setEnabled(tabsOpen); + ui->actionMetrics->setEnabled(tabsOpen); +} + void TraceAnalyzer::on_traceFileTabs_tabCloseRequested(int index) { TraceFileTab *traceFileTab = static_cast @@ -154,14 +151,6 @@ void TraceAnalyzer::on_actionClose_all_triggered() on_traceFileTabs_tabCloseRequested(i); } - // All files closed. Disable actions except for "Open". - ui->actionReload_all->setEnabled(false); - ui->actionSaveChangesToDB->setEnabled(false); - ui->actionExportAsVCD->setEnabled(false); - ui->actionClose_all->setEnabled(false); - ui->actionTest->setEnabled(false); - ui->actionMetrics->setEnabled(false); - statusLabel->clear(); } diff --git a/DRAMSys/traceAnalyzer/traceanalyzer.h b/DRAMSys/traceAnalyzer/traceanalyzer.h index cfcf9e58..e6916862 100644 --- a/DRAMSys/traceAnalyzer/traceanalyzer.h +++ b/DRAMSys/traceAnalyzer/traceanalyzer.h @@ -76,14 +76,15 @@ private: QSet openedTraceFiles; private Q_SLOTS: + void on_menuFile_aboutToShow(); + void on_traceFileTabs_tabCloseRequested(int index); + void on_actionOpen_triggered(); void on_actionReload_all_triggered(); void on_actionSaveChangesToDB_triggered(); void on_actionExportAsVCD_triggered(); - void on_traceFileTabs_tabCloseRequested(int index); void on_actionClose_all_triggered(); void on_actionTest_triggered(); - void on_actionMetrics_triggered(); public Q_SLOTS: From eae0eb326fdb0c99ed6b5bd9c19fcb45adc769d2 Mon Sep 17 00:00:00 2001 From: Derek Christ Date: Mon, 20 Sep 2021 12:54:12 +0200 Subject: [PATCH 9/9] Fix mistakenly double instantiation of TraceNavigator --- DRAMSys/traceAnalyzer/tracefiletab.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/DRAMSys/traceAnalyzer/tracefiletab.cpp b/DRAMSys/traceAnalyzer/tracefiletab.cpp index db6d3f62..80da307a 100644 --- a/DRAMSys/traceAnalyzer/tracefiletab.cpp +++ b/DRAMSys/traceAnalyzer/tracefiletab.cpp @@ -133,8 +133,6 @@ void TraceFileTab::setUpTraceplotScrollbar() void TraceFileTab::initNavigatorAndItsDependentWidgets(QString path) { - navigator = new TraceNavigator(path, commentModel, this); - ui->traceplot->init(navigator, ui->traceplotScrollbar, commentModel); ui->traceScroller->init(navigator, ui->traceplot);