#include "radixwidgets/navigationwidget.hh" #include "radixwidgets/navigationitem.hh" #include "radixwidgets/navigationmodel.hh" #include "radixbug/bug.hh" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace radix { class NavigationItemSortFilterProxyModel::PImpl { public: QHash seen; }; NavigationItemSortFilterProxyModel::NavigationItemSortFilterProxyModel( QObject* parent) : QSortFilterProxyModel(parent) , p(new PImpl(), [](PImpl* impl) { delete impl; }) { } bool NavigationItemSortFilterProxyModel::accepts(const QModelIndex& index) const { const QString& text = index.data().toString(); const QRegExp& regex = filterRegExp(); bool accept = text.contains(regex); for (int i = 0, ie = sourceModel()->rowCount(index); i < ie; i++) { if (accepts(sourceModel()->index(i, 0, index))) { accept = true; break; } } p->seen[index] = accept; return accept; } void NavigationItemSortFilterProxyModel::clearCache() { p->seen.clear(); } bool NavigationItemSortFilterProxyModel::filterAcceptsRow( int source_row, const QModelIndex& source_parent) const { const QModelIndex& index = sourceModel()->index(source_row, 0, source_parent); if (p->seen.contains(index)) { return p->seen.value(index); } return accepts(index); } class NavigationWidget::PImpl { public: QLineEdit* filter; NavigationModel* model; NavigationItemSortFilterProxyModel* proxy; QTreeView* view; }; NavigationWidget::NavigationWidget(QWidget* parent) : QWidget(parent) , p(new PImpl(), [](PImpl* impl) { delete impl; }) { initMembers(); initLayout(); } NavigationModel* NavigationWidget::navigationModel() { return p->model; } void NavigationWidget::contextMenuRequested(QPoint point) { radix_tagged_line("contextMenuRequested()"); QModelIndex index = p->view->indexAt(point); QMenu m; m.exec(p->view->viewport()->mapToGlobal(point)); } void NavigationWidget::initLayout() { auto vlayout = new QVBoxLayout(this); vlayout->addWidget(p->filter); vlayout->addWidget(p->view); } void NavigationWidget::initMembers() { // allocate p->filter = new QLineEdit(); p->model = new NavigationModel(); p->proxy = new NavigationItemSortFilterProxyModel(); p->view = new QTreeView(); // init properties p->filter->setPlaceholderText("Filter"); p->view->installEventFilter(this); p->view->setContextMenuPolicy(Qt::CustomContextMenu); p->view->setEditTriggers(QAbstractItemView::NoEditTriggers); p->view->setModel(p->proxy); p->view->header()->setSectionResizeMode(QHeaderView::ResizeToContents); p->view->header()->setStretchLastSection(false); p->view->header()->setVisible(false); p->proxy->setSourceModel(p->model); // shortcuts auto activateEnter = new QShortcut(p->view); auto activateReturn = new QShortcut(p->view); auto collapseBranch = new QShortcut(p->view); activateEnter->setContext(Qt::WidgetShortcut); activateEnter->setKey(Qt::Key_Enter); activateReturn->setContext(Qt::WidgetShortcut); activateReturn->setKey(Qt::Key_Return); collapseBranch->setContext(Qt::WidgetShortcut); collapseBranch->setKey(Qt::Key_Left); // // connect signals/slots connect(p->filter, SIGNAL(textChanged(QString)), this, SLOT(filterModel(QString))); connect(p->view, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(itemDoubleClicked(QModelIndex))); connect(p->view, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextMenuRequested(QPoint))); } void NavigationWidget::filterModel(const QString& pattern) { // regex used to filter the model QRegExp regex(pattern, Qt::CaseInsensitive, QRegExp::RegExp2); // update the model p->proxy->clearCache(); p->proxy->setFilterRegExp(regex); // update the tree if (pattern.isEmpty()) { p->view->collapseAll(); for (int i = 0, ie = p->model->rowCount(); i < ie; i++) { p->view->expand(p->proxy->mapFromSource(p->model->index(i, 0))); } } else { p->view->expandAll(); } } void NavigationWidget::itemDoubleClicked(QModelIndex index) { radix_tagged_line("itemDoubleClicked()"); const auto& mapped = p->proxy->mapToSource(index); radix_tagged_line("\t[" << mapped.row() << "," << mapped.column() << "]"); } } // namespace radix