##// END OF EJS Templates
Implements merge method (2)...
Alexandre Leroux -
r1073:243c12122366
parent child
Show More
@@ -1,150 +1,152
1 1 #ifndef SCIQLOP_DATASOURCEITEM_H
2 2 #define SCIQLOP_DATASOURCEITEM_H
3 3
4 4 #include "CoreGlobal.h"
5 5
6 6 #include <Common/spimpl.h>
7 7
8 8 #include <QVariant>
9 9 #include <QVector>
10 10
11 11 class DataSourceItemAction;
12 12
13 13 /**
14 14 * Possible types of an item
15 15 */
16 16 enum class DataSourceItemType { NODE, PRODUCT, COMPONENT };
17 17
18 18 /**
19 19 * @brief The DataSourceItem class aims to represent a structure element of a data source.
20 20 * A data source has a tree structure that is made up of a main DataSourceItem object (root)
21 21 * containing other DataSourceItem objects (children).
22 22 * For each DataSourceItem can be associated a set of data representing it.
23 23 */
24 24 class SCIQLOP_CORE_EXPORT DataSourceItem {
25 25 public:
26 26 /// Key associated with the name of the item
27 27 static const QString NAME_DATA_KEY;
28 28
29 29 explicit DataSourceItem(DataSourceItemType type, const QString &name);
30 30 explicit DataSourceItem(DataSourceItemType type, QVariantHash data = {});
31 31
32 std::unique_ptr<DataSourceItem> clone() const;
33
32 34 /// @return the actions of the item as a vector
33 35 QVector<DataSourceItemAction *> actions() const noexcept;
34 36
35 37 /**
36 38 * Adds an action to the item. The item takes ownership of the action, and the action is
37 39 * automatically associated to the item
38 40 * @param action the action to add
39 41 */
40 42 void addAction(std::unique_ptr<DataSourceItemAction> action) noexcept;
41 43
42 44 /**
43 45 * Adds a child to the item. The item takes ownership of the child.
44 46 * @param child the child to add
45 47 */
46 48 void appendChild(std::unique_ptr<DataSourceItem> child) noexcept;
47 49
48 50 /**
49 51 * Returns the item's child associated to an index
50 52 * @param childIndex the index to search
51 53 * @return a pointer to the child if index is valid, nullptr otherwise
52 54 */
53 55 DataSourceItem *child(int childIndex) const noexcept;
54 56
55 57 int childCount() const noexcept;
56 58
57 59 /**
58 60 * Get the data associated to a key
59 61 * @param key the key to search
60 62 * @return the data found if key is valid, default QVariant otherwise
61 63 */
62 64 QVariant data(const QString &key) const noexcept;
63 65
64 66 /// Gets all data
65 67 QVariantHash data() const noexcept;
66 68
67 69 /**
68 70 * Merge in the item the source item passed as parameter.
69 71 *
70 72 * The merge is done by adding as child of the item the complete tree represented by the source
71 73 * item. If a part of the tree already exists in the item (based on the name of the nodes), it
72 74 * is merged by completing the existing tree by items "leaves" (products, components or nodes
73 75 * with no child).
74 76 *
75 77 * For example, with item representing the tree:
76 78 * R (root node)
77 79 * - N1 (node)
78 80 * -- N11 (node)
79 81 * --- P1 (product)
80 82 * --- P2 (product)
81 83 * - N2 (node)
82 84 *
83 85 * and the source item representing the tree:
84 86 * N1 (root node)
85 87 * - N11 (node)
86 88 * -- P3 (product)
87 89 * - N12 (node)
88 90 *
89 91 * The leaves of the source item to merge into the item are N1/N11/P3 and N1/N12 => we therefore
90 92 * have the following merge result:
91 93 * R
92 94 * - N1
93 95 * -- N11
94 96 * --- P1
95 97 * --- P2
96 98 * --- P3 (added leaf)
97 99 * -- N12 (added leaf)
98 100 *
99 101 * @param item the source item
100 102 * @remarks No control is performed on products or components that are merged into the same tree
101 103 * part (two products or components may have the same name)
102 104 * @remarks the merge is made by copy (source item is not changed and still exists after the
103 105 * operation)
104 106 */
105 107 void merge(const DataSourceItem &item);
106 108
107 109 bool isRoot() const noexcept;
108 110
109 111 QString name() const noexcept;
110 112
111 113 /**
112 114 * Get the item's parent
113 115 * @return a pointer to the parent if it exists, nullptr if the item is a root
114 116 */
115 117 DataSourceItem *parentItem() const noexcept;
116 118
117 119 /**
118 120 * Gets the item's root
119 121 * @return the top parent, the item itself if it's the root item
120 122 */
121 123 const DataSourceItem &rootItem() const noexcept;
122 124
123 125 /**
124 126 * Sets or appends a value to a key
125 127 * @param key the key
126 128 * @param value the value
127 129 * @param append if true, the value is added to the values already existing for the key,
128 130 * otherwise it replaces the existing values
129 131 */
130 132 void setData(const QString &key, const QVariant &value, bool append = false) noexcept;
131 133
132 134 DataSourceItemType type() const noexcept;
133 135
134 136 /**
135 137 * @brief Searches the first child matching the specified data.
136 138 * @param data The data to search.
137 139 * @param recursive So the search recursively.
138 140 * @return the item matching the data or nullptr if it was not found.
139 141 */
140 142 DataSourceItem *findItem(const QVariantHash &data, bool recursive);
141 143
142 144 bool operator==(const DataSourceItem &other);
143 145 bool operator!=(const DataSourceItem &other);
144 146
145 147 private:
146 148 class DataSourceItemPrivate;
147 149 spimpl::unique_impl_ptr<DataSourceItemPrivate> impl;
148 150 };
149 151
150 152 #endif // SCIQLOP_DATASOURCEITEMMODEL_H
@@ -1,52 +1,54
1 1 #ifndef SCIQLOP_DATASOURCEITEMACTION_H
2 2 #define SCIQLOP_DATASOURCEITEMACTION_H
3 3
4 4 #include "CoreGlobal.h"
5 5
6 6 #include <Common/spimpl.h>
7 7
8 8 #include <QLoggingCategory>
9 9 #include <QObject>
10 10
11 11 #include <functional>
12 12
13 13 Q_DECLARE_LOGGING_CATEGORY(LOG_DataSourceItemAction)
14 14
15 15 class DataSourceItem;
16 16
17 17 /**
18 18 * @brief The DataSourceItemAction class represents an action on a data source item.
19 19 *
20 20 * An action is a function that will be executed when the slot execute() is called.
21 21 */
22 22 class SCIQLOP_CORE_EXPORT DataSourceItemAction : public QObject {
23 23
24 24 Q_OBJECT
25 25
26 26 public:
27 27 /// Signature of the function associated to the action
28 28 using ExecuteFunction = std::function<void(DataSourceItem &dataSourceItem)>;
29 29
30 30 /**
31 31 * Ctor
32 32 * @param name the name of the action
33 33 * @param fun the function that will be called when the action is executed
34 34 * @sa execute()
35 35 */
36 36 explicit DataSourceItemAction(const QString &name, ExecuteFunction fun);
37 37
38 std::unique_ptr<DataSourceItemAction> clone() const;
39
38 40 QString name() const noexcept;
39 41
40 42 /// Sets the data source item concerned by the action
41 43 void setDataSourceItem(DataSourceItem *dataSourceItem) noexcept;
42 44
43 45 public slots:
44 46 /// Executes the action
45 47 void execute();
46 48
47 49 private:
48 50 class DataSourceItemActionPrivate;
49 51 spimpl::unique_impl_ptr<DataSourceItemActionPrivate> impl;
50 52 };
51 53
52 54 #endif // SCIQLOP_DATASOURCEITEMACTION_H
@@ -1,168 +1,185
1 1 #include <DataSource/DataSourceItem.h>
2 2 #include <DataSource/DataSourceItemAction.h>
3 3 #include <DataSource/DataSourceItemMergeHelper.h>
4 4
5 5 #include <QVector>
6 6
7 7 const QString DataSourceItem::NAME_DATA_KEY = QStringLiteral("name");
8 8
9 9 struct DataSourceItem::DataSourceItemPrivate {
10 10 explicit DataSourceItemPrivate(DataSourceItemType type, QVariantHash data)
11 11 : m_Parent{nullptr}, m_Children{}, m_Type{type}, m_Data{std::move(data)}, m_Actions{}
12 12 {
13 13 }
14 14
15 15 DataSourceItem *m_Parent;
16 16 std::vector<std::unique_ptr<DataSourceItem> > m_Children;
17 17 DataSourceItemType m_Type;
18 18 QVariantHash m_Data;
19 19 std::vector<std::unique_ptr<DataSourceItemAction> > m_Actions;
20 20 };
21 21
22 22 DataSourceItem::DataSourceItem(DataSourceItemType type, const QString &name)
23 23 : DataSourceItem{type, QVariantHash{{NAME_DATA_KEY, name}}}
24 24 {
25 25 }
26 26
27 27 DataSourceItem::DataSourceItem(DataSourceItemType type, QVariantHash data)
28 28 : impl{spimpl::make_unique_impl<DataSourceItemPrivate>(type, std::move(data))}
29 29 {
30 30 }
31 31
32 std::unique_ptr<DataSourceItem> DataSourceItem::clone() const
33 {
34 auto result = std::make_unique<DataSourceItem>(impl->m_Type, impl->m_Data);
35
36 // Clones children
37 for (const auto &child : impl->m_Children) {
38 result->appendChild(std::move(child->clone()));
39 }
40
41 // Clones actions
42 for (const auto &action : impl->m_Actions) {
43 result->addAction(std::move(action->clone()));
44 }
45
46 return result;
47 }
48
32 49 QVector<DataSourceItemAction *> DataSourceItem::actions() const noexcept
33 50 {
34 51 auto result = QVector<DataSourceItemAction *>{};
35 52
36 53 std::transform(std::cbegin(impl->m_Actions), std::cend(impl->m_Actions),
37 54 std::back_inserter(result), [](const auto &action) { return action.get(); });
38 55
39 56 return result;
40 57 }
41 58
42 59 void DataSourceItem::addAction(std::unique_ptr<DataSourceItemAction> action) noexcept
43 60 {
44 61 action->setDataSourceItem(this);
45 62 impl->m_Actions.push_back(std::move(action));
46 63 }
47 64
48 65 void DataSourceItem::appendChild(std::unique_ptr<DataSourceItem> child) noexcept
49 66 {
50 67 child->impl->m_Parent = this;
51 68 impl->m_Children.push_back(std::move(child));
52 69 }
53 70
54 71 DataSourceItem *DataSourceItem::child(int childIndex) const noexcept
55 72 {
56 73 if (childIndex < 0 || childIndex >= childCount()) {
57 74 return nullptr;
58 75 }
59 76 else {
60 77 return impl->m_Children.at(childIndex).get();
61 78 }
62 79 }
63 80
64 81 int DataSourceItem::childCount() const noexcept
65 82 {
66 83 return impl->m_Children.size();
67 84 }
68 85
69 86 QVariant DataSourceItem::data(const QString &key) const noexcept
70 87 {
71 88 return impl->m_Data.value(key);
72 89 }
73 90
74 91 QVariantHash DataSourceItem::data() const noexcept
75 92 {
76 93 return impl->m_Data;
77 94 }
78 95
79 96 void DataSourceItem::merge(const DataSourceItem &item)
80 97 {
81 98 DataSourceItemMergeHelper::merge(item, *this);
82 99 }
83 100
84 101 bool DataSourceItem::isRoot() const noexcept
85 102 {
86 103 return impl->m_Parent == nullptr;
87 104 }
88 105
89 106 QString DataSourceItem::name() const noexcept
90 107 {
91 108 return data(NAME_DATA_KEY).toString();
92 109 }
93 110
94 111 DataSourceItem *DataSourceItem::parentItem() const noexcept
95 112 {
96 113 return impl->m_Parent;
97 114 }
98 115
99 116 const DataSourceItem &DataSourceItem::rootItem() const noexcept
100 117 {
101 118 return isRoot() ? *this : parentItem()->rootItem();
102 119 }
103 120
104 121 void DataSourceItem::setData(const QString &key, const QVariant &value, bool append) noexcept
105 122 {
106 123 auto it = impl->m_Data.constFind(key);
107 124 if (append && it != impl->m_Data.constEnd()) {
108 125 // Case of an existing value to which we want to add to the new value
109 126 if (it->canConvert<QVariantList>()) {
110 127 auto variantList = it->value<QVariantList>();
111 128 variantList.append(value);
112 129
113 130 impl->m_Data.insert(key, variantList);
114 131 }
115 132 else {
116 133 impl->m_Data.insert(key, QVariantList{*it, value});
117 134 }
118 135 }
119 136 else {
120 137 // Other cases :
121 138 // - new value in map OR
122 139 // - replacement of an existing value (not appending)
123 140 impl->m_Data.insert(key, value);
124 141 }
125 142 }
126 143
127 144 DataSourceItemType DataSourceItem::type() const noexcept
128 145 {
129 146 return impl->m_Type;
130 147 }
131 148
132 149 DataSourceItem *DataSourceItem::findItem(const QVariantHash &data, bool recursive)
133 150 {
134 151 for (const auto &child : impl->m_Children) {
135 152 if (child->impl->m_Data == data) {
136 153 return child.get();
137 154 }
138 155
139 156 if (recursive) {
140 157 if (auto foundItem = child->findItem(data, true)) {
141 158 return foundItem;
142 159 }
143 160 }
144 161 }
145 162
146 163 return nullptr;
147 164 }
148 165
149 166 bool DataSourceItem::operator==(const DataSourceItem &other)
150 167 {
151 168 // Compares items' attributes
152 169 if (std::tie(impl->m_Type, impl->m_Data) == std::tie(other.impl->m_Type, other.impl->m_Data)) {
153 170 // Compares contents of items' children
154 171 return std::equal(std::cbegin(impl->m_Children), std::cend(impl->m_Children),
155 172 std::cbegin(other.impl->m_Children),
156 173 [](const auto &itemChild, const auto &otherChild) {
157 174 return *itemChild == *otherChild;
158 175 });
159 176 }
160 177 else {
161 178 return false;
162 179 }
163 180 }
164 181
165 182 bool DataSourceItem::operator!=(const DataSourceItem &other)
166 183 {
167 184 return !(*this == other);
168 185 }
@@ -1,44 +1,49
1 1 #include <DataSource/DataSourceItemAction.h>
2 2
3 3 #include <functional>
4 4
5 5 Q_LOGGING_CATEGORY(LOG_DataSourceItemAction, "DataSourceItemAction")
6 6
7 7 struct DataSourceItemAction::DataSourceItemActionPrivate {
8 8 explicit DataSourceItemActionPrivate(const QString &name,
9 9 DataSourceItemAction::ExecuteFunction fun)
10 10 : m_Name{name}, m_Fun{std::move(fun)}, m_DataSourceItem{nullptr}
11 11 {
12 12 }
13 13
14 14 QString m_Name;
15 15 DataSourceItemAction::ExecuteFunction m_Fun;
16 16 /// Item associated to the action (can be null, in which case the action will not be executed)
17 17 DataSourceItem *m_DataSourceItem;
18 18 };
19 19
20 20 DataSourceItemAction::DataSourceItemAction(const QString &name, ExecuteFunction fun)
21 21 : impl{spimpl::make_unique_impl<DataSourceItemActionPrivate>(name, std::move(fun))}
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 30 QString DataSourceItemAction::name() const noexcept
26 31 {
27 32 return impl->m_Name;
28 33 }
29 34
30 35 void DataSourceItemAction::setDataSourceItem(DataSourceItem *dataSourceItem) noexcept
31 36 {
32 37 impl->m_DataSourceItem = dataSourceItem;
33 38 }
34 39
35 40 void DataSourceItemAction::execute()
36 41 {
37 42 if (impl->m_DataSourceItem) {
38 43 impl->m_Fun(*impl->m_DataSourceItem);
39 44 }
40 45 else {
41 46 qCDebug(LOG_DataSourceItemAction())
42 47 << tr("Can't execute action : no item has been associated");
43 48 }
44 49 }
General Comments 0
You need to be logged in to leave comments. Login now