##// END OF EJS Templates
The mock plugin can now create data with view operation
perrinel -
r235:746eaca503e3
parent child
Show More
@@ -1,45 +1,54
1 1 #ifndef SCIQLOP_VARIABLE_H
2 2 #define SCIQLOP_VARIABLE_H
3 3
4 4 #include <Data/SqpDateTime.h>
5 5
6 6
7 7 #include <QLoggingCategory>
8 8 #include <QObject>
9 9
10 10 #include <Common/spimpl.h>
11 11
12 12 Q_DECLARE_LOGGING_CATEGORY(LOG_Variable)
13 13
14 14 class IDataSeries;
15 15 class QString;
16 16
17 17 /**
18 18 * @brief The Variable class represents a variable in SciQlop.
19 19 */
20 class Variable {
20 class Variable : public QObject {
21
22 Q_OBJECT
23
21 24 public:
22 25 explicit Variable(const QString &name, const QString &unit, const QString &mission,
23 26 const SqpDateTime &dateTime);
24 27
25 28 QString name() const noexcept;
26 29 QString mission() const noexcept;
27 30 QString unit() const noexcept;
28
29 void addDataSeries(std::unique_ptr<IDataSeries> dataSeries) noexcept;
31 SqpDateTime dateTime() const noexcept;
30 32
31 33 /// @return the data of the variable, nullptr if there is no data
32 34 IDataSeries *dataSeries() const noexcept;
33 35
36 bool contains(SqpDateTime dateTime);
37 void setDataSeries(std::unique_ptr<IDataSeries> dataSeries) noexcept;
38
34 39 public slots:
35 void onXRangeChanged(SqpDateTime dateTime);
40 void onAddDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept;
41
42 signals:
43 void dataCacheUpdated();
44
36 45
37 46 private:
38 47 class VariablePrivate;
39 48 spimpl::unique_impl_ptr<VariablePrivate> impl;
40 49 };
41 50
42 51 // Required for using shared_ptr in signals/slots
43 52 Q_DECLARE_METATYPE(std::shared_ptr<Variable>)
44 53
45 54 #endif // SCIQLOP_VARIABLE_H
@@ -1,51 +1,58
1 1 #ifndef SCIQLOP_VARIABLECONTROLLER_H
2 2 #define SCIQLOP_VARIABLECONTROLLER_H
3 3
4 #include <Data/SqpDateTime.h>
5
4 6 #include <QLoggingCategory>
5 7 #include <QObject>
6 8
7 9 #include <Common/spimpl.h>
8 10
11
9 12 class IDataProvider;
10 13 class TimeController;
11 14 class Variable;
12 15 class VariableModel;
13 16
14 17 Q_DECLARE_LOGGING_CATEGORY(LOG_VariableController)
15 18
16 19 /**
17 20 * @brief The VariableController class aims to handle the variables in SciQlop.
18 21 */
19 22 class VariableController : public QObject {
20 23 Q_OBJECT
21 24 public:
22 25 explicit VariableController(QObject *parent = 0);
23 26 virtual ~VariableController();
24 27
25 28 VariableModel *variableModel() noexcept;
26 29
27 30 void setTimeController(TimeController *timeController) noexcept;
28 31
32
33 /// Request the data loading of the variable whithin dateTime
34 void requestDataLoading(std::shared_ptr<Variable> variable, const SqpDateTime &dateTime);
35
29 36 signals:
30 37 /// Signal emitted when a variable has been created
31 38 void variableCreated(std::shared_ptr<Variable> variable);
32 39
33 40 public slots:
34 41 /**
35 42 * Creates a new variable and adds it to the model
36 43 * @param name the name of the new variable
37 44 * @param provider the data provider for the new variable
38 45 */
39 46 void createVariable(const QString &name, std::shared_ptr<IDataProvider> provider) noexcept;
40 47
41 48 void initialize();
42 49 void finalize();
43 50
44 51 private:
45 52 void waitForFinish();
46 53
47 54 class VariableControllerPrivate;
48 55 spimpl::unique_impl_ptr<VariableControllerPrivate> impl;
49 56 };
50 57
51 58 #endif // SCIQLOP_VARIABLECONTROLLER_H
@@ -1,74 +1,89
1 1 #include "Variable/Variable.h"
2 2
3 3 #include <Data/IDataSeries.h>
4 4 #include <Data/SqpDateTime.h>
5 5
6 6 Q_LOGGING_CATEGORY(LOG_Variable, "Variable")
7 7
8 8 struct Variable::VariablePrivate {
9 9 explicit VariablePrivate(const QString &name, const QString &unit, const QString &mission,
10 10 const SqpDateTime &dateTime)
11 11 : m_Name{name},
12 12 m_Unit{unit},
13 13 m_Mission{mission},
14 14 m_DateTime{dateTime},
15 15 m_DataSeries{nullptr}
16 16 {
17 17 }
18 18
19 19 QString m_Name;
20 20 QString m_Unit;
21 21 QString m_Mission;
22 22
23 23 SqpDateTime m_DateTime; // The dateTime available in the view and loaded. not the cache.
24 24 std::unique_ptr<IDataSeries> m_DataSeries;
25 25 };
26 26
27 27 Variable::Variable(const QString &name, const QString &unit, const QString &mission,
28 28 const SqpDateTime &dateTime)
29 29 : impl{spimpl::make_unique_impl<VariablePrivate>(name, unit, mission, dateTime)}
30 30 {
31 31 }
32 32
33 33 QString Variable::name() const noexcept
34 34 {
35 35 return impl->m_Name;
36 36 }
37 37
38 38 QString Variable::mission() const noexcept
39 39 {
40 40 return impl->m_Mission;
41 41 }
42 42
43 43 QString Variable::unit() const noexcept
44 44 {
45 45 return impl->m_Unit;
46 46 }
47 47
48 void Variable::addDataSeries(std::unique_ptr<IDataSeries> dataSeries) noexcept
48 SqpDateTime Variable::dateTime() const noexcept
49 {
50 return impl->m_DateTime;
51 }
52
53 void Variable::setDataSeries(std::unique_ptr<IDataSeries> dataSeries) noexcept
49 54 {
50 55 if (!impl->m_DataSeries) {
51 56 impl->m_DataSeries = std::move(dataSeries);
52 57 }
53 /// @todo : else, merge the two data series (if possible)
58 }
59
60 void Variable::onAddDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept
61 {
62 if (impl->m_DataSeries) {
63 impl->m_DataSeries->merge(dataSeries.get());
64
65 emit dataCacheUpdated();
66 }
54 67 }
55 68
56 69 IDataSeries *Variable::dataSeries() const noexcept
57 70 {
58 71 return impl->m_DataSeries.get();
59 72 }
60 73
61 void Variable::onXRangeChanged(SqpDateTime dateTime)
74 bool Variable::contains(SqpDateTime dateTime)
62 75 {
63 qCInfo(LOG_Variable()) << "onXRangeChanged detected";
64
65 76 if (!impl->m_DateTime.contains(dateTime)) {
66 77 // The current variable dateTime isn't enough to display the dateTime requested.
67 78 // We have to update it to the new dateTime requested.
68 79 // the correspondant new data to display will be given by the cache if possible and the
69 80 // provider if necessary.
70 81 qCInfo(LOG_Variable()) << "NEW DATE NEEDED";
71 82
72 83 impl->m_DateTime = dateTime;
84
85 return false;
73 86 }
87
88 return true;
74 89 }
@@ -1,123 +1,164
1 #include <Variable/Variable.h>
1 2 #include <Variable/VariableCacheController.h>
2 3 #include <Variable/VariableController.h>
3 4 #include <Variable/VariableModel.h>
4 5
5 6 #include <Data/DataProviderParameters.h>
6 7 #include <Data/IDataProvider.h>
7 8 #include <Data/IDataSeries.h>
8 9 #include <Time/TimeController.h>
9 10
10 11 #include <QDateTime>
12 #include <QElapsedTimer>
11 13 #include <QMutex>
12 14 #include <QThread>
13 15
14 16 #include <unordered_map>
15 17
16 18 Q_LOGGING_CATEGORY(LOG_VariableController, "VariableController")
17 19
18 20 namespace {
19 21
20 22 /// @todo Generates default dataseries, according to the provider passed in parameter. This method
21 23 /// will be deleted when the timerange is recovered from SciQlop
22 24 std::unique_ptr<IDataSeries> generateDefaultDataSeries(const IDataProvider &provider,
23 25 const SqpDateTime &dateTime) noexcept
24 26 {
25 27 auto parameters = DataProviderParameters{dateTime};
26 28
27 29 return provider.retrieveData(parameters);
28 30 }
29 31
30 32 } // namespace
31 33
32 34 struct VariableController::VariableControllerPrivate {
33 35 explicit VariableControllerPrivate(VariableController *parent)
34 36 : m_WorkingMutex{},
35 37 m_VariableModel{new VariableModel{parent}},
36 38 m_VariableCacheController{std::make_unique<VariableCacheController>()}
37 39 {
38 40 }
39 41
40 42 QMutex m_WorkingMutex;
41 43 /// Variable model. The VariableController has the ownership
42 44 VariableModel *m_VariableModel;
43 45
44 46
45 47 TimeController *m_TimeController{nullptr};
46 48 std::unique_ptr<VariableCacheController> m_VariableCacheController;
49
50 std::unordered_map<std::shared_ptr<Variable>, std::shared_ptr<IDataProvider> >
51 m_VariableToProviderMap;
47 52 };
48 53
49 54 VariableController::VariableController(QObject *parent)
50 55 : QObject{parent}, impl{spimpl::make_unique_impl<VariableControllerPrivate>(this)}
51 56 {
52 57 qCDebug(LOG_VariableController()) << tr("VariableController construction")
53 58 << QThread::currentThread();
54 59 }
55 60
56 61 VariableController::~VariableController()
57 62 {
58 63 qCDebug(LOG_VariableController()) << tr("VariableController destruction")
59 64 << QThread::currentThread();
60 65 this->waitForFinish();
61 66 }
62 67
63 68 VariableModel *VariableController::variableModel() noexcept
64 69 {
65 70 return impl->m_VariableModel;
66 71 }
67 72
68 73 void VariableController::setTimeController(TimeController *timeController) noexcept
69 74 {
70 75 impl->m_TimeController = timeController;
71 76 }
72 77
73 78 void VariableController::createVariable(const QString &name,
74 79 std::shared_ptr<IDataProvider> provider) noexcept
75 80 {
76 // TORM
77 // auto dateTime = SqpDateTime{
78 // // Remarks : we don't use toSecsSinceEpoch() here (method is for Qt 5.8 or above)
79 // static_cast<double>(QDateTime{QDate{2017, 01, 01}, QTime{12, 00}}.toMSecsSinceEpoch()
80 // / 1000.),
81 // static_cast<double>(QDateTime{QDate{2017, 01, 01}, QTime{12, 01}}.toMSecsSinceEpoch())
82 // / 1000.};
83 81
84 82 if (!impl->m_TimeController) {
85 83 qCCritical(LOG_VariableController())
86 84 << tr("Impossible to create variable: The time controller is null");
87 85 return;
88 86 }
89 87
90 88
91 89 /// @todo : for the moment :
92 90 /// - the provider is only used to retrieve data from the variable for its initialization, but
93 91 /// it will be retained later
94 92 /// - default data are generated for the variable, without taking into account the timerange set
95 93 /// in sciqlop
96 94 auto dateTime = impl->m_TimeController->dateTime();
97 95 if (auto newVariable = impl->m_VariableModel->createVariable(
98 96 name, dateTime, generateDefaultDataSeries(*provider, dateTime))) {
99 97
98 // store the provider
99 impl->m_VariableToProviderMap[newVariable] = provider;
100 qRegisterMetaType<std::shared_ptr<IDataSeries> >();
101 qRegisterMetaType<SqpDateTime>();
102 connect(provider.get(), &IDataProvider::dataProvided, newVariable.get(),
103 &Variable::onAddDataSeries);
104
105
100 106 // store in cache
101 107 impl->m_VariableCacheController->addDateTime(newVariable, dateTime);
102 108
103 109 // notify the creation
104 110 emit variableCreated(newVariable);
105 111 }
106 112 }
107 113
114
115 void VariableController::requestDataLoading(std::shared_ptr<Variable> variable,
116 const SqpDateTime &dateTime)
117 {
118 // we want to load data of the variable for the dateTime.
119 // First we check if the cache contains some of them.
120 // For the other, we ask the provider to give them.
121 if (variable) {
122
123 QElapsedTimer timer;
124 timer.start();
125 qCInfo(LOG_VariableController()) << "The slow s0 operation took" << timer.elapsed()
126 << "milliseconds";
127 auto dateTimeListNotInCache
128 = impl->m_VariableCacheController->provideNotInCacheDateTimeList(variable, dateTime);
129 qCInfo(LOG_VariableController()) << "The slow s1 operation took" << timer.elapsed()
130 << "milliseconds";
131
132 // Ask the provider for each data on the dateTimeListNotInCache
133 impl->m_VariableToProviderMap.at(variable)->requestDataLoading(dateTimeListNotInCache);
134
135 qCInfo(LOG_VariableController()) << "The slow s2 operation took" << timer.elapsed()
136 << "milliseconds";
137
138 // store in cache
139 impl->m_VariableCacheController->addDateTime(variable, dateTime);
140 qCInfo(LOG_VariableController()) << "The slow s3 operation took" << timer.elapsed()
141 << "milliseconds";
142 }
143 else {
144 qCCritical(LOG_VariableController()) << tr("Impossible to load data of a variable null");
145 }
146 }
147
148
108 149 void VariableController::initialize()
109 150 {
110 151 qCDebug(LOG_VariableController()) << tr("VariableController init") << QThread::currentThread();
111 152 impl->m_WorkingMutex.lock();
112 153 qCDebug(LOG_VariableController()) << tr("VariableController init END");
113 154 }
114 155
115 156 void VariableController::finalize()
116 157 {
117 158 impl->m_WorkingMutex.unlock();
118 159 }
119 160
120 161 void VariableController::waitForFinish()
121 162 {
122 163 QMutexLocker locker{&impl->m_WorkingMutex};
123 164 }
@@ -1,120 +1,120
1 1 #include <Variable/Variable.h>
2 2 #include <Variable/VariableModel.h>
3 3
4 4 #include <Data/IDataSeries.h>
5 5
6 6 Q_LOGGING_CATEGORY(LOG_VariableModel, "VariableModel")
7 7
8 8 namespace {
9 9
10 10 // Column indexes
11 11 const auto NAME_COLUMN = 0;
12 12 const auto UNIT_COLUMN = 1;
13 13 const auto MISSION_COLUMN = 2;
14 14 const auto NB_COLUMNS = 3;
15 15
16 16 } // namespace
17 17
18 18 struct VariableModel::VariableModelPrivate {
19 19 /// Variables created in SciQlop
20 20 std::vector<std::shared_ptr<Variable> > m_Variables;
21 21 };
22 22
23 23 VariableModel::VariableModel(QObject *parent)
24 24 : QAbstractTableModel{parent}, impl{spimpl::make_unique_impl<VariableModelPrivate>()}
25 25 {
26 26 }
27 27
28 28 std::shared_ptr<Variable>
29 29 VariableModel::createVariable(const QString &name, const SqpDateTime &dateTime,
30 30 std::unique_ptr<IDataSeries> defaultDataSeries) noexcept
31 31 {
32 32 auto insertIndex = rowCount();
33 33 beginInsertRows({}, insertIndex, insertIndex);
34 34
35 35 /// @todo For the moment, the other data of the variable is initialized with default values
36 36 auto variable = std::make_shared<Variable>(name, QStringLiteral("unit"),
37 37 QStringLiteral("mission"), dateTime);
38 variable->addDataSeries(std::move(defaultDataSeries));
38 variable->setDataSeries(std::move(defaultDataSeries));
39 39
40 40 impl->m_Variables.push_back(variable);
41 41
42 42 endInsertRows();
43 43
44 44 return variable;
45 45 }
46 46
47 47 int VariableModel::columnCount(const QModelIndex &parent) const
48 48 {
49 49 Q_UNUSED(parent);
50 50
51 51 return NB_COLUMNS;
52 52 }
53 53
54 54 int VariableModel::rowCount(const QModelIndex &parent) const
55 55 {
56 56 Q_UNUSED(parent);
57 57
58 58 return impl->m_Variables.size();
59 59 }
60 60
61 61 QVariant VariableModel::data(const QModelIndex &index, int role) const
62 62 {
63 63 if (!index.isValid()) {
64 64 return QVariant{};
65 65 }
66 66
67 67 if (index.row() < 0 || index.row() >= rowCount()) {
68 68 return QVariant{};
69 69 }
70 70
71 71 if (role == Qt::DisplayRole) {
72 72 if (auto variable = impl->m_Variables.at(index.row()).get()) {
73 73 switch (index.column()) {
74 74 case NAME_COLUMN:
75 75 return variable->name();
76 76 case UNIT_COLUMN:
77 77 return variable->unit();
78 78 case MISSION_COLUMN:
79 79 return variable->mission();
80 80 default:
81 81 // No action
82 82 break;
83 83 }
84 84
85 85 qWarning(LOG_VariableModel())
86 86 << tr("Can't get data (unknown column %1)").arg(index.column());
87 87 }
88 88 else {
89 89 qWarning(LOG_VariableModel()) << tr("Can't get data (no variable)");
90 90 }
91 91 }
92 92
93 93 return QVariant{};
94 94 }
95 95
96 96 QVariant VariableModel::headerData(int section, Qt::Orientation orientation, int role) const
97 97 {
98 98 if (role != Qt::DisplayRole) {
99 99 return QVariant{};
100 100 }
101 101
102 102 if (orientation == Qt::Horizontal) {
103 103 switch (section) {
104 104 case NAME_COLUMN:
105 105 return tr("Name");
106 106 case UNIT_COLUMN:
107 107 return tr("Unit");
108 108 case MISSION_COLUMN:
109 109 return tr("Mission");
110 110 default:
111 111 // No action
112 112 break;
113 113 }
114 114
115 115 qWarning(LOG_VariableModel())
116 116 << tr("Can't get header data (unknown column %1)").arg(section);
117 117 }
118 118
119 119 return QVariant{};
120 120 }
@@ -1,38 +1,39
1 1 #ifndef SCIQLOP_DATASOURCEWIDGET_H
2 2 #define SCIQLOP_DATASOURCEWIDGET_H
3 3
4 4 #include <QWidget>
5 5
6 6 namespace Ui {
7 7 class DataSourceWidget;
8 8 } // Ui
9 9
10 10 class DataSourceItem;
11 11
12 12 /**
13 13 * @brief The DataSourceWidget handles the graphical representation (as a tree) of the data sources
14 14 * attached to SciQlop.
15 15 */
16 16 class DataSourceWidget : public QWidget {
17 17 Q_OBJECT
18 18
19 19 public:
20 20 explicit DataSourceWidget(QWidget *parent = 0);
21 virtual ~DataSourceWidget() noexcept;
21 22
22 23 public slots:
23 24 /**
24 25 * Adds a data source. An item associated to the data source is created and then added to the
25 26 * representation tree
26 27 * @param dataSource the data source to add. The pointer has to be not null
27 28 */
28 29 void addDataSource(DataSourceItem *dataSource) noexcept;
29 30
30 31 private:
31 32 Ui::DataSourceWidget *ui;
32 33
33 34 private slots:
34 35 /// Slot called when right clicking on an item in the tree (displays a menu)
35 36 void onTreeMenuRequested(const QPoint &pos) noexcept;
36 37 };
37 38
38 39 #endif // SCIQLOP_DATASOURCEWIDGET_H
@@ -1,32 +1,38
1 1 #ifndef SCIQLOP_GRAPHPLOTTABLESFACTORY_H
2 2 #define SCIQLOP_GRAPHPLOTTABLESFACTORY_H
3 3
4 #include <Data/SqpDateTime.h>
5
4 6 #include <QLoggingCategory>
5 7 #include <QVector>
6 8
7 9 #include <memory>
8 10
9 11 Q_DECLARE_LOGGING_CATEGORY(LOG_GraphPlottablesFactory)
10 12
13 class IDataSeries;
11 14 class QCPAbstractPlottable;
12 15 class QCustomPlot;
13 16 class Variable;
14 17
15 18 /**
16 19 * @brief The GraphPlottablesFactory class aims to create the QCustomPlot components relative to a
17 20 * variable, depending on the data series of this variable
18 21 */
19 22 struct GraphPlottablesFactory {
20 23 /**
21 24 * Creates (if possible) the QCustomPlot components relative to the variable passed in
22 25 * parameter, and adds these to the plot passed in parameter.
23 26 * @param variable the variable for which to create the components
24 27 * @param plot the plot in which to add the created components. It takes ownership of these
25 28 * components.
26 29 * @return the list of the components created
27 30 */
28 31 static QVector<QCPAbstractPlottable *> create(std::shared_ptr<Variable> variable,
29 32 QCustomPlot &plot) noexcept;
33
34 static void updateData(QVector<QCPAbstractPlottable *> plotableVect, IDataSeries *dataSeries,
35 const SqpDateTime &dateTime);
30 36 };
31 37
32 38 #endif // SCIQLOP_GRAPHPLOTTABLESFACTORY_H
@@ -1,51 +1,56
1 1 #ifndef SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
2 2 #define SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
3 3
4 4 #include "Visualization/IVisualizationWidget.h"
5 5
6 6 #include <QLoggingCategory>
7 7 #include <QWidget>
8 8
9 9 #include <memory>
10 10
11 11 #include <Common/spimpl.h>
12 12
13 13 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationGraphWidget)
14 14
15 15 class QCPRange;
16 16 class Variable;
17 17
18 18 namespace Ui {
19 19 class VisualizationGraphWidget;
20 20 } // namespace Ui
21 21
22 22 class VisualizationGraphWidget : public QWidget, public IVisualizationWidget {
23 23 Q_OBJECT
24 24
25 25 public:
26 26 explicit VisualizationGraphWidget(const QString &name = {}, QWidget *parent = 0);
27 27 virtual ~VisualizationGraphWidget();
28 28
29 29 void addVariable(std::shared_ptr<Variable> variable);
30 30
31 31 // IVisualizationWidget interface
32 32 void accept(IVisualizationWidgetVisitor *visitor) override;
33 33 bool canDrop(const Variable &variable) const override;
34 34 void close() override;
35 35 QString name() const override;
36 36
37 void updateDisplay(std::shared_ptr<Variable> variable);
38
39
37 40 private:
38 41 Ui::VisualizationGraphWidget *ui;
39 42
40 43 class VisualizationGraphWidgetPrivate;
41 44 spimpl::unique_impl_ptr<VisualizationGraphWidgetPrivate> impl;
42 45
43 46 private slots:
44 47
45 48 void onRangeChanged(const QCPRange &t1, const QCPRange &t2);
46 49
47 50 /// Slot called when a mouse wheel was made, to perform some processing before the zoom is done
48 51 void onMouseWheel(QWheelEvent *event) noexcept;
52
53 void onDataCacheVariableUpdated();
49 54 };
50 55
51 56 #endif // SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
@@ -1,91 +1,151
1 1 #include "Visualization/GraphPlottablesFactory.h"
2 2 #include "Visualization/qcustomplot.h"
3 3
4 4 #include <Data/ScalarSeries.h>
5 5
6 6 #include <Variable/Variable.h>
7 7
8 #include <QElapsedTimer>
9
8 10 Q_LOGGING_CATEGORY(LOG_GraphPlottablesFactory, "GraphPlottablesFactory")
9 11
10 12 namespace {
11 13
12 14 /// Format for datetimes on a axis
13 15 const auto DATETIME_TICKER_FORMAT = QStringLiteral("yyyy/MM/dd \nhh:mm:ss");
14 16
15 17 /// Generates the appropriate ticker for an axis, depending on whether the axis displays time or
16 18 /// non-time data
17 19 QSharedPointer<QCPAxisTicker> axisTicker(bool isTimeAxis)
18 20 {
19 21 if (isTimeAxis) {
20 22 auto dateTicker = QSharedPointer<QCPAxisTickerDateTime>::create();
21 23 dateTicker->setDateTimeFormat(DATETIME_TICKER_FORMAT);
22 24
23 25 return dateTicker;
24 26 }
25 27 else {
26 28 // default ticker
27 29 return QSharedPointer<QCPAxisTicker>::create();
28 30 }
29 31 }
30 32
31 QCPAbstractPlottable *createScalarSeriesComponent(ScalarSeries &scalarSeries, QCustomPlot &plot)
33 void updateScalarData(QCPAbstractPlottable *component, ScalarSeries &scalarSeries,
34 const SqpDateTime &dateTime)
35 {
36 QElapsedTimer timer;
37 timer.start();
38 if (auto qcpGraph = dynamic_cast<QCPGraph *>(component)) {
39 // Clean the graph
40 qCDebug(LOG_GraphPlottablesFactory()) << "The slow s1 operation took" << timer.elapsed()
41 << "milliseconds";
42 // NAIVE approch
43 const auto &xData = scalarSeries.xAxisData()->data();
44 const auto &valuesData = scalarSeries.valuesData()->data();
45
46 auto xValue = QVector<double>();
47 auto vValue = QVector<double>();
48
49 const auto count = xData.count();
50 auto ite = 0;
51 for (auto i = 0; i < count; ++i) {
52 const auto x = xData.at(i);
53 if (x >= dateTime.m_TStart && x <= dateTime.m_TEnd) {
54 xValue.push_back(x);
55 vValue.push_back(valuesData.at(i));
56 ++ite;
57 }
58 }
59
60 qcpGraph->setData(xValue, vValue);
61
62 qCDebug(LOG_GraphPlottablesFactory()) << "The slow s2 operation took" << timer.elapsed()
63 << "milliseconds";
64 }
65 else {
66 /// @todo DEBUG
67 }
68 }
69
70 QCPAbstractPlottable *createScalarSeriesComponent(ScalarSeries &scalarSeries, QCustomPlot &plot,
71 const SqpDateTime &dateTime)
32 72 {
33 73 auto component = plot.addGraph();
34 74
35 75 if (component) {
36 // Graph data
76 // // Graph data
37 77 component->setData(scalarSeries.xAxisData()->data(), scalarSeries.valuesData()->data(),
38 78 true);
39 79
80 updateScalarData(component, scalarSeries, dateTime);
81
40 82 // Axes properties
41 83 /// @todo : for the moment, no control is performed on the axes: the units and the tickers
42 84 /// are fixed for the default x-axis and y-axis of the plot, and according to the new graph
43 85
44 86 auto setAxisProperties = [](auto axis, const auto &unit) {
45 87 // label (unit name)
46 88 axis->setLabel(unit.m_Name);
47 89
48 90 // ticker (depending on the type of unit)
49 91 axis->setTicker(axisTicker(unit.m_TimeUnit));
50 92 };
51 93 setAxisProperties(plot.xAxis, scalarSeries.xAxisUnit());
52 94 setAxisProperties(plot.yAxis, scalarSeries.valuesUnit());
53 95
54 96 // Display all data
55 97 component->rescaleAxes();
56 98
57 99 plot.replot();
58 100 }
59 101 else {
60 102 qCDebug(LOG_GraphPlottablesFactory())
61 103 << QObject::tr("Can't create graph for the scalar series");
62 104 }
63 105
64 106 return component;
65 107 }
66 108
67 109 } // namespace
68 110
69 111 QVector<QCPAbstractPlottable *> GraphPlottablesFactory::create(std::shared_ptr<Variable> variable,
70 112 QCustomPlot &plot) noexcept
71 113 {
72 114 auto result = QVector<QCPAbstractPlottable *>{};
73 115
74 116 if (variable) {
75 117 // Gets the data series of the variable to call the creation of the right components
76 118 // according to its type
77 119 if (auto scalarSeries = dynamic_cast<ScalarSeries *>(variable->dataSeries())) {
78 result.append(createScalarSeriesComponent(*scalarSeries, plot));
120 result.append(createScalarSeriesComponent(*scalarSeries, plot, variable->dateTime()));
79 121 }
80 122 else {
81 123 qCDebug(LOG_GraphPlottablesFactory())
82 124 << QObject::tr("Can't create graph plottables : unmanaged data series type");
83 125 }
84 126 }
85 127 else {
86 128 qCDebug(LOG_GraphPlottablesFactory())
87 129 << QObject::tr("Can't create graph plottables : the variable is null");
88 130 }
89 131
90 132 return result;
91 133 }
134
135 void GraphPlottablesFactory::updateData(QVector<QCPAbstractPlottable *> plotableVect,
136 IDataSeries *dataSeries, const SqpDateTime &dateTime)
137 {
138 if (auto scalarSeries = dynamic_cast<ScalarSeries *>(dataSeries)) {
139 if (plotableVect.size() == 1) {
140 updateScalarData(plotableVect.at(0), *scalarSeries, dateTime);
141 }
142 else {
143 qCCritical(LOG_GraphPlottablesFactory()) << QObject::tr(
144 "Can't update Data of a scalarSeries because there is not only one component "
145 "associated");
146 }
147 }
148 else {
149 /// @todo DEBUG
150 }
151 }
@@ -1,122 +1,166
1 1 #include "Visualization/VisualizationGraphWidget.h"
2 2 #include "Visualization/GraphPlottablesFactory.h"
3 3 #include "Visualization/IVisualizationWidgetVisitor.h"
4 4 #include "ui_VisualizationGraphWidget.h"
5 5
6 #include <Data/ArrayData.h>
7 #include <Data/IDataSeries.h>
8 #include <SqpApplication.h>
6 9 #include <Variable/Variable.h>
10 #include <Variable/VariableController.h>
11
7 12 #include <unordered_map>
8 13
9 14 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
10 15
11 16 namespace {
12 17
13 18 /// Key pressed to enable zoom on horizontal axis
14 19 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::NoModifier;
15 20
16 21 /// Key pressed to enable zoom on vertical axis
17 22 const auto VERTICAL_ZOOM_MODIFIER = Qt::ControlModifier;
18 23
19 24 } // namespace
20 25
21 26 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
22 27
23 28 // 1 variable -> n qcpplot
24 std::unordered_map<std::shared_ptr<Variable>, QCPAbstractPlottable *> m_VariableToPlotMap;
29 std::unordered_multimap<std::shared_ptr<Variable>, QCPAbstractPlottable *>
30 m_VariableToPlotMultiMap;
25 31 };
26 32
27 33 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
28 34 : QWidget{parent},
29 35 ui{new Ui::VisualizationGraphWidget},
30 36 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>()}
31 37 {
32 38 ui->setupUi(this);
33 39
34 40 // qcpplot title
35 41 ui->widget->plotLayout()->insertRow(0);
36 42 ui->widget->plotLayout()->addElement(0, 0, new QCPTextElement{ui->widget, name});
37 43
38 44 // Set qcpplot properties :
39 45 // - Drag (on x-axis) and zoom are enabled
40 46 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
41 47 ui->widget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);
42 48 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal);
43 49 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
44 50 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
45 51 &QCPAxis::rangeChanged),
46 52 this, &VisualizationGraphWidget::onRangeChanged);
47 53 }
48 54
49 55
50 56 VisualizationGraphWidget::~VisualizationGraphWidget()
51 57 {
52 58 delete ui;
53 59 }
54 60
55 61 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable)
56 62 {
57 63 // Uses delegate to create the qcpplot components according to the variable
58 64 auto createdPlottables = GraphPlottablesFactory::create(variable, *ui->widget);
59 65
60 66 for (auto createdPlottable : qAsConst(createdPlottables)) {
61 impl->m_VariableToPlotMap.insert({variable, createdPlottable});
67 impl->m_VariableToPlotMultiMap.insert({variable, createdPlottable});
62 68 }
69
70 connect(variable.get(), &Variable::dataCacheUpdated, this,
71 &VisualizationGraphWidget::onDataCacheVariableUpdated);
63 72 }
64 73
65 74 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
66 75 {
67 76 if (visitor) {
68 77 visitor->visit(this);
69 78 }
70 79 else {
71 80 qCCritical(LOG_VisualizationGraphWidget())
72 81 << tr("Can't visit widget : the visitor is null");
73 82 }
74 83 }
75 84
76 85 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
77 86 {
78 87 /// @todo : for the moment, a graph can always accomodate a variable
79 88 Q_UNUSED(variable);
80 89 return true;
81 90 }
82 91
83 92 void VisualizationGraphWidget::close()
84 93 {
85 94 // The main view cannot be directly closed.
86 95 return;
87 96 }
88 97
89 98 QString VisualizationGraphWidget::name() const
90 99 {
91 100 if (auto title = dynamic_cast<QCPTextElement *>(ui->widget->plotLayout()->elementAt(0))) {
92 101 return title->text();
93 102 }
94 103 else {
95 104 return QString{};
96 105 }
97 106 }
98 107
99 108 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
100 109 {
101 for (auto it = impl->m_VariableToPlotMap.cbegin(); it != impl->m_VariableToPlotMap.cend();
102 ++it) {
103 it->first->onXRangeChanged(SqpDateTime{t2.lower, t2.upper});
110
111 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::onRangeChanged");
112
113 for (auto it = impl->m_VariableToPlotMultiMap.cbegin();
114 it != impl->m_VariableToPlotMultiMap.cend(); ++it) {
115 auto variable = it->first;
116 auto tolerance = 0.1 * (t2.upper - t2.lower);
117 auto dateTime = SqpDateTime{t2.lower - tolerance, t2.upper + tolerance};
118
119 qCInfo(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::onRangeChanged")
120 << variable->dataSeries()->xAxisData()->size();
121 if (!variable->contains(dateTime)) {
122 sqpApp->variableController().requestDataLoading(variable, dateTime);
123 }
104 124 }
105 125 }
106 126
107 127 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
108 128 {
109 129 auto zoomOrientations = QFlags<Qt::Orientation>{};
110 130
111 131 // Lambda that enables a zoom orientation if the key modifier related to this orientation has
112 132 // been pressed
113 133 auto enableOrientation
114 134 = [&zoomOrientations, event](const auto &orientation, const auto &modifier) {
115 135 auto orientationEnabled = event->modifiers().testFlag(modifier);
116 136 zoomOrientations.setFlag(orientation, orientationEnabled);
117 137 };
118 138 enableOrientation(Qt::Vertical, VERTICAL_ZOOM_MODIFIER);
119 139 enableOrientation(Qt::Horizontal, HORIZONTAL_ZOOM_MODIFIER);
120 140
121 141 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
122 142 }
143
144 void VisualizationGraphWidget::onDataCacheVariableUpdated()
145 {
146 for (auto it = impl->m_VariableToPlotMultiMap.cbegin();
147 it != impl->m_VariableToPlotMultiMap.cend(); ++it) {
148 auto variable = it->first;
149 GraphPlottablesFactory::updateData(QVector<QCPAbstractPlottable *>{} << it->second,
150 variable->dataSeries(), variable->dateTime());
151 }
152 }
153
154 void VisualizationGraphWidget::updateDisplay(std::shared_ptr<Variable> variable)
155 {
156 auto abstractPlotableItPair = impl->m_VariableToPlotMultiMap.equal_range(variable);
157
158 auto abstractPlotableVect = QVector<QCPAbstractPlottable *>{};
159
160 for (auto it = abstractPlotableItPair.first; it != abstractPlotableItPair.second; ++it) {
161 abstractPlotableVect.push_back(it->second);
162 }
163
164 GraphPlottablesFactory::updateData(abstractPlotableVect, variable->dataSeries(),
165 variable->dateTime());
166 }
General Comments 0
You need to be logged in to leave comments. Login now