From 7b09a7402e45e2c1a2538b2f3565607ac75eccdd Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Sat, 28 Jul 2018 15:44:00 +0200 Subject: Move all to tree model --- gui/treemodel.cc | 297 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 297 insertions(+) create mode 100644 gui/treemodel.cc (limited to 'gui/treemodel.cc') diff --git a/gui/treemodel.cc b/gui/treemodel.cc new file mode 100644 index 00000000..65a17a2f --- /dev/null +++ b/gui/treemodel.cc @@ -0,0 +1,297 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Miodrag Milanovic + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "treemodel.h" + +NEXTPNR_NAMESPACE_BEGIN + +ContextTreeItem::ContextTreeItem() { parentNode = nullptr; } + +ContextTreeItem::ContextTreeItem(QString name) + : parentNode(nullptr), itemId(IdString()), itemType(ElementType::NONE), itemName(name) +{ +} + +ContextTreeItem::ContextTreeItem(IdString id, ElementType type, QString name) + : parentNode(nullptr), itemId(id), itemType(type), itemName(name) +{ +} + +ContextTreeItem::~ContextTreeItem() +{ + if (parentNode) + parentNode->children.removeOne(this); + qDeleteAll(children); +} +void ContextTreeItem::addChild(ContextTreeItem *item) +{ + item->parentNode = this; + children.append(item); +} + +ContextTreeModel::ContextTreeModel(QObject *parent) : QAbstractItemModel(parent) { root = new ContextTreeItem(); } + +ContextTreeModel::~ContextTreeModel() { delete root; } + +void ContextTreeModel::loadData(Context *ctx) +{ + if (!ctx) + return; + delete root; + root = new ContextTreeItem(); + + for (int i = 0; i < 6; i++) + nameToItem[i].clear(); + + IdString none; + + ContextTreeItem *bels_root = new ContextTreeItem("Bels"); + root->addChild(bels_root); + QMap bel_items; + + // Add bels to tree + for (auto bel : ctx->getBels()) { + IdString id = ctx->getBelName(bel); + QStringList items = QString(id.c_str(ctx)).split("/"); + QString name; + ContextTreeItem *parent = bels_root; + for (int i = 0; i < items.size(); i++) { + if (!name.isEmpty()) + name += "/"; + name += items.at(i); + if (!bel_items.contains(name)) { + if (i == items.size() - 1) { + ContextTreeItem *item = new ContextTreeItem(id, ElementType::BEL, items.at(i)); + parent->addChild(item); + nameToItem[0].insert(name, item); + } else { + ContextTreeItem *item = new ContextTreeItem(none, ElementType::NONE, items.at(i)); + parent->addChild(item); + bel_items.insert(name, item); + } + } + parent = bel_items[name]; + } + } + + ContextTreeItem *wire_root = new ContextTreeItem("Wires"); + root->addChild(wire_root); + QMap wire_items; + + // Add wires to tree + for (auto wire : ctx->getWires()) { + auto id = ctx->getWireName(wire); + QStringList items = QString(id.c_str(ctx)).split("/"); + QString name; + ContextTreeItem *parent = wire_root; + for (int i = 0; i < items.size(); i++) { + if (!name.isEmpty()) + name += "/"; + name += items.at(i); + if (!wire_items.contains(name)) { + if (i == items.size() - 1) { + ContextTreeItem *item = new ContextTreeItem(id, ElementType::WIRE, items.at(i)); + parent->addChild(item); + nameToItem[1].insert(name, item); + } else { + ContextTreeItem *item = new ContextTreeItem(none, ElementType::NONE, items.at(i)); + parent->addChild(item); + wire_items.insert(name, item); + } + } + parent = wire_items[name]; + } + } + + ContextTreeItem *pip_root = new ContextTreeItem("Pips"); + root->addChild(pip_root); + QMap pip_items; + + // Add pips to tree + for (auto pip : ctx->getPips()) { + auto id = ctx->getPipName(pip); + QStringList items = QString(id.c_str(ctx)).split("/"); + QString name; + ContextTreeItem *parent = pip_root; + for (int i = 0; i < items.size(); i++) { + if (!name.isEmpty()) + name += "/"; + name += items.at(i); + if (!pip_items.contains(name)) { + if (i == items.size() - 1) { + ContextTreeItem *item = new ContextTreeItem(id, ElementType::PIP, items.at(i)); + parent->addChild(item); + nameToItem[2].insert(name, item); + } else { + ContextTreeItem *item = new ContextTreeItem(none, ElementType::NONE, items.at(i)); + parent->addChild(item); + pip_items.insert(name, item); + } + } + parent = pip_items[name]; + } + } + + nets_root = new ContextTreeItem("Nets"); + root->addChild(nets_root); + + cells_root = new ContextTreeItem("Cells"); + root->addChild(cells_root); +} + +void ContextTreeModel::updateData(Context *ctx) +{ + if (!ctx) + return; + + // Remove nets not existing any more + QMap::iterator i = nameToItem[3].begin(); + while (i != nameToItem[3].end()) { + QMap::iterator prev = i; + ++i; + if (ctx->nets.find(ctx->id(prev.key().toStdString())) == ctx->nets.end()) { + /* if (treeWidget->currentItem() == prev.value()) + treeWidget->setCurrentItem(nets_root); + if (highlightSelected.contains(prev.value())) + highlightSelected.remove(prev.value());*/ + delete prev.value(); + nameToItem[3].erase(prev); + } + } + // Add nets to tree + for (auto &item : ctx->nets) { + auto id = item.first; + QString name = QString(id.c_str(ctx)); + if (!nameToItem[3].contains(name)) { + ContextTreeItem *newItem = new ContextTreeItem(id, ElementType::NET, name); + nets_root->addChild(newItem); + nameToItem[3].insert(name, newItem); + } + } + + // Remove cells not existing any more + i = nameToItem[4].begin(); + while (i != nameToItem[4].end()) { + QMap::iterator prev = i; + ++i; + if (ctx->cells.find(ctx->id(prev.key().toStdString())) == ctx->cells.end()) { + /* if (treeWidget->currentItem() == prev.value()) + treeWidget->setCurrentItem(cells_root); + if (highlightSelected.contains(prev.value())) + highlightSelected.remove(prev.value());*/ + delete prev.value(); + nameToItem[4].erase(prev); + } + } + // Add cells to tree + for (auto &item : ctx->cells) { + auto id = item.first; + QString name = QString(id.c_str(ctx)); + if (!nameToItem[4].contains(name)) { + ContextTreeItem *newItem = new ContextTreeItem(id, ElementType::CELL, name); + cells_root->addChild(newItem); + nameToItem[4].insert(name, newItem); + } + } +} + +int ContextTreeModel::rowCount(const QModelIndex &parent) const { return nodeFromIndex(parent)->count(); } + +int ContextTreeModel::columnCount(const QModelIndex &parent) const { return 1; } + +QModelIndex ContextTreeModel::index(int row, int column, const QModelIndex &parent) const +{ + ContextTreeItem *node = nodeFromIndex(parent); + if (row >= node->count()) + return QModelIndex(); + return createIndex(row, column, node->at(row)); +} + +QModelIndex ContextTreeModel::parent(const QModelIndex &child) const +{ + ContextTreeItem *parent = nodeFromIndex(child)->parent(); + if (parent == root) + return QModelIndex(); + ContextTreeItem *node = parent->parent(); + return createIndex(node->indexOf(parent), 0, parent); +} + +QVariant ContextTreeModel::data(const QModelIndex &index, int role) const +{ + if (index.column() != 0) + return QVariant(); + if (role != Qt::DisplayRole) + return QVariant(); + ContextTreeItem *node = nodeFromIndex(index); + return node->name(); +} + +QVariant ContextTreeModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + Q_UNUSED(section); + if (orientation == Qt::Horizontal && role == Qt::DisplayRole) + return QString("Items"); + + return QVariant(); +} + +ContextTreeItem *ContextTreeModel::nodeFromIndex(const QModelIndex &idx) const +{ + if (idx.isValid()) + return (ContextTreeItem *)idx.internalPointer(); + return root; +} + +static int getElementIndex(ElementType type) +{ + if (type == ElementType::BEL) + return 0; + if (type == ElementType::WIRE) + return 1; + if (type == ElementType::PIP) + return 2; + if (type == ElementType::NET) + return 3; + if (type == ElementType::CELL) + return 4; + return -1; +} + +ContextTreeItem *ContextTreeModel::nodeForIdType(const ElementType type, const QString name) const +{ + int index = getElementIndex(type); + if (type != ElementType::NONE && nameToItem[index].contains(name)) + return nameToItem[index].value(name); + return nullptr; +} + +QModelIndex ContextTreeModel::indexFromNode(ContextTreeItem *node) +{ + ContextTreeItem *parent = node->parent(); + if (parent == root) + return QModelIndex(); + return createIndex(parent->indexOf(node), 0, node); +} + +Qt::ItemFlags ContextTreeModel::flags(const QModelIndex &index) const +{ + ContextTreeItem *node = nodeFromIndex(index); + return Qt::ItemIsEnabled | (node->type() != ElementType::NONE ? Qt::ItemIsSelectable : Qt::NoItemFlags); +} +NEXTPNR_NAMESPACE_END \ No newline at end of file -- cgit v1.2.3 From 0d3d149c4f3bb3197bc2f4488ba8f856f0f35889 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Sat, 28 Jul 2018 16:56:16 +0200 Subject: Clean highlight selection if removed from tree --- gui/treemodel.cc | 8 -------- 1 file changed, 8 deletions(-) (limited to 'gui/treemodel.cc') diff --git a/gui/treemodel.cc b/gui/treemodel.cc index 65a17a2f..5a064f57 100644 --- a/gui/treemodel.cc +++ b/gui/treemodel.cc @@ -166,10 +166,6 @@ void ContextTreeModel::updateData(Context *ctx) QMap::iterator prev = i; ++i; if (ctx->nets.find(ctx->id(prev.key().toStdString())) == ctx->nets.end()) { - /* if (treeWidget->currentItem() == prev.value()) - treeWidget->setCurrentItem(nets_root); - if (highlightSelected.contains(prev.value())) - highlightSelected.remove(prev.value());*/ delete prev.value(); nameToItem[3].erase(prev); } @@ -191,10 +187,6 @@ void ContextTreeModel::updateData(Context *ctx) QMap::iterator prev = i; ++i; if (ctx->cells.find(ctx->id(prev.key().toStdString())) == ctx->cells.end()) { - /* if (treeWidget->currentItem() == prev.value()) - treeWidget->setCurrentItem(cells_root); - if (highlightSelected.contains(prev.value())) - highlightSelected.remove(prev.value());*/ delete prev.value(); nameToItem[4].erase(prev); } -- cgit v1.2.3 From ba2531edc04a9e57b69fe6a289444db2f69c44d2 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Sat, 28 Jul 2018 18:48:32 +0200 Subject: add proper info on model changes --- gui/treemodel.cc | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'gui/treemodel.cc') diff --git a/gui/treemodel.cc b/gui/treemodel.cc index 5a064f57..86b272bb 100644 --- a/gui/treemodel.cc +++ b/gui/treemodel.cc @@ -53,6 +53,9 @@ void ContextTreeModel::loadData(Context *ctx) { if (!ctx) return; + + beginResetModel(); + delete root; root = new ContextTreeItem(); @@ -153,6 +156,8 @@ void ContextTreeModel::loadData(Context *ctx) cells_root = new ContextTreeItem("Cells"); root->addChild(cells_root); + + endResetModel(); } void ContextTreeModel::updateData(Context *ctx) @@ -160,14 +165,18 @@ void ContextTreeModel::updateData(Context *ctx) if (!ctx) return; + QModelIndex nets_index = indexFromNode(nets_root); // Remove nets not existing any more QMap::iterator i = nameToItem[3].begin(); while (i != nameToItem[3].end()) { QMap::iterator prev = i; ++i; if (ctx->nets.find(ctx->id(prev.key().toStdString())) == ctx->nets.end()) { + int pos = prev.value()->parent()->indexOf(prev.value()); + beginRemoveRows(nets_index, pos, pos); delete prev.value(); nameToItem[3].erase(prev); + endRemoveRows(); } } // Add nets to tree @@ -175,20 +184,26 @@ void ContextTreeModel::updateData(Context *ctx) auto id = item.first; QString name = QString(id.c_str(ctx)); if (!nameToItem[3].contains(name)) { + beginInsertRows(nets_index, nets_root->count() + 1, nets_root->count() + 1); ContextTreeItem *newItem = new ContextTreeItem(id, ElementType::NET, name); nets_root->addChild(newItem); nameToItem[3].insert(name, newItem); + endInsertRows(); } } + QModelIndex cell_index = indexFromNode(cells_root); // Remove cells not existing any more i = nameToItem[4].begin(); while (i != nameToItem[4].end()) { QMap::iterator prev = i; ++i; if (ctx->cells.find(ctx->id(prev.key().toStdString())) == ctx->cells.end()) { + int pos = prev.value()->parent()->indexOf(prev.value()); + beginRemoveRows(cell_index, pos, pos); delete prev.value(); nameToItem[4].erase(prev); + endRemoveRows(); } } // Add cells to tree @@ -196,9 +211,11 @@ void ContextTreeModel::updateData(Context *ctx) auto id = item.first; QString name = QString(id.c_str(ctx)); if (!nameToItem[4].contains(name)) { + beginInsertRows(cell_index, cells_root->count() + 1, cells_root->count() + 1); ContextTreeItem *newItem = new ContextTreeItem(id, ElementType::CELL, name); cells_root->addChild(newItem); nameToItem[4].insert(name, newItem); + endInsertRows(); } } } -- cgit v1.2.3 From 7c8865d2fc9c2d6b19185627d650448df858fe75 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Sun, 29 Jul 2018 10:56:36 +0200 Subject: Added sorting --- gui/treemodel.cc | 51 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 14 deletions(-) (limited to 'gui/treemodel.cc') diff --git a/gui/treemodel.cc b/gui/treemodel.cc index 86b272bb..59391f02 100644 --- a/gui/treemodel.cc +++ b/gui/treemodel.cc @@ -21,6 +21,11 @@ NEXTPNR_NAMESPACE_BEGIN +static bool contextTreeItemLessThan(const ContextTreeItem *v1, const ContextTreeItem *v2) + { + return v1->name() < v2->name(); + } + ContextTreeItem::ContextTreeItem() { parentNode = nullptr; } ContextTreeItem::ContextTreeItem(QString name) @@ -45,6 +50,13 @@ void ContextTreeItem::addChild(ContextTreeItem *item) children.append(item); } +void ContextTreeItem::sort() +{ + for (auto item : children) + if (item->count()>1) item->sort(); + qSort(children.begin(), children.end(), contextTreeItemLessThan); +} + ContextTreeModel::ContextTreeModel(QObject *parent) : QAbstractItemModel(parent) { root = new ContextTreeItem(); } ContextTreeModel::~ContextTreeModel() { delete root; } @@ -91,8 +103,9 @@ void ContextTreeModel::loadData(Context *ctx) } parent = bel_items[name]; } - } - + } + bels_root->sort(); + ContextTreeItem *wire_root = new ContextTreeItem("Wires"); root->addChild(wire_root); QMap wire_items; @@ -121,6 +134,7 @@ void ContextTreeModel::loadData(Context *ctx) parent = wire_items[name]; } } + wire_root->sort(); ContextTreeItem *pip_root = new ContextTreeItem("Pips"); root->addChild(pip_root); @@ -150,6 +164,7 @@ void ContextTreeModel::loadData(Context *ctx) parent = pip_items[name]; } } + pip_root->sort(); nets_root = new ContextTreeItem("Nets"); root->addChild(nets_root); @@ -165,18 +180,20 @@ void ContextTreeModel::updateData(Context *ctx) if (!ctx) return; - QModelIndex nets_index = indexFromNode(nets_root); + beginResetModel(); + + //QModelIndex nets_index = indexFromNode(nets_root); // Remove nets not existing any more QMap::iterator i = nameToItem[3].begin(); while (i != nameToItem[3].end()) { QMap::iterator prev = i; ++i; if (ctx->nets.find(ctx->id(prev.key().toStdString())) == ctx->nets.end()) { - int pos = prev.value()->parent()->indexOf(prev.value()); - beginRemoveRows(nets_index, pos, pos); + //int pos = prev.value()->parent()->indexOf(prev.value()); + //beginRemoveRows(nets_index, pos, pos); delete prev.value(); nameToItem[3].erase(prev); - endRemoveRows(); + //endRemoveRows(); } } // Add nets to tree @@ -184,26 +201,28 @@ void ContextTreeModel::updateData(Context *ctx) auto id = item.first; QString name = QString(id.c_str(ctx)); if (!nameToItem[3].contains(name)) { - beginInsertRows(nets_index, nets_root->count() + 1, nets_root->count() + 1); + //beginInsertRows(nets_index, nets_root->count() + 1, nets_root->count() + 1); ContextTreeItem *newItem = new ContextTreeItem(id, ElementType::NET, name); nets_root->addChild(newItem); nameToItem[3].insert(name, newItem); - endInsertRows(); + //endInsertRows(); } } - QModelIndex cell_index = indexFromNode(cells_root); + nets_root->sort(); + + //QModelIndex cell_index = indexFromNode(cells_root); // Remove cells not existing any more i = nameToItem[4].begin(); while (i != nameToItem[4].end()) { QMap::iterator prev = i; ++i; if (ctx->cells.find(ctx->id(prev.key().toStdString())) == ctx->cells.end()) { - int pos = prev.value()->parent()->indexOf(prev.value()); - beginRemoveRows(cell_index, pos, pos); + //int pos = prev.value()->parent()->indexOf(prev.value()); + //beginRemoveRows(cell_index, pos, pos); delete prev.value(); nameToItem[4].erase(prev); - endRemoveRows(); + //endRemoveRows(); } } // Add cells to tree @@ -211,13 +230,17 @@ void ContextTreeModel::updateData(Context *ctx) auto id = item.first; QString name = QString(id.c_str(ctx)); if (!nameToItem[4].contains(name)) { - beginInsertRows(cell_index, cells_root->count() + 1, cells_root->count() + 1); + //beginInsertRows(cell_index, cells_root->count() + 1, cells_root->count() + 1); ContextTreeItem *newItem = new ContextTreeItem(id, ElementType::CELL, name); cells_root->addChild(newItem); nameToItem[4].insert(name, newItem); - endInsertRows(); + //endInsertRows(); } } + + cells_root->sort(); + + endResetModel(); } int ContextTreeModel::rowCount(const QModelIndex &parent) const { return nodeFromIndex(parent)->count(); } -- cgit v1.2.3