From e550317fdf74c940ffa2c10af7546ad22719b7ad Mon Sep 17 00:00:00 2001 From: Mateusz Kaduk Date: Sun, 10 Apr 2016 18:46:40 +0200 Subject: [PATCH] LP-286 Port TauLabs filter in UAVobjectbrowser --- .../streamservice/streamserviceplugin.h | 2 +- .../uavobjectbrowser/browseritemdelegate.cpp | 32 ++- .../uavobjectbrowser/browseritemdelegate.h | 10 +- .../uavobjectbrowser/uavobjectbrowser.ui | 35 ++++ .../uavobjectbrowserwidget.cpp | 193 ++++++++++++++---- .../uavobjectbrowser/uavobjectbrowserwidget.h | 19 +- .../uavobjectbrowser/uavobjecttreemodel.h | 2 +- 7 files changed, 243 insertions(+), 50 deletions(-) diff --git a/ground/gcs/src/plugins/streamservice/streamserviceplugin.h b/ground/gcs/src/plugins/streamservice/streamserviceplugin.h index b17f49789..2a628b7d7 100644 --- a/ground/gcs/src/plugins/streamservice/streamserviceplugin.h +++ b/ground/gcs/src/plugins/streamservice/streamserviceplugin.h @@ -37,7 +37,7 @@ class QTcpSocket; class StreamServicePlugin : public ExtensionSystem::IPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "Openpilot.StreamService") + Q_PLUGIN_METADATA(IID "Openpilot.StreamService") public: StreamServicePlugin(); diff --git a/ground/gcs/src/plugins/uavobjectbrowser/browseritemdelegate.cpp b/ground/gcs/src/plugins/uavobjectbrowser/browseritemdelegate.cpp index 028dc82c3..6fddafa1d 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/browseritemdelegate.cpp +++ b/ground/gcs/src/plugins/uavobjectbrowser/browseritemdelegate.cpp @@ -2,7 +2,8 @@ ****************************************************************************** * * @file browseritemdelegate.cpp - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. + * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. * @addtogroup GCSPlugins GCS Plugins * @{ * @addtogroup UAVObjectBrowserPlugin UAVObject Browser Plugin @@ -25,41 +26,52 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include "uavobjectbrowserwidget.h" #include "browseritemdelegate.h" #include "fieldtreeitem.h" -BrowserItemDelegate::BrowserItemDelegate(QObject *parent) : +BrowserItemDelegate::BrowserItemDelegate(TreeSortFilterProxyModel *proxyModel, QObject *parent) : QStyledItemDelegate(parent) -{} +{ + this->proxyModel = proxyModel; +} QWidget *BrowserItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem & option, - const QModelIndex & index) const + const QModelIndex & proxyIndex) const { Q_UNUSED(option) - FieldTreeItem * item = static_cast(index.internalPointer()); - QWidget *editor = item->createEditor(parent); + QModelIndex index = proxyModel->mapToSource(proxyIndex); + + FieldTreeItem *item = static_cast(index.internalPointer()); + QWidget *editor = item->createEditor(parent); Q_ASSERT(editor); return editor; } void BrowserItemDelegate::setEditorData(QWidget *editor, - const QModelIndex &index) const + const QModelIndex & proxyIndex) const { + QModelIndex index = proxyModel->mapToSource(proxyIndex); + FieldTreeItem *item = static_cast(index.internalPointer()); - QVariant value = index.model()->data(index, Qt::EditRole); + QVariant value = proxyIndex.model()->data(proxyIndex, Qt::EditRole); item->setEditorValue(editor, value); } void BrowserItemDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, - const QModelIndex &index) const + const QModelIndex &proxyIndex) const { + QModelIndex index = proxyModel->mapToSource(proxyIndex); + FieldTreeItem *item = static_cast(index.internalPointer()); QVariant value = item->getEditorValue(editor); - model->setData(index, value, Qt::EditRole); + bool ret = model->setData(proxyIndex, value, Qt::EditRole); + + Q_ASSERT(ret); } void BrowserItemDelegate::updateEditorGeometry(QWidget *editor, diff --git a/ground/gcs/src/plugins/uavobjectbrowser/browseritemdelegate.h b/ground/gcs/src/plugins/uavobjectbrowser/browseritemdelegate.h index 17952b5db..2605db7dc 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/browseritemdelegate.h +++ b/ground/gcs/src/plugins/uavobjectbrowser/browseritemdelegate.h @@ -2,7 +2,8 @@ ****************************************************************************** * * @file browseritemdelegate.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. + * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. * @addtogroup GCSPlugins GCS Plugins * @{ * @addtogroup UAVObjectBrowserPlugin UAVObject Browser Plugin @@ -30,10 +31,12 @@ #include +class TreeSortFilterProxyModel; + class BrowserItemDelegate : public QStyledItemDelegate { Q_OBJECT public: - explicit BrowserItemDelegate(QObject *parent = 0); + explicit BrowserItemDelegate(TreeSortFilterProxyModel *proxyModel, QObject *parent = 0); QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const; @@ -51,6 +54,9 @@ public: signals: public slots: + +private: + TreeSortFilterProxyModel *proxyModel; }; #endif // BROWSERITEMDELEGATE_H diff --git a/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowser.ui b/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowser.ui index 492ab119f..5feed5889 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowser.ui +++ b/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowser.ui @@ -204,6 +204,40 @@ + + + + Qt::Horizontal + + + QSizePolicy::Preferred + + + + 10 + 20 + + + + + + + + Search for UAVObject... + + + + + + + Clear + + + + .. + + + @@ -273,6 +307,7 @@ This space shows a description of the selected UAVObject. + diff --git a/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.cpp b/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.cpp index cea702e25..59efba6e1 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.cpp +++ b/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.cpp @@ -2,7 +2,8 @@ ****************************************************************************** * * @file uavobjectbrowserwidget.cpp - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. + * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. * @addtogroup GCSPlugins GCS Plugins * @{ * @addtogroup UAVObjectBrowserPlugin UAVObject Browser Plugin @@ -49,10 +50,13 @@ UAVObjectBrowserWidget::UAVObjectBrowserWidget(QWidget *parent) : QWidget(parent m_viewoptions->setupUi(m_viewoptionsDialog); m_browser->setupUi(this); m_model = new UAVObjectTreeModel(); - m_browser->treeView->setModel(m_model); + m_modelProxy = new TreeSortFilterProxyModel(this); + m_modelProxy->setSourceModel(m_model); + m_modelProxy->setDynamicSortFilter(true); + m_browser->treeView->setModel(m_modelProxy); m_browser->treeView->setColumnWidth(0, 300); - BrowserItemDelegate *m_delegate = new BrowserItemDelegate(); + BrowserItemDelegate *m_delegate = new BrowserItemDelegate(m_modelProxy); m_browser->treeView->setItemDelegate(m_delegate); m_browser->treeView->setEditTriggers(QAbstractItemView::AllEditTriggers); m_browser->treeView->setSelectionBehavior(QAbstractItemView::SelectItems); @@ -76,6 +80,8 @@ UAVObjectBrowserWidget::UAVObjectBrowserWidget(QWidget *parent) : QWidget(parent connect(m_viewoptions->cbCategorized, SIGNAL(toggled(bool)), this, SLOT(viewOptionsChangedSlot())); connect(m_viewoptions->cbDescription, SIGNAL(toggled(bool)), this, SLOT(viewOptionsChangedSlot())); connect(m_browser->splitter, SIGNAL(splitterMoved(int, int)), this, SLOT(splitterMoved())); + connect(m_browser->searchLine, SIGNAL(textChanged(QString)), this, SLOT(searchLineChanged(QString))); + connect(m_browser->searchClearButton, SIGNAL(clicked(bool)), this, SLOT(searchTextCleared())); enableSendRequest(false); } @@ -97,11 +103,29 @@ void UAVObjectBrowserWidget::setSplitterState(QByteArray state) m_browser->splitter->restoreState(state); } + +void UAVObjectBrowserWidget::resetProxyModel(UAVObjectTreeModel *currentModel) +{ + m_modelProxy = new TreeSortFilterProxyModel(this); + m_modelProxy->setSourceModel(currentModel); + m_modelProxy->setDynamicSortFilter(true); + m_browser->treeView->setModel(m_modelProxy); + + BrowserItemDelegate *m_delegate = new BrowserItemDelegate(m_modelProxy); + m_browser->treeView->setItemDelegate(m_delegate); + + if (!m_browser->searchLine->text().isEmpty()) { + emit searchLineChanged(m_browser->searchLine->text()); + } +} + void UAVObjectBrowserWidget::showMetaData(bool show) { QList metaIndexes = m_model->getMetaDataIndexes(); - foreach(QModelIndex index, metaIndexes) { - m_browser->treeView->setRowHidden(index.row(), index.parent(), !show); + foreach(QModelIndex modelIndex, metaIndexes) { + QModelIndex proxyModelindex = m_modelProxy->mapFromSource(modelIndex); + + m_browser->treeView->setRowHidden(proxyModelindex.row(), proxyModelindex.parent(), !show); } } @@ -115,12 +139,12 @@ void UAVObjectBrowserWidget::categorize(bool categorize) UAVObjectTreeModel *tmpModel = m_model; m_model = new UAVObjectTreeModel(0, categorize, m_viewoptions->cbScientific->isChecked()); + resetProxyModel(m_model); m_model->setRecentlyUpdatedColor(m_recentlyUpdatedColor); m_model->setManuallyChangedColor(m_manuallyChangedColor); m_model->setRecentlyUpdatedTimeout(m_recentlyUpdatedTimeout); m_model->setOnlyHilightChangedValues(m_onlyHilightChangedValues); m_model->setUnknowObjectColor(m_unknownObjectColor); - m_browser->treeView->setModel(m_model); showMetaData(m_viewoptions->cbMetaData->isChecked()); connect(m_browser->treeView->selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)), this, SLOT(currentChanged(QModelIndex, QModelIndex)), Qt::UniqueConnection); @@ -132,11 +156,10 @@ void UAVObjectBrowserWidget::useScientificNotation(bool scientific) UAVObjectTreeModel *tmpModel = m_model; m_model = new UAVObjectTreeModel(0, m_viewoptions->cbCategorized->isChecked(), scientific); - m_model->setRecentlyUpdatedColor(m_recentlyUpdatedColor); + resetProxyModel(m_model); m_model->setManuallyChangedColor(m_manuallyChangedColor); m_model->setRecentlyUpdatedTimeout(m_recentlyUpdatedTimeout); m_model->setUnknowObjectColor(m_unknownObjectColor); - m_browser->treeView->setModel(m_model); showMetaData(m_viewoptions->cbMetaData->isChecked()); connect(m_browser->treeView->selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)), this, SLOT(currentChanged(QModelIndex, QModelIndex)), Qt::UniqueConnection); @@ -147,26 +170,28 @@ void UAVObjectBrowserWidget::sendUpdate() { this->setFocus(); ObjectTreeItem *objItem = findCurrentObjectTreeItem(); - Q_ASSERT(objItem); - objItem->apply(); - UAVObject *obj = objItem->object(); - Q_ASSERT(obj); - obj->updated(); + if (objItem != NULL) { + objItem->apply(); + UAVObject *obj = objItem->object(); + Q_ASSERT(obj); + obj->updated(); + } } void UAVObjectBrowserWidget::requestUpdate() { ObjectTreeItem *objItem = findCurrentObjectTreeItem(); - Q_ASSERT(objItem); - UAVObject *obj = objItem->object(); - Q_ASSERT(obj); - obj->requestUpdate(); + if (objItem != NULL) { + UAVObject *obj = objItem->object(); + Q_ASSERT(obj); + obj->requestUpdate(); + } } ObjectTreeItem *UAVObjectBrowserWidget::findCurrentObjectTreeItem() { - QModelIndex current = m_browser->treeView->currentIndex(); + QModelIndex current = m_modelProxy->mapToSource(m_browser->treeView->currentIndex()); TreeItem *item = static_cast(current.internalPointer()); ObjectTreeItem *objItem = 0; @@ -196,12 +221,14 @@ void UAVObjectBrowserWidget::saveObject() this->setFocus(); // Send update so that the latest value is saved sendUpdate(); + // Save object ObjectTreeItem *objItem = findCurrentObjectTreeItem(); - Q_ASSERT(objItem); - UAVObject *obj = objItem->object(); - Q_ASSERT(obj); - updateObjectPersistance(ObjectPersistence::OPERATION_SAVE, obj); + if (objItem != NULL) { + UAVObject *obj = objItem->object(); + Q_ASSERT(obj); + updateObjectPersistance(ObjectPersistence::OPERATION_SAVE, obj); + } } void UAVObjectBrowserWidget::loadObject() @@ -209,22 +236,24 @@ void UAVObjectBrowserWidget::loadObject() // Load object ObjectTreeItem *objItem = findCurrentObjectTreeItem(); - Q_ASSERT(objItem); - UAVObject *obj = objItem->object(); - Q_ASSERT(obj); - updateObjectPersistance(ObjectPersistence::OPERATION_LOAD, obj); - // Retrieve object so that latest value is displayed - requestUpdate(); + if (objItem != NULL) { + UAVObject *obj = objItem->object(); + Q_ASSERT(obj); + updateObjectPersistance(ObjectPersistence::OPERATION_LOAD, obj); + // Retrieve object so that latest value is displayed + requestUpdate(); + } } void UAVObjectBrowserWidget::eraseObject() { ObjectTreeItem *objItem = findCurrentObjectTreeItem(); - Q_ASSERT(objItem); - UAVObject *obj = objItem->object(); - Q_ASSERT(obj); - updateObjectPersistance(ObjectPersistence::OPERATION_DELETE, obj); + if (objItem != NULL) { + UAVObject *obj = objItem->object(); + Q_ASSERT(obj); + updateObjectPersistance(ObjectPersistence::OPERATION_DELETE, obj); + } } void UAVObjectBrowserWidget::updateObjectPersistance(ObjectPersistence::OperationOptions op, UAVObject *obj) @@ -248,9 +277,11 @@ void UAVObjectBrowserWidget::currentChanged(const QModelIndex ¤t, const QM { Q_UNUSED(previous); - TreeItem *item = static_cast(current.internalPointer()); - bool enable = true; - if (current == QModelIndex()) { + QModelIndex cindex = m_modelProxy->mapToSource(current); + + TreeItem *item = static_cast(cindex.internalPointer()); + bool enable = true; + if (cindex == QModelIndex()) { enable = false; } TopTreeItem *top = dynamic_cast(item); @@ -388,3 +419,95 @@ void UAVObjectBrowserWidget::updateDescription() } m_browser->descriptionText->setText(""); } + +/** + * @brief UAVObjectBrowserWidget::searchTextChanged Looks for matching text in the UAVO fields + */ + +void UAVObjectBrowserWidget::searchLineChanged(QString searchText) +{ + m_modelProxy->setFilterRegExp(QRegExp(searchText, Qt::CaseInsensitive, QRegExp::FixedString)); + showMetaData(m_viewoptions->cbMetaData->isChecked()); + if (!searchText.isEmpty()) { + m_browser->treeView->expandAll(); + } else { + m_browser->treeView->collapseAll(); + } +} + +void UAVObjectBrowserWidget::searchTextCleared() +{ + m_browser->searchLine->clear(); +} + +TreeSortFilterProxyModel::TreeSortFilterProxyModel(QObject *p) : + QSortFilterProxyModel(p) +{ + Q_ASSERT(p); +} + +/** + * @brief TreeSortFilterProxyModel::filterAcceptsRow Taken from + * http://qt-project.org/forums/viewthread/7782. This proxy model + * will accept rows: + * - That match themselves, or + * - That have a parent that matches (on its own), or + * - That have a child that matches. + * @param sourceRow + * @param sourceParent + * @return + */ +bool TreeSortFilterProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const +{ + if (filterAcceptsRowItself(source_row, source_parent)) { + return true; + } + + // accept if any of the parents is accepted on it's own merits + QModelIndex parent = source_parent; + while (parent.isValid()) { + if (filterAcceptsRowItself(parent.row(), parent.parent())) { + return true; + } + parent = parent.parent(); + } + + // accept if any of the children is accepted on it's own merits + if (hasAcceptedChildren(source_row, source_parent)) { + return true; + } + + return false; +} + +bool TreeSortFilterProxyModel::filterAcceptsRowItself(int source_row, const QModelIndex &source_parent) const +{ + return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent); +} + +bool TreeSortFilterProxyModel::hasAcceptedChildren(int source_row, const QModelIndex &source_parent) const +{ + QModelIndex item = sourceModel()->index(source_row, 0, source_parent); + + if (!item.isValid()) { + return false; + } + + // check if there are children + int childCount = item.model()->rowCount(item); + if (childCount == 0) { + return false; + } + + for (int i = 0; i < childCount; ++i) { + if (filterAcceptsRowItself(i, item)) { + return true; + } + + if (hasAcceptedChildren(i, item)) { + return true; + } + } + + return false; +} diff --git a/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.h b/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.h index 92cb4af3f..fda1609a7 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.h +++ b/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.h @@ -2,7 +2,8 @@ ****************************************************************************** * * @file uavobjectbrowserwidget.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. + * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. * @addtogroup GCSPlugins GCS Plugins * @{ * @addtogroup UAVObjectBrowserPlugin UAVObject Browser Plugin @@ -30,6 +31,8 @@ #include #include +#include +#include #include "objectpersistence.h" #include "uavobjecttreemodel.h" @@ -38,6 +41,16 @@ class ObjectTreeItem; class Ui_UAVObjectBrowser; class Ui_viewoptions; +class TreeSortFilterProxyModel : public QSortFilterProxyModel { +public: + TreeSortFilterProxyModel(QObject *parent); + +protected: + bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const; + bool filterAcceptsRowItself(int source_row, const QModelIndex &source_parent) const; + bool hasAcceptedChildren(int source_row, const QModelIndex &source_parent) const; +}; + class UAVObjectBrowserWidget : public QWidget { Q_OBJECT @@ -87,6 +100,8 @@ private slots: void currentChanged(const QModelIndex ¤t, const QModelIndex &previous); void viewSlot(); void viewOptionsChangedSlot(); + void searchLineChanged(QString searchText); + void searchTextCleared(); void splitterMoved(); QString createObjectDescription(UAVObject *object); signals: @@ -99,6 +114,7 @@ private: Ui_viewoptions *m_viewoptions; QDialog *m_viewoptionsDialog; UAVObjectTreeModel *m_model; + TreeSortFilterProxyModel *m_modelProxy; int m_recentlyUpdatedTimeout; QColor m_unknownObjectColor; @@ -110,6 +126,7 @@ private: void updateObjectPersistance(ObjectPersistence::OperationOptions op, UAVObject *obj); void enableSendRequest(bool enable); void updateDescription(); + void resetProxyModel(UAVObjectTreeModel *currentModel); ObjectTreeItem *findCurrentObjectTreeItem(); QString loadFileIntoString(QString fileName); }; diff --git a/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.h b/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.h index 48466f4fa..687310f40 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.h +++ b/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.h @@ -30,6 +30,7 @@ #include "treeitem.h" #include +#include #include #include #include @@ -127,5 +128,4 @@ private: // Highlight manager to handle highlighting of tree items. HighLightManager *m_highlightManager; }; - #endif // UAVOBJECTTREEMODEL_H