##// END OF EJS Templates
Merge branch 'feature/MergeDataSourceItem' into develop
Alexandre Leroux -
r1042:a949d016326d merge
parent child
Show More
@@ -0,0 +1,15
1 #ifndef SCIQLOP_DATASOURCEITEMMERGEHELPER_H
2 #define SCIQLOP_DATASOURCEITEMMERGEHELPER_H
3
4 class DataSourceItem;
5
6 /**
7 * @brief The DataSourceItemMergeHelper struct is used to merge two data source items
8 * @sa DataSourceItem::merge()
9 */
10 struct DataSourceItemMergeHelper {
11 /// Merges source item into dest item
12 static void merge(const DataSourceItem &source, DataSourceItem &dest);
13 };
14
15 #endif // SCIQLOP_DATASOURCEITEMMERGEHELPER_H
@@ -0,0 +1,55
1 #include "DataSource/DataSourceItemMergeHelper.h"
2
3 #include <DataSource/DataSourceItem.h>
4
5 namespace {
6
7 /**
8 * Finds in a tree an item similar to the item passed in parameter
9 * @param item the item for which to find a similar item
10 * @param root the root item of the tree
11 * @return the similar item if found, nullptr otherwise
12 */
13 DataSourceItem *findSimilarItem(const DataSourceItem &item, const DataSourceItem &root)
14 {
15 // An item is considered similar to the another item if:
16 // - the items are both nodes AND
17 // - the names of the items are identical
18
19 if (item.type() != DataSourceItemType::NODE) {
20 return nullptr;
21 }
22
23 DataSourceItem *result{nullptr};
24 bool found{false};
25 for (auto i = 0, count = root.childCount(); i < count && !found; ++i) {
26 auto child = root.child(i);
27
28 found = child->type() == DataSourceItemType::NODE
29 && QString::compare(child->name(), item.name(), Qt::CaseInsensitive) == 0;
30 if (found) {
31 result = child;
32 }
33 }
34
35 return result;
36 }
37
38 } // namespace
39
40 void DataSourceItemMergeHelper::merge(const DataSourceItem &source, DataSourceItem &dest)
41 {
42 // Checks if the source item can be merged into the destination item (i.e. there is a child item
43 // similar to the source item)
44 if (auto subItem = findSimilarItem(source, dest)) {
45 // If there is an item similar to the source item, applies the merge recursively
46 for (auto i = 0, count = source.childCount(); i < count; ++i) {
47 merge(*source.child(i), *subItem);
48 }
49 }
50 else {
51 // If no item is similar to the source item, the item is copied as the child of the
52 // destination item
53 dest.appendChild(source.clone());
54 }
55 }
@@ -0,0 +1,73
1 #include "DataSourceItemBuilder.h"
2
3 DataSourceItemBuilder &DataSourceItemBuilder::root(const QString &name)
4 {
5 m_Root = std::make_shared<DataSourceItem>(DataSourceItemType::NODE, name);
6 m_Items.push(m_Root.get());
7 return *this;
8 }
9
10 DataSourceItemBuilder &DataSourceItemBuilder::root(QVariantHash data)
11 {
12 m_Root = std::make_shared<DataSourceItem>(DataSourceItemType::NODE, data);
13 m_Items.push(m_Root.get());
14 return *this;
15 }
16
17 DataSourceItemBuilder &DataSourceItemBuilder::node(const QString &name)
18 {
19 return append(DataSourceItemType::NODE, name);
20 }
21
22 DataSourceItemBuilder &DataSourceItemBuilder::node(QVariantHash data)
23 {
24 return append(DataSourceItemType::NODE, std::move(data));
25 }
26
27 DataSourceItemBuilder &DataSourceItemBuilder::product(const QString &name)
28 {
29 return append(DataSourceItemType::PRODUCT, name);
30 }
31
32 DataSourceItemBuilder &DataSourceItemBuilder::product(QVariantHash data)
33 {
34 return append(DataSourceItemType::PRODUCT, std::move(data));
35 }
36
37 DataSourceItemBuilder &DataSourceItemBuilder::component(const QString &name)
38 {
39 return append(DataSourceItemType::COMPONENT, name);
40 }
41
42 DataSourceItemBuilder &DataSourceItemBuilder::component(QVariantHash data)
43 {
44 return append(DataSourceItemType::COMPONENT, std::move(data));
45 }
46
47 DataSourceItemBuilder &DataSourceItemBuilder::end()
48 {
49 m_Items.pop();
50 return *this;
51 }
52
53 std::shared_ptr<DataSourceItem> DataSourceItemBuilder::build()
54 {
55 return m_Root;
56 }
57
58 DataSourceItemBuilder &DataSourceItemBuilder::append(DataSourceItemType type, const QString &name)
59 {
60 append(type, QVariantHash{{DataSourceItem::NAME_DATA_KEY, name}});
61 return *this;
62 }
63
64 DataSourceItemBuilder &DataSourceItemBuilder::append(DataSourceItemType type, QVariantHash data)
65 {
66 auto parentItem = m_Items.top();
67
68 auto insertIndex = parentItem->childCount();
69 parentItem->appendChild(std::make_unique<DataSourceItem>(type, std::move(data)));
70
71 m_Items.push(parentItem->child(insertIndex));
72 return *this;
73 }
@@ -0,0 +1,45
1 #ifndef SCIQLOP_DATASOURCEITEMBUILDER_H
2 #define SCIQLOP_DATASOURCEITEMBUILDER_H
3
4 #include <DataSource/DataSourceItem.h>
5
6 #include <memory>
7 #include <stack>
8
9 /**
10 * @brief The DataSourceItemBuilder class aims to facilitate the creation of a DataSourceItem for unit tests
11 * @sa DataSourceItem
12 */
13 class DataSourceItemBuilder {
14 public:
15 /// Inits root item
16 DataSourceItemBuilder & root(const QString &name);
17 DataSourceItemBuilder & root(QVariantHash data);
18
19 /// Adds node into the current item
20 DataSourceItemBuilder & node(const QString &name);
21 DataSourceItemBuilder & node(QVariantHash data);
22
23 /// Adds product into the current item
24 DataSourceItemBuilder & product(const QString &name);
25 DataSourceItemBuilder & product(QVariantHash data);
26
27 /// Adds component into the current item
28 DataSourceItemBuilder & component(const QString &name);
29 DataSourceItemBuilder & component(QVariantHash data);
30
31 /// Closes the build of the current item
32 DataSourceItemBuilder& end();
33
34 /// Creates the DataSourceItem
35 std::shared_ptr<DataSourceItem> build();
36
37 private:
38 DataSourceItemBuilder& append(DataSourceItemType type, const QString &name);
39 DataSourceItemBuilder& append(DataSourceItemType type, QVariantHash data);
40
41 std::shared_ptr<DataSourceItem> m_Root{nullptr};
42 std::stack<DataSourceItem*> m_Items;
43 };
44
45 #endif // SCIQLOP_DATASOURCEITEMBUILDER_H
@@ -0,0 +1,207
1 #include <DataSource/DataSourceItem.h>
2
3 #include "DataSourceItemBuilder.h"
4
5 #include <QObject>
6 #include <QtTest>
7
8 #include <iostream>
9
10 namespace {
11
12 void printItem(std::ostream &out, const DataSourceItem &item, int level = 0)
13 {
14 for (auto i = 0; i < level; ++i) {
15 out << " ";
16 }
17
18 out << item.name().toStdString() << "\n";
19
20 for (auto i = 0, count = item.childCount(); i < count; ++i) {
21 printItem(out, *item.child(i), level + 1);
22 }
23 }
24
25 std::ostream &operator<<(std::ostream &out, const DataSourceItem &item)
26 {
27 printItem(out, item, 0);
28 return out;
29 }
30
31 } // namespace
32
33 Q_DECLARE_METATYPE(std::shared_ptr<DataSourceItem>)
34
35 class TestDataSourceItem : public QObject {
36 Q_OBJECT
37 private slots:
38 void testMerge_data();
39 void testMerge();
40 };
41
42 void TestDataSourceItem::testMerge_data()
43 {
44 QTest::addColumn<std::shared_ptr<DataSourceItem> >("source");
45 QTest::addColumn<std::shared_ptr<DataSourceItem> >("dest");
46 QTest::addColumn<std::shared_ptr<DataSourceItem> >("expectedResult");
47
48 QTest::newRow("merge (basic case)") << DataSourceItemBuilder{}
49 .root("A2")
50 .node("- B2")
51 .product("-- P2")
52 .end() // P2
53 .end() // B2
54 .end() // A2
55 .build()
56 << DataSourceItemBuilder{}
57 .root("A1")
58 .node("- B1")
59 .product("-- P1")
60 .end() // P1
61 .end() // B1
62 .end() // A1
63 .build()
64 << DataSourceItemBuilder{}
65 .root("A1")
66 .node("- B1")
67 .product("-- P1")
68 .end() // P1
69 .end() // B1
70 .node("- B2")
71 .product("-- P2")
72 .end() // P2
73 .end() // B2
74 .end() // A1
75 .build();
76
77 QTest::newRow("merge (some of the source and destination trees are identical)")
78 << DataSourceItemBuilder{}
79 .root("A2")
80 .node("- B1")
81 .node("-- C1")
82 .product("--- P2")
83 .end() // P2
84 .end() // C1
85 .node("-- C2")
86 .end() // C2
87 .end() // B1
88 .end() // A2
89 .build()
90 << DataSourceItemBuilder{}
91 .root("A1")
92 .node("- B1")
93 .node("-- C1")
94 .product("--- P1")
95 .end() // P1
96 .end() // C1
97 .end() // B1
98 .end() // A1
99 .build()
100 << DataSourceItemBuilder{}
101 .root("A1")
102 .node("- B1")
103 .node("-- C1")
104 .product("--- P1")
105 .end() // P1
106 .product("--- P2")
107 .end() // P2
108 .end() // C1
109 .node("-- C2")
110 .end() // C2
111 .end() // B1
112 .end() // A1
113 .build();
114
115 QTest::newRow("merge (products with the same name and tree are kept)")
116 << DataSourceItemBuilder{}
117 .root("A2")
118 .node("- B1")
119 .node("-- C1")
120 .product({{"name", "--- P1"}, {"from", "source"}})
121 .end() // P1
122 .end() // C1
123 .end() // B1
124 .end() // A2
125 .build()
126 << DataSourceItemBuilder{}
127 .root("A1")
128 .node("- B1")
129 .node("-- C1")
130 .product({{"name", "--- P1"}, {"from", "dest"}})
131 .end() // P1
132 .end() // C1
133 .end() // B1
134 .end() // A1
135 .build()
136 << DataSourceItemBuilder{}
137 .root("A1")
138 .node("- B1")
139 .node("-- C1")
140 .product({{"name", "--- P1"}, {"from", "dest"}})
141 .end() // P1 (dest)
142 .product({{"name", "--- P1"}, {"from", "source"}})
143 .end() // P1 (source)
144 .end() // C1
145 .end() // B1
146 .end() // A1
147 .build();
148
149 QTest::newRow("merge (for same nodes, metadata of dest node are kept)")
150 << DataSourceItemBuilder{}
151 .root("A2")
152 .node("- B1")
153 .node({{"name", "-- C1"}, {"from", "source"}})
154 .product("--- P2")
155 .end() // P1
156 .end() // C1
157 .end() // B1
158 .end() // A2
159 .build()
160 << DataSourceItemBuilder{}
161 .root("A1")
162 .node("- B1")
163 .node({{"name", "-- C1"}, {"from", "dest"}})
164 .product("--- P1")
165 .end() // P1
166 .end() // C1
167 .end() // B1
168 .end() // A1
169 .build()
170 << DataSourceItemBuilder{}
171 .root("A1")
172 .node("- B1")
173 .node({{"name", "-- C1"}, {"from", "dest"}})
174 .product("--- P1")
175 .end() // P1
176 .product("--- P2")
177 .end() // P2
178 .end() // C1 (dest)
179 .end() // B1
180 .end() // A1
181 .build();
182 }
183
184 void TestDataSourceItem::testMerge()
185 {
186 QFETCH(std::shared_ptr<DataSourceItem>, source);
187 QFETCH(std::shared_ptr<DataSourceItem>, dest);
188 QFETCH(std::shared_ptr<DataSourceItem>, expectedResult);
189
190 // Uncomment to print trees
191 // std::cout << "source: \n" << *source << "\n";
192 // std::cout << "dest: \n" << *dest << "\n";
193
194 // Merges source in dest (not taking source root)
195 for (auto i = 0, count = source->childCount(); i < count; ++i) {
196 dest->merge(*source->child(i));
197 }
198
199 // Uncomment to print trees
200 // std::cout << "dest after merge: \n" << *dest << "\n";
201
202 // Checks merge result
203 QVERIFY(*dest == *expectedResult);
204 }
205
206 QTEST_MAIN(TestDataSourceItem)
207 #include "TestDataSourceItem.moc"
@@ -112,7 +112,13
112 <widget class="QWidget" name="commonPropertyInspectorWidget" native="true"/>
112 <widget class="QWidget" name="commonPropertyInspectorWidget" native="true"/>
113 </item>
113 </item>
114 <item>
114 <item>
115 <widget class="DataSourceWidget" name="catalogWidget" native="true"/>
115 <widget class="QTreeWidget" name="catalogWidget">
116 <column>
117 <property name="text">
118 <string notr="true">Name</string>
119 </property>
120 </column>
121 </widget>
116 </item>
122 </item>
117 </layout>
123 </layout>
118 </widget>
124 </widget>
@@ -25,10 +25,14 class SCIQLOP_CORE_EXPORT DataSourceItem {
25 public:
25 public:
26 /// Key associated with the name of the item
26 /// Key associated with the name of the item
27 static const QString NAME_DATA_KEY;
27 static const QString NAME_DATA_KEY;
28 /// Key associated with the plugin of the item
29 static const QString PLUGIN_DATA_KEY;
28
30
29 explicit DataSourceItem(DataSourceItemType type, const QString &name);
31 explicit DataSourceItem(DataSourceItemType type, const QString &name);
30 explicit DataSourceItem(DataSourceItemType type, QVariantHash data = {});
32 explicit DataSourceItem(DataSourceItemType type, QVariantHash data = {});
31
33
34 std::unique_ptr<DataSourceItem> clone() const;
35
32 /// @return the actions of the item as a vector
36 /// @return the actions of the item as a vector
33 QVector<DataSourceItemAction *> actions() const noexcept;
37 QVector<DataSourceItemAction *> actions() const noexcept;
34
38
@@ -64,6 +68,46 public:
64 /// Gets all data
68 /// Gets all data
65 QVariantHash data() const noexcept;
69 QVariantHash data() const noexcept;
66
70
71 /**
72 * Merge in the item the source item passed as parameter.
73 *
74 * The merge is done by adding as child of the item the complete tree represented by the source
75 * item. If a part of the tree already exists in the item (based on the name of the nodes), it
76 * is merged by completing the existing tree by items "leaves" (products, components or nodes
77 * with no child).
78 *
79 * For example, with item representing the tree:
80 * R (root node)
81 * - N1 (node)
82 * -- N11 (node)
83 * --- P1 (product)
84 * --- P2 (product)
85 * - N2 (node)
86 *
87 * and the source item representing the tree:
88 * N1 (root node)
89 * - N11 (node)
90 * -- P3 (product)
91 * - N12 (node)
92 *
93 * The leaves of the source item to merge into the item are N1/N11/P3 and N1/N12 => we therefore
94 * have the following merge result:
95 * R
96 * - N1
97 * -- N11
98 * --- P1
99 * --- P2
100 * --- P3 (added leaf)
101 * -- N12 (added leaf)
102 *
103 * @param item the source item
104 * @remarks No control is performed on products or components that are merged into the same tree
105 * part (two products or components may have the same name)
106 * @remarks the merge is made by copy (source item is not changed and still exists after the
107 * operation)
108 */
109 void merge(const DataSourceItem &item);
110
67 bool isRoot() const noexcept;
111 bool isRoot() const noexcept;
68
112
69 QString name() const noexcept;
113 QString name() const noexcept;
@@ -35,6 +35,8 public:
35 */
35 */
36 explicit DataSourceItemAction(const QString &name, ExecuteFunction fun);
36 explicit DataSourceItemAction(const QString &name, ExecuteFunction fun);
37
37
38 std::unique_ptr<DataSourceItemAction> clone() const;
39
38 QString name() const noexcept;
40 QString name() const noexcept;
39
41
40 /// Sets the data source item concerned by the action
42 /// Sets the data source item concerned by the action
@@ -31,6 +31,7 core_sources = [
31 'src/DataSource/DataSourceController.cpp',
31 'src/DataSource/DataSourceController.cpp',
32 'src/DataSource/DataSourceItem.cpp',
32 'src/DataSource/DataSourceItem.cpp',
33 'src/DataSource/DataSourceItemAction.cpp',
33 'src/DataSource/DataSourceItemAction.cpp',
34 'src/DataSource/DataSourceItemMergeHelper.cpp',
34 'src/Network/NetworkController.cpp',
35 'src/Network/NetworkController.cpp',
35 'src/Plugin/PluginManager.cpp',
36 'src/Plugin/PluginManager.cpp',
36 'src/Settings/SqpSettingsDefs.cpp',
37 'src/Settings/SqpSettingsDefs.cpp',
@@ -12,28 +12,6
12
12
13 Q_LOGGING_CATEGORY(LOG_DataSourceController, "DataSourceController")
13 Q_LOGGING_CATEGORY(LOG_DataSourceController, "DataSourceController")
14
14
15 namespace {
16
17 /**
18 * Builds the metadata of the variable that will be generated from the loading of an item
19 * @param dataSourceItem the data source item from which to generate the metadata
20 * @return the metadata of the variable
21 */
22 QVariantHash variableMetadata(const DataSourceItem &dataSourceItem)
23 {
24 // Variable metadata contains...
25
26 // ... all metadata of the item
27 auto result = dataSourceItem.data();
28
29 // ... and the name of the plugin, recovered from root item
30 result.insert(QStringLiteral("plugin"), dataSourceItem.rootItem().name());
31
32 return result;
33 }
34
35 } // namespace
36
37 class DataSourceController::DataSourceControllerPrivate {
15 class DataSourceController::DataSourceControllerPrivate {
38 public:
16 public:
39 QMutex m_WorkingMutex;
17 QMutex m_WorkingMutex;
@@ -131,8 +109,7 void DataSourceController::loadProductItem(const QUuid &dataSourceUid,
131 auto it = impl->m_DataProviders.find(dataSourceUid);
109 auto it = impl->m_DataProviders.find(dataSourceUid);
132 auto dataProvider = (it != impl->m_DataProviders.end()) ? it->second : nullptr;
110 auto dataProvider = (it != impl->m_DataProviders.end()) ? it->second : nullptr;
133
111
134 emit variableCreationRequested(productItem.name(), variableMetadata(productItem),
112 emit variableCreationRequested(productItem.name(), productItem.data(), dataProvider);
135 dataProvider);
136 }
113 }
137 else {
114 else {
138 qCWarning(LOG_DataSourceController()) << tr("Can't load an item that is not a product");
115 qCWarning(LOG_DataSourceController()) << tr("Can't load an item that is not a product");
@@ -1,9 +1,11
1 #include <DataSource/DataSourceItem.h>
1 #include <DataSource/DataSourceItem.h>
2 #include <DataSource/DataSourceItemAction.h>
2 #include <DataSource/DataSourceItemAction.h>
3 #include <DataSource/DataSourceItemMergeHelper.h>
3
4
4 #include <QVector>
5 #include <QVector>
5
6
6 const QString DataSourceItem::NAME_DATA_KEY = QStringLiteral("name");
7 const QString DataSourceItem::NAME_DATA_KEY = QStringLiteral("name");
8 const QString DataSourceItem::PLUGIN_DATA_KEY = QStringLiteral("plugin");
7
9
8 struct DataSourceItem::DataSourceItemPrivate {
10 struct DataSourceItem::DataSourceItemPrivate {
9 explicit DataSourceItemPrivate(DataSourceItemType type, QVariantHash data)
11 explicit DataSourceItemPrivate(DataSourceItemType type, QVariantHash data)
@@ -28,6 +30,23 DataSourceItem::DataSourceItem(DataSourceItemType type, QVariantHash data)
28 {
30 {
29 }
31 }
30
32
33 std::unique_ptr<DataSourceItem> DataSourceItem::clone() const
34 {
35 auto result = std::make_unique<DataSourceItem>(impl->m_Type, impl->m_Data);
36
37 // Clones children
38 for (const auto &child : impl->m_Children) {
39 result->appendChild(std::move(child->clone()));
40 }
41
42 // Clones actions
43 for (const auto &action : impl->m_Actions) {
44 result->addAction(std::move(action->clone()));
45 }
46
47 return result;
48 }
49
31 QVector<DataSourceItemAction *> DataSourceItem::actions() const noexcept
50 QVector<DataSourceItemAction *> DataSourceItem::actions() const noexcept
32 {
51 {
33 auto result = QVector<DataSourceItemAction *>{};
52 auto result = QVector<DataSourceItemAction *>{};
@@ -75,6 +94,11 QVariantHash DataSourceItem::data() const noexcept
75 return impl->m_Data;
94 return impl->m_Data;
76 }
95 }
77
96
97 void DataSourceItem::merge(const DataSourceItem &item)
98 {
99 DataSourceItemMergeHelper::merge(item, *this);
100 }
101
78 bool DataSourceItem::isRoot() const noexcept
102 bool DataSourceItem::isRoot() const noexcept
79 {
103 {
80 return impl->m_Parent == nullptr;
104 return impl->m_Parent == nullptr;
@@ -146,7 +170,7 bool DataSourceItem::operator==(const DataSourceItem &other)
146 if (std::tie(impl->m_Type, impl->m_Data) == std::tie(other.impl->m_Type, other.impl->m_Data)) {
170 if (std::tie(impl->m_Type, impl->m_Data) == std::tie(other.impl->m_Type, other.impl->m_Data)) {
147 // Compares contents of items' children
171 // Compares contents of items' children
148 return std::equal(std::cbegin(impl->m_Children), std::cend(impl->m_Children),
172 return std::equal(std::cbegin(impl->m_Children), std::cend(impl->m_Children),
149 std::cbegin(other.impl->m_Children),
173 std::cbegin(other.impl->m_Children), std::cend(other.impl->m_Children),
150 [](const auto &itemChild, const auto &otherChild) {
174 [](const auto &itemChild, const auto &otherChild) {
151 return *itemChild == *otherChild;
175 return *itemChild == *otherChild;
152 });
176 });
@@ -22,6 +22,11 DataSourceItemAction::DataSourceItemAction(const QString &name, ExecuteFunction
22 {
22 {
23 }
23 }
24
24
25 std::unique_ptr<DataSourceItemAction> DataSourceItemAction::clone() const
26 {
27 return std::make_unique<DataSourceItemAction>(impl->m_Name, impl->m_Fun);
28 }
29
25 QString DataSourceItemAction::name() const noexcept
30 QString DataSourceItemAction::name() const noexcept
26 {
31 {
27 return impl->m_Name;
32 return impl->m_Name;
@@ -10,6 +10,7 tests = [
10 [['Data/TestTwoDimArrayData.cpp'],'test_2d','Two Dim Array test'],
10 [['Data/TestTwoDimArrayData.cpp'],'test_2d','Two Dim Array test'],
11 [['Data/TestDataSeriesUtils.cpp'],'test_dataseries_util','Data series utils test'],
11 [['Data/TestDataSeriesUtils.cpp'],'test_dataseries_util','Data series utils test'],
12 [['DataSource/TestDataSourceController.cpp'],'test_data_source','DataSourceController test'],
12 [['DataSource/TestDataSourceController.cpp'],'test_data_source','DataSourceController test'],
13 [['DataSource/TestDataSourceItem.cpp'],'test_data_source_item','DataSourceItem test'],
13 [['Variable/TestVariableCacheController.cpp'],'test_variable_cache','VariableCacheController test'],
14 [['Variable/TestVariableCacheController.cpp'],'test_variable_cache','VariableCacheController test'],
14 [['Variable/TestVariable.cpp'],'test_variable','Variable test'],
15 [['Variable/TestVariable.cpp'],'test_variable','Variable test'],
15 [['Variable/TestVariableSync.cpp'],'test_variable_sync','Variable synchronization test']
16 [['Variable/TestVariableSync.cpp'],'test_variable_sync','Variable synchronization test']
@@ -19,7 +20,9 amdatest_sources = [
19 'Data/DataSeriesBuilders.h',
20 'Data/DataSeriesBuilders.h',
20 'Data/DataSeriesBuilders.cpp',
21 'Data/DataSeriesBuilders.cpp',
21 'Data/DataSeriesTestsUtils.h',
22 'Data/DataSeriesTestsUtils.h',
22 'Data/DataSeriesTestsUtils.cpp'
23 'Data/DataSeriesTestsUtils.cpp',
24 'DataSource/DataSourceItemBuilder.h',
25 'DataSource/DataSourceItemBuilder.cpp'
23 ]
26 ]
24
27
25 foreach unit_test : tests
28 foreach unit_test : tests
@@ -3,6 +3,8
3
3
4 #include <QWidget>
4 #include <QWidget>
5
5
6 #include <memory>
7
6 namespace Ui {
8 namespace Ui {
7 class DataSourceWidget;
9 class DataSourceWidget;
8 } // Ui
10 } // Ui
@@ -29,7 +31,10 public slots:
29 void addDataSource(DataSourceItem *dataSource) noexcept;
31 void addDataSource(DataSourceItem *dataSource) noexcept;
30
32
31 private:
33 private:
34 void updateTreeWidget() noexcept;
35
32 Ui::DataSourceWidget *ui;
36 Ui::DataSourceWidget *ui;
37 std::unique_ptr<DataSourceItem> m_Root;
33
38
34 private slots:
39 private slots:
35 /// Slot called when the filtering text has changed
40 /// Slot called when the filtering text has changed
@@ -11,6 +11,41 namespace {
11 // Column indexes
11 // Column indexes
12 const auto NAME_COLUMN = 0;
12 const auto NAME_COLUMN = 0;
13
13
14 /**
15 * Generates the full name of an item.
16 *
17 * The full name of an item is its name possibly suffixed by the name of its plugin, in case there
18 * are items of the same name in its relatives
19 * @param item the item for which to generate the complete name
20 * @return the complete name of the item
21 */
22 QString completeName(const DataSourceItem &item)
23 {
24 auto name = item.name();
25
26 if (item.type() == DataSourceItemType::NODE) {
27 return name;
28 }
29
30 auto parentItem = item.parentItem();
31 if (!parentItem) {
32 return name;
33 }
34
35 // Finds in item's relatives items that have the same name
36 bool foundSameName = false;
37 for (auto i = 0, count = parentItem->childCount(); i < count && !foundSameName; ++i) {
38 auto child = parentItem->child(i);
39 foundSameName = child != &item
40 && QString::compare(child->name(), item.name(), Qt::CaseInsensitive) == 0;
41 }
42
43 // If the name of the item is not unique, it is completed by the plugin suffix
44 return foundSameName
45 ? QString{"%1 (%2)"}.arg(name, item.data(DataSourceItem::PLUGIN_DATA_KEY).toString())
46 : name;
47 }
48
14 QIcon itemIcon(const DataSourceItem *dataSource)
49 QIcon itemIcon(const DataSourceItem *dataSource)
15 {
50 {
16 if (dataSource) {
51 if (dataSource) {
@@ -92,10 +127,15 QString itemTooltip(const DataSourceItem *dataSource) noexcept
92 } // namespace
127 } // namespace
93
128
94 struct DataSourceTreeWidgetItem::DataSourceTreeWidgetItemPrivate {
129 struct DataSourceTreeWidgetItem::DataSourceTreeWidgetItemPrivate {
95 explicit DataSourceTreeWidgetItemPrivate(const DataSourceItem *data) : m_Data{data} {}
130 explicit DataSourceTreeWidgetItemPrivate(const DataSourceItem *data)
131 : m_Data{data}, m_Name{completeName(*m_Data)}
132 {
133 }
96
134
97 /// Model used to retrieve data source information
135 /// Model used to retrieve data source information
98 const DataSourceItem *m_Data;
136 const DataSourceItem *m_Data;
137 /// Name displayed
138 QString m_Name;
99 /// Actions associated to the item. The parent of the item (QTreeWidget) takes the ownership of
139 /// Actions associated to the item. The parent of the item (QTreeWidget) takes the ownership of
100 /// the actions
140 /// the actions
101 QList<QAction *> m_Actions;
141 QList<QAction *> m_Actions;
@@ -151,7 +191,7 QVariant DataSourceTreeWidgetItem::data(int column, int role) const
151 if (impl->m_Data) {
191 if (impl->m_Data) {
152 switch (column) {
192 switch (column) {
153 case NAME_COLUMN:
193 case NAME_COLUMN:
154 return impl->m_Data->name();
194 return impl->m_Name;
155 default:
195 default:
156 // No action
196 // No action
157 break;
197 break;
@@ -36,7 +36,11 DataSourceTreeWidgetItem *createTreeWidgetItem(DataSourceItem *dataSource)
36
36
37 } // namespace
37 } // namespace
38
38
39 DataSourceWidget::DataSourceWidget(QWidget *parent) : QWidget{parent}, ui{new Ui::DataSourceWidget}
39 DataSourceWidget::DataSourceWidget(QWidget *parent)
40 : QWidget{parent},
41 ui{new Ui::DataSourceWidget},
42 m_Root{
43 std::make_unique<DataSourceItem>(DataSourceItemType::NODE, QStringLiteral("Sources"))}
40 {
44 {
41 ui->setupUi(this);
45 ui->setupUi(this);
42
46
@@ -51,6 +55,9 DataSourceWidget::DataSourceWidget(QWidget *parent) : QWidget{parent}, ui{new Ui
51
55
52 // Connection to filter tree
56 // Connection to filter tree
53 connect(ui->filterLineEdit, &QLineEdit::textChanged, this, &DataSourceWidget::filterChanged);
57 connect(ui->filterLineEdit, &QLineEdit::textChanged, this, &DataSourceWidget::filterChanged);
58
59 // First init
60 updateTreeWidget();
54 }
61 }
55
62
56 DataSourceWidget::~DataSourceWidget() noexcept
63 DataSourceWidget::~DataSourceWidget() noexcept
@@ -60,11 +67,27 DataSourceWidget::~DataSourceWidget() noexcept
60
67
61 void DataSourceWidget::addDataSource(DataSourceItem *dataSource) noexcept
68 void DataSourceWidget::addDataSource(DataSourceItem *dataSource) noexcept
62 {
69 {
63 // Creates the item associated to the source and adds it to the tree widget. The tree widget
70 // Merges the data source (without taking its root)
64 // takes the ownership of the item
65 if (dataSource) {
71 if (dataSource) {
66 ui->treeWidget->addTopLevelItem(createTreeWidgetItem(dataSource));
72 for (auto i = 0, count = dataSource->childCount(); i < count; ++i) {
73 m_Root->merge(*dataSource->child(i));
74 }
75
76 updateTreeWidget();
77 }
67 }
78 }
79
80 void DataSourceWidget::updateTreeWidget() noexcept
81 {
82 ui->treeWidget->clear();
83
84 auto rootItem = createTreeWidgetItem(m_Root.get());
85 ui->treeWidget->addTopLevelItem(rootItem);
86 rootItem->setExpanded(true);
87
88 // Sorts tree
89 ui->treeWidget->setSortingEnabled(true);
90 ui->treeWidget->sortByColumn(0, Qt::AscendingOrder);
68 }
91 }
69
92
70 void DataSourceWidget::filterChanged(const QString &text) noexcept
93 void DataSourceWidget::filterChanged(const QString &text) noexcept
@@ -31,11 +31,14 void associateActions(DataSourceItem &item, const QUuid &dataSourceUid)
31 };
31 };
32
32
33 const auto itemType = item.type();
33 const auto itemType = item.type();
34 if (itemType == DataSourceItemType::PRODUCT) {
34 if (itemType == DataSourceItemType::PRODUCT || itemType == DataSourceItemType::COMPONENT) {
35 addLoadAction(QObject::tr("Load %1 product").arg(item.name()));
35 // Adds plugin name to item metadata
36 }
36 item.setData(DataSourceItem::PLUGIN_DATA_KEY, DATA_SOURCE_NAME);
37 else if (itemType == DataSourceItemType::COMPONENT) {
37
38 addLoadAction(QObject::tr("Load %1 component").arg(item.name()));
38 // Adds load action
39 auto actionLabel = QObject::tr(
40 itemType == DataSourceItemType::PRODUCT ? "Load %1 product" : "Load %1 component");
41 addLoadAction(actionLabel.arg(item.name()));
39 }
42 }
40
43
41 auto count = item.childCount();
44 auto count = item.childCount();
@@ -25,6 +25,10 std::unique_ptr<DataSourceItem> createProductItem(const QVariantHash &data,
25 const QUuid &dataSourceUid)
25 const QUuid &dataSourceUid)
26 {
26 {
27 auto result = std::make_unique<DataSourceItem>(DataSourceItemType::PRODUCT, data);
27 auto result = std::make_unique<DataSourceItem>(DataSourceItemType::PRODUCT, data);
28
29 // Adds plugin name to product metadata
30 result->setData(DataSourceItem::PLUGIN_DATA_KEY, DATA_SOURCE_NAME);
31
28 auto productName = data.value(DataSourceItem::NAME_DATA_KEY).toString();
32 auto productName = data.value(DataSourceItem::NAME_DATA_KEY).toString();
29
33
30 // Add action to load product from DataSourceController
34 // Add action to load product from DataSourceController
General Comments 0
You need to be logged in to leave comments. Login now