##// END OF EJS Templates
Minor refactoring...
Alexandre Leroux -
r424:09d21ab89520
parent child
Show More
@@ -1,76 +1,79
1 1 /*------------------------------------------------------------------------------
2 2 -- This file is a part of the QLop Software
3 3 -- Copyright (C) 2015, Plasma Physics Laboratory - CNRS
4 4 --
5 5 -- This program is free software; you can redistribute it and/or modify
6 6 -- it under the terms of the GNU General Public License as published by
7 7 -- the Free Software Foundation; either version 2 of the License, or
8 8 -- (at your option) any later version.
9 9 --
10 10 -- This program is distributed in the hope that it will be useful,
11 11 -- but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 13 -- GNU General Public License for more details.
14 14 --
15 15 -- You should have received a copy of the GNU General Public License
16 16 -- along with this program; if not, write to the Free Software
17 17 -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 18 -------------------------------------------------------------------------------*/
19 19 /*-- Author : Alexis Jeandet
20 20 -- Mail : alexis.jeandet@member.fsf.org
21 21 ----------------------------------------------------------------------------*/
22 22 #include "MainWindow.h"
23 23 #include <QProcessEnvironment>
24 24 #include <QThread>
25 25 #include <SqpApplication.h>
26 26 #include <qglobal.h>
27 27
28 28 #include <Plugin/PluginManager.h>
29 29 #include <QDir>
30 30
31 #include <QLoggingCategory>
32
33 Q_LOGGING_CATEGORY(LOG_Main, "Main")
34
31 35 namespace {
32 36
33 37 /// Name of the directory containing the plugins
34 38
35 39 #if _WIN32 || _WIN64
36 40 const auto PLUGIN_DIRECTORY_NAME = QStringLiteral("plugins");
37 41 #endif
38 42
39 43 } // namespace
40 44
41 45 int main(int argc, char *argv[])
42 46 {
43 47 SqpApplication a{argc, argv};
44 48 SqpApplication::setOrganizationName("LPP");
45 49 SqpApplication::setOrganizationDomain("lpp.fr");
46 50 SqpApplication::setApplicationName("SciQLop");
47 51 MainWindow w;
48 52 w.show();
49 53
50 54 // Loads plugins
51 55 auto pluginDir = QDir{sqpApp->applicationDirPath()};
52 56 #if _WIN32 || _WIN64
53 57 pluginDir.mkdir(PLUGIN_DIRECTORY_NAME);
54 58 pluginDir.cd(PLUGIN_DIRECTORY_NAME);
55 59 #endif
56 60
57 61
58 62 #if __unix || __APPLE
59 63 #if __x86_64__ || __ppc64__
60 64 if (!pluginDir.cd("../lib64/SciQlop")) {
61 65 pluginDir.cd("../lib64/sciqlop");
62 66 }
63 67 #else
64 68 if (!pluginDir.cd("../lib/SciQlop")) {
65 69 pluginDir.cd("../lib/sciqlop");
66 70 }
67 71 #endif
68 72 #endif
69 qCDebug(LOG_PluginManager())
70 << QObject::tr("Plugin directory: %1").arg(pluginDir.absolutePath());
73 qCDebug(LOG_Main()) << QObject::tr("Plugin directory: %1").arg(pluginDir.absolutePath());
71 74
72 75 PluginManager pluginManager{};
73 76 pluginManager.loadPlugins(pluginDir);
74 77
75 78 return a.exec();
76 79 }
@@ -1,269 +1,214
1 1 /*------------------------------------------------------------------------------
2 2 -- This file is a part of the SciQLop Software
3 3 -- Copyright (C) 2017, Plasma Physics Laboratory - CNRS
4 4 --
5 5 -- This program is free software; you can redistribute it and/or modify
6 6 -- it under the terms of the GNU General Public License as published by
7 7 -- the Free Software Foundation; either version 2 of the License, or
8 8 -- (at your option) any later version.
9 9 --
10 10 -- This program is distributed in the hope that it will be useful,
11 11 -- but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 13 -- GNU General Public License for more details.
14 14 --
15 15 -- You should have received a copy of the GNU General Public License
16 16 -- along with this program; if not, write to the Free Software
17 17 -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 18 -------------------------------------------------------------------------------*/
19 19 /*-- Author : Alexis Jeandet
20 20 -- Mail : alexis.jeandet@member.fsf.org
21 21 ----------------------------------------------------------------------------*/
22 22 #include "MainWindow.h"
23 23 #include "ui_MainWindow.h"
24 24
25 25 #include <DataSource/DataSourceController.h>
26 26 #include <DataSource/DataSourceWidget.h>
27 27 #include <SidePane/SqpSidePane.h>
28 28 #include <SqpApplication.h>
29 29 #include <Time/TimeController.h>
30 30 #include <TimeWidget/TimeWidget.h>
31 31 #include <Variable/Variable.h>
32 32 #include <Variable/VariableController.h>
33 33 #include <Visualization/VisualizationController.h>
34 34
35 35 #include <QAction>
36 36 #include <QDate>
37 37 #include <QDateTime>
38 38 #include <QDir>
39 39 #include <QFileDialog>
40 40 #include <QToolBar>
41 41 #include <QToolButton>
42 42 #include <memory.h>
43 43
44 //#include <omp.h>
45 //#include <network/filedownloader.h>
46 //#include <qlopdatabase.h>
47 //#include <qlopsettings.h>
48 //#include <qlopgui.h>
49 //#include <spacedata.h>
50 //#include "qlopcore.h"
51 //#include "qlopcodecmanager.h"
52 //#include "cdfcodec.h"
53 //#include "amdatxtcodec.h"
54 //#include <qlopplotmanager.h>
55
56 44 #include "iostream"
57 45
58 46 Q_LOGGING_CATEGORY(LOG_MainWindow, "MainWindow")
59 47
60 48 namespace {
61 49 const auto LEFTMAININSPECTORWIDGETSPLITTERINDEX = 0;
62 50 const auto LEFTINSPECTORSIDEPANESPLITTERINDEX = 1;
63 51 const auto VIEWPLITTERINDEX = 2;
64 52 const auto RIGHTINSPECTORSIDEPANESPLITTERINDEX = 3;
65 53 const auto RIGHTMAININSPECTORWIDGETSPLITTERINDEX = 4;
66 54 }
67 55
68 56 class MainWindow::MainWindowPrivate {
69 57 public:
70 58 QSize m_LastOpenLeftInspectorSize;
71 59 QSize m_LastOpenRightInspectorSize;
72 60 };
73 61
74 62 MainWindow::MainWindow(QWidget *parent)
75 63 : QMainWindow{parent},
76 64 m_Ui{new Ui::MainWindow},
77 65 impl{spimpl::make_unique_impl<MainWindowPrivate>()}
78 66 {
79 67 m_Ui->setupUi(this);
80 68
81 69 m_Ui->splitter->setCollapsible(LEFTINSPECTORSIDEPANESPLITTERINDEX, false);
82 70 m_Ui->splitter->setCollapsible(RIGHTINSPECTORSIDEPANESPLITTERINDEX, false);
83 71
84 72
85 73 auto leftSidePane = m_Ui->leftInspectorSidePane->sidePane();
86 74 auto openLeftInspectorAction = new QAction{QIcon{
87 75 ":/icones/previous.png",
88 76 },
89 77 tr("Show/hide the left inspector"), this};
90 78
91 79
92 80 auto spacerLeftTop = new QWidget{};
93 81 spacerLeftTop->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
94 82
95 83 auto spacerLeftBottom = new QWidget{};
96 84 spacerLeftBottom->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
97 85
98 86 leftSidePane->addWidget(spacerLeftTop);
99 87 leftSidePane->addAction(openLeftInspectorAction);
100 88 leftSidePane->addWidget(spacerLeftBottom);
101 89
102 90
103 91 auto rightSidePane = m_Ui->rightInspectorSidePane->sidePane();
104 92 auto openRightInspectorAction = new QAction{QIcon{
105 93 ":/icones/next.png",
106 94 },
107 95 tr("Show/hide the right inspector"), this};
108 96
109 97 auto spacerRightTop = new QWidget{};
110 98 spacerRightTop->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
111 99
112 100 auto spacerRightBottom = new QWidget{};
113 101 spacerRightBottom->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
114 102
115 103 rightSidePane->addWidget(spacerRightTop);
116 104 rightSidePane->addAction(openRightInspectorAction);
117 105 rightSidePane->addWidget(spacerRightBottom);
118 106
119 107 openLeftInspectorAction->setCheckable(true);
120 108 openRightInspectorAction->setCheckable(true);
121 109
122 110 auto openInspector = [this](bool checked, bool right, auto action) {
123 111
124 112 action->setIcon(QIcon{(checked xor right) ? ":/icones/next.png" : ":/icones/previous.png"});
125 113
126 114 auto &lastInspectorSize
127 115 = right ? impl->m_LastOpenRightInspectorSize : impl->m_LastOpenLeftInspectorSize;
128 116
129 117 auto nextInspectorSize = right ? m_Ui->rightMainInspectorWidget->size()
130 118 : m_Ui->leftMainInspectorWidget->size();
131 119
132 120 // Update of the last opened geometry
133 121 if (checked) {
134 122 lastInspectorSize = nextInspectorSize;
135 123 }
136 124
137 125 auto startSize = lastInspectorSize;
138 126 auto endSize = startSize;
139 127 endSize.setWidth(0);
140 128
141 129 auto splitterInspectorIndex
142 130 = right ? RIGHTMAININSPECTORWIDGETSPLITTERINDEX : LEFTMAININSPECTORWIDGETSPLITTERINDEX;
143 131
144 132 auto currentSizes = m_Ui->splitter->sizes();
145 133 if (checked) {
146 134 // adjust sizes individually here, e.g.
147 135 currentSizes[splitterInspectorIndex] -= lastInspectorSize.width();
148 136 currentSizes[VIEWPLITTERINDEX] += lastInspectorSize.width();
149 137 m_Ui->splitter->setSizes(currentSizes);
150 138 }
151 139 else {
152 140 // adjust sizes individually here, e.g.
153 141 currentSizes[splitterInspectorIndex] += lastInspectorSize.width();
154 142 currentSizes[VIEWPLITTERINDEX] -= lastInspectorSize.width();
155 143 m_Ui->splitter->setSizes(currentSizes);
156 144 }
157 145
158 146 };
159 147
160 148
161 149 connect(openLeftInspectorAction, &QAction::triggered,
162 150 [openInspector, openLeftInspectorAction](bool checked) {
163 151 openInspector(checked, false, openLeftInspectorAction);
164 152 });
165 153 connect(openRightInspectorAction, &QAction::triggered,
166 154 [openInspector, openRightInspectorAction](bool checked) {
167 155 openInspector(checked, true, openRightInspectorAction);
168 156 });
169 157
170 158 this->menuBar()->addAction(tr("File"));
171 159 auto mainToolBar = this->addToolBar(QStringLiteral("MainToolBar"));
172 160
173 161 auto timeWidget = new TimeWidget{};
174 162 mainToolBar->addWidget(timeWidget);
175 163
176 164 // Controllers / controllers connections
177 165 connect(&sqpApp->timeController(), SIGNAL(timeUpdated(SqpDateTime)),
178 166 &sqpApp->variableController(), SLOT(onDateTimeOnSelection(SqpDateTime)));
179 167
180 168 // Widgets / controllers connections
181 169
182 170 // DataSource
183 171 connect(&sqpApp->dataSourceController(), SIGNAL(dataSourceItemSet(DataSourceItem *)),
184 172 m_Ui->dataSourceWidget, SLOT(addDataSource(DataSourceItem *)));
185 173
186 174 // Time
187 175 connect(timeWidget, SIGNAL(timeUpdated(SqpDateTime)), &sqpApp->timeController(),
188 176 SLOT(onTimeToUpdate(SqpDateTime)));
189 177
190 178 // Visualization
191 179 connect(&sqpApp->visualizationController(),
192 180 SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)), m_Ui->view,
193 181 SLOT(onVariableAboutToBeDeleted(std::shared_ptr<Variable>)));
194 182
195 183 connect(&sqpApp->visualizationController(),
196 184 SIGNAL(rangeChanged(std::shared_ptr<Variable>, const SqpDateTime &)), m_Ui->view,
197 185 SLOT(onRangeChanged(std::shared_ptr<Variable>, const SqpDateTime &)));
198 186
199 187 // Widgets / widgets connections
200 188
201 189 // For the following connections, we use DirectConnection to allow each widget that can
202 190 // potentially attach a menu to the variable's menu to do so before this menu is displayed.
203 191 // The order of connections is also important, since it determines the order in which each
204 192 // widget will attach its menu
205 193 connect(
206 194 m_Ui->variableInspectorWidget,
207 195 SIGNAL(tableMenuAboutToBeDisplayed(QMenu *, const QVector<std::shared_ptr<Variable> > &)),
208 196 m_Ui->view, SLOT(attachVariableMenu(QMenu *, const QVector<std::shared_ptr<Variable> > &)),
209 197 Qt::DirectConnection);
210
211 /* QLopGUI::registerMenuBar(menuBar());
212 this->setWindowIcon(QIcon(":/sciqlopLOGO.svg"));
213 this->m_progressWidget = new QWidget();
214 this->m_progressLayout = new QVBoxLayout(this->m_progressWidget);
215 this->m_progressWidget->setLayout(this->m_progressLayout);
216 this->m_progressWidget->setWindowModality(Qt::WindowModal);
217 m_progressThreadIds = (int*) malloc(OMP_THREADS*sizeof(int));
218 for(int i=0;i<OMP_THREADS;i++)
219 {
220 this->m_progress.append(new QProgressBar(this->m_progressWidget));
221 this->m_progress.last()->setMinimum(0);
222 this->m_progress.last()->setMaximum(100);
223 this->m_progressLayout->addWidget(this->m_progress.last());
224 this->m_progressWidget->hide();
225 this->m_progressThreadIds[i] = -1;
226 }
227 this->m_progressWidget->setWindowTitle("Loading File");
228 const QList<QLopService*>ServicesToLoad=QList<QLopService*>()
229 << QLopCore::self()
230 << QLopPlotManager::self()
231 << QLopCodecManager::self()
232 << FileDownloader::self()
233 << QLopDataBase::self()
234 << SpaceData::self();
235
236 CDFCodec::registerToManager();
237 AMDATXTCodec::registerToManager();
238
239
240 for(int i=0;i<ServicesToLoad.count();i++)
241 {
242 qDebug()<<ServicesToLoad.at(i)->serviceName();
243 ServicesToLoad.at(i)->initialize(); //must be called before getGUI
244 QDockWidget* wdgt=ServicesToLoad.at(i)->getGUI();
245 if(wdgt)
246 {
247 wdgt->setAllowedAreas(Qt::AllDockWidgetAreas);
248 this->addDockWidget(Qt::TopDockWidgetArea,wdgt);
249 }
250 PythonQt::self()->getMainModule().addObject(ServicesToLoad.at(i)->serviceName(),(QObject*)ServicesToLoad.at(i));
251 }*/
252 198 }
253 199
254 200 MainWindow::~MainWindow()
255 201 {
256 202 }
257 203
258
259 204 void MainWindow::changeEvent(QEvent *e)
260 205 {
261 206 QMainWindow::changeEvent(e);
262 207 switch (e->type()) {
263 208 case QEvent::LanguageChange:
264 209 m_Ui->retranslateUi(this);
265 210 break;
266 211 default:
267 212 break;
268 213 }
269 214 }
@@ -1,46 +1,43
1 1 #ifndef SCIQLOP_VARIABLECACHECONTROLLER_H
2 2 #define SCIQLOP_VARIABLECACHECONTROLLER_H
3 3
4 4 #include <QLoggingCategory>
5 5 #include <QObject>
6 6
7 7 #include <Data/SqpDateTime.h>
8 8
9 9 #include <QLoggingCategory>
10 10
11 11 #include <Common/spimpl.h>
12 12
13 13 Q_DECLARE_LOGGING_CATEGORY(LOG_VariableCacheController)
14 14
15 15 class Variable;
16 16
17 Q_DECLARE_LOGGING_CATEGORY(LOG_VariableCacheController)
18
19
20 17 /// This class aims to store in the cache all of the dateTime already requested to the variable.
21 18 class VariableCacheController : public QObject {
22 19 Q_OBJECT
23 20 public:
24 21 explicit VariableCacheController(QObject *parent = 0);
25 22
26 23
27 24 void addDateTime(std::shared_ptr<Variable> variable, const SqpDateTime &dateTime);
28 25
29 26 /// Clears cache concerning a variable
30 27 void clear(std::shared_ptr<Variable> variable) noexcept;
31 28
32 29 /// Return all of the SqpDataTime part of the dateTime whose are not in the cache
33 30 QVector<SqpDateTime> provideNotInCacheDateTimeList(std::shared_ptr<Variable> variable,
34 31 const SqpDateTime &dateTime);
35 32
36 33
37 34 QVector<SqpDateTime> dateCacheList(std::shared_ptr<Variable> variable) const noexcept;
38 35
39 36 void displayCache(std::shared_ptr<Variable> variable) const;
40 37
41 38 private:
42 39 class VariableCacheControllerPrivate;
43 40 spimpl::unique_impl_ptr<VariableCacheControllerPrivate> impl;
44 41 };
45 42
46 43 #endif // SCIQLOP_VARIABLECACHECONTROLLER_H
@@ -1,401 +1,401
1 1 #include "Visualization/VisualizationGraphWidget.h"
2 2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 3 #include "Visualization/VisualizationGraphHelper.h"
4 4 #include "ui_VisualizationGraphWidget.h"
5 5
6 6 #include <Data/ArrayData.h>
7 7 #include <Data/IDataSeries.h>
8 8 #include <SqpApplication.h>
9 9 #include <Variable/Variable.h>
10 10 #include <Variable/VariableController.h>
11 11
12 12 #include <unordered_map>
13 13
14 14 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
15 15
16 16 namespace {
17 17
18 18 /// Key pressed to enable zoom on horizontal axis
19 19 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::NoModifier;
20 20
21 21 /// Key pressed to enable zoom on vertical axis
22 22 const auto VERTICAL_ZOOM_MODIFIER = Qt::ControlModifier;
23 23
24 24 } // namespace
25 25
26 26 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
27 27
28 28 explicit VisualizationGraphWidgetPrivate() : m_DoSynchronize{true}, m_IsCalibration{false} {}
29 29
30 30
31 31 // Return the operation when range changed
32 32 VisualizationGraphWidgetZoomType getZoomType(const QCPRange &t1, const QCPRange &t2);
33 33
34 34 // 1 variable -> n qcpplot
35 35 std::multimap<std::shared_ptr<Variable>, QCPAbstractPlottable *> m_VariableToPlotMultiMap;
36 36
37 37 bool m_DoSynchronize;
38 38 bool m_IsCalibration;
39 39 };
40 40
41 41 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
42 42 : QWidget{parent},
43 43 ui{new Ui::VisualizationGraphWidget},
44 44 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>()}
45 45 {
46 46 ui->setupUi(this);
47 47
48 48 ui->graphNameLabel->setText(name);
49 49
50 50 // 'Close' options : widget is deleted when closed
51 51 setAttribute(Qt::WA_DeleteOnClose);
52 52 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationGraphWidget::close);
53 53 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
54 54
55 55 // Set qcpplot properties :
56 56 // - Drag (on x-axis) and zoom are enabled
57 57 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
58 58 ui->widget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);
59 59 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal);
60 60 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
61 61 connect(ui->widget, &QCustomPlot::mouseRelease, this,
62 62 &VisualizationGraphWidget::onMouseRelease);
63 63 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
64 64 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
65 65 &QCPAxis::rangeChanged),
66 66 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
67 67
68 68 // Activates menu when right clicking on the graph
69 69 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
70 70 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
71 71 &VisualizationGraphWidget::onGraphMenuRequested);
72 72
73 73 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
74 74 &VariableController::onRequestDataLoading);
75 75 }
76 76
77 77
78 78 VisualizationGraphWidget::~VisualizationGraphWidget()
79 79 {
80 80 delete ui;
81 81 }
82 82
83 83 void VisualizationGraphWidget::enableSynchronize(bool enable)
84 84 {
85 85 impl->m_DoSynchronize = enable;
86 86 }
87 87
88 88 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable)
89 89 {
90 90 // Uses delegate to create the qcpplot components according to the variable
91 91 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
92 92
93 93 for (auto createdPlottable : qAsConst(createdPlottables)) {
94 94 impl->m_VariableToPlotMultiMap.insert({variable, createdPlottable});
95 95 }
96 96
97 97 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
98 98 }
99 99 void VisualizationGraphWidget::addVariableUsingGraph(std::shared_ptr<Variable> variable)
100 100 {
101 101
102 102 // when adding a variable, we need to set its time range to the current graph range
103 103 auto grapheRange = ui->widget->xAxis->range();
104 104 auto dateTime = SqpDateTime{grapheRange.lower, grapheRange.upper};
105 105 variable->setDateTime(dateTime);
106 106
107 107 auto variableDateTimeWithTolerance = dateTime;
108 108
109 109 // add 20% tolerance for each side
110 110 auto tolerance = 0.2 * (dateTime.m_TEnd - dateTime.m_TStart);
111 111 variableDateTimeWithTolerance.m_TStart -= tolerance;
112 112 variableDateTimeWithTolerance.m_TEnd += tolerance;
113 113
114 114 // Uses delegate to create the qcpplot components according to the variable
115 115 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
116 116
117 117 for (auto createdPlottable : qAsConst(createdPlottables)) {
118 118 impl->m_VariableToPlotMultiMap.insert({variable, createdPlottable});
119 119 }
120 120
121 121 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
122 122
123 123 // CHangement detected, we need to ask controller to request data loading
124 124 emit requestDataLoading(variable, variableDateTimeWithTolerance);
125 125 }
126 126
127 127 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
128 128 {
129 129 // Each component associated to the variable :
130 130 // - is removed from qcpplot (which deletes it)
131 131 // - is no longer referenced in the map
132 132 auto componentsIt = impl->m_VariableToPlotMultiMap.equal_range(variable);
133 133 for (auto it = componentsIt.first; it != componentsIt.second;) {
134 134 ui->widget->removePlottable(it->second);
135 135 it = impl->m_VariableToPlotMultiMap.erase(it);
136 136 }
137 137
138 138 // Updates graph
139 139 ui->widget->replot();
140 140 }
141 141
142 142 void VisualizationGraphWidget::setRange(std::shared_ptr<Variable> variable,
143 143 const SqpDateTime &range)
144 144 {
145 145 // Note: in case of different axes that depends on variable, we could start with a code like
146 146 // that:
147 147 // auto componentsIt = impl->m_VariableToPlotMultiMap.equal_range(variable);
148 148 // for (auto it = componentsIt.first; it != componentsIt.second;) {
149 149 // }
150 150 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
151 151 ui->widget->replot();
152 152 }
153 153
154 154 SqpDateTime VisualizationGraphWidget::graphRange() const noexcept
155 155 {
156 156 auto grapheRange = ui->widget->xAxis->range();
157 157 return SqpDateTime{grapheRange.lower, grapheRange.upper};
158 158 }
159 159
160 160 void VisualizationGraphWidget::setGraphRange(const SqpDateTime &range)
161 161 {
162 162 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
163 163 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
164 164 ui->widget->replot();
165 165 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
166 166 }
167 167
168 168 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
169 169 {
170 170 if (visitor) {
171 171 visitor->visit(this);
172 172 }
173 173 else {
174 174 qCCritical(LOG_VisualizationGraphWidget())
175 175 << tr("Can't visit widget : the visitor is null");
176 176 }
177 177 }
178 178
179 179 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
180 180 {
181 181 /// @todo : for the moment, a graph can always accomodate a variable
182 182 Q_UNUSED(variable);
183 183 return true;
184 184 }
185 185
186 186 bool VisualizationGraphWidget::contains(const Variable &variable) const
187 187 {
188 188 // Finds the variable among the keys of the map
189 189 auto variablePtr = &variable;
190 190 auto findVariable
191 191 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
192 192
193 193 auto end = impl->m_VariableToPlotMultiMap.cend();
194 194 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
195 195 return it != end;
196 196 }
197 197
198 198 QString VisualizationGraphWidget::name() const
199 199 {
200 200 return ui->graphNameLabel->text();
201 201 }
202 202
203 203 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
204 204 {
205 205 QMenu graphMenu{};
206 206
207 207 // Iterates on variables (unique keys)
208 208 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
209 209 end = impl->m_VariableToPlotMultiMap.cend();
210 210 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
211 211 // 'Remove variable' action
212 212 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
213 213 [ this, var = it->first ]() { removeVariable(var); });
214 214 }
215 215
216 216 if (!graphMenu.isEmpty()) {
217 217 graphMenu.exec(mapToGlobal(pos));
218 218 }
219 219 }
220 220
221 221 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
222 222 {
223 223 qCInfo(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::onRangeChanged")
224 224 << QThread::currentThread()->objectName();
225 225
226 226 auto dateTimeRange = SqpDateTime{t1.lower, t1.upper};
227 227
228 228 auto zoomType = impl->getZoomType(t1, t2);
229 229 for (auto it = impl->m_VariableToPlotMultiMap.cbegin();
230 230 it != impl->m_VariableToPlotMultiMap.cend(); ++it) {
231 231
232 232 auto variable = it->first;
233 233 auto currentDateTime = dateTimeRange;
234 234
235 235 auto toleranceFactor = 0.2;
236 236 auto tolerance = toleranceFactor * (currentDateTime.m_TEnd - currentDateTime.m_TStart);
237 237 auto variableDateTimeWithTolerance = currentDateTime;
238 238 variableDateTimeWithTolerance.m_TStart -= tolerance;
239 239 variableDateTimeWithTolerance.m_TEnd += tolerance;
240 240
241 241 qCDebug(LOG_VisualizationGraphWidget()) << "r" << currentDateTime;
242 242 qCDebug(LOG_VisualizationGraphWidget()) << "t" << variableDateTimeWithTolerance;
243 243 qCDebug(LOG_VisualizationGraphWidget()) << "v" << variable->dateTime();
244 244 // If new range with tol is upper than variable datetime parameters. we need to request new
245 245 // data
246 246 if (!variable->contains(variableDateTimeWithTolerance)) {
247 247
248 248 auto variableDateTimeWithTolerance = currentDateTime;
249 249 if (!variable->isInside(currentDateTime)) {
250 250 auto variableDateTime = variable->dateTime();
251 251 if (variable->contains(variableDateTimeWithTolerance)) {
252 252 qCDebug(LOG_VisualizationGraphWidget())
253 253 << tr("TORM: Detection zoom in that need request:");
254 // add 10% tolerance for each side
254 // add tolerance for each side
255 255 tolerance
256 256 = toleranceFactor * (currentDateTime.m_TEnd - currentDateTime.m_TStart);
257 257 variableDateTimeWithTolerance.m_TStart -= tolerance;
258 258 variableDateTimeWithTolerance.m_TEnd += tolerance;
259 259 }
260 260 else if (variableDateTime.m_TStart < currentDateTime.m_TStart) {
261 261 qCInfo(LOG_VisualizationGraphWidget()) << tr("TORM: Detection pan to right:");
262 262
263 263 auto diffEndToKeepDelta = currentDateTime.m_TEnd - variableDateTime.m_TEnd;
264 264 currentDateTime.m_TStart = variableDateTime.m_TStart + diffEndToKeepDelta;
265 265 // Tolerance have to be added to the right
266 266 // add tolerance for right (end) side
267 267 tolerance
268 268 = toleranceFactor * (currentDateTime.m_TEnd - currentDateTime.m_TStart);
269 269 variableDateTimeWithTolerance.m_TEnd += tolerance;
270 270 }
271 271 else if (variableDateTime.m_TEnd > currentDateTime.m_TEnd) {
272 272 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: Detection pan to left: ");
273 273 auto diffStartToKeepDelta
274 274 = variableDateTime.m_TStart - currentDateTime.m_TStart;
275 275 currentDateTime.m_TEnd = variableDateTime.m_TEnd - diffStartToKeepDelta;
276 276 // Tolerance have to be added to the left
277 277 // add tolerance for left (start) side
278 278 tolerance
279 279 = toleranceFactor * (currentDateTime.m_TEnd - currentDateTime.m_TStart);
280 280 variableDateTimeWithTolerance.m_TStart -= tolerance;
281 281 }
282 282 else {
283 283 qCCritical(LOG_VisualizationGraphWidget())
284 284 << tr("Detection anormal zoom detection: ");
285 285 }
286 286 }
287 287 else {
288 288 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: Detection zoom out: ");
289 // add 10% tolerance for each side
289 // add tolerance for each side
290 290 tolerance = toleranceFactor * (currentDateTime.m_TEnd - currentDateTime.m_TStart);
291 291 variableDateTimeWithTolerance.m_TStart -= tolerance;
292 292 variableDateTimeWithTolerance.m_TEnd += tolerance;
293 293 zoomType = VisualizationGraphWidgetZoomType::ZoomOut;
294 294 }
295 295 if (!variable->contains(dateTimeRange)) {
296 296 qCDebug(LOG_VisualizationGraphWidget())
297 297 << "TORM: Modif on variable datetime detected" << currentDateTime;
298 298 variable->setDateTime(currentDateTime);
299 299 }
300 300
301 301 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: Request data detection: ");
302 302 // CHangement detected, we need to ask controller to request data loading
303 303 emit requestDataLoading(variable, variableDateTimeWithTolerance);
304 304 }
305 305 else {
306 306 qCInfo(LOG_VisualizationGraphWidget())
307 307 << tr("TORM: Detection zoom in that doesn't need request: ");
308 308 zoomType = VisualizationGraphWidgetZoomType::ZoomIn;
309 309 }
310 310 }
311 311
312 312 if (impl->m_DoSynchronize && !impl->m_IsCalibration) {
313 313 auto oldDateTime = SqpDateTime{t2.lower, t2.upper};
314 314 qCDebug(LOG_VisualizationGraphWidget())
315 315 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
316 316 << QThread::currentThread()->objectName();
317 317 emit synchronize(dateTimeRange, oldDateTime, zoomType);
318 318 }
319 319 }
320 320
321 321 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
322 322 {
323 323 auto zoomOrientations = QFlags<Qt::Orientation>{};
324 324
325 325 // Lambda that enables a zoom orientation if the key modifier related to this orientation
326 326 // has
327 327 // been pressed
328 328 auto enableOrientation
329 329 = [&zoomOrientations, event](const auto &orientation, const auto &modifier) {
330 330 auto orientationEnabled = event->modifiers().testFlag(modifier);
331 331 zoomOrientations.setFlag(orientation, orientationEnabled);
332 332 };
333 333 enableOrientation(Qt::Vertical, VERTICAL_ZOOM_MODIFIER);
334 334 enableOrientation(Qt::Horizontal, HORIZONTAL_ZOOM_MODIFIER);
335 335
336 336 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
337 337 }
338 338
339 339 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
340 340 {
341 341 impl->m_IsCalibration = event->modifiers().testFlag(Qt::ControlModifier);
342 342 }
343 343
344 344 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
345 345 {
346 346 impl->m_IsCalibration = false;
347 347 }
348 348
349 349 void VisualizationGraphWidget::onDataCacheVariableUpdated()
350 350 {
351 351 // NOTE:
352 352 // We don't want to call the method for each component of a variable unitarily, but for
353 353 // all
354 354 // its components at once (eg its three components in the case of a vector).
355 355
356 356 // The unordered_multimap does not do this easily, so the question is whether to:
357 357 // - use an ordered_multimap and the algos of std to group the values by key
358 358 // - use a map (unique keys) and store as values directly the list of components
359 359
360 360 auto grapheRange = ui->widget->xAxis->range();
361 361 auto dateTime = SqpDateTime{grapheRange.lower, grapheRange.upper};
362 362
363 363 for (auto it = impl->m_VariableToPlotMultiMap.cbegin();
364 364 it != impl->m_VariableToPlotMultiMap.cend(); ++it) {
365 365 auto variable = it->first;
366 366 qCDebug(LOG_VisualizationGraphWidget())
367 367 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S"
368 368 << variable->dateTime();
369 369 qCDebug(LOG_VisualizationGraphWidget())
370 370 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
371 371 if (dateTime.contains(variable->dateTime()) || dateTime.intersect(variable->dateTime())) {
372 372
373 373 VisualizationGraphHelper::updateData(QVector<QCPAbstractPlottable *>{} << it->second,
374 374 variable->dataSeries(), variable->dateTime());
375 375 }
376 376 }
377 377 }
378 378
379 379 VisualizationGraphWidgetZoomType
380 380 VisualizationGraphWidget::VisualizationGraphWidgetPrivate::getZoomType(const QCPRange &t1,
381 381 const QCPRange &t2)
382 382 {
383 383 // t1.lower <= t2.lower && t2.upper <= t1.upper
384 384 auto zoomType = VisualizationGraphWidgetZoomType::Unknown;
385 385 if (t1.lower <= t2.lower && t2.upper <= t1.upper) {
386 386 zoomType = VisualizationGraphWidgetZoomType::ZoomOut;
387 387 }
388 388 else if (t1.lower > t2.lower && t1.upper > t2.upper) {
389 389 zoomType = VisualizationGraphWidgetZoomType::PanRight;
390 390 }
391 391 else if (t1.lower < t2.lower && t1.upper < t2.upper) {
392 392 zoomType = VisualizationGraphWidgetZoomType::PanLeft;
393 393 }
394 394 else if (t1.lower > t2.lower && t2.upper > t1.upper) {
395 395 zoomType = VisualizationGraphWidgetZoomType::ZoomIn;
396 396 }
397 397 else {
398 398 qCCritical(LOG_VisualizationGraphWidget()) << "getZoomType: Unknown type detected";
399 399 }
400 400 return zoomType;
401 401 }
@@ -1,148 +1,147
1 1 #include "AmdaProvider.h"
2 2 #include "AmdaDefs.h"
3 3 #include "AmdaResultParser.h"
4 4
5 5 #include <Data/DataProviderParameters.h>
6 6 #include <Network/NetworkController.h>
7 7 #include <SqpApplication.h>
8 8 #include <Variable/Variable.h>
9 9
10 10 #include <QNetworkAccessManager>
11 11 #include <QNetworkReply>
12 12 #include <QTemporaryFile>
13 13 #include <QThread>
14 14
15 15 Q_LOGGING_CATEGORY(LOG_AmdaProvider, "AmdaProvider")
16 16
17 17 namespace {
18 18
19 19 /// URL format for a request on AMDA server. The parameters are as follows:
20 20 /// - %1: start date
21 21 /// - %2: end date
22 22 /// - %3: parameter id
23 23 const auto AMDA_URL_FORMAT = QStringLiteral(
24 24 "http://amda.irap.omp.eu/php/rest/"
25 25 "getParameter.php?startTime=%1&stopTime=%2&parameterID=%3&sampling=60&outputFormat=ASCII&"
26 26 "timeFormat=ISO8601&gzip=0");
27 27
28 28 /// Dates format passed in the URL (e.g 2013-09-23T09:00)
29 29 const auto AMDA_TIME_FORMAT = QStringLiteral("yyyy-MM-ddThh:mm:ss");
30 30
31 31 /// Formats a time to a date that can be passed in URL
32 32 QString dateFormat(double sqpDateTime) noexcept
33 33 {
34 34 auto dateTime = QDateTime::fromMSecsSinceEpoch(sqpDateTime * 1000.);
35 35 return dateTime.toString(AMDA_TIME_FORMAT);
36 36 }
37 37
38 38 } // namespace
39 39
40 40 AmdaProvider::AmdaProvider()
41 41 {
42 qCDebug(LOG_NetworkController()) << tr("AmdaProvider::AmdaProvider")
43 << QThread::currentThread();
42 qCDebug(LOG_AmdaProvider()) << tr("AmdaProvider::AmdaProvider") << QThread::currentThread();
44 43 if (auto app = sqpApp) {
45 44 auto &networkController = app->networkController();
46 45 connect(this, SIGNAL(requestConstructed(QNetworkRequest, QUuid,
47 46 std::function<void(QNetworkReply *, QUuid)>)),
48 47 &networkController,
49 48 SLOT(onProcessRequested(QNetworkRequest, QUuid,
50 49 std::function<void(QNetworkReply *, QUuid)>)));
51 50
52 51
53 52 connect(&sqpApp->networkController(), SIGNAL(replyDownloadProgress(QUuid, double)), this,
54 53 SIGNAL(dataProvidedProgress(QUuid, double)));
55 54 }
56 55 }
57 56
58 57 void AmdaProvider::requestDataLoading(QUuid token, const DataProviderParameters &parameters)
59 58 {
60 59 // NOTE: Try to use multithread if possible
61 60 const auto times = parameters.m_Times;
62 61 const auto data = parameters.m_Data;
63 62 for (const auto &dateTime : qAsConst(times)) {
64 63 retrieveData(token, dateTime, data);
65 64 }
66 65 }
67 66
68 67 void AmdaProvider::requestDataAborting(QUuid identifier)
69 68 {
70 69 if (auto app = sqpApp) {
71 70 auto &networkController = app->networkController();
72 71 networkController.onReplyCanceled(identifier);
73 72 }
74 73 }
75 74
76 75 void AmdaProvider::retrieveData(QUuid token, const SqpDateTime &dateTime, const QVariantHash &data)
77 76 {
78 77 // Retrieves product ID from data: if the value is invalid, no request is made
79 78 auto productId = data.value(AMDA_XML_ID_KEY).toString();
80 79 if (productId.isNull()) {
81 80 qCCritical(LOG_AmdaProvider()) << tr("Can't retrieve data: unknown product id");
82 81 return;
83 82 }
84 83 qCInfo(LOG_AmdaProvider()) << tr("AmdaProvider::retrieveData") << dateTime;
85 84
86 85 // /////////// //
87 86 // Creates URL //
88 87 // /////////// //
89 88
90 89 auto startDate = dateFormat(dateTime.m_TStart);
91 90 auto endDate = dateFormat(dateTime.m_TEnd);
92 91
93 92 auto url = QUrl{QString{AMDA_URL_FORMAT}.arg(startDate, endDate, productId)};
94 93 qCInfo(LOG_AmdaProvider()) << tr("AmdaProvider::retrieveData url:") << url;
95 94 auto tempFile = std::make_shared<QTemporaryFile>();
96 95
97 96 // LAMBDA
98 97 auto httpDownloadFinished
99 98 = [this, dateTime, tempFile, token](QNetworkReply *reply, QUuid dataId) noexcept {
100 99 Q_UNUSED(dataId);
101 100
102 101 // Don't do anything if the reply was abort
103 102 if (reply->error() != QNetworkReply::OperationCanceledError) {
104 103
105 104 if (tempFile) {
106 105 auto replyReadAll = reply->readAll();
107 106 if (!replyReadAll.isEmpty()) {
108 107 tempFile->write(replyReadAll);
109 108 }
110 109 tempFile->close();
111 110
112 111 // Parse results file
113 112 if (auto dataSeries = AmdaResultParser::readTxt(tempFile->fileName())) {
114 113 emit dataProvided(token, dataSeries, dateTime);
115 114 }
116 115 else {
117 116 /// @todo ALX : debug
118 117 }
119 118 }
120 119 }
121 120
122 121 };
123 122 auto httpFinishedLambda
124 123 = [this, httpDownloadFinished, tempFile](QNetworkReply *reply, QUuid dataId) noexcept {
125 124
126 125 // Don't do anything if the reply was abort
127 126 if (reply->error() != QNetworkReply::OperationCanceledError) {
128 127 auto downloadFileUrl = QUrl{QString{reply->readAll()}};
129 128
130 129
131 130 qCInfo(LOG_AmdaProvider()) << tr("AmdaProvider::retrieveData downloadFileUrl:")
132 131 << downloadFileUrl;
133 132 // Executes request for downloading file //
134 133
135 134 // Creates destination file
136 135 if (tempFile->open()) {
137 136 // Executes request
138 137 emit requestConstructed(QNetworkRequest{downloadFileUrl}, dataId,
139 138 httpDownloadFinished);
140 139 }
141 140 }
142 141 };
143 142
144 143 // //////////////// //
145 144 // Executes request //
146 145 // //////////////// //
147 146 emit requestConstructed(QNetworkRequest{url}, token, httpFinishedLambda);
148 147 }
General Comments 0
You need to be logged in to leave comments. Login now