##// END OF EJS Templates
Implements filter function for data source...
Alexandre Leroux -
r477:eab21078feec
parent child
Show More
@@ -1,35 +1,37
1 1 #ifndef SCIQLOP_DATASOURCETREEWIDGETITEM_H
2 2 #define SCIQLOP_DATASOURCETREEWIDGETITEM_H
3 3
4 4 #include <Common/spimpl.h>
5 5
6 6 #include <QLoggingCategory>
7 7 #include <QTreeWidgetItem>
8 8
9 9 Q_DECLARE_LOGGING_CATEGORY(LOG_DataSourceTreeWidgetItem)
10 10
11 11 class DataSourceItem;
12 12
13 13 /**
14 14 * @brief The DataSourceTreeWidgetItem is the graphical representation of a data source item. It is
15 15 * intended to be displayed in a QTreeWidget.
16 16 * @sa DataSourceItem
17 17 */
18 18 class DataSourceTreeWidgetItem : public QTreeWidgetItem {
19 19 public:
20 20 explicit DataSourceTreeWidgetItem(const DataSourceItem *data, int type = Type);
21 21 explicit DataSourceTreeWidgetItem(QTreeWidget *parent, const DataSourceItem *data,
22 22 int type = Type);
23 23
24 const DataSourceItem *data() const;
25
24 26 virtual QVariant data(int column, int role) const override;
25 27 virtual void setData(int column, int role, const QVariant &value) override;
26 28
27 29 /// @return the actions associated to the item
28 30 QList<QAction *> actions() const noexcept;
29 31
30 32 private:
31 33 class DataSourceTreeWidgetItemPrivate;
32 34 spimpl::unique_impl_ptr<DataSourceTreeWidgetItemPrivate> impl;
33 35 };
34 36
35 37 #endif // SCIQLOP_DATASOURCETREEWIDGETITEM_H
@@ -1,171 +1,176
1 1 #include <DataSource/DataSourceItem.h>
2 2 #include <DataSource/DataSourceItemAction.h>
3 3 #include <DataSource/DataSourceTreeWidgetItem.h>
4 4
5 5 #include <QAction>
6 6
7 7 Q_LOGGING_CATEGORY(LOG_DataSourceTreeWidgetItem, "DataSourceTreeWidgetItem")
8 8
9 9 namespace {
10 10
11 11 // Column indexes
12 12 const auto NAME_COLUMN = 0;
13 13
14 14 QIcon itemIcon(const DataSourceItem *dataSource)
15 15 {
16 16 if (dataSource) {
17 17 auto dataSourceType = dataSource->type();
18 18 switch (dataSourceType) {
19 19 case DataSourceItemType::NODE: {
20 20 return dataSource->isRoot() ? QIcon{":/icones/dataSourceRoot.png"}
21 21 : QIcon{":/icones/dataSourceNode.png"};
22 22 }
23 23 case DataSourceItemType::PRODUCT:
24 24 return QIcon{":/icones/dataSourceProduct.png"};
25 25 case DataSourceItemType::COMPONENT:
26 26 return QIcon{":/icones/dataSourceComponent.png"};
27 27 default:
28 28 // No action
29 29 break;
30 30 }
31 31
32 32 qCWarning(LOG_DataSourceTreeWidgetItem())
33 33 << QObject::tr("Can't set data source icon : unknown data source type");
34 34 }
35 35 else {
36 36 qCCritical(LOG_DataSourceTreeWidgetItem())
37 37 << QObject::tr("Can't set data source icon : the data source is null");
38 38 }
39 39
40 40 // Default cases
41 41 return QIcon{};
42 42 }
43 43
44 44 /// @return the tooltip text for a variant. The text depends on whether the data is a simple variant
45 45 /// or a list of variants
46 46 QString tooltipValue(const QVariant &variant) noexcept
47 47 {
48 48 // If the variant is a list of variants, the text of the tooltip is of the form: {val1, val2,
49 49 // ...}
50 50 if (variant.canConvert<QVariantList>()) {
51 51 auto valueString = QStringLiteral("{");
52 52
53 53 auto variantList = variant.value<QVariantList>();
54 54 for (auto it = variantList.cbegin(), end = variantList.cend(); it != end; ++it) {
55 55 valueString.append(it->toString());
56 56
57 57 if (std::distance(it, end) != 1) {
58 58 valueString.append(", ");
59 59 }
60 60 }
61 61
62 62 valueString.append(QStringLiteral("}"));
63 63
64 64 return valueString;
65 65 }
66 66 else {
67 67 return variant.toString();
68 68 }
69 69 }
70 70
71 71 QString itemTooltip(const DataSourceItem *dataSource) noexcept
72 72 {
73 73 // The tooltip displays all item's data
74 74 if (dataSource) {
75 75 auto result = QString{};
76 76
77 77 const auto &data = dataSource->data();
78 78 for (auto it = data.cbegin(), end = data.cend(); it != end; ++it) {
79 79 result.append(QString{"<b>%1:</b> %2<br/>"}.arg(it.key(), tooltipValue(it.value())));
80 80 }
81 81
82 82 return result;
83 83 }
84 84 else {
85 85 qCCritical(LOG_DataSourceTreeWidgetItem())
86 86 << QObject::tr("Can't set data source tooltip : the data source is null");
87 87
88 88 return QString{};
89 89 }
90 90 }
91 91
92 92 } // namespace
93 93
94 94 struct DataSourceTreeWidgetItem::DataSourceTreeWidgetItemPrivate {
95 95 explicit DataSourceTreeWidgetItemPrivate(const DataSourceItem *data) : m_Data{data} {}
96 96
97 97 /// Model used to retrieve data source information
98 98 const DataSourceItem *m_Data;
99 99 /// Actions associated to the item. The parent of the item (QTreeWidget) takes the ownership of
100 100 /// the actions
101 101 QList<QAction *> m_Actions;
102 102 };
103 103
104 104 DataSourceTreeWidgetItem::DataSourceTreeWidgetItem(const DataSourceItem *data, int type)
105 105 : DataSourceTreeWidgetItem{nullptr, data, type}
106 106 {
107 107 }
108 108
109 109 DataSourceTreeWidgetItem::DataSourceTreeWidgetItem(QTreeWidget *parent, const DataSourceItem *data,
110 110 int type)
111 111 : QTreeWidgetItem{parent, type},
112 112 impl{spimpl::make_unique_impl<DataSourceTreeWidgetItemPrivate>(data)}
113 113 {
114 114 // Sets the icon and the tooltip depending on the data source
115 115 setIcon(0, itemIcon(impl->m_Data));
116 116 setToolTip(0, itemTooltip(impl->m_Data));
117 117
118 118 // Generates tree actions based on the item actions
119 119 auto createTreeAction = [this, &parent](const auto &itemAction) {
120 120 auto treeAction = new QAction{itemAction->name(), parent};
121 121
122 122 // Executes item action when tree action is triggered
123 123 QObject::connect(treeAction, &QAction::triggered, itemAction,
124 124 &DataSourceItemAction::execute);
125 125
126 126 return treeAction;
127 127 };
128 128
129 129 auto itemActions = impl->m_Data->actions();
130 130 std::transform(std::cbegin(itemActions), std::cend(itemActions),
131 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 139 QVariant DataSourceTreeWidgetItem::data(int column, int role) const
135 140 {
136 141 if (role == Qt::DisplayRole) {
137 142 if (impl->m_Data) {
138 143 switch (column) {
139 144 case NAME_COLUMN:
140 145 return impl->m_Data->name();
141 146 default:
142 147 // No action
143 148 break;
144 149 }
145 150
146 151 qCWarning(LOG_DataSourceTreeWidgetItem())
147 152 << QObject::tr("Can't get data (unknown column %1)").arg(column);
148 153 }
149 154 else {
150 155 qCCritical(LOG_DataSourceTreeWidgetItem()) << QObject::tr("Can't get data (null item)");
151 156 }
152 157
153 158 return QVariant{};
154 159 }
155 160 else {
156 161 return QTreeWidgetItem::data(column, role);
157 162 }
158 163 }
159 164
160 165 void DataSourceTreeWidgetItem::setData(int column, int role, const QVariant &value)
161 166 {
162 167 // Data can't be changed by edition
163 168 if (role != Qt::EditRole) {
164 169 QTreeWidgetItem::setData(column, role, value);
165 170 }
166 171 }
167 172
168 173 QList<QAction *> DataSourceTreeWidgetItem::actions() const noexcept
169 174 {
170 175 return impl->m_Actions;
171 176 }
@@ -1,84 +1,100
1 1 #include <DataSource/DataSourceWidget.h>
2 2
3 3 #include <ui_DataSourceWidget.h>
4 4
5 5 #include <DataSource/DataSourceItem.h>
6 #include <DataSource/DataSourceTreeWidgetHelper.h>
6 7 #include <DataSource/DataSourceTreeWidgetItem.h>
7 8
8 9 #include <QMenu>
9 10
10 11 namespace {
11 12
12 13 /// Number of columns displayed in the tree
13 14 const auto TREE_NB_COLUMNS = 1;
14 15
15 16 /// Header labels for the tree
16 17 const auto TREE_HEADER_LABELS = QStringList{QObject::tr("Name")};
17 18
18 19 /**
19 20 * Creates the item associated to a data source
20 21 * @param dataSource the data source for which to create the item
21 22 * @return the new item
22 23 */
23 24 DataSourceTreeWidgetItem *createTreeWidgetItem(DataSourceItem *dataSource)
24 25 {
25 26 // Creates item for the data source
26 27 auto item = new DataSourceTreeWidgetItem{dataSource};
27 28
28 29 // Generates items for the children of the data source
29 30 for (auto i = 0; i < dataSource->childCount(); ++i) {
30 31 item->addChild(createTreeWidgetItem(dataSource->child(i)));
31 32 }
32 33
33 34 return item;
34 35 }
35 36
36 37 } // namespace
37 38
38 39 DataSourceWidget::DataSourceWidget(QWidget *parent) : QWidget{parent}, ui{new Ui::DataSourceWidget}
39 40 {
40 41 ui->setupUi(this);
41 42
42 43 // Set tree properties
43 44 ui->treeWidget->setColumnCount(TREE_NB_COLUMNS);
44 45 ui->treeWidget->setHeaderLabels(TREE_HEADER_LABELS);
45 46 ui->treeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
46 47
47 48 // Connection to show a menu when right clicking on the tree
48 49 connect(ui->treeWidget, &QTreeWidget::customContextMenuRequested, this,
49 50 &DataSourceWidget::onTreeMenuRequested);
50 51
51 52 // Connection to filter tree
52 53 connect(ui->filterLineEdit, &QLineEdit::textChanged, this, &DataSourceWidget::filterChanged);
53 54 }
54 55
55 56 DataSourceWidget::~DataSourceWidget() noexcept
56 57 {
57 58 delete ui;
58 59 }
59 60
60 61 void DataSourceWidget::addDataSource(DataSourceItem *dataSource) noexcept
61 62 {
62 63 // Creates the item associated to the source and adds it to the tree widget. The tree widget
63 64 // takes the ownership of the item
64 65 if (dataSource) {
65 66 ui->treeWidget->addTopLevelItem(createTreeWidgetItem(dataSource));
66 67 }
67 68 }
68 69
69 70 void DataSourceWidget::filterChanged(const QString &text) noexcept
70 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 = [&regExp](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);
71 87 }
72 88
73 89 void DataSourceWidget::onTreeMenuRequested(const QPoint &pos) noexcept
74 90 {
75 91 // Retrieves the selected item in the tree, and build the menu from its actions
76 92 if (auto selectedItem = dynamic_cast<DataSourceTreeWidgetItem *>(ui->treeWidget->itemAt(pos))) {
77 93 QMenu treeMenu{};
78 94 treeMenu.addActions(selectedItem->actions());
79 95
80 96 if (!treeMenu.isEmpty()) {
81 97 treeMenu.exec(mapToGlobal(pos));
82 98 }
83 99 }
84 100 }
General Comments 0
You need to be logged in to leave comments. Login now