diff options
Diffstat (limited to 'gui')
-rw-r--r-- | gui/designwidget.cc | 30 | ||||
-rw-r--r-- | gui/designwidget.h | 6 | ||||
-rw-r--r-- | gui/treemodel.cc | 189 | ||||
-rw-r--r-- | gui/treemodel.h | 114 |
4 files changed, 144 insertions, 195 deletions
diff --git a/gui/designwidget.cc b/gui/designwidget.cc index 249df423..ad1362c8 100644 --- a/gui/designwidget.cc +++ b/gui/designwidget.cc @@ -51,10 +51,11 @@ DesignWidget::DesignWidget(QWidget *parent) : QWidget(parent), ctx(nullptr), sel propertyEditor->treeWidget()->setContextMenuPolicy(Qt::CustomContextMenu);
propertyEditor->treeWidget()->setSelectionMode(QAbstractItemView::ExtendedSelection);
- QLineEdit *lineEdit = new QLineEdit();
- lineEdit->setClearButtonEnabled(true);
- lineEdit->addAction(QIcon(":/icons/resources/zoom.png"), QLineEdit::LeadingPosition);
- lineEdit->setPlaceholderText("Search...");
+ searchEdit = new QLineEdit();
+ searchEdit->setClearButtonEnabled(true);
+ searchEdit->addAction(QIcon(":/icons/resources/zoom.png"), QLineEdit::LeadingPosition);
+ searchEdit->setPlaceholderText("Search...");
+ connect(searchEdit, SIGNAL(returnPressed()), this, SLOT(onSearchInserted()));
actionFirst = new QAction("", this);
actionFirst->setIcon(QIcon(":/icons/resources/resultset_first.png"));
@@ -123,7 +124,7 @@ DesignWidget::DesignWidget(QWidget *parent) : QWidget(parent), ctx(nullptr), sel topWidget->setLayout(vbox1);
vbox1->setSpacing(5);
vbox1->setContentsMargins(0, 0, 0, 0);
- vbox1->addWidget(lineEdit);
+ vbox1->addWidget(searchEdit);
vbox1->addWidget(treeView);
QWidget *toolbarWidget = new QWidget();
@@ -214,7 +215,7 @@ void DesignWidget::newContext(Context *ctx) highlightSelected.clear();
this->ctx = ctx;
- treeModel->loadData(ctx);
+ treeModel->loadContext(ctx);
updateTree();
}
@@ -234,7 +235,7 @@ void DesignWidget::updateTree() }
}
- treeModel->updateData(ctx);
+ treeModel->updateCellsNets(ctx);
}
QtProperty *DesignWidget::addTopLevelProperty(const QString &id)
{
@@ -714,4 +715,19 @@ void DesignWidget::onItemDoubleClicked(QTreeWidgetItem *item, int column) }
void DesignWidget::onDoubleClicked(const QModelIndex &index) { Q_EMIT zoomSelected(); }
+
+void DesignWidget::onSearchInserted()
+{
+ if (currentSearch == searchEdit->text()) {
+ currentIndex++;
+ if (currentIndex >= currentSearchIndexes.size())
+ currentIndex = 0;
+ } else {
+ currentSearch = searchEdit->text();
+ currentSearchIndexes = treeModel->search(searchEdit->text());
+ currentIndex = 0;
+ }
+ if (currentSearchIndexes.size() > 0 && currentIndex < currentSearchIndexes.size())
+ selectionModel->setCurrentIndex(currentSearchIndexes.at(currentIndex), QItemSelectionModel::ClearAndSelect);
+}
NEXTPNR_NAMESPACE_END
diff --git a/gui/designwidget.h b/gui/designwidget.h index b229a8a8..d6af83a0 100644 --- a/gui/designwidget.h +++ b/gui/designwidget.h @@ -64,6 +64,7 @@ class DesignWidget : public QWidget void onSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
void onItemDoubleClicked(QTreeWidgetItem *item, int column);
void onDoubleClicked(const QModelIndex &index);
+ void onSearchInserted();
public Q_SLOTS:
void newContext(Context *ctx);
void updateTree();
@@ -77,6 +78,7 @@ class DesignWidget : public QWidget QTreeView *treeView;
QItemSelectionModel *selectionModel;
ContextTreeModel *treeModel;
+ QLineEdit *searchEdit;
QtVariantPropertyManager *variantManager;
QtVariantPropertyManager *readOnlyManager;
QtGroupPropertyManager *groupManager;
@@ -98,6 +100,10 @@ class DesignWidget : public QWidget QColor highlightColors[8];
QMap<LazyTreeItem *, int> highlightSelected;
+
+ QString currentSearch;
+ QList<QModelIndex> currentSearchIndexes;
+ int currentIndex;
};
NEXTPNR_NAMESPACE_END
diff --git a/gui/treemodel.cc b/gui/treemodel.cc index 9a501eb9..fd3ae45b 100644 --- a/gui/treemodel.cc +++ b/gui/treemodel.cc @@ -18,114 +18,48 @@ */ #include "treemodel.h" +#include "log.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); -//} - -void ContextTreeItem::sort() -{ - for (auto item : children) - if (item->count()>1) item->sort(); - qSort(children.begin(), children.end(), [&](const ContextTreeItem *a, const ContextTreeItem *b){ - QString name_a = a->name(); - QString name_b = b->name(); - // Try to extract a common prefix from both strings. - QString common; - for (int i = 0; i < std::min(name_a.size(), name_b.size()); i++) { - const QChar c_a = name_a[i]; - const QChar c_b = name_b[i]; - if (c_a == c_b) { - common.push_back(c_a); - } else { - break; - } - } - // No common part? lexical sort. - if (common.size() == 0) { - return a->name() < b->name(); - } - - // Get the non-common parts. - name_a.remove(0, common.size()); - name_b.remove(0, common.size()); - // And see if they're strings. - bool ok = true; - int num_a = name_a.toInt(&ok); - if (!ok) { - return a->name() < b->name(); - } - int num_b = name_b.toInt(&ok); - if (!ok) { - return a->name() < b->name(); - } - return num_a < num_b; - }); -} - ContextTreeModel::ContextTreeModel(QObject *parent) : QAbstractItemModel(parent), root_(new StaticTreeItem("Elements", nullptr)) {} ContextTreeModel::~ContextTreeModel() {} -void ContextTreeModel::loadData(Context *ctx) +void ContextTreeModel::loadContext(Context *ctx) { if (!ctx) return; beginResetModel(); + // Currently we lack an API to get a proper hierarchy of bels/pip/wires + // cross-arch. So we only do this for ICE40 by querying the ChipDB + // directly. + // TODO(q3k): once AnyId and the tree API land in Arch, move this over. +#ifdef ARCH_ICE40 { - printf("generating bel map...\n"); std::map<std::pair<int, int>, std::vector<BelId>> belMap; for (auto bel : ctx->getBels()) { auto loc = ctx->getBelLocation(bel); belMap[std::pair<int, int>(loc.x, loc.y)].push_back(bel); } - printf("generating bel static tree...\n"); auto belGetter = [](Context *ctx, BelId id) { return ctx->getBelName(id); }; bel_root_ = std::unique_ptr<BelXYRoot>(new BelXYRoot(ctx, "Bels", root_.get(), belMap, belGetter)); - printf("generating wire map...\n"); std::map<std::pair<int, int>, std::vector<WireId>> wireMap; - //TODO(q3k): change this once we have an API to get wire categories/locations/labels for (int i = 0; i < ctx->chip_info->num_wires; i++) { const auto wire = &ctx->chip_info->wire_data[i]; WireId wireid; wireid.index = i; wireMap[std::pair<int, int>(wire->x, wire->y)].push_back(wireid); } - printf("generating wire static tree...\n"); auto wireGetter = [](Context *ctx, WireId id) { return ctx->getWireName(id); }; wire_root_ = std::unique_ptr<WireXYRoot>(new WireXYRoot(ctx, "Wires", root_.get(), wireMap, wireGetter)); - printf("generating pip map...\n"); std::map<std::pair<int, int>, std::vector<PipId>> pipMap; - //TODO(q3k): change this once we have an API to get wire categories/locations/labels for (int i = 0; i < ctx->chip_info->num_pips; i++) { const auto pip = &ctx->chip_info->pip_data[i]; PipId pipid; @@ -136,80 +70,34 @@ void ContextTreeModel::loadData(Context *ctx) auto pipGetter = [](Context *ctx, PipId id) { return ctx->getPipName(id); }; pip_root_ = std::unique_ptr<PipXYRoot>(new PipXYRoot(ctx, "Pips", root_.get(), pipMap, pipGetter)); } +#endif - //nets_root = new ContextTreeItem("Nets"); - //root->addChild(nets_root); - - //cells_root = new ContextTreeItem("Cells"); - //root->addChild(cells_root); + cell_root_ = std::unique_ptr<IdStringList>(new IdStringList(QString("Cells"), root_.get())); + net_root_ = std::unique_ptr<IdStringList>(new IdStringList(QString("Nets"), root_.get())); endResetModel(); + + updateCellsNets(ctx); } -void ContextTreeModel::updateData(Context *ctx) +void ContextTreeModel::updateCellsNets(Context *ctx) { if (!ctx) return; beginResetModel(); - //QModelIndex nets_index = indexFromNode(nets_root); - // Remove nets not existing any more - //QMap<QString, ContextTreeItem *>::iterator i = nameToItem[3].begin(); - //while (i != nameToItem[3].end()) { - // QMap<QString, ContextTreeItem *>::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 - //for (auto &item : ctx->nets) { - // 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(); - // } - //} - - //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<QString, ContextTreeItem *>::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 - //for (auto &item : ctx->cells) { - // 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(); - // } - //} + std::vector<IdString> cells; + for (auto &pair : ctx->cells) { + cells.push_back(pair.first); + } + cell_root_->updateElements(ctx, cells); - //cells_root->sort(); + std::vector<IdString> nets; + for (auto &pair : ctx->nets) { + nets.push_back(pair.first); + } + net_root_->updateElements(ctx, nets); endResetModel(); } @@ -277,22 +165,6 @@ static int getElementIndex(ElementType type) 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 { LazyTreeItem *node = nodeFromIndex(index); @@ -310,4 +182,19 @@ bool ContextTreeModel::canFetchMore(const QModelIndex &parent) const return nodeFromIndex(parent)->canFetchMore(); } +QList<QModelIndex> ContextTreeModel::search(QString text) +{ + QList<QModelIndex> list; + //for (int i = 0; i < 6; i++) { + // for (auto key : nameToItem[i].keys()) { + // if (key.contains(text, Qt::CaseInsensitive)) { + // list.append(indexFromNode(nameToItem[i].value(key))); + // if (list.count() > 500) + // break; // limit to 500 results + // } + // } + //} + return list; +} + NEXTPNR_NAMESPACE_END diff --git a/gui/treemodel.h b/gui/treemodel.h index 7de54db4..f193468a 100644 --- a/gui/treemodel.h +++ b/gui/treemodel.h @@ -22,6 +22,7 @@ #include <QAbstractItemModel> #include "nextpnr.h" +#include "log.h" NEXTPNR_NAMESPACE_BEGIN @@ -36,31 +37,6 @@ enum class ElementType 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; } - void sort(); - private: - ContextTreeItem *parentNode; - QList<ContextTreeItem *> children; - IdString itemId; - ElementType itemType; - QString itemName; -}; - class LazyTreeItem { protected: @@ -207,6 +183,74 @@ class ElementList : public LazyTreeItem } }; +class IdStringList : public StaticTreeItem +{ + private: + std::unordered_map<IdString, std::unique_ptr<StaticTreeItem>> managed_; + public: + using StaticTreeItem::StaticTreeItem; + + void updateElements(Context *ctx, std::vector<IdString> elements) + { + // for any elements that are not yet in managed_, created them. + std::unordered_set<IdString> element_set; + for (auto elem : elements) { + element_set.insert(elem); + auto existing = managed_.find(elem); + if (existing == managed_.end()) { + auto item = new StaticTreeItem(elem.c_str(ctx), this); + managed_.emplace(elem, std::unique_ptr<StaticTreeItem>(item)); + } + } + + children_.clear(); + // for any elements that are in managed_ but not in new, delete them. + for (auto &pair : managed_) { + if (element_set.count(pair.first) != 0) { + children_.push_back(pair.second.get()); + continue; + } + managed_.erase(pair.first); + } + + // sort new children + qSort(children_.begin(), children_.end(), [&](const LazyTreeItem *a, const LazyTreeItem *b){ + QString name_a = a->name(); + QString name_b = b->name(); + // Try to extract a common prefix from both strings. + QString common; + for (int i = 0; i < std::min(name_a.size(), name_b.size()); i++) { + const QChar c_a = name_a[i]; + const QChar c_b = name_b[i]; + if (c_a == c_b) { + common.push_back(c_a); + } else { + break; + } + } + // No common part? lexical sort. + if (common.size() == 0) { + return a->name() < b->name(); + } + + // Get the non-common parts. + name_a.remove(0, common.size()); + name_b.remove(0, common.size()); + // And see if they're strings. + bool ok = true; + int num_a = name_a.toInt(&ok); + if (!ok) { + return a->name() < b->name(); + } + int num_b = name_b.toInt(&ok); + if (!ok) { + return a->name() < b->name(); + } + return num_a < num_b; + }); + } +}; + template <typename ElementT> class ElementXYRoot : public StaticTreeItem { @@ -217,7 +261,7 @@ class ElementXYRoot : public StaticTreeItem private: Context *ctx_; - std::vector<std::unique_ptr<LazyTreeItem>> bels_; + std::vector<std::unique_ptr<LazyTreeItem>> managed_; ElementMap map_; ElementGetter getter_; @@ -241,11 +285,11 @@ class ElementXYRoot : public StaticTreeItem // create X item for tree auto item = new StaticTreeItem(QString("X%1").arg(i), this); - bels_.push_back(std::move(std::unique_ptr<LazyTreeItem>(item))); + managed_.push_back(std::move(std::unique_ptr<LazyTreeItem>(item))); for (auto j : y_present) { auto item2 = new ElementList<ElementT>(ctx_, QString("Y%1").arg(j), item, &map_, i, j, getter_); item2->fetchMore(1); - bels_.push_back(std::move(std::unique_ptr<LazyTreeItem>(item2))); + managed_.push_back(std::move(std::unique_ptr<LazyTreeItem>(item2))); } } } @@ -261,11 +305,10 @@ class ContextTreeModel : public QAbstractItemModel ContextTreeModel(QObject *parent = nullptr); ~ContextTreeModel(); - void loadData(Context *ctx); - void updateData(Context *ctx); + void loadContext(Context *ctx); + void updateCellsNets(Context *ctx); LazyTreeItem *nodeFromIndex(const QModelIndex &idx) const; - //QModelIndex indexFromNode(ContextTreeItem *node); - //ContextTreeItem *nodeForIdType(const ElementType type, const QString name) const; + QList<QModelIndex> search(QString text); // Override QAbstractItemModel methods int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; @@ -283,11 +326,8 @@ class ContextTreeModel : public QAbstractItemModel std::unique_ptr<BelXYRoot> bel_root_; std::unique_ptr<WireXYRoot> wire_root_; std::unique_ptr<PipXYRoot> pip_root_; - //std::unique_ptr<ElementXYRoot> wires_root_; - //std::unique_ptr<ElementXYRoot> pips_root_; - //QMap<QString, ContextTreeItem *> nameToItem[6]; - //ContextTreeItem *nets_root; - //ContextTreeItem *cells_root; + std::unique_ptr<IdStringList> cell_root_; + std::unique_ptr<IdStringList> net_root_; }; NEXTPNR_NAMESPACE_END |