@@ -0,0 +1,23 | |||||
|
1 | #ifndef SCIQLOP_DATASOURCETREEWIDGETHELPER_H | |||
|
2 | #define SCIQLOP_DATASOURCETREEWIDGETHELPER_H | |||
|
3 | ||||
|
4 | #include <functional> | |||
|
5 | ||||
|
6 | class DataSourceTreeWidgetItem; | |||
|
7 | class QTreeWidget; | |||
|
8 | ||||
|
9 | class DataSourceTreeWidgetHelper { | |||
|
10 | public: | |||
|
11 | /// Signature of the function associated to the filtering action | |||
|
12 | using FilterFunction = std::function<bool(const DataSourceTreeWidgetItem &dataSourceItem)>; | |||
|
13 | ||||
|
14 | /** | |||
|
15 | * Filters a tree widget according to a function. If an item is valid according to this | |||
|
16 | * function, all of its ancestors and children are shown | |||
|
17 | * @param treeWidget the widget to filter | |||
|
18 | * @param fun the filter function | |||
|
19 | */ | |||
|
20 | static void filter(QTreeWidget &treeWidget, FilterFunction fun) noexcept; | |||
|
21 | }; | |||
|
22 | ||||
|
23 | #endif // SCIQLOP_DATASOURCETREEWIDGETHELPER_H |
@@ -0,0 +1,36 | |||||
|
1 | #include "DataSource/DataSourceTreeWidgetHelper.h" | |||
|
2 | #include "DataSource/DataSourceTreeWidgetItem.h" | |||
|
3 | ||||
|
4 | namespace { | |||
|
5 | ||||
|
6 | bool filterTreeItem(DataSourceTreeWidgetItem &treeItem, | |||
|
7 | DataSourceTreeWidgetHelper::FilterFunction fun, bool parentValid = false) | |||
|
8 | { | |||
|
9 | auto selfValid = parentValid || fun(treeItem); | |||
|
10 | ||||
|
11 | auto childValid = false; | |||
|
12 | auto childCount = treeItem.childCount(); | |||
|
13 | for (auto i = 0; i < childCount; ++i) { | |||
|
14 | if (auto childItem = dynamic_cast<DataSourceTreeWidgetItem *>(treeItem.child(i))) { | |||
|
15 | childValid |= filterTreeItem(*childItem, fun, selfValid); | |||
|
16 | } | |||
|
17 | } | |||
|
18 | ||||
|
19 | auto valid = selfValid || childValid; | |||
|
20 | ||||
|
21 | treeItem.setHidden(!valid); | |||
|
22 | ||||
|
23 | return valid; | |||
|
24 | } | |||
|
25 | ||||
|
26 | } // namespace | |||
|
27 | ||||
|
28 | void DataSourceTreeWidgetHelper::filter(QTreeWidget &treeWidget, FilterFunction fun) noexcept | |||
|
29 | { | |||
|
30 | auto itemCount = treeWidget.topLevelItemCount(); | |||
|
31 | for (auto i = 0; i < itemCount; ++i) { | |||
|
32 | if (auto item = dynamic_cast<DataSourceTreeWidgetItem *>(treeWidget.topLevelItem(i))) { | |||
|
33 | filterTreeItem(*item, fun); | |||
|
34 | } | |||
|
35 | } | |||
|
36 | } |
@@ -21,6 +21,8 public: | |||||
21 | explicit DataSourceTreeWidgetItem(QTreeWidget *parent, const DataSourceItem *data, |
|
21 | explicit DataSourceTreeWidgetItem(QTreeWidget *parent, const DataSourceItem *data, | |
22 | int type = Type); |
|
22 | int type = Type); | |
23 |
|
23 | |||
|
24 | const DataSourceItem *data() const; | |||
|
25 | ||||
24 | virtual QVariant data(int column, int role) const override; |
|
26 | virtual QVariant data(int column, int role) const override; | |
25 | virtual void setData(int column, int role, const QVariant &value) override; |
|
27 | virtual void setData(int column, int role, const QVariant &value) override; | |
26 |
|
28 |
@@ -32,6 +32,9 private: | |||||
32 | Ui::DataSourceWidget *ui; |
|
32 | Ui::DataSourceWidget *ui; | |
33 |
|
33 | |||
34 | private slots: |
|
34 | private slots: | |
|
35 | /// Slot called when the filtering text has changed | |||
|
36 | void filterChanged(const QString &text) noexcept; | |||
|
37 | ||||
35 | /// Slot called when right clicking on an item in the tree (displays a menu) |
|
38 | /// Slot called when right clicking on an item in the tree (displays a menu) | |
36 | void onTreeMenuRequested(const QPoint &pos) noexcept; |
|
39 | void onTreeMenuRequested(const QPoint &pos) noexcept; | |
37 | }; |
|
40 | }; |
@@ -131,6 +131,11 DataSourceTreeWidgetItem::DataSourceTreeWidgetItem(QTreeWidget *parent, const Da | |||||
131 | std::back_inserter(impl->m_Actions), createTreeAction); |
|
131 | std::back_inserter(impl->m_Actions), createTreeAction); | |
132 | } |
|
132 | } | |
133 |
|
133 | |||
|
134 | const DataSourceItem *DataSourceTreeWidgetItem::data() const | |||
|
135 | { | |||
|
136 | return impl->m_Data; | |||
|
137 | } | |||
|
138 | ||||
134 | QVariant DataSourceTreeWidgetItem::data(int column, int role) const |
|
139 | QVariant DataSourceTreeWidgetItem::data(int column, int role) const | |
135 | { |
|
140 | { | |
136 | if (role == Qt::DisplayRole) { |
|
141 | if (role == Qt::DisplayRole) { |
@@ -3,6 +3,7 | |||||
3 | #include <ui_DataSourceWidget.h> |
|
3 | #include <ui_DataSourceWidget.h> | |
4 |
|
4 | |||
5 | #include <DataSource/DataSourceItem.h> |
|
5 | #include <DataSource/DataSourceItem.h> | |
|
6 | #include <DataSource/DataSourceTreeWidgetHelper.h> | |||
6 | #include <DataSource/DataSourceTreeWidgetItem.h> |
|
7 | #include <DataSource/DataSourceTreeWidgetItem.h> | |
7 |
|
8 | |||
8 | #include <QMenu> |
|
9 | #include <QMenu> | |
@@ -47,6 +48,9 DataSourceWidget::DataSourceWidget(QWidget *parent) : QWidget{parent}, ui{new Ui | |||||
47 | // Connection to show a menu when right clicking on the tree |
|
48 | // Connection to show a menu when right clicking on the tree | |
48 | connect(ui->treeWidget, &QTreeWidget::customContextMenuRequested, this, |
|
49 | connect(ui->treeWidget, &QTreeWidget::customContextMenuRequested, this, | |
49 | &DataSourceWidget::onTreeMenuRequested); |
|
50 | &DataSourceWidget::onTreeMenuRequested); | |
|
51 | ||||
|
52 | // Connection to filter tree | |||
|
53 | connect(ui->filterLineEdit, &QLineEdit::textChanged, this, &DataSourceWidget::filterChanged); | |||
50 | } |
|
54 | } | |
51 |
|
55 | |||
52 | DataSourceWidget::~DataSourceWidget() noexcept |
|
56 | DataSourceWidget::~DataSourceWidget() noexcept | |
@@ -63,6 +67,25 void DataSourceWidget::addDataSource(DataSourceItem *dataSource) noexcept | |||||
63 | } |
|
67 | } | |
64 | } |
|
68 | } | |
65 |
|
69 | |||
|
70 | void DataSourceWidget::filterChanged(const QString &text) noexcept | |||
|
71 | { | |||
|
72 | auto validateItem = [&text](const DataSourceTreeWidgetItem &item) { | |||
|
73 | auto regExp = QRegExp{text, Qt::CaseInsensitive, QRegExp::Wildcard}; | |||
|
74 | ||||
|
75 | // An item is valid if any of its metadata validates the text filter | |||
|
76 | auto itemMetadata = item.data()->data(); | |||
|
77 | auto itemMetadataEnd = itemMetadata.cend(); | |||
|
78 | auto acceptFilter | |||
|
79 | = [®Exp](const auto &variant) { return variant.toString().contains(regExp); }; | |||
|
80 | ||||
|
81 | return std::find_if(itemMetadata.cbegin(), itemMetadataEnd, acceptFilter) | |||
|
82 | != itemMetadataEnd; | |||
|
83 | }; | |||
|
84 | ||||
|
85 | // Applies filter on tree widget | |||
|
86 | DataSourceTreeWidgetHelper::filter(*ui->treeWidget, validateItem); | |||
|
87 | } | |||
|
88 | ||||
66 | void DataSourceWidget::onTreeMenuRequested(const QPoint &pos) noexcept |
|
89 | void DataSourceWidget::onTreeMenuRequested(const QPoint &pos) noexcept | |
67 | { |
|
90 | { | |
68 | // Retrieves the selected item in the tree, and build the menu from its actions |
|
91 | // Retrieves the selected item in the tree, and build the menu from its actions |
@@ -14,19 +14,10 | |||||
14 | <string>Data sources</string> |
|
14 | <string>Data sources</string> | |
15 | </property> |
|
15 | </property> | |
16 | <layout class="QGridLayout" name="gridLayout"> |
|
16 | <layout class="QGridLayout" name="gridLayout"> | |
17 | <property name="topMargin"> |
|
|||
18 | <number>0</number> |
|
|||
19 | </property> |
|
|||
20 | <property name="rightMargin"> |
|
|||
21 | <number>0</number> |
|
|||
22 | </property> |
|
|||
23 | <property name="bottomMargin"> |
|
|||
24 | <number>0</number> |
|
|||
25 | </property> |
|
|||
26 | <property name="spacing"> |
|
|||
27 | <number>0</number> |
|
|||
28 | </property> |
|
|||
29 | <item row="0" column="0"> |
|
17 | <item row="0" column="0"> | |
|
18 | <widget class="QLineEdit" name="filterLineEdit"/> | |||
|
19 | </item> | |||
|
20 | <item row="1" column="0"> | |||
30 | <widget class="QTreeWidget" name="treeWidget"> |
|
21 | <widget class="QTreeWidget" name="treeWidget"> | |
31 | <column> |
|
22 | <column> | |
32 | <property name="text"> |
|
23 | <property name="text"> |
General Comments 0
You need to be logged in to leave comments.
Login now