##// END OF EJS Templates
Check unsaved data on close
trabillard -
r1294:af6db233f5d0
parent child
Show More
@@ -1,65 +1,66
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 #ifndef SCIQLOP_MAINWINDOW_H
23 23 #define SCIQLOP_MAINWINDOW_H
24 24
25 25 #include <QListWidgetItem>
26 26 #include <QLoggingCategory>
27 27 #include <QMainWindow>
28 28 #include <QProgressBar>
29 29 #include <QProgressDialog>
30 30 #include <QThread>
31 31 #include <QVBoxLayout>
32 32 #include <QWidget>
33 33
34 34 #include <Common/spimpl.h>
35 35
36 36 #include <memory>
37 37
38 38 Q_DECLARE_LOGGING_CATEGORY(LOG_MainWindow)
39 39
40 40 namespace Ui {
41 41 class MainWindow;
42 42 } // namespace Ui
43 43
44 44
45 45 class MainWindow : public QMainWindow {
46 46 Q_OBJECT
47 47
48 48 public:
49 49 explicit MainWindow(QWidget *parent = 0);
50 50 virtual ~MainWindow();
51 51 public slots:
52 52
53 53 protected:
54 54 void changeEvent(QEvent *e);
55 void closeEvent(QCloseEvent *event);
55 56
56 57 private:
57 58 std::unique_ptr<Ui::MainWindow> m_Ui;
58 59 // QWidget *m_progressWidget;
59 60 // QVBoxLayout *m_progressLayout;
60 61 // QList<QLopService*> m_qlopServices;
61 62 class MainWindowPrivate;
62 63 spimpl::unique_impl_ptr<MainWindowPrivate> impl;
63 64 };
64 65
65 66 #endif // SCIQLOP_MAINWINDOW_H
@@ -1,366 +1,405
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 #include <Catalogue/CatalogueController.h>
25 26 #include <Catalogue/CatalogueExplorer.h>
26 27 #include <DataSource/DataSourceController.h>
27 28 #include <DataSource/DataSourceWidget.h>
28 29 #include <Settings/SqpSettingsDialog.h>
29 30 #include <Settings/SqpSettingsGeneralWidget.h>
30 31 #include <SidePane/SqpSidePane.h>
31 32 #include <SqpApplication.h>
32 33 #include <Time/TimeController.h>
33 34 #include <TimeWidget/TimeWidget.h>
34 35 #include <Variable/Variable.h>
35 36 #include <Variable/VariableController.h>
36 37 #include <Visualization/VisualizationController.h>
37 38
38 39 #include <QAction>
40 #include <QCloseEvent>
39 41 #include <QDate>
40 42 #include <QDir>
41 43 #include <QFileDialog>
44 #include <QMessageBox>
42 45 #include <QToolBar>
43 46 #include <QToolButton>
44 47 #include <memory.h>
45 48
46 49 #include "iostream"
47 50
48 51 Q_LOGGING_CATEGORY(LOG_MainWindow, "MainWindow")
49 52
50 53 namespace {
51 54 const auto LEFTMAININSPECTORWIDGETSPLITTERINDEX = 0;
52 55 const auto LEFTINSPECTORSIDEPANESPLITTERINDEX = 1;
53 56 const auto VIEWPLITTERINDEX = 2;
54 57 const auto RIGHTINSPECTORSIDEPANESPLITTERINDEX = 3;
55 58 const auto RIGHTMAININSPECTORWIDGETSPLITTERINDEX = 4;
56 59 }
57 60
58 61 class MainWindow::MainWindowPrivate {
59 62 public:
60 63 explicit MainWindowPrivate(MainWindow *mainWindow)
61 64 : m_LastOpenLeftInspectorSize{},
62 65 m_LastOpenRightInspectorSize{},
63 66 m_GeneralSettingsWidget{new SqpSettingsGeneralWidget{mainWindow}},
64 67 m_SettingsDialog{new SqpSettingsDialog{mainWindow}},
65 68 m_CatalogExplorer{new CatalogueExplorer{mainWindow}}
66 69 {
67 70 }
68 71
69 72 QSize m_LastOpenLeftInspectorSize;
70 73 QSize m_LastOpenRightInspectorSize;
71 74 /// General settings widget. MainWindow has the ownership
72 75 SqpSettingsGeneralWidget *m_GeneralSettingsWidget;
73 76 /// Settings dialog. MainWindow has the ownership
74 77 SqpSettingsDialog *m_SettingsDialog;
75 78 /// Catalogue dialog. MainWindow has the ownership
76 79 CatalogueExplorer *m_CatalogExplorer;
80
81 bool checkDataToSave(QWidget *parentWidget);
77 82 };
78 83
79 84 MainWindow::MainWindow(QWidget *parent)
80 85 : QMainWindow{parent},
81 86 m_Ui{new Ui::MainWindow},
82 87 impl{spimpl::make_unique_impl<MainWindowPrivate>(this)}
83 88 {
84 89 m_Ui->setupUi(this);
85 90
86 91 m_Ui->splitter->setCollapsible(LEFTINSPECTORSIDEPANESPLITTERINDEX, false);
87 92 m_Ui->splitter->setCollapsible(RIGHTINSPECTORSIDEPANESPLITTERINDEX, false);
88 93
89 94 impl->m_CatalogExplorer->setVisualizationWidget(m_Ui->view);
90 95
91 96
92 97 auto leftSidePane = m_Ui->leftInspectorSidePane->sidePane();
93 98 auto openLeftInspectorAction = new QAction{QIcon{
94 99 ":/icones/previous.png",
95 100 },
96 101 tr("Show/hide the left inspector"), this};
97 102
98 103
99 104 auto spacerLeftTop = new QWidget{};
100 105 spacerLeftTop->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
101 106
102 107 auto spacerLeftBottom = new QWidget{};
103 108 spacerLeftBottom->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
104 109
105 110 leftSidePane->addWidget(spacerLeftTop);
106 111 leftSidePane->addAction(openLeftInspectorAction);
107 112 leftSidePane->addWidget(spacerLeftBottom);
108 113
109 114
110 115 auto rightSidePane = m_Ui->rightInspectorSidePane->sidePane();
111 116 auto openRightInspectorAction = new QAction{QIcon{
112 117 ":/icones/next.png",
113 118 },
114 119 tr("Show/hide the right inspector"), this};
115 120
116 121 auto spacerRightTop = new QWidget{};
117 122 spacerRightTop->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
118 123
119 124 auto spacerRightBottom = new QWidget{};
120 125 spacerRightBottom->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
121 126
122 127 rightSidePane->addWidget(spacerRightTop);
123 128 rightSidePane->addAction(openRightInspectorAction);
124 129 rightSidePane->addWidget(spacerRightBottom);
125 130
126 131 openLeftInspectorAction->setCheckable(true);
127 132 openRightInspectorAction->setCheckable(true);
128 133
129 134 auto openInspector = [this](bool checked, bool right, auto action) {
130 135
131 136 action->setIcon(QIcon{(checked xor right) ? ":/icones/next.png" : ":/icones/previous.png"});
132 137
133 138 auto &lastInspectorSize
134 139 = right ? impl->m_LastOpenRightInspectorSize : impl->m_LastOpenLeftInspectorSize;
135 140
136 141 auto nextInspectorSize = right ? m_Ui->rightMainInspectorWidget->size()
137 142 : m_Ui->leftMainInspectorWidget->size();
138 143
139 144 // Update of the last opened geometry
140 145 if (checked) {
141 146 lastInspectorSize = nextInspectorSize;
142 147 }
143 148
144 149 auto startSize = lastInspectorSize;
145 150 auto endSize = startSize;
146 151 endSize.setWidth(0);
147 152
148 153 auto splitterInspectorIndex
149 154 = right ? RIGHTMAININSPECTORWIDGETSPLITTERINDEX : LEFTMAININSPECTORWIDGETSPLITTERINDEX;
150 155
151 156 auto currentSizes = m_Ui->splitter->sizes();
152 157 if (checked) {
153 158 // adjust sizes individually here, e.g.
154 159 currentSizes[splitterInspectorIndex] -= lastInspectorSize.width();
155 160 currentSizes[VIEWPLITTERINDEX] += lastInspectorSize.width();
156 161 m_Ui->splitter->setSizes(currentSizes);
157 162 }
158 163 else {
159 164 // adjust sizes individually here, e.g.
160 165 currentSizes[splitterInspectorIndex] += lastInspectorSize.width();
161 166 currentSizes[VIEWPLITTERINDEX] -= lastInspectorSize.width();
162 167 m_Ui->splitter->setSizes(currentSizes);
163 168 }
164 169
165 170 };
166 171
167 172
168 173 connect(openLeftInspectorAction, &QAction::triggered,
169 174 [openInspector, openLeftInspectorAction](bool checked) {
170 175 openInspector(checked, false, openLeftInspectorAction);
171 176 });
172 177 connect(openRightInspectorAction, &QAction::triggered,
173 178 [openInspector, openRightInspectorAction](bool checked) {
174 179 openInspector(checked, true, openRightInspectorAction);
175 180 });
176 181
177 182 // //////////////// //
178 183 // Menu and Toolbar //
179 184 // //////////////// //
180 185 this->menuBar()->addAction(tr("File"));
181 186 auto toolsMenu = this->menuBar()->addMenu(tr("Tools"));
182 187 toolsMenu->addAction(tr("Settings..."), [this]() {
183 188 // Loads settings
184 189 impl->m_SettingsDialog->loadSettings();
185 190
186 191 // Open settings dialog and save settings if the dialog is accepted
187 192 if (impl->m_SettingsDialog->exec() == QDialog::Accepted) {
188 193 impl->m_SettingsDialog->saveSettings();
189 194 }
190 195
191 196 });
192 197
193 198 auto mainToolBar = this->addToolBar(QStringLiteral("MainToolBar"));
194 199
195 200 auto timeWidget = new TimeWidget{};
196 201 mainToolBar->addWidget(timeWidget);
197 202
198 203 // Interaction modes
199 204 auto actionPointerMode = new QAction{QIcon(":/icones/pointer.png"), "Move", this};
200 205 actionPointerMode->setCheckable(true);
201 206 actionPointerMode->setChecked(sqpApp->plotsInteractionMode()
202 207 == SqpApplication::PlotsInteractionMode::None);
203 208 connect(actionPointerMode, &QAction::triggered,
204 209 []() { sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::None); });
205 210
206 211 auto actionZoomMode = new QAction{QIcon(":/icones/zoom.png"), "Zoom", this};
207 212 actionZoomMode->setCheckable(true);
208 213 actionZoomMode->setChecked(sqpApp->plotsInteractionMode()
209 214 == SqpApplication::PlotsInteractionMode::ZoomBox);
210 215 connect(actionZoomMode, &QAction::triggered, []() {
211 216 sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::ZoomBox);
212 217 });
213 218
214 219 auto actionOrganisationMode = new QAction{QIcon(":/icones/drag.png"), "Organize", this};
215 220 actionOrganisationMode->setCheckable(true);
216 221 actionOrganisationMode->setChecked(sqpApp->plotsInteractionMode()
217 222 == SqpApplication::PlotsInteractionMode::DragAndDrop);
218 223 connect(actionOrganisationMode, &QAction::triggered, []() {
219 224 sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::DragAndDrop);
220 225 });
221 226
222 227 auto actionZonesMode = new QAction{QIcon(":/icones/rectangle.png"), "Zones", this};
223 228 actionZonesMode->setCheckable(true);
224 229 actionZonesMode->setChecked(sqpApp->plotsInteractionMode()
225 230 == SqpApplication::PlotsInteractionMode::SelectionZones);
226 231 connect(actionZonesMode, &QAction::triggered, []() {
227 232 sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::SelectionZones);
228 233 });
229 234
230 235 auto modeActionGroup = new QActionGroup{this};
231 236 modeActionGroup->addAction(actionZoomMode);
232 237 modeActionGroup->addAction(actionZonesMode);
233 238 modeActionGroup->addAction(actionOrganisationMode);
234 239 modeActionGroup->addAction(actionPointerMode);
235 240 modeActionGroup->setExclusive(true);
236 241
237 242 mainToolBar->addSeparator();
238 243 mainToolBar->addAction(actionPointerMode);
239 244 mainToolBar->addAction(actionZoomMode);
240 245 mainToolBar->addAction(actionOrganisationMode);
241 246 mainToolBar->addAction(actionZonesMode);
242 247 mainToolBar->addSeparator();
243 248
244 249 // Cursors
245 250 auto btnCursor = new QToolButton{this};
246 251 btnCursor->setIcon(QIcon(":/icones/cursor.png"));
247 252 btnCursor->setText("Cursor");
248 253 btnCursor->setToolTip("Cursor");
249 254 btnCursor->setPopupMode(QToolButton::InstantPopup);
250 255 auto cursorMenu = new QMenu("CursorMenu", this);
251 256 btnCursor->setMenu(cursorMenu);
252 257
253 258 auto noCursorAction = cursorMenu->addAction("No Cursor");
254 259 noCursorAction->setCheckable(true);
255 260 noCursorAction->setChecked(sqpApp->plotsCursorMode()
256 261 == SqpApplication::PlotsCursorMode::NoCursor);
257 262 connect(noCursorAction, &QAction::triggered,
258 263 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::NoCursor); });
259 264
260 265 cursorMenu->addSeparator();
261 266 auto verticalCursorAction = cursorMenu->addAction("Vertical Cursor");
262 267 verticalCursorAction->setCheckable(true);
263 268 verticalCursorAction->setChecked(sqpApp->plotsCursorMode()
264 269 == SqpApplication::PlotsCursorMode::Vertical);
265 270 connect(verticalCursorAction, &QAction::triggered,
266 271 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Vertical); });
267 272
268 273 auto temporalCursorAction = cursorMenu->addAction("Temporal Cursor");
269 274 temporalCursorAction->setCheckable(true);
270 275 temporalCursorAction->setChecked(sqpApp->plotsCursorMode()
271 276 == SqpApplication::PlotsCursorMode::Temporal);
272 277 connect(temporalCursorAction, &QAction::triggered,
273 278 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Temporal); });
274 279
275 280 auto horizontalCursorAction = cursorMenu->addAction("Horizontal Cursor");
276 281 horizontalCursorAction->setCheckable(true);
277 282 horizontalCursorAction->setChecked(sqpApp->plotsCursorMode()
278 283 == SqpApplication::PlotsCursorMode::Horizontal);
279 284 connect(horizontalCursorAction, &QAction::triggered,
280 285 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Horizontal); });
281 286
282 287 auto crossCursorAction = cursorMenu->addAction("Cross Cursor");
283 288 crossCursorAction->setCheckable(true);
284 289 crossCursorAction->setChecked(sqpApp->plotsCursorMode()
285 290 == SqpApplication::PlotsCursorMode::Cross);
286 291 connect(crossCursorAction, &QAction::triggered,
287 292 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Cross); });
288 293
289 294 mainToolBar->addWidget(btnCursor);
290 295
291 296 auto cursorModeActionGroup = new QActionGroup{this};
292 297 cursorModeActionGroup->setExclusive(true);
293 298 cursorModeActionGroup->addAction(noCursorAction);
294 299 cursorModeActionGroup->addAction(verticalCursorAction);
295 300 cursorModeActionGroup->addAction(temporalCursorAction);
296 301 cursorModeActionGroup->addAction(horizontalCursorAction);
297 302 cursorModeActionGroup->addAction(crossCursorAction);
298 303
299 304 // Catalog
300 305 mainToolBar->addSeparator();
301 306 mainToolBar->addAction(QIcon(":/icones/catalogue.png"), "Catalogues",
302 307 [this]() { impl->m_CatalogExplorer->show(); });
303 308
304 309 // //////// //
305 310 // Settings //
306 311 // //////// //
307 312
308 313 // Registers "general settings" widget to the settings dialog
309 314 impl->m_SettingsDialog->registerWidget(QStringLiteral("General"),
310 315 impl->m_GeneralSettingsWidget);
311 316
312 317 // /////////// //
313 318 // Connections //
314 319 // /////////// //
315 320
316 321 // Controllers / controllers connections
317 322 connect(&sqpApp->timeController(), SIGNAL(timeUpdated(SqpRange)), &sqpApp->variableController(),
318 323 SLOT(onDateTimeOnSelection(SqpRange)));
319 324
320 325 // Widgets / controllers connections
321 326
322 327 // DataSource
323 328 connect(&sqpApp->dataSourceController(), SIGNAL(dataSourceItemSet(DataSourceItem *)),
324 329 m_Ui->dataSourceWidget, SLOT(addDataSource(DataSourceItem *)));
325 330
326 331 // Time
327 332 connect(timeWidget, SIGNAL(timeUpdated(SqpRange)), &sqpApp->timeController(),
328 333 SLOT(onTimeToUpdate(SqpRange)));
329 334
330 335 // Visualization
331 336 connect(&sqpApp->visualizationController(),
332 337 SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)), m_Ui->view,
333 338 SLOT(onVariableAboutToBeDeleted(std::shared_ptr<Variable>)));
334 339
335 340 connect(&sqpApp->visualizationController(),
336 341 SIGNAL(rangeChanged(std::shared_ptr<Variable>, const SqpRange &)), m_Ui->view,
337 342 SLOT(onRangeChanged(std::shared_ptr<Variable>, const SqpRange &)));
338 343
339 344 // Widgets / widgets connections
340 345
341 346 // For the following connections, we use DirectConnection to allow each widget that can
342 347 // potentially attach a menu to the variable's menu to do so before this menu is displayed.
343 348 // The order of connections is also important, since it determines the order in which each
344 349 // widget will attach its menu
345 350 connect(
346 351 m_Ui->variableInspectorWidget,
347 352 SIGNAL(tableMenuAboutToBeDisplayed(QMenu *, const QVector<std::shared_ptr<Variable> > &)),
348 353 m_Ui->view, SLOT(attachVariableMenu(QMenu *, const QVector<std::shared_ptr<Variable> > &)),
349 354 Qt::DirectConnection);
350 355 }
351 356
352 357 MainWindow::~MainWindow()
353 358 {
354 359 }
355 360
356 361 void MainWindow::changeEvent(QEvent *e)
357 362 {
358 363 QMainWindow::changeEvent(e);
359 364 switch (e->type()) {
360 365 case QEvent::LanguageChange:
361 366 m_Ui->retranslateUi(this);
362 367 break;
363 368 default:
364 369 break;
365 370 }
366 371 }
372
373 void MainWindow::closeEvent(QCloseEvent *event)
374 {
375 if (!impl->checkDataToSave(this)) {
376 event->ignore();
377 }
378 else {
379 event->accept();
380 }
381 }
382
383 bool MainWindow::MainWindowPrivate::checkDataToSave(QWidget *parentWidget)
384 {
385 auto hasChanges = sqpApp->catalogueController().hasChanges();
386 if (hasChanges) {
387 // There are some unsaved changes
388 switch (QMessageBox::question(
389 parentWidget, "Save changes",
390 tr("The catalogue controller unsaved changes.\nDo you want to save them ?"),
391 QMessageBox::SaveAll | QMessageBox::Discard | QMessageBox::Cancel,
392 QMessageBox::SaveAll)) {
393 case QMessageBox::SaveAll:
394 sqpApp->catalogueController().saveAll();
395 break;
396 case QMessageBox::Discard:
397 break;
398 case QMessageBox::Cancel:
399 default:
400 return false;
401 }
402 }
403
404 return true;
405 }
@@ -1,81 +1,82
1 1 #ifndef SCIQLOP_CATALOGUECONTROLLER_H
2 2 #define SCIQLOP_CATALOGUECONTROLLER_H
3 3
4 4 #include "CoreGlobal.h"
5 5
6 6 #include <Data/SqpRange.h>
7 7
8 8 #include <QLoggingCategory>
9 9 #include <QObject>
10 10 #include <QUuid>
11 11
12 12 #include <Common/spimpl.h>
13 13
14 14 #include <memory>
15 15
16 16 class DBCatalogue;
17 17 class DBEvent;
18 18 class DBEventProduct;
19 19
20 20 Q_DECLARE_LOGGING_CATEGORY(LOG_CatalogueController)
21 21
22 22 class DataSourceItem;
23 23 class Variable;
24 24
25 25 /**
26 26 * @brief The CatalogueController class aims to handle catalogues and event using the CatalogueAPI
27 27 * library.
28 28 */
29 29 class SCIQLOP_CORE_EXPORT CatalogueController : public QObject {
30 30 Q_OBJECT
31 31 public:
32 32 explicit CatalogueController(QObject *parent = 0);
33 33 virtual ~CatalogueController();
34 34
35 35 // DB
36 36 QStringList getRepositories() const;
37 37 void addDB(const QString &dbPath);
38 38 void saveDB(const QString &destinationPath, const QString &repository);
39 39
40 40 // Event
41 41 /// retrieveEvents with empty repository retrieve them from the default repository
42 42 std::list<std::shared_ptr<DBEvent> > retrieveEvents(const QString &repository) const;
43 43 std::list<std::shared_ptr<DBEvent> > retrieveAllEvents() const;
44 44 std::list<std::shared_ptr<DBEvent> >
45 45 retrieveEventsFromCatalogue(std::shared_ptr<DBCatalogue> catalogue) const;
46 46 void addEvent(std::shared_ptr<DBEvent> event);
47 47 void updateEvent(std::shared_ptr<DBEvent> event);
48 48 void updateEventProduct(std::shared_ptr<DBEventProduct> eventProduct);
49 49 void removeEvent(std::shared_ptr<DBEvent> event);
50 50 // void trashEvent(std::shared_ptr<DBEvent> event);
51 51 // void restore(QUuid eventId);
52 52 void saveEvent(std::shared_ptr<DBEvent> event);
53 53 bool eventHasChanges(std::shared_ptr<DBEvent> event) const;
54 54
55 55 // Catalogue
56 56 // bool createCatalogue(const QString &name, QVector<QUuid> eventList);
57 57 /// retrieveEvents with empty repository retrieve them from the default repository
58 58 std::list<std::shared_ptr<DBCatalogue> > retrieveCatalogues(const QString &repository
59 59 = QString()) const;
60 60 void updateCatalogue(std::shared_ptr<DBCatalogue> catalogue);
61 61 void removeCatalogue(std::shared_ptr<DBCatalogue> catalogue);
62 62 void saveCatalogue(std::shared_ptr<DBCatalogue> catalogue);
63 63
64 64 void saveAll();
65 bool hasChanges() const;
65 66
66 67 /// Returns the MIME data associated to a list of variables
67 68 QByteArray mimeDataForEvents(const QVector<std::shared_ptr<DBEvent> > &events) const;
68 69
69 70 /// Returns the list of variables contained in a MIME data
70 71 QVector<std::shared_ptr<DBEvent> > eventsForMimeData(const QByteArray &mimeData) const;
71 72
72 73 public slots:
73 74 /// Manage init/end of the controller
74 75 void initialize();
75 76
76 77 private:
77 78 class CatalogueControllerPrivate;
78 79 spimpl::unique_impl_ptr<CatalogueControllerPrivate> impl;
79 80 };
80 81
81 82 #endif // SCIQLOP_CATALOGUECONTROLLER_H
@@ -1,388 +1,393
1 1 #include <Catalogue/CatalogueController.h>
2 2
3 3 #include <Variable/Variable.h>
4 4
5 5 #include <CatalogueDao.h>
6 6
7 7 #include <ComparaisonPredicate.h>
8 8 #include <CompoundPredicate.h>
9 9 #include <DBCatalogue.h>
10 10 #include <DBEvent.h>
11 11 #include <DBEventProduct.h>
12 12 #include <DBTag.h>
13 13 #include <IRequestPredicate.h>
14 14
15 15 #include <QDataStream>
16 16 #include <QMutex>
17 17 #include <QThread>
18 18
19 19 #include <QDir>
20 20 #include <QStandardPaths>
21 21
22 22 Q_LOGGING_CATEGORY(LOG_CatalogueController, "CatalogueController")
23 23
24 24 namespace {
25 25
26 26 static QString REPOSITORY_WORK_SUFFIX = QString{"_work"};
27 27 static QString REPOSITORY_TRASH_SUFFIX = QString{"_trash"};
28 28 }
29 29
30 30 class CatalogueController::CatalogueControllerPrivate {
31 31
32 32 public:
33 33 explicit CatalogueControllerPrivate(CatalogueController *parent) : m_Q{parent} {}
34 34
35 35 CatalogueDao m_CatalogueDao;
36 36
37 37 QStringList m_RepositoryList;
38 38 CatalogueController *m_Q;
39 39
40 40 QSet<QString> m_EventKeysWithChanges;
41 41
42 42 QString eventUniqueKey(const std::shared_ptr<DBEvent> &event) const;
43 43
44 44 void copyDBtoDB(const QString &dbFrom, const QString &dbTo);
45 45 QString toWorkRepository(QString repository);
46 46 QString toSyncRepository(QString repository);
47 47 void savAllDB();
48 48
49 49 void saveEvent(std::shared_ptr<DBEvent> event, bool persist = true);
50 50 void saveCatalogue(std::shared_ptr<DBCatalogue> catalogue, bool persist = true);
51 51 };
52 52
53 53 CatalogueController::CatalogueController(QObject *parent)
54 54 : impl{spimpl::make_unique_impl<CatalogueControllerPrivate>(this)}
55 55 {
56 56 qCDebug(LOG_CatalogueController()) << tr("CatalogueController construction")
57 57 << QThread::currentThread();
58 58 }
59 59
60 60 CatalogueController::~CatalogueController()
61 61 {
62 62 qCDebug(LOG_CatalogueController()) << tr("CatalogueController destruction")
63 63 << QThread::currentThread();
64 64 }
65 65
66 66 QStringList CatalogueController::getRepositories() const
67 67 {
68 68 return impl->m_RepositoryList;
69 69 }
70 70
71 71 void CatalogueController::addDB(const QString &dbPath)
72 72 {
73 73 QDir dbDir(dbPath);
74 74 if (dbDir.exists()) {
75 75 auto dirName = dbDir.dirName();
76 76
77 77 if (std::find(impl->m_RepositoryList.cbegin(), impl->m_RepositoryList.cend(), dirName)
78 78 != impl->m_RepositoryList.cend()) {
79 79 qCCritical(LOG_CatalogueController())
80 80 << tr("Impossible to addDB that is already loaded");
81 81 }
82 82
83 83 if (!impl->m_CatalogueDao.addDB(dbPath, dirName)) {
84 84 qCCritical(LOG_CatalogueController())
85 85 << tr("Impossible to addDB %1 from %2 ").arg(dirName, dbPath);
86 86 }
87 87 else {
88 88 impl->m_RepositoryList << dirName;
89 89 impl->copyDBtoDB(dirName, impl->toWorkRepository(dirName));
90 90 }
91 91 }
92 92 else {
93 93 qCCritical(LOG_CatalogueController()) << tr("Impossible to addDB that not exists: ")
94 94 << dbPath;
95 95 }
96 96 }
97 97
98 98 void CatalogueController::saveDB(const QString &destinationPath, const QString &repository)
99 99 {
100 100 if (!impl->m_CatalogueDao.saveDB(destinationPath, repository)) {
101 101 qCCritical(LOG_CatalogueController())
102 102 << tr("Impossible to saveDB %1 from %2 ").arg(repository, destinationPath);
103 103 }
104 104 }
105 105
106 106 std::list<std::shared_ptr<DBEvent> >
107 107 CatalogueController::retrieveEvents(const QString &repository) const
108 108 {
109 109 QString dbDireName = repository.isEmpty() ? REPOSITORY_DEFAULT : repository;
110 110
111 111 auto eventsShared = std::list<std::shared_ptr<DBEvent> >{};
112 112 auto events = impl->m_CatalogueDao.getEvents(impl->toWorkRepository(dbDireName));
113 113 for (auto event : events) {
114 114 eventsShared.push_back(std::make_shared<DBEvent>(event));
115 115 }
116 116 return eventsShared;
117 117 }
118 118
119 119 std::list<std::shared_ptr<DBEvent> > CatalogueController::retrieveAllEvents() const
120 120 {
121 121 auto eventsShared = std::list<std::shared_ptr<DBEvent> >{};
122 122 for (auto repository : impl->m_RepositoryList) {
123 123 eventsShared.splice(eventsShared.end(), retrieveEvents(repository));
124 124 }
125 125
126 126 return eventsShared;
127 127 }
128 128
129 129 std::list<std::shared_ptr<DBEvent> >
130 130 CatalogueController::retrieveEventsFromCatalogue(std::shared_ptr<DBCatalogue> catalogue) const
131 131 {
132 132 auto eventsShared = std::list<std::shared_ptr<DBEvent> >{};
133 133 auto events = impl->m_CatalogueDao.getCatalogueEvents(*catalogue);
134 134 for (auto event : events) {
135 135 eventsShared.push_back(std::make_shared<DBEvent>(event));
136 136 }
137 137 return eventsShared;
138 138 }
139 139
140 140 void CatalogueController::updateEvent(std::shared_ptr<DBEvent> event)
141 141 {
142 142 event->setRepository(impl->toWorkRepository(event->getRepository()));
143 143
144 144 auto uniqueId = impl->eventUniqueKey(event);
145 145 impl->m_EventKeysWithChanges.insert(uniqueId);
146 146
147 147 impl->m_CatalogueDao.updateEvent(*event);
148 148 }
149 149
150 150 void CatalogueController::updateEventProduct(std::shared_ptr<DBEventProduct> eventProduct)
151 151 {
152 152 impl->m_CatalogueDao.updateEventProduct(*eventProduct);
153 153 }
154 154
155 155 void CatalogueController::removeEvent(std::shared_ptr<DBEvent> event)
156 156 {
157 157 // Remove it from both repository and repository_work
158 158 event->setRepository(impl->toWorkRepository(event->getRepository()));
159 159 impl->m_CatalogueDao.removeEvent(*event);
160 160 event->setRepository(impl->toSyncRepository(event->getRepository()));
161 161 impl->m_CatalogueDao.removeEvent(*event);
162 162 }
163 163
164 164 void CatalogueController::addEvent(std::shared_ptr<DBEvent> event)
165 165 {
166 166 event->setRepository(impl->toWorkRepository(event->getRepository()));
167 167
168 168 auto eventTemp = *event;
169 169 impl->m_CatalogueDao.addEvent(eventTemp);
170 170
171 171 // Call update is necessary at the creation of add Event if it has some tags or some event
172 172 // products
173 173 if (!event->getEventProducts().empty() || !event->getTags().empty()) {
174 174
175 175 auto eventProductsTemp = eventTemp.getEventProducts();
176 176 auto eventProductTempUpdated = std::list<DBEventProduct>{};
177 177 for (auto eventProductTemp : eventProductsTemp) {
178 178 eventProductTemp.setEvent(eventTemp);
179 179 eventProductTempUpdated.push_back(eventProductTemp);
180 180 }
181 181 eventTemp.setEventProducts(eventProductTempUpdated);
182 182
183 183 impl->m_CatalogueDao.updateEvent(eventTemp);
184 184 }
185 185 }
186 186
187 187 void CatalogueController::saveEvent(std::shared_ptr<DBEvent> event)
188 188 {
189 189 impl->saveEvent(event, true);
190 190 impl->m_EventKeysWithChanges.remove(impl->eventUniqueKey(event));
191 191 }
192 192
193 193 bool CatalogueController::eventHasChanges(std::shared_ptr<DBEvent> event) const
194 194 {
195 195 return impl->m_EventKeysWithChanges.contains(impl->eventUniqueKey(event));
196 196 }
197 197
198 198 std::list<std::shared_ptr<DBCatalogue> >
199 199 CatalogueController::retrieveCatalogues(const QString &repository) const
200 200 {
201 201 QString dbDireName = repository.isEmpty() ? REPOSITORY_DEFAULT : repository;
202 202
203 203 auto cataloguesShared = std::list<std::shared_ptr<DBCatalogue> >{};
204 204 auto catalogues = impl->m_CatalogueDao.getCatalogues(impl->toWorkRepository(dbDireName));
205 205 for (auto catalogue : catalogues) {
206 206 cataloguesShared.push_back(std::make_shared<DBCatalogue>(catalogue));
207 207 }
208 208 return cataloguesShared;
209 209 }
210 210
211 211 void CatalogueController::updateCatalogue(std::shared_ptr<DBCatalogue> catalogue)
212 212 {
213 213 catalogue->setRepository(impl->toWorkRepository(catalogue->getRepository()));
214 214
215 215 impl->m_CatalogueDao.updateCatalogue(*catalogue);
216 216 }
217 217
218 218 void CatalogueController::removeCatalogue(std::shared_ptr<DBCatalogue> catalogue)
219 219 {
220 220 // Remove it from both repository and repository_work
221 221 catalogue->setRepository(impl->toWorkRepository(catalogue->getRepository()));
222 222 impl->m_CatalogueDao.removeCatalogue(*catalogue);
223 223 catalogue->setRepository(impl->toSyncRepository(catalogue->getRepository()));
224 224 impl->m_CatalogueDao.removeCatalogue(*catalogue);
225 225 }
226 226
227 227 void CatalogueController::saveCatalogue(std::shared_ptr<DBCatalogue> catalogue)
228 228 {
229 229 impl->saveCatalogue(catalogue, true);
230 230 }
231 231
232 232 void CatalogueController::saveAll()
233 233 {
234 234 for (auto repository : impl->m_RepositoryList) {
235 235 // Save Event
236 236 auto events = this->retrieveEvents(repository);
237 237 for (auto event : events) {
238 238 impl->saveEvent(event, false);
239 239 }
240 240
241 241 // Save Catalogue
242 242 auto catalogues = this->retrieveCatalogues(repository);
243 243 for (auto catalogue : catalogues) {
244 244 impl->saveCatalogue(catalogue, false);
245 245 }
246 246 }
247 247
248 248 impl->savAllDB();
249 249 impl->m_EventKeysWithChanges.clear();
250 250 }
251 251
252 bool CatalogueController::hasChanges() const
253 {
254 return !impl->m_EventKeysWithChanges.isEmpty(); // TODO: catalogues
255 }
256
252 257 QByteArray
253 258 CatalogueController::mimeDataForEvents(const QVector<std::shared_ptr<DBEvent> > &events) const
254 259 {
255 260 auto encodedData = QByteArray{};
256 261
257 262 QMap<QString, QVariantList> idsPerRepository;
258 263 for (auto event : events) {
259 264 idsPerRepository[event->getRepository()] << event->getUniqId();
260 265 }
261 266
262 267 QDataStream stream{&encodedData, QIODevice::WriteOnly};
263 268 stream << idsPerRepository;
264 269
265 270 return encodedData;
266 271 }
267 272
268 273 QVector<std::shared_ptr<DBEvent> >
269 274 CatalogueController::eventsForMimeData(const QByteArray &mimeData) const
270 275 {
271 276 auto events = QVector<std::shared_ptr<DBEvent> >{};
272 277 QDataStream stream{mimeData};
273 278
274 279 QMap<QString, QVariantList> idsPerRepository;
275 280 stream >> idsPerRepository;
276 281
277 282 for (auto it = idsPerRepository.cbegin(); it != idsPerRepository.cend(); ++it) {
278 283 auto repository = it.key();
279 284 auto allRepositoryEvent = retrieveEvents(repository);
280 285 for (auto uuid : it.value()) {
281 286 for (auto repositoryEvent : allRepositoryEvent) {
282 287 if (uuid.toUuid() == repositoryEvent->getUniqId()) {
283 288 events << repositoryEvent;
284 289 }
285 290 }
286 291 }
287 292 }
288 293
289 294 return events;
290 295 }
291 296
292 297 void CatalogueController::initialize()
293 298 {
294 299 <<<<<<< HEAD
295 300 qCDebug(LOG_CatalogueController()) << tr("CatalogueController init")
296 301 << QThread::currentThread();
297 302 impl->m_WorkingMutex.lock();
298 303 =======
299 304 qCDebug(LOG_CatalogueController())
300 305 << tr("CatalogueController init") << QThread::currentThread();
301 306 >>>>>>> 286decc... unthread the catalogue controller
302 307 impl->m_CatalogueDao.initialize();
303 308 auto defaultRepositoryLocation
304 309 = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
305 310
306 311 QDir defaultRepositoryLocationDir;
307 312 if (defaultRepositoryLocationDir.mkpath(defaultRepositoryLocation)) {
308 313 defaultRepositoryLocationDir.cd(defaultRepositoryLocation);
309 314 auto defaultRepository = defaultRepositoryLocationDir.absoluteFilePath(REPOSITORY_DEFAULT);
310 315 qCInfo(LOG_CatalogueController()) << tr("Persistant data loading from: ")
311 316 << defaultRepository;
312 317 this->addDB(defaultRepository);
313 318 }
314 319 else {
315 320 qCWarning(LOG_CatalogueController())
316 321 << tr("Cannot load the persistent default repository from ")
317 322 << defaultRepositoryLocation;
318 323 }
319 324
320 325 qCDebug(LOG_CatalogueController()) << tr("CatalogueController init END");
321 326 }
322 327
323 328 QString CatalogueController::CatalogueControllerPrivate::eventUniqueKey(
324 329 const std::shared_ptr<DBEvent> &event) const
325 330 {
326 331 return event->getUniqId().toString().append(event->getRepository());
327 332 }
328 333
329 334 void CatalogueController::CatalogueControllerPrivate::copyDBtoDB(const QString &dbFrom,
330 335 const QString &dbTo)
331 336 {
332 337 // auto cataloguesShared = std::list<std::shared_ptr<DBCatalogue> >{};
333 338 auto catalogues = m_CatalogueDao.getCatalogues(dbFrom);
334 339 auto events = m_CatalogueDao.getEvents(dbFrom);
335 340 for (auto catalogue : catalogues) {
336 341 m_CatalogueDao.copyCatalogue(catalogue, dbTo, true);
337 342 }
338 343
339 344 for (auto event : events) {
340 345 m_CatalogueDao.copyEvent(event, dbTo, true);
341 346 }
342 347 }
343 348
344 349 QString CatalogueController::CatalogueControllerPrivate::toWorkRepository(QString repository)
345 350 {
346 351 auto syncRepository = toSyncRepository(repository);
347 352
348 353 return QString("%1%2").arg(syncRepository, REPOSITORY_WORK_SUFFIX);
349 354 }
350 355
351 356 QString CatalogueController::CatalogueControllerPrivate::toSyncRepository(QString repository)
352 357 {
353 358 auto syncRepository = repository;
354 359 if (repository.endsWith(REPOSITORY_WORK_SUFFIX)) {
355 360 syncRepository.remove(REPOSITORY_WORK_SUFFIX);
356 361 }
357 362 else if (repository.endsWith(REPOSITORY_TRASH_SUFFIX)) {
358 363 syncRepository.remove(REPOSITORY_TRASH_SUFFIX);
359 364 }
360 365 return syncRepository;
361 366 }
362 367
363 368 void CatalogueController::CatalogueControllerPrivate::savAllDB()
364 369 {
365 370 for (auto repository : m_RepositoryList) {
366 371 auto defaultRepositoryLocation
367 372 = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
368 373 m_CatalogueDao.saveDB(defaultRepositoryLocation, repository);
369 374 }
370 375 }
371 376
372 377 void CatalogueController::CatalogueControllerPrivate::saveEvent(std::shared_ptr<DBEvent> event,
373 378 bool persist)
374 379 {
375 380 m_CatalogueDao.copyEvent(*event, toSyncRepository(event->getRepository()), true);
376 381 if (persist) {
377 382 savAllDB();
378 383 }
379 384 }
380 385
381 386 void CatalogueController::CatalogueControllerPrivate::saveCatalogue(
382 387 std::shared_ptr<DBCatalogue> catalogue, bool persist)
383 388 {
384 389 m_CatalogueDao.copyCatalogue(*catalogue, toSyncRepository(catalogue->getRepository()), true);
385 390 if (persist) {
386 391 savAllDB();
387 392 }
388 393 }
General Comments 3
Under Review
author

Auto status change to "Under Review"

Approved
author

Status change > Approved

You need to be logged in to leave comments. Login now