##// END OF EJS Templates
"Apply" and "cancel" buttons on an event
trabillard -
r1194:73d5f3ef941a
parent child
Show More
@@ -0,0 +1,13
1 #ifndef SCIQLOP_CATALOGUEEXPLORERHELPER_H
2 #define SCIQLOP_CATALOGUEEXPLORERHELPER_H
3
4 #include <QWidget>
5
6 #include <functional>
7
8 struct CatalogueExplorerHelper {
9 static QWidget *buildValidationWidget(QWidget *parent, std::function<void()> save,
10 std::function<void()> discard);
11 };
12
13 #endif // SCIQLOP_CATALOGUEEXPLORERHELPER_H
@@ -0,0 +1,32
1 #include "Catalogue/CatalogueExplorerHelper.h"
2
3 #include <QBoxLayout>
4 #include <QToolButton>
5
6 const auto VALIDATION_BUTTON_ICON_SIZE = 12;
7
8 QWidget *CatalogueExplorerHelper::buildValidationWidget(QWidget *parent, std::function<void()> save,
9 std::function<void()> discard)
10 {
11 auto widget = new QWidget{parent};
12
13 auto layout = new QHBoxLayout{widget};
14 layout->setContentsMargins(0, 0, 0, 0);
15 layout->setSpacing(0);
16
17 auto btnValid = new QToolButton{widget};
18 btnValid->setIcon(QIcon{":/icones/save"});
19 btnValid->setIconSize(QSize{VALIDATION_BUTTON_ICON_SIZE, VALIDATION_BUTTON_ICON_SIZE});
20 btnValid->setAutoRaise(true);
21 QObject::connect(btnValid, &QToolButton::clicked, save);
22 layout->addWidget(btnValid);
23
24 auto btnDiscard = new QToolButton{widget};
25 btnDiscard->setIcon(QIcon{":/icones/discard"});
26 btnDiscard->setIconSize(QSize{VALIDATION_BUTTON_ICON_SIZE, VALIDATION_BUTTON_ICON_SIZE});
27 btnDiscard->setAutoRaise(true);
28 QObject::connect(btnDiscard, &QToolButton::clicked, discard);
29 layout->addWidget(btnDiscard);
30
31 return widget;
32 }
@@ -1,46 +1,68
1 #ifndef SCIQLOP_CATALOGUEEVENTSMODEL_H
1 #ifndef SCIQLOP_CATALOGUEEVENTSMODEL_H
2 #define SCIQLOP_CATALOGUEEVENTSMODEL_H
2 #define SCIQLOP_CATALOGUEEVENTSMODEL_H
3
3
4 #include <Common/spimpl.h>
4 #include <Common/spimpl.h>
5 #include <QAbstractItemModel>
5 #include <QAbstractItemModel>
6 #include <QLoggingCategory>
7 #include <unordered_set>
6
8
7 class DBEvent;
9 class DBEvent;
8 class DBEventProduct;
10 class DBEventProduct;
9
11
12 Q_DECLARE_LOGGING_CATEGORY(LOG_CatalogueEventsModel)
13
10 class CatalogueEventsModel : public QAbstractItemModel {
14 class CatalogueEventsModel : public QAbstractItemModel {
15 Q_OBJECT
16
17 signals:
18 void modelSorted();
19
11 public:
20 public:
12 CatalogueEventsModel(QObject *parent = nullptr);
21 CatalogueEventsModel(QObject *parent = nullptr);
13
22
23 enum class Column { Name, TStart, TEnd, Tags, Product, Validation, NbColumn };
24
14 void setEvents(const QVector<std::shared_ptr<DBEvent> > &events);
25 void setEvents(const QVector<std::shared_ptr<DBEvent> > &events);
15 void addEvent(const std::shared_ptr<DBEvent> &event);
26 void addEvent(const std::shared_ptr<DBEvent> &event);
16 void removeEvent(const std::shared_ptr<DBEvent> &event);
27 void removeEvent(const std::shared_ptr<DBEvent> &event);
28 QVector<std::shared_ptr<DBEvent> > events() const;
17
29
18 enum class ItemType { Root, Event, EventProduct };
30 enum class ItemType { Root, Event, EventProduct };
19 ItemType itemTypeOf(const QModelIndex &index) const;
31 ItemType itemTypeOf(const QModelIndex &index) const;
20 std::shared_ptr<DBEvent> getEvent(const QModelIndex &index) const;
32 std::shared_ptr<DBEvent> getEvent(const QModelIndex &index) const;
21 std::shared_ptr<DBEvent> getParentEvent(const QModelIndex &index) const;
33 std::shared_ptr<DBEvent> getParentEvent(const QModelIndex &index) const;
22 std::shared_ptr<DBEventProduct> getEventProduct(const QModelIndex &index) const;
34 std::shared_ptr<DBEventProduct> getEventProduct(const QModelIndex &index) const;
23
35
36 /// Refresh the data for the specified event
24 void refreshEvent(const std::shared_ptr<DBEvent> &event);
37 void refreshEvent(const std::shared_ptr<DBEvent> &event);
25
38
39 /// Returns a QModelIndex which represent the specified event
40 QModelIndex indexOf(const std::shared_ptr<DBEvent> &event) const;
41
42 /// Marks a change flag on the specified event to allow sorting on the validation column
43 void setEventHasChanges(const std::shared_ptr<DBEvent> &event, bool hasChanges);
44
45 /// Returns true if the specified event has unsaved changes
46 bool eventsHasChanges(const std::shared_ptr<DBEvent> &event) const;
47
26 // Model
48 // Model
27 QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
49 QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
28 QModelIndex parent(const QModelIndex &index) const;
50 QModelIndex parent(const QModelIndex &index) const;
29 int rowCount(const QModelIndex &parent = QModelIndex()) const override;
51 int rowCount(const QModelIndex &parent = QModelIndex()) const override;
30 int columnCount(const QModelIndex &parent = QModelIndex()) const override;
52 int columnCount(const QModelIndex &parent = QModelIndex()) const override;
31 Qt::ItemFlags flags(const QModelIndex &index) const override;
53 Qt::ItemFlags flags(const QModelIndex &index) const override;
32 QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
54 QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
33 QVariant headerData(int section, Qt::Orientation orientation,
55 QVariant headerData(int section, Qt::Orientation orientation,
34 int role = Qt::DisplayRole) const override;
56 int role = Qt::DisplayRole) const override;
35 void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override;
57 void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override;
36
58
37 Qt::DropActions supportedDragActions() const override;
59 Qt::DropActions supportedDragActions() const override;
38 QStringList mimeTypes() const override;
60 QStringList mimeTypes() const override;
39 QMimeData *mimeData(const QModelIndexList &indexes) const override;
61 QMimeData *mimeData(const QModelIndexList &indexes) const override;
40
62
41 private:
63 private:
42 class CatalogueEventsModelPrivate;
64 class CatalogueEventsModelPrivate;
43 spimpl::unique_impl_ptr<CatalogueEventsModelPrivate> impl;
65 spimpl::unique_impl_ptr<CatalogueEventsModelPrivate> impl;
44 };
66 };
45
67
46 #endif // SCIQLOP_CATALOGUEEVENTSMODEL_H
68 #endif // SCIQLOP_CATALOGUEEVENTSMODEL_H
@@ -1,33 +1,36
1 #ifndef SCIQLOP_CATALOGUETREEWIDGETITEM_H
1 #ifndef SCIQLOP_CATALOGUETREEWIDGETITEM_H
2 #define SCIQLOP_CATALOGUETREEWIDGETITEM_H
2 #define SCIQLOP_CATALOGUETREEWIDGETITEM_H
3
3
4 #include <Common/spimpl.h>
4 #include <Common/spimpl.h>
5 #include <QTreeWidgetItem>
5 #include <QTreeWidgetItem>
6
6
7 class DBCatalogue;
7 class DBCatalogue;
8
8
9
9
10 class CatalogueTreeWidgetItem : public QTreeWidgetItem {
10 class CatalogueTreeWidgetItem : public QTreeWidgetItem {
11 public:
11 public:
12 CatalogueTreeWidgetItem(std::shared_ptr<DBCatalogue> catalogue,
12 CatalogueTreeWidgetItem(std::shared_ptr<DBCatalogue> catalogue,
13 int type = QTreeWidgetItem::Type);
13 int type = QTreeWidgetItem::Type);
14
14
15 QVariant data(int column, int role) const override;
15 QVariant data(int column, int role) const override;
16 void setData(int column, int role, const QVariant &value) override;
16 void setData(int column, int role, const QVariant &value) override;
17
17
18 /// Returns the catalogue represented by the item
18 /// Returns the catalogue represented by the item
19 std::shared_ptr<DBCatalogue> catalogue() const;
19 std::shared_ptr<DBCatalogue> catalogue() const;
20
20
21 /// Displays or hides the save and cancel buttons indicating that the catalogue has unsaved
21 /// Displays or hides the save and cancel buttons indicating that the catalogue has unsaved
22 /// changes
22 /// changes
23 void setHasChanges(bool value);
23 void setHasChanges(bool value);
24
24
25 /// Returns true if the widget indicating the event has unsaved changes is displayed
26 bool hasChanges();
27
25 /// Refreshes the data displayed by the item from the catalogue
28 /// Refreshes the data displayed by the item from the catalogue
26 void refresh();
29 void refresh();
27
30
28 private:
31 private:
29 class CatalogueTreeWidgetItemPrivate;
32 class CatalogueTreeWidgetItemPrivate;
30 spimpl::unique_impl_ptr<CatalogueTreeWidgetItemPrivate> impl;
33 spimpl::unique_impl_ptr<CatalogueTreeWidgetItemPrivate> impl;
31 };
34 };
32
35
33 #endif // SCIQLOP_CATALOGUETREEWIDGETITEM_H
36 #endif // SCIQLOP_CATALOGUETREEWIDGETITEM_H
@@ -1,137 +1,139
1 qxorm_dep = dependency('QxOrm', required : true, fallback:['QxOrm','qxorm_dep'])
1 qxorm_dep = dependency('QxOrm', required : true, fallback:['QxOrm','qxorm_dep'])
2 catalogueapi_dep = dependency('CatalogueAPI', required : true, fallback:['CatalogueAPI','CatalogueAPI_dep'])
2 catalogueapi_dep = dependency('CatalogueAPI', required : true, fallback:['CatalogueAPI','CatalogueAPI_dep'])
3
3
4 gui_moc_headers = [
4 gui_moc_headers = [
5 'include/DataSource/DataSourceWidget.h',
5 'include/DataSource/DataSourceWidget.h',
6 'include/Settings/SqpSettingsDialog.h',
6 'include/Settings/SqpSettingsDialog.h',
7 'include/Settings/SqpSettingsGeneralWidget.h',
7 'include/Settings/SqpSettingsGeneralWidget.h',
8 'include/SidePane/SqpSidePane.h',
8 'include/SidePane/SqpSidePane.h',
9 'include/SqpApplication.h',
9 'include/SqpApplication.h',
10 'include/DragAndDrop/DragDropScroller.h',
10 'include/DragAndDrop/DragDropScroller.h',
11 'include/DragAndDrop/DragDropTabSwitcher.h',
11 'include/DragAndDrop/DragDropTabSwitcher.h',
12 'include/TimeWidget/TimeWidget.h',
12 'include/TimeWidget/TimeWidget.h',
13 'include/Variable/VariableInspectorWidget.h',
13 'include/Variable/VariableInspectorWidget.h',
14 'include/Variable/RenameVariableDialog.h',
14 'include/Variable/RenameVariableDialog.h',
15 'include/Visualization/qcustomplot.h',
15 'include/Visualization/qcustomplot.h',
16 'include/Visualization/VisualizationGraphWidget.h',
16 'include/Visualization/VisualizationGraphWidget.h',
17 'include/Visualization/VisualizationTabWidget.h',
17 'include/Visualization/VisualizationTabWidget.h',
18 'include/Visualization/VisualizationWidget.h',
18 'include/Visualization/VisualizationWidget.h',
19 'include/Visualization/VisualizationZoneWidget.h',
19 'include/Visualization/VisualizationZoneWidget.h',
20 'include/Visualization/VisualizationDragDropContainer.h',
20 'include/Visualization/VisualizationDragDropContainer.h',
21 'include/Visualization/VisualizationDragWidget.h',
21 'include/Visualization/VisualizationDragWidget.h',
22 'include/Visualization/ColorScaleEditor.h',
22 'include/Visualization/ColorScaleEditor.h',
23 'include/Actions/SelectionZoneAction.h',
23 'include/Actions/SelectionZoneAction.h',
24 'include/Visualization/VisualizationMultiZoneSelectionDialog.h',
24 'include/Visualization/VisualizationMultiZoneSelectionDialog.h',
25 'include/Catalogue/CatalogueExplorer.h',
25 'include/Catalogue/CatalogueExplorer.h',
26 'include/Catalogue/CatalogueEventsWidget.h',
26 'include/Catalogue/CatalogueEventsWidget.h',
27 'include/Catalogue/CatalogueSideBarWidget.h',
27 'include/Catalogue/CatalogueSideBarWidget.h',
28 'include/Catalogue/CatalogueInspectorWidget.h'
28 'include/Catalogue/CatalogueInspectorWidget.h',
29 'include/Catalogue/CatalogueEventsModel.h'
29 ]
30 ]
30
31
31 gui_ui_files = [
32 gui_ui_files = [
32 'ui/DataSource/DataSourceWidget.ui',
33 'ui/DataSource/DataSourceWidget.ui',
33 'ui/Settings/SqpSettingsDialog.ui',
34 'ui/Settings/SqpSettingsDialog.ui',
34 'ui/Settings/SqpSettingsGeneralWidget.ui',
35 'ui/Settings/SqpSettingsGeneralWidget.ui',
35 'ui/SidePane/SqpSidePane.ui',
36 'ui/SidePane/SqpSidePane.ui',
36 'ui/TimeWidget/TimeWidget.ui',
37 'ui/TimeWidget/TimeWidget.ui',
37 'ui/Variable/VariableInspectorWidget.ui',
38 'ui/Variable/VariableInspectorWidget.ui',
38 'ui/Variable/RenameVariableDialog.ui',
39 'ui/Variable/RenameVariableDialog.ui',
39 'ui/Variable/VariableMenuHeaderWidget.ui',
40 'ui/Variable/VariableMenuHeaderWidget.ui',
40 'ui/Visualization/VisualizationGraphWidget.ui',
41 'ui/Visualization/VisualizationGraphWidget.ui',
41 'ui/Visualization/VisualizationTabWidget.ui',
42 'ui/Visualization/VisualizationTabWidget.ui',
42 'ui/Visualization/VisualizationWidget.ui',
43 'ui/Visualization/VisualizationWidget.ui',
43 'ui/Visualization/VisualizationZoneWidget.ui',
44 'ui/Visualization/VisualizationZoneWidget.ui',
44 'ui/Visualization/ColorScaleEditor.ui',
45 'ui/Visualization/ColorScaleEditor.ui',
45 'ui/Visualization/VisualizationMultiZoneSelectionDialog.ui',
46 'ui/Visualization/VisualizationMultiZoneSelectionDialog.ui',
46 'ui/Catalogue/CatalogueExplorer.ui',
47 'ui/Catalogue/CatalogueExplorer.ui',
47 'ui/Catalogue/CatalogueEventsWidget.ui',
48 'ui/Catalogue/CatalogueEventsWidget.ui',
48 'ui/Catalogue/CatalogueSideBarWidget.ui',
49 'ui/Catalogue/CatalogueSideBarWidget.ui',
49 'ui/Catalogue/CatalogueInspectorWidget.ui'
50 'ui/Catalogue/CatalogueInspectorWidget.ui'
50 ]
51 ]
51
52
52 gui_qresources = ['resources/sqpguiresources.qrc']
53 gui_qresources = ['resources/sqpguiresources.qrc']
53
54
54 rcc_gen = generator(rcc,
55 rcc_gen = generator(rcc,
55 output : 'qrc_@BASENAME@.cpp',
56 output : 'qrc_@BASENAME@.cpp',
56 arguments : [
57 arguments : [
57 '--output',
58 '--output',
58 '@OUTPUT@',
59 '@OUTPUT@',
59 '@INPUT@',
60 '@INPUT@',
60 '@EXTRA_ARGS@'])
61 '@EXTRA_ARGS@'])
61
62
62 rcc_files = rcc_gen.process(gui_qresources, extra_args : ['-name', 'sqpguiresources'])
63 rcc_files = rcc_gen.process(gui_qresources, extra_args : ['-name', 'sqpguiresources'])
63
64
64 gui_moc_files = qt5.preprocess(moc_headers : gui_moc_headers,
65 gui_moc_files = qt5.preprocess(moc_headers : gui_moc_headers,
65 ui_files : gui_ui_files)
66 ui_files : gui_ui_files)
66
67
67 gui_sources = [
68 gui_sources = [
68 'src/SqpApplication.cpp',
69 'src/SqpApplication.cpp',
69 'src/DragAndDrop/DragDropGuiController.cpp',
70 'src/DragAndDrop/DragDropGuiController.cpp',
70 'src/DragAndDrop/DragDropScroller.cpp',
71 'src/DragAndDrop/DragDropScroller.cpp',
71 'src/DragAndDrop/DragDropTabSwitcher.cpp',
72 'src/DragAndDrop/DragDropTabSwitcher.cpp',
72 'src/Common/ColorUtils.cpp',
73 'src/Common/ColorUtils.cpp',
73 'src/Common/VisualizationDef.cpp',
74 'src/Common/VisualizationDef.cpp',
74 'src/DataSource/DataSourceTreeWidgetItem.cpp',
75 'src/DataSource/DataSourceTreeWidgetItem.cpp',
75 'src/DataSource/DataSourceTreeWidgetHelper.cpp',
76 'src/DataSource/DataSourceTreeWidgetHelper.cpp',
76 'src/DataSource/DataSourceWidget.cpp',
77 'src/DataSource/DataSourceWidget.cpp',
77 'src/DataSource/DataSourceTreeWidget.cpp',
78 'src/DataSource/DataSourceTreeWidget.cpp',
78 'src/Settings/SqpSettingsDialog.cpp',
79 'src/Settings/SqpSettingsDialog.cpp',
79 'src/Settings/SqpSettingsGeneralWidget.cpp',
80 'src/Settings/SqpSettingsGeneralWidget.cpp',
80 'src/SidePane/SqpSidePane.cpp',
81 'src/SidePane/SqpSidePane.cpp',
81 'src/TimeWidget/TimeWidget.cpp',
82 'src/TimeWidget/TimeWidget.cpp',
82 'src/Variable/VariableInspectorWidget.cpp',
83 'src/Variable/VariableInspectorWidget.cpp',
83 'src/Variable/VariableInspectorTableView.cpp',
84 'src/Variable/VariableInspectorTableView.cpp',
84 'src/Variable/VariableMenuHeaderWidget.cpp',
85 'src/Variable/VariableMenuHeaderWidget.cpp',
85 'src/Variable/RenameVariableDialog.cpp',
86 'src/Variable/RenameVariableDialog.cpp',
86 'src/Visualization/VisualizationGraphHelper.cpp',
87 'src/Visualization/VisualizationGraphHelper.cpp',
87 'src/Visualization/VisualizationGraphRenderingDelegate.cpp',
88 'src/Visualization/VisualizationGraphRenderingDelegate.cpp',
88 'src/Visualization/VisualizationGraphWidget.cpp',
89 'src/Visualization/VisualizationGraphWidget.cpp',
89 'src/Visualization/VisualizationTabWidget.cpp',
90 'src/Visualization/VisualizationTabWidget.cpp',
90 'src/Visualization/VisualizationWidget.cpp',
91 'src/Visualization/VisualizationWidget.cpp',
91 'src/Visualization/VisualizationZoneWidget.cpp',
92 'src/Visualization/VisualizationZoneWidget.cpp',
92 'src/Visualization/qcustomplot.cpp',
93 'src/Visualization/qcustomplot.cpp',
93 'src/Visualization/QCustomPlotSynchronizer.cpp',
94 'src/Visualization/QCustomPlotSynchronizer.cpp',
94 'src/Visualization/operations/FindVariableOperation.cpp',
95 'src/Visualization/operations/FindVariableOperation.cpp',
95 'src/Visualization/operations/GenerateVariableMenuOperation.cpp',
96 'src/Visualization/operations/GenerateVariableMenuOperation.cpp',
96 'src/Visualization/operations/MenuBuilder.cpp',
97 'src/Visualization/operations/MenuBuilder.cpp',
97 'src/Visualization/operations/RemoveVariableOperation.cpp',
98 'src/Visualization/operations/RemoveVariableOperation.cpp',
98 'src/Visualization/operations/RescaleAxeOperation.cpp',
99 'src/Visualization/operations/RescaleAxeOperation.cpp',
99 'src/Visualization/VisualizationDragDropContainer.cpp',
100 'src/Visualization/VisualizationDragDropContainer.cpp',
100 'src/Visualization/VisualizationDragWidget.cpp',
101 'src/Visualization/VisualizationDragWidget.cpp',
101 'src/Visualization/AxisRenderingUtils.cpp',
102 'src/Visualization/AxisRenderingUtils.cpp',
102 'src/Visualization/PlottablesRenderingUtils.cpp',
103 'src/Visualization/PlottablesRenderingUtils.cpp',
103 'src/Visualization/MacScrollBarStyle.cpp',
104 'src/Visualization/MacScrollBarStyle.cpp',
104 'src/Visualization/VisualizationCursorItem.cpp',
105 'src/Visualization/VisualizationCursorItem.cpp',
105 'src/Visualization/ColorScaleEditor.cpp',
106 'src/Visualization/ColorScaleEditor.cpp',
106 'src/Visualization/SqpColorScale.cpp',
107 'src/Visualization/SqpColorScale.cpp',
107 'src/Visualization/QCPColorMapIterator.cpp',
108 'src/Visualization/QCPColorMapIterator.cpp',
108 'src/Visualization/VisualizationSelectionZoneItem.cpp',
109 'src/Visualization/VisualizationSelectionZoneItem.cpp',
109 'src/Visualization/VisualizationSelectionZoneManager.cpp',
110 'src/Visualization/VisualizationSelectionZoneManager.cpp',
110 'src/Actions/SelectionZoneAction.cpp',
111 'src/Actions/SelectionZoneAction.cpp',
111 'src/Actions/ActionsGuiController.cpp',
112 'src/Actions/ActionsGuiController.cpp',
112 'src/Visualization/VisualizationActionManager.cpp',
113 'src/Visualization/VisualizationActionManager.cpp',
113 'src/Visualization/VisualizationMultiZoneSelectionDialog.cpp',
114 'src/Visualization/VisualizationMultiZoneSelectionDialog.cpp',
114 'src/Catalogue/CatalogueExplorer.cpp',
115 'src/Catalogue/CatalogueExplorer.cpp',
115 'src/Catalogue/CatalogueEventsWidget.cpp',
116 'src/Catalogue/CatalogueEventsWidget.cpp',
116 'src/Catalogue/CatalogueSideBarWidget.cpp',
117 'src/Catalogue/CatalogueSideBarWidget.cpp',
117 'src/Catalogue/CatalogueInspectorWidget.cpp',
118 'src/Catalogue/CatalogueInspectorWidget.cpp',
118 'src/Catalogue/CatalogueTreeWidgetItem.cpp',
119 'src/Catalogue/CatalogueTreeWidgetItem.cpp',
119 'src/Catalogue/CatalogueEventsModel.cpp'
120 'src/Catalogue/CatalogueEventsModel.cpp',
121 'src/Catalogue/CatalogueExplorerHelper.cpp'
120 ]
122 ]
121
123
122 gui_inc = include_directories(['include'])
124 gui_inc = include_directories(['include'])
123
125
124 sciqlop_gui_lib = library('sciqlopgui',
126 sciqlop_gui_lib = library('sciqlopgui',
125 gui_sources,
127 gui_sources,
126 gui_moc_files,
128 gui_moc_files,
127 rcc_files,
129 rcc_files,
128 include_directories : [gui_inc],
130 include_directories : [gui_inc],
129 dependencies : [ qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core, catalogueapi_dep],
131 dependencies : [ qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core, catalogueapi_dep],
130 install : true
132 install : true
131 )
133 )
132
134
133 sciqlop_gui = declare_dependency(link_with : sciqlop_gui_lib,
135 sciqlop_gui = declare_dependency(link_with : sciqlop_gui_lib,
134 include_directories : gui_inc,
136 include_directories : gui_inc,
135 dependencies : [qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core, catalogueapi_dep])
137 dependencies : [qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core, catalogueapi_dep])
136
138
137
139
@@ -1,387 +1,442
1 #include "Catalogue/CatalogueEventsModel.h"
1 #include "Catalogue/CatalogueEventsModel.h"
2
2
3 #include <Common/DateUtils.h>
3 #include <Common/DateUtils.h>
4 #include <Common/MimeTypesDef.h>
4 #include <Common/MimeTypesDef.h>
5 #include <DBEvent.h>
5 #include <DBEvent.h>
6 #include <DBEventProduct.h>
6 #include <DBEventProduct.h>
7 #include <DBTag.h>
7 #include <DBTag.h>
8 #include <Data/SqpRange.h>
8 #include <Data/SqpRange.h>
9 #include <SqpApplication.h>
9 #include <SqpApplication.h>
10 #include <Time/TimeController.h>
10 #include <Time/TimeController.h>
11
11
12 #include <list>
12 #include <list>
13 #include <unordered_map>
13 #include <unordered_map>
14
14
15 #include <QHash>
15 #include <QHash>
16 #include <QMimeData>
16 #include <QMimeData>
17
17
18 Q_LOGGING_CATEGORY(LOG_CatalogueEventsModel, "CatalogueEventsModel")
19
18 const auto EVENT_ITEM_TYPE = 1;
20 const auto EVENT_ITEM_TYPE = 1;
19 const auto EVENT_PRODUCT_ITEM_TYPE = 2;
21 const auto EVENT_PRODUCT_ITEM_TYPE = 2;
20
22
21 struct CatalogueEventsModel::CatalogueEventsModelPrivate {
23 struct CatalogueEventsModel::CatalogueEventsModelPrivate {
22 QVector<std::shared_ptr<DBEvent> > m_Events;
24 QVector<std::shared_ptr<DBEvent> > m_Events;
23 std::unordered_map<DBEvent *, QVector<std::shared_ptr<DBEventProduct> > > m_EventProducts;
25 std::unordered_map<DBEvent *, QVector<std::shared_ptr<DBEventProduct> > > m_EventProducts;
26 std::unordered_set<std::shared_ptr<DBEvent> > m_EventsWithChanges;
24
27
25 enum class Column { Name, TStart, TEnd, Tags, Product, NbColumn };
26 QStringList columnNames()
28 QStringList columnNames()
27 {
29 {
28 return QStringList{tr("Event"), tr("TStart"), tr("TEnd"), tr("Tags"), tr("Product")};
30 return QStringList{tr("Event"), tr("TStart"), tr("TEnd"),
31 tr("Tags"), tr("Product"), tr("")};
32 }
33
34 QVariant sortData(int col, const std::shared_ptr<DBEvent> &event) const
35 {
36 if (col == (int)CatalogueEventsModel::Column::Validation) {
37 return m_EventsWithChanges.find(event) != m_EventsWithChanges.cend() ? true
38 : QVariant();
39 }
40
41 return eventData(col, event);
29 }
42 }
30
43
31 QVariant eventData(int col, const std::shared_ptr<DBEvent> &event) const
44 QVariant eventData(int col, const std::shared_ptr<DBEvent> &event) const
32 {
45 {
33 switch (static_cast<Column>(col)) {
46 switch (static_cast<Column>(col)) {
34 case Column::Name:
47 case CatalogueEventsModel::Column::Name:
35 return event->getName();
48 return event->getName();
36 case Column::TStart:
49 case CatalogueEventsModel::Column::TStart:
37 return nbEventProducts(event) > 0 ? DateUtils::dateTime(event->getTStart())
50 return nbEventProducts(event) > 0 ? DateUtils::dateTime(event->getTStart())
38 : QVariant{};
51 : QVariant{};
39 case Column::TEnd:
52 case CatalogueEventsModel::Column::TEnd:
40 return nbEventProducts(event) > 0 ? DateUtils::dateTime(event->getTEnd())
53 return nbEventProducts(event) > 0 ? DateUtils::dateTime(event->getTEnd())
41 : QVariant{};
54 : QVariant{};
42 case Column::Product:
55 case CatalogueEventsModel::Column::Product:
43 return QString::number(nbEventProducts(event)) + " product(s)";
56 return QString::number(nbEventProducts(event)) + " product(s)";
44 case Column::Tags: {
57 case CatalogueEventsModel::Column::Tags: {
45 QString tagList;
58 QString tagList;
46 auto tags = event->getTags();
59 auto tags = event->getTags();
47 for (auto tag : tags) {
60 for (auto tag : tags) {
48 tagList += tag.getName();
61 tagList += tag.getName();
49 tagList += ' ';
62 tagList += ' ';
50 }
63 }
51
64
52 return tagList;
65 return tagList;
53 }
66 }
67 case CatalogueEventsModel::Column::Validation:
68 return QVariant();
54 default:
69 default:
55 break;
70 break;
56 }
71 }
57
72
58 Q_ASSERT(false);
73 Q_ASSERT(false);
59 return QStringLiteral("Unknown Data");
74 return QStringLiteral("Unknown Data");
60 }
75 }
61
76
62 void parseEventProduct(const std::shared_ptr<DBEvent> &event)
77 void parseEventProduct(const std::shared_ptr<DBEvent> &event)
63 {
78 {
64 for (auto product : event->getEventProducts()) {
79 for (auto product : event->getEventProducts()) {
65 m_EventProducts[event.get()].append(std::make_shared<DBEventProduct>(product));
80 m_EventProducts[event.get()].append(std::make_shared<DBEventProduct>(product));
66 }
81 }
67 }
82 }
68
83
69 int nbEventProducts(const std::shared_ptr<DBEvent> &event) const
84 int nbEventProducts(const std::shared_ptr<DBEvent> &event) const
70 {
85 {
71 auto eventProductsIt = m_EventProducts.find(event.get());
86 auto eventProductsIt = m_EventProducts.find(event.get());
72 if (eventProductsIt != m_EventProducts.cend()) {
87 if (eventProductsIt != m_EventProducts.cend()) {
73 return m_EventProducts.at(event.get()).count();
88 return m_EventProducts.at(event.get()).count();
74 }
89 }
75 else {
90 else {
76 return 0;
91 return 0;
77 }
92 }
78 }
93 }
79
94
80 QVariant eventProductData(int col, const std::shared_ptr<DBEventProduct> &eventProduct) const
95 QVariant eventProductData(int col, const std::shared_ptr<DBEventProduct> &eventProduct) const
81 {
96 {
82 switch (static_cast<Column>(col)) {
97 switch (static_cast<Column>(col)) {
83 case Column::Name:
98 case CatalogueEventsModel::Column::Name:
84 return eventProduct->getProductId();
99 return eventProduct->getProductId();
85 case Column::TStart:
100 case CatalogueEventsModel::Column::TStart:
86 return DateUtils::dateTime(eventProduct->getTStart());
101 return DateUtils::dateTime(eventProduct->getTStart());
87 case Column::TEnd:
102 case CatalogueEventsModel::Column::TEnd:
88 return DateUtils::dateTime(eventProduct->getTEnd());
103 return DateUtils::dateTime(eventProduct->getTEnd());
89 case Column::Product:
104 case CatalogueEventsModel::Column::Product:
90 return eventProduct->getProductId();
105 return eventProduct->getProductId();
91 case Column::Tags: {
106 case CatalogueEventsModel::Column::Tags:
92 return QString();
107 return QString();
93 }
108 case CatalogueEventsModel::Column::Validation:
109 return QVariant();
94 default:
110 default:
95 break;
111 break;
96 }
112 }
97
113
98 Q_ASSERT(false);
114 Q_ASSERT(false);
99 return QStringLiteral("Unknown Data");
115 return QStringLiteral("Unknown Data");
100 }
116 }
101 };
117 };
102
118
103 CatalogueEventsModel::CatalogueEventsModel(QObject *parent)
119 CatalogueEventsModel::CatalogueEventsModel(QObject *parent)
104 : QAbstractItemModel(parent), impl{spimpl::make_unique_impl<CatalogueEventsModelPrivate>()}
120 : QAbstractItemModel(parent), impl{spimpl::make_unique_impl<CatalogueEventsModelPrivate>()}
105 {
121 {
106 }
122 }
107
123
108 void CatalogueEventsModel::setEvents(const QVector<std::shared_ptr<DBEvent> > &events)
124 void CatalogueEventsModel::setEvents(const QVector<std::shared_ptr<DBEvent> > &events)
109 {
125 {
110 beginResetModel();
126 beginResetModel();
111
127
112 impl->m_Events = events;
128 impl->m_Events = events;
113 impl->m_EventProducts.clear();
129 impl->m_EventProducts.clear();
130 impl->m_EventsWithChanges.clear();
114 for (auto event : events) {
131 for (auto event : events) {
115 impl->parseEventProduct(event);
132 impl->parseEventProduct(event);
116 }
133 }
117
134
118 endResetModel();
135 endResetModel();
119 }
136 }
120
137
121 std::shared_ptr<DBEvent> CatalogueEventsModel::getEvent(const QModelIndex &index) const
138 std::shared_ptr<DBEvent> CatalogueEventsModel::getEvent(const QModelIndex &index) const
122 {
139 {
123 if (itemTypeOf(index) == CatalogueEventsModel::ItemType::Event) {
140 if (itemTypeOf(index) == CatalogueEventsModel::ItemType::Event) {
124 return impl->m_Events.value(index.row());
141 return impl->m_Events.value(index.row());
125 }
142 }
126 else {
143 else {
127 return nullptr;
144 return nullptr;
128 }
145 }
129 }
146 }
130
147
131 std::shared_ptr<DBEvent> CatalogueEventsModel::getParentEvent(const QModelIndex &index) const
148 std::shared_ptr<DBEvent> CatalogueEventsModel::getParentEvent(const QModelIndex &index) const
132 {
149 {
133 if (itemTypeOf(index) == CatalogueEventsModel::ItemType::EventProduct) {
150 if (itemTypeOf(index) == CatalogueEventsModel::ItemType::EventProduct) {
134 return getEvent(index.parent());
151 return getEvent(index.parent());
135 }
152 }
136 else {
153 else {
137 return nullptr;
154 return nullptr;
138 }
155 }
139 }
156 }
140
157
141 std::shared_ptr<DBEventProduct>
158 std::shared_ptr<DBEventProduct>
142 CatalogueEventsModel::getEventProduct(const QModelIndex &index) const
159 CatalogueEventsModel::getEventProduct(const QModelIndex &index) const
143 {
160 {
144 if (itemTypeOf(index) == CatalogueEventsModel::ItemType::EventProduct) {
161 if (itemTypeOf(index) == CatalogueEventsModel::ItemType::EventProduct) {
145 auto event = static_cast<DBEvent *>(index.internalPointer());
162 auto event = static_cast<DBEvent *>(index.internalPointer());
146 return impl->m_EventProducts.at(event).value(index.row());
163 return impl->m_EventProducts.at(event).value(index.row());
147 }
164 }
148 else {
165 else {
149 return nullptr;
166 return nullptr;
150 }
167 }
151 }
168 }
152
169
153 void CatalogueEventsModel::addEvent(const std::shared_ptr<DBEvent> &event)
170 void CatalogueEventsModel::addEvent(const std::shared_ptr<DBEvent> &event)
154 {
171 {
155 beginInsertRows(QModelIndex(), impl->m_Events.count() - 1, impl->m_Events.count() - 1);
172 beginInsertRows(QModelIndex(), impl->m_Events.count() - 1, impl->m_Events.count() - 1);
156 impl->m_Events.append(event);
173 impl->m_Events.append(event);
157 impl->parseEventProduct(event);
174 impl->parseEventProduct(event);
158 endInsertRows();
175 endInsertRows();
159 }
176 }
160
177
161 void CatalogueEventsModel::removeEvent(const std::shared_ptr<DBEvent> &event)
178 void CatalogueEventsModel::removeEvent(const std::shared_ptr<DBEvent> &event)
162 {
179 {
163 auto index = impl->m_Events.indexOf(event);
180 auto index = impl->m_Events.indexOf(event);
164 if (index >= 0) {
181 if (index >= 0) {
165 beginRemoveRows(QModelIndex(), index, index);
182 beginRemoveRows(QModelIndex(), index, index);
166 impl->m_Events.removeAt(index);
183 impl->m_Events.removeAt(index);
167 impl->m_EventProducts.erase(event.get());
184 impl->m_EventProducts.erase(event.get());
185 impl->m_EventsWithChanges.erase(event);
168 endRemoveRows();
186 endRemoveRows();
169 }
187 }
170 }
188 }
171
189
190 QVector<std::shared_ptr<DBEvent> > CatalogueEventsModel::events() const
191 {
192 return impl->m_Events;
193 }
194
172 void CatalogueEventsModel::refreshEvent(const std::shared_ptr<DBEvent> &event)
195 void CatalogueEventsModel::refreshEvent(const std::shared_ptr<DBEvent> &event)
173 {
196 {
174 auto i = impl->m_Events.indexOf(event);
197 auto eventIndex = indexOf(event);
175 if (i >= 0) {
198 if (eventIndex.isValid()) {
176 auto eventIndex = index(i, 0);
199
200 // Refreshes the event line
177 auto colCount = columnCount();
201 auto colCount = columnCount();
178 emit dataChanged(eventIndex, index(i, colCount));
202 emit dataChanged(eventIndex, index(eventIndex.row(), colCount));
179
203
204 // Also refreshes its children event products
180 auto childCount = rowCount(eventIndex);
205 auto childCount = rowCount(eventIndex);
181 emit dataChanged(index(0, 0, eventIndex), index(childCount, colCount, eventIndex));
206 emit dataChanged(index(0, 0, eventIndex), index(childCount, colCount, eventIndex));
182 }
207 }
208 else {
209 qCWarning(LOG_CatalogueEventsModel()) << "refreshEvent: event not found.";
210 }
211 }
212
213 QModelIndex CatalogueEventsModel::indexOf(const std::shared_ptr<DBEvent> &event) const
214 {
215 auto row = impl->m_Events.indexOf(event);
216 if (row >= 0) {
217 return index(row, 0);
218 }
219
220 return QModelIndex();
221 }
222
223 void CatalogueEventsModel::setEventHasChanges(const std::shared_ptr<DBEvent> &event,
224 bool hasChanges)
225 {
226 if (hasChanges) {
227 impl->m_EventsWithChanges.insert(event);
228 }
229 else {
230 impl->m_EventsWithChanges.erase(event);
231 }
232 }
233
234 bool CatalogueEventsModel::eventsHasChanges(const std::shared_ptr<DBEvent> &event) const
235 {
236 return impl->m_EventsWithChanges.find(event) != impl->m_EventsWithChanges.cend();
183 }
237 }
184
238
185 QModelIndex CatalogueEventsModel::index(int row, int column, const QModelIndex &parent) const
239 QModelIndex CatalogueEventsModel::index(int row, int column, const QModelIndex &parent) const
186 {
240 {
187 if (!hasIndex(row, column, parent)) {
241 if (!hasIndex(row, column, parent)) {
188 return QModelIndex();
242 return QModelIndex();
189 }
243 }
190
244
191 switch (itemTypeOf(parent)) {
245 switch (itemTypeOf(parent)) {
192 case CatalogueEventsModel::ItemType::Root:
246 case CatalogueEventsModel::ItemType::Root:
193 return createIndex(row, column);
247 return createIndex(row, column);
194 case CatalogueEventsModel::ItemType::Event: {
248 case CatalogueEventsModel::ItemType::Event: {
195 auto event = getEvent(parent);
249 auto event = getEvent(parent);
196 return createIndex(row, column, event.get());
250 return createIndex(row, column, event.get());
197 }
251 }
198 case CatalogueEventsModel::ItemType::EventProduct:
252 case CatalogueEventsModel::ItemType::EventProduct:
199 break;
253 break;
200 default:
254 default:
201 break;
255 break;
202 }
256 }
203
257
204 return QModelIndex();
258 return QModelIndex();
205 }
259 }
206
260
207 QModelIndex CatalogueEventsModel::parent(const QModelIndex &index) const
261 QModelIndex CatalogueEventsModel::parent(const QModelIndex &index) const
208 {
262 {
209 switch (itemTypeOf(index)) {
263 switch (itemTypeOf(index)) {
210 case CatalogueEventsModel::ItemType::EventProduct: {
264 case CatalogueEventsModel::ItemType::EventProduct: {
211 auto parentEvent = static_cast<DBEvent *>(index.internalPointer());
265 auto parentEvent = static_cast<DBEvent *>(index.internalPointer());
212 auto it
266 auto it
213 = std::find_if(impl->m_Events.cbegin(), impl->m_Events.cend(),
267 = std::find_if(impl->m_Events.cbegin(), impl->m_Events.cend(),
214 [parentEvent](auto event) { return event.get() == parentEvent; });
268 [parentEvent](auto event) { return event.get() == parentEvent; });
215
269
216 if (it != impl->m_Events.cend()) {
270 if (it != impl->m_Events.cend()) {
217 return createIndex(it - impl->m_Events.cbegin(), 0);
271 return createIndex(it - impl->m_Events.cbegin(), 0);
218 }
272 }
219 else {
273 else {
220 return QModelIndex();
274 return QModelIndex();
221 }
275 }
222 }
276 }
223 case CatalogueEventsModel::ItemType::Root:
277 case CatalogueEventsModel::ItemType::Root:
224 break;
278 break;
225 case CatalogueEventsModel::ItemType::Event:
279 case CatalogueEventsModel::ItemType::Event:
226 break;
280 break;
227 default:
281 default:
228 break;
282 break;
229 }
283 }
230
284
231 return QModelIndex();
285 return QModelIndex();
232 }
286 }
233
287
234 int CatalogueEventsModel::rowCount(const QModelIndex &parent) const
288 int CatalogueEventsModel::rowCount(const QModelIndex &parent) const
235 {
289 {
236 if (parent.column() > 0) {
290 if (parent.column() > 0) {
237 return 0;
291 return 0;
238 }
292 }
239
293
240 switch (itemTypeOf(parent)) {
294 switch (itemTypeOf(parent)) {
241 case CatalogueEventsModel::ItemType::Root:
295 case CatalogueEventsModel::ItemType::Root:
242 return impl->m_Events.count();
296 return impl->m_Events.count();
243 case CatalogueEventsModel::ItemType::Event: {
297 case CatalogueEventsModel::ItemType::Event: {
244 auto event = getEvent(parent);
298 auto event = getEvent(parent);
245 return impl->m_EventProducts[event.get()].count();
299 return impl->m_EventProducts[event.get()].count();
246 }
300 }
247 case CatalogueEventsModel::ItemType::EventProduct:
301 case CatalogueEventsModel::ItemType::EventProduct:
248 break;
302 break;
249 default:
303 default:
250 break;
304 break;
251 }
305 }
252
306
253 return 0;
307 return 0;
254 }
308 }
255
309
256 int CatalogueEventsModel::columnCount(const QModelIndex &parent) const
310 int CatalogueEventsModel::columnCount(const QModelIndex &parent) const
257 {
311 {
258 return static_cast<int>(CatalogueEventsModelPrivate::Column::NbColumn);
312 return static_cast<int>(CatalogueEventsModel::Column::NbColumn);
259 }
313 }
260
314
261 Qt::ItemFlags CatalogueEventsModel::flags(const QModelIndex &index) const
315 Qt::ItemFlags CatalogueEventsModel::flags(const QModelIndex &index) const
262 {
316 {
263 return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled;
317 return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled;
264 }
318 }
265
319
266 QVariant CatalogueEventsModel::data(const QModelIndex &index, int role) const
320 QVariant CatalogueEventsModel::data(const QModelIndex &index, int role) const
267 {
321 {
268 if (index.isValid()) {
322 if (index.isValid()) {
269
323
270 auto type = itemTypeOf(index);
324 auto type = itemTypeOf(index);
271 if (type == CatalogueEventsModel::ItemType::Event) {
325 if (type == CatalogueEventsModel::ItemType::Event) {
272 auto event = getEvent(index);
326 auto event = getEvent(index);
273 switch (role) {
327 switch (role) {
274 case Qt::DisplayRole:
328 case Qt::DisplayRole:
275 return impl->eventData(index.column(), event);
329 return impl->eventData(index.column(), event);
276 break;
330 break;
277 }
331 }
278 }
332 }
279 else if (type == CatalogueEventsModel::ItemType::EventProduct) {
333 else if (type == CatalogueEventsModel::ItemType::EventProduct) {
280 auto product = getEventProduct(index);
334 auto product = getEventProduct(index);
281 switch (role) {
335 switch (role) {
282 case Qt::DisplayRole:
336 case Qt::DisplayRole:
283 return impl->eventProductData(index.column(), product);
337 return impl->eventProductData(index.column(), product);
284 break;
338 break;
285 }
339 }
286 }
340 }
287 }
341 }
288
342
289 return QVariant{};
343 return QVariant{};
290 }
344 }
291
345
292 QVariant CatalogueEventsModel::headerData(int section, Qt::Orientation orientation, int role) const
346 QVariant CatalogueEventsModel::headerData(int section, Qt::Orientation orientation, int role) const
293 {
347 {
294 if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
348 if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
295 return impl->columnNames().value(section);
349 return impl->columnNames().value(section);
296 }
350 }
297
351
298 return QVariant();
352 return QVariant();
299 }
353 }
300
354
301 void CatalogueEventsModel::sort(int column, Qt::SortOrder order)
355 void CatalogueEventsModel::sort(int column, Qt::SortOrder order)
302 {
356 {
303 std::sort(impl->m_Events.begin(), impl->m_Events.end(),
357 std::sort(impl->m_Events.begin(), impl->m_Events.end(),
304 [this, column, order](auto e1, auto e2) {
358 [this, column, order](auto e1, auto e2) {
305 auto data1 = impl->eventData(column, e1);
359 auto data1 = impl->sortData(column, e1);
306 auto data2 = impl->eventData(column, e2);
360 auto data2 = impl->sortData(column, e2);
307
361
308 auto result = data1.toString() < data2.toString();
362 auto result = data1.toString() < data2.toString();
309
363
310 return order == Qt::AscendingOrder ? result : !result;
364 return order == Qt::AscendingOrder ? result : !result;
311 });
365 });
312
366
313 emit dataChanged(QModelIndex(), QModelIndex());
367 emit dataChanged(QModelIndex(), QModelIndex());
368 emit modelSorted();
314 }
369 }
315
370
316 Qt::DropActions CatalogueEventsModel::supportedDragActions() const
371 Qt::DropActions CatalogueEventsModel::supportedDragActions() const
317 {
372 {
318 return Qt::CopyAction | Qt::MoveAction;
373 return Qt::CopyAction | Qt::MoveAction;
319 }
374 }
320
375
321 QStringList CatalogueEventsModel::mimeTypes() const
376 QStringList CatalogueEventsModel::mimeTypes() const
322 {
377 {
323 return {MIME_TYPE_EVENT_LIST, MIME_TYPE_TIME_RANGE};
378 return {MIME_TYPE_EVENT_LIST, MIME_TYPE_TIME_RANGE};
324 }
379 }
325
380
326 QMimeData *CatalogueEventsModel::mimeData(const QModelIndexList &indexes) const
381 QMimeData *CatalogueEventsModel::mimeData(const QModelIndexList &indexes) const
327 {
382 {
328 auto mimeData = new QMimeData;
383 auto mimeData = new QMimeData;
329
384
330 bool isFirst = true;
385 bool isFirst = true;
331
386
332 QVector<std::shared_ptr<DBEvent> > eventList;
387 QVector<std::shared_ptr<DBEvent> > eventList;
333 QVector<std::shared_ptr<DBEventProduct> > eventProductList;
388 QVector<std::shared_ptr<DBEventProduct> > eventProductList;
334
389
335 SqpRange firstTimeRange;
390 SqpRange firstTimeRange;
336 for (const auto &index : indexes) {
391 for (const auto &index : indexes) {
337 if (index.column() == 0) { // only the first column
392 if (index.column() == 0) { // only the first column
338
393
339 auto type = itemTypeOf(index);
394 auto type = itemTypeOf(index);
340 if (type == ItemType::Event) {
395 if (type == ItemType::Event) {
341 auto event = getEvent(index);
396 auto event = getEvent(index);
342 eventList << event;
397 eventList << event;
343
398
344 if (isFirst) {
399 if (isFirst) {
345 isFirst = false;
400 isFirst = false;
346 firstTimeRange.m_TStart = event->getTStart();
401 firstTimeRange.m_TStart = event->getTStart();
347 firstTimeRange.m_TEnd = event->getTEnd();
402 firstTimeRange.m_TEnd = event->getTEnd();
348 }
403 }
349 }
404 }
350 else if (type == ItemType::EventProduct) {
405 else if (type == ItemType::EventProduct) {
351 auto product = getEventProduct(index);
406 auto product = getEventProduct(index);
352 eventProductList << product;
407 eventProductList << product;
353
408
354 if (isFirst) {
409 if (isFirst) {
355 isFirst = false;
410 isFirst = false;
356 firstTimeRange.m_TStart = product->getTStart();
411 firstTimeRange.m_TStart = product->getTStart();
357 firstTimeRange.m_TEnd = product->getTEnd();
412 firstTimeRange.m_TEnd = product->getTEnd();
358 }
413 }
359 }
414 }
360 }
415 }
361 }
416 }
362
417
363 auto eventsEncodedData
418 auto eventsEncodedData
364 = QByteArray{}; // sqpApp->catalogueController().->mimeDataForEvents(eventList); //TODO
419 = QByteArray{}; // sqpApp->catalogueController().->mimeDataForEvents(eventList); //TODO
365 mimeData->setData(MIME_TYPE_EVENT_LIST, eventsEncodedData);
420 mimeData->setData(MIME_TYPE_EVENT_LIST, eventsEncodedData);
366
421
367 if (eventList.count() + eventProductList.count() == 1) {
422 if (eventList.count() + eventProductList.count() == 1) {
368 // No time range MIME data if multiple events are dragged
423 // No time range MIME data if multiple events are dragged
369 auto timeEncodedData = TimeController::mimeDataForTimeRange(firstTimeRange);
424 auto timeEncodedData = TimeController::mimeDataForTimeRange(firstTimeRange);
370 mimeData->setData(MIME_TYPE_TIME_RANGE, timeEncodedData);
425 mimeData->setData(MIME_TYPE_TIME_RANGE, timeEncodedData);
371 }
426 }
372
427
373 return mimeData;
428 return mimeData;
374 }
429 }
375
430
376 CatalogueEventsModel::ItemType CatalogueEventsModel::itemTypeOf(const QModelIndex &index) const
431 CatalogueEventsModel::ItemType CatalogueEventsModel::itemTypeOf(const QModelIndex &index) const
377 {
432 {
378 if (!index.isValid()) {
433 if (!index.isValid()) {
379 return ItemType::Root;
434 return ItemType::Root;
380 }
435 }
381 else if (index.internalPointer() == nullptr) {
436 else if (index.internalPointer() == nullptr) {
382 return ItemType::Event;
437 return ItemType::Event;
383 }
438 }
384 else {
439 else {
385 return ItemType::EventProduct;
440 return ItemType::EventProduct;
386 }
441 }
387 }
442 }
@@ -1,328 +1,360
1 #include "Catalogue/CatalogueEventsWidget.h"
1 #include "Catalogue/CatalogueEventsWidget.h"
2 #include "ui_CatalogueEventsWidget.h"
2 #include "ui_CatalogueEventsWidget.h"
3
3
4 #include <Catalogue/CatalogueController.h>
4 #include <Catalogue/CatalogueController.h>
5 #include <Catalogue/CatalogueEventsModel.h>
5 #include <Catalogue/CatalogueEventsModel.h>
6 #include <Catalogue/CatalogueExplorerHelper.h>
6 #include <CatalogueDao.h>
7 #include <CatalogueDao.h>
7 #include <DBCatalogue.h>
8 #include <DBCatalogue.h>
8 #include <SqpApplication.h>
9 #include <SqpApplication.h>
9 #include <Visualization/VisualizationTabWidget.h>
10 #include <Visualization/VisualizationTabWidget.h>
10 #include <Visualization/VisualizationWidget.h>
11 #include <Visualization/VisualizationWidget.h>
11 #include <Visualization/VisualizationZoneWidget.h>
12 #include <Visualization/VisualizationZoneWidget.h>
12
13
13 #include <QDialog>
14 #include <QDialog>
14 #include <QDialogButtonBox>
15 #include <QDialogButtonBox>
15 #include <QListWidget>
16 #include <QListWidget>
16
17
17 Q_LOGGING_CATEGORY(LOG_CatalogueEventsWidget, "CatalogueEventsWidget")
18 Q_LOGGING_CATEGORY(LOG_CatalogueEventsWidget, "CatalogueEventsWidget")
18
19
19 /// Format of the dates appearing in the label of a cursor
20 /// Fixed size of the validation column
20 const auto DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd hh:mm:ss");
21 const auto VALIDATION_COLUMN_SIZE = 35;
21
22
22 struct CatalogueEventsWidget::CatalogueEventsWidgetPrivate {
23 struct CatalogueEventsWidget::CatalogueEventsWidgetPrivate {
23
24
24 CatalogueEventsModel *m_Model = nullptr;
25 CatalogueEventsModel *m_Model = nullptr;
25 QStringList m_ZonesForTimeMode;
26 QStringList m_ZonesForTimeMode;
26 QString m_ZoneForGraphMode;
27 QString m_ZoneForGraphMode;
27
28
28 VisualizationWidget *m_VisualizationWidget = nullptr;
29 VisualizationWidget *m_VisualizationWidget = nullptr;
29
30
30 void setEvents(const QVector<std::shared_ptr<DBEvent> > &events, QTreeView *treeView)
31 void setEvents(const QVector<std::shared_ptr<DBEvent> > &events, QTreeView *treeView)
31 {
32 {
32 treeView->setSortingEnabled(false);
33 treeView->setSortingEnabled(false);
33 m_Model->setEvents(events);
34 m_Model->setEvents(events);
34 treeView->setSortingEnabled(true);
35 treeView->setSortingEnabled(true);
35 }
36 }
36
37
37 void addEvent(const std::shared_ptr<DBEvent> &event, QTreeView *treeView)
38 void addEvent(const std::shared_ptr<DBEvent> &event, QTreeView *treeView)
38 {
39 {
39 treeView->setSortingEnabled(false);
40 treeView->setSortingEnabled(false);
40 m_Model->addEvent(event);
41 m_Model->addEvent(event);
41 treeView->setSortingEnabled(true);
42 treeView->setSortingEnabled(true);
42 }
43 }
43
44
44 void removeEvent(const std::shared_ptr<DBEvent> &event, QTreeView *treeView)
45 void removeEvent(const std::shared_ptr<DBEvent> &event, QTreeView *treeView)
45 {
46 {
46 treeView->setSortingEnabled(false);
47 treeView->setSortingEnabled(false);
47 m_Model->removeEvent(event);
48 m_Model->removeEvent(event);
48 treeView->setSortingEnabled(true);
49 treeView->setSortingEnabled(true);
49 }
50 }
50
51
51 QStringList getAvailableVisualizationZoneList() const
52 QStringList getAvailableVisualizationZoneList() const
52 {
53 {
53 if (m_VisualizationWidget) {
54 if (m_VisualizationWidget) {
54 if (auto tab = m_VisualizationWidget->currentTabWidget()) {
55 if (auto tab = m_VisualizationWidget->currentTabWidget()) {
55 return tab->availableZoneWidgets();
56 return tab->availableZoneWidgets();
56 }
57 }
57 }
58 }
58
59
59 return QStringList{};
60 return QStringList{};
60 }
61 }
61
62
62 QStringList selectZone(QWidget *parent, const QStringList &selectedZones,
63 QStringList selectZone(QWidget *parent, const QStringList &selectedZones,
63 bool allowMultiSelection, const QPoint &location)
64 bool allowMultiSelection, const QPoint &location)
64 {
65 {
65 auto availableZones = getAvailableVisualizationZoneList();
66 auto availableZones = getAvailableVisualizationZoneList();
66 if (availableZones.isEmpty()) {
67 if (availableZones.isEmpty()) {
67 return QStringList{};
68 return QStringList{};
68 }
69 }
69
70
70 QDialog d(parent, Qt::Tool);
71 QDialog d(parent, Qt::Tool);
71 d.setWindowTitle("Choose a zone");
72 d.setWindowTitle("Choose a zone");
72 auto layout = new QVBoxLayout{&d};
73 auto layout = new QVBoxLayout{&d};
73 layout->setContentsMargins(0, 0, 0, 0);
74 layout->setContentsMargins(0, 0, 0, 0);
74 auto listWidget = new QListWidget{&d};
75 auto listWidget = new QListWidget{&d};
75 layout->addWidget(listWidget);
76 layout->addWidget(listWidget);
76
77
77 QSet<QListWidgetItem *> checkedItems;
78 QSet<QListWidgetItem *> checkedItems;
78 for (auto zone : availableZones) {
79 for (auto zone : availableZones) {
79 auto item = new QListWidgetItem{zone};
80 auto item = new QListWidgetItem{zone};
80 item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsUserCheckable);
81 item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsUserCheckable);
81 if (selectedZones.contains(zone)) {
82 if (selectedZones.contains(zone)) {
82 item->setCheckState(Qt::Checked);
83 item->setCheckState(Qt::Checked);
83 checkedItems << item;
84 checkedItems << item;
84 }
85 }
85 else {
86 else {
86 item->setCheckState(Qt::Unchecked);
87 item->setCheckState(Qt::Unchecked);
87 }
88 }
88
89
89 listWidget->addItem(item);
90 listWidget->addItem(item);
90 }
91 }
91
92
92 auto buttonBox = new QDialogButtonBox{QDialogButtonBox::Ok, &d};
93 auto buttonBox = new QDialogButtonBox{QDialogButtonBox::Ok, &d};
93 layout->addWidget(buttonBox);
94 layout->addWidget(buttonBox);
94
95
95 QObject::connect(buttonBox, &QDialogButtonBox::accepted, &d, &QDialog::accept);
96 QObject::connect(buttonBox, &QDialogButtonBox::accepted, &d, &QDialog::accept);
96 QObject::connect(buttonBox, &QDialogButtonBox::rejected, &d, &QDialog::reject);
97 QObject::connect(buttonBox, &QDialogButtonBox::rejected, &d, &QDialog::reject);
97
98
98 QObject::connect(listWidget, &QListWidget::itemChanged,
99 QObject::connect(listWidget, &QListWidget::itemChanged,
99 [&checkedItems, allowMultiSelection, listWidget](auto item) {
100 [&checkedItems, allowMultiSelection, listWidget](auto item) {
100 if (item->checkState() == Qt::Checked) {
101 if (item->checkState() == Qt::Checked) {
101 if (!allowMultiSelection) {
102 if (!allowMultiSelection) {
102 for (auto checkedItem : checkedItems) {
103 for (auto checkedItem : checkedItems) {
103 listWidget->blockSignals(true);
104 listWidget->blockSignals(true);
104 checkedItem->setCheckState(Qt::Unchecked);
105 checkedItem->setCheckState(Qt::Unchecked);
105 listWidget->blockSignals(false);
106 listWidget->blockSignals(false);
106 }
107 }
107
108
108 checkedItems.clear();
109 checkedItems.clear();
109 }
110 }
110 checkedItems << item;
111 checkedItems << item;
111 }
112 }
112 else {
113 else {
113 checkedItems.remove(item);
114 checkedItems.remove(item);
114 }
115 }
115 });
116 });
116
117
117 QStringList result;
118 QStringList result;
118
119
119 d.setMinimumWidth(120);
120 d.setMinimumWidth(120);
120 d.resize(d.minimumSizeHint());
121 d.resize(d.minimumSizeHint());
121 d.move(location);
122 d.move(location);
122 if (d.exec() == QDialog::Accepted) {
123 if (d.exec() == QDialog::Accepted) {
123 for (auto item : checkedItems) {
124 for (auto item : checkedItems) {
124 result += item->text();
125 result += item->text();
125 }
126 }
126 }
127 }
127 else {
128 else {
128 result = selectedZones;
129 result = selectedZones;
129 }
130 }
130
131
131 return result;
132 return result;
132 }
133 }
133
134
134 void updateForTimeMode(QTreeView *treeView)
135 void updateForTimeMode(QTreeView *treeView)
135 {
136 {
136 auto selectedRows = treeView->selectionModel()->selectedRows();
137 auto selectedRows = treeView->selectionModel()->selectedRows();
137
138
138 if (selectedRows.count() == 1) {
139 if (selectedRows.count() == 1) {
139 auto event = m_Model->getEvent(selectedRows.first());
140 auto event = m_Model->getEvent(selectedRows.first());
140 if (event) {
141 if (event) {
141 if (m_VisualizationWidget) {
142 if (m_VisualizationWidget) {
142 if (auto tab = m_VisualizationWidget->currentTabWidget()) {
143 if (auto tab = m_VisualizationWidget->currentTabWidget()) {
143
144
144 for (auto zoneName : m_ZonesForTimeMode) {
145 for (auto zoneName : m_ZonesForTimeMode) {
145 if (auto zone = tab->getZoneWithName(zoneName)) {
146 if (auto zone = tab->getZoneWithName(zoneName)) {
146 SqpRange eventRange;
147 SqpRange eventRange;
147 eventRange.m_TStart = event->getTStart();
148 eventRange.m_TStart = event->getTStart();
148 eventRange.m_TEnd = event->getTEnd();
149 eventRange.m_TEnd = event->getTEnd();
149 zone->setZoneRange(eventRange);
150 zone->setZoneRange(eventRange);
150 }
151 }
151 }
152 }
152 }
153 }
153 else {
154 else {
154 qCWarning(LOG_CatalogueEventsWidget())
155 qCWarning(LOG_CatalogueEventsWidget())
155 << "updateTimeZone: no tab found in the visualization";
156 << "updateTimeZone: no tab found in the visualization";
156 }
157 }
157 }
158 }
158 else {
159 else {
159 qCWarning(LOG_CatalogueEventsWidget())
160 qCWarning(LOG_CatalogueEventsWidget())
160 << "updateTimeZone: visualization widget not found";
161 << "updateTimeZone: visualization widget not found";
161 }
162 }
162 }
163 }
163 }
164 }
164 else {
165 else {
165 qCWarning(LOG_CatalogueEventsWidget())
166 qCWarning(LOG_CatalogueEventsWidget())
166 << "updateTimeZone: not compatible with multiple events selected";
167 << "updateTimeZone: not compatible with multiple events selected";
167 }
168 }
168 }
169 }
169
170
170 void updateForGraphMode(QTreeView *treeView)
171 void updateForGraphMode(QTreeView *treeView)
171 {
172 {
172 auto selectedRows = treeView->selectionModel()->selectedRows();
173 auto selectedRows = treeView->selectionModel()->selectedRows();
173
174
174 if (selectedRows.count() == 1) {
175 if (selectedRows.count() == 1) {
175 auto event = m_Model->getEvent(selectedRows.first());
176 auto event = m_Model->getEvent(selectedRows.first());
176 if (m_VisualizationWidget) {
177 if (m_VisualizationWidget) {
177 if (auto tab = m_VisualizationWidget->currentTabWidget()) {
178 if (auto tab = m_VisualizationWidget->currentTabWidget()) {
178 if (auto zone = tab->getZoneWithName(m_ZoneForGraphMode)) {
179 if (auto zone = tab->getZoneWithName(m_ZoneForGraphMode)) {
179 // TODO
180 // TODO
180 }
181 }
181 }
182 }
182 else {
183 else {
183 qCWarning(LOG_CatalogueEventsWidget())
184 qCWarning(LOG_CatalogueEventsWidget())
184 << "updateGraphMode: no tab found in the visualization";
185 << "updateGraphMode: no tab found in the visualization";
185 }
186 }
186 }
187 }
187 else {
188 else {
188 qCWarning(LOG_CatalogueEventsWidget())
189 qCWarning(LOG_CatalogueEventsWidget())
189 << "updateGraphMode: visualization widget not found";
190 << "updateGraphMode: visualization widget not found";
190 }
191 }
191 }
192 }
192 else {
193 else {
193 qCWarning(LOG_CatalogueEventsWidget())
194 qCWarning(LOG_CatalogueEventsWidget())
194 << "updateGraphMode: not compatible with multiple events selected";
195 << "updateGraphMode: not compatible with multiple events selected";
195 }
196 }
196 }
197 }
197 };
198 };
198
199
199 CatalogueEventsWidget::CatalogueEventsWidget(QWidget *parent)
200 CatalogueEventsWidget::CatalogueEventsWidget(QWidget *parent)
200 : QWidget(parent),
201 : QWidget(parent),
201 ui(new Ui::CatalogueEventsWidget),
202 ui(new Ui::CatalogueEventsWidget),
202 impl{spimpl::make_unique_impl<CatalogueEventsWidgetPrivate>()}
203 impl{spimpl::make_unique_impl<CatalogueEventsWidgetPrivate>()}
203 {
204 {
204 ui->setupUi(this);
205 ui->setupUi(this);
205
206
206 impl->m_Model = new CatalogueEventsModel{this};
207 impl->m_Model = new CatalogueEventsModel{this};
207 ui->treeView->setModel(impl->m_Model);
208 ui->treeView->setModel(impl->m_Model);
208
209
209 ui->treeView->setSortingEnabled(true);
210 ui->treeView->setSortingEnabled(true);
210 ui->treeView->setDragDropMode(QAbstractItemView::DragDrop);
211 ui->treeView->setDragDropMode(QAbstractItemView::DragDrop);
211 ui->treeView->setDragEnabled(true);
212 ui->treeView->setDragEnabled(true);
212
213
213 connect(ui->btnTime, &QToolButton::clicked, [this](auto checked) {
214 connect(ui->btnTime, &QToolButton::clicked, [this](auto checked) {
214 if (checked) {
215 if (checked) {
215 ui->btnChart->setChecked(false);
216 ui->btnChart->setChecked(false);
216 impl->m_ZonesForTimeMode
217 impl->m_ZonesForTimeMode
217 = impl->selectZone(this, impl->m_ZonesForTimeMode, true,
218 = impl->selectZone(this, impl->m_ZonesForTimeMode, true,
218 this->mapToGlobal(ui->btnTime->frameGeometry().center()));
219 this->mapToGlobal(ui->btnTime->frameGeometry().center()));
219
220
220 impl->updateForTimeMode(ui->treeView);
221 impl->updateForTimeMode(ui->treeView);
221 }
222 }
222 });
223 });
223
224
224 connect(ui->btnChart, &QToolButton::clicked, [this](auto checked) {
225 connect(ui->btnChart, &QToolButton::clicked, [this](auto checked) {
225 if (checked) {
226 if (checked) {
226 ui->btnTime->setChecked(false);
227 ui->btnTime->setChecked(false);
227 impl->m_ZoneForGraphMode
228 impl->m_ZoneForGraphMode
228 = impl->selectZone(this, {impl->m_ZoneForGraphMode}, false,
229 = impl->selectZone(this, {impl->m_ZoneForGraphMode}, false,
229 this->mapToGlobal(ui->btnChart->frameGeometry().center()))
230 this->mapToGlobal(ui->btnChart->frameGeometry().center()))
230 .value(0);
231 .value(0);
231
232
232 impl->updateForGraphMode(ui->treeView);
233 impl->updateForGraphMode(ui->treeView);
233 }
234 }
234 });
235 });
235
236
236 auto emitSelection = [this]() {
237 auto emitSelection = [this]() {
237 QVector<std::shared_ptr<DBEvent> > events;
238 QVector<std::shared_ptr<DBEvent> > events;
238 QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > > eventProducts;
239 QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > > eventProducts;
239
240
240 for (auto rowIndex : ui->treeView->selectionModel()->selectedRows()) {
241 for (auto rowIndex : ui->treeView->selectionModel()->selectedRows()) {
241
242
242 auto itemType = impl->m_Model->itemTypeOf(rowIndex);
243 auto itemType = impl->m_Model->itemTypeOf(rowIndex);
243 if (itemType == CatalogueEventsModel::ItemType::Event) {
244 if (itemType == CatalogueEventsModel::ItemType::Event) {
244 events << impl->m_Model->getEvent(rowIndex);
245 events << impl->m_Model->getEvent(rowIndex);
245 }
246 }
246 else if (itemType == CatalogueEventsModel::ItemType::EventProduct) {
247 else if (itemType == CatalogueEventsModel::ItemType::EventProduct) {
247 eventProducts << qMakePair(impl->m_Model->getParentEvent(rowIndex),
248 eventProducts << qMakePair(impl->m_Model->getParentEvent(rowIndex),
248 impl->m_Model->getEventProduct(rowIndex));
249 impl->m_Model->getEventProduct(rowIndex));
249 }
250 }
250 }
251 }
251
252
252 if (!events.isEmpty() && eventProducts.isEmpty()) {
253 if (!events.isEmpty() && eventProducts.isEmpty()) {
253 emit this->eventsSelected(events);
254 emit this->eventsSelected(events);
254 }
255 }
255 else if (events.isEmpty() && !eventProducts.isEmpty()) {
256 else if (events.isEmpty() && !eventProducts.isEmpty()) {
256 emit this->eventProductsSelected(eventProducts);
257 emit this->eventProductsSelected(eventProducts);
257 }
258 }
258 else {
259 else {
259 emit this->selectionCleared();
260 emit this->selectionCleared();
260 }
261 }
261 };
262 };
262
263
263 connect(ui->treeView, &QTreeView::clicked, emitSelection);
264 connect(ui->treeView, &QTreeView::clicked, emitSelection);
264 connect(ui->treeView->selectionModel(), &QItemSelectionModel::selectionChanged, emitSelection);
265 connect(ui->treeView->selectionModel(), &QItemSelectionModel::selectionChanged, emitSelection);
265
266
266 connect(ui->treeView->selectionModel(), &QItemSelectionModel::selectionChanged, [this]() {
267 connect(ui->treeView->selectionModel(), &QItemSelectionModel::selectionChanged, [this]() {
267 auto isNotMultiSelection = ui->treeView->selectionModel()->selectedRows().count() <= 1;
268 auto isNotMultiSelection = ui->treeView->selectionModel()->selectedRows().count() <= 1;
268 ui->btnChart->setEnabled(isNotMultiSelection);
269 ui->btnChart->setEnabled(isNotMultiSelection);
269 ui->btnTime->setEnabled(isNotMultiSelection);
270 ui->btnTime->setEnabled(isNotMultiSelection);
270
271
271 if (isNotMultiSelection && ui->btnTime->isChecked()) {
272 if (isNotMultiSelection && ui->btnTime->isChecked()) {
272 impl->updateForTimeMode(ui->treeView);
273 impl->updateForTimeMode(ui->treeView);
273 }
274 }
274 else if (isNotMultiSelection && ui->btnChart->isChecked()) {
275 else if (isNotMultiSelection && ui->btnChart->isChecked()) {
275 impl->updateForGraphMode(ui->treeView);
276 impl->updateForGraphMode(ui->treeView);
276 }
277 }
277 });
278 });
278
279
279 ui->treeView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
280 ui->treeView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
280 ui->treeView->header()->setSectionResizeMode(0, QHeaderView::Stretch);
281 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::Name,
282 QHeaderView::Stretch);
283 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::Validation,
284 QHeaderView::Fixed);
285 ui->treeView->header()->resizeSection((int)CatalogueEventsModel::Column::Validation,
286 VALIDATION_COLUMN_SIZE);
281 ui->treeView->header()->setSortIndicatorShown(true);
287 ui->treeView->header()->setSortIndicatorShown(true);
288
289 connect(impl->m_Model, &CatalogueEventsModel::modelSorted, [this]() {
290 auto allEvents = impl->m_Model->events();
291 for (auto event : allEvents) {
292 setEventChanges(event, impl->m_Model->eventsHasChanges(event));
293 }
294 });
282 }
295 }
283
296
284 CatalogueEventsWidget::~CatalogueEventsWidget()
297 CatalogueEventsWidget::~CatalogueEventsWidget()
285 {
298 {
286 delete ui;
299 delete ui;
287 }
300 }
288
301
289 void CatalogueEventsWidget::setVisualizationWidget(VisualizationWidget *visualization)
302 void CatalogueEventsWidget::setVisualizationWidget(VisualizationWidget *visualization)
290 {
303 {
291 impl->m_VisualizationWidget = visualization;
304 impl->m_VisualizationWidget = visualization;
292 }
305 }
293
306
294 void CatalogueEventsWidget::setEventChanges(const std::shared_ptr<DBEvent> &event, bool hasChanges)
307 void CatalogueEventsWidget::setEventChanges(const std::shared_ptr<DBEvent> &event, bool hasChanges)
295 {
308 {
296 impl->m_Model->refreshEvent(event);
309 impl->m_Model->refreshEvent(event);
310
311 auto eventIndex = impl->m_Model->indexOf(event);
312 auto validationIndex
313 = eventIndex.sibling(eventIndex.row(), (int)CatalogueEventsModel::Column::Validation);
314
315 if (hasChanges) {
316 if (ui->treeView->indexWidget(validationIndex) == nullptr) {
317 auto widget = CatalogueExplorerHelper::buildValidationWidget(
318 ui->treeView, [this, event]() { setEventChanges(event, false); },
319 [this, event]() { setEventChanges(event, false); });
320 ui->treeView->setIndexWidget(validationIndex, widget);
321 }
322 }
323 else {
324 // Note: the widget is destroyed
325 ui->treeView->setIndexWidget(validationIndex, nullptr);
326 }
327
328 impl->m_Model->setEventHasChanges(event, hasChanges);
297 }
329 }
298
330
299 void CatalogueEventsWidget::populateWithCatalogues(
331 void CatalogueEventsWidget::populateWithCatalogues(
300 const QVector<std::shared_ptr<DBCatalogue> > &catalogues)
332 const QVector<std::shared_ptr<DBCatalogue> > &catalogues)
301 {
333 {
302 QSet<QUuid> eventIds;
334 QSet<QUuid> eventIds;
303 QVector<std::shared_ptr<DBEvent> > events;
335 QVector<std::shared_ptr<DBEvent> > events;
304
336
305 for (auto catalogue : catalogues) {
337 for (auto catalogue : catalogues) {
306 auto catalogueEvents = sqpApp->catalogueController().retrieveEventsFromCatalogue(catalogue);
338 auto catalogueEvents = sqpApp->catalogueController().retrieveEventsFromCatalogue(catalogue);
307 for (auto event : catalogueEvents) {
339 for (auto event : catalogueEvents) {
308 if (!eventIds.contains(event->getUniqId())) {
340 if (!eventIds.contains(event->getUniqId())) {
309 events << event;
341 events << event;
310 eventIds.insert(event->getUniqId());
342 eventIds.insert(event->getUniqId());
311 }
343 }
312 }
344 }
313 }
345 }
314
346
315 impl->setEvents(events, ui->treeView);
347 impl->setEvents(events, ui->treeView);
316 }
348 }
317
349
318 void CatalogueEventsWidget::populateWithAllEvents()
350 void CatalogueEventsWidget::populateWithAllEvents()
319 {
351 {
320 auto allEvents = sqpApp->catalogueController().retrieveAllEvents();
352 auto allEvents = sqpApp->catalogueController().retrieveAllEvents();
321
353
322 QVector<std::shared_ptr<DBEvent> > events;
354 QVector<std::shared_ptr<DBEvent> > events;
323 for (auto event : allEvents) {
355 for (auto event : allEvents) {
324 events << event;
356 events << event;
325 }
357 }
326
358
327 impl->setEvents(events, ui->treeView);
359 impl->setEvents(events, ui->treeView);
328 }
360 }
@@ -1,103 +1,87
1 #include "Catalogue/CatalogueTreeWidgetItem.h"
1 #include "Catalogue/CatalogueTreeWidgetItem.h"
2 #include <Catalogue/CatalogueExplorerHelper.h>
2
3
3 #include <memory>
4 #include <memory>
4
5
5 #include <DBCatalogue.h>
6 #include <DBCatalogue.h>
6 #include <QBoxLayout>
7 #include <QToolButton>
8
9 const auto VALIDATION_BUTTON_ICON_SIZE = 12;
10
7
11 /// Column in the tree widget where the apply and cancel buttons must appear
8 /// Column in the tree widget where the apply and cancel buttons must appear
12 const auto APPLY_CANCEL_BUTTONS_COLUMN = 1;
9 const auto APPLY_CANCEL_BUTTONS_COLUMN = 1;
13
10
14 struct CatalogueTreeWidgetItem::CatalogueTreeWidgetItemPrivate {
11 struct CatalogueTreeWidgetItem::CatalogueTreeWidgetItemPrivate {
15
12
16 std::shared_ptr<DBCatalogue> m_Catalogue;
13 std::shared_ptr<DBCatalogue> m_Catalogue;
17
14
18 CatalogueTreeWidgetItemPrivate(std::shared_ptr<DBCatalogue> catalogue) : m_Catalogue(catalogue)
15 CatalogueTreeWidgetItemPrivate(std::shared_ptr<DBCatalogue> catalogue) : m_Catalogue(catalogue)
19 {
16 {
20 }
17 }
21 };
18 };
22
19
23
20
24 CatalogueTreeWidgetItem::CatalogueTreeWidgetItem(std::shared_ptr<DBCatalogue> catalogue, int type)
21 CatalogueTreeWidgetItem::CatalogueTreeWidgetItem(std::shared_ptr<DBCatalogue> catalogue, int type)
25 : QTreeWidgetItem(type),
22 : QTreeWidgetItem(type),
26 impl{spimpl::make_unique_impl<CatalogueTreeWidgetItemPrivate>(catalogue)}
23 impl{spimpl::make_unique_impl<CatalogueTreeWidgetItemPrivate>(catalogue)}
27 {
24 {
28 setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable);
25 setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable);
29 }
26 }
30
27
31 QVariant CatalogueTreeWidgetItem::data(int column, int role) const
28 QVariant CatalogueTreeWidgetItem::data(int column, int role) const
32 {
29 {
33 if (column == 0) {
30 if (column == 0) {
34 switch (role) {
31 switch (role) {
35 case Qt::EditRole: // fallthrough
32 case Qt::EditRole: // fallthrough
36 case Qt::DisplayRole:
33 case Qt::DisplayRole:
37 return impl->m_Catalogue->getName();
34 return impl->m_Catalogue->getName();
38 default:
35 default:
39 break;
36 break;
40 }
37 }
41 }
38 }
42
39
43 return QTreeWidgetItem::data(column, role);
40 return QTreeWidgetItem::data(column, role);
44 }
41 }
45
42
46 void CatalogueTreeWidgetItem::setData(int column, int role, const QVariant &value)
43 void CatalogueTreeWidgetItem::setData(int column, int role, const QVariant &value)
47 {
44 {
48 if (role == Qt::EditRole && column == 0) {
45 if (role == Qt::EditRole && column == 0) {
49 auto newName = value.toString();
46 auto newName = value.toString();
50 if (newName != impl->m_Catalogue->getName()) {
47 if (newName != impl->m_Catalogue->getName()) {
51 setText(0, newName);
48 setText(0, newName);
52 impl->m_Catalogue->setName(newName);
49 impl->m_Catalogue->setName(newName);
53 setHasChanges(true);
50 setHasChanges(true);
54 }
51 }
55 }
52 }
56 else {
53 else {
57 QTreeWidgetItem::setData(column, role, value);
54 QTreeWidgetItem::setData(column, role, value);
58 }
55 }
59 }
56 }
60
57
61 std::shared_ptr<DBCatalogue> CatalogueTreeWidgetItem::catalogue() const
58 std::shared_ptr<DBCatalogue> CatalogueTreeWidgetItem::catalogue() const
62 {
59 {
63 return impl->m_Catalogue;
60 return impl->m_Catalogue;
64 }
61 }
65
62
66 void CatalogueTreeWidgetItem::setHasChanges(bool value)
63 void CatalogueTreeWidgetItem::setHasChanges(bool value)
67 {
64 {
68 if (value) {
65 if (value) {
69 if (treeWidget()->itemWidget(this, APPLY_CANCEL_BUTTONS_COLUMN) == nullptr) {
66 if (!hasChanges()) {
70 auto widet = new QWidget{treeWidget()};
67 auto widget = CatalogueExplorerHelper::buildValidationWidget(
71
68 treeWidget(), [this]() { setHasChanges(false); },
72 auto layout = new QHBoxLayout{widet};
69 [this]() { setHasChanges(false); });
73 layout->setContentsMargins(0, 0, 0, 0);
70 treeWidget()->setItemWidget(this, APPLY_CANCEL_BUTTONS_COLUMN, widget);
74 layout->setSpacing(0);
75
76 auto btnValid = new QToolButton{widet};
77 btnValid->setIcon(QIcon{":/icones/save"});
78 btnValid->setIconSize(QSize{VALIDATION_BUTTON_ICON_SIZE, VALIDATION_BUTTON_ICON_SIZE});
79 btnValid->setAutoRaise(true);
80 QObject::connect(btnValid, &QToolButton::clicked, [this]() { setHasChanges(false); });
81 layout->addWidget(btnValid);
82
83 auto btnDiscard = new QToolButton{widet};
84 btnDiscard->setIcon(QIcon{":/icones/discard"});
85 btnDiscard->setIconSize(
86 QSize{VALIDATION_BUTTON_ICON_SIZE, VALIDATION_BUTTON_ICON_SIZE});
87 btnDiscard->setAutoRaise(true);
88 QObject::connect(btnDiscard, &QToolButton::clicked, [this]() { setHasChanges(false); });
89 layout->addWidget(btnDiscard);
90
91 treeWidget()->setItemWidget(this, APPLY_CANCEL_BUTTONS_COLUMN, {widet});
92 }
71 }
93 }
72 }
94 else {
73 else {
95 // Note: the widget is destroyed
74 // Note: the widget is destroyed
96 treeWidget()->setItemWidget(this, APPLY_CANCEL_BUTTONS_COLUMN, nullptr);
75 treeWidget()->setItemWidget(this, APPLY_CANCEL_BUTTONS_COLUMN, nullptr);
97 }
76 }
98 }
77 }
99
78
79 bool CatalogueTreeWidgetItem::hasChanges()
80 {
81 return treeWidget()->itemWidget(this, APPLY_CANCEL_BUTTONS_COLUMN) != nullptr;
82 }
83
100 void CatalogueTreeWidgetItem::refresh()
84 void CatalogueTreeWidgetItem::refresh()
101 {
85 {
102 emitDataChanged();
86 emitDataChanged();
103 }
87 }
General Comments 4
Under Review
author

Pull request updated. Auto status change to "Under Review"

Changed commits:
  * 1 added
  * 0 removed

Changed files:
  * M app/src/Main.cpp
  * M core/include/Catalogue/CatalogueController.h
  * M core/src/Catalogue/CatalogueController.cpp
  * M core/src/Plugin/PluginManager.cpp
  * M core/tests/Data/TestDataSeriesUtils.cpp
  * M gui/include/Catalogue/CatalogueEventsModel.h
  * M gui/include/Catalogue/CatalogueEventsWidget.h
  * M gui/include/Catalogue/CatalogueTreeWidgetItem.h
  * M gui/meson.build
  * M gui/src/Catalogue/CatalogueEventsModel.cpp
  * M gui/src/Catalogue/CatalogueEventsWidget.cpp
  * M gui/src/Catalogue/CatalogueExplorer.cpp
  * M gui/src/Catalogue/CatalogueSideBarWidget.cpp
  * M gui/src/Catalogue/CatalogueTreeWidgetItem.cpp
  * M gui/src/Visualization/VisualizationActionManager.cpp
  * M gui/src/Visualization/VisualizationGraphWidget.cpp
  * M gui/src/Visualization/VisualizationSelectionZoneItem.cpp
  * M plugins/amda/tests/TestAmdaResultParser.cpp
  * R cmake/FindCatalogueAPI.cmake
  * R core/include/Common/MimeTypesDef.h
  * R core/include/Data/DataSeriesUtils.h
  * R core/include/Data/OptionalAxis.h
  * R core/include/Data/SpectrogramSeries.h
  * R core/include/Data/Unit.h
  * R core/include/DataSource/DataSourceItemMergeHelper.h
  * R core/include/Variable/VariableCacheStrategyFactory.h
  * R core/include/Variable/VariableSingleThresholdCacheStrategy.h
  * R core/src/Common/MimeTypesDef.cpp
  * R core/src/Data/DataSeriesUtils.cpp
  * R core/src/Data/OptionalAxis.cpp
  * R core/src/Data/SpectrogramSeries.cpp
  * R core/src/DataSource/DataSourceItemMergeHelper.cpp
  * R core/tests-resources/TestDataSeriesUtils/TestThresholds.txt
  * R core/tests/Data/DataSeriesBuilders.cpp
  * R core/tests/Data/DataSeriesBuilders.h
  * R core/tests/Data/DataSeriesTestsUtils.cpp
  * R core/tests/Data/DataSeriesTestsUtils.h
  * R core/tests/Data/TestOptionalAxis.cpp
  * R core/tests/Data/TestScalarSeries.cpp
  * R core/tests/Data/TestSpectrogramSeries.cpp
  * R core/tests/Data/TestVectorSeries.cpp
  * R core/tests/DataSource/DataSourceItemBuilder.cpp
  * R core/tests/DataSource/DataSourceItemBuilder.h
  * R core/tests/DataSource/TestDataSourceItem.cpp
  * R core/tests/Variable/TestVariableSync.cpp
  * R extern/CatalogueAPI.cmake
  * R gui/include/Actions/ActionsGuiController.h
  * R gui/include/Actions/SelectionZoneAction.h
  * R gui/include/Catalogue/CatalogueExplorer.h
  * R gui/include/Catalogue/CatalogueInspectorWidget.h
  * R gui/include/Catalogue/CatalogueSideBarWidget.h
  * R gui/include/Common/VisualizationDef.h
  * R gui/include/DataSource/DataSourceTreeWidget.h
  * R gui/include/DragAndDrop/DragDropGuiController.h
  * R gui/include/DragAndDrop/DragDropScroller.h
  * R gui/include/DragAndDrop/DragDropTabSwitcher.h
  * R gui/include/Variable/VariableInspectorTableView.h
  * R gui/include/Visualization/AxisRenderingUtils.h
  * R gui/include/Visualization/ColorScaleEditor.h
  * R gui/include/Visualization/MacScrollBarStyle.h
  * R gui/include/Visualization/PlottablesRenderingUtils.h
  * R gui/include/Visualization/QCPColorMapIterator.h
  * R gui/include/Visualization/SqpColorScale.h
  * R gui/include/Visualization/VisualizationActionManager.h
  * R gui/include/Visualization/VisualizationCursorItem.h
  * R gui/include/Visualization/VisualizationDragDropContainer.h
  * R gui/include/Visualization/VisualizationDragWidget.h
  * R gui/include/Visualization/VisualizationMultiZoneSelectionDialog.h
  * R gui/include/Visualization/VisualizationSelectionZoneItem.h
  * R gui/include/Visualization/VisualizationSelectionZoneManager.h
  * R gui/resources/icones/add.png
  * R gui/resources/icones/allEvents.png
  * R gui/resources/icones/catalogue.png
  * R gui/resources/icones/chart.png
  * R gui/resources/icones/cursor.png
  * R gui/resources/icones/database.png
  * R gui/resources/icones/discard.png
  * R gui/resources/icones/drag.png
  * R gui/resources/icones/pointer.png
  * R gui/resources/icones/rectangle.png
  * R gui/resources/icones/remove.png
  * R gui/resources/icones/save.png
  * R gui/resources/icones/time.png
  * R gui/resources/icones/trash.png
  * R gui/resources/icones/zoom.png
  * R gui/src/Actions/ActionsGuiController.cpp
  * R gui/src/Actions/SelectionZoneAction.cpp
  * R gui/src/Catalogue/CatalogueInspectorWidget.cpp
  * R gui/src/Common/VisualizationDef.cpp
  * R gui/src/DataSource/DataSourceTreeWidget.cpp
  * R gui/src/DragAndDrop/DragDropGuiController.cpp
  * R gui/src/DragAndDrop/DragDropScroller.cpp
  * R gui/src/DragAndDrop/DragDropTabSwitcher.cpp
  * R gui/src/Variable/VariableInspectorTableView.cpp
  * R gui/src/Visualization/AxisRenderingUtils.cpp
  * R gui/src/Visualization/ColorScaleEditor.cpp
  * R gui/src/Visualization/MacScrollBarStyle.cpp
  * R gui/src/Visualization/PlottablesRenderingUtils.cpp
  * R gui/src/Visualization/QCPColorMapIterator.cpp
  * R gui/src/Visualization/SqpColorScale.cpp
  * R gui/src/Visualization/VisualizationCursorItem.cpp
  * R gui/src/Visualization/VisualizationDragDropContainer.cpp
  * R gui/src/Visualization/VisualizationDragWidget.cpp
  * R gui/src/Visualization/VisualizationMultiZoneSelectionDialog.cpp
  * R gui/src/Visualization/VisualizationSelectionZoneManager.cpp
  * R gui/ui/Catalogue/CatalogueEventsWidget.ui
  * R gui/ui/Catalogue/CatalogueExplorer.ui
  * R gui/ui/Catalogue/CatalogueInspectorWidget.ui
  * R gui/ui/Catalogue/CatalogueSideBarWidget.ui
  * R gui/ui/Visualization/ColorScaleEditor.ui
  * R gui/ui/Visualization/VisualizationMultiZoneSelectionDialog.ui
  * R plugins/amda/include/AmdaResultParserDefs.h
  * R plugins/amda/include/AmdaResultParserHelper.h
  * R plugins/amda/include/AmdaServer.h
  * R plugins/amda/resources/samples/AmdaSampleV3.json
  * R plugins/amda/src/AmdaResultParserDefs.cpp
  * R plugins/amda/src/AmdaResultParserHelper.cpp
  * R plugins/amda/src/AmdaServer.cpp
  * R plugins/amda/tests-resources/TestAmdaResultParser/amdaV2/FileNotFound.txt
  * R plugins/amda/tests-resources/TestAmdaResultParser/amdaV2/NaNValue.txt
  * R plugins/amda/tests-resources/TestAmdaResultParser/amdaV2/NaNX.txt
  * R plugins/amda/tests-resources/TestAmdaResultParser/amdaV2/NoUnit.txt
  * R plugins/amda/tests-resources/TestAmdaResultParser/amdaV2/TooManyValues.txt
  * R plugins/amda/tests-resources/TestAmdaResultParser/amdaV2/ValidScalar1.txt
  * R plugins/amda/tests-resources/TestAmdaResultParser/amdaV2/ValidVector1.txt
  * R plugins/amda/tests-resources/TestAmdaResultParser/amdaV2/WrongDate.txt
  * R plugins/amda/tests-resources/TestAmdaResultParser/amdaV2/WrongUnit.txt
  * R plugins/amda/tests-resources/TestAmdaResultParser/amdaV2/WrongValue.txt
  * R plugins/amda/tests-resources/TestAmdaResultParser/spectro/InvalidSpectrogramWrongBands.txt
  * R plugins/amda/tests-resources/TestAmdaResultParser/spectro/ValidSpectrogram1.txt
  * R plugins/amda/tests-resources/TestAmdaResultParser/spectro/ValidSpectrogram2.txt
  * R plugins/amda/tests-resources/TestAmdaResultParser/spectro/ValidSpectrogram3.txt
  * R plugins/amda/tests-resources/TestAmdaResultParser/spectro/ValidSpectrogramDataHoles.txt
  * R plugins/amda/tests-resources/TestAmdaResultParser/spectro/ValidSpectrogramDataHoles2.txt
  * R plugins/amda/tests-resources/TestAmdaResultParser/spectro/ValidSpectrogramFillValues.txt
  * R plugins/amda/tests-resources/TestAmdaResultParser/spectro/ValidSpectrogramNaNValues.txt
  * R plugins/amda/vera-exclusions/exclusions.txt
  * R plugins/mockplugin/include/MockDefs.h
  * R plugins/mockplugin/src/MockDefs.cpp
  * R subprojects/CatalogueAPI.wrap
  * R subprojects/QxOrm.wrap
  * R .gitignore
  * R CMakeLists.txt
  * R app/src/MainWindow.cpp
  * R app/ui/MainWindow.ui
  * R cmake/sciqlop_applications.cmake
  * R cmake/sciqlop_package_qt.cmake
  * R core/CMakeLists.txt
  * R core/cmake/Findsciqlop-core.cmake
  * R core/include/Common/SortUtils.h
  * R core/include/Data/ArrayData.h
  * R core/include/Data/DataSeries.h
  * R core/include/Data/DataSeriesIterator.h
  * R core/include/Data/IDataSeries.h
  * R core/include/Data/VariableRequest.h
  * R core/include/DataSource/DataSourceController.h
  * R core/include/DataSource/DataSourceItem.h
  * R core/include/DataSource/DataSourceItemAction.h
  * R core/include/Plugin/PluginManager.h
  * R core/include/Time/TimeController.h
  * R core/include/Variable/Variable.h
  * R core/include/Variable/VariableCacheStrategy.h
  * R core/include/Variable/VariableController.h
  * R core/include/Variable/VariableModel.h
  * R core/meson.build
  * R core/src/Data/DataSeriesIterator.cpp
  * R core/src/Data/VectorSeries.cpp
  * R core/src/DataSource/DataSourceController.cpp
  * R core/src/DataSource/DataSourceItem.cpp
  * R core/src/DataSource/DataSourceItemAction.cpp
  * R core/src/Time/TimeController.cpp
  * R core/src/Variable/Variable.cpp
  * R core/src/Variable/VariableAcquisitionWorker.cpp
  * R core/src/Variable/VariableController.cpp
  * R core/src/Variable/VariableModel.cpp
  * R core/tests/Data/TestTwoDimArrayData.cpp
  * R core/tests/Variable/TestVariable.cpp
  * R core/tests/meson.build
  * R gui/CMakeLists.txt
  * R gui/cmake/Findsciqlop-gui.cmake
  * R gui/include/DataSource/DataSourceWidget.h
  * R gui/include/SqpApplication.h
  * R gui/include/TimeWidget/TimeWidget.h
  * R gui/include/Visualization/VisualizationGraphHelper.h
  * R gui/include/Visualization/VisualizationGraphRenderingDelegate.h
  * R gui/include/Visualization/VisualizationGraphWidget.h
  * R gui/include/Visualization/VisualizationTabWidget.h
  * R gui/include/Visualization/VisualizationWidget.h
  * R gui/include/Visualization/VisualizationZoneWidget.h
  * R gui/resources/sqpguiresources.qrc
  * R gui/src/DataSource/DataSourceTreeWidgetItem.cpp
  * R gui/src/DataSource/DataSourceWidget.cpp
  * R gui/src/SqpApplication.cpp
  * R gui/src/TimeWidget/TimeWidget.cpp
  * R gui/src/Variable/VariableInspectorWidget.cpp
  * R gui/src/Visualization/VisualizationGraphHelper.cpp
  * R gui/src/Visualization/VisualizationGraphRenderingDelegate.cpp
  * R gui/src/Visualization/VisualizationTabWidget.cpp
  * R gui/src/Visualization/VisualizationWidget.cpp
  * R gui/src/Visualization/VisualizationZoneWidget.cpp
  * R gui/src/Visualization/operations/GenerateVariableMenuOperation.cpp
  * R gui/src/Visualization/operations/RescaleAxeOperation.cpp
  * R gui/ui/DataSource/DataSourceWidget.ui
  * R gui/ui/TimeWidget/TimeWidget.ui
  * R gui/ui/Variable/VariableInspectorWidget.ui
  * R gui/ui/Visualization/VisualizationTabWidget.ui
  * R gui/ui/Visualization/VisualizationZoneWidget.ui
  * R gui/vera-exclusions/exclusions.txt
  * R meson.build
  * R plugins/amda/CMakeLists.txt
  * R plugins/amda/cmake/Findsciqlop-amda.cmake
  * R plugins/amda/include/AmdaDefs.h
  * R plugins/amda/include/AmdaPlugin.h
  * R plugins/amda/include/AmdaProvider.h
  * R plugins/amda/include/AmdaResultParser.h
  * R plugins/amda/meson.build
  * R plugins/amda/resources/amdaresources.qrc
  * R plugins/amda/src/AmdaDefs.cpp
  * R plugins/amda/src/AmdaPlugin.cpp
  * R plugins/amda/src/AmdaProvider.cpp
  * R plugins/amda/src/AmdaResultParser.cpp
  * R plugins/amda/tests/TestAmdaAcquisition.cpp
  * R plugins/mockplugin/cmake/Findsciqlop-mockplugin.cmake
  * R plugins/mockplugin/include/CosinusProvider.h
  * R plugins/mockplugin/meson.build
  * R plugins/mockplugin/src/CosinusProvider.cpp
  * R plugins/mockplugin/src/MockPlugin.cpp
  * R plugins/mockplugin/tests/TestCosinusAcquisition.cpp
  * R core/src/Variable/VariableCacheStrategy.cpp
  * R core/tests/Data/TestDataSeries.cpp
Approved

Status change > Approved

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