##// END OF EJS Templates
New DataSources model class ready for integration...
jeandet -
r98:b081849458c2
parent child
Show More
@@ -0,0 +1,55
1 /*------------------------------------------------------------------------------
2 * -- This file is a part of SciQLop
3 * -- Copyright (C) 2019, Plasma Physics Laboratory - CNRS
4 * --
5 * -- This program is free software; you can redistribute it and/or modify
6 * -- it under the terms of the GNU General Public License as published by
7 * -- the Free Software Foundation; either version 3 of the License, or
8 * -- (at your option) any later version.
9 * --
10 * -- This program is distributed in the hope that it will be useful,
11 * -- but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * -- GNU General Public License for more details.
14 * --
15 * -- You should have received a copy of the GNU General Public License
16 * -- along with this program; if not, write to the Free Software
17 * -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 * -------------------------------------------------------------------------------*/
19 /* -- Author : Alexis Jeandet
20 * -- Mail : alexis.jeandet@lpp.polytechnique.fr
21 * -- alexis.jeandet@member.fsf.org
22 * ----------------------------------------------------------------------------*/
23 #ifndef DATASOURCESFILTER_H_INCLUDED
24 #define DATASOURCESFILTER_H_INCLUDED
25
26 #include "DataSourceItem.h"
27
28 #include <QObject>
29 #include <QSortFilterProxyModel>
30
31 class DataSourceFilter : public QSortFilterProxyModel
32 {
33 Q_OBJECT
34 public:
35 explicit DataSourceFilter(QObject* parent = nullptr);
36
37 bool filterAcceptsRow(int sourceRow,
38 const QModelIndex& sourceParent) const override
39 {
40 if(filterRegExp().isEmpty()) { return true; }
41 DataSourceItem* childItem = static_cast<DataSourceItem*>(
42 sourceModel()->index(sourceRow, 0, sourceParent).internalPointer());
43 if(childItem)
44 {
45 auto data = childItem->data();
46 return (std::find_if(std::cbegin(data), std::cend(data),
47 [regex = filterRegExp()](const auto& item) {
48 return item.toString().contains(regex);
49 }) != std::cend(data));
50 }
51 return false;
52 }
53 };
54
55 #endif // DATASOURCESFILTER_H_INCLUDED
@@ -0,0 +1,28
1 /*------------------------------------------------------------------------------
2 * -- This file is a part of SciQLop
3 * -- Copyright (C) 2019, Plasma Physics Laboratory - CNRS
4 * --
5 * -- This program is free software; you can redistribute it and/or modify
6 * -- it under the terms of the GNU General Public License as published by
7 * -- the Free Software Foundation; either version 3 of the License, or
8 * -- (at your option) any later version.
9 * --
10 * -- This program is distributed in the hope that it will be useful,
11 * -- but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * -- GNU General Public License for more details.
14 * --
15 * -- You should have received a copy of the GNU General Public License
16 * -- along with this program; if not, write to the Free Software
17 * -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 * -------------------------------------------------------------------------------*/
19 /* -- Author : Alexis Jeandet
20 * -- Mail : alexis.jeandet@lpp.polytechnique.fr
21 * -- alexis.jeandet@member.fsf.org
22 * ----------------------------------------------------------------------------*/
23
24 #include "DataSource/DataSourcesFilter.h"
25
26 DataSourceFilter::DataSourceFilter(QObject* parent)
27 : QSortFilterProxyModel(parent)
28 {}
@@ -0,0 +1,78
1 #include "DataSource/DataSourcesFilter.h"
2 #include "DataSource/datasources.h"
3 #include "TestProviders.h"
4
5 #include <QApplication>
6 #include <QFileIconProvider>
7 #include <QLineEdit>
8 #include <QObject>
9 #include <QTreeView>
10 #include <QVBoxLayout>
11 #include <QWidget>
12 #include <cpp_utils.hpp>
13 #include <iostream>
14
15 void fillModel(DataSources* ds, SimpleRange<1>* provider)
16 {
17 ds->addIcon("folder", QFileIconProvider().icon(QFileIconProvider::Folder));
18 ds->addIcon("computer",
19 QFileIconProvider().icon(QFileIconProvider::Computer));
20 ds->addProvider(provider);
21 ds->addDataSourceItem(*provider, "/test/node1", {{"Key", "Value"}});
22 ds->addDataSourceItem(*provider, "/test/node2", {});
23 ds->addDataSourceItem(*provider, "/test/node3", {});
24 ds->addDataSourceItem(*provider, "/test/node4", {});
25 ds->setIcon("/test", "folder");
26 ds->addDataSourceItem(*provider, "/test/folder/node1", {});
27 ds->addDataSourceItem(*provider, "/test2/folder/node1", {});
28 repeat_n(
29 [ds, provider](int i) {
30 repeat_n(
31 [ds, provider, i](int j) {
32 repeat_n(
33 [ds, provider, i, j](int k) {
34 ds->addDataSourceItem(*provider,
35 "/test2/folder" + QString::number(i) +
36 "/folder" + QString::number(j) +
37 "/node" + QString::number(k),
38 {});
39 },
40 10);
41 },
42 10);
43 },
44 10);
45
46 ds->updateNodeMetaData("/test2/folder", {{"KeyUp", "ValueUp"}});
47 ds->setIcon("/test2", "computer");
48 }
49
50 int main(int argc, char** argv)
51 {
52 SimpleRange<1>* provider = new SimpleRange<1>{};
53 QApplication app(argc, argv);
54 auto w = new QWidget();
55 auto layout = new QVBoxLayout(w);
56 DataSources* ds = new DataSources();
57 // DataSourceFilter* filter = new DataSourceFilter();
58 QSortFilterProxyModel* filter = new QSortFilterProxyModel();
59 filter->setSourceModel(ds);
60 QTreeView* view = new QTreeView();
61 QLineEdit* filterBox = new QLineEdit();
62 QObject::connect(
63 filterBox,
64 static_cast<void (QLineEdit::*)(const QString&)>(&QLineEdit::textChanged),
65 filter,
66 static_cast<void (QSortFilterProxyModel::*)(const QString&)>(
67 &QSortFilterProxyModel::setFilterRegExp));
68 layout->addWidget(filterBox);
69 layout->addWidget(view);
70 view->setModel(filter);
71 w->show();
72 view->setDragEnabled(true);
73 filter->setFilterRole(Qt::ToolTipRole);
74 filter->setRecursiveFilteringEnabled(true);
75 fillModel(ds, provider);
76 view->expandAll();
77 return app.exec();
78 }
@@ -1,56 +1,58
1 #ifndef SCIQLOP_IDATAPROVIDER_H
1 #ifndef SCIQLOP_IDATAPROVIDER_H
2 #define SCIQLOP_IDATAPROVIDER_H
2 #define SCIQLOP_IDATAPROVIDER_H
3
3
4 #include "CoreGlobal.h"
4 #include "CoreGlobal.h"
5
5
6 #include <Common/MetaTypes.h>
6 #include <Common/MetaTypes.h>
7 #include <deprecate.h>
7 #include <deprecate.h>
8 #include <Data/DateTimeRange.h>
8 #include <Data/DateTimeRange.h>
9 #include <QObject>
9 #include <QObject>
10 #include <QUuid>
10 #include <QUuid>
11 #include <TimeSeries.h>
11 #include <TimeSeries.h>
12 #include <functional>
12 #include <functional>
13 #include <memory>
13 #include <memory>
14
14
15 class DataProviderParameters;
15 class DataProviderParameters;
16 class IDataSeries;
16 class IDataSeries;
17 DEPRECATE(class QNetworkReply; class QNetworkRequest;)
17 DEPRECATE(class QNetworkReply; class QNetworkRequest;)
18
18
19 /**
19 /**
20 * @brief The IDataProvider interface aims to declare a data provider.
20 * @brief The IDataProvider interface aims to declare a data provider.
21 *
21 *
22 * A data provider is an entity that generates data and returns it according to
22 * A data provider is an entity that generates data and returns it according to
23 * various parameters (time interval, product to retrieve the data, etc.) Since
23 * various parameters (time interval, product to retrieve the data, etc.) Since
24 * its client mihgt use it from different threads it has to be either stateless
24 * its client mihgt use it from different threads it has to be either stateless
25 * and/or thread safe
25 * and/or thread safe
26 *
26 *
27 * @sa IDataSeries
27 * @sa IDataSeries
28 */
28 */
29 class SCIQLOP_CORE_EXPORT IDataProvider : public QObject
29 class SCIQLOP_CORE_EXPORT IDataProvider : public QObject
30 {
30 {
31 Q_OBJECT
31 Q_OBJECT
32
32
33 QUuid _id=QUuid::createUuid();
33 QUuid _id=QUuid::createUuid();
34
34
35 public:
35 public:
36 virtual ~IDataProvider() noexcept = default;
36 virtual ~IDataProvider() noexcept = default;
37
37
38 virtual TimeSeries::ITimeSerie*
38 virtual TimeSeries::ITimeSerie*
39 getData(const DataProviderParameters& parameters) = 0;
39 getData(const DataProviderParameters& parameters) = 0;
40
40
41 QUuid id() const { return _id; }
41 QUuid id() const { return _id; }
42 QString name()
42 QString name()
43 {
43 {
44 return QString("%1-%2").arg(this->metaObject()->className()).arg(id().toString());
44 return QString("%1-%2").arg(this->metaObject()->className()).arg(id().toString());
45 }
45 }
46
46
47 operator QUuid(){return _id;}
48
47 signals:
49 signals:
48
50
49 void progress(QUuid requestID, double progress);
51 void progress(QUuid requestID, double progress);
50 };
52 };
51
53
52 // Required for using shared_ptr in signals/slots
54 // Required for using shared_ptr in signals/slots
53 SCIQLOP_REGISTER_META_TYPE(IDATAPROVIDER_PTR_REGISTRY,
55 SCIQLOP_REGISTER_META_TYPE(IDATAPROVIDER_PTR_REGISTRY,
54 std::shared_ptr<IDataProvider>)
56 std::shared_ptr<IDataProvider>)
55
57
56 #endif // SCIQLOP_IDATAPROVIDER_H
58 #endif // SCIQLOP_IDATAPROVIDER_H
@@ -1,191 +1,204
1 #ifndef SCIQLOP_DATASOURCEITEM_H
1 #ifndef SCIQLOP_DATASOURCEITEM_H
2 #define SCIQLOP_DATASOURCEITEM_H
2 #define SCIQLOP_DATASOURCEITEM_H
3
3
4 #include "CoreGlobal.h"
4 #include "CoreGlobal.h"
5
5
6 #include <Common/spimpl.h>
6 #include <Common/spimpl.h>
7 #include <QUuid>
7 #include <QVariant>
8 #include <QVariant>
8 #include <QVector>
9 #include <QVector>
9 #include <iomanip>
10 #include <iomanip>
10 #include <iostream>
11 #include <iostream>
12 #include <optional>
11 #include <trees/algorithms.hpp>
13 #include <trees/algorithms.hpp>
12
14
13 class DataSourceItemAction;
15 class DataSourceItemAction;
14
16
15 /**
17 /**
16 * Possible types of an item
18 * Possible types of an item
17 */
19 */
18 enum class DataSourceItemType
20 enum class DataSourceItemType
19 {
21 {
20 NODE,
22 NODE,
21 PRODUCT,
23 PRODUCT,
22 COMPONENT
24 COMPONENT
23 };
25 };
24
26
25 /**
27 /**
26 * @brief The DataSourceItem class aims to represent a structure element of a
28 * @brief The DataSourceItem class aims to represent a structure element of a
27 * data source. A data source has a tree structure that is made up of a main
29 * data source. A data source has a tree structure that is made up of a main
28 * DataSourceItem object (root) containing other DataSourceItem objects
30 * DataSourceItem object (root) containing other DataSourceItem objects
29 * (children). For each DataSourceItem can be associated a set of data
31 * (children). For each DataSourceItem can be associated a set of data
30 * representing it.
32 * representing it.
31 */
33 */
32 class SCIQLOP_CORE_EXPORT DataSourceItem
34 class SCIQLOP_CORE_EXPORT DataSourceItem
33 {
35 {
34 public:
36 public:
35 using iterator_type = decltype(
37 using iterator_type = decltype(
36 std::begin(std::declval<std::vector<std::unique_ptr<DataSourceItem>>>()));
38 std::begin(std::declval<std::vector<std::unique_ptr<DataSourceItem>>>()));
37 using const_iterator_type = decltype(std::cbegin(
39 using const_iterator_type = decltype(std::cbegin(
38 std::declval<std::vector<std::unique_ptr<DataSourceItem>>>()));
40 std::declval<std::vector<std::unique_ptr<DataSourceItem>>>()));
39 /// Key associated with the name of the item
41 /// Key associated with the name of the item
40 static const QString NAME_DATA_KEY;
42 static const QString NAME_DATA_KEY;
41 /// Key associated with the plugin of the item
43 /// Key associated with the plugin of the item
42 static const QString PLUGIN_DATA_KEY;
44 static const QString PLUGIN_DATA_KEY;
43 /// Key associated with a unique id of the plugin
45 /// Key associated with a unique id of the plugin
44 static const QString ID_DATA_KEY;
46 static const QString ID_DATA_KEY;
45
47
46 explicit DataSourceItem(DataSourceItemType type, const QString& name);
48 //explicit DataSourceItem(DataSourceItemType type, const QString& name);
47 explicit DataSourceItem(DataSourceItemType type, QVariantHash data = {});
49 explicit DataSourceItem(DataSourceItemType type, const QString& name, QVariantHash data = {},
50 std::optional<QUuid> sourceUUID = std::nullopt);
48
51
49 std::unique_ptr<DataSourceItem> clone() const;
52 std::unique_ptr<DataSourceItem> clone() const;
50
53
51 /// @return the actions of the item as a vector
54 /// @return the actions of the item as a vector
52 QVector<DataSourceItemAction*> actions() const noexcept;
55 QVector<DataSourceItemAction*> actions() const noexcept;
53
56
54 /**
57 /**
55 * Adds an action to the item. The item takes ownership of the action, and the
58 * Adds an action to the item. The item takes ownership of the action, and the
56 * action is automatically associated to the item
59 * action is automatically associated to the item
57 * @param action the action to add
60 * @param action the action to add
58 */
61 */
59 void addAction(std::unique_ptr<DataSourceItemAction> action) noexcept;
62 void addAction(std::unique_ptr<DataSourceItemAction> action) noexcept;
60
63
61 /**
64 /**
62 * Adds a child to the item. The item takes ownership of the child.
65 * Adds a child to the item. The item takes ownership of the child.
63 * @param child the child to add
66 * @param child the child to add
64 */
67 */
65 void appendChild(std::unique_ptr<DataSourceItem> child) noexcept;
68 void appendChild(std::unique_ptr<DataSourceItem> child) noexcept;
66
69
67 /**
70 /**
68 * Returns the item's child associated to an index
71 * Returns the item's child associated to an index
69 * @param childIndex the index to search
72 * @param childIndex the index to search
70 * @return a pointer to the child if index is valid, nullptr otherwise
73 * @return a pointer to the child if index is valid, nullptr otherwise
71 */
74 */
72 DataSourceItem* child(int childIndex) const noexcept;
75 DataSourceItem* child(int childIndex) const noexcept;
73
76
74 int childCount() const noexcept;
77 int childCount() const noexcept;
75
78
76 int index() const noexcept;
79 int index() const noexcept;
77
80
78 /**
81 /**
79 * Get the data associated to a key
82 * Get the data associated to a key
80 * @param key the key to search
83 * @param key the key to search
81 * @return the data found if key is valid, default QVariant otherwise
84 * @return the data found if key is valid, default QVariant otherwise
82 */
85 */
83 QVariant data(const QString& key) const noexcept;
86 QVariant data(const QString& key) const noexcept;
84
87
85 /// Gets all data
88 /// Gets all data
86 QVariantHash data() const noexcept;
89 QVariantHash data() const noexcept;
87
90
88 /**
91 /**
89 * Merge in the item the source item passed as parameter.
92 * Merge in the item the source item passed as parameter.
90 *
93 *
91 * The merge is done by adding as child of the item the complete tree
94 * The merge is done by adding as child of the item the complete tree
92 * represented by the source item. If a part of the tree already exists in the
95 * represented by the source item. If a part of the tree already exists in the
93 * item (based on the name of the nodes), it is merged by completing the
96 * item (based on the name of the nodes), it is merged by completing the
94 * existing tree by items "leaves" (products, components or nodes with no
97 * existing tree by items "leaves" (products, components or nodes with no
95 * child).
98 * child).
96 *
99 *
97 * For example, with item representing the tree:
100 * For example, with item representing the tree:
98 * R (root node)
101 * R (root node)
99 * - N1 (node)
102 * - N1 (node)
100 * -- N11 (node)
103 * -- N11 (node)
101 * --- P1 (product)
104 * --- P1 (product)
102 * --- P2 (product)
105 * --- P2 (product)
103 * - N2 (node)
106 * - N2 (node)
104 *
107 *
105 * and the source item representing the tree:
108 * and the source item representing the tree:
106 * N1 (root node)
109 * N1 (root node)
107 * - N11 (node)
110 * - N11 (node)
108 * -- P3 (product)
111 * -- P3 (product)
109 * - N12 (node)
112 * - N12 (node)
110 *
113 *
111 * The leaves of the source item to merge into the item are N1/N11/P3 and
114 * The leaves of the source item to merge into the item are N1/N11/P3 and
112 * N1/N12 => we therefore have the following merge result:
115 * N1/N12 => we therefore have the following merge result:
113 * R
116 * R
114 * - N1
117 * - N1
115 * -- N11
118 * -- N11
116 * --- P1
119 * --- P1
117 * --- P2
120 * --- P2
118 * --- P3 (added leaf)
121 * --- P3 (added leaf)
119 * -- N12 (added leaf)
122 * -- N12 (added leaf)
120 *
123 *
121 * @param item the source item
124 * @param item the source item
122 * @remarks No control is performed on products or components that are merged
125 * @remarks No control is performed on products or components that are merged
123 * into the same tree part (two products or components may have the same name)
126 * into the same tree part (two products or components may have the same name)
124 * @remarks the merge is made by copy (source item is not changed and still
127 * @remarks the merge is made by copy (source item is not changed and still
125 * exists after the operation)
128 * exists after the operation)
126 */
129 */
127 void merge(const DataSourceItem& item);
130 void merge(const DataSourceItem& item);
128
131
129 bool isRoot() const noexcept;
132 bool isRoot() const noexcept;
130
133
134 inline bool isProductOrComponent() const noexcept
135 {
136 return (this->type() == DataSourceItemType::PRODUCT) ||
137 (this->type() == DataSourceItemType::COMPONENT);
138 }
139
131 QString name() const noexcept;
140 QString name() const noexcept;
141 QString icon() const noexcept;
142 void setIcon(const QString& iconName);
132
143
133 /**
144 /**
134 * Get the item's parent
145 * Get the item's parent
135 * @return a pointer to the parent if it exists, nullptr if the item is a root
146 * @return a pointer to the parent if it exists, nullptr if the item is a root
136 */
147 */
137 DataSourceItem* parentItem() const noexcept;
148 DataSourceItem* parentItem() const noexcept;
138
149
139 /**
150 /**
140 * Gets the item's root
151 * Gets the item's root
141 * @return the top parent, the item itself if it's the root item
152 * @return the top parent, the item itself if it's the root item
142 */
153 */
143 const DataSourceItem& rootItem() const noexcept;
154 const DataSourceItem& rootItem() const noexcept;
144
155
145 /**
156 /**
146 * Sets or appends a value to a key
157 * Sets or appends a value to a key
147 * @param key the key
158 * @param key the key
148 * @param value the value
159 * @param value the value
149 * @param append if true, the value is added to the values already existing
160 * @param append if true, the value is added to the values already existing
150 * for the key, otherwise it replaces the existing values
161 * for the key, otherwise it replaces the existing values
151 */
162 */
152 void setData(const QString& key, const QVariant& value,
163 void setData(const QString& key, const QVariant& value,
153 bool append = false) noexcept;
164 bool append = false) noexcept;
154
165
155 DataSourceItemType type() const noexcept;
166 DataSourceItemType type() const noexcept;
156
167
157 /**
168 /**
158 * @brief Searches the first child matching the specified data.
169 * @brief Searches the first child matching the specified data.
159 * @param data The data to search.
170 * @param data The data to search.
160 * @param recursive So the search recursively.
171 * @param recursive So the search recursively.
161 * @return the item matching the data or nullptr if it was not found.
172 * @return the item matching the data or nullptr if it was not found.
162 */
173 */
163 DataSourceItem* findItem(const QVariantHash& data, bool recursive);
174 DataSourceItem* findItem(const QVariantHash& data, bool recursive);
164
175
165 DataSourceItem* findItem(const QString& name);
176 DataSourceItem* findItem(const QString& name);
166
177
167 /**
178 /**
168 * @brief Searches the first child matching the specified \p ID_DATA_KEY in
179 * @brief Searches the first child matching the specified \p ID_DATA_KEY in
169 * its metadata.
180 * its metadata.
170 * @param id The id to search.
181 * @param id The id to search.
171 * @param recursive So the search recursively.
182 * @param recursive So the search recursively.
172 * @return the item matching the data or nullptr if it was not found.
183 * @return the item matching the data or nullptr if it was not found.
173 */
184 */
174 DataSourceItem* findItem(const QString& datasourceIdKey, bool recursive);
185 DataSourceItem* findItem(const QString& datasourceIdKey, bool recursive);
175
186
176 bool operator==(const DataSourceItem& other);
187 bool operator==(const DataSourceItem& other);
177 bool operator!=(const DataSourceItem& other);
188 bool operator!=(const DataSourceItem& other);
178
189
179 iterator_type begin() noexcept;
190 iterator_type begin() noexcept;
180 iterator_type end() noexcept;
191 iterator_type end() noexcept;
181 const_iterator_type begin() const noexcept;
192 const_iterator_type begin() const noexcept;
182 const_iterator_type end() const noexcept;
193 const_iterator_type end() const noexcept;
183 const_iterator_type cbegin() const noexcept;
194 const_iterator_type cbegin() const noexcept;
184 const_iterator_type cend() const noexcept;
195 const_iterator_type cend() const noexcept;
185
196
197 std::optional<QUuid> source_uuid() const noexcept;
198
186 private:
199 private:
187 class DataSourceItemPrivate;
200 struct DataSourceItemPrivate;
188 spimpl::unique_impl_ptr<DataSourceItemPrivate> impl;
201 spimpl::unique_impl_ptr<DataSourceItemPrivate> impl;
189 };
202 };
190
203
191 #endif // SCIQLOP_DATASOURCEITEMMODEL_H
204 #endif // SCIQLOP_DATASOURCEITEMMODEL_H
@@ -1,68 +1,90
1
2 /*------------------------------------------------------------------------------
1 /*------------------------------------------------------------------------------
3 * -- This file is a part of SciQLop
2 * -- This file is a part of SciQLop
4 * -- Copyright (C) 2019, Plasma Physics Laboratory - CNRS
3 * -- Copyright (C) 2019, Plasma Physics Laboratory - CNRS
5 * --
4 * --
6 * -- This program is free software; you can redistribute it and/or modify
5 * -- This program is free software; you can redistribute it and/or modify
7 * -- it under the terms of the GNU General Public License as published by
6 * -- it under the terms of the GNU General Public License as published by
8 * -- the Free Software Foundation; either version 3 of the License, or
7 * -- the Free Software Foundation; either version 3 of the License, or
9 * -- (at your option) any later version.
8 * -- (at your option) any later version.
10 * --
9 * --
11 * -- This program is distributed in the hope that it will be useful,
10 * -- This program is distributed in the hope that it will be useful,
12 * -- but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * -- but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * -- GNU General Public License for more details.
13 * -- GNU General Public License for more details.
15 * --
14 * --
16 * -- You should have received a copy of the GNU General Public License
15 * -- You should have received a copy of the GNU General Public License
17 * -- along with this program; if not, write to the Free Software
16 * -- along with this program; if not, write to the Free Software
18 * -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 * -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 * -------------------------------------------------------------------------------*/
18 * -------------------------------------------------------------------------------*/
20 /* -- Author : Alexis Jeandet
19 /* -- Author : Alexis Jeandet
21 * -- Mail : alexis.jeandet@lpp.polytechnique.fr
20 * -- Mail : alexis.jeandet@lpp.polytechnique.fr
22 * -- alexis.jeandet@member.fsf.org
21 * -- alexis.jeandet@member.fsf.org
23 * ----------------------------------------------------------------------------*/
22 * ----------------------------------------------------------------------------*/
24
23
25 #ifndef DATASOURCES_H
24 #ifndef DATASOURCES_H
26 #define DATASOURCES_H
25 #define DATASOURCES_H
27
26
28 #include "Data/IDataProvider.h"
27 #include "Data/IDataProvider.h"
29 #include "DataSourceItem.h"
28 #include "DataSourceItem.h"
30
29
31 #include <QAbstractItemModel>
30 #include <QAbstractItemModel>
31 #include <QObject>
32 #include <QMimeData>
32
33
33 class DataSources : public QAbstractItemModel
34 class DataSources : public QAbstractItemModel
34 {
35 {
35 Q_OBJECT
36 Q_OBJECT
36
37
37 public:
38 public:
38 enum Roles
39 enum Roles
39 {
40 {
40 CustomRole = Qt::UserRole
41 CustomRole = Qt::UserRole
41 };
42 };
42
43
43 public:
44 public:
44 DataSources() : _root{} {}
45 DataSources() : _root(new DataSourceItem(DataSourceItemType::NODE, "root")) {}
45 ~DataSources() { delete _root; }
46 ~DataSources() { delete _root; }
46
47
47 virtual QVariant data(const QModelIndex& index, int role) const override;
48 virtual QVariant data(const QModelIndex& index, int role) const final;
49 virtual QMimeData* mimeData(const QModelIndexList& indexes) const final;
48
50
49 int columnCount(const QModelIndex& parent) const override;
51 virtual int columnCount(const QModelIndex& parent) const final;
50
52
51 virtual int rowCount(const QModelIndex& parent) const override;
53 virtual int rowCount(const QModelIndex& parent) const final;
52
54
53 QModelIndex parent(const QModelIndex& index) const override;
55 QModelIndex parent(const QModelIndex& index) const final;
54
56
55 virtual QModelIndex index(int row, int column,
57 virtual QModelIndex index(int row, int column,
56 const QModelIndex& parent) const override;
58 const QModelIndex& parent) const final;
59
60 Qt::ItemFlags flags(const QModelIndex& index) const final;
57
61
58 void addDataSourceItem(const QUuid& providerUid, const QString& path,
62 void addDataSourceItem(const QUuid& providerUid, const QString& path,
59 const QMap<QString, QString>& metaData) noexcept;
63 const QMap<QString, QString>& metaData) noexcept;
60
64
61 void addProvider(IDataProvider* provider) noexcept;
65 void addProvider(IDataProvider* provider) noexcept;
62
66
67 void updateNodeMetaData(const QString& path,
68 const QMap<QString, QString>& metaData) noexcept;
69
70 void createVariable(const DataSourceItem& item);
71
72 void addIcon(const QString& name, QVariant icon)
73 {
74 _icons[name] = std::move(icon);
75 }
76
77 void setIcon(const QString& path, const QString& iconName);
78
79 Q_SIGNALS:
80 void createVariable(const QString& variableName,
81 const QVariantHash& variableMetadata,
82 std::shared_ptr<IDataProvider> variableProvider);
83
63 private:
84 private:
64 DataSourceItem* _root;
85 DataSourceItem* _root;
65 std::map<QUuid, std::shared_ptr<IDataProvider>> _DataProviders;
86 std::map<QUuid, std::shared_ptr<IDataProvider>> _DataProviders;
87 QHash<QString, QVariant> _icons;
66 };
88 };
67
89
68 #endif // DATASOURCES_H
90 #endif // DATASOURCES_H
@@ -1,108 +1,110
1
1
2 catalogicpp_dep = dependency('catalogicpp', required : true, fallback:['catalogicpp','catalogicpp_dep'])
2 catalogicpp_dep = dependency('catalogicpp', required : true, fallback:['catalogicpp','catalogicpp_dep'])
3 pybind11_dep = dependency('pybind11', required : true, fallback:['pybind11','pybind11_dep'])
3 pybind11_dep = dependency('pybind11', required : true, fallback:['pybind11','pybind11_dep'])
4 timeseries_dep = dependency('TimeSeries', required : true, fallback:['TimeSeries','time_series_dep'])
4 timeseries_dep = dependency('TimeSeries', required : true, fallback:['TimeSeries','time_series_dep'])
5 cpp_utils_dep = dependency('cpp_utils', fallback:['cpp_utils','cpp_utils_dep'])
5 cpp_utils_dep = dependency('cpp_utils', fallback:['cpp_utils','cpp_utils_dep'])
6
6
7 core_moc_headers = [
7 core_moc_headers = [
8 './include/Common/spimpl.h',
8 './include/Common/spimpl.h',
9 './include/Common/DateUtils.h',
9 './include/Common/DateUtils.h',
10 './include/Common/MimeTypesDef.h',
10 './include/Common/MimeTypesDef.h',
11 './include/Common/SignalWaiter.h',
11 './include/Common/SignalWaiter.h',
12 './include/Common/debug.h',
12 './include/Common/debug.h',
13 './include/Common/MetaTypes.h',
13 './include/Common/MetaTypes.h',
14 './include/Common/SortUtils.h',
14 './include/Common/SortUtils.h',
15 './include/Data/DateTimeRangeHelper.h',
15 './include/Data/DateTimeRangeHelper.h',
16 './include/Data/ScalarTimeSerie.h',
16 './include/Data/ScalarTimeSerie.h',
17 './include/Data/DateTimeRange.h',
17 './include/Data/DateTimeRange.h',
18 './include/Data/DataProviderParameters.h',
18 './include/Data/DataProviderParameters.h',
19 './include/Data/TimeSeriesUtils.h',
19 './include/Data/TimeSeriesUtils.h',
20 './include/Data/VectorTimeSerie.h',
20 './include/Data/VectorTimeSerie.h',
21 './include/Data/SqpIterator.h',
21 './include/Data/SqpIterator.h',
22 './include/Data/IDataProvider.h',
22 './include/Data/IDataProvider.h',
23 './include/Data/SpectrogramTimeSerie.h',
23 './include/Data/SpectrogramTimeSerie.h',
24 './include/Data/MultiComponentTimeSerie.h',
24 './include/Data/MultiComponentTimeSerie.h',
25 './include/Data/DataSeriesType.h',
25 './include/Data/DataSeriesType.h',
26 './include/CoreGlobal.h',
26 './include/CoreGlobal.h',
27 './include/Network/NetworkController.h',
27 './include/Network/NetworkController.h',
28 './include/Network/Response.h',
28 './include/Network/Response.h',
29 './include/Network/Downloader.h',
29 './include/Network/Downloader.h',
30 './include/Settings/SqpSettingsDefs.h',
30 './include/Settings/SqpSettingsDefs.h',
31 './include/Settings/ISqpSettingsBindable.h',
31 './include/Settings/ISqpSettingsBindable.h',
32 './include/DataSource/DataSourceController.h',
32 './include/DataSource/DataSourceController.h',
33 './include/DataSource/datasources.h',
33 './include/DataSource/datasources.h',
34 './include/DataSource/DataSourcesFilter.h',
34 './include/DataSource/DataSourceItem.h',
35 './include/DataSource/DataSourceItem.h',
35 './include/DataSource/DataSourceItemAction.h',
36 './include/DataSource/DataSourceItemAction.h',
36 './include/DataSource/DataSourceItemMergeHelper.h',
37 './include/DataSource/DataSourceItemMergeHelper.h',
37 './include/Time/TimeController.h',
38 './include/Time/TimeController.h',
38 './include/PluginManager/PluginManager.h',
39 './include/PluginManager/PluginManager.h',
39 './include/Version.h',
40 './include/Version.h',
40 './include/Catalogue/CatalogueController.h',
41 './include/Catalogue/CatalogueController.h',
41 './include/Plugin/IPlugin.h',
42 './include/Plugin/IPlugin.h',
42 './include/Variable/VariableModel2.h',
43 './include/Variable/VariableModel2.h',
43 './include/Variable/VariableController2.h',
44 './include/Variable/VariableController2.h',
44 './include/Variable/Variable2.h',
45 './include/Variable/Variable2.h',
45 './include/Variable/VariableSynchronizationGroup2.h',
46 './include/Variable/VariableSynchronizationGroup2.h',
46 './include/Variable/private/VCTransaction.h']
47 './include/Variable/private/VCTransaction.h']
47
48
48
49
49
50
50 core_moc_sources = ['src/Network/Downloader.cpp']
51 core_moc_sources = ['src/Network/Downloader.cpp']
51
52
52
53
53 core_moc_files = qt5.preprocess(moc_headers : core_moc_headers, moc_sources: core_moc_sources)
54 core_moc_files = qt5.preprocess(moc_headers : core_moc_headers, moc_sources: core_moc_sources)
54
55
55 core_sources = ['./src/Common/MimeTypesDef.cpp',
56 core_sources = ['./src/Common/MimeTypesDef.cpp',
56 './src/Common/SignalWaiter.cpp',
57 './src/Common/SignalWaiter.cpp',
57 './src/Common/DateUtils.cpp',
58 './src/Common/DateUtils.cpp',
58 './src/Network/Downloader.cpp',
59 './src/Network/Downloader.cpp',
59 './src/Network/NetworkController.cpp',
60 './src/Network/NetworkController.cpp',
60 './src/Settings/SqpSettingsDefs.cpp',
61 './src/Settings/SqpSettingsDefs.cpp',
61 './src/DataSource/DataSourceItemAction.cpp',
62 './src/DataSource/DataSourceItemAction.cpp',
62 './src/DataSource/DataSourceItemMergeHelper.cpp',
63 './src/DataSource/DataSourceItemMergeHelper.cpp',
63 './src/DataSource/DataSourceItem.cpp',
64 './src/DataSource/DataSourceItem.cpp',
64 './src/DataSource/DataSourceController.cpp',
65 './src/DataSource/DataSourceController.cpp',
65 './src/DataSource/datasources.cpp',
66 './src/DataSource/datasources.cpp',
67 './src/DataSource/DataSourcesFilter.cpp',
66 './src/Time/TimeController.cpp',
68 './src/Time/TimeController.cpp',
67 './src/PluginManager/PluginManager.cpp',
69 './src/PluginManager/PluginManager.cpp',
68 './src/Version.cpp',
70 './src/Version.cpp',
69 './src/Catalogue/CatalogueController.cpp',
71 './src/Catalogue/CatalogueController.cpp',
70 './src/Variable/VariableSynchronizationGroup2.cpp',
72 './src/Variable/VariableSynchronizationGroup2.cpp',
71 './src/Variable/Variable2.cpp',
73 './src/Variable/Variable2.cpp',
72 './src/Variable/VariableController2.cpp',
74 './src/Variable/VariableController2.cpp',
73 './src/Variable/VariableModel2.cpp']
75 './src/Variable/VariableModel2.cpp']
74
76
75
77
76 core_inc = include_directories(['include', 'include/Plugin'])
78 core_inc = include_directories(['include', 'include/Plugin'])
77
79
78 sciqlop_core_lib = library('sciqlopcore',
80 sciqlop_core_lib = library('sciqlopcore',
79 core_sources,
81 core_sources,
80 core_moc_files,
82 core_moc_files,
81 cpp_args : '-DCORE_LIB',
83 cpp_args : '-DCORE_LIB',
82 include_directories : core_inc,
84 include_directories : core_inc,
83 dependencies : [qt5core, qt5network, catalogicpp_dep, pybind11_dep, timeseries_dep, cpp_utils_dep],
85 dependencies : [qt5core, qt5network, catalogicpp_dep, pybind11_dep, timeseries_dep, cpp_utils_dep],
84 install : true
86 install : true
85 )
87 )
86
88
87
89
88 sciqlop_core = declare_dependency(link_with : sciqlop_core_lib,
90 sciqlop_core = declare_dependency(link_with : sciqlop_core_lib,
89 include_directories : core_inc,
91 include_directories : core_inc,
90 dependencies : [qt5core, qt5network, catalogicpp_dep, pybind11_dep, timeseries_dep, cpp_utils_dep])
92 dependencies : [qt5core, qt5network, catalogicpp_dep, pybind11_dep, timeseries_dep, cpp_utils_dep])
91
93
92 pymod = import('python')
94 pymod = import('python')
93 python3 = pymod.find_installation('python3')
95 python3 = pymod.find_installation('python3')
94
96
95 pysciqlopcore_srcs = [
97 pysciqlopcore_srcs = [
96 './src/pybind11_wrappers/CatalogWrappers.cpp',
98 './src/pybind11_wrappers/CatalogWrappers.cpp',
97 './src/pybind11_wrappers/QtWrappers.cpp',
99 './src/pybind11_wrappers/QtWrappers.cpp',
98 './src/pybind11_wrappers/CoreWrappers.cpp'
100 './src/pybind11_wrappers/CoreWrappers.cpp'
99 ]
101 ]
100
102
101 python3.extension_module('pysciqlopcore', './src/pybind11_wrappers/CoreWrappers.cpp',
103 python3.extension_module('pysciqlopcore', './src/pybind11_wrappers/CoreWrappers.cpp',
102 dependencies: [sciqlop_core],
104 dependencies: [sciqlop_core],
103 install: true
105 install: true
104 )
106 )
105
107
106
108
107 subdir('tests')
109 subdir('tests')
108
110
@@ -1,298 +1,299
1 #include "DataSource/DataSourceController.h"
1 #include "DataSource/DataSourceController.h"
2
2
3 #include "DataSource/DataSourceItem.h"
3 #include "DataSource/DataSourceItem.h"
4 #include "DataSource/DataSourceItemAction.h"
4 #include "DataSource/DataSourceItemAction.h"
5
5
6 #include <containers/algorithms.hpp>
6 #include <containers/algorithms.hpp>
7 #include <Data/IDataProvider.h>
7 #include <Data/IDataProvider.h>
8 #include <QDataStream>
8 #include <QDataStream>
9 #include <QDir>
9 #include <QDir>
10 #include <QMutex>
10 #include <QMutex>
11 #include <QStandardPaths>
11 #include <QStandardPaths>
12 #include <QThread>
12 #include <QThread>
13
13
14 Q_LOGGING_CATEGORY(LOG_DataSourceController, "DataSourceController")
14 Q_LOGGING_CATEGORY(LOG_DataSourceController, "DataSourceController")
15
15
16 std::unique_ptr<DataSourceItem> make_folder_item(const QString& name)
16 std::unique_ptr<DataSourceItem> make_folder_item(const QString& name)
17 {
17 {
18 return std::make_unique<DataSourceItem>(DataSourceItemType::NODE, name);
18 return std::make_unique<DataSourceItem>(DataSourceItemType::NODE, name);
19 }
19 }
20
20
21 template<typename T>
21 template<typename T>
22 DataSourceItem* make_path_items(const T& path_list_begin,
22 DataSourceItem* make_path_items(const T& path_list_begin,
23 const T& path_list_end, DataSourceItem* root)
23 const T& path_list_end, DataSourceItem* root)
24 {
24 {
25 std::for_each(path_list_begin, path_list_end,
25 std::for_each(path_list_begin, path_list_end,
26 [&root](const auto& folder_name) mutable {
26 [&root](const auto& folder_name) mutable {
27 auto folder_ptr = root->findItem(folder_name);
27 auto folder_ptr = root->findItem(folder_name);
28 if(folder_ptr == nullptr)
28 if(folder_ptr == nullptr)
29 {
29 {
30 auto folder = make_folder_item(folder_name);
30 auto folder = make_folder_item(folder_name);
31 folder_ptr = folder.get();
31 folder_ptr = folder.get();
32 root->appendChild(std::move(folder));
32 root->appendChild(std::move(folder));
33 }
33 }
34 root = folder_ptr;
34 root = folder_ptr;
35 });
35 });
36 return root;
36 return root;
37 }
37 }
38
38
39 std::unique_ptr<DataSourceItem>
39 std::unique_ptr<DataSourceItem>
40 make_product_item(const QVariantHash& metaData, const QUuid& dataSourceUid,
40 make_product_item(const QVariantHash& metaData, const QUuid& dataSourceUid,
41 const QString& DATA_SOURCE_NAME, DataSourceController* dc)
41 const QString& DATA_SOURCE_NAME, DataSourceController* dc)
42 {
42 {
43 auto productName = metaData.value(DataSourceItem::NAME_DATA_KEY).toString();
43 auto result =
44 auto result =
44 std::make_unique<DataSourceItem>(DataSourceItemType::PRODUCT, metaData);
45 std::make_unique<DataSourceItem>(DataSourceItemType::PRODUCT,productName, metaData);
45
46
46 // Adds plugin name to product metadata
47 // Adds plugin name to product metadata
47 result->setData(DataSourceItem::PLUGIN_DATA_KEY, DATA_SOURCE_NAME);
48 result->setData(DataSourceItem::PLUGIN_DATA_KEY, DATA_SOURCE_NAME);
48 result->setData(DataSourceItem::ID_DATA_KEY,
49 result->setData(DataSourceItem::ID_DATA_KEY,
49 metaData.value(DataSourceItem::NAME_DATA_KEY));
50 metaData.value(DataSourceItem::NAME_DATA_KEY));
50
51
51 auto productName = metaData.value(DataSourceItem::NAME_DATA_KEY).toString();
52
52
53
53 // Add action to load product from DataSourceController
54 // Add action to load product from DataSourceController
54 result->addAction(std::make_unique<DataSourceItemAction>(
55 result->addAction(std::make_unique<DataSourceItemAction>(
55 QObject::tr("Load %1 product").arg(productName),
56 QObject::tr("Load %1 product").arg(productName),
56 [productName, dataSourceUid, dc](DataSourceItem& item) {
57 [productName, dataSourceUid, dc](DataSourceItem& item) {
57 if(dc) { dc->loadProductItem(dataSourceUid, item); }
58 if(dc) { dc->loadProductItem(dataSourceUid, item); }
58 }));
59 }));
59
60
60 return result;
61 return result;
61 }
62 }
62
63
63 class DataSourceController::DataSourceControllerPrivate
64 class DataSourceController::DataSourceControllerPrivate
64 {
65 {
65 public:
66 public:
66 QMutex m_WorkingMutex;
67 QMutex m_WorkingMutex;
67 /// Data sources registered
68 /// Data sources registered
68 QHash<QUuid, QString> m_DataSources;
69 QHash<QUuid, QString> m_DataSources;
69 /// Data sources structures
70 /// Data sources structures
70 std::map<QUuid, std::unique_ptr<DataSourceItem>> m_DataSourceItems;
71 std::map<QUuid, std::unique_ptr<DataSourceItem>> m_DataSourceItems;
71 /// Data providers registered
72 /// Data providers registered
72 /// @remarks Data providers are stored as shared_ptr as they can be sent to a
73 /// @remarks Data providers are stored as shared_ptr as they can be sent to a
73 /// variable and continue to live without necessarily the data source
74 /// variable and continue to live without necessarily the data source
74 /// controller
75 /// controller
75 std::map<QUuid, std::shared_ptr<IDataProvider>> m_DataProviders;
76 std::map<QUuid, std::shared_ptr<IDataProvider>> m_DataProviders;
76
77
77 // Search for the first datasource item matching the specified data
78 // Search for the first datasource item matching the specified data
78 DataSourceItem* findDataSourceItem(const QVariantHash& data)
79 DataSourceItem* findDataSourceItem(const QVariantHash& data)
79 {
80 {
80 DataSourceItem* sourceItem = nullptr;
81 DataSourceItem* sourceItem = nullptr;
81 for(const auto& item : m_DataSourceItems)
82 for(const auto& item : m_DataSourceItems)
82 {
83 {
83 sourceItem = item.second->findItem(data, true);
84 sourceItem = item.second->findItem(data, true);
84 if(sourceItem) { break; }
85 if(sourceItem) { break; }
85 }
86 }
86
87
87 return sourceItem;
88 return sourceItem;
88 }
89 }
89
90
90 // Search for the first datasource item matching the specified ID_DATA_KEY
91 // Search for the first datasource item matching the specified ID_DATA_KEY
91 DataSourceItem* findDataSourceItem(const QString& datasourceIdKey)
92 DataSourceItem* findDataSourceItem(const QString& datasourceIdKey)
92 {
93 {
93 DataSourceItem* sourceItem = nullptr;
94 DataSourceItem* sourceItem = nullptr;
94 for(const auto& item : m_DataSourceItems)
95 for(const auto& item : m_DataSourceItems)
95 {
96 {
96 sourceItem = item.second->findItem(datasourceIdKey, true);
97 sourceItem = item.second->findItem(datasourceIdKey, true);
97 if(sourceItem) { break; }
98 if(sourceItem) { break; }
98 }
99 }
99
100
100 return sourceItem;
101 return sourceItem;
101 }
102 }
102 };
103 };
103
104
104 DataSourceController::DataSourceController(QObject* parent)
105 DataSourceController::DataSourceController(QObject* parent)
105 : impl{spimpl::make_unique_impl<DataSourceControllerPrivate>()}
106 : impl{spimpl::make_unique_impl<DataSourceControllerPrivate>()}
106 {
107 {
107 qCDebug(LOG_DataSourceController())
108 qCDebug(LOG_DataSourceController())
108 << tr("DataSourceController construction") << QThread::currentThread();
109 << tr("DataSourceController construction") << QThread::currentThread();
109 }
110 }
110
111
111 DataSourceController::~DataSourceController()
112 DataSourceController::~DataSourceController()
112 {
113 {
113 qCDebug(LOG_DataSourceController())
114 qCDebug(LOG_DataSourceController())
114 << tr("DataSourceController destruction") << QThread::currentThread();
115 << tr("DataSourceController destruction") << QThread::currentThread();
115 this->waitForFinish();
116 this->waitForFinish();
116 }
117 }
117
118
118 QUuid DataSourceController::registerDataSource(
119 QUuid DataSourceController::registerDataSource(
119 const QString& dataSourceName) noexcept
120 const QString& dataSourceName) noexcept
120 {
121 {
121 auto dataSourceUid = QUuid::createUuid();
122 auto dataSourceUid = QUuid::createUuid();
122 impl->m_DataSources.insert(dataSourceUid, dataSourceName);
123 impl->m_DataSources.insert(dataSourceUid, dataSourceName);
123
124
124 return dataSourceUid;
125 return dataSourceUid;
125 }
126 }
126
127
127 void DataSourceController::registerProvider(IDataProvider *provider) noexcept
128 void DataSourceController::registerProvider(IDataProvider *provider) noexcept
128 {
129 {
129 impl->m_DataSources.insert(provider->id(), provider->name());
130 impl->m_DataSources.insert(provider->id(), provider->name());
130 impl->m_DataProviders.insert({provider->id(), std::unique_ptr<IDataProvider>{provider}});
131 impl->m_DataProviders.insert({provider->id(), std::unique_ptr<IDataProvider>{provider}});
131 // TODO rethink this, I don't get why we have to do this crap
132 // TODO rethink this, I don't get why we have to do this crap
132 // why do we need a root node for each provider
133 // why do we need a root node for each provider
133 setDataSourceItem(provider->id(),make_folder_item(provider->name()));
134 setDataSourceItem(provider->id(),make_folder_item(provider->name()));
134 }
135 }
135
136
136 void DataSourceController::setDataSourceItem(
137 void DataSourceController::setDataSourceItem(
137 const QUuid& dataSourceUid,
138 const QUuid& dataSourceUid,
138 std::unique_ptr<DataSourceItem> dataSourceItem) noexcept
139 std::unique_ptr<DataSourceItem> dataSourceItem) noexcept
139 {
140 {
140 if(!dataSourceItem)
141 if(!dataSourceItem)
141 {
142 {
142 qCWarning(LOG_DataSourceController())
143 qCWarning(LOG_DataSourceController())
143 << tr("Data source item can't be registered (null item)");
144 << tr("Data source item can't be registered (null item)");
144 return;
145 return;
145 }
146 }
146
147
147 if(impl->m_DataSources.contains(dataSourceUid))
148 if(impl->m_DataSources.contains(dataSourceUid))
148 {
149 {
149 // The data provider is implicitly converted to a shared_ptr
150 // The data provider is implicitly converted to a shared_ptr
150 impl->m_DataSourceItems.insert(
151 impl->m_DataSourceItems.insert(
151 std::make_pair(dataSourceUid, std::move(dataSourceItem)));
152 std::make_pair(dataSourceUid, std::move(dataSourceItem)));
152
153
153 // Retrieves the data source item to emit the signal with it
154 // Retrieves the data source item to emit the signal with it
154 auto it = impl->m_DataSourceItems.find(dataSourceUid);
155 auto it = impl->m_DataSourceItems.find(dataSourceUid);
155 if(it != impl->m_DataSourceItems.end())
156 if(it != impl->m_DataSourceItems.end())
156 { emit dataSourceItemSet(it->second.get()); }
157 { emit dataSourceItemSet(it->second.get()); }
157 }
158 }
158 else
159 else
159 {
160 {
160 qCWarning(LOG_DataSourceController())
161 qCWarning(LOG_DataSourceController())
161 << tr("Can't set data source item for uid %1 : no "
162 << tr("Can't set data source item for uid %1 : no "
162 "data source has been registered with the uid")
163 "data source has been registered with the uid")
163 .arg(dataSourceUid.toString());
164 .arg(dataSourceUid.toString());
164 }
165 }
165 }
166 }
166
167
167
168
168
169
169 void DataSourceController::setDataSourceItem(const QUuid& dataSourceUid, const QString& path,
170 void DataSourceController::setDataSourceItem(const QUuid& dataSourceUid, const QString& path,
170 const QMap<QString, QString> &metaData) noexcept
171 const QMap<QString, QString> &metaData) noexcept
171 {
172 {
172 if(auto it = impl->m_DataSourceItems.find(dataSourceUid);
173 if(auto it = impl->m_DataSourceItems.find(dataSourceUid);
173 it != impl->m_DataSourceItems.end())
174 it != impl->m_DataSourceItems.end())
174 {
175 {
175 auto path_list = path.split('/', QString::SkipEmptyParts);
176 auto path_list = path.split('/', QString::SkipEmptyParts);
176 auto name = *(std::cend(path_list) - 1);
177 auto name = *(std::cend(path_list) - 1);
177 auto path_item = make_path_items(
178 auto path_item = make_path_items(
178 std::cbegin(path_list), std::cend(path_list) - 1, it->second.get());
179 std::cbegin(path_list), std::cend(path_list) - 1, it->second.get());
179 QVariantHash meta_data{{DataSourceItem::NAME_DATA_KEY, name}};
180 QVariantHash meta_data{{DataSourceItem::NAME_DATA_KEY, name}};
180 for(auto& key : metaData.keys())
181 for(auto& key : metaData.keys())
181 {
182 {
182 meta_data[key] = metaData[key];
183 meta_data[key] = metaData[key];
183 }
184 }
184 path_item->appendChild(
185 path_item->appendChild(
185 make_product_item(meta_data, dataSourceUid, "test", this));
186 make_product_item(meta_data, dataSourceUid, "test", this));
186 emit dataSourceItemSet(it->second.get());
187 emit dataSourceItemSet(it->second.get());
187 }
188 }
188 }
189 }
189
190
190 void DataSourceController::setDataProvider(
191 void DataSourceController::setDataProvider(
191 const QUuid& dataSourceUid,
192 const QUuid& dataSourceUid,
192 std::unique_ptr<IDataProvider> dataProvider) noexcept
193 std::unique_ptr<IDataProvider> dataProvider) noexcept
193 {
194 {
194 if(impl->m_DataSources.contains(dataSourceUid))
195 if(impl->m_DataSources.contains(dataSourceUid))
195 {
196 {
196 impl->m_DataProviders.insert(
197 impl->m_DataProviders.insert(
197 std::make_pair(dataSourceUid, std::move(dataProvider)));
198 std::make_pair(dataSourceUid, std::move(dataProvider)));
198 }
199 }
199 else
200 else
200 {
201 {
201 qCWarning(LOG_DataSourceController())
202 qCWarning(LOG_DataSourceController())
202 << tr("Can't set data provider for uid %1 : no data "
203 << tr("Can't set data provider for uid %1 : no data "
203 "source has been registered with the uid")
204 "source has been registered with the uid")
204 .arg(dataSourceUid.toString());
205 .arg(dataSourceUid.toString());
205 }
206 }
206 }
207 }
207
208
208 void DataSourceController::loadProductItem(
209 void DataSourceController::loadProductItem(
209 const QUuid& dataSourceUid, const DataSourceItem& productItem) noexcept
210 const QUuid& dataSourceUid, const DataSourceItem& productItem) noexcept
210 {
211 {
211 if(productItem.type() == DataSourceItemType::PRODUCT ||
212 if(productItem.type() == DataSourceItemType::PRODUCT ||
212 productItem.type() == DataSourceItemType::COMPONENT)
213 productItem.type() == DataSourceItemType::COMPONENT)
213 {
214 {
214 /// Retrieves the data provider of the data source (if any)
215 /// Retrieves the data provider of the data source (if any)
215 auto it = impl->m_DataProviders.find(dataSourceUid);
216 auto it = impl->m_DataProviders.find(dataSourceUid);
216 auto dataProvider =
217 auto dataProvider =
217 (it != impl->m_DataProviders.end()) ? it->second : nullptr;
218 (it != impl->m_DataProviders.end()) ? it->second : nullptr;
218
219
219 emit createVariable(productItem.name(), productItem.data(), dataProvider);
220 emit createVariable(productItem.name(), productItem.data(), dataProvider);
220 }
221 }
221 else
222 else
222 {
223 {
223 qCWarning(LOG_DataSourceController())
224 qCWarning(LOG_DataSourceController())
224 << tr("Can't load an item that is not a product");
225 << tr("Can't load an item that is not a product");
225 }
226 }
226 }
227 }
227
228
228 QByteArray
229 QByteArray
229 DataSourceController::mimeDataForProductsData(const QVariantList& productsData)
230 DataSourceController::mimeDataForProductsData(const QVariantList& productsData)
230 {
231 {
231 QByteArray encodedData;
232 QByteArray encodedData;
232 QDataStream stream{&encodedData, QIODevice::WriteOnly};
233 QDataStream stream{&encodedData, QIODevice::WriteOnly};
233
234
234 stream << productsData;
235 stream << productsData;
235
236
236 return encodedData;
237 return encodedData;
237 }
238 }
238
239
239 QVariantList
240 QVariantList
240 DataSourceController::productsDataForMimeData(const QByteArray& mimeData)
241 DataSourceController::productsDataForMimeData(const QByteArray& mimeData)
241 {
242 {
242 QDataStream stream{mimeData};
243 QDataStream stream{mimeData};
243
244
244 QVariantList productList;
245 QVariantList productList;
245 stream >> productList;
246 stream >> productList;
246
247
247 return productList;
248 return productList;
248 }
249 }
249
250
250 void DataSourceController::initialize()
251 void DataSourceController::initialize()
251 {
252 {
252 qCDebug(LOG_DataSourceController())
253 qCDebug(LOG_DataSourceController())
253 << tr("DataSourceController init") << QThread::currentThread();
254 << tr("DataSourceController init") << QThread::currentThread();
254 impl->m_WorkingMutex.lock();
255 impl->m_WorkingMutex.lock();
255 qCDebug(LOG_DataSourceController()) << tr("DataSourceController init END");
256 qCDebug(LOG_DataSourceController()) << tr("DataSourceController init END");
256 }
257 }
257
258
258 void DataSourceController::finalize() { impl->m_WorkingMutex.unlock(); }
259 void DataSourceController::finalize() { impl->m_WorkingMutex.unlock(); }
259
260
260 void DataSourceController::requestVariableFromProductIdKey(
261 void DataSourceController::requestVariableFromProductIdKey(
261 const QString& datasourceIdKey)
262 const QString& datasourceIdKey)
262 {
263 {
263 auto sourceItem = impl->findDataSourceItem(datasourceIdKey);
264 auto sourceItem = impl->findDataSourceItem(datasourceIdKey);
264
265
265 if(sourceItem)
266 if(sourceItem)
266 {
267 {
267 auto sourceName = sourceItem->rootItem().name();
268 auto sourceName = sourceItem->rootItem().name();
268 auto sourceId = impl->m_DataSources.key(sourceName);
269 auto sourceId = impl->m_DataSources.key(sourceName);
269 loadProductItem(sourceId, *sourceItem);
270 loadProductItem(sourceId, *sourceItem);
270 }
271 }
271 else
272 else
272 {
273 {
273 qCWarning(LOG_DataSourceController())
274 qCWarning(LOG_DataSourceController())
274 << tr("requestVariable, product data not found");
275 << tr("requestVariable, product data not found");
275 }
276 }
276 }
277 }
277
278
278 void DataSourceController::requestVariable(const QVariantHash& productData)
279 void DataSourceController::requestVariable(const QVariantHash& productData)
279 {
280 {
280 auto sourceItem = impl->findDataSourceItem(productData);
281 auto sourceItem = impl->findDataSourceItem(productData);
281
282
282 if(sourceItem)
283 if(sourceItem)
283 {
284 {
284 auto sourceName = sourceItem->rootItem().name();
285 auto sourceName = sourceItem->rootItem().name();
285 auto sourceId = impl->m_DataSources.key(sourceName);
286 auto sourceId = impl->m_DataSources.key(sourceName);
286 loadProductItem(sourceId, *sourceItem);
287 loadProductItem(sourceId, *sourceItem);
287 }
288 }
288 else
289 else
289 {
290 {
290 qCWarning(LOG_DataSourceController())
291 qCWarning(LOG_DataSourceController())
291 << tr("requestVariable, product data not found");
292 << tr("requestVariable, product data not found");
292 }
293 }
293 }
294 }
294
295
295 void DataSourceController::waitForFinish()
296 void DataSourceController::waitForFinish()
296 {
297 {
297 QMutexLocker locker{&impl->m_WorkingMutex};
298 QMutexLocker locker{&impl->m_WorkingMutex};
298 }
299 }
@@ -1,273 +1,303
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 #include <DataSource/DataSourceItemMergeHelper.h>
4 #include <QUuid>
4 #include <QVector>
5 #include <QVector>
5 #include <containers/algorithms.hpp>
6 #include <containers/algorithms.hpp>
7 #include <optional>
6
8
7 const QString DataSourceItem::NAME_DATA_KEY = QStringLiteral("name");
9 const QString DataSourceItem::NAME_DATA_KEY = QStringLiteral("name");
8 const QString DataSourceItem::PLUGIN_DATA_KEY = QStringLiteral("plugin");
10 const QString DataSourceItem::PLUGIN_DATA_KEY = QStringLiteral("plugin");
9 const QString DataSourceItem::ID_DATA_KEY = QStringLiteral("uuid");
11 const QString DataSourceItem::ID_DATA_KEY = QStringLiteral("uuid");
10
12
11 struct DataSourceItem::DataSourceItemPrivate
13 struct DataSourceItem::DataSourceItemPrivate
12 {
14 {
13 explicit DataSourceItemPrivate(DataSourceItemType type, QVariantHash data)
15 explicit DataSourceItemPrivate(DataSourceItemType type, const QString& name,
14 : m_Parent{nullptr},
16 QVariantHash data,
15 m_Children{}, m_Type{type}, m_Data{std::move(data)}, m_Actions{}
17 std::optional<QUuid> sourceUUID = std::nullopt)
16 {}
18 : m_Parent{nullptr}, m_dataSourceUid{sourceUUID}, m_Children{},
19 m_name{name}, m_Type{type}, m_Data{std::move(data)}, m_Actions{}
20 {
21 m_Data[DataSourceItem::NAME_DATA_KEY] = name;
22 }
17
23
18 DataSourceItem* m_Parent;
24 DataSourceItem* m_Parent;
25 std::optional<QUuid> m_dataSourceUid = std::nullopt;
19 std::vector<std::unique_ptr<DataSourceItem>> m_Children;
26 std::vector<std::unique_ptr<DataSourceItem>> m_Children;
27 QString m_icon;
28 QString m_name;
20 DataSourceItemType m_Type;
29 DataSourceItemType m_Type;
21 //TODO check if QVariant is really wise here, looks quite overkill
30 // TODO check if QVariant is really wise here, looks quite overkill
22 // maybe a simple map<string,string> could be enough
31 // maybe a simple map<string,string> could be enough
23 QVariantHash m_Data;
32 QVariantHash m_Data;
24 std::vector<std::unique_ptr<DataSourceItemAction>> m_Actions;
33 std::vector<std::unique_ptr<DataSourceItemAction>> m_Actions;
25 auto begin()noexcept{return m_Children.begin();}
34 auto begin() noexcept { return m_Children.begin(); }
26 auto end()noexcept{return m_Children.end();}
35 auto end() noexcept { return m_Children.end(); }
27 auto cbegin()const noexcept{return m_Children.cbegin();}
36 auto cbegin() const noexcept { return m_Children.cbegin(); }
28 auto cend()const noexcept{return m_Children.cend();}
37 auto cend() const noexcept { return m_Children.cend(); }
29
38 inline std::optional<QUuid> source_uuid() const noexcept
39 {
40 return m_dataSourceUid;
41 }
30 int index_of(const DataSourceItem* item)
42 int index_of(const DataSourceItem* item)
31 {
43 {
32 return std::distance(
44 return std::distance(std::cbegin(m_Children),
33 std::cbegin(m_Children), std::find_if(std::cbegin(m_Children), std::cend(m_Children), [item](const auto& other){return other.get()==item;}));
45 std::find_if(std::cbegin(m_Children),
46 std::cend(m_Children),
47 [item](const auto& other) {
48 return other.get() == item;
49 }));
34 }
50 }
51 inline QString name() const noexcept { return m_name; }
52 inline QString icon() const noexcept { return m_icon; }
53 inline void setIcon(const QString& iconName) { m_icon = iconName; }
35 };
54 };
36
55
37 DataSourceItem::DataSourceItem(DataSourceItemType type, const QString& name)
56 // DataSourceItem::DataSourceItem(DataSourceItemType type, const QString& name)
38 : DataSourceItem{type, QVariantHash{{NAME_DATA_KEY, name}}}
57 // : DataSourceItem{type,name, QVariantHash{{NAME_DATA_KEY, name}}}
39 {}
58 //{}
40
59
41 DataSourceItem::DataSourceItem(DataSourceItemType type, QVariantHash data)
60 DataSourceItem::DataSourceItem(DataSourceItemType type, const QString& name,
42 : impl{spimpl::make_unique_impl<DataSourceItemPrivate>(type,
61 QVariantHash data,
43 std::move(data))}
62 std::optional<QUuid> sourceUUID)
63 : impl{spimpl::make_unique_impl<DataSourceItemPrivate>(
64 type, name, std::move(data), sourceUUID)}
44 {}
65 {}
45
66
67 // TODO remove this method ASAP
46 std::unique_ptr<DataSourceItem> DataSourceItem::clone() const
68 std::unique_ptr<DataSourceItem> DataSourceItem::clone() const
47 {
69 {
48 auto result = std::make_unique<DataSourceItem>(impl->m_Type, impl->m_Data);
70 auto result = std::make_unique<DataSourceItem>(impl->m_Type, impl->m_name,
71 impl->m_Data);
49
72
50 // Clones children
73 // Clones children
51 for(const auto& child : impl->m_Children)
74 for(const auto& child : impl->m_Children)
52 {
75 {
53 result->appendChild(std::move(child->clone()));
76 result->appendChild(std::move(child->clone()));
54 }
77 }
55
78
56 // Clones actions
79 // Clones actions
57 for(const auto& action : impl->m_Actions)
80 for(const auto& action : impl->m_Actions)
58 {
81 {
59 result->addAction(std::move(action->clone()));
82 result->addAction(std::move(action->clone()));
60 }
83 }
61
84
62 return result;
85 return result;
63 }
86 }
64
87
65 QVector<DataSourceItemAction*> DataSourceItem::actions() const noexcept
88 QVector<DataSourceItemAction*> DataSourceItem::actions() const noexcept
66 {
89 {
67 auto result = QVector<DataSourceItemAction*>{};
90 auto result = QVector<DataSourceItemAction*>{};
68
91
69 std::transform(std::cbegin(impl->m_Actions), std::cend(impl->m_Actions),
92 std::transform(std::cbegin(impl->m_Actions), std::cend(impl->m_Actions),
70 std::back_inserter(result),
93 std::back_inserter(result),
71 [](const auto& action) { return action.get(); });
94 [](const auto& action) { return action.get(); });
72
95
73 return result;
96 return result;
74 }
97 }
75
98
76 void DataSourceItem::addAction(
99 void DataSourceItem::addAction(
77 std::unique_ptr<DataSourceItemAction> action) noexcept
100 std::unique_ptr<DataSourceItemAction> action) noexcept
78 {
101 {
79 action->setDataSourceItem(this);
102 action->setDataSourceItem(this);
80 impl->m_Actions.push_back(std::move(action));
103 impl->m_Actions.push_back(std::move(action));
81 }
104 }
82
105
83 void DataSourceItem::appendChild(std::unique_ptr<DataSourceItem> child) noexcept
106 void DataSourceItem::appendChild(std::unique_ptr<DataSourceItem> child) noexcept
84 {
107 {
85 child->impl->m_Parent = this;
108 child->impl->m_Parent = this;
86 impl->m_Children.push_back(std::move(child));
109 impl->m_Children.push_back(std::move(child));
87 }
110 }
88
111
89 DataSourceItem* DataSourceItem::child(int childIndex) const noexcept
112 DataSourceItem* DataSourceItem::child(int childIndex) const noexcept
90 {
113 {
91 if(childIndex < 0 || childIndex >= childCount()) { return nullptr; }
114 if(childIndex < 0 || childIndex >= childCount()) { return nullptr; }
92 else
115 else
93 {
116 {
94 return impl->m_Children.at(childIndex).get();
117 return impl->m_Children.at(childIndex).get();
95 }
118 }
96 }
119 }
97
120
98 int DataSourceItem::childCount() const noexcept
121 int DataSourceItem::childCount() const noexcept
99 {
122 {
100 return impl->m_Children.size();
123 return impl->m_Children.size();
101 }
124 }
102
125
103 QVariant DataSourceItem::data(const QString& key) const noexcept
126 QVariant DataSourceItem::data(const QString& key) const noexcept
104 {
127 {
105 return impl->m_Data.value(key);
128 return impl->m_Data.value(key);
106 }
129 }
107
130
108 QVariantHash DataSourceItem::data() const noexcept { return impl->m_Data; }
131 QVariantHash DataSourceItem::data() const noexcept { return impl->m_Data; }
109
132
110 void DataSourceItem::merge(const DataSourceItem& item)
133 void DataSourceItem::merge(const DataSourceItem& item)
111 {
134 {
112 DataSourceItemMergeHelper::merge(item, *this);
135 DataSourceItemMergeHelper::merge(item, *this);
113 }
136 }
114
137
115 bool DataSourceItem::isRoot() const noexcept
138 bool DataSourceItem::isRoot() const noexcept
116 {
139 {
117 return impl->m_Parent == nullptr;
140 return impl->m_Parent == nullptr;
118 }
141 }
119
142
120 QString DataSourceItem::name() const noexcept
143 QString DataSourceItem::name() const noexcept { return impl->name(); }
144
145 QString DataSourceItem::icon() const noexcept { return impl->icon(); }
146
147 void DataSourceItem::setIcon(const QString& iconName)
121 {
148 {
122 return data(NAME_DATA_KEY).toString();
149 impl->setIcon(iconName);
123 }
150 }
124
151
125 DataSourceItem* DataSourceItem::parentItem() const noexcept
152 DataSourceItem* DataSourceItem::parentItem() const noexcept
126 {
153 {
127 return impl->m_Parent;
154 return impl->m_Parent;
128 }
155 }
129
156
130 int DataSourceItem::index() const noexcept
157 int DataSourceItem::index() const noexcept
131 {
158 {
132 if(auto parent = parentItem(); parent)
159 if(auto parent = parentItem(); parent)
133 {
160 { return parent->impl->index_of(this); }
134 return parent->impl->index_of(this);
135 }
136 return 0;
161 return 0;
137 }
162 }
138
163
139 const DataSourceItem& DataSourceItem::rootItem() const noexcept
164 const DataSourceItem& DataSourceItem::rootItem() const noexcept
140 {
165 {
141 return isRoot() ? *this : parentItem()->rootItem();
166 return isRoot() ? *this : parentItem()->rootItem();
142 }
167 }
143
168
144 void DataSourceItem::setData(const QString& key, const QVariant& value,
169 void DataSourceItem::setData(const QString& key, const QVariant& value,
145 bool append) noexcept
170 bool append) noexcept
146 {
171 {
147 auto it = impl->m_Data.constFind(key);
172 auto it = impl->m_Data.constFind(key);
148 if(append && it != impl->m_Data.constEnd())
173 if(append && it != impl->m_Data.constEnd())
149 {
174 {
150 // Case of an existing value to which we want to add to the new value
175 // Case of an existing value to which we want to add to the new value
151 if(it->canConvert<QVariantList>())
176 if(it->canConvert<QVariantList>())
152 {
177 {
153 auto variantList = it->value<QVariantList>();
178 auto variantList = it->value<QVariantList>();
154 variantList.append(value);
179 variantList.append(value);
155
180
156 impl->m_Data.insert(key, variantList);
181 impl->m_Data.insert(key, variantList);
157 }
182 }
158 else
183 else
159 {
184 {
160 impl->m_Data.insert(key, QVariantList{*it, value});
185 impl->m_Data.insert(key, QVariantList{*it, value});
161 }
186 }
162 }
187 }
163 else
188 else
164 {
189 {
165 // Other cases :
190 // Other cases :
166 // - new value in map OR
191 // - new value in map OR
167 // - replacement of an existing value (not appending)
192 // - replacement of an existing value (not appending)
168 impl->m_Data.insert(key, value);
193 impl->m_Data.insert(key, value);
169 }
194 }
170 }
195 }
171
196
172 DataSourceItemType DataSourceItem::type() const noexcept
197 DataSourceItemType DataSourceItem::type() const noexcept
173 {
198 {
174 return impl->m_Type;
199 return impl->m_Type;
175 }
200 }
176
201
177 DataSourceItem* DataSourceItem::findItem(const QVariantHash& data,
202 DataSourceItem* DataSourceItem::findItem(const QVariantHash& data,
178 bool recursive)
203 bool recursive)
179 {
204 {
180 for(const auto& child : impl->m_Children)
205 for(const auto& child : impl->m_Children)
181 {
206 {
182 if(child->impl->m_Data == data) { return child.get(); }
207 if(child->impl->m_Data == data) { return child.get(); }
183
208
184 if(recursive)
209 if(recursive)
185 {
210 {
186 if(auto foundItem = child->findItem(data, true)) { return foundItem; }
211 if(auto foundItem = child->findItem(data, true)) { return foundItem; }
187 }
212 }
188 }
213 }
189
214
190 return nullptr;
215 return nullptr;
191 }
216 }
192
217
193 DataSourceItem* DataSourceItem::findItem(const QString& name)
218 DataSourceItem* DataSourceItem::findItem(const QString& name)
194 {
219 {
195 auto item =
220 auto item =
196 std::find_if(std::cbegin(impl->m_Children), std::cend(impl->m_Children),
221 std::find_if(std::cbegin(impl->m_Children), std::cend(impl->m_Children),
197 [name](const auto& item) { return item->name() == name; });
222 [name](const auto& item) { return item->name() == name; });
198 if(item != std::cend(impl->m_Children)) return item->get();
223 if(item != std::cend(impl->m_Children)) return item->get();
199 return nullptr;
224 return nullptr;
200 }
225 }
201
226
202 DataSourceItem* DataSourceItem::findItem(const QString& datasourceIdKey,
227 DataSourceItem* DataSourceItem::findItem(const QString& datasourceIdKey,
203 bool recursive)
228 bool recursive)
204 {
229 {
205 for(const auto& child : impl->m_Children)
230 for(const auto& child : impl->m_Children)
206 {
231 {
207 auto childId = child->impl->m_Data.value(ID_DATA_KEY);
232 auto childId = child->impl->m_Data.value(ID_DATA_KEY);
208 if(childId == datasourceIdKey) { return child.get(); }
233 if(childId == datasourceIdKey) { return child.get(); }
209
234
210 if(recursive)
235 if(recursive)
211 {
236 {
212 if(auto foundItem = child->findItem(datasourceIdKey, true))
237 if(auto foundItem = child->findItem(datasourceIdKey, true))
213 { return foundItem; }
238 { return foundItem; }
214 }
239 }
215 }
240 }
216
241
217 return nullptr;
242 return nullptr;
218 }
243 }
219
244
220 bool DataSourceItem::operator==(const DataSourceItem& other)
245 bool DataSourceItem::operator==(const DataSourceItem& other)
221 {
246 {
222 // Compares items' attributes
247 // Compares items' attributes
223 if(std::tie(impl->m_Type, impl->m_Data) ==
248 if(std::tie(impl->m_Type, impl->m_Data) ==
224 std::tie(other.impl->m_Type, other.impl->m_Data))
249 std::tie(other.impl->m_Type, other.impl->m_Data))
225 {
250 {
226 // Compares contents of items' children
251 // Compares contents of items' children
227 return std::equal(
252 return std::equal(
228 std::cbegin(impl->m_Children), std::cend(impl->m_Children),
253 std::cbegin(impl->m_Children), std::cend(impl->m_Children),
229 std::cbegin(other.impl->m_Children), std::cend(other.impl->m_Children),
254 std::cbegin(other.impl->m_Children), std::cend(other.impl->m_Children),
230 [](const auto& itemChild, const auto& otherChild) {
255 [](const auto& itemChild, const auto& otherChild) {
231 return *itemChild == *otherChild;
256 return *itemChild == *otherChild;
232 });
257 });
233 }
258 }
234 else
259 else
235 {
260 {
236 return false;
261 return false;
237 }
262 }
238 }
263 }
239
264
240 bool DataSourceItem::operator!=(const DataSourceItem& other)
265 bool DataSourceItem::operator!=(const DataSourceItem& other)
241 {
266 {
242 return !(*this == other);
267 return !(*this == other);
243 }
268 }
244
269
245 DataSourceItem::iterator_type DataSourceItem::begin() noexcept
270 DataSourceItem::iterator_type DataSourceItem::begin() noexcept
246 {
271 {
247 return impl->begin();
272 return impl->begin();
248 }
273 }
249
274
250 DataSourceItem::iterator_type DataSourceItem::end() noexcept
275 DataSourceItem::iterator_type DataSourceItem::end() noexcept
251 {
276 {
252 return impl->end();
277 return impl->end();
253 }
278 }
254
279
255 DataSourceItem::const_iterator_type DataSourceItem::cbegin() const noexcept
280 DataSourceItem::const_iterator_type DataSourceItem::cbegin() const noexcept
256 {
281 {
257 return impl->cbegin();
282 return impl->cbegin();
258 }
283 }
259
284
260 DataSourceItem::const_iterator_type DataSourceItem::cend() const noexcept
285 DataSourceItem::const_iterator_type DataSourceItem::cend() const noexcept
261 {
286 {
262 return impl->cend();
287 return impl->cend();
263 }
288 }
264
289
265 DataSourceItem::const_iterator_type DataSourceItem::begin() const noexcept
290 DataSourceItem::const_iterator_type DataSourceItem::begin() const noexcept
266 {
291 {
267 return impl->cbegin();
292 return impl->cbegin();
268 }
293 }
269
294
270 DataSourceItem::const_iterator_type DataSourceItem::end() const noexcept
295 DataSourceItem::const_iterator_type DataSourceItem::end() const noexcept
271 {
296 {
272 return impl->cend();
297 return impl->cend();
273 }
298 }
299
300 std::optional<QUuid> DataSourceItem::source_uuid() const noexcept
301 {
302 return impl->source_uuid();
303 }
@@ -1,144 +1,288
1 /*------------------------------------------------------------------------------
1 /*------------------------------------------------------------------------------
2 * -- This file is a part of SciQLop
2 * -- This file is a part of SciQLop
3 * -- Copyright (C) 2019, Plasma Physics Laboratory - CNRS
3 * -- Copyright (C) 2019, Plasma Physics Laboratory - CNRS
4 * --
4 * --
5 * -- This program is free software; you can redistribute it and/or modify
5 * -- This program is free software; you can redistribute it and/or modify
6 * -- it under the terms of the GNU General Public License as published by
6 * -- it under the terms of the GNU General Public License as published by
7 * -- the Free Software Foundation; either version 3 of the License, or
7 * -- the Free Software Foundation; either version 3 of the License, or
8 * -- (at your option) any later version.
8 * -- (at your option) any later version.
9 * --
9 * --
10 * -- This program is distributed in the hope that it will be useful,
10 * -- This program is distributed in the hope that it will be useful,
11 * -- but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * -- but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * -- GNU General Public License for more details.
13 * -- GNU General Public License for more details.
14 * --
14 * --
15 * -- You should have received a copy of the GNU General Public License
15 * -- You should have received a copy of the GNU General Public License
16 * -- along with this program; if not, write to the Free Software
16 * -- along with this program; if not, write to the Free Software
17 * -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 * -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 * -------------------------------------------------------------------------------*/
18 * -------------------------------------------------------------------------------*/
19 /*-- Author : Alexis Jeandet
19 /*-- Author : Alexis Jeandet
20 * -- Mail : alexis.jeandet@lpp.polytechnique.fr
20 * -- Mail : alexis.jeandet@lpp.polytechnique.fr
21 * -- alexis.jeandet@member.fsf.org
21 * -- alexis.jeandet@member.fsf.org
22 * ----------------------------------------------------------------------------*/
22 * ----------------------------------------------------------------------------*/
23 // https://doc.qt.io/qt-5/qtwidgets-itemviews-simpletreemodel-example.html
23 // https://doc.qt.io/qt-5/qtwidgets-itemviews-simpletreemodel-example.html
24
24
25 #include "DataSource/datasources.h"
25 #include "DataSource/datasources.h"
26
26
27 #include "Common/MimeTypesDef.h"
28 #include "DataSource/DataSourceItemAction.h"
29 #include "containers/algorithms.hpp"
30
31 #include <QDataStream>
32
33 QString QVariant2QString(const QVariant& variant) noexcept
34 {
35 if(variant.canConvert<QVariantList>())
36 {
37 auto valueString = QStringLiteral("{");
38 auto variantList = variant.value<QVariantList>();
39 QStringList items;
40 std::transform(std::cbegin(variantList), std::cend(variantList),
41 std::back_inserter(items),
42 [](const auto& item) { return QVariant2QString(item); });
43 valueString.append(cpp_utils::containers::join(items, ", "));
44 valueString.append("}");
45 return valueString;
46 }
47 else
48 {
49 return variant.toString();
50 }
51 }
52
27 inline std::unique_ptr<DataSourceItem> make_folder_item(const QString& name)
53 inline std::unique_ptr<DataSourceItem> make_folder_item(const QString& name)
28 {
54 {
29 return std::make_unique<DataSourceItem>(DataSourceItemType::NODE, name);
55 return std::make_unique<DataSourceItem>(DataSourceItemType::NODE, name);
30 }
56 }
31
57
32 template<typename T>
58 template<typename T>
33 DataSourceItem* make_path_items(const T& path_list_begin,
59 DataSourceItem* walk_tree(
34 const T& path_list_end, DataSourceItem* root)
60 const T& path_list_begin, const T& path_list_end, DataSourceItem* root,
61 const std::function<DataSourceItem*(DataSourceItem*, DataSourceItem*,
62 const decltype(*std::declval<T>())&)>&
63 f = [](DataSourceItem* parent, DataSourceItem* node,
64 const auto& name) -> DataSourceItem* {
65 (void)parent;
66 (void)name;
67 return node;
68 })
35 {
69 {
36 std::for_each(path_list_begin, path_list_end,
70 std::for_each(path_list_begin, path_list_end,
37 [&root](const auto& folder_name) mutable {
71 [&root, &f](const auto& folder_name) mutable {
38 auto folder_ptr = root->findItem(folder_name);
72 auto folder_ptr = root->findItem(folder_name);
39 if(folder_ptr == nullptr)
73 root = f(root, folder_ptr, folder_name);
40 {
41 auto folder = make_folder_item(folder_name);
42 folder_ptr = folder.get();
43 root->appendChild(std::move(folder));
44 }
45 root = folder_ptr;
46 });
74 });
47 return root;
75 return root;
48 }
76 }
49
77
78 DataSourceItem* walk_tree(
79 const QString& path, DataSourceItem* root,
80 const std::function<DataSourceItem*(DataSourceItem*, DataSourceItem*,
81 const QString&)>& f =
82 [](DataSourceItem* parent, DataSourceItem* node,
83 const auto& name) -> DataSourceItem* {
84 (void)parent;
85 (void)name;
86 return node;
87 })
88 {
89 auto path_list = path.split('/', QString::SkipEmptyParts);
90 return walk_tree(std::cbegin(path_list), std::cend(path_list), root, f);
91 }
92
93 template<typename T>
94 DataSourceItem* make_path_items(const T& path_list_begin,
95 const T& path_list_end, DataSourceItem* root)
96 {
97 auto node_ctor = [](DataSourceItem* parent, DataSourceItem* node,
98 const auto& name) -> DataSourceItem* {
99 if(node == nullptr)
100 {
101 auto folder = make_folder_item(name);
102 node = folder.get();
103 parent->appendChild(std::move(folder));
104 }
105 return node;
106 };
107 return walk_tree(path_list_begin, path_list_end, root, node_ctor);
108 }
109
50 inline std::unique_ptr<DataSourceItem>
110 inline std::unique_ptr<DataSourceItem>
51 make_product_item(const QVariantHash& metaData, const QUuid& dataSourceUid,
111 make_product_item(const QString& name, QVariantHash& metaData,
52 const QString& DATA_SOURCE_NAME, DataSources* dc)
112 const QUuid& dataSourceUid, const QString& DATA_SOURCE_NAME,
113 DataSources* dataSources)
53 {
114 {
54 auto result =
115 auto result = std::make_unique<DataSourceItem>(DataSourceItemType::PRODUCT,
55 std::make_unique<DataSourceItem>(DataSourceItemType::PRODUCT, metaData);
116 name, metaData, dataSourceUid);
56
117
57 // Adds plugin name to product metadata
118 // Adds plugin name to product metadata
119 // TODO re-consider adding a name attribute to DataSourceItem class
58 result->setData(DataSourceItem::PLUGIN_DATA_KEY, DATA_SOURCE_NAME);
120 result->setData(DataSourceItem::PLUGIN_DATA_KEY, DATA_SOURCE_NAME);
59 result->setData(DataSourceItem::ID_DATA_KEY,
121 // result->setData(DataSourceItem::ID_DATA_KEY,
60 metaData.value(DataSourceItem::NAME_DATA_KEY));
122 // metaData.value(DataSourceItem::NAME_DATA_KEY));
61
62 auto productName = metaData.value(DataSourceItem::NAME_DATA_KEY).toString();
63
123
64 // Add action to load product from DataSourceController
124 // Add action to load product from DataSources
65 // result->addAction(std::make_unique<DataSourceItemAction>(
125 result->addAction(std::make_unique<DataSourceItemAction>(
66 // QObject::tr("Load %1 product").arg(productName),
126 QObject::tr("Load %1 product").arg(name),
67 // [productName, dataSourceUid, dc](DataSourceItem& item) {
127 [dataSources](DataSourceItem& item) {
68 // if(dc) { dc->loadProductItem(dataSourceUid, item); }
128 if(dataSources) { dataSources->createVariable(item); }
69 // }));
129 }));
70
130
71 return result;
131 return result;
72 }
132 }
73
133
74 QVariant DataSources::data(const QModelIndex& index, int role) const
134 QVariant DataSources::data(const QModelIndex& index, int role) const
75 {
135 {
76 if(!index.isValid()) return QVariant();
136 if(!index.isValid()) return QVariant();
77 if(role != Qt::DisplayRole) return QVariant();
78 DataSourceItem* item = static_cast<DataSourceItem*>(index.internalPointer());
137 DataSourceItem* item = static_cast<DataSourceItem*>(index.internalPointer());
79 return item->name();
138 if(role == Qt::DisplayRole) { return item->name(); }
139 if(role == Qt::DecorationRole)
140 { return _icons.value(item->icon(), QVariant{}); }
141 if(role == Qt::ToolTipRole)
142 {
143 auto result = QString{};
144 const auto& data = item->data();
145 std::for_each(data.constKeyValueBegin(), data.constKeyValueEnd(),
146 [&result](const auto& item) {
147 result.append(QString{"<b>%1:</b> %2<br/>"}.arg(
148 item.first, QVariant2QString(item.second)));
149 });
150 return result;
151 }
152 return QVariant();
153 }
154
155 QMimeData* DataSources::mimeData(const QModelIndexList& indexes) const
156 {
157 QVariantList productData;
158 std::for_each(std::cbegin(indexes), std::cend(indexes),
159 [&productData](const auto& index) {
160 if(index.isValid())
161 {
162 DataSourceItem* item =
163 static_cast<DataSourceItem*>(index.internalPointer());
164 if(item->isProductOrComponent())
165 { productData.append(item->data()); }
166 }
167 });
168 // TODO refactor this later
169 // maybe just an encode function
170 QByteArray encodedData;
171 QDataStream stream{&encodedData, QIODevice::WriteOnly};
172 stream << productData;
173 auto mimeData = new QMimeData;
174 mimeData->setData(MIME_TYPE_PRODUCT_LIST, encodedData);
175 return mimeData;
80 }
176 }
81
177
82 int DataSources::columnCount(const QModelIndex& parent) const
178 int DataSources::columnCount(const QModelIndex& parent) const
83 {
179 {
84 (void)parent;
180 (void)parent;
85 return 0;
181 return 1;
86 }
182 }
87
183
88 int DataSources::rowCount(const QModelIndex& parent) const
184 int DataSources::rowCount(const QModelIndex& parent) const
89 {
185 {
90 DataSourceItem* parentItem;
186 DataSourceItem* parentItem;
91 if(parent.column() > 0) return 0;
187 if(parent.column() > 0) return 0;
92 if(!parent.isValid())
188 if(!parent.isValid())
93 parentItem = _root;
189 parentItem = _root;
94 else
190 else
95 parentItem = static_cast<DataSourceItem*>(parent.internalPointer());
191 parentItem = static_cast<DataSourceItem*>(parent.internalPointer());
96 return parentItem->childCount();
192 return parentItem->childCount();
97 }
193 }
98
194
99 QModelIndex DataSources::parent(const QModelIndex& index) const
195 QModelIndex DataSources::parent(const QModelIndex& index) const
100 {
196 {
101 if(!index.isValid()) return QModelIndex();
197 if(!index.isValid()) return QModelIndex();
102 DataSourceItem* childItem =
198 DataSourceItem* childItem =
103 static_cast<DataSourceItem*>(index.internalPointer());
199 static_cast<DataSourceItem*>(index.internalPointer());
104 DataSourceItem* parentItem = childItem->parentItem();
200 DataSourceItem* parentItem = childItem->parentItem();
105 if(parentItem == _root) return QModelIndex();
201 if(parentItem == _root) return QModelIndex();
106 return createIndex(parentItem->index(), 0, parentItem);
202 return createIndex(parentItem->index(), 0, parentItem);
107 }
203 }
108
204
109 QModelIndex DataSources::index(int row, int column,
205 QModelIndex DataSources::index(int row, int column,
110 const QModelIndex& parent) const
206 const QModelIndex& parent) const
111 {
207 {
112 if(!hasIndex(row, column, parent)) return QModelIndex();
208 if(!hasIndex(row, column, parent)) return QModelIndex();
113 DataSourceItem* parentItem;
209 DataSourceItem* parentItem;
114 if(!parent.isValid())
210 if(!parent.isValid())
115 parentItem = _root;
211 parentItem = _root;
116 else
212 else
117 parentItem = static_cast<DataSourceItem*>(parent.internalPointer());
213 parentItem = static_cast<DataSourceItem*>(parent.internalPointer());
118 DataSourceItem* childItem = parentItem->child(row);
214 DataSourceItem* childItem = parentItem->child(row);
119 if(childItem) return createIndex(row, column, childItem);
215 if(childItem) return createIndex(row, column, childItem);
120 return QModelIndex();
216 return QModelIndex();
121 }
217 }
122
218
219 Qt::ItemFlags DataSources::flags(const QModelIndex& index) const
220 {
221 Qt::ItemFlags flags = Qt::NoItemFlags;
222 if(index.isValid())
223 {
224 flags |= Qt::ItemIsSelectable | Qt::ItemIsEnabled;
225 DataSourceItem* item =
226 static_cast<DataSourceItem*>(index.internalPointer());
227 if(item && item->isProductOrComponent())
228 { flags |= Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; }
229 }
230 return flags;
231 }
232
233 // TODO This can be optimized to only use insert row and column
234 // this should be much faster than doing a ResetModel all the time
235 // but this is more difficult to implement
123 void DataSources::addDataSourceItem(
236 void DataSources::addDataSourceItem(
124 const QUuid& providerUid, const QString& path,
237 const QUuid& providerUid, const QString& path,
125 const QMap<QString, QString>& metaData) noexcept
238 const QMap<QString, QString>& metaData) noexcept
126 {
239 {
240 beginResetModel();
127 auto path_list = path.split('/', QString::SkipEmptyParts);
241 auto path_list = path.split('/', QString::SkipEmptyParts);
128 auto name = *(std::cend(path_list) - 1);
242 auto name = *(std::cend(path_list) - 1);
129 auto path_item =
243 auto path_item =
130 make_path_items(std::cbegin(path_list), std::cend(path_list) - 1, _root);
244 make_path_items(std::cbegin(path_list), std::cend(path_list) - 1, _root);
131 QVariantHash meta_data{{DataSourceItem::NAME_DATA_KEY, name}};
245 QVariantHash meta_data{{DataSourceItem::NAME_DATA_KEY, name}};
132 for(auto& key : metaData.keys())
246 for(auto& key : metaData.keys())
133 {
247 {
134 meta_data[key] = metaData[key];
248 meta_data[key] = metaData[key];
135 }
249 }
136 path_item->appendChild(
250 path_item->appendChild(
137 make_product_item(meta_data, providerUid, "test", this));
251 make_product_item(name, meta_data, providerUid, "test", this));
252 endResetModel();
138 }
253 }
139
254
140 void DataSources::addProvider(IDataProvider* provider) noexcept
255 void DataSources::addProvider(IDataProvider* provider) noexcept
141 {
256 {
142 _DataProviders.insert(
257 _DataProviders.insert(
143 {provider->id(), std::unique_ptr<IDataProvider>{provider}});
258 {provider->id(), std::unique_ptr<IDataProvider>{provider}});
144 }
259 }
260
261 void DataSources::updateNodeMetaData(
262 const QString& path, const QMap<QString, QString>& metaData) noexcept
263 {
264 auto node = walk_tree(path, _root);
265 if(node != nullptr)
266 {
267 std::for_each(
268 metaData.constKeyValueBegin(), metaData.constKeyValueEnd(),
269 [node](const auto& it) { node->setData(it.first, it.second, true); });
270 }
271 }
272
273 void DataSources::createVariable(const DataSourceItem& item)
274 {
275 if(auto ds_uuid = item.source_uuid();
276 ds_uuid.has_value() && item.isProductOrComponent())
277 {
278 if(auto data_source_it = _DataProviders.find(ds_uuid.value());
279 data_source_it != std::cend(_DataProviders))
280 emit createVariable(item.name(), item.data(), data_source_it->second);
281 }
282 }
283
284 void DataSources::setIcon(const QString& path, const QString& iconName)
285 {
286 auto node = walk_tree(path, _root);
287 if(node != nullptr) { node->setIcon(iconName); }
288 }
@@ -1,248 +1,250
1 #include <Numeric.h>
1 #include <Numeric.h>
2 #include <Data/DateTimeRange.h>
2 #include <Data/DateTimeRange.h>
3 #include <Data/DateTimeRangeHelper.h>
3 #include <Data/DateTimeRangeHelper.h>
4 #include <QObject>
4 #include <QObject>
5 #include <QUuid>
5 #include <QUuid>
6 #include <QtTest>
6 #include <QtTest>
7 #include <limits>
7 #include <limits>
8
8
9 Q_DECLARE_METATYPE(Seconds<double>);
9 Q_DECLARE_METATYPE(Seconds<double>);
10 Q_DECLARE_METATYPE(DateTimeRangeTransformation);
10 Q_DECLARE_METATYPE(DateTimeRangeTransformation);
11
11
12 DateTimeRange computeZoom(QDateTime start, QDateTime stop, double zoom)
12 DateTimeRange computeZoom(QDateTime start, QDateTime stop, double zoom)
13 {
13 {
14 double start_epoch = start.toMSecsSinceEpoch();
14 double start_epoch = start.toMSecsSinceEpoch();
15 double stop_epoch = stop.toMSecsSinceEpoch();
15 double stop_epoch = stop.toMSecsSinceEpoch();
16 auto delta = stop_epoch - start_epoch;
16 auto delta = stop_epoch - start_epoch;
17 auto dt_ms = (zoom - 1.) * (double(delta)) / 2.;
17 auto dt_ms = (zoom - 1.) * (double(delta)) / 2.;
18 return DateTimeRange{(start_epoch - dt_ms) / 1000.,
18 return DateTimeRange{(start_epoch - dt_ms) / 1000.,
19 (stop_epoch + dt_ms) / 1000.};
19 (stop_epoch + dt_ms) / 1000.};
20 }
20 }
21
21
22 class TestDateTimeRange : public QObject
22 class TestDateTimeRange : public QObject
23 {
23 {
24 Q_OBJECT
24 Q_OBJECT
25
25
26 private slots:
26 private slots:
27 void testRangeDelta_data()
27 void testRangeDelta_data()
28 {
28 {
29 QTest::addColumn<QDateTime>("tstart");
29 QTest::addColumn<QDateTime>("tstart");
30 QTest::addColumn<QDateTime>("tend");
30 QTest::addColumn<QDateTime>("tend");
31 QTest::addColumn<double>("expected");
31 QTest::addColumn<double>("expected");
32 auto now = QDateTime::currentDateTime();
32 auto now = QDateTime::currentDateTime();
33 auto yesterday = QDateTime::currentDateTime().addDays(-1);
33 auto yesterday = now.addDays(-1);
34 QTest::newRow("No delta") << now << now << 0.;
34 QTest::newRow("No delta") << now << now << 0.;
35 QTest::newRow("One day delta") << yesterday << now << 60. * 60. * 24.;
35 QTest::newRow("One day delta") << yesterday << now << 60. * 60. * 24.;
36 QTest::newRow("Minus one day delta")
36 QTest::newRow("Minus one day delta")
37 << now << yesterday << -60. * 60. * 24.;
37 << now << yesterday << -60. * 60. * 24.;
38 }
38 }
39
39
40 void testRangeDelta()
40 void testRangeDelta()
41 {
41 {
42 QFETCH(QDateTime, tstart);
42 QFETCH(QDateTime, tstart);
43 QFETCH(QDateTime, tend);
43 QFETCH(QDateTime, tend);
44 QFETCH(double, expected);
44 QFETCH(double, expected);
45 auto range = DateTimeRange::fromDateTime(tstart, tend);
45 auto range = DateTimeRange::fromDateTime(tstart, tend);
46 double delta = range.delta();
46 double delta = range.delta();
47 // Since it is built from QDateTime don't expect better resolution
47 // Since it is built from QDateTime don't expect better resolution
48 QVERIFY((delta - expected) <= 0.002);
48 QVERIFY((delta - expected) <= 0.002);
49 }
49 }
50
50
51 void testRangeShift_data()
51 void testRangeShift_data()
52 {
52 {
53 QTest::addColumn<DateTimeRange>("initial");
53 QTest::addColumn<DateTimeRange>("initial");
54 QTest::addColumn<Seconds<double>>("shift");
54 QTest::addColumn<Seconds<double>>("shift");
55 QTest::addColumn<DateTimeRange>("expected");
55 QTest::addColumn<DateTimeRange>("expected");
56 auto now = QDateTime::currentDateTime();
56 auto now = QDateTime::currentDateTime();
57 auto yestd = QDateTime::currentDateTime().addDays(-1);
57 auto yestd = QDateTime::currentDateTime().addDays(-1);
58 auto range = DateTimeRange::fromDateTime(yestd, now);
58 auto range = DateTimeRange::fromDateTime(yestd, now);
59 QTest::newRow("No shift") << range << Seconds<double>{0.} << range;
59 QTest::newRow("No shift") << range << Seconds<double>{0.} << range;
60
60
61 QTest::newRow("One milisecond left")
61 QTest::newRow("One milisecond left")
62 << range << Seconds<double>{-.001}
62 << range << Seconds<double>{-.001}
63 << DateTimeRange::fromDateTime(yestd.addMSecs(-1.), now.addMSecs(-1.));
63 << DateTimeRange::fromDateTime(yestd.addMSecs(-1.), now.addMSecs(-1.));
64 QTest::newRow("One milisecond right")
64 QTest::newRow("One milisecond right")
65 << range << Seconds<double>{.001}
65 << range << Seconds<double>{.001}
66 << DateTimeRange::fromDateTime(yestd.addMSecs(1.), now.addMSecs(1.));
66 << DateTimeRange::fromDateTime(yestd.addMSecs(1.), now.addMSecs(1.));
67 QTest::newRow("One second left")
67 QTest::newRow("One second left")
68 << range << Seconds<double>{-1.}
68 << range << Seconds<double>{-1.}
69 << DateTimeRange::fromDateTime(yestd.addSecs(-1.), now.addSecs(-1.));
69 << DateTimeRange::fromDateTime(yestd.addSecs(-1.), now.addSecs(-1.));
70 QTest::newRow("One second right")
70 QTest::newRow("One second right")
71 << range << Seconds<double>{1.}
71 << range << Seconds<double>{1.}
72 << DateTimeRange::fromDateTime(yestd.addSecs(1.), now.addSecs(1.));
72 << DateTimeRange::fromDateTime(yestd.addSecs(1.), now.addSecs(1.));
73 QTest::newRow("One year left")
73 QTest::newRow("One year left")
74 << range << Seconds<double>{-365. * 24. * 60. * 60.}
74 << range << Seconds<double>{-365. * 24. * 60. * 60.}
75 << DateTimeRange::fromDateTime(yestd.addSecs(-365 * 24 * 60 * 60),
75 << DateTimeRange::fromDateTime(yestd.addSecs(-365 * 24 * 60 * 60),
76 now.addSecs(-365 * 24 * 60 * 60));
76 now.addSecs(-365 * 24 * 60 * 60));
77 QTest::newRow("One year right")
77 QTest::newRow("One year right")
78 << range << Seconds<double>{365. * 24. * 60. * 60.}
78 << range << Seconds<double>{365. * 24. * 60. * 60.}
79 << DateTimeRange::fromDateTime(yestd.addSecs(365 * 24 * 60 * 60),
79 << DateTimeRange::fromDateTime(yestd.addSecs(365 * 24 * 60 * 60),
80 now.addSecs(365 * 24 * 60 * 60));
80 now.addSecs(365 * 24 * 60 * 60));
81 }
81 }
82
82
83 void testRangeShift()
83 void testRangeShift()
84 {
84 {
85 QFETCH(DateTimeRange, initial);
85 QFETCH(DateTimeRange, initial);
86 QFETCH(Seconds<double>, shift);
86 QFETCH(Seconds<double>, shift);
87 QFETCH(DateTimeRange, expected);
87 QFETCH(DateTimeRange, expected);
88 QCOMPARE(initial + shift, expected);
88 QCOMPARE(initial + shift, expected);
89 }
89 }
90
90
91 void testRangeZoom_data()
91 void testRangeZoom_data()
92 {
92 {
93 QTest::addColumn<DateTimeRange>("initial");
93 QTest::addColumn<DateTimeRange>("initial");
94 QTest::addColumn<double>("zoom");
94 QTest::addColumn<double>("zoom");
95 QTest::addColumn<DateTimeRange>("expected");
95 QTest::addColumn<DateTimeRange>("expected");
96 auto now = QDateTime::currentDateTime();
96 auto now = QDateTime::currentDateTime();
97 auto yestd = QDateTime::currentDateTime().addDays(-1);
97 auto yestd = QDateTime::currentDateTime().addDays(-1);
98 auto range = DateTimeRange::fromDateTime(yestd, now);
98 auto range = DateTimeRange::fromDateTime(yestd, now);
99 QTest::newRow("No zoom") << range << 1. << range;
99 QTest::newRow("No zoom") << range << 1. << range;
100
100
101 QTest::newRow("Zoom IN 0.001")
101 QTest::newRow("Zoom IN 0.001")
102 << range << 1.001 << computeZoom(yestd, now, 1.001);
102 << range << 1.001 << computeZoom(yestd, now, 1.001);
103 QTest::newRow("Zoom OUT 0.001")
103 QTest::newRow("Zoom OUT 0.001")
104 << range << 0.999 << computeZoom(yestd, now, 0.999);
104 << range << 0.999 << computeZoom(yestd, now, 0.999);
105 }
105 }
106
106 void testRangeZoom()
107 void testRangeZoom()
107 {
108 {
108 QFETCH(DateTimeRange, initial);
109 QFETCH(DateTimeRange, initial);
109 QFETCH(double, zoom);
110 QFETCH(double, zoom);
110 QFETCH(DateTimeRange, expected);
111 QFETCH(DateTimeRange, expected);
111 QCOMPARE(initial * zoom, expected);
112 QCOMPARE(initial * zoom, expected);
112 }
113 }
113
114
114 void testRangeContains_data()
115 void testRangeContains_data()
115 {
116 {
116 QTest::addColumn<DateTimeRange>("range");
117 QTest::addColumn<DateTimeRange>("range");
117 QTest::addColumn<DateTimeRange>("range2");
118 QTest::addColumn<DateTimeRange>("range2");
118 QTest::addColumn<bool>("contains");
119 QTest::addColumn<bool>("contains");
119 auto now = QDateTime::currentDateTime();
120 auto now = QDateTime::currentDateTime();
120 auto yestd = QDateTime::currentDateTime().addDays(-1);
121 auto yestd = QDateTime::currentDateTime().addDays(-1);
121 auto range = DateTimeRange::fromDateTime(yestd, now);
122 auto range = DateTimeRange::fromDateTime(yestd, now);
122 QTest::newRow("Same range") << range << range << true;
123 QTest::newRow("Same range") << range << range << true;
123 QTest::newRow("Smaller range") << range << range * 0.8 << true;
124 QTest::newRow("Smaller range") << range << range * 0.8 << true;
124 QTest::newRow("Bigger range") << range << range * 1.2 << false;
125 QTest::newRow("Bigger range") << range << range * 1.2 << false;
125 QTest::newRow("Shifted range with overlap")
126 QTest::newRow("Shifted range with overlap")
126 << range << range + Seconds<double>{1000.} << false;
127 << range << range + Seconds<double>{1000.} << false;
127 QTest::newRow("Shifted range without overlap")
128 QTest::newRow("Shifted range without overlap")
128 << range << range + Seconds<double>{24. * 60. * 60. * 10} << false;
129 << range << range + Seconds<double>{24. * 60. * 60. * 10} << false;
129 }
130 }
130
131
131 void testRangeContains()
132 void testRangeContains()
132 {
133 {
133 QFETCH(DateTimeRange, range);
134 QFETCH(DateTimeRange, range);
134 QFETCH(DateTimeRange, range2);
135 QFETCH(DateTimeRange, range2);
135 QFETCH(bool, contains);
136 QFETCH(bool, contains);
136 QCOMPARE(range.contains(range2), contains);
137 QCOMPARE(range.contains(range2), contains);
137 }
138 }
138
139
139 void testRangeIntersect_data()
140 void testRangeIntersect_data()
140 {
141 {
141 QTest::addColumn<DateTimeRange>("range");
142 QTest::addColumn<DateTimeRange>("range");
142 QTest::addColumn<DateTimeRange>("range2");
143 QTest::addColumn<DateTimeRange>("range2");
143 QTest::addColumn<bool>("contains");
144 QTest::addColumn<bool>("contains");
144 auto now = QDateTime::currentDateTime();
145 auto now = QDateTime::currentDateTime();
145 auto yestd = QDateTime::currentDateTime().addDays(-1);
146 auto yestd = QDateTime::currentDateTime().addDays(-1);
146 auto tomorrow = QDateTime::currentDateTime().addDays(1);
147 auto tomorrow = QDateTime::currentDateTime().addDays(1);
147 auto range = DateTimeRange::fromDateTime(yestd, now);
148 auto range = DateTimeRange::fromDateTime(yestd, now);
148 auto range2 = DateTimeRange::fromDateTime(now, tomorrow);
149 auto range2 = DateTimeRange::fromDateTime(now, tomorrow);
149 QTest::newRow("Same range") << range << range << true;
150 QTest::newRow("Same range") << range << range << true;
150 QTest::newRow("Smaller range") << range << range * 0.8 << true;
151 QTest::newRow("Smaller range") << range << range * 0.8 << true;
151 QTest::newRow("Bigger range") << range << range * 1.2 << true;
152 QTest::newRow("Bigger range") << range << range * 1.2 << true;
152 QTest::newRow("Shifted range with overlap")
153 QTest::newRow("Shifted range with overlap")
153 << range << range + Seconds<double>{1000.} << true;
154 << range << range + Seconds<double>{1000.} << true;
154 QTest::newRow("Shifted range with overlaping boundary")
155 QTest::newRow("Shifted range with overlaping boundary")
155 << range << range2 << true;
156 << range << range2 << true;
156 QTest::newRow("Shifted range .1 seonds outside")
157 QTest::newRow("Shifted range .1 seonds outside")
157 << range << range2 + Seconds<double>{.1} << false;
158 << range << range2 + Seconds<double>{.1} << false;
158 QTest::newRow("Shifted range without overlap")
159 QTest::newRow("Shifted range without overlap")
159 << range << range + Seconds<double>{24. * 60. * 60. * 10} << false;
160 << range << range + Seconds<double>{24. * 60. * 60. * 10} << false;
160 }
161 }
161
162
162 void testRangeIntersect()
163 void testRangeIntersect()
163 {
164 {
164 QFETCH(DateTimeRange, range);
165 QFETCH(DateTimeRange, range);
165 QFETCH(DateTimeRange, range2);
166 QFETCH(DateTimeRange, range2);
166 QFETCH(bool, contains);
167 QFETCH(bool, contains);
167 QCOMPARE(range.intersect(range2), contains);
168 QCOMPARE(range.intersect(range2), contains);
168 }
169 }
169
170
170 void testRangeTransformations_data()
171 void testRangeTransformations_data()
171 {
172 {
172 QTest::addColumn<DateTimeRange>("range1");
173 QTest::addColumn<DateTimeRange>("range1");
173 QTest::addColumn<DateTimeRange>("range2");
174 QTest::addColumn<DateTimeRange>("range2");
174 QTest::addColumn<DateTimeRangeTransformation>("transformation");
175 QTest::addColumn<DateTimeRangeTransformation>("transformation");
175 auto now = QDateTime::currentDateTime();
176 auto now = QDateTime::currentDateTime();
176 auto yestd = QDateTime::currentDateTime().addDays(-1);
177 auto yestd = QDateTime::currentDateTime().addDays(-1);
177 auto range = DateTimeRange::fromDateTime(yestd, now);
178 auto range = DateTimeRange::fromDateTime(yestd, now);
178
179
179 QTest::newRow("Same range")
180 QTest::newRow("Same range")
180 << range << range
181 << range << range
181 << DateTimeRangeTransformation{1., Seconds<double>{0.}};
182 << DateTimeRangeTransformation{1., Seconds<double>{0.}};
182
183
183 QTest::newRow("Transformatio 1.1x + 10s")
184 QTest::newRow("Transformatio 1.1x + 10s")
184 << range << range * 1.1 + Seconds<double>{10.}
185 << range << range * 1.1 + Seconds<double>{10.}
185 << DateTimeRangeTransformation{1.1, Seconds<double>{10.}};
186 << DateTimeRangeTransformation{1.1, Seconds<double>{10.}};
186
187
187 QTest::newRow("Transformatio 1.x + 10s")
188 QTest::newRow("Transformatio 1.x + 10s")
188 << range << range * 1. + Seconds<double>{10.}
189 << range << range * 1. + Seconds<double>{10.}
189 << DateTimeRangeTransformation{1., Seconds<double>{10.}};
190 << DateTimeRangeTransformation{1., Seconds<double>{10.}};
190
191
191 QTest::newRow("Transformatio 1.1x + 0s")
192 QTest::newRow("Transformatio 1.1x + 0s")
192 << range << range * 1.1 + Seconds<double>{0.}
193 << range << range * 1.1 + Seconds<double>{0.}
193 << DateTimeRangeTransformation{1.1, Seconds<double>{0.}};
194 << DateTimeRangeTransformation{1.1, Seconds<double>{0.}};
194
195
195 QTest::newRow("Transformatio 0.9x - 10s")
196 QTest::newRow("Transformatio 0.9x - 10s")
196 << range << range * 0.9 + Seconds<double>{-10.}
197 << range << range * 0.9 + Seconds<double>{-10.}
197 << DateTimeRangeTransformation{0.9, Seconds<double>{-10.}};
198 << DateTimeRangeTransformation{0.9, Seconds<double>{-10.}};
198 }
199 }
200
199 void testRangeTransformations()
201 void testRangeTransformations()
200 {
202 {
201 QFETCH(DateTimeRange, range1);
203 QFETCH(DateTimeRange, range1);
202 QFETCH(DateTimeRange, range2);
204 QFETCH(DateTimeRange, range2);
203 QFETCH(DateTimeRangeTransformation, transformation);
205 QFETCH(DateTimeRangeTransformation, transformation);
204 auto computed_tr =
206 auto computed_tr =
205 DateTimeRangeHelper::computeTransformation(range1, range2).value();
207 DateTimeRangeHelper::computeTransformation(range1, range2).value();
206 QCOMPARE(computed_tr, transformation);
208 QCOMPARE(computed_tr, transformation);
207 QCOMPARE(range1.transform(transformation), range2);
209 QCOMPARE(range1.transform(transformation), range2);
208 QCOMPARE(range1.transform(computed_tr), range2);
210 QCOMPARE(range1.transform(computed_tr), range2);
209 }
211 }
210
212
211 void testRangeDiff_data()
213 void testRangeDiff_data()
212 {
214 {
213 QTest::addColumn<DateTimeRange>("source");
215 QTest::addColumn<DateTimeRange>("source");
214 QTest::addColumn<DateTimeRange>("destination");
216 QTest::addColumn<DateTimeRange>("destination");
215 QTest::addColumn<int>("count");
217 QTest::addColumn<int>("count");
216 auto now = QDateTime::currentDateTime();
218 auto now = QDateTime::currentDateTime();
217 auto yestd = QDateTime::currentDateTime().addDays(-1);
219 auto yestd = QDateTime::currentDateTime().addDays(-1);
218 auto range = DateTimeRange::fromDateTime(yestd, now);
220 auto range = DateTimeRange::fromDateTime(yestd, now);
219 QTest::newRow("Same range") << range << range << 0;
221 QTest::newRow("Same range") << range << range << 0;
220 QTest::newRow("No missing data (zoom in)") << range << range * 0.9 << 0;
222 QTest::newRow("No missing data (zoom in)") << range << range * 0.9 << 0;
221 QTest::newRow("Missing data on both sides (zoom out)")
223 QTest::newRow("Missing data on both sides (zoom out)")
222 << range << range * 2. << 2;
224 << range << range * 2. << 2;
223 QTest::newRow("Missing data on left side (pan left)")
225 QTest::newRow("Missing data on left side (pan left)")
224 << range << range - Seconds<double>{1000.} << 1;
226 << range << range - Seconds<double>{1000.} << 1;
225 QTest::newRow("Missing data on right side (pan right)")
227 QTest::newRow("Missing data on right side (pan right)")
226 << range << range + Seconds<double>{1000.} << 1;
228 << range << range + Seconds<double>{1000.} << 1;
227 QTest::newRow("Missing data on right side no intersect (big pan right)")
229 QTest::newRow("Missing data on right side no intersect (big pan right)")
228 << range << range + Seconds<double>{24. * 60. * 60. * 2} << 1;
230 << range << range + Seconds<double>{24. * 60. * 60. * 2} << 1;
229 QTest::newRow("Missing data on left side no intersect (big pan left)")
231 QTest::newRow("Missing data on left side no intersect (big pan left)")
230 << range << range - Seconds<double>{24. * 60. * 60. * 2} << 1;
232 << range << range - Seconds<double>{24. * 60. * 60. * 2} << 1;
231 }
233 }
232
234
233 void testRangeDiff()
235 void testRangeDiff()
234 {
236 {
235 QFETCH(DateTimeRange, source);
237 QFETCH(DateTimeRange, source);
236 QFETCH(DateTimeRange, destination);
238 QFETCH(DateTimeRange, destination);
237 QFETCH(int, count);
239 QFETCH(int, count);
238 auto diff = destination - source;
240 auto diff = destination - source;
239 QCOMPARE(diff.size(), count);
241 QCOMPARE(diff.size(), count);
240 for(const auto& range : diff)
242 for(const auto& range : diff)
241 {
243 {
242 QVERIFY(range.delta().value > 0.);
244 QVERIFY(range.delta().value > 0.);
243 }
245 }
244 }
246 }
245 };
247 };
246 QTEST_MAIN(TestDateTimeRange)
248 QTEST_MAIN(TestDateTimeRange)
247
249
248 #include "TestDateTimeRange.moc"
250 #include "TestDateTimeRange.moc"
@@ -1,73 +1,73
1 #include "DataSourceItemBuilder.h"
1 #include "DataSourceItemBuilder.h"
2
2
3 DataSourceItemBuilder &DataSourceItemBuilder::root(const QString &name)
3 DataSourceItemBuilder &DataSourceItemBuilder::root(const QString &name)
4 {
4 {
5 m_Root = std::make_shared<DataSourceItem>(DataSourceItemType::NODE, name);
5 m_Root = std::make_shared<DataSourceItem>(DataSourceItemType::NODE, name);
6 m_Items.push(m_Root.get());
6 m_Items.push(m_Root.get());
7 return *this;
7 return *this;
8 }
8 }
9
9
10 DataSourceItemBuilder &DataSourceItemBuilder::root(QVariantHash data)
10 DataSourceItemBuilder &DataSourceItemBuilder::root(QVariantHash data)
11 {
11 {
12 m_Root = std::make_shared<DataSourceItem>(DataSourceItemType::NODE, data);
12 m_Root = std::make_shared<DataSourceItem>(DataSourceItemType::NODE,data[DataSourceItem::NAME_DATA_KEY].toString(), data);
13 m_Items.push(m_Root.get());
13 m_Items.push(m_Root.get());
14 return *this;
14 return *this;
15 }
15 }
16
16
17 DataSourceItemBuilder &DataSourceItemBuilder::node(const QString &name)
17 DataSourceItemBuilder &DataSourceItemBuilder::node(const QString &name)
18 {
18 {
19 return append(DataSourceItemType::NODE, name);
19 return append(DataSourceItemType::NODE, name);
20 }
20 }
21
21
22 DataSourceItemBuilder &DataSourceItemBuilder::node(QVariantHash data)
22 DataSourceItemBuilder &DataSourceItemBuilder::node(QVariantHash data)
23 {
23 {
24 return append(DataSourceItemType::NODE, std::move(data));
24 return append(DataSourceItemType::NODE,data[DataSourceItem::NAME_DATA_KEY].toString(), std::move(data));
25 }
25 }
26
26
27 DataSourceItemBuilder &DataSourceItemBuilder::product(const QString &name)
27 DataSourceItemBuilder &DataSourceItemBuilder::product(const QString &name)
28 {
28 {
29 return append(DataSourceItemType::PRODUCT, name);
29 return append(DataSourceItemType::PRODUCT, name);
30 }
30 }
31
31
32 DataSourceItemBuilder &DataSourceItemBuilder::product(QVariantHash data)
32 DataSourceItemBuilder &DataSourceItemBuilder::product(QVariantHash data)
33 {
33 {
34 return append(DataSourceItemType::PRODUCT, std::move(data));
34 return append(DataSourceItemType::PRODUCT,data[DataSourceItem::NAME_DATA_KEY].toString(), std::move(data));
35 }
35 }
36
36
37 DataSourceItemBuilder &DataSourceItemBuilder::component(const QString &name)
37 DataSourceItemBuilder &DataSourceItemBuilder::component(const QString &name)
38 {
38 {
39 return append(DataSourceItemType::COMPONENT, name);
39 return append(DataSourceItemType::COMPONENT, name);
40 }
40 }
41
41
42 DataSourceItemBuilder &DataSourceItemBuilder::component(QVariantHash data)
42 DataSourceItemBuilder &DataSourceItemBuilder::component(QVariantHash data)
43 {
43 {
44 return append(DataSourceItemType::COMPONENT, std::move(data));
44 return append(DataSourceItemType::COMPONENT,data[DataSourceItem::NAME_DATA_KEY].toString(), std::move(data));
45 }
45 }
46
46
47 DataSourceItemBuilder &DataSourceItemBuilder::end()
47 DataSourceItemBuilder &DataSourceItemBuilder::end()
48 {
48 {
49 m_Items.pop();
49 m_Items.pop();
50 return *this;
50 return *this;
51 }
51 }
52
52
53 std::shared_ptr<DataSourceItem> DataSourceItemBuilder::build()
53 std::shared_ptr<DataSourceItem> DataSourceItemBuilder::build()
54 {
54 {
55 return m_Root;
55 return m_Root;
56 }
56 }
57
57
58 DataSourceItemBuilder &DataSourceItemBuilder::append(DataSourceItemType type, const QString &name)
58 DataSourceItemBuilder &DataSourceItemBuilder::append(DataSourceItemType type, const QString &name)
59 {
59 {
60 append(type, QVariantHash{{DataSourceItem::NAME_DATA_KEY, name}});
60 append(type,name, QVariantHash{{DataSourceItem::NAME_DATA_KEY, name}});
61 return *this;
61 return *this;
62 }
62 }
63
63
64 DataSourceItemBuilder &DataSourceItemBuilder::append(DataSourceItemType type, QVariantHash data)
64 DataSourceItemBuilder &DataSourceItemBuilder::append(DataSourceItemType type, const QString &name, QVariantHash data)
65 {
65 {
66 auto parentItem = m_Items.top();
66 auto parentItem = m_Items.top();
67
67
68 auto insertIndex = parentItem->childCount();
68 auto insertIndex = parentItem->childCount();
69 parentItem->appendChild(std::make_unique<DataSourceItem>(type, std::move(data)));
69 parentItem->appendChild(std::make_unique<DataSourceItem>(type,name, std::move(data)));
70
70
71 m_Items.push(parentItem->child(insertIndex));
71 m_Items.push(parentItem->child(insertIndex));
72 return *this;
72 return *this;
73 }
73 }
@@ -1,45 +1,45
1 #ifndef SCIQLOP_DATASOURCEITEMBUILDER_H
1 #ifndef SCIQLOP_DATASOURCEITEMBUILDER_H
2 #define SCIQLOP_DATASOURCEITEMBUILDER_H
2 #define SCIQLOP_DATASOURCEITEMBUILDER_H
3
3
4 #include <DataSource/DataSourceItem.h>
4 #include <DataSource/DataSourceItem.h>
5
5
6 #include <memory>
6 #include <memory>
7 #include <stack>
7 #include <stack>
8
8
9 /**
9 /**
10 * @brief The DataSourceItemBuilder class aims to facilitate the creation of a DataSourceItem for unit tests
10 * @brief The DataSourceItemBuilder class aims to facilitate the creation of a DataSourceItem for unit tests
11 * @sa DataSourceItem
11 * @sa DataSourceItem
12 */
12 */
13 class DataSourceItemBuilder {
13 class DataSourceItemBuilder {
14 public:
14 public:
15 /// Inits root item
15 /// Inits root item
16 DataSourceItemBuilder & root(const QString &name);
16 DataSourceItemBuilder & root(const QString &name);
17 DataSourceItemBuilder & root(QVariantHash data);
17 DataSourceItemBuilder & root(QVariantHash data);
18
18
19 /// Adds node into the current item
19 /// Adds node into the current item
20 DataSourceItemBuilder & node(const QString &name);
20 DataSourceItemBuilder & node(const QString &name);
21 DataSourceItemBuilder & node(QVariantHash data);
21 DataSourceItemBuilder & node(QVariantHash data);
22
22
23 /// Adds product into the current item
23 /// Adds product into the current item
24 DataSourceItemBuilder & product(const QString &name);
24 DataSourceItemBuilder & product(const QString &name);
25 DataSourceItemBuilder & product(QVariantHash data);
25 DataSourceItemBuilder & product(QVariantHash data);
26
26
27 /// Adds component into the current item
27 /// Adds component into the current item
28 DataSourceItemBuilder & component(const QString &name);
28 DataSourceItemBuilder & component(const QString &name);
29 DataSourceItemBuilder & component(QVariantHash data);
29 DataSourceItemBuilder & component(QVariantHash data);
30
30
31 /// Closes the build of the current item
31 /// Closes the build of the current item
32 DataSourceItemBuilder& end();
32 DataSourceItemBuilder& end();
33
33
34 /// Creates the DataSourceItem
34 /// Creates the DataSourceItem
35 std::shared_ptr<DataSourceItem> build();
35 std::shared_ptr<DataSourceItem> build();
36
36
37 private:
37 private:
38 DataSourceItemBuilder& append(DataSourceItemType type, const QString &name);
38 DataSourceItemBuilder& append(DataSourceItemType type, const QString &name);
39 DataSourceItemBuilder& append(DataSourceItemType type, QVariantHash data);
39 DataSourceItemBuilder& append(DataSourceItemType type,const QString &name, QVariantHash data);
40
40
41 std::shared_ptr<DataSourceItem> m_Root{nullptr};
41 std::shared_ptr<DataSourceItem> m_Root{nullptr};
42 std::stack<DataSourceItem*> m_Items;
42 std::stack<DataSourceItem*> m_Items;
43 };
43 };
44
44
45 #endif // SCIQLOP_DATASOURCEITEMBUILDER_H
45 #endif // SCIQLOP_DATASOURCEITEMBUILDER_H
@@ -1,49 +1,49
1 #include <DataSource/DataSourceController.h>
1 #include <DataSource/DataSourceController.h>
2 #include <DataSource/DataSourceItem.h>
2 #include <DataSource/DataSourceItem.h>
3
3
4 #include <QObject>
4 #include <QObject>
5 #include <QtTest>
5 #include <QtTest>
6
6
7 #include <memory>
7 #include <memory>
8
8 //TODO remove this
9 class TestDataSourceController : public QObject {
9 class TestDataSourceController : public QObject {
10 Q_OBJECT
10 Q_OBJECT
11 private slots:
11 private slots:
12 void testRegisterDataSource();
12 void testRegisterDataSource();
13 void testSetDataSourceItem();
13 void testSetDataSourceItem();
14 };
14 };
15
15
16 void TestDataSourceController::testRegisterDataSource()
16 void TestDataSourceController::testRegisterDataSource()
17 {
17 {
18 DataSourceController dataSourceController{};
18 DataSourceController dataSourceController{};
19
19
20 auto uid = dataSourceController.registerDataSource(QStringLiteral("Source1"));
20 auto uid = dataSourceController.registerDataSource(QStringLiteral("Source1"));
21 QVERIFY(!uid.isNull());
21 QVERIFY(!uid.isNull());
22 }
22 }
23
23
24 void TestDataSourceController::testSetDataSourceItem()
24 void TestDataSourceController::testSetDataSourceItem()
25 {
25 {
26 DataSourceController dataSourceController{};
26 DataSourceController dataSourceController{};
27
27
28 // Spy to test controllers' signals
28 // Spy to test controllers' signals
29 QSignalSpy signalSpy{&dataSourceController, SIGNAL(dataSourceItemSet(DataSourceItem *))};
29 QSignalSpy signalSpy{&dataSourceController, SIGNAL(dataSourceItemSet(DataSourceItem *))};
30
30
31 // Create a data source item
31 // Create a data source item
32 auto source1Name = QStringLiteral("Source1");
32 auto source1Name = QStringLiteral("Source1");
33 auto source1Item = std::make_unique<DataSourceItem>(DataSourceItemType::PRODUCT, source1Name);
33 auto source1Item = std::make_unique<DataSourceItem>(DataSourceItemType::PRODUCT, source1Name);
34
34
35 // Add data source item to the controller and check that a signal has been emitted after setting
35 // Add data source item to the controller and check that a signal has been emitted after setting
36 // data source item in the controller
36 // data source item in the controller
37 auto source1Uid = dataSourceController.registerDataSource(source1Name);
37 auto source1Uid = dataSourceController.registerDataSource(source1Name);
38 dataSourceController.setDataSourceItem(source1Uid, std::move(source1Item));
38 dataSourceController.setDataSourceItem(source1Uid, std::move(source1Item));
39 QCOMPARE(signalSpy.count(), 1);
39 QCOMPARE(signalSpy.count(), 1);
40
40
41 // Try to a data source item with an unregistered uid and check that no signal has been emitted
41 // Try to a data source item with an unregistered uid and check that no signal has been emitted
42 auto unregisteredUid = QUuid::createUuid();
42 //auto unregisteredUid = QUuid::createUuid();
43 dataSourceController.setDataSourceItem(
43 ///dataSourceController.setDataSourceItem(
44 unregisteredUid, std::make_unique<DataSourceItem>(DataSourceItemType::PRODUCT));
44 // unregisteredUid, std::make_unique<DataSourceItem>(DataSourceItemType::PRODUCT));
45 QCOMPARE(signalSpy.count(), 1);
45 //QCOMPARE(signalSpy.count(), 1);
46 }
46 }
47
47
48 QTEST_MAIN(TestDataSourceController)
48 QTEST_MAIN(TestDataSourceController)
49 #include "TestDataSourceController.moc"
49 #include "TestDataSourceController.moc"
@@ -1,19 +1,28
1 #include <DataSource/datasources.h>
1 #include <DataSource/datasources.h>
2 #include <DataSource/DataSourceItem.h>
2 #include <DataSource/DataSourceItem.h>
3
3
4 #include <QObject>
4 #include <QObject>
5 #include <QtTest>
5 #include <QtTest>
6 #include "TestProviders.h"
6
7
7 class TestDataSources : public QObject {
8 class TestDataSources : public QObject {
8 Q_OBJECT
9 Q_OBJECT
9 private slots:
10 private slots:
10 void addItems();
11 void addItems();
11 };
12 };
12
13
13 void TestDataSources::addItems()
14 void TestDataSources::addItems()
14 {
15 {
16 SimpleRange<1>* provider = new SimpleRange<1>{};
15 DataSources ds;
17 DataSources ds;
18 ds.addProvider(provider);
19 ds.addDataSourceItem(provider->id(),"/test/node1",{});
20 ds.addDataSourceItem(provider->id(),"/test/node2",{});
21 ds.addDataSourceItem(provider->id(),"/test/node3",{});
22 ds.addDataSourceItem(provider->id(),"/test/node4",{});
23 auto rc = ds.rowCount(ds.index(0,0,QModelIndex()));
24 QVERIFY(rc==4);
16 }
25 }
17
26
18 QTEST_MAIN(TestDataSources)
27 QTEST_MAIN(TestDataSources)
19 #include "TestDataSources.moc"
28 #include "TestDataSources.moc"
@@ -1,87 +1,87
1 TestUtils = library('TestUtils', 'TestUtils/TestProviders.h', 'TestUtils/TestProviders.cpp',
1 TestUtils = library('TestUtils', 'TestUtils/TestProviders.h', 'TestUtils/TestProviders.cpp',
2 dependencies : [sciqlop_core, qt5test]
2 dependencies : [sciqlop_core, qt5test]
3 )
3 )
4
4
5
5
6 TestUtils_dep = declare_dependency(link_with : TestUtils,
6 TestUtils_dep = declare_dependency(link_with : TestUtils,
7 include_directories: include_directories('TestUtils'),
7 include_directories: include_directories('TestUtils'),
8 dependencies : [sciqlop_core, qt5test])
8 dependencies : [sciqlop_core, qt5test])
9
9
10
11
12 tests = [
10 tests = [
13 {
11 {
14 'name':'TestSyncGroup',
12 'name':'TestSyncGroup',
15 'sources': ['Variable/TestSyncGroup.cpp'],
13 'sources': ['Variable/TestSyncGroup.cpp'],
16 'deps': [sciqlop_core, qt5test]
14 'deps': [sciqlop_core, qt5test]
17 },
15 },
18 {
16 {
19 'name':'TestDateTimeRange',
17 'name':'TestDateTimeRange',
20 'sources': ['Data/TestDateTimeRange.cpp'],
18 'sources': ['Data/TestDateTimeRange.cpp'],
21 'deps': [sciqlop_core, qt5test]
19 'deps': [sciqlop_core, qt5test]
22 },
20 },
23 {
21 {
24 'name':'TestDataSourceController',
22 'name':'TestDataSourceController',
25 'sources': [
23 'sources': [
26 'DataSource/TestDataSourceController.cpp',
24 'DataSource/TestDataSourceController.cpp',
27 'DataSource/DataSourceItemBuilder.cpp'
25 'DataSource/DataSourceItemBuilder.cpp'
28 ],
26 ],
29 'deps': [sciqlop_core, qt5test]
27 'deps': [sciqlop_core, qt5test]
30 },
28 },
31 {
29 {
32 'name':'TestDataSources',
30 'name':'TestDataSources',
33 'sources': [
31 'sources': [
34 'DataSource/TestDataSources.cpp'
32 'DataSource/TestDataSources.cpp'
35 ],
33 ],
36 'deps': [sciqlop_core, qt5test, TestUtils_dep]
34 'deps': [sciqlop_core, qt5test, TestUtils_dep]
37 },
35 },
38 {
36 {
39 'name':'TestDataSourceItem',
37 'name':'TestDataSourceItem',
40 'sources': [
38 'sources': [
41 'DataSource/TestDataSourceItem.cpp',
39 'DataSource/TestDataSourceItem.cpp',
42 'DataSource/DataSourceItemBuilder.cpp'
40 'DataSource/DataSourceItemBuilder.cpp'
43 ],
41 ],
44 'deps': [sciqlop_core, qt5test]
42 'deps': [sciqlop_core, qt5test]
45 },
43 },
46 {
44 {
47 'name':'TestVariable',
45 'name':'TestVariable',
48 'sources': ['Variable/TestVariable.cpp'],
46 'sources': ['Variable/TestVariable.cpp'],
49 'deps': [sciqlop_core, qt5test]
47 'deps': [sciqlop_core, qt5test]
50 },
48 },
51 {
49 {
52 'name':'TestDownloader',
50 'name':'TestDownloader',
53 'sources': ['Network/TestDownloader.cpp'],
51 'sources': ['Network/TestDownloader.cpp'],
54 'deps': [sciqlop_core, qt5test, qt5Concurrent]
52 'deps': [sciqlop_core, qt5test, qt5Concurrent]
55 },
53 },
56 {
54 {
57 'name':'TestVariableController2',
55 'name':'TestVariableController2',
58 'sources': ['Variable/TestVariableController2.cpp'],
56 'sources': ['Variable/TestVariableController2.cpp'],
59 'deps': [sciqlop_core, qt5test, qt5Concurrent, TestUtils_dep]
57 'deps': [sciqlop_core, qt5test, qt5Concurrent, TestUtils_dep]
60 },
58 },
61 {
59 {
62 'name':'TestVariableController2Async',
60 'name':'TestVariableController2Async',
63 'sources': ['Variable/TestVariableController2Async.cpp'],
61 'sources': ['Variable/TestVariableController2Async.cpp'],
64 'deps': [sciqlop_core, qt5test, qt5Concurrent, TestUtils_dep]
62 'deps': [sciqlop_core, qt5test, qt5Concurrent, TestUtils_dep]
65 },
63 },
66 {
64 {
67 'name':'TestVariableController2WithSync',
65 'name':'TestVariableController2WithSync',
68 'sources': ['Variable/TestVariableController2WithSync.cpp'],
66 'sources': ['Variable/TestVariableController2WithSync.cpp'],
69 'deps': [sciqlop_core, qt5test, qt5Concurrent, TestUtils_dep]
67 'deps': [sciqlop_core, qt5test, qt5Concurrent, TestUtils_dep]
70 }
68 }
71 ]
69 ]
72
70
73 foreach unit_test : tests
71 foreach unit_test : tests
74 test_moc_files = qt5.preprocess(moc_sources : unit_test['sources'])
72 test_moc_files = qt5.preprocess(moc_sources : unit_test['sources'])
75 test_exe = executable(unit_test['name'],unit_test['sources'] , test_moc_files,
73 test_exe = executable(unit_test['name'],unit_test['sources'] , test_moc_files,
76 dependencies : unit_test['deps'],
74 dependencies : unit_test['deps'],
77 cpp_args : ['-DCORE_TESTS_RESOURCES_DIR="'+meson.current_source_dir()+'/../tests-resources"']
75 cpp_args : ['-DCORE_TESTS_RESOURCES_DIR="'+meson.current_source_dir()+'/../tests-resources"']
78 )
76 )
79 if get_option('teamcity')
77 if get_option('teamcity')
80 test_exe_args = ['-teamcity', '-o', '@0@.teamcity.txt'.format(unit_test['name'])]
78 test_exe_args = ['-teamcity', '-o', '@0@.teamcity.txt'.format(unit_test['name'])]
81 else
79 else
82 test_exe_args = []
80 test_exe_args = []
83 endif
81 endif
84 test('Test-' + unit_test['name'], test_exe, args: test_exe_args)
82 test('Test-' + unit_test['name'], test_exe, args: test_exe_args)
85
83
86 endforeach
84 endforeach
87
85
86 datasources_manual_test_exe = executable('datasources_manual_test', 'DataSource/DataSourcesManualTest.cpp', dependencies :[sciqlop_core,
87 TestUtils_dep, qt5gui, qt5widgets])
General Comments 0
You need to be logged in to leave comments. Login now