659 lines
20 KiB
C++
659 lines
20 KiB
C++
/*
|
|
* Copyright (c) 2021, RPTU Kaiserslautern-Landau
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are
|
|
* met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice,
|
|
* this list of conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* 3. Neither the name of the copyright holder nor the names of its
|
|
* contributors may be used to endorse or promote products derived from
|
|
* this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
|
|
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
* Authors:
|
|
* Derek Christ
|
|
*/
|
|
|
|
#include "traceplotlinemodel.h"
|
|
#include "../presentation/traceplot.h"
|
|
#include "../presentation/util/customlabelscaledraw.h"
|
|
|
|
#include <QItemSelectionModel>
|
|
#include <QKeyEvent>
|
|
#include <QMimeData>
|
|
|
|
AbstractTracePlotLineModel::AbstractTracePlotLineModel(const GeneralInfo &generalInfo, QObject *parent)
|
|
: QAbstractItemModel(parent), internalSelectionModel(new QItemSelectionModel(this, this)),
|
|
rootNode(std::make_shared<Node>()), numberOfRanks(generalInfo.numberOfRanks),
|
|
groupsPerRank(generalInfo.groupsPerRank), banksPerGroup(generalInfo.banksPerGroup),
|
|
banksPerRank(generalInfo.banksPerRank), commandBusType(getCommandBusType(generalInfo)),
|
|
dataBusType(getDataBusType(generalInfo))
|
|
{
|
|
createInitialNodes();
|
|
}
|
|
|
|
AvailableTracePlotLineModel::AvailableTracePlotLineModel(const GeneralInfo &generalInfo, QObject *parent)
|
|
: AbstractTracePlotLineModel(generalInfo, parent)
|
|
{
|
|
}
|
|
|
|
SelectedTracePlotLineModel::SelectedTracePlotLineModel(const GeneralInfo &generalInfo, QObject *parent)
|
|
: AbstractTracePlotLineModel(generalInfo, parent)
|
|
{
|
|
}
|
|
|
|
void AbstractTracePlotLineModel::addTopLevelNode(std::shared_ptr<Node> &&node)
|
|
{
|
|
rootNode->children.push_back(std::move(node));
|
|
}
|
|
|
|
void AbstractTracePlotLineModel::createInitialNodes()
|
|
{
|
|
addTopLevelNode(
|
|
std::unique_ptr<Node>(new Node({LineType::RequestLine, getLabel(LineType::RequestLine)}, rootNode.get())));
|
|
addTopLevelNode(
|
|
std::unique_ptr<Node>(new Node({LineType::ResponseLine, getLabel(LineType::ResponseLine)}, rootNode.get())));
|
|
|
|
for (unsigned int rank = 0; rank < numberOfRanks; rank++)
|
|
addTopLevelNode(createRankGroupNode(rank));
|
|
|
|
if (commandBusType == CommandBusType::SingleCommandBus)
|
|
{
|
|
addTopLevelNode(std::unique_ptr<Node>(
|
|
new Node({LineType::CommandBusLine, getLabel(LineType::CommandBusLine)}, rootNode.get())));
|
|
}
|
|
else // commandBusType == CommandBusType::RowColumnCommandBus
|
|
{
|
|
addTopLevelNode(std::unique_ptr<Node>(
|
|
new Node({LineType::RowCommandBusLine, getLabel(LineType::RowCommandBusLine)}, rootNode.get())));
|
|
addTopLevelNode(std::unique_ptr<Node>(
|
|
new Node({LineType::ColumnCommandBusLine, getLabel(LineType::ColumnCommandBusLine)}, rootNode.get())));
|
|
}
|
|
|
|
if (dataBusType == DataBusType::LegacyMode)
|
|
{
|
|
addTopLevelNode(
|
|
std::unique_ptr<Node>(new Node({LineType::DataBusLine, getLabel(LineType::DataBusLine)}, rootNode.get())));
|
|
}
|
|
else // dataBusType == DataBusType::PseudoChannelMode
|
|
{
|
|
addTopLevelNode(std::unique_ptr<Node>(
|
|
new Node({LineType::PseudoChannel0Line, getLabel(LineType::PseudoChannel0Line)}, rootNode.get())));
|
|
addTopLevelNode(std::unique_ptr<Node>(
|
|
new Node({LineType::PseudoChannel1Line, getLabel(LineType::PseudoChannel1Line)}, rootNode.get())));
|
|
}
|
|
}
|
|
|
|
std::shared_ptr<AbstractTracePlotLineModel::Node>
|
|
AbstractTracePlotLineModel::createRankGroupNode(unsigned int rank) const
|
|
{
|
|
auto rankGroup = std::unique_ptr<Node>(new Node({LineType::RankGroup, getLabel(rank), rank}, rootNode.get()));
|
|
|
|
for (unsigned int group = 0; group < groupsPerRank; group++)
|
|
{
|
|
for (unsigned int bank = 0; bank < banksPerGroup; bank++)
|
|
{
|
|
unsigned int absoluteRank = rank;
|
|
unsigned int absoluteGroup = group + rank * groupsPerRank;
|
|
unsigned int absoluteBank = bank + rank * banksPerRank + group * banksPerGroup;
|
|
|
|
auto bankLine = std::unique_ptr<Node>(
|
|
new Node({LineType::BankLine, getLabel(rank, group, bank), absoluteRank, absoluteGroup, absoluteBank},
|
|
rankGroup.get()));
|
|
|
|
rankGroup->children.push_back(std::move(bankLine));
|
|
}
|
|
}
|
|
|
|
return rankGroup;
|
|
}
|
|
|
|
int AbstractTracePlotLineModel::rowCount(const QModelIndex &parent) const
|
|
{
|
|
if (parent.column() > 0)
|
|
return 0;
|
|
|
|
const Node *parentNode;
|
|
|
|
if (!parent.isValid())
|
|
parentNode = rootNode.get();
|
|
else
|
|
parentNode = static_cast<const Node *>(parent.internalPointer());
|
|
|
|
return parentNode->childCount();
|
|
}
|
|
|
|
int AbstractTracePlotLineModel::columnCount(const QModelIndex &parent) const
|
|
{
|
|
Q_UNUSED(parent)
|
|
|
|
return 1;
|
|
}
|
|
|
|
QVariant AbstractTracePlotLineModel::data(const QModelIndex &index, int role) const
|
|
{
|
|
if (!index.isValid())
|
|
return QVariant();
|
|
|
|
auto *node = static_cast<const Node *>(index.internalPointer());
|
|
|
|
switch (role)
|
|
{
|
|
case Qt::DisplayRole:
|
|
return node->data.label;
|
|
|
|
case Role::TypeRole:
|
|
return QVariant::fromValue(node->data.type);
|
|
|
|
case Role::CollapsedRole:
|
|
return node->data.collapsed;
|
|
}
|
|
|
|
return QVariant();
|
|
}
|
|
|
|
bool SelectedTracePlotLineModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
|
{
|
|
if (!index.isValid())
|
|
return false;
|
|
|
|
auto *node = static_cast<Node *>(index.internalPointer());
|
|
|
|
switch (role)
|
|
{
|
|
case Role::CollapsedRole:
|
|
node->data.collapsed = value.toBool();
|
|
emit dataChanged(index, index, {role});
|
|
return true;
|
|
|
|
case Qt::DisplayRole:
|
|
case Role::TypeRole:
|
|
// Not allowed
|
|
return false;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
QVariant AvailableTracePlotLineModel::headerData(int section, Qt::Orientation orientation, int role) const
|
|
{
|
|
if (role != Qt::DisplayRole)
|
|
return QVariant();
|
|
|
|
if (orientation == Qt::Horizontal && section == 0)
|
|
return "Available Items";
|
|
|
|
return QVariant();
|
|
}
|
|
|
|
QVariant SelectedTracePlotLineModel::headerData(int section, Qt::Orientation orientation, int role) const
|
|
{
|
|
if (role != Qt::DisplayRole)
|
|
return QVariant();
|
|
|
|
if (orientation == Qt::Horizontal && section == 0)
|
|
{
|
|
return "Selected Items";
|
|
}
|
|
|
|
return QVariant();
|
|
}
|
|
|
|
QModelIndex AbstractTracePlotLineModel::index(int row, int column, const QModelIndex &parent) const
|
|
{
|
|
if (!hasIndex(row, column, parent))
|
|
return QModelIndex();
|
|
|
|
const Node *parentNode;
|
|
|
|
if (!parent.isValid())
|
|
parentNode = rootNode.get();
|
|
else
|
|
parentNode = static_cast<const Node *>(parent.internalPointer());
|
|
|
|
const Node *node = parentNode->children[row].get();
|
|
|
|
return createIndex(row, column, const_cast<Node *>(node));
|
|
}
|
|
|
|
QModelIndex AbstractTracePlotLineModel::parent(const QModelIndex &index) const
|
|
{
|
|
if (!index.isValid())
|
|
return QModelIndex();
|
|
|
|
const Node *childNode = static_cast<const Node *>(index.internalPointer());
|
|
const Node *parentNode = childNode->parent;
|
|
|
|
if (!parentNode || parentNode == rootNode.get())
|
|
return QModelIndex();
|
|
|
|
return createIndex(parentNode->getRow(), 0, const_cast<Node *>(parentNode));
|
|
}
|
|
|
|
void SelectedTracePlotLineModel::recreateCollapseButtons(TracePlot *tracePlot,
|
|
CustomLabelScaleDraw *customLabelScaleDraw)
|
|
{
|
|
// Remove old buttons
|
|
for (auto button : collapseButtons)
|
|
{
|
|
button->hide();
|
|
button->deleteLater();
|
|
}
|
|
|
|
collapseButtons.clear();
|
|
|
|
for (const auto &node : rootNode->children)
|
|
{
|
|
if (node->data.type != LineType::RankGroup)
|
|
continue;
|
|
|
|
QPushButton *collapseButton = new QPushButton(tracePlot);
|
|
|
|
unsigned int yVal = [node]()
|
|
{
|
|
if (node->data.collapsed)
|
|
return node->data.yVal;
|
|
else
|
|
return node->children.at(0)->data.yVal;
|
|
}();
|
|
bool isCollapsed = node->data.collapsed;
|
|
QModelIndex nodeIndex = index(node->getRow(), 0);
|
|
|
|
auto repositionButton = [=]()
|
|
{
|
|
QPointF point = tracePlot->axisScaleDraw(QwtPlot::yLeft)->labelPosition(yVal);
|
|
collapseButton->setGeometry(point.x(), point.y() - 4, 25, 25);
|
|
};
|
|
repositionButton();
|
|
|
|
auto updateLabel = [=]() { collapseButton->setText(isCollapsed ? "+" : "-"); };
|
|
updateLabel();
|
|
|
|
auto toggleCollapsed = [=]()
|
|
{
|
|
setData(nodeIndex, !isCollapsed, Role::CollapsedRole);
|
|
|
|
recreateCollapseButtons(tracePlot, customLabelScaleDraw);
|
|
};
|
|
|
|
// Important: The context of the connection is `collapseButton` as it should be disconnected when the button
|
|
// ceases to exist.
|
|
connect(customLabelScaleDraw, &CustomLabelScaleDraw::scaleRedraw, collapseButton, repositionButton);
|
|
connect(collapseButton, &QPushButton::pressed, this, toggleCollapsed);
|
|
connect(collapseButton, &QPushButton::pressed, tracePlot, &TracePlot::recreateCollapseButtons);
|
|
|
|
collapseButton->show();
|
|
collapseButtons.push_back(collapseButton);
|
|
}
|
|
}
|
|
|
|
int AbstractTracePlotLineModel::Node::getRow() const
|
|
{
|
|
if (!parent)
|
|
return 0;
|
|
|
|
const auto &siblings = parent->children;
|
|
const auto siblingsIt = std::find_if(siblings.begin(), siblings.end(),
|
|
[this](const std::shared_ptr<Node> &node) { return node.get() == this; });
|
|
|
|
Q_ASSERT(siblingsIt != siblings.end());
|
|
|
|
return std::distance(siblings.begin(), siblingsIt);
|
|
}
|
|
|
|
std::shared_ptr<AbstractTracePlotLineModel::Node> AbstractTracePlotLineModel::Node::cloneNode(const Node *node,
|
|
const Node *parent)
|
|
{
|
|
std::shared_ptr<Node> clonedNode = std::make_shared<Node>(node->data, parent);
|
|
|
|
for (const auto &child : node->children)
|
|
clonedNode->children.push_back(cloneNode(child.get(), clonedNode.get()));
|
|
|
|
return clonedNode;
|
|
}
|
|
|
|
QString AbstractTracePlotLineModel::getLabel(LineType type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case LineType::RequestLine:
|
|
return "REQ";
|
|
case LineType::ResponseLine:
|
|
return "RESP";
|
|
case LineType::CommandBusLine:
|
|
return "Command Bus";
|
|
case LineType::RowCommandBusLine:
|
|
return "Command Bus [R]";
|
|
case LineType::ColumnCommandBusLine:
|
|
return "Command Bus [C]";
|
|
case LineType::DataBusLine:
|
|
return "Data Bus";
|
|
case LineType::PseudoChannel0Line:
|
|
return "Data Bus [PC0]";
|
|
case LineType::PseudoChannel1Line:
|
|
return "Data Bus [PC1]";
|
|
default:
|
|
return "";
|
|
}
|
|
}
|
|
|
|
QString AbstractTracePlotLineModel::getLabel(unsigned int rank) const
|
|
{
|
|
std::string_view rankLabel = dataBusType == DataBusType::LegacyMode ? "RA" : "PC";
|
|
return rankLabel.data() + QString::number(rank);
|
|
}
|
|
|
|
QString AbstractTracePlotLineModel::getLabel(unsigned int rank, unsigned int group, unsigned int bank) const
|
|
{
|
|
std::string_view rankLabel = dataBusType == DataBusType::LegacyMode ? "RA" : "PC";
|
|
return rankLabel.data() + QString::number(rank) + " BG" + QString::number(group) + " BA" + QString::number(bank);
|
|
}
|
|
|
|
AbstractTracePlotLineModel::CommandBusType AbstractTracePlotLineModel::getCommandBusType(const GeneralInfo &generalInfo)
|
|
{
|
|
if (generalInfo.rowColumnCommandBus)
|
|
return CommandBusType::RowColumnCommandBus;
|
|
else
|
|
return CommandBusType::SingleCommandBus;
|
|
}
|
|
|
|
AbstractTracePlotLineModel::DataBusType AbstractTracePlotLineModel::getDataBusType(const GeneralInfo &generalInfo)
|
|
{
|
|
if (generalInfo.pseudoChannelMode)
|
|
return DataBusType::PseudoChannelMode;
|
|
else
|
|
return DataBusType::LegacyMode;
|
|
}
|
|
|
|
bool SelectedTracePlotLineModel::removeRows(int row, int count, const QModelIndex &parent)
|
|
{
|
|
if (parent != QModelIndex())
|
|
return false;
|
|
|
|
// Note: beginRemoveRows requires [first, last], but erase requires [first, last)
|
|
beginRemoveRows(QModelIndex(), row, row + count - 1);
|
|
rootNode->children.erase(rootNode->children.begin() + row, rootNode->children.begin() + row + count);
|
|
endRemoveRows();
|
|
|
|
return true;
|
|
}
|
|
|
|
void AvailableTracePlotLineModel::itemsDoubleClicked(const QModelIndex &index)
|
|
{
|
|
QModelIndexList indexList({index});
|
|
|
|
emit returnPressed(indexList);
|
|
}
|
|
|
|
void SelectedTracePlotLineModel::itemsDoubleClicked(const QModelIndex &index)
|
|
{
|
|
if (index.parent() != QModelIndex())
|
|
return;
|
|
|
|
removeRow(index.row(), QModelIndex());
|
|
}
|
|
|
|
bool AvailableTracePlotLineModel::eventFilter(QObject *object, QEvent *event)
|
|
{
|
|
Q_UNUSED(object)
|
|
|
|
if (event->type() == QEvent::KeyPress)
|
|
{
|
|
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
|
|
|
|
if (keyEvent->key() == Qt::Key_Return)
|
|
{
|
|
const QModelIndexList indexes = internalSelectionModel->selectedRows();
|
|
|
|
emit returnPressed(indexes);
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool SelectedTracePlotLineModel::eventFilter(QObject *object, QEvent *event)
|
|
{
|
|
Q_UNUSED(object)
|
|
|
|
if (event->type() == QEvent::KeyPress)
|
|
{
|
|
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
|
|
|
|
if (keyEvent->key() == Qt::Key_Delete)
|
|
{
|
|
// Note: This implementation requires the selection to be contiguous
|
|
|
|
const QModelIndexList indexes = internalSelectionModel->selectedRows();
|
|
|
|
if (indexes.count() == 0)
|
|
return true;
|
|
|
|
for (const auto &index : indexes)
|
|
{
|
|
// Only remove toplevel indexes
|
|
if (index.parent() != QModelIndex())
|
|
return true;
|
|
}
|
|
|
|
removeRows(indexes.at(0).row(), indexes.size(), QModelIndex());
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void SelectedTracePlotLineModel::addIndexesFromAvailableModel(const QModelIndexList &indexes)
|
|
{
|
|
for (const auto &index : indexes)
|
|
{
|
|
auto node = static_cast<const Node *>(index.internalPointer());
|
|
auto clonedNode = Node::cloneNode(node, rootNode.get());
|
|
|
|
beginInsertRows(QModelIndex(), rootNode->children.size(), rootNode->children.size());
|
|
addTopLevelNode(std::move(clonedNode));
|
|
endInsertRows();
|
|
}
|
|
}
|
|
|
|
QItemSelectionModel *AbstractTracePlotLineModel::selectionModel() const
|
|
{
|
|
return internalSelectionModel;
|
|
}
|
|
|
|
QStringList AbstractTracePlotLineModel::mimeTypes() const
|
|
{
|
|
QStringList types = QAbstractItemModel::mimeTypes();
|
|
types << TRACELINE_MIMETYPE;
|
|
|
|
return types;
|
|
}
|
|
|
|
QMimeData *AbstractTracePlotLineModel::mimeData(const QModelIndexList &indexes) const
|
|
{
|
|
QByteArray traceLineData;
|
|
QDataStream dataStream(&traceLineData, QIODevice::WriteOnly);
|
|
|
|
for (const auto &index : indexes)
|
|
{
|
|
const Node *node = static_cast<const Node *>(index.internalPointer());
|
|
|
|
dataStream << node->data.type << node->data.label << node->data.rank << node->data.group << node->data.bank
|
|
<< node->data.collapsed;
|
|
}
|
|
|
|
QMimeData *mimeData = new QMimeData;
|
|
mimeData->setData(TRACELINE_MIMETYPE, traceLineData);
|
|
|
|
return mimeData;
|
|
}
|
|
|
|
bool AbstractTracePlotLineModel::canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column,
|
|
const QModelIndex &parent) const
|
|
{
|
|
Q_UNUSED(action);
|
|
Q_UNUSED(row);
|
|
Q_UNUSED(parent);
|
|
|
|
if (!data->hasFormat(TRACELINE_MIMETYPE))
|
|
return false;
|
|
|
|
if (column > 0)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool AbstractTracePlotLineModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column,
|
|
const QModelIndex &parent)
|
|
{
|
|
if (!canDropMimeData(data, action, row, column, parent))
|
|
return false;
|
|
|
|
if (action == Qt::IgnoreAction)
|
|
return true;
|
|
|
|
bool dropHandled = false;
|
|
|
|
int beginRow;
|
|
|
|
if (row != -1)
|
|
beginRow = row;
|
|
else
|
|
beginRow = rowCount(QModelIndex());
|
|
|
|
if (action == Qt::CopyAction || action == Qt::MoveAction)
|
|
{
|
|
dropHandled = true;
|
|
|
|
QByteArray traceLineData = data->data(TRACELINE_MIMETYPE);
|
|
QDataStream dataStream(&traceLineData, QIODevice::ReadOnly);
|
|
|
|
std::vector<std::shared_ptr<Node>> droppedNodes;
|
|
|
|
while (!dataStream.atEnd())
|
|
{
|
|
LineType type;
|
|
QString label;
|
|
unsigned int rank, group, bank;
|
|
bool isCollapsed;
|
|
|
|
dataStream >> type >> label >> rank >> group >> bank >> isCollapsed;
|
|
|
|
std::shared_ptr<Node> node;
|
|
|
|
if (type == LineType::BankLine)
|
|
node = std::make_shared<Node>(Node::NodeData{type, label, rank, group, bank}, rootNode.get());
|
|
else if (type == LineType::RankGroup)
|
|
node = createRankGroupNode(rank);
|
|
else
|
|
node = std::make_shared<Node>(Node::NodeData{type, label}, rootNode.get());
|
|
|
|
if (node->data.type == RankGroup)
|
|
node->data.collapsed = isCollapsed;
|
|
|
|
droppedNodes.push_back(std::move(node));
|
|
}
|
|
|
|
// Note: beginRemoveRows requires [first, last]
|
|
beginInsertRows(QModelIndex(), beginRow, beginRow + droppedNodes.size() - 1);
|
|
rootNode->children.insert(rootNode->children.begin() + beginRow, std::make_move_iterator(droppedNodes.begin()),
|
|
std::make_move_iterator(droppedNodes.end()));
|
|
endInsertRows();
|
|
}
|
|
else
|
|
{
|
|
dropHandled = QAbstractItemModel::dropMimeData(data, action, row, column, parent);
|
|
}
|
|
|
|
return dropHandled;
|
|
}
|
|
|
|
Qt::DropActions AbstractTracePlotLineModel::supportedDropActions() const
|
|
{
|
|
return (Qt::MoveAction | Qt::CopyAction);
|
|
}
|
|
|
|
Qt::ItemFlags AbstractTracePlotLineModel::flags(const QModelIndex &index) const
|
|
{
|
|
Qt::ItemFlags defaultFlags = QAbstractItemModel::flags(index);
|
|
|
|
if (index.isValid())
|
|
return Qt::ItemIsDragEnabled | defaultFlags;
|
|
else
|
|
return Qt::ItemIsDropEnabled | defaultFlags;
|
|
}
|
|
|
|
std::shared_ptr<AbstractTracePlotLineModel::Node> SelectedTracePlotLineModel::getClonedRootNode()
|
|
{
|
|
return Node::cloneNode(rootNode.get(), nullptr);
|
|
}
|
|
|
|
void SelectedTracePlotLineModel::setRootNode(std::shared_ptr<AbstractTracePlotLineModel::Node> node)
|
|
{
|
|
removeRows(0, rootNode->childCount(), QModelIndex());
|
|
|
|
beginInsertRows(QModelIndex(), 0, node->childCount() - 1);
|
|
rootNode = std::move(node);
|
|
endInsertRows();
|
|
}
|
|
|
|
TracePlotLineDataSource::TracePlotLineDataSource(SelectedTracePlotLineModel *selectedModel, QObject *parent)
|
|
: selectedModel(selectedModel)
|
|
{
|
|
Q_UNUSED(parent)
|
|
|
|
updateModel();
|
|
}
|
|
|
|
void TracePlotLineDataSource::updateModel()
|
|
{
|
|
entries.clear();
|
|
|
|
std::function<void(std::shared_ptr<AbstractTracePlotLineModel::Node> & parent)> addNodes;
|
|
addNodes = [=, &addNodes](std::shared_ptr<AbstractTracePlotLineModel::Node> &parent)
|
|
{
|
|
for (auto &childNode : parent->children)
|
|
{
|
|
if (childNode->data.type == AbstractTracePlotLineModel::RankGroup && !childNode->data.collapsed)
|
|
{
|
|
addNodes(childNode);
|
|
continue; // Don't add the parent node itself when not collapsed.
|
|
}
|
|
entries.push_back(childNode);
|
|
}
|
|
};
|
|
|
|
addNodes(selectedModel->rootNode);
|
|
|
|
emit modelChanged();
|
|
}
|