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/designwidget.cc | 344 ++++++++++------------------------------------------ gui/designwidget.h | 33 ++--- gui/treemodel.cc | 297 +++++++++++++++++++++++++++++++++++++++++++++ gui/treemodel.h | 92 ++++++++++++++ 4 files changed, 463 insertions(+), 303 deletions(-) create mode 100644 gui/treemodel.cc create mode 100644 gui/treemodel.h diff --git a/gui/designwidget.cc b/gui/designwidget.cc index d55c84e9..b321aef1 100644 --- a/gui/designwidget.cc +++ b/gui/designwidget.cc @@ -30,48 +30,14 @@ NEXTPNR_NAMESPACE_BEGIN -class ElementTreeItem : public QTreeWidgetItem +DesignWidget::DesignWidget(QWidget *parent) : QWidget(parent), ctx(nullptr) { - public: - ElementTreeItem(ElementType t, QString str, QTreeWidgetItem *parent) - : QTreeWidgetItem(parent, QStringList(str)), type(t) - { - this->setFlags(this->flags() & ~Qt::ItemIsSelectable); - } - virtual ~ElementTreeItem(){}; - - ElementType getType() { return type; }; - - private: - ElementType type; -}; - -class IdStringTreeItem : public ElementTreeItem -{ - public: - IdStringTreeItem(IdString d, ElementType t, QString str, QTreeWidgetItem *parent) : ElementTreeItem(t, str, parent) - { - this->setFlags(this->flags() | Qt::ItemIsSelectable); - this->data = d; - } - virtual ~IdStringTreeItem(){}; - - IdString getData() { return this->data; }; - - private: - IdString data; -}; - -DesignWidget::DesignWidget(QWidget *parent) : QWidget(parent), ctx(nullptr), nets_root(nullptr), cells_root(nullptr) -{ - - treeWidget = new QTreeWidget(); - // Add tree view - treeWidget->setColumnCount(1); - treeWidget->setHeaderLabel("Items"); - treeWidget->setContextMenuPolicy(Qt::CustomContextMenu); - treeWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); + treeView = new QTreeView(); + treeModel = new ContextTreeModel(); + treeView->setModel(treeModel); + treeView->setContextMenuPolicy(Qt::CustomContextMenu); + treeView->setSelectionMode(QAbstractItemView::ExtendedSelection); // Add property view variantManager = new QtVariantPropertyManager(this); @@ -96,7 +62,7 @@ DesignWidget::DesignWidget(QWidget *parent) : QWidget(parent), ctx(nullptr), net connect(actionFirst, &QAction::triggered, this, [this] { history_ignore = true; history_index = 0; - treeWidget->setCurrentItem(history.at(history_index)); + selectionModel->setCurrentIndex(history.at(history_index), QItemSelectionModel::ClearAndSelect); updateButtons(); }); @@ -106,7 +72,7 @@ DesignWidget::DesignWidget(QWidget *parent) : QWidget(parent), ctx(nullptr), net connect(actionPrev, &QAction::triggered, this, [this] { history_ignore = true; history_index--; - treeWidget->setCurrentItem(history.at(history_index)); + selectionModel->setCurrentIndex(history.at(history_index), QItemSelectionModel::ClearAndSelect); updateButtons(); }); @@ -116,7 +82,7 @@ DesignWidget::DesignWidget(QWidget *parent) : QWidget(parent), ctx(nullptr), net connect(actionNext, &QAction::triggered, this, [this] { history_ignore = true; history_index++; - treeWidget->setCurrentItem(history.at(history_index)); + selectionModel->setCurrentIndex(history.at(history_index), QItemSelectionModel::ClearAndSelect); updateButtons(); }); @@ -126,7 +92,7 @@ DesignWidget::DesignWidget(QWidget *parent) : QWidget(parent), ctx(nullptr), net connect(actionLast, &QAction::triggered, this, [this] { history_ignore = true; history_index = int(history.size() - 1); - treeWidget->setCurrentItem(history.at(history_index)); + selectionModel->setCurrentIndex(history.at(history_index), QItemSelectionModel::ClearAndSelect); updateButtons(); }); @@ -136,11 +102,11 @@ DesignWidget::DesignWidget(QWidget *parent) : QWidget(parent), ctx(nullptr), net connect(actionClear, &QAction::triggered, this, [this] { history_index = -1; history.clear(); - QTreeWidgetItem *clickItem = treeWidget->selectedItems().at(0); - if (clickItem->parent()) { - ElementType type = static_cast(clickItem)->getType(); + QModelIndex index = selectionModel->selectedIndexes().at(0); + if (index.isValid()) { + ElementType type = treeModel->nodeFromIndex(index)->type(); if (type != ElementType::NONE) - addToHistory(treeWidget->selectedItems().at(0)); + addToHistory(index); } updateButtons(); }); @@ -158,7 +124,7 @@ DesignWidget::DesignWidget(QWidget *parent) : QWidget(parent), ctx(nullptr), net vbox1->setSpacing(5); vbox1->setContentsMargins(0, 0, 0, 0); vbox1->addWidget(lineEdit); - vbox1->addWidget(treeWidget); + vbox1->addWidget(treeView); QWidget *toolbarWidget = new QWidget(); QHBoxLayout *hbox = new QHBoxLayout; @@ -192,8 +158,10 @@ DesignWidget::DesignWidget(QWidget *parent) : QWidget(parent), ctx(nullptr), net &DesignWidget::prepareMenuProperty); connect(propertyEditor->treeWidget(), &QTreeWidget::itemDoubleClicked, this, &DesignWidget::onItemDoubleClicked); - connect(treeWidget, SIGNAL(itemSelectionChanged()), SLOT(onItemSelectionChanged())); - connect(treeWidget, &QTreeWidget::customContextMenuRequested, this, &DesignWidget::prepareMenuTree); + selectionModel = treeView->selectionModel(); + connect(selectionModel, SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)), + SLOT(onSelectionChanged(const QItemSelection &, const QItemSelection &))); + connect(treeView, &QTreeWidget::customContextMenuRequested, this, &DesignWidget::prepareMenuTree); history_index = -1; history_ignore = false; @@ -219,7 +187,7 @@ void DesignWidget::updateButtons() actionLast->setEnabled(history_index < (count - 1)); } -void DesignWidget::addToHistory(QTreeWidgetItem *item) +void DesignWidget::addToHistory(QModelIndex item) { if (!history_ignore) { int count = int(history.size()); @@ -234,130 +202,16 @@ void DesignWidget::addToHistory(QTreeWidgetItem *item) void DesignWidget::newContext(Context *ctx) { + highlightSelected.clear(); - treeWidget->clear(); - // reset pointers since they are not valid after clear - nets_root = nullptr; - cells_root = nullptr; history_ignore = false; history_index = -1; history.clear(); updateButtons(); - for (int i = 0; i < 6; i++) - nameToItem[i].clear(); - + highlightSelected.clear(); this->ctx = ctx; - - // Add bels to tree - QTreeWidgetItem *bel_root = new QTreeWidgetItem(treeWidget); - QMap bel_items; - bel_root->setText(0, "Bels"); - bel_root->setFlags(bel_root->flags() & ~Qt::ItemIsSelectable); - treeWidget->insertTopLevelItem(0, bel_root); - if (ctx) { - for (auto bel : ctx->getBels()) { - auto id = ctx->getBelName(bel); - QStringList items = QString(id.c_str(ctx)).split("/"); - QString name; - QTreeWidgetItem *parent = nullptr; - 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) - nameToItem[0].insert(name, new IdStringTreeItem(id, ElementType::BEL, items.at(i), parent)); - else - bel_items.insert(name, new ElementTreeItem(ElementType::NONE, items.at(i), parent)); - } - parent = bel_items[name]; - } - } - } - for (auto bel : bel_items.toStdMap()) { - bel_root->addChild(bel.second); - } - for (auto bel : nameToItem[0].toStdMap()) { - bel_root->addChild(bel.second); - } - - // Add wires to tree - QTreeWidgetItem *wire_root = new QTreeWidgetItem(treeWidget); - QMap wire_items; - wire_root->setText(0, "Wires"); - wire_root->setFlags(wire_root->flags() & ~Qt::ItemIsSelectable); - treeWidget->insertTopLevelItem(0, wire_root); - if (ctx) { - for (auto wire : ctx->getWires()) { - auto id = ctx->getWireName(wire); - QStringList items = QString(id.c_str(ctx)).split("/"); - QString name; - QTreeWidgetItem *parent = nullptr; - 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) - nameToItem[1].insert(name, new IdStringTreeItem(id, ElementType::WIRE, items.at(i), parent)); - else - wire_items.insert(name, new ElementTreeItem(ElementType::NONE, items.at(i), parent)); - } - parent = wire_items[name]; - } - } - } - for (auto wire : wire_items.toStdMap()) { - wire_root->addChild(wire.second); - } - for (auto wire : nameToItem[1].toStdMap()) { - wire_root->addChild(wire.second); - } - // Add pips to tree - QTreeWidgetItem *pip_root = new QTreeWidgetItem(treeWidget); - QMap pip_items; - pip_root->setText(0, "Pips"); - pip_root->setFlags(pip_root->flags() & ~Qt::ItemIsSelectable); - treeWidget->insertTopLevelItem(0, pip_root); -#ifndef ARCH_ECP5 - if (ctx) { - for (auto pip : ctx->getPips()) { - auto id = ctx->getPipName(pip); - QStringList items = QString(id.c_str(ctx)).split("/"); - QString name; - QTreeWidgetItem *parent = nullptr; - 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) - nameToItem[2].insert(name, new IdStringTreeItem(id, ElementType::PIP, items.at(i), parent)); - else - pip_items.insert(name, new ElementTreeItem(ElementType::NONE, items.at(i), parent)); - } - parent = pip_items[name]; - } - } - } - for (auto pip : pip_items.toStdMap()) { - pip_root->addChild(pip.second); - } - for (auto pip : nameToItem[2].toStdMap()) { - pip_root->addChild(pip.second); - } -#endif - - nets_root = new QTreeWidgetItem(treeWidget); - nets_root->setText(0, "Nets"); - nets_root->setFlags(nets_root->flags() & ~Qt::ItemIsSelectable); - treeWidget->insertTopLevelItem(0, nets_root); - - cells_root = new QTreeWidgetItem(treeWidget); - cells_root->setText(0, "Cells"); - cells_root->setFlags(cells_root->flags() & ~Qt::ItemIsSelectable); - treeWidget->insertTopLevelItem(0, cells_root); + treeModel->loadData(ctx); updateTree(); } @@ -369,59 +223,7 @@ void DesignWidget::updateTree() clearProperties(); - // treeWidget->setSortingEnabled(false); - - // 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)) { - IdStringTreeItem *newItem = new IdStringTreeItem(id, ElementType::NET, name, nullptr); - 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)) { - IdStringTreeItem *newItem = new IdStringTreeItem(id, ElementType::CELL, name, nullptr); - cells_root->addChild(newItem); - nameToItem[4].insert(name, newItem); - } - } - // treeWidget->sortByColumn(0, Qt::AscendingOrder); - // treeWidget->setSortingEnabled(true); + treeModel->updateData(ctx); } QtProperty *DesignWidget::addTopLevelProperty(const QString &id) { @@ -460,21 +262,6 @@ QString DesignWidget::getElementTypeName(ElementType type) return "CELL"; return ""; } -int DesignWidget::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; -} - ElementType DesignWidget::getElementTypeByName(QString type) { if (type == "BEL") @@ -510,59 +297,55 @@ QtProperty *DesignWidget::addSubGroup(QtProperty *topItem, const QString &name) void DesignWidget::onClickedBel(BelId bel, bool keep) { - QTreeWidgetItem *item = nameToItem[getElementIndex(ElementType::BEL)].value(ctx->getBelName(bel).c_str(ctx)); - treeWidget->setCurrentItem(item); + ContextTreeItem *item = treeModel->nodeForIdType(ElementType::BEL, ctx->getBelName(bel).c_str(ctx)); + selectionModel->setCurrentIndex(treeModel->indexFromNode(item), QItemSelectionModel::ClearAndSelect); Q_EMIT selected(getDecals(ElementType::BEL, ctx->getBelName(bel)), keep); } void DesignWidget::onClickedWire(WireId wire, bool keep) { - QTreeWidgetItem *item = nameToItem[getElementIndex(ElementType::WIRE)].value(ctx->getWireName(wire).c_str(ctx)); - treeWidget->setCurrentItem(item); + ContextTreeItem *item = treeModel->nodeForIdType(ElementType::WIRE, ctx->getWireName(wire).c_str(ctx)); + selectionModel->setCurrentIndex(treeModel->indexFromNode(item), QItemSelectionModel::ClearAndSelect); Q_EMIT selected(getDecals(ElementType::WIRE, ctx->getWireName(wire)), keep); } void DesignWidget::onClickedPip(PipId pip, bool keep) { - QTreeWidgetItem *item = nameToItem[getElementIndex(ElementType::PIP)].value(ctx->getPipName(pip).c_str(ctx)); - treeWidget->setCurrentItem(item); + ContextTreeItem *item = treeModel->nodeForIdType(ElementType::PIP, ctx->getPipName(pip).c_str(ctx)); + selectionModel->setCurrentIndex(treeModel->indexFromNode(item), QItemSelectionModel::ClearAndSelect); Q_EMIT selected(getDecals(ElementType::PIP, ctx->getPipName(pip)), keep); } -void DesignWidget::onItemSelectionChanged() +void DesignWidget::onSelectionChanged(const QItemSelection &, const QItemSelection &) { - if (treeWidget->selectedItems().size() == 0) + if (selectionModel->selectedIndexes().size() == 0) return; - if (treeWidget->selectedItems().size() > 1) { + if (selectionModel->selectedIndexes().size() > 1) { std::vector decals; - for (auto clickItem : treeWidget->selectedItems()) { - IdString value = static_cast(clickItem)->getData(); - ElementType type = static_cast(clickItem)->getType(); - std::vector d = getDecals(type, value); + for (auto index : selectionModel->selectedIndexes()) { + ContextTreeItem *item = treeModel->nodeFromIndex(index); + std::vector d = getDecals(item->type(), item->id()); std::move(d.begin(), d.end(), std::back_inserter(decals)); } Q_EMIT selected(decals, false); return; } - - QTreeWidgetItem *clickItem = treeWidget->selectedItems().at(0); - - if (!clickItem->parent()) + QModelIndex index = selectionModel->selectedIndexes().at(0); + if (!index.isValid()) return; + ContextTreeItem *clickItem = treeModel->nodeFromIndex(index); - ElementType type = static_cast(clickItem)->getType(); - if (type == ElementType::NONE) { + ElementType type = clickItem->type(); + if (type == ElementType::NONE) return; - } - std::vector decals; - addToHistory(clickItem); + addToHistory(index); clearProperties(); - IdString c = static_cast(clickItem)->getData(); + IdString c = clickItem->id(); Q_EMIT selected(getDecals(type, c), false); if (type == ElementType::BEL) { @@ -799,7 +582,7 @@ std::vector DesignWidget::getDecals(ElementType type, IdString value) return decals; } -void DesignWidget::updateHighlightGroup(QList items, int group) +void DesignWidget::updateHighlightGroup(QList items, int group) { const bool shouldClear = items.size() == 1; for (auto item : items) { @@ -814,9 +597,7 @@ void DesignWidget::updateHighlightGroup(QList items, int grou std::vector decals[8]; for (auto it : highlightSelected.toStdMap()) { - ElementType type = static_cast(it.first)->getType(); - IdString value = static_cast(it.first)->getData(); - std::vector d = getDecals(type, value); + std::vector d = getDecals(it.first->type(), it.first->id()); std::move(d.begin(), d.end(), std::back_inserter(decals[it.second])); } for (int i = 0; i < 8; i++) @@ -826,7 +607,7 @@ void DesignWidget::updateHighlightGroup(QList items, int grou void DesignWidget::prepareMenuProperty(const QPoint &pos) { QTreeWidget *tree = propertyEditor->treeWidget(); - QList items; + QList items; for (auto itemContextMenu : tree->selectedItems()) { QtBrowserItem *browserItem = propertyEditor->itemToBrowserItem(itemContextMenu); if (!browserItem) @@ -836,11 +617,11 @@ void DesignWidget::prepareMenuProperty(const QPoint &pos) if (type == ElementType::NONE) continue; IdString value = ctx->id(selectedProperty->valueText().toStdString()); - items.append(nameToItem[getElementIndex(type)].value(value.c_str(ctx))); + items.append(treeModel->nodeForIdType(type, value.c_str(ctx))); } int selectedIndex = -1; if (items.size() == 1) { - QTreeWidgetItem *item = items.at(0); + ContextTreeItem *item = items.at(0); if (highlightSelected.contains(item)) selectedIndex = highlightSelected[item]; } @@ -850,9 +631,7 @@ void DesignWidget::prepareMenuProperty(const QPoint &pos) connect(selectAction, &QAction::triggered, this, [this, items] { std::vector decals; for (auto clickItem : items) { - IdString value = static_cast(clickItem)->getData(); - ElementType type = static_cast(clickItem)->getType(); - std::vector d = getDecals(type, value); + std::vector d = getDecals(clickItem->type(), clickItem->id()); std::move(d.begin(), d.end(), std::back_inserter(decals)); } Q_EMIT selected(decals, false); @@ -878,12 +657,18 @@ void DesignWidget::prepareMenuProperty(const QPoint &pos) void DesignWidget::prepareMenuTree(const QPoint &pos) { - if (treeWidget->selectedItems().size() == 0) - return; int selectedIndex = -1; - QList items = treeWidget->selectedItems(); - if (treeWidget->selectedItems().size() == 1) { - QTreeWidgetItem *item = treeWidget->selectedItems().at(0); + + if (selectionModel->selectedIndexes().size() == 0) + return; + + QList items; + for (auto index : selectionModel->selectedIndexes()) { + ContextTreeItem *item = treeModel->nodeFromIndex(index); + items.append(item); + } + if (items.size() == 1) { + ContextTreeItem *item = items.at(0); if (highlightSelected.contains(item)) selectedIndex = highlightSelected[item]; } @@ -902,17 +687,16 @@ void DesignWidget::prepareMenuTree(const QPoint &pos) action->setChecked(true); connect(action, &QAction::triggered, this, [this, i, items] { updateHighlightGroup(items, i); }); } - menu.exec(treeWidget->mapToGlobal(pos)); + menu.exec(treeView->mapToGlobal(pos)); } void DesignWidget::onItemDoubleClicked(QTreeWidgetItem *item, int column) { QtProperty *selectedProperty = propertyEditor->itemToBrowserItem(item)->property(); ElementType type = getElementTypeByName(selectedProperty->propertyId()); - QString value = selectedProperty->valueText(); - int index = getElementIndex(type); - if (type != ElementType::NONE && nameToItem[index].contains(value)) - treeWidget->setCurrentItem(nameToItem[index].value(value)); + ContextTreeItem *it = treeModel->nodeForIdType(type, selectedProperty->valueText()); + if (it) + selectionModel->setCurrentIndex(treeModel->indexFromNode(it), QItemSelectionModel::ClearAndSelect); } NEXTPNR_NAMESPACE_END diff --git a/gui/designwidget.h b/gui/designwidget.h index 60291cf3..bbd188cd 100644 --- a/gui/designwidget.h +++ b/gui/designwidget.h @@ -20,27 +20,17 @@ #ifndef DESIGNWIDGET_H #define DESIGNWIDGET_H -#include +#include #include #include "nextpnr.h" #include "qtgroupboxpropertybrowser.h" #include "qtpropertymanager.h" #include "qttreepropertybrowser.h" #include "qtvariantproperty.h" +#include "treemodel.h" NEXTPNR_NAMESPACE_BEGIN -enum class ElementType -{ - NONE, - BEL, - WIRE, - PIP, - NET, - CELL, - GROUP -}; - class DesignWidget : public QWidget { Q_OBJECT @@ -59,9 +49,9 @@ class DesignWidget : public QWidget ElementType getElementTypeByName(QString type); int getElementIndex(ElementType type); void updateButtons(); - void addToHistory(QTreeWidgetItem *item); + void addToHistory(QModelIndex item); std::vector getDecals(ElementType type, IdString value); - void updateHighlightGroup(QList item, int group); + void updateHighlightGroup(QList item, int group); Q_SIGNALS: void info(std::string text); void selected(std::vector decal, bool keep); @@ -70,7 +60,7 @@ class DesignWidget : public QWidget private Q_SLOTS: void prepareMenuProperty(const QPoint &pos); void prepareMenuTree(const QPoint &pos); - void onItemSelectionChanged(); + void onSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected); void onItemDoubleClicked(QTreeWidgetItem *item, int column); public Q_SLOTS: void newContext(Context *ctx); @@ -82,8 +72,9 @@ class DesignWidget : public QWidget private: Context *ctx; - QTreeWidget *treeWidget; - + QTreeView *treeView; + QItemSelectionModel *selectionModel; + ContextTreeModel *treeModel; QtVariantPropertyManager *variantManager; QtVariantPropertyManager *readOnlyManager; QtGroupPropertyManager *groupManager; @@ -93,14 +84,10 @@ class DesignWidget : public QWidget QMap propertyToId; QMap idToProperty; - QMap nameToItem[6]; - std::vector history; + std::vector history; int history_index; bool history_ignore; - QTreeWidgetItem *nets_root; - QTreeWidgetItem *cells_root; - QAction *actionFirst; QAction *actionPrev; QAction *actionNext; @@ -108,7 +95,7 @@ class DesignWidget : public QWidget QAction *actionClear; QColor highlightColors[8]; - QMap highlightSelected; + QMap highlightSelected; }; NEXTPNR_NAMESPACE_END 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 diff --git a/gui/treemodel.h b/gui/treemodel.h new file mode 100644 index 00000000..a976c5bc --- /dev/null +++ b/gui/treemodel.h @@ -0,0 +1,92 @@ +/* + * 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. + * + */ + +#ifndef TREEMODEL_H +#define TREEMODEL_H + +#include +#include "nextpnr.h" + +NEXTPNR_NAMESPACE_BEGIN + +enum class ElementType +{ + NONE, + BEL, + WIRE, + PIP, + NET, + CELL, + GROUP +}; + +class ContextTreeItem +{ + public: + ContextTreeItem(); + ContextTreeItem(QString name); + ContextTreeItem(IdString id, ElementType type, QString name); + ~ContextTreeItem(); + + void addChild(ContextTreeItem *item); + int indexOf(ContextTreeItem *n) const { return children.indexOf(n); } + ContextTreeItem *at(int idx) const { return children.at(idx); } + int count() const { return children.count(); } + ContextTreeItem *parent() const { return parentNode; } + IdString id() const { return itemId; } + ElementType type() const { return itemType; } + QString name() const { return itemName; } + private: + ContextTreeItem *parentNode; + QList children; + IdString itemId; + ElementType itemType; + QString itemName; +}; + +class ContextTreeModel : public QAbstractItemModel +{ + public: + ContextTreeModel(QObject *parent = nullptr); + ~ContextTreeModel(); + + void loadData(Context *ctx); + void updateData(Context *ctx); + ContextTreeItem *nodeFromIndex(const QModelIndex &idx) const; + QModelIndex indexFromNode(ContextTreeItem *node); + ContextTreeItem *nodeForIdType(const ElementType type, const QString name) const; + // Override QAbstractItemModel methods + int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; + int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; + QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; + QModelIndex parent(const QModelIndex &child) const Q_DECL_OVERRIDE; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; + QVariant headerData(int section, Qt::Orientation orientation, int role) const Q_DECL_OVERRIDE; + Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE; + + private: + ContextTreeItem *root; + QMap nameToItem[6]; + ContextTreeItem *nets_root; + ContextTreeItem *cells_root; +}; + +NEXTPNR_NAMESPACE_END + +#endif // TREEMODEL_H -- 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/designwidget.cc | 12 ++++++++++++ gui/treemodel.cc | 8 -------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/gui/designwidget.cc b/gui/designwidget.cc index b321aef1..ee6a14b4 100644 --- a/gui/designwidget.cc +++ b/gui/designwidget.cc @@ -223,6 +223,18 @@ void DesignWidget::updateTree() clearProperties(); + QMap::iterator i = highlightSelected.begin(); + while (i != highlightSelected.end()) { + QMap::iterator prev = i; + ++i; + if (prev.key()->type() == ElementType::NET && ctx->nets.find(prev.key()->id()) == ctx->nets.end()) { + highlightSelected.erase(prev); + } + if (prev.key()->type() == ElementType::CELL && ctx->cells.find(prev.key()->id()) == ctx->cells.end()) { + highlightSelected.erase(prev); + } + } + treeModel->updateData(ctx); } QtProperty *DesignWidget::addTopLevelProperty(const QString &id) 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 9a30b6330b1997d07a8f18b87e2b413faf95094a Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Sat, 28 Jul 2018 17:13:13 +0200 Subject: fix select multiple, and reinit model --- gui/designwidget.cc | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/gui/designwidget.cc b/gui/designwidget.cc index ee6a14b4..106c3146 100644 --- a/gui/designwidget.cc +++ b/gui/designwidget.cc @@ -30,7 +30,7 @@ NEXTPNR_NAMESPACE_BEGIN -DesignWidget::DesignWidget(QWidget *parent) : QWidget(parent), ctx(nullptr) +DesignWidget::DesignWidget(QWidget *parent) : QWidget(parent), ctx(nullptr), selectionModel(nullptr) { // Add tree view treeView = new QTreeView(); @@ -158,9 +158,6 @@ DesignWidget::DesignWidget(QWidget *parent) : QWidget(parent), ctx(nullptr) &DesignWidget::prepareMenuProperty); connect(propertyEditor->treeWidget(), &QTreeWidget::itemDoubleClicked, this, &DesignWidget::onItemDoubleClicked); - selectionModel = treeView->selectionModel(); - connect(selectionModel, SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)), - SLOT(onSelectionChanged(const QItemSelection &, const QItemSelection &))); connect(treeView, &QTreeWidget::customContextMenuRequested, this, &DesignWidget::prepareMenuTree); history_index = -1; @@ -202,6 +199,8 @@ void DesignWidget::addToHistory(QModelIndex item) void DesignWidget::newContext(Context *ctx) { + if (!ctx) + return; highlightSelected.clear(); history_ignore = false; @@ -211,16 +210,13 @@ void DesignWidget::newContext(Context *ctx) highlightSelected.clear(); this->ctx = ctx; + treeView->setModel(nullptr); treeModel->loadData(ctx); - updateTree(); } void DesignWidget::updateTree() { - if (!ctx) - return; - clearProperties(); QMap::iterator i = highlightSelected.begin(); @@ -236,6 +232,10 @@ void DesignWidget::updateTree() } treeModel->updateData(ctx); + treeView->setModel(treeModel); + selectionModel = treeView->selectionModel(); + connect(selectionModel, SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)), + SLOT(onSelectionChanged(const QItemSelection &, const QItemSelection &))); } QtProperty *DesignWidget::addTopLevelProperty(const QString &id) { @@ -310,21 +310,21 @@ QtProperty *DesignWidget::addSubGroup(QtProperty *topItem, const QString &name) void DesignWidget::onClickedBel(BelId bel, bool keep) { ContextTreeItem *item = treeModel->nodeForIdType(ElementType::BEL, ctx->getBelName(bel).c_str(ctx)); - selectionModel->setCurrentIndex(treeModel->indexFromNode(item), QItemSelectionModel::ClearAndSelect); + selectionModel->setCurrentIndex(treeModel->indexFromNode(item), keep ? QItemSelectionModel::Select : QItemSelectionModel::ClearAndSelect); Q_EMIT selected(getDecals(ElementType::BEL, ctx->getBelName(bel)), keep); } void DesignWidget::onClickedWire(WireId wire, bool keep) { ContextTreeItem *item = treeModel->nodeForIdType(ElementType::WIRE, ctx->getWireName(wire).c_str(ctx)); - selectionModel->setCurrentIndex(treeModel->indexFromNode(item), QItemSelectionModel::ClearAndSelect); + selectionModel->setCurrentIndex(treeModel->indexFromNode(item), keep ? QItemSelectionModel::Select : QItemSelectionModel::ClearAndSelect); Q_EMIT selected(getDecals(ElementType::WIRE, ctx->getWireName(wire)), keep); } void DesignWidget::onClickedPip(PipId pip, bool keep) { ContextTreeItem *item = treeModel->nodeForIdType(ElementType::PIP, ctx->getPipName(pip).c_str(ctx)); - selectionModel->setCurrentIndex(treeModel->indexFromNode(item), QItemSelectionModel::ClearAndSelect); + selectionModel->setCurrentIndex(treeModel->indexFromNode(item), keep ? QItemSelectionModel::Select : QItemSelectionModel::ClearAndSelect); Q_EMIT selected(getDecals(ElementType::PIP, ctx->getPipName(pip)), keep); } -- 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/designwidget.cc | 18 ++++++++++-------- gui/treemodel.cc | 17 +++++++++++++++++ 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/gui/designwidget.cc b/gui/designwidget.cc index 106c3146..0f01b3c5 100644 --- a/gui/designwidget.cc +++ b/gui/designwidget.cc @@ -160,6 +160,10 @@ DesignWidget::DesignWidget(QWidget *parent) : QWidget(parent), ctx(nullptr), sel connect(treeView, &QTreeWidget::customContextMenuRequested, this, &DesignWidget::prepareMenuTree); + selectionModel = treeView->selectionModel(); + connect(selectionModel, SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)), + SLOT(onSelectionChanged(const QItemSelection &, const QItemSelection &))); + history_index = -1; history_ignore = false; @@ -210,7 +214,6 @@ void DesignWidget::newContext(Context *ctx) highlightSelected.clear(); this->ctx = ctx; - treeView->setModel(nullptr); treeModel->loadData(ctx); updateTree(); } @@ -232,10 +235,6 @@ void DesignWidget::updateTree() } treeModel->updateData(ctx); - treeView->setModel(treeModel); - selectionModel = treeView->selectionModel(); - connect(selectionModel, SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)), - SLOT(onSelectionChanged(const QItemSelection &, const QItemSelection &))); } QtProperty *DesignWidget::addTopLevelProperty(const QString &id) { @@ -310,21 +309,24 @@ QtProperty *DesignWidget::addSubGroup(QtProperty *topItem, const QString &name) void DesignWidget::onClickedBel(BelId bel, bool keep) { ContextTreeItem *item = treeModel->nodeForIdType(ElementType::BEL, ctx->getBelName(bel).c_str(ctx)); - selectionModel->setCurrentIndex(treeModel->indexFromNode(item), keep ? QItemSelectionModel::Select : QItemSelectionModel::ClearAndSelect); + selectionModel->setCurrentIndex(treeModel->indexFromNode(item), + keep ? QItemSelectionModel::Select : QItemSelectionModel::ClearAndSelect); Q_EMIT selected(getDecals(ElementType::BEL, ctx->getBelName(bel)), keep); } void DesignWidget::onClickedWire(WireId wire, bool keep) { ContextTreeItem *item = treeModel->nodeForIdType(ElementType::WIRE, ctx->getWireName(wire).c_str(ctx)); - selectionModel->setCurrentIndex(treeModel->indexFromNode(item), keep ? QItemSelectionModel::Select : QItemSelectionModel::ClearAndSelect); + selectionModel->setCurrentIndex(treeModel->indexFromNode(item), + keep ? QItemSelectionModel::Select : QItemSelectionModel::ClearAndSelect); Q_EMIT selected(getDecals(ElementType::WIRE, ctx->getWireName(wire)), keep); } void DesignWidget::onClickedPip(PipId pip, bool keep) { ContextTreeItem *item = treeModel->nodeForIdType(ElementType::PIP, ctx->getPipName(pip).c_str(ctx)); - selectionModel->setCurrentIndex(treeModel->indexFromNode(item), keep ? QItemSelectionModel::Select : QItemSelectionModel::ClearAndSelect); + selectionModel->setCurrentIndex(treeModel->indexFromNode(item), + keep ? QItemSelectionModel::Select : QItemSelectionModel::ClearAndSelect); Q_EMIT selected(getDecals(ElementType::PIP, ctx->getPipName(pip)), keep); } 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 +++++++++++++++++++++++++++++++++++++-------------- gui/treemodel.h | 1 + 2 files changed, 38 insertions(+), 14 deletions(-) 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(); } diff --git a/gui/treemodel.h b/gui/treemodel.h index a976c5bc..a85c290a 100644 --- a/gui/treemodel.h +++ b/gui/treemodel.h @@ -52,6 +52,7 @@ class ContextTreeItem IdString id() const { return itemId; } ElementType type() const { return itemType; } QString name() const { return itemName; } + void sort(); private: ContextTreeItem *parentNode; QList children; -- cgit v1.2.3