##// END OF EJS Templates
Time Zone Mode + prepare graph mode
trabillard -
r1138:f7fe3621eadc
parent child
Show More
@@ -1,37 +1,40
1 1 #ifndef SCIQLOP_CATALOGUEEVENTSWIDGET_H
2 2 #define SCIQLOP_CATALOGUEEVENTSWIDGET_H
3 3
4 4 #include <Common/spimpl.h>
5 #include <QLoggingCategory>
5 6 #include <QWidget>
6 7
7 8 class DBCatalogue;
8 9 class DBEvent;
9 10 class VisualizationWidget;
10 11
11 12 namespace Ui {
12 13 class CatalogueEventsWidget;
13 14 }
14 15
16 Q_DECLARE_LOGGING_CATEGORY(LOG_CatalogueEventsWidget)
17
15 18 class CatalogueEventsWidget : public QWidget {
16 19 Q_OBJECT
17 20
18 21 signals:
19 22 void eventsSelected(const QVector<DBEvent> &event);
20 23
21 24 public:
22 25 explicit CatalogueEventsWidget(QWidget *parent = 0);
23 26 virtual ~CatalogueEventsWidget();
24 27
25 28 void setVisualizationWidget(VisualizationWidget *visualization);
26 29
27 30 public slots:
28 31 void populateWithCatalogues(const QVector<DBCatalogue> &catalogues);
29 32
30 33 private:
31 34 Ui::CatalogueEventsWidget *ui;
32 35
33 36 class CatalogueEventsWidgetPrivate;
34 37 spimpl::unique_impl_ptr<CatalogueEventsWidgetPrivate> impl;
35 38 };
36 39
37 40 #endif // SCIQLOP_CATALOGUEEVENTSWIDGET_H
@@ -1,84 +1,88
1 1 #ifndef SCIQLOP_VISUALIZATIONTABWIDGET_H
2 2 #define SCIQLOP_VISUALIZATIONTABWIDGET_H
3 3
4 4 #include "Visualization/IVisualizationWidget.h"
5 5
6 6 #include <Common/spimpl.h>
7 7
8 8 #include <QLoggingCategory>
9 9 #include <QMimeData>
10 10 #include <QWidget>
11 11
12 12 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationTabWidget)
13 13
14 14 class Variable;
15 15 class VisualizationZoneWidget;
16 16
17 17 namespace Ui {
18 18 class VisualizationTabWidget;
19 19 } // namespace Ui
20 20
21 21 class VisualizationTabWidget : public QWidget, public IVisualizationWidget {
22 22 Q_OBJECT
23 23
24 24 public:
25 25 explicit VisualizationTabWidget(const QString &name = {}, QWidget *parent = 0);
26 26 virtual ~VisualizationTabWidget();
27 27
28 28 /// Adds a zone widget
29 29 void addZone(VisualizationZoneWidget *zoneWidget);
30 30
31 31 /// Inserts a zone widget at the specified position
32 32 void insertZone(int index, VisualizationZoneWidget *zoneWidget);
33 33
34 34 /// Returns the list of zone widget names in the order they are displayed
35 35 QStringList availableZoneWidgets() const;
36 36
37 /// Returns the zone with the specified name.
38 /// If multiple zone with the same name exist, the first one is returned.
39 VisualizationZoneWidget *getZoneWithName(const QString &zoneName);
40
37 41 /**
38 42 * Creates a zone using a variable. The variable will be displayed in a new graph of the new
39 43 * zone. The zone is added at the end.
40 44 * @param variable the variable for which to create the zone
41 45 * @return the pointer to the created zone
42 46 */
43 47 VisualizationZoneWidget *createZone(std::shared_ptr<Variable> variable);
44 48
45 49 /**
46 50 * Creates a zone using a list of variables. The variables will be displayed in a new graph of
47 51 * the new zone. The zone is inserted at the specified index.
48 52 * @param variables the variables for which to create the zone
49 53 * @param index The index where the zone should be inserted in the layout
50 54 * @return the pointer to the created zone
51 55 */
52 56 VisualizationZoneWidget *createZone(const QList<std::shared_ptr<Variable> > &variables,
53 57 int index);
54 58
55 59 /**
56 60 * Creates a zone which is empty (no variables). The zone is inserted at the specified index.
57 61 * @param index The index where the zone should be inserted in the layout
58 62 * @return the pointer to the created zone
59 63 */
60 64 VisualizationZoneWidget *createEmptyZone(int index);
61 65
62 66 // IVisualizationWidget interface
63 67 void accept(IVisualizationWidgetVisitor *visitor) override;
64 68 bool canDrop(const Variable &variable) const override;
65 69 bool contains(const Variable &variable) const override;
66 70 QString name() const override;
67 71
68 72 protected:
69 73 void closeEvent(QCloseEvent *event) override;
70 74
71 75 private:
72 76 /// @return the layout of tab in which zones are added
73 77 QLayout &tabLayout() const noexcept;
74 78
75 79 Ui::VisualizationTabWidget *ui;
76 80
77 81 class VisualizationTabWidgetPrivate;
78 82 spimpl::unique_impl_ptr<VisualizationTabWidgetPrivate> impl;
79 83
80 84 private slots:
81 85 void dropMimeData(int index, const QMimeData *mimeData);
82 86 };
83 87
84 88 #endif // SCIQLOP_VISUALIZATIONTABWIDGET_H
@@ -1,98 +1,103
1 1 #ifndef SCIQLOP_VISUALIZATIONZONEWIDGET_H
2 2 #define SCIQLOP_VISUALIZATIONZONEWIDGET_H
3 3
4 #include "Data/SqpRange.h"
4 5 #include "Visualization/IVisualizationWidget.h"
5 6 #include "Visualization/VisualizationDragWidget.h"
6 7
7 8 #include <QLoggingCategory>
8 9 #include <QWidget>
9 10
10 11 #include <memory>
11 12
12 13 #include <Common/spimpl.h>
13 14
14 15 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationZoneWidget)
15 16
16 17 namespace Ui {
17 18 class VisualizationZoneWidget;
18 19 } // namespace Ui
19 20
20 21 class Variable;
21 22 class VisualizationGraphWidget;
22 23
23 24 class VisualizationZoneWidget : public VisualizationDragWidget, public IVisualizationWidget {
24 25 Q_OBJECT
25 26
26 27 public:
27 28 explicit VisualizationZoneWidget(const QString &name = {}, QWidget *parent = 0);
28 29 virtual ~VisualizationZoneWidget();
29 30
31 /// Sets the range of the zone, only works if there is at least one graph in the zone
32 /// Note: calibrations between graphs are lost.
33 void setZoneRange(const SqpRange &range);
34
30 35 /// Adds a graph widget
31 36 void addGraph(VisualizationGraphWidget *graphWidget);
32 37
33 38 /// Inserts a graph widget
34 39 void insertGraph(int index, VisualizationGraphWidget *graphWidget);
35 40
36 41 /**
37 42 * Creates a graph using a variable. The variable will be displayed in the new graph.
38 43 * The graph is added at the end.
39 44 * @param variable the variable for which to create the graph
40 45 * @return the pointer to the created graph
41 46 */
42 47 VisualizationGraphWidget *createGraph(std::shared_ptr<Variable> variable);
43 48
44 49 /**
45 50 * Creates a graph using a variable. The variable will be displayed in the new graph.
46 51 * The graph is inserted at the specified index.
47 52 * @param variable the variable for which to create the graph
48 53 * @param index The index where the graph should be inserted in the layout
49 54 * @return the pointer to the created graph
50 55 */
51 56 VisualizationGraphWidget *createGraph(std::shared_ptr<Variable> variable, int index);
52 57
53 58 /**
54 59 * Creates a graph using a list of variables. The variables will be displayed in the new graph.
55 60 * The graph is inserted at the specified index.
56 61 * @param variables List of variables to be added to the graph
57 62 * @param index The index where the graph should be inserted in the layout
58 63 * @return the pointer to the created graph
59 64 */
60 65 VisualizationGraphWidget *createGraph(const QList<std::shared_ptr<Variable> > variables,
61 66 int index);
62 67
63 68 /// Returns the first graph in the zone or nullptr if there is no graph inside
64 69 VisualizationGraphWidget *firstGraph() const;
65 70
66 71 // IVisualizationWidget interface
67 72 void accept(IVisualizationWidgetVisitor *visitor) override;
68 73 bool canDrop(const Variable &variable) const override;
69 74 bool contains(const Variable &variable) const override;
70 75 QString name() const override;
71 76
72 77 // VisualisationDragWidget
73 78 QMimeData *mimeData(const QPoint &position) const override;
74 79 bool isDragAllowed() const override;
75 80
76 81 void notifyMouseMoveInGraph(const QPointF &graphPosition, const QPointF &plotPosition,
77 82 VisualizationGraphWidget *graphWidget);
78 83 void notifyMouseLeaveGraph(VisualizationGraphWidget *graphWidget);
79 84
80 85 protected:
81 86 void closeEvent(QCloseEvent *event) override;
82 87
83 88 private:
84 89 Ui::VisualizationZoneWidget *ui;
85 90
86 91 class VisualizationZoneWidgetPrivate;
87 92 spimpl::unique_impl_ptr<VisualizationZoneWidgetPrivate> impl;
88 93
89 94 private slots:
90 95 void onVariableAdded(std::shared_ptr<Variable> variable);
91 96 /// Slot called when a variable is about to be removed from a graph contained in the zone
92 97 void onVariableAboutToBeRemoved(std::shared_ptr<Variable> variable);
93 98
94 99 void dropMimeData(int index, const QMimeData *mimeData);
95 100 void dropMimeDataOnGraph(VisualizationDragWidget *dragWidget, const QMimeData *mimeData);
96 101 };
97 102
98 103 #endif // SCIQLOP_VISUALIZATIONZONEWIDGET_H
@@ -1,218 +1,292
1 1 #include "Catalogue/CatalogueEventsWidget.h"
2 2 #include "ui_CatalogueEventsWidget.h"
3 3
4 4 #include <Catalogue/CatalogueController.h>
5 5 #include <Catalogue/CatalogueEventsTableModel.h>
6 6 #include <CatalogueDao.h>
7 7 #include <DBCatalogue.h>
8 8 #include <SqpApplication.h>
9 9 #include <Visualization/VisualizationTabWidget.h>
10 10 #include <Visualization/VisualizationWidget.h>
11 #include <Visualization/VisualizationZoneWidget.h>
11 12
12 13 #include <QDialog>
13 14 #include <QDialogButtonBox>
14 15 #include <QListWidget>
15 16
17 Q_LOGGING_CATEGORY(LOG_CatalogueEventsWidget, "CatalogueEventsWidget")
16 18
17 19 /// Format of the dates appearing in the label of a cursor
18 20 const auto DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd hh:mm:ss");
19 21
20 22 struct CatalogueEventsWidget::CatalogueEventsWidgetPrivate {
21 23
22 24 CatalogueEventsTableModel *m_Model = nullptr;
23 QString m_ZoneForTimeMode;
25 QStringList m_ZonesForTimeMode;
24 26 QString m_ZoneForGraphMode;
25 27
26 28 VisualizationWidget *m_VisualizationWidget = nullptr;
27 29
28 30 void setEvents(const QVector<DBEvent> &events, QTableView *tableView)
29 31 {
30 32 tableView->setSortingEnabled(false);
31 33 m_Model->setEvents(events);
32 34 tableView->setSortingEnabled(true);
33 35 }
34 36
35 37 void addEvent(const DBEvent &event, QTableView *tableView)
36 38 {
37 39 tableView->setSortingEnabled(false);
38 40 m_Model->addEvent(event);
39 41 tableView->setSortingEnabled(true);
40 42 }
41 43
42 44 void removeEvent(const DBEvent &event, QTableView *tableView)
43 45 {
44 46 tableView->setSortingEnabled(false);
45 47 m_Model->removeEvent(event);
46 48 tableView->setSortingEnabled(true);
47 49 }
48 50
49 51 QStringList getAvailableVisualizationZoneList() const
50 52 {
51 53 if (m_VisualizationWidget) {
52 54 if (auto tab = m_VisualizationWidget->currentTabWidget()) {
53 55 return tab->availableZoneWidgets();
54 56 }
55 57 }
56 58
57 59 return QStringList{};
58 60 }
59 61
60 62 QStringList selectZone(QWidget *parent, const QStringList &selectedZones,
61 63 bool allowMultiSelection, const QPoint &location)
62 64 {
63 65 auto availableZones = getAvailableVisualizationZoneList();
64 66 if (availableZones.isEmpty()) {
65 67 return QStringList{};
66 68 }
67 69
68 70 QDialog d(parent, Qt::Tool);
69 71 d.setWindowTitle("Choose a zone");
70 72 auto layout = new QVBoxLayout{&d};
71 73 layout->setContentsMargins(0, 0, 0, 0);
72 74 auto listWidget = new QListWidget{&d};
73 75 layout->addWidget(listWidget);
74 76
75 77 QSet<QListWidgetItem *> checkedItems;
76 78 for (auto zone : availableZones) {
77 79 auto item = new QListWidgetItem{zone};
78 80 item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsUserCheckable);
79 81 if (selectedZones.contains(zone)) {
80 82 item->setCheckState(Qt::Checked);
81 83 checkedItems << item;
82 84 }
83 85 else {
84 86 item->setCheckState(Qt::Unchecked);
85 87 }
86 88
87 89 listWidget->addItem(item);
88 90 }
89 91
90 92 auto buttonBox = new QDialogButtonBox{QDialogButtonBox::Ok, &d};
91 93 layout->addWidget(buttonBox);
92 94
93 95 QObject::connect(buttonBox, &QDialogButtonBox::accepted, &d, &QDialog::accept);
94 96 QObject::connect(buttonBox, &QDialogButtonBox::rejected, &d, &QDialog::reject);
95 97
96 98 QObject::connect(listWidget, &QListWidget::itemChanged,
97 99 [&checkedItems, allowMultiSelection, listWidget](auto item) {
98 100 if (item->checkState() == Qt::Checked) {
99 101 if (!allowMultiSelection) {
100 102 for (auto checkedItem : checkedItems) {
101 103 listWidget->blockSignals(true);
102 104 checkedItem->setCheckState(Qt::Unchecked);
103 105 listWidget->blockSignals(false);
104 106 }
105 107
106 108 checkedItems.clear();
107 109 }
108 110 checkedItems << item;
109 111 }
110 112 else {
111 113 checkedItems.remove(item);
112 114 }
113 115 });
114 116
115 117 QStringList result;
116 118
117 119 d.setMinimumWidth(120);
118 120 d.resize(d.minimumSizeHint());
119 121 d.move(location);
120 122 if (d.exec() == QDialog::Accepted) {
121 123 for (auto item : checkedItems) {
122 124 result += item->text();
123 125 }
124 126 }
125 127 else {
126 128 result = selectedZones;
127 129 }
128 130
129 131 return result;
130 132 }
133
134 void updateForTimeMode(QTableView *tableView)
135 {
136 auto selectedRows = tableView->selectionModel()->selectedRows();
137
138 if (selectedRows.count() == 1) {
139 auto event = m_Model->getEvent(selectedRows.first().row());
140 if (m_VisualizationWidget) {
141 if (auto tab = m_VisualizationWidget->currentTabWidget()) {
142
143 for (auto zoneName : m_ZonesForTimeMode) {
144 if (auto zone = tab->getZoneWithName(zoneName)) {
145 SqpRange eventRange;
146 eventRange.m_TStart = event.getTStart();
147 eventRange.m_TEnd = event.getTEnd();
148 zone->setZoneRange(eventRange);
149 }
150 }
151 }
152 else {
153 qCWarning(LOG_CatalogueEventsWidget())
154 << "updateTimeZone: no tab found in the visualization";
155 }
156 }
157 else {
158 qCWarning(LOG_CatalogueEventsWidget())
159 << "updateTimeZone: visualization widget not found";
160 }
161 }
162 else {
163 qCWarning(LOG_CatalogueEventsWidget())
164 << "updateTimeZone: not compatible with multiple events selected";
165 }
166 }
167
168 void updateForGraphMode(QTableView *tableView)
169 {
170 auto selectedRows = tableView->selectionModel()->selectedRows();
171
172 if (selectedRows.count() == 1) {
173 auto event = m_Model->getEvent(selectedRows.first().row());
174 if (m_VisualizationWidget) {
175 if (auto tab = m_VisualizationWidget->currentTabWidget()) {
176 if (auto zone = tab->getZoneWithName(m_ZoneForGraphMode)) {
177 // TODO
178 }
179 }
180 else {
181 qCWarning(LOG_CatalogueEventsWidget())
182 << "updateGraphMode: no tab found in the visualization";
183 }
184 }
185 else {
186 qCWarning(LOG_CatalogueEventsWidget())
187 << "updateGraphMode: visualization widget not found";
188 }
189 }
190 else {
191 qCWarning(LOG_CatalogueEventsWidget())
192 << "updateGraphMode: not compatible with multiple events selected";
193 }
194 }
131 195 };
132 196
133 197 CatalogueEventsWidget::CatalogueEventsWidget(QWidget *parent)
134 198 : QWidget(parent),
135 199 ui(new Ui::CatalogueEventsWidget),
136 200 impl{spimpl::make_unique_impl<CatalogueEventsWidgetPrivate>()}
137 201 {
138 202 ui->setupUi(this);
139 203
140 204 impl->m_Model = new CatalogueEventsTableModel{this};
141 205 ui->tableView->setModel(impl->m_Model);
142 206
143 207 ui->tableView->setSortingEnabled(true);
144 208 ui->tableView->setDragDropMode(QAbstractItemView::DragDrop);
145 209 ui->tableView->setDragEnabled(true);
146 210
147 211 connect(ui->btnTime, &QToolButton::clicked, [this](auto checked) {
148 212 if (checked) {
149 213 ui->btnChart->setChecked(false);
150 impl->m_ZoneForTimeMode
151 = impl->selectZone(this, {impl->m_ZoneForTimeMode}, false,
152 this->mapToGlobal(ui->btnTime->frameGeometry().center()))
153 .value(0);
214 impl->m_ZonesForTimeMode
215 = impl->selectZone(this, impl->m_ZonesForTimeMode, true,
216 this->mapToGlobal(ui->btnTime->frameGeometry().center()));
217
218 impl->updateForTimeMode(ui->tableView);
154 219 }
155 220 });
156 221
157 222 connect(ui->btnChart, &QToolButton::clicked, [this](auto checked) {
158 223 if (checked) {
159 224 ui->btnTime->setChecked(false);
160 225 impl->m_ZoneForGraphMode
161 226 = impl->selectZone(this, {impl->m_ZoneForGraphMode}, false,
162 227 this->mapToGlobal(ui->btnChart->frameGeometry().center()))
163 228 .value(0);
229
230 impl->updateForGraphMode(ui->tableView);
164 231 }
165 232 });
166 233
167 234 auto emitSelection = [this]() {
168 235 QVector<DBEvent> events;
169 236 for (auto rowIndex : ui->tableView->selectionModel()->selectedRows()) {
170 237 events << impl->m_Model->getEvent(rowIndex.row());
171 238 }
172 239
173 240 emit this->eventsSelected(events);
174 241 };
175 242
176 243 connect(ui->tableView, &QTableView::clicked, emitSelection);
177 244 connect(ui->tableView->selectionModel(), &QItemSelectionModel::selectionChanged, emitSelection);
178 245
179 246 connect(ui->tableView->selectionModel(), &QItemSelectionModel::selectionChanged, [this]() {
180 247 auto isNotMultiSelection = ui->tableView->selectionModel()->selectedRows().count() <= 1;
181 248 ui->btnChart->setEnabled(isNotMultiSelection);
182 249 ui->btnTime->setEnabled(isNotMultiSelection);
250
251 if (isNotMultiSelection && ui->btnTime->isChecked()) {
252 impl->updateForTimeMode(ui->tableView);
253 }
254 else if (isNotMultiSelection && ui->btnChart->isChecked()) {
255 impl->updateForGraphMode(ui->tableView);
256 }
183 257 });
184 258
185 259 ui->tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
186 260 ui->tableView->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
187 261 ui->tableView->horizontalHeader()->setSortIndicatorShown(true);
188 262 }
189 263
190 264 CatalogueEventsWidget::~CatalogueEventsWidget()
191 265 {
192 266 delete ui;
193 267 }
194 268
195 269 void CatalogueEventsWidget::setVisualizationWidget(VisualizationWidget *visualization)
196 270 {
197 271 impl->m_VisualizationWidget = visualization;
198 272 }
199 273
200 274 void CatalogueEventsWidget::populateWithCatalogues(const QVector<DBCatalogue> &catalogues)
201 275 {
202 276 auto &dao = sqpApp->catalogueController().getDao();
203 277
204 278 QSet<QUuid> eventIds;
205 279 QVector<DBEvent> events;
206 280
207 281 for (auto catalogue : catalogues) {
208 282 auto catalogueEvents = dao.getCatalogueEvents(catalogue);
209 283 for (auto event : catalogueEvents) {
210 284 if (!eventIds.contains(event.getUniqId())) {
211 285 events << event;
212 286 eventIds.insert(event.getUniqId());
213 287 }
214 288 }
215 289 }
216 290
217 291 impl->setEvents(events, ui->tableView);
218 292 }
@@ -1,342 +1,354
1 1 #include "Visualization/VisualizationTabWidget.h"
2 2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 3 #include "ui_VisualizationTabWidget.h"
4 4
5 5 #include "Visualization/VisualizationGraphWidget.h"
6 6 #include "Visualization/VisualizationZoneWidget.h"
7 7
8 8 #include "Visualization/MacScrollBarStyle.h"
9 9
10 10 #include "Variable/VariableController.h"
11 11
12 12 #include "Common/MimeTypesDef.h"
13 13
14 14 #include "DragAndDrop/DragDropGuiController.h"
15 15 #include "SqpApplication.h"
16 16
17 17 Q_LOGGING_CATEGORY(LOG_VisualizationTabWidget, "VisualizationTabWidget")
18 18
19 19 namespace {
20 20
21 21 /**
22 22 * Applies a function to all zones of the tab represented by its layout
23 23 * @param layout the layout that contains zones
24 24 * @param fun the function to apply to each zone
25 25 */
26 26 template <typename Fun>
27 27 void processZones(QLayout &layout, Fun fun)
28 28 {
29 29 for (auto i = 0; i < layout.count(); ++i) {
30 30 if (auto item = layout.itemAt(i)) {
31 31 if (auto visualizationZoneWidget
32 32 = qobject_cast<VisualizationZoneWidget *>(item->widget())) {
33 33 fun(*visualizationZoneWidget);
34 34 }
35 35 }
36 36 }
37 37 }
38 38
39 39 /// Generates a default name for a new zone, according to the number of zones already displayed in
40 40 /// the tab
41 41 QString defaultZoneName(QLayout &layout)
42 42 {
43 43 QSet<QString> existingNames;
44 44 processZones(layout,
45 45 [&existingNames](auto &zoneWidget) { existingNames.insert(zoneWidget.name()); });
46 46
47 47 int zoneNum = 1;
48 48 QString name;
49 49 do {
50 50 name = QObject::tr("Zone ").append(QString::number(zoneNum));
51 51 ++zoneNum;
52 52 } while (existingNames.contains(name));
53 53
54 54 return name;
55 55 }
56 56
57 57 } // namespace
58 58
59 59 struct VisualizationTabWidget::VisualizationTabWidgetPrivate {
60 60 explicit VisualizationTabWidgetPrivate(const QString &name) : m_Name{name} {}
61 61
62 62 QString m_Name;
63 63
64 64 #ifdef Q_OS_MAC
65 65 std::unique_ptr<MacScrollBarStyle> m_MacScrollBarStyle = std::make_unique<MacScrollBarStyle>();
66 66 #endif
67 67
68 68 void dropGraph(int index, VisualizationTabWidget *tabWidget);
69 69 void dropZone(int index, VisualizationTabWidget *tabWidget);
70 70 void dropVariables(const QList<std::shared_ptr<Variable> > &variables, int index,
71 71 VisualizationTabWidget *tabWidget);
72 72 };
73 73
74 74 VisualizationTabWidget::VisualizationTabWidget(const QString &name, QWidget *parent)
75 75 : QWidget{parent},
76 76 ui{new Ui::VisualizationTabWidget},
77 77 impl{spimpl::make_unique_impl<VisualizationTabWidgetPrivate>(name)}
78 78 {
79 79 ui->setupUi(this);
80 80
81 81 #ifdef Q_OS_MAC
82 82 impl->m_MacScrollBarStyle->selfInstallOn(ui->scrollArea, true);
83 83 #endif
84 84
85 85 ui->dragDropContainer->setPlaceHolderType(DragDropGuiController::PlaceHolderType::Zone, "Zone");
86 86 ui->dragDropContainer->layout()->setContentsMargins(0, 0, 0, 12);
87 87 ui->dragDropContainer->layout()->setSpacing(0);
88 88 ui->dragDropContainer->setMimeType(MIME_TYPE_GRAPH,
89 89 VisualizationDragDropContainer::DropBehavior::Inserted);
90 90 ui->dragDropContainer->setMimeType(MIME_TYPE_ZONE,
91 91 VisualizationDragDropContainer::DropBehavior::Inserted);
92 92 ui->dragDropContainer->setMimeType(MIME_TYPE_VARIABLE_LIST,
93 93 VisualizationDragDropContainer::DropBehavior::Inserted);
94 94
95 95 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
96 96 return sqpApp->dragDropGuiController().checkMimeDataForVisualization(mimeData,
97 97 ui->dragDropContainer);
98 98 });
99 99
100 100 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredInContainer, this,
101 101 &VisualizationTabWidget::dropMimeData);
102 102
103 103 sqpApp->dragDropGuiController().addDragDropScrollArea(ui->scrollArea);
104 104
105 105 // Widget is deleted when closed
106 106 setAttribute(Qt::WA_DeleteOnClose);
107 107 }
108 108
109 109 VisualizationTabWidget::~VisualizationTabWidget()
110 110 {
111 111 sqpApp->dragDropGuiController().removeDragDropScrollArea(ui->scrollArea);
112 112 delete ui;
113 113 }
114 114
115 115 void VisualizationTabWidget::addZone(VisualizationZoneWidget *zoneWidget)
116 116 {
117 117 ui->dragDropContainer->addDragWidget(zoneWidget);
118 118 }
119 119
120 120 void VisualizationTabWidget::insertZone(int index, VisualizationZoneWidget *zoneWidget)
121 121 {
122 122 ui->dragDropContainer->insertDragWidget(index, zoneWidget);
123 123 }
124 124
125 125 QStringList VisualizationTabWidget::availableZoneWidgets() const
126 126 {
127 127 QStringList zones;
128 128 processZones(tabLayout(),
129 129 [&zones](VisualizationZoneWidget &zoneWidget) { zones << zoneWidget.name(); });
130 130
131 131 return zones;
132 132 }
133 133
134 VisualizationZoneWidget *VisualizationTabWidget::getZoneWithName(const QString &zoneName)
135 {
136 VisualizationZoneWidget *result = nullptr;
137 processZones(tabLayout(), [&zoneName, &result](VisualizationZoneWidget &zoneWidget) {
138 if (!result && zoneWidget.name() == zoneName) {
139 result = &zoneWidget;
140 }
141 });
142
143 return result;
144 }
145
134 146 VisualizationZoneWidget *VisualizationTabWidget::createZone(std::shared_ptr<Variable> variable)
135 147 {
136 148 return createZone({variable}, -1);
137 149 }
138 150
139 151 VisualizationZoneWidget *
140 152 VisualizationTabWidget::createZone(const QList<std::shared_ptr<Variable> > &variables, int index)
141 153 {
142 154 auto zoneWidget = createEmptyZone(index);
143 155
144 156 // Creates a new graph into the zone
145 157 zoneWidget->createGraph(variables, index);
146 158
147 159 return zoneWidget;
148 160 }
149 161
150 162 VisualizationZoneWidget *VisualizationTabWidget::createEmptyZone(int index)
151 163 {
152 164 auto zoneWidget
153 165 = new VisualizationZoneWidget{defaultZoneName(*ui->dragDropContainer->layout()), this};
154 166 this->insertZone(index, zoneWidget);
155 167
156 168 return zoneWidget;
157 169 }
158 170
159 171 void VisualizationTabWidget::accept(IVisualizationWidgetVisitor *visitor)
160 172 {
161 173 if (visitor) {
162 174 visitor->visitEnter(this);
163 175
164 176 // Apply visitor to zone children: widgets different from zones are not visited (no action)
165 177 processZones(tabLayout(), [visitor](VisualizationZoneWidget &zoneWidget) {
166 178 zoneWidget.accept(visitor);
167 179 });
168 180
169 181 visitor->visitLeave(this);
170 182 }
171 183 else {
172 184 qCCritical(LOG_VisualizationTabWidget()) << tr("Can't visit widget : the visitor is null");
173 185 }
174 186 }
175 187
176 188 bool VisualizationTabWidget::canDrop(const Variable &variable) const
177 189 {
178 190 // A tab can always accomodate a variable
179 191 Q_UNUSED(variable);
180 192 return true;
181 193 }
182 194
183 195 bool VisualizationTabWidget::contains(const Variable &variable) const
184 196 {
185 197 Q_UNUSED(variable);
186 198 return false;
187 199 }
188 200
189 201 QString VisualizationTabWidget::name() const
190 202 {
191 203 return impl->m_Name;
192 204 }
193 205
194 206 void VisualizationTabWidget::closeEvent(QCloseEvent *event)
195 207 {
196 208 // Closes zones in the tab
197 209 processZones(tabLayout(), [](VisualizationZoneWidget &zoneWidget) { zoneWidget.close(); });
198 210
199 211 QWidget::closeEvent(event);
200 212 }
201 213
202 214 QLayout &VisualizationTabWidget::tabLayout() const noexcept
203 215 {
204 216 return *ui->dragDropContainer->layout();
205 217 }
206 218
207 219 void VisualizationTabWidget::dropMimeData(int index, const QMimeData *mimeData)
208 220 {
209 221 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
210 222 impl->dropGraph(index, this);
211 223 }
212 224 else if (mimeData->hasFormat(MIME_TYPE_ZONE)) {
213 225 impl->dropZone(index, this);
214 226 }
215 227 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
216 228 auto variables = sqpApp->variableController().variablesForMimeData(
217 229 mimeData->data(MIME_TYPE_VARIABLE_LIST));
218 230 impl->dropVariables(variables, index, this);
219 231 }
220 232 else {
221 233 qCWarning(LOG_VisualizationZoneWidget())
222 234 << tr("VisualizationTabWidget::dropMimeData, unknown MIME data received.");
223 235 }
224 236 }
225 237
226 238 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropGraph(
227 239 int index, VisualizationTabWidget *tabWidget)
228 240 {
229 241 auto &helper = sqpApp->dragDropGuiController();
230 242
231 243 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
232 244 if (!graphWidget) {
233 245 qCWarning(LOG_VisualizationZoneWidget())
234 246 << tr("VisualizationTabWidget::dropGraph, drop aborted, the dropped graph is not "
235 247 "found or invalid.");
236 248 Q_ASSERT(false);
237 249 return;
238 250 }
239 251
240 252 auto parentDragDropContainer
241 253 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
242 254 if (!parentDragDropContainer) {
243 255 qCWarning(LOG_VisualizationZoneWidget())
244 256 << tr("VisualizationTabWidget::dropGraph, drop aborted, the parent container of "
245 257 "the dropped graph is not found.");
246 258 Q_ASSERT(false);
247 259 return;
248 260 }
249 261
250 262 auto nbGraph = parentDragDropContainer->countDragWidget();
251 263
252 264 const auto &variables = graphWidget->variables();
253 265
254 266 if (!variables.isEmpty()) {
255 267 // Abort the requests for the variables (if any)
256 268 // Commented, because it's not sure if it's needed or not
257 269 // for (const auto& var : variables)
258 270 //{
259 271 // sqpApp->variableController().onAbortProgressRequested(var);
260 272 //}
261 273
262 274 if (nbGraph == 1) {
263 275 // This is the only graph in the previous zone, close the zone
264 276 helper.delayedCloseWidget(graphWidget->parentZoneWidget());
265 277 }
266 278 else {
267 279 // Close the graph
268 280 helper.delayedCloseWidget(graphWidget);
269 281 }
270 282
271 283 auto zoneWidget = tabWidget->createZone(variables, index);
272 284 auto firstGraph = zoneWidget->firstGraph();
273 285 if (firstGraph) {
274 286 firstGraph->addSelectionZones(graphWidget->selectionZoneRanges());
275 287 }
276 288 else {
277 289 qCWarning(LOG_VisualizationZoneWidget())
278 290 << tr("VisualizationTabWidget::dropGraph, no graph added in the widget.");
279 291 Q_ASSERT(false);
280 292 }
281 293 }
282 294 else {
283 295 // The graph is empty, create an empty zone and move the graph inside
284 296
285 297 auto parentZoneWidget = graphWidget->parentZoneWidget();
286 298
287 299 parentDragDropContainer->layout()->removeWidget(graphWidget);
288 300
289 301 auto zoneWidget = tabWidget->createEmptyZone(index);
290 302 zoneWidget->addGraph(graphWidget);
291 303
292 304 // Close the old zone if it was the only graph inside
293 305 if (nbGraph == 1) {
294 306 helper.delayedCloseWidget(parentZoneWidget);
295 307 }
296 308 }
297 309 }
298 310
299 311 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropZone(
300 312 int index, VisualizationTabWidget *tabWidget)
301 313 {
302 314 auto &helper = sqpApp->dragDropGuiController();
303 315
304 316 auto zoneWidget = qobject_cast<VisualizationZoneWidget *>(helper.getCurrentDragWidget());
305 317 if (!zoneWidget) {
306 318 qCWarning(LOG_VisualizationZoneWidget())
307 319 << tr("VisualizationTabWidget::dropZone, drop aborted, the dropped zone is not "
308 320 "found or invalid.");
309 321 Q_ASSERT(false);
310 322 return;
311 323 }
312 324
313 325 auto parentDragDropContainer
314 326 = qobject_cast<VisualizationDragDropContainer *>(zoneWidget->parentWidget());
315 327 if (!parentDragDropContainer) {
316 328 qCWarning(LOG_VisualizationZoneWidget())
317 329 << tr("VisualizationTabWidget::dropZone, drop aborted, the parent container of "
318 330 "the dropped zone is not found.");
319 331 Q_ASSERT(false);
320 332 return;
321 333 }
322 334
323 335 // Simple move of the zone, no variable operation associated
324 336 parentDragDropContainer->layout()->removeWidget(zoneWidget);
325 337 tabWidget->ui->dragDropContainer->insertDragWidget(index, zoneWidget);
326 338 }
327 339
328 340 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropVariables(
329 341 const QList<std::shared_ptr<Variable> > &variables, int index,
330 342 VisualizationTabWidget *tabWidget)
331 343 {
332 344 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
333 345 // compatible variable here
334 346 if (variables.count() > 1) {
335 347 qCWarning(LOG_VisualizationZoneWidget())
336 348 << tr("VisualizationTabWidget::dropVariables, dropping multiple variables, operation "
337 349 "aborted.");
338 350 return;
339 351 }
340 352
341 353 tabWidget->createZone(variables, index);
342 354 }
@@ -1,590 +1,601
1 1 #include "Visualization/VisualizationZoneWidget.h"
2 2
3 3 #include "Visualization/IVisualizationWidgetVisitor.h"
4 4 #include "Visualization/QCustomPlotSynchronizer.h"
5 5 #include "Visualization/VisualizationGraphWidget.h"
6 6 #include "Visualization/VisualizationWidget.h"
7 7 #include "ui_VisualizationZoneWidget.h"
8 8
9 9 #include "Common/MimeTypesDef.h"
10 10 #include "Common/VisualizationDef.h"
11 11
12 12 #include <Data/SqpRange.h>
13 13 #include <Time/TimeController.h>
14 14 #include <Variable/Variable.h>
15 15 #include <Variable/VariableController.h>
16 16
17 17 #include <Visualization/operations/FindVariableOperation.h>
18 18
19 19 #include <DragAndDrop/DragDropGuiController.h>
20 20 #include <QUuid>
21 21 #include <SqpApplication.h>
22 22 #include <cmath>
23 23
24 24 #include <QLayout>
25 25
26 26 Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget")
27 27
28 28 namespace {
29 29
30 30 /**
31 31 * Applies a function to all graphs of the zone represented by its layout
32 32 * @param layout the layout that contains graphs
33 33 * @param fun the function to apply to each graph
34 34 */
35 35 template <typename Fun>
36 36 void processGraphs(QLayout &layout, Fun fun)
37 37 {
38 38 for (auto i = 0; i < layout.count(); ++i) {
39 39 if (auto item = layout.itemAt(i)) {
40 40 if (auto visualizationGraphWidget
41 41 = qobject_cast<VisualizationGraphWidget *>(item->widget())) {
42 42 fun(*visualizationGraphWidget);
43 43 }
44 44 }
45 45 }
46 46 }
47 47
48 48 /// Generates a default name for a new graph, according to the number of graphs already displayed in
49 49 /// the zone
50 50 QString defaultGraphName(QLayout &layout)
51 51 {
52 52 QSet<QString> existingNames;
53 53 processGraphs(
54 54 layout, [&existingNames](auto &graphWidget) { existingNames.insert(graphWidget.name()); });
55 55
56 56 int zoneNum = 1;
57 57 QString name;
58 58 do {
59 59 name = QObject::tr("Graph ").append(QString::number(zoneNum));
60 60 ++zoneNum;
61 61 } while (existingNames.contains(name));
62 62
63 63 return name;
64 64 }
65 65
66 66 } // namespace
67 67
68 68 struct VisualizationZoneWidget::VisualizationZoneWidgetPrivate {
69 69
70 70 explicit VisualizationZoneWidgetPrivate()
71 71 : m_SynchronisationGroupId{QUuid::createUuid()},
72 72 m_Synchronizer{std::make_unique<QCustomPlotSynchronizer>()}
73 73 {
74 74 }
75 75 QUuid m_SynchronisationGroupId;
76 76 std::unique_ptr<IGraphSynchronizer> m_Synchronizer;
77 77
78 78 void dropGraph(int index, VisualizationZoneWidget *zoneWidget);
79 79 void dropVariables(const QList<std::shared_ptr<Variable> > &variables, int index,
80 80 VisualizationZoneWidget *zoneWidget);
81 81 };
82 82
83 83 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent)
84 84 : VisualizationDragWidget{parent},
85 85 ui{new Ui::VisualizationZoneWidget},
86 86 impl{spimpl::make_unique_impl<VisualizationZoneWidgetPrivate>()}
87 87 {
88 88 ui->setupUi(this);
89 89
90 90 ui->zoneNameLabel->setText(name);
91 91
92 92 ui->dragDropContainer->setPlaceHolderType(DragDropGuiController::PlaceHolderType::Graph);
93 93 ui->dragDropContainer->setMimeType(MIME_TYPE_GRAPH,
94 94 VisualizationDragDropContainer::DropBehavior::Inserted);
95 95 ui->dragDropContainer->setMimeType(
96 96 MIME_TYPE_VARIABLE_LIST, VisualizationDragDropContainer::DropBehavior::InsertedAndMerged);
97 97 ui->dragDropContainer->setMimeType(MIME_TYPE_TIME_RANGE,
98 98 VisualizationDragDropContainer::DropBehavior::Merged);
99 99 ui->dragDropContainer->setMimeType(MIME_TYPE_ZONE,
100 100 VisualizationDragDropContainer::DropBehavior::Forbidden);
101 101 ui->dragDropContainer->setMimeType(MIME_TYPE_SELECTION_ZONE,
102 102 VisualizationDragDropContainer::DropBehavior::Forbidden);
103 103 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
104 104 return sqpApp->dragDropGuiController().checkMimeDataForVisualization(mimeData,
105 105 ui->dragDropContainer);
106 106 });
107 107
108 108 auto acceptDragWidgetFun = [](auto dragWidget, auto mimeData) {
109 109 if (!mimeData) {
110 110 return false;
111 111 }
112 112
113 113 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
114 114 auto variables = sqpApp->variableController().variablesForMimeData(
115 115 mimeData->data(MIME_TYPE_VARIABLE_LIST));
116 116
117 117 if (variables.count() != 1) {
118 118 return false;
119 119 }
120 120 auto variable = variables.first();
121 121
122 122 if (auto graphWidget = dynamic_cast<const VisualizationGraphWidget *>(dragWidget)) {
123 123 return graphWidget->canDrop(*variable);
124 124 }
125 125 }
126 126
127 127 return true;
128 128 };
129 129 ui->dragDropContainer->setAcceptDragWidgetFunction(acceptDragWidgetFun);
130 130
131 131 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredInContainer, this,
132 132 &VisualizationZoneWidget::dropMimeData);
133 133 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredOnWidget, this,
134 134 &VisualizationZoneWidget::dropMimeDataOnGraph);
135 135
136 136 // 'Close' options : widget is deleted when closed
137 137 setAttribute(Qt::WA_DeleteOnClose);
138 138 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close);
139 139 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
140 140
141 141 // Synchronisation id
142 142 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronizationGroupId",
143 143 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
144 144 }
145 145
146 146 VisualizationZoneWidget::~VisualizationZoneWidget()
147 147 {
148 148 delete ui;
149 149 }
150 150
151 void VisualizationZoneWidget::setZoneRange(const SqpRange &range)
152 {
153 if (auto graph = firstGraph()) {
154 graph->setGraphRange(range);
155 }
156 else {
157 qCWarning(LOG_VisualizationZoneWidget())
158 << tr("setZoneRange:Cannot set the range of an empty zone.");
159 }
160 }
161
151 162 void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget)
152 163 {
153 164 // Synchronize new graph with others in the zone
154 165 impl->m_Synchronizer->addGraph(*graphWidget);
155 166
156 167 ui->dragDropContainer->addDragWidget(graphWidget);
157 168 }
158 169
159 170 void VisualizationZoneWidget::insertGraph(int index, VisualizationGraphWidget *graphWidget)
160 171 {
161 172 // Synchronize new graph with others in the zone
162 173 impl->m_Synchronizer->addGraph(*graphWidget);
163 174
164 175 ui->dragDropContainer->insertDragWidget(index, graphWidget);
165 176 }
166 177
167 178 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable)
168 179 {
169 180 return createGraph(variable, -1);
170 181 }
171 182
172 183 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable,
173 184 int index)
174 185 {
175 186 auto graphWidget
176 187 = new VisualizationGraphWidget{defaultGraphName(*ui->dragDropContainer->layout()), this};
177 188
178 189
179 190 // Set graph properties
180 191 graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
181 192 graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT);
182 193
183 194
184 195 // Lambda to synchronize zone widget
185 196 auto synchronizeZoneWidget = [this, graphWidget](const SqpRange &graphRange,
186 197 const SqpRange &oldGraphRange) {
187 198
188 199 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
189 200 auto frameLayout = ui->dragDropContainer->layout();
190 201 for (auto i = 0; i < frameLayout->count(); ++i) {
191 202 auto graphChild
192 203 = dynamic_cast<VisualizationGraphWidget *>(frameLayout->itemAt(i)->widget());
193 204 if (graphChild && (graphChild != graphWidget)) {
194 205
195 206 auto graphChildRange = graphChild->graphRange();
196 207 switch (zoomType) {
197 208 case AcquisitionZoomType::ZoomIn: {
198 209 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
199 210 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
200 211 graphChildRange.m_TStart += deltaLeft;
201 212 graphChildRange.m_TEnd -= deltaRight;
202 213 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomIn");
203 214 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
204 215 << deltaLeft;
205 216 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
206 217 << deltaRight;
207 218 qCDebug(LOG_VisualizationZoneWidget())
208 219 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
209 220
210 221 break;
211 222 }
212 223
213 224 case AcquisitionZoomType::ZoomOut: {
214 225 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomOut");
215 226 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
216 227 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
217 228 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
218 229 << deltaLeft;
219 230 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
220 231 << deltaRight;
221 232 qCDebug(LOG_VisualizationZoneWidget())
222 233 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
223 234 graphChildRange.m_TStart -= deltaLeft;
224 235 graphChildRange.m_TEnd += deltaRight;
225 236 break;
226 237 }
227 238 case AcquisitionZoomType::PanRight: {
228 239 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanRight");
229 240 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
230 241 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
231 242 graphChildRange.m_TStart += deltaLeft;
232 243 graphChildRange.m_TEnd += deltaRight;
233 244 qCDebug(LOG_VisualizationZoneWidget())
234 245 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
235 246 break;
236 247 }
237 248 case AcquisitionZoomType::PanLeft: {
238 249 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanLeft");
239 250 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
240 251 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
241 252 graphChildRange.m_TStart -= deltaLeft;
242 253 graphChildRange.m_TEnd -= deltaRight;
243 254 break;
244 255 }
245 256 case AcquisitionZoomType::Unknown: {
246 257 qCDebug(LOG_VisualizationZoneWidget())
247 258 << tr("Impossible to synchronize: zoom type unknown");
248 259 break;
249 260 }
250 261 default:
251 262 qCCritical(LOG_VisualizationZoneWidget())
252 263 << tr("Impossible to synchronize: zoom type not take into account");
253 264 // No action
254 265 break;
255 266 }
256 267 graphChild->enableAcquisition(false);
257 268 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range before: ")
258 269 << graphChild->graphRange();
259 270 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range after : ")
260 271 << graphChildRange;
261 272 qCDebug(LOG_VisualizationZoneWidget())
262 273 << tr("TORM: child dt") << graphChildRange.m_TEnd - graphChildRange.m_TStart;
263 274 graphChild->setGraphRange(graphChildRange);
264 275 graphChild->enableAcquisition(true);
265 276 }
266 277 }
267 278 };
268 279
269 280 // connection for synchronization
270 281 connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget);
271 282 connect(graphWidget, &VisualizationGraphWidget::variableAdded, this,
272 283 &VisualizationZoneWidget::onVariableAdded);
273 284 connect(graphWidget, &VisualizationGraphWidget::variableAboutToBeRemoved, this,
274 285 &VisualizationZoneWidget::onVariableAboutToBeRemoved);
275 286
276 287 auto range = SqpRange{};
277 288 if (auto firstGraph = this->firstGraph()) {
278 289 // Case of a new graph in a existant zone
279 290 range = firstGraph->graphRange();
280 291 }
281 292 else {
282 293 // Case of a new graph as the first of the zone
283 294 range = variable->range();
284 295 }
285 296
286 297 this->insertGraph(index, graphWidget);
287 298
288 299 graphWidget->addVariable(variable, range);
289 300 graphWidget->setYRange(variable);
290 301
291 302 return graphWidget;
292 303 }
293 304
294 305 VisualizationGraphWidget *
295 306 VisualizationZoneWidget::createGraph(const QList<std::shared_ptr<Variable> > variables, int index)
296 307 {
297 308 if (variables.isEmpty()) {
298 309 return nullptr;
299 310 }
300 311
301 312 auto graphWidget = createGraph(variables.first(), index);
302 313 for (auto variableIt = variables.cbegin() + 1; variableIt != variables.cend(); ++variableIt) {
303 314 graphWidget->addVariable(*variableIt, graphWidget->graphRange());
304 315 }
305 316
306 317 return graphWidget;
307 318 }
308 319
309 320 VisualizationGraphWidget *VisualizationZoneWidget::firstGraph() const
310 321 {
311 322 VisualizationGraphWidget *firstGraph = nullptr;
312 323 auto layout = ui->dragDropContainer->layout();
313 324 if (layout->count() > 0) {
314 325 if (auto visualizationGraphWidget
315 326 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
316 327 firstGraph = visualizationGraphWidget;
317 328 }
318 329 }
319 330
320 331 return firstGraph;
321 332 }
322 333
323 334 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
324 335 {
325 336 if (visitor) {
326 337 visitor->visitEnter(this);
327 338
328 339 // Apply visitor to graph children: widgets different from graphs are not visited (no
329 340 // action)
330 341 processGraphs(
331 342 *ui->dragDropContainer->layout(),
332 343 [visitor](VisualizationGraphWidget &graphWidget) { graphWidget.accept(visitor); });
333 344
334 345 visitor->visitLeave(this);
335 346 }
336 347 else {
337 348 qCCritical(LOG_VisualizationZoneWidget()) << tr("Can't visit widget : the visitor is null");
338 349 }
339 350 }
340 351
341 352 bool VisualizationZoneWidget::canDrop(const Variable &variable) const
342 353 {
343 354 // A tab can always accomodate a variable
344 355 Q_UNUSED(variable);
345 356 return true;
346 357 }
347 358
348 359 bool VisualizationZoneWidget::contains(const Variable &variable) const
349 360 {
350 361 Q_UNUSED(variable);
351 362 return false;
352 363 }
353 364
354 365 QString VisualizationZoneWidget::name() const
355 366 {
356 367 return ui->zoneNameLabel->text();
357 368 }
358 369
359 370 QMimeData *VisualizationZoneWidget::mimeData(const QPoint &position) const
360 371 {
361 372 Q_UNUSED(position);
362 373
363 374 auto mimeData = new QMimeData;
364 375 mimeData->setData(MIME_TYPE_ZONE, QByteArray{});
365 376
366 377 if (auto firstGraph = this->firstGraph()) {
367 378 auto timeRangeData = TimeController::mimeDataForTimeRange(firstGraph->graphRange());
368 379 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
369 380 }
370 381
371 382 return mimeData;
372 383 }
373 384
374 385 bool VisualizationZoneWidget::isDragAllowed() const
375 386 {
376 387 return true;
377 388 }
378 389
379 390 void VisualizationZoneWidget::notifyMouseMoveInGraph(const QPointF &graphPosition,
380 391 const QPointF &plotPosition,
381 392 VisualizationGraphWidget *graphWidget)
382 393 {
383 394 processGraphs(*ui->dragDropContainer->layout(), [&graphPosition, &plotPosition, &graphWidget](
384 395 VisualizationGraphWidget &processedGraph) {
385 396
386 397 switch (sqpApp->plotsCursorMode()) {
387 398 case SqpApplication::PlotsCursorMode::Vertical:
388 399 processedGraph.removeHorizontalCursor();
389 400 processedGraph.addVerticalCursorAtViewportPosition(graphPosition.x());
390 401 break;
391 402 case SqpApplication::PlotsCursorMode::Temporal:
392 403 processedGraph.addVerticalCursor(plotPosition.x());
393 404 processedGraph.removeHorizontalCursor();
394 405 break;
395 406 case SqpApplication::PlotsCursorMode::Horizontal:
396 407 processedGraph.removeVerticalCursor();
397 408 if (&processedGraph == graphWidget) {
398 409 processedGraph.addHorizontalCursorAtViewportPosition(graphPosition.y());
399 410 }
400 411 else {
401 412 processedGraph.removeHorizontalCursor();
402 413 }
403 414 break;
404 415 case SqpApplication::PlotsCursorMode::Cross:
405 416 if (&processedGraph == graphWidget) {
406 417 processedGraph.addVerticalCursorAtViewportPosition(graphPosition.x());
407 418 processedGraph.addHorizontalCursorAtViewportPosition(graphPosition.y());
408 419 }
409 420 else {
410 421 processedGraph.removeHorizontalCursor();
411 422 processedGraph.removeVerticalCursor();
412 423 }
413 424 break;
414 425 case SqpApplication::PlotsCursorMode::NoCursor:
415 426 processedGraph.removeHorizontalCursor();
416 427 processedGraph.removeVerticalCursor();
417 428 break;
418 429 }
419 430
420 431
421 432 });
422 433 }
423 434
424 435 void VisualizationZoneWidget::notifyMouseLeaveGraph(VisualizationGraphWidget *graphWidget)
425 436 {
426 437 processGraphs(*ui->dragDropContainer->layout(), [](VisualizationGraphWidget &processedGraph) {
427 438 processedGraph.removeHorizontalCursor();
428 439 processedGraph.removeVerticalCursor();
429 440 });
430 441 }
431 442
432 443 void VisualizationZoneWidget::closeEvent(QCloseEvent *event)
433 444 {
434 445 // Closes graphs in the zone
435 446 processGraphs(*ui->dragDropContainer->layout(),
436 447 [](VisualizationGraphWidget &graphWidget) { graphWidget.close(); });
437 448
438 449 // Delete synchronization group from variable controller
439 450 QMetaObject::invokeMethod(&sqpApp->variableController(), "onRemoveSynchronizationGroupId",
440 451 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
441 452
442 453 QWidget::closeEvent(event);
443 454 }
444 455
445 456 void VisualizationZoneWidget::onVariableAdded(std::shared_ptr<Variable> variable)
446 457 {
447 458 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronized",
448 459 Qt::QueuedConnection, Q_ARG(std::shared_ptr<Variable>, variable),
449 460 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
450 461 }
451 462
452 463 void VisualizationZoneWidget::onVariableAboutToBeRemoved(std::shared_ptr<Variable> variable)
453 464 {
454 465 QMetaObject::invokeMethod(&sqpApp->variableController(), "desynchronize", Qt::QueuedConnection,
455 466 Q_ARG(std::shared_ptr<Variable>, variable),
456 467 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
457 468 }
458 469
459 470 void VisualizationZoneWidget::dropMimeData(int index, const QMimeData *mimeData)
460 471 {
461 472 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
462 473 impl->dropGraph(index, this);
463 474 }
464 475 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
465 476 auto variables = sqpApp->variableController().variablesForMimeData(
466 477 mimeData->data(MIME_TYPE_VARIABLE_LIST));
467 478 impl->dropVariables(variables, index, this);
468 479 }
469 480 else {
470 481 qCWarning(LOG_VisualizationZoneWidget())
471 482 << tr("VisualizationZoneWidget::dropMimeData, unknown MIME data received.");
472 483 }
473 484 }
474 485
475 486 void VisualizationZoneWidget::dropMimeDataOnGraph(VisualizationDragWidget *dragWidget,
476 487 const QMimeData *mimeData)
477 488 {
478 489 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(dragWidget);
479 490 if (!graphWidget) {
480 491 qCWarning(LOG_VisualizationZoneWidget())
481 492 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, dropping in an unknown widget, "
482 493 "drop aborted");
483 494 Q_ASSERT(false);
484 495 return;
485 496 }
486 497
487 498 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
488 499 auto variables = sqpApp->variableController().variablesForMimeData(
489 500 mimeData->data(MIME_TYPE_VARIABLE_LIST));
490 501 for (const auto &var : variables) {
491 502 graphWidget->addVariable(var, graphWidget->graphRange());
492 503 }
493 504 }
494 505 else if (mimeData->hasFormat(MIME_TYPE_TIME_RANGE)) {
495 506 auto range = TimeController::timeRangeForMimeData(mimeData->data(MIME_TYPE_TIME_RANGE));
496 507 graphWidget->setGraphRange(range);
497 508 }
498 509 else {
499 510 qCWarning(LOG_VisualizationZoneWidget())
500 511 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, unknown MIME data received.");
501 512 }
502 513 }
503 514
504 515 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropGraph(
505 516 int index, VisualizationZoneWidget *zoneWidget)
506 517 {
507 518 auto &helper = sqpApp->dragDropGuiController();
508 519
509 520 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
510 521 if (!graphWidget) {
511 522 qCWarning(LOG_VisualizationZoneWidget())
512 523 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the dropped graph is not "
513 524 "found or invalid.");
514 525 Q_ASSERT(false);
515 526 return;
516 527 }
517 528
518 529 auto parentDragDropContainer
519 530 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
520 531 if (!parentDragDropContainer) {
521 532 qCWarning(LOG_VisualizationZoneWidget())
522 533 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the parent container of "
523 534 "the dropped graph is not found.");
524 535 Q_ASSERT(false);
525 536 return;
526 537 }
527 538
528 539 const auto &variables = graphWidget->variables();
529 540
530 541 if (parentDragDropContainer != zoneWidget->ui->dragDropContainer && !variables.isEmpty()) {
531 542 // The drop didn't occur in the same zone
532 543
533 544 // Abort the requests for the variables (if any)
534 545 // Commented, because it's not sure if it's needed or not
535 546 // for (const auto& var : variables)
536 547 //{
537 548 // sqpApp->variableController().onAbortProgressRequested(var);
538 549 //}
539 550
540 551 auto previousParentZoneWidget = graphWidget->parentZoneWidget();
541 552 auto nbGraph = parentDragDropContainer->countDragWidget();
542 553 if (nbGraph == 1) {
543 554 // This is the only graph in the previous zone, close the zone
544 555 helper.delayedCloseWidget(previousParentZoneWidget);
545 556 }
546 557 else {
547 558 // Close the graph
548 559 helper.delayedCloseWidget(graphWidget);
549 560 }
550 561
551 562 // Creates the new graph in the zone
552 563 auto newGraphWidget = zoneWidget->createGraph(variables, index);
553 564 newGraphWidget->addSelectionZones(graphWidget->selectionZoneRanges());
554 565 }
555 566 else {
556 567 // The drop occurred in the same zone or the graph is empty
557 568 // Simple move of the graph, no variable operation associated
558 569 parentDragDropContainer->layout()->removeWidget(graphWidget);
559 570
560 571 if (variables.isEmpty() && parentDragDropContainer != zoneWidget->ui->dragDropContainer) {
561 572 // The graph is empty and dropped in a different zone.
562 573 // Take the range of the first graph in the zone (if existing).
563 574 auto layout = zoneWidget->ui->dragDropContainer->layout();
564 575 if (layout->count() > 0) {
565 576 if (auto visualizationGraphWidget
566 577 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
567 578 graphWidget->setGraphRange(visualizationGraphWidget->graphRange());
568 579 }
569 580 }
570 581 }
571 582
572 583 zoneWidget->ui->dragDropContainer->insertDragWidget(index, graphWidget);
573 584 }
574 585 }
575 586
576 587 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropVariables(
577 588 const QList<std::shared_ptr<Variable> > &variables, int index,
578 589 VisualizationZoneWidget *zoneWidget)
579 590 {
580 591 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
581 592 // compatible variable here
582 593 if (variables.count() > 1) {
583 594 qCWarning(LOG_VisualizationZoneWidget())
584 595 << tr("VisualizationZoneWidget::dropVariables, dropping multiple variables, operation "
585 596 "aborted.");
586 597 return;
587 598 }
588 599
589 600 zoneWidget->createGraph(variables, index);
590 601 }
General Comments 0
You need to be logged in to leave comments. Login now