##// END OF EJS Templates
Drag of product
trabillard -
r868:86e05857e5c8
parent child
Show More
@@ -0,0 +1,14
1 #ifndef SCIQLOP_DATASOURCETREEWIDGET_H
2 #define SCIQLOP_DATASOURCETREEWIDGET_H
3
4 #include <QTreeWidget>
5
6 class DataSourceTreeWidget : public QTreeWidget {
7 public:
8 DataSourceTreeWidget(QWidget *parent);
9
10 protected:
11 QMimeData *mimeData(const QList<QTreeWidgetItem *> items) const override;
12 };
13
14 #endif // SCIQLOP_DATASOURCETREEWIDGET_H
@@ -0,0 +1,37
1 #include "DataSource/DataSourceTreeWidget.h"
2 #include "Common/MimeTypesDef.h"
3 #include "DataSource/DataSourceController.h"
4 #include "DataSource/DataSourceItem.h"
5 #include "DataSource/DataSourceTreeWidgetItem.h"
6
7 #include "SqpApplication.h"
8
9 #include <QMimeData>
10
11 DataSourceTreeWidget::DataSourceTreeWidget(QWidget *parent) : QTreeWidget(parent) {}
12
13 QMimeData *DataSourceTreeWidget::mimeData(const QList<QTreeWidgetItem *> items) const
14 {
15 auto mimeData = new QMimeData;
16
17 // Basic check to ensure the item are correctly typed
18 Q_ASSERT(items.isEmpty() || dynamic_cast<DataSourceTreeWidgetItem *>(items.first()) != nullptr);
19
20 QVariantList productData;
21
22 for (auto item : items) {
23 auto dataSourceTreeItem = static_cast<DataSourceTreeWidgetItem *>(item);
24 auto dataSource = dataSourceTreeItem->data();
25
26 if (dataSource->type() == DataSourceItemType::COMPONENT
27 || dataSource->type() == DataSourceItemType::PRODUCT) {
28 auto metaData = dataSource->data();
29 productData << metaData;
30 }
31 }
32
33 auto encodedData = sqpApp->dataSourceController().mimeDataForProductsData(productData);
34 mimeData->setData(MIME_TYPE_PRODUCT_LIST, encodedData);
35
36 return mimeData;
37 }
@@ -1,18 +1,19
1 1 #ifndef SCIQLOP_MIMETYPESDEF_H
2 2 #define SCIQLOP_MIMETYPESDEF_H
3 3
4 4 #include "CoreGlobal.h"
5 5
6 6 #include <QString>
7 7
8 8 // ////////////////// //
9 9 // SciQlop Mime Types //
10 10 // ////////////////// //
11 11
12 12 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_GRAPH;
13 13 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_ZONE;
14 14 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_VARIABLE_LIST;
15 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_PRODUCT_LIST;
15 16 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_TIME_RANGE;
16 17
17 18
18 19 #endif // SCIQLOP_MIMETYPESDEF_H
@@ -1,94 +1,97
1 1 #ifndef SCIQLOP_DATASOURCECONTROLLER_H
2 2 #define SCIQLOP_DATASOURCECONTROLLER_H
3 3
4 4 #include "CoreGlobal.h"
5 5
6 6 #include <QLoggingCategory>
7 7 #include <QObject>
8 8 #include <QUuid>
9 9
10 10 #include <Common/spimpl.h>
11 11
12 12 Q_DECLARE_LOGGING_CATEGORY(LOG_DataSourceController)
13 13
14 14 class DataSourceItem;
15 15 class IDataProvider;
16 16
17 17 /**
18 18 * @brief The DataSourceController class aims to make the link between SciQlop and its plugins. This
19 19 * is the intermediate class that SciQlop has to use in the way to connect a data source. Please
20 20 * first use register method to initialize a plugin specified by its metadata name (JSON plugin
21 21 * source) then others specifics method will be able to access it. You can load a data source driver
22 22 * plugin then create a data source.
23 23 */
24 24 class SCIQLOP_CORE_EXPORT DataSourceController : public QObject {
25 25 Q_OBJECT
26 26 public:
27 27 explicit DataSourceController(QObject *parent = 0);
28 28 virtual ~DataSourceController();
29 29
30 30 /**
31 31 * Registers a data source. The method delivers a unique id that can be used afterwards to
32 32 * access to the data source properties (structure, connection parameters, data provider, etc.)
33 33 * @param dataSourceName the name of the data source
34 34 * @return the unique id with which the data source has been registered
35 35 */
36 36 QUuid registerDataSource(const QString &dataSourceName) noexcept;
37 37
38 38 /**
39 39 * Sets the structure of a data source. The controller takes ownership of the structure.
40 40 * @param dataSourceUid the unique id with which the data source has been registered into the
41 41 * controller. If it is invalid, the method has no effect.
42 42 * @param dataSourceItem the structure of the data source. It must be not null to be registered
43 43 * @sa registerDataSource()
44 44 */
45 45 void setDataSourceItem(const QUuid &dataSourceUid,
46 46 std::unique_ptr<DataSourceItem> dataSourceItem) noexcept;
47 47
48 48 /**
49 49 * Sets the data provider used to retrieve data from of a data source. The controller takes
50 50 * ownership of the provider.
51 51 * @param dataSourceUid the unique id with which the data source has been registered into the
52 52 * controller. If it is invalid, the method has no effect.
53 53 * @param dataProvider the provider of the data source
54 54 * @sa registerDataSource()
55 55 */
56 56 void setDataProvider(const QUuid &dataSourceUid,
57 57 std::unique_ptr<IDataProvider> dataProvider) noexcept;
58 58
59 59 /**
60 60 * Loads an item (product) as a variable in SciQlop
61 61 * @param dataSourceUid the unique id of the data source containing the item. It is used to get
62 62 * the data provider associated to the data source, and pass it to for the variable creation
63 63 * @param productItem the item to load
64 64 */
65 65 void loadProductItem(const QUuid &dataSourceUid, const DataSourceItem &productItem) noexcept;
66 66
67 QByteArray mimeDataForProductsData(const QVariantList &productsData) const;
68 QVariantList productsDataForMimeData(const QByteArray &mimeData) const;
69
67 70 public slots:
68 71 /// Manage init/end of the controller
69 72 void initialize();
70 73 void finalize();
71 74
72 75 signals:
73 76 /// Signal emitted when a structure has been set for a data source
74 77 void dataSourceItemSet(DataSourceItem *dataSourceItem);
75 78
76 79 /**
77 80 * Signal emitted when a variable creation is asked for a product
78 81 * @param variableName the name of the variable
79 82 * @param variableMetadata the metadata of the variable
80 83 * @param variableProvider the provider that will be used to retrieve the data of the variable
81 84 * (can be null)
82 85 */
83 86 void variableCreationRequested(const QString &variableName,
84 87 const QVariantHash &variableMetadata,
85 88 std::shared_ptr<IDataProvider> variableProvider);
86 89
87 90 private:
88 91 void waitForFinish();
89 92
90 93 class DataSourceControllerPrivate;
91 94 spimpl::unique_impl_ptr<DataSourceControllerPrivate> impl;
92 95 };
93 96
94 97 #endif // SCIQLOP_DATASOURCECONTROLLER_H
@@ -1,65 +1,67
1 1
2 2 core_moc_headers = [
3 3 'include/Data/IDataProvider.h',
4 4 'include/DataSource/DataSourceController.h',
5 5 'include/DataSource/DataSourceItemAction.h',
6 'include/DataSource/DataSourceWidget.h',
6 7 'include/Network/NetworkController.h',
7 8 'include/Time/TimeController.h',
8 9 'include/Variable/Variable.h',
9 10 'include/Variable/VariableCacheController.h',
10 11 'include/Variable/VariableController.h',
11 12 'include/Variable/VariableAcquisitionWorker.h',
12 13 'include/Variable/VariableCacheStrategy.h',
13 14 'include/Variable/VariableSynchronizationGroup.h',
14 15 'include/Variable/VariableModel.h',
15 16 'include/Visualization/VisualizationController.h'
16 17 ]
17 18
18 19
19 20 core_moc_files = qt5.preprocess(moc_headers : core_moc_headers)
20 21
21 22 core_sources = [
22 23 'src/Common/DateUtils.cpp',
23 24 'src/Common/StringUtils.cpp',
24 25 'src/Common/MimeTypesDef.cpp',
25 26 'src/Data/ScalarSeries.cpp',
26 27 'src/Data/SpectrogramSeries.cpp',
27 28 'src/Data/DataSeriesIterator.cpp',
28 29 'src/Data/ArrayDataIterator.cpp',
29 30 'src/Data/VectorSeries.cpp',
30 31 'src/Data/OptionalAxis.cpp',
31 32 'src/DataSource/DataSourceController.cpp',
32 33 'src/DataSource/DataSourceItem.cpp',
33 34 'src/DataSource/DataSourceItemAction.cpp',
35 'src/DataSource/DataSourceWidget.cpp',
34 36 'src/Network/NetworkController.cpp',
35 37 'src/Plugin/PluginManager.cpp',
36 38 'src/Settings/SqpSettingsDefs.cpp',
37 39 'src/Time/TimeController.cpp',
38 40 'src/Variable/Variable.cpp',
39 41 'src/Variable/VariableCacheController.cpp',
40 42 'src/Variable/VariableController.cpp',
41 43 'src/Variable/VariableAcquisitionWorker.cpp',
42 44 'src/Variable/VariableSynchronizationGroup.cpp',
43 45 'src/Variable/VariableModel.cpp',
44 46 'src/Visualization/VisualizationController.cpp'
45 47 ]
46 48
47 49 core_inc = include_directories(['include', '../plugin/include'])
48 50
49 51 sciqlop_core_lib = library('sciqlopcore',
50 52 core_sources,
51 53 core_moc_files,
52 54 cpp_args : '-DCORE_LIB',
53 55 include_directories : core_inc,
54 56 dependencies : [qt5core, qt5network],
55 57 install : true
56 58 )
57 59
58 60
59 61 sciqlop_core = declare_dependency(link_with : sciqlop_core_lib,
60 62 include_directories : core_inc,
61 63 dependencies : [qt5core, qt5network])
62 64
63 65
64 66 subdir('tests')
65 67
@@ -1,6 +1,7
1 1 #include "Common/MimeTypesDef.h"
2 2
3 const QString MIME_TYPE_GRAPH = QStringLiteral("scqlop/graph");
4 const QString MIME_TYPE_ZONE = QStringLiteral("scqlop/zone");
5 const QString MIME_TYPE_VARIABLE_LIST = QStringLiteral("scqlop/var-list");
6 const QString MIME_TYPE_TIME_RANGE = QStringLiteral("scqlop/time-range");
3 const QString MIME_TYPE_GRAPH = QStringLiteral("sciqlop/graph");
4 const QString MIME_TYPE_ZONE = QStringLiteral("sciqlop/zone");
5 const QString MIME_TYPE_VARIABLE_LIST = QStringLiteral("sciqlop/var-list");
6 const QString MIME_TYPE_PRODUCT_LIST = QStringLiteral("sciqlop/product-list");
7 const QString MIME_TYPE_TIME_RANGE = QStringLiteral("sciqlop/time-range");
@@ -1,143 +1,163
1 1 #include "DataSource/DataSourceController.h"
2 2 #include "DataSource/DataSourceItem.h"
3 3
4 4 #include <Data/IDataProvider.h>
5 5
6 6 #include <QMutex>
7 7 #include <QThread>
8 8
9 9 #include <QDir>
10 10 #include <QStandardPaths>
11 11
12 12 Q_LOGGING_CATEGORY(LOG_DataSourceController, "DataSourceController")
13 13
14 14 namespace {
15 15
16 16 /**
17 17 * Builds the metadata of the variable that will be generated from the loading of an item
18 18 * @param dataSourceItem the data source item from which to generate the metadata
19 19 * @return the metadata of the variable
20 20 */
21 21 QVariantHash variableMetadata(const DataSourceItem &dataSourceItem)
22 22 {
23 23 // Variable metadata contains...
24 24
25 25 // ... all metadata of the item
26 26 auto result = dataSourceItem.data();
27 27
28 28 // ... and the name of the plugin, recovered from root item
29 29 result.insert(QStringLiteral("plugin"), dataSourceItem.rootItem().name());
30 30
31 31 return result;
32 32 }
33 33
34 34 } // namespace
35 35
36 36 class DataSourceController::DataSourceControllerPrivate {
37 37 public:
38 38 QMutex m_WorkingMutex;
39 39 /// Data sources registered
40 40 QHash<QUuid, QString> m_DataSources;
41 41 /// Data sources structures
42 42 std::map<QUuid, std::unique_ptr<DataSourceItem> > m_DataSourceItems;
43 43 /// Data providers registered
44 44 /// @remarks Data providers are stored as shared_ptr as they can be sent to a variable and
45 45 /// continue to live without necessarily the data source controller
46 46 std::map<QUuid, std::shared_ptr<IDataProvider> > m_DataProviders;
47 47 };
48 48
49 49 DataSourceController::DataSourceController(QObject *parent)
50 50 : impl{spimpl::make_unique_impl<DataSourceControllerPrivate>()}
51 51 {
52 52 qCDebug(LOG_DataSourceController()) << tr("DataSourceController construction")
53 53 << QThread::currentThread();
54 54 }
55 55
56 56 DataSourceController::~DataSourceController()
57 57 {
58 58 qCDebug(LOG_DataSourceController()) << tr("DataSourceController destruction")
59 59 << QThread::currentThread();
60 60 this->waitForFinish();
61 61 }
62 62
63 63 QUuid DataSourceController::registerDataSource(const QString &dataSourceName) noexcept
64 64 {
65 65 auto dataSourceUid = QUuid::createUuid();
66 66 impl->m_DataSources.insert(dataSourceUid, dataSourceName);
67 67
68 68 return dataSourceUid;
69 69 }
70 70
71 71 void DataSourceController::setDataSourceItem(
72 72 const QUuid &dataSourceUid, std::unique_ptr<DataSourceItem> dataSourceItem) noexcept
73 73 {
74 74 if (!dataSourceItem) {
75 75 qCWarning(LOG_DataSourceController())
76 76 << tr("Data source item can't be registered (null item)");
77 77 return;
78 78 }
79 79
80 80 if (impl->m_DataSources.contains(dataSourceUid)) {
81 81 // The data provider is implicitly converted to a shared_ptr
82 82 impl->m_DataSourceItems.insert(std::make_pair(dataSourceUid, std::move(dataSourceItem)));
83 83
84 84 // Retrieves the data source item to emit the signal with it
85 85 auto it = impl->m_DataSourceItems.find(dataSourceUid);
86 86 if (it != impl->m_DataSourceItems.end()) {
87 87 emit dataSourceItemSet(it->second.get());
88 88 }
89 89 }
90 90 else {
91 91 qCWarning(LOG_DataSourceController()) << tr("Can't set data source item for uid %1 : no "
92 92 "data source has been registered with the uid")
93 93 .arg(dataSourceUid.toString());
94 94 }
95 95 }
96 96
97 97 void DataSourceController::setDataProvider(const QUuid &dataSourceUid,
98 98 std::unique_ptr<IDataProvider> dataProvider) noexcept
99 99 {
100 100 if (impl->m_DataSources.contains(dataSourceUid)) {
101 101 impl->m_DataProviders.insert(std::make_pair(dataSourceUid, std::move(dataProvider)));
102 102 }
103 103 else {
104 104 qCWarning(LOG_DataSourceController()) << tr("Can't set data provider for uid %1 : no data "
105 105 "source has been registered with the uid")
106 106 .arg(dataSourceUid.toString());
107 107 }
108 108 }
109 109
110 110 void DataSourceController::loadProductItem(const QUuid &dataSourceUid,
111 111 const DataSourceItem &productItem) noexcept
112 112 {
113 113 if (productItem.type() == DataSourceItemType::PRODUCT
114 114 || productItem.type() == DataSourceItemType::COMPONENT) {
115 115 /// Retrieves the data provider of the data source (if any)
116 116 auto it = impl->m_DataProviders.find(dataSourceUid);
117 117 auto dataProvider = (it != impl->m_DataProviders.end()) ? it->second : nullptr;
118 118
119 119 emit variableCreationRequested(productItem.name(), variableMetadata(productItem),
120 120 dataProvider);
121 121 }
122 122 else {
123 123 qCWarning(LOG_DataSourceController()) << tr("Can't load an item that is not a product");
124 124 }
125 125 }
126 126
127 QByteArray DataSourceController::mimeDataForProductsData(const QVariantList &productsData) const
128 {
129 QByteArray encodedData;
130 QDataStream stream{&encodedData, QIODevice::WriteOnly};
131
132 stream << productsData;
133
134 return encodedData;
135 }
136
137 QVariantList DataSourceController::productsDataForMimeData(const QByteArray &mimeData) const
138 {
139 QDataStream stream{mimeData};
140
141 QVariantList productList;
142 stream >> productList;
143
144 return productList;
145 }
146
127 147 void DataSourceController::initialize()
128 148 {
129 149 qCDebug(LOG_DataSourceController()) << tr("DataSourceController init")
130 150 << QThread::currentThread();
131 151 impl->m_WorkingMutex.lock();
132 152 qCDebug(LOG_DataSourceController()) << tr("DataSourceController init END");
133 153 }
134 154
135 155 void DataSourceController::finalize()
136 156 {
137 157 impl->m_WorkingMutex.unlock();
138 158 }
139 159
140 160 void DataSourceController::waitForFinish()
141 161 {
142 162 QMutexLocker locker{&impl->m_WorkingMutex};
143 163 }
@@ -1,1053 +1,1053
1 1 #include <Variable/Variable.h>
2 2 #include <Variable/VariableAcquisitionWorker.h>
3 3 #include <Variable/VariableCacheStrategy.h>
4 4 #include <Variable/VariableCacheStrategyFactory.h>
5 5 #include <Variable/VariableController.h>
6 6 #include <Variable/VariableModel.h>
7 7 #include <Variable/VariableSynchronizationGroup.h>
8 8
9 9 #include <Data/DataProviderParameters.h>
10 10 #include <Data/IDataProvider.h>
11 11 #include <Data/IDataSeries.h>
12 12 #include <Data/VariableRequest.h>
13 13 #include <Time/TimeController.h>
14 14
15 15 #include <QDataStream>
16 16 #include <QMutex>
17 17 #include <QThread>
18 18 #include <QUuid>
19 19 #include <QtCore/QItemSelectionModel>
20 20
21 21 #include <deque>
22 22 #include <set>
23 23 #include <unordered_map>
24 24
25 25 Q_LOGGING_CATEGORY(LOG_VariableController, "VariableController")
26 26
27 27 namespace {
28 28
29 29 SqpRange computeSynchroRangeRequested(const SqpRange &varRange, const SqpRange &graphRange,
30 30 const SqpRange &oldGraphRange)
31 31 {
32 32 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
33 33
34 34 auto varRangeRequested = varRange;
35 35 switch (zoomType) {
36 36 case AcquisitionZoomType::ZoomIn: {
37 37 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
38 38 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
39 39 varRangeRequested.m_TStart += deltaLeft;
40 40 varRangeRequested.m_TEnd -= deltaRight;
41 41 break;
42 42 }
43 43
44 44 case AcquisitionZoomType::ZoomOut: {
45 45 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
46 46 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
47 47 varRangeRequested.m_TStart -= deltaLeft;
48 48 varRangeRequested.m_TEnd += deltaRight;
49 49 break;
50 50 }
51 51 case AcquisitionZoomType::PanRight: {
52 52 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
53 53 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
54 54 varRangeRequested.m_TStart += deltaLeft;
55 55 varRangeRequested.m_TEnd += deltaRight;
56 56 break;
57 57 }
58 58 case AcquisitionZoomType::PanLeft: {
59 59 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
60 60 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
61 61 varRangeRequested.m_TStart -= deltaLeft;
62 62 varRangeRequested.m_TEnd -= deltaRight;
63 63 break;
64 64 }
65 65 case AcquisitionZoomType::Unknown: {
66 66 qCCritical(LOG_VariableController())
67 67 << VariableController::tr("Impossible to synchronize: zoom type unknown");
68 68 break;
69 69 }
70 70 default:
71 71 qCCritical(LOG_VariableController()) << VariableController::tr(
72 72 "Impossible to synchronize: zoom type not take into account");
73 73 // No action
74 74 break;
75 75 }
76 76
77 77 return varRangeRequested;
78 78 }
79 79 }
80 80
81 81 enum class VariableRequestHandlerState { OFF, RUNNING, PENDING };
82 82
83 83 struct VariableRequestHandler {
84 84
85 85 VariableRequestHandler()
86 86 {
87 87 m_CanUpdate = false;
88 88 m_State = VariableRequestHandlerState::OFF;
89 89 }
90 90
91 91 QUuid m_VarId;
92 92 VariableRequest m_RunningVarRequest;
93 93 VariableRequest m_PendingVarRequest;
94 94 VariableRequestHandlerState m_State;
95 95 bool m_CanUpdate;
96 96 };
97 97
98 98 struct VariableController::VariableControllerPrivate {
99 99 explicit VariableControllerPrivate(VariableController *parent)
100 100 : m_WorkingMutex{},
101 101 m_VariableModel{new VariableModel{parent}},
102 102 m_VariableSelectionModel{new QItemSelectionModel{m_VariableModel, parent}},
103 103 // m_VariableCacheStrategy{std::make_unique<VariableCacheStrategy>()},
104 104 m_VariableCacheStrategy{VariableCacheStrategyFactory::createCacheStrategy(
105 105 CacheStrategy::SingleThreshold)},
106 106 m_VariableAcquisitionWorker{std::make_unique<VariableAcquisitionWorker>()},
107 107 q{parent}
108 108 {
109 109
110 110 m_VariableAcquisitionWorker->moveToThread(&m_VariableAcquisitionWorkerThread);
111 111 m_VariableAcquisitionWorkerThread.setObjectName("VariableAcquisitionWorkerThread");
112 112 }
113 113
114 114
115 115 virtual ~VariableControllerPrivate()
116 116 {
117 117 qCDebug(LOG_VariableController()) << tr("VariableControllerPrivate destruction");
118 118 m_VariableAcquisitionWorkerThread.quit();
119 119 m_VariableAcquisitionWorkerThread.wait();
120 120 }
121 121
122 122
123 123 void processRequest(std::shared_ptr<Variable> var, const SqpRange &rangeRequested,
124 124 QUuid varRequestId);
125 125
126 126 std::shared_ptr<Variable> findVariable(QUuid vIdentifier);
127 127 std::shared_ptr<IDataSeries>
128 128 retrieveDataSeries(const QVector<AcquisitionDataPacket> acqDataPacketVector);
129 129
130 130 void registerProvider(std::shared_ptr<IDataProvider> provider);
131 131
132 132 void storeVariableRequest(QUuid varId, QUuid varRequestId, const VariableRequest &varRequest);
133 133 QUuid acceptVariableRequest(QUuid varId, std::shared_ptr<IDataSeries> dataSeries);
134 134 void updateVariables(QUuid varRequestId);
135 135 void updateVariableRequest(QUuid varRequestId);
136 136 void cancelVariableRequest(QUuid varRequestId);
137 137 void executeVarRequest(std::shared_ptr<Variable> var, VariableRequest &varRequest);
138 138
139 139 QMutex m_WorkingMutex;
140 140 /// Variable model. The VariableController has the ownership
141 141 VariableModel *m_VariableModel;
142 142 QItemSelectionModel *m_VariableSelectionModel;
143 143
144 144
145 145 TimeController *m_TimeController{nullptr};
146 146 std::unique_ptr<VariableCacheStrategy> m_VariableCacheStrategy;
147 147 std::unique_ptr<VariableAcquisitionWorker> m_VariableAcquisitionWorker;
148 148 QThread m_VariableAcquisitionWorkerThread;
149 149
150 150 std::unordered_map<std::shared_ptr<Variable>, std::shared_ptr<IDataProvider> >
151 151 m_VariableToProviderMap;
152 152 std::unordered_map<std::shared_ptr<Variable>, QUuid> m_VariableToIdentifierMap;
153 153 std::map<QUuid, std::shared_ptr<VariableSynchronizationGroup> >
154 154 m_GroupIdToVariableSynchronizationGroupMap;
155 155 std::map<QUuid, QUuid> m_VariableIdGroupIdMap;
156 156 std::set<std::shared_ptr<IDataProvider> > m_ProviderSet;
157 157
158 158 std::map<QUuid, std::list<QUuid> > m_VarGroupIdToVarIds;
159 159 std::map<QUuid, std::unique_ptr<VariableRequestHandler> > m_VarIdToVarRequestHandler;
160 160
161 161 VariableController *q;
162 162 };
163 163
164 164
165 165 VariableController::VariableController(QObject *parent)
166 166 : QObject{parent}, impl{spimpl::make_unique_impl<VariableControllerPrivate>(this)}
167 167 {
168 168 qCDebug(LOG_VariableController()) << tr("VariableController construction")
169 169 << QThread::currentThread();
170 170
171 171 connect(impl->m_VariableModel, &VariableModel::abortProgessRequested, this,
172 172 &VariableController::onAbortProgressRequested);
173 173
174 174 connect(impl->m_VariableAcquisitionWorker.get(),
175 175 &VariableAcquisitionWorker::variableCanceledRequested, this,
176 176 &VariableController::onAbortAcquisitionRequested);
177 177
178 178 connect(impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::dataProvided, this,
179 179 &VariableController::onDataProvided);
180 180 connect(impl->m_VariableAcquisitionWorker.get(),
181 181 &VariableAcquisitionWorker::variableRequestInProgress, this,
182 182 &VariableController::onVariableRetrieveDataInProgress);
183 183
184 184
185 185 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::started,
186 186 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::initialize);
187 187 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::finished,
188 188 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::finalize);
189 189
190 190
191 191 impl->m_VariableAcquisitionWorkerThread.start();
192 192 }
193 193
194 194 VariableController::~VariableController()
195 195 {
196 196 qCDebug(LOG_VariableController()) << tr("VariableController destruction")
197 197 << QThread::currentThread();
198 198 this->waitForFinish();
199 199 }
200 200
201 201 VariableModel *VariableController::variableModel() noexcept
202 202 {
203 203 return impl->m_VariableModel;
204 204 }
205 205
206 206 QItemSelectionModel *VariableController::variableSelectionModel() noexcept
207 207 {
208 208 return impl->m_VariableSelectionModel;
209 209 }
210 210
211 211 void VariableController::setTimeController(TimeController *timeController) noexcept
212 212 {
213 213 impl->m_TimeController = timeController;
214 214 }
215 215
216 216 std::shared_ptr<Variable>
217 217 VariableController::cloneVariable(std::shared_ptr<Variable> variable) noexcept
218 218 {
219 219 if (impl->m_VariableModel->containsVariable(variable)) {
220 220 // Clones variable
221 221 auto duplicate = variable->clone();
222 222
223 223 // Adds clone to model
224 224 impl->m_VariableModel->addVariable(duplicate);
225 225
226 226 // Generates clone identifier
227 227 impl->m_VariableToIdentifierMap[duplicate] = QUuid::createUuid();
228 228
229 229 // Registers provider
230 230 auto variableProvider = impl->m_VariableToProviderMap.at(variable);
231 231 auto duplicateProvider = variableProvider != nullptr ? variableProvider->clone() : nullptr;
232 232
233 233 impl->m_VariableToProviderMap[duplicate] = duplicateProvider;
234 234 if (duplicateProvider) {
235 235 impl->registerProvider(duplicateProvider);
236 236 }
237 237
238 238 return duplicate;
239 239 }
240 240 else {
241 241 qCCritical(LOG_VariableController())
242 242 << tr("Can't create duplicate of variable %1: variable not registered in the model")
243 243 .arg(variable->name());
244 244 return nullptr;
245 245 }
246 246 }
247 247
248 248 void VariableController::deleteVariable(std::shared_ptr<Variable> variable) noexcept
249 249 {
250 250 if (!variable) {
251 251 qCCritical(LOG_VariableController()) << "Can't delete variable: variable is null";
252 252 return;
253 253 }
254 254
255 255 // Spreads in SciQlop that the variable will be deleted, so that potential receivers can
256 256 // make some treatments before the deletion
257 257 emit variableAboutToBeDeleted(variable);
258 258
259 259 // Deletes identifier
260 260 impl->m_VariableToIdentifierMap.erase(variable);
261 261
262 262 // Deletes provider
263 263 auto nbProvidersDeleted = impl->m_VariableToProviderMap.erase(variable);
264 264 qCDebug(LOG_VariableController())
265 265 << tr("Number of providers deleted for variable %1: %2")
266 266 .arg(variable->name(), QString::number(nbProvidersDeleted));
267 267
268 268
269 269 // Deletes from model
270 270 impl->m_VariableModel->deleteVariable(variable);
271 271 }
272 272
273 273 void VariableController::deleteVariables(
274 274 const QVector<std::shared_ptr<Variable> > &variables) noexcept
275 275 {
276 276 for (auto variable : qAsConst(variables)) {
277 277 deleteVariable(variable);
278 278 }
279 279 }
280 280
281 281 QByteArray
282 282 VariableController::mimeDataForVariables(const QList<std::shared_ptr<Variable> > &variables) const
283 283 {
284 284 auto encodedData = QByteArray{};
285 285
286 286 QVariantList ids;
287 287 for (auto &var : variables) {
288 288 auto itVar = impl->m_VariableToIdentifierMap.find(var);
289 289 if (itVar == impl->m_VariableToIdentifierMap.cend()) {
290 290 qCCritical(LOG_VariableController())
291 291 << tr("Impossible to find the data for an unknown variable.");
292 292 }
293 293
294 294 ids << itVar->second.toByteArray();
295 295 }
296 296
297 297 QDataStream stream{&encodedData, QIODevice::WriteOnly};
298 298 stream << ids;
299 299
300 300 return encodedData;
301 301 }
302 302
303 303 QList<std::shared_ptr<Variable> >
304 304 VariableController::variablesForMimeData(const QByteArray &mimeData) const
305 305 {
306 306 auto variables = QList<std::shared_ptr<Variable> >{};
307 307 QDataStream stream{mimeData};
308 308
309 309 QVariantList ids;
310 310 stream >> ids;
311 311
312 312 for (auto id : ids) {
313 auto uuid = QUuid(id.toByteArray());
313 auto uuid = QUuid{id.toByteArray()};
314 314 auto var = impl->findVariable(uuid);
315 315 variables << var;
316 316 }
317 317
318 318 return variables;
319 319 }
320 320
321 321 std::shared_ptr<Variable>
322 322 VariableController::createVariable(const QString &name, const QVariantHash &metadata,
323 323 std::shared_ptr<IDataProvider> provider) noexcept
324 324 {
325 325 if (!impl->m_TimeController) {
326 326 qCCritical(LOG_VariableController())
327 327 << tr("Impossible to create variable: The time controller is null");
328 328 return nullptr;
329 329 }
330 330
331 331 auto range = impl->m_TimeController->dateTime();
332 332
333 333 if (auto newVariable = impl->m_VariableModel->createVariable(name, metadata)) {
334 334 auto varId = QUuid::createUuid();
335 335
336 336 // Create the handler
337 337 auto varRequestHandler = std::make_unique<VariableRequestHandler>();
338 338 varRequestHandler->m_VarId = varId;
339 339
340 340 impl->m_VarIdToVarRequestHandler.insert(
341 341 std::make_pair(varId, std::move(varRequestHandler)));
342 342
343 343 // store the provider
344 344 impl->registerProvider(provider);
345 345
346 346 // Associate the provider
347 347 impl->m_VariableToProviderMap[newVariable] = provider;
348 348 impl->m_VariableToIdentifierMap[newVariable] = varId;
349 349
350 350 this->onRequestDataLoading(QVector<std::shared_ptr<Variable> >{newVariable}, range, false);
351 351
352 352 // auto varRequestId = QUuid::createUuid();
353 353 // qCInfo(LOG_VariableController()) << "createVariable: " << varId << varRequestId;
354 354 // impl->processRequest(newVariable, range, varRequestId);
355 355 // impl->updateVariableRequest(varRequestId);
356 356
357 357 return newVariable;
358 358 }
359 359 }
360 360
361 361 void VariableController::onDateTimeOnSelection(const SqpRange &dateTime)
362 362 {
363 363 // NOTE: Even if acquisition request is aborting, the graphe range will be changed
364 364 qCDebug(LOG_VariableController()) << "VariableController::onDateTimeOnSelection"
365 365 << QThread::currentThread()->objectName();
366 366 auto selectedRows = impl->m_VariableSelectionModel->selectedRows();
367 367
368 368 // NOTE we only permit the time modification for one variable
369 369 // DEPRECATED
370 370 // auto variables = QVector<std::shared_ptr<Variable> >{};
371 371 // for (const auto &selectedRow : qAsConst(selectedRows)) {
372 372 // if (auto selectedVariable =
373 373 // impl->m_VariableModel->variable(selectedRow.row())) {
374 374 // variables << selectedVariable;
375 375
376 376 // // notify that rescale operation has to be done
377 377 // emit rangeChanged(selectedVariable, dateTime);
378 378 // }
379 379 // }
380 380 // if (!variables.isEmpty()) {
381 381 // this->onRequestDataLoading(variables, dateTime, synchro);
382 382 // }
383 383 if (selectedRows.size() == 1) {
384 384
385 385 if (auto selectedVariable
386 386 = impl->m_VariableModel->variable(qAsConst(selectedRows).first().row())) {
387 387
388 388 auto itVar = impl->m_VariableToIdentifierMap.find(selectedVariable);
389 389 if (itVar == impl->m_VariableToIdentifierMap.cend()) {
390 390 qCCritical(LOG_VariableController())
391 391 << tr("Impossible to onDateTimeOnSelection request for unknown variable");
392 392 return;
393 393 }
394 394
395 395 // notify that rescale operation has to be done
396 396 emit rangeChanged(selectedVariable, dateTime);
397 397
398 398 auto synchro = impl->m_VariableIdGroupIdMap.find(itVar->second)
399 399 != impl->m_VariableIdGroupIdMap.cend();
400 400
401 401 this->onRequestDataLoading(QVector<std::shared_ptr<Variable> >{selectedVariable},
402 402 dateTime, synchro);
403 403 }
404 404 }
405 405 else if (selectedRows.size() > 1) {
406 406 qCCritical(LOG_VariableController())
407 407 << tr("Impossible to set time for more than 1 variable in the same time");
408 408 }
409 409 else {
410 410 qCWarning(LOG_VariableController())
411 411 << tr("There is no variable selected to set the time one");
412 412 }
413 413 }
414 414
415 415 void VariableController::onDataProvided(QUuid vIdentifier, const SqpRange &rangeRequested,
416 416 const SqpRange &cacheRangeRequested,
417 417 QVector<AcquisitionDataPacket> dataAcquired)
418 418 {
419 419 qCDebug(LOG_VariableController()) << tr("onDataProvided") << QThread::currentThread();
420 420 auto retrievedDataSeries = impl->retrieveDataSeries(dataAcquired);
421 421 auto varRequestId = impl->acceptVariableRequest(vIdentifier, retrievedDataSeries);
422 422 if (!varRequestId.isNull()) {
423 423 impl->updateVariables(varRequestId);
424 424 }
425 425 }
426 426
427 427 void VariableController::onVariableRetrieveDataInProgress(QUuid identifier, double progress)
428 428 {
429 429 qCDebug(LOG_VariableController())
430 430 << "TORM: variableController::onVariableRetrieveDataInProgress"
431 431 << QThread::currentThread()->objectName() << progress;
432 432 if (auto var = impl->findVariable(identifier)) {
433 433 impl->m_VariableModel->setDataProgress(var, progress);
434 434 }
435 435 else {
436 436 qCCritical(LOG_VariableController())
437 437 << tr("Impossible to notify progression of a null variable");
438 438 }
439 439 }
440 440
441 441 void VariableController::onAbortProgressRequested(std::shared_ptr<Variable> variable)
442 442 {
443 443 qCDebug(LOG_VariableController()) << "TORM: variableController::onAbortProgressRequested"
444 444 << QThread::currentThread()->objectName() << variable->name();
445 445
446 446 auto itVar = impl->m_VariableToIdentifierMap.find(variable);
447 447 if (itVar == impl->m_VariableToIdentifierMap.cend()) {
448 448 qCCritical(LOG_VariableController())
449 449 << tr("Impossible to onAbortProgressRequested request for unknown variable");
450 450 return;
451 451 }
452 452
453 453 auto varId = itVar->second;
454 454
455 455 auto itVarHandler = impl->m_VarIdToVarRequestHandler.find(varId);
456 456 if (itVarHandler == impl->m_VarIdToVarRequestHandler.cend()) {
457 457 qCCritical(LOG_VariableController())
458 458 << tr("Impossible to onAbortProgressRequested for variable with unknown handler");
459 459 return;
460 460 }
461 461
462 462 auto varHandler = itVarHandler->second.get();
463 463
464 464 // case where a variable has a running request
465 465 if (varHandler->m_State != VariableRequestHandlerState::OFF) {
466 466 impl->cancelVariableRequest(varHandler->m_RunningVarRequest.m_VariableGroupId);
467 467 }
468 468 }
469 469
470 470 void VariableController::onAbortAcquisitionRequested(QUuid vIdentifier)
471 471 {
472 472 qCDebug(LOG_VariableController()) << "TORM: variableController::onAbortAcquisitionRequested"
473 473 << QThread::currentThread()->objectName() << vIdentifier;
474 474
475 475 if (auto var = impl->findVariable(vIdentifier)) {
476 476 this->onAbortProgressRequested(var);
477 477 }
478 478 else {
479 479 qCCritical(LOG_VariableController())
480 480 << tr("Impossible to abort Acquisition Requestof a null variable");
481 481 }
482 482 }
483 483
484 484 void VariableController::onAddSynchronizationGroupId(QUuid synchronizationGroupId)
485 485 {
486 486 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronizationGroupId"
487 487 << QThread::currentThread()->objectName()
488 488 << synchronizationGroupId;
489 489 auto vSynchroGroup = std::make_shared<VariableSynchronizationGroup>();
490 490 impl->m_GroupIdToVariableSynchronizationGroupMap.insert(
491 491 std::make_pair(synchronizationGroupId, vSynchroGroup));
492 492 }
493 493
494 494 void VariableController::onRemoveSynchronizationGroupId(QUuid synchronizationGroupId)
495 495 {
496 496 impl->m_GroupIdToVariableSynchronizationGroupMap.erase(synchronizationGroupId);
497 497 }
498 498
499 499 void VariableController::onAddSynchronized(std::shared_ptr<Variable> variable,
500 500 QUuid synchronizationGroupId)
501 501
502 502 {
503 503 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronized"
504 504 << synchronizationGroupId;
505 505 auto varToVarIdIt = impl->m_VariableToIdentifierMap.find(variable);
506 506 if (varToVarIdIt != impl->m_VariableToIdentifierMap.cend()) {
507 507 auto groupIdToVSGIt
508 508 = impl->m_GroupIdToVariableSynchronizationGroupMap.find(synchronizationGroupId);
509 509 if (groupIdToVSGIt != impl->m_GroupIdToVariableSynchronizationGroupMap.cend()) {
510 510 impl->m_VariableIdGroupIdMap.insert(
511 511 std::make_pair(varToVarIdIt->second, synchronizationGroupId));
512 512 groupIdToVSGIt->second->addVariableId(varToVarIdIt->second);
513 513 }
514 514 else {
515 515 qCCritical(LOG_VariableController())
516 516 << tr("Impossible to synchronize a variable with an unknown sycnhronization group")
517 517 << variable->name();
518 518 }
519 519 }
520 520 else {
521 521 qCCritical(LOG_VariableController())
522 522 << tr("Impossible to synchronize a variable with no identifier") << variable->name();
523 523 }
524 524 }
525 525
526 526 void VariableController::desynchronize(std::shared_ptr<Variable> variable,
527 527 QUuid synchronizationGroupId)
528 528 {
529 529 // Gets variable id
530 530 auto variableIt = impl->m_VariableToIdentifierMap.find(variable);
531 531 if (variableIt == impl->m_VariableToIdentifierMap.cend()) {
532 532 qCCritical(LOG_VariableController())
533 533 << tr("Can't desynchronize variable %1: variable identifier not found")
534 534 .arg(variable->name());
535 535 return;
536 536 }
537 537
538 538 // Gets synchronization group
539 539 auto groupIt = impl->m_GroupIdToVariableSynchronizationGroupMap.find(synchronizationGroupId);
540 540 if (groupIt == impl->m_GroupIdToVariableSynchronizationGroupMap.cend()) {
541 541 qCCritical(LOG_VariableController())
542 542 << tr("Can't desynchronize variable %1: unknown synchronization group")
543 543 .arg(variable->name());
544 544 return;
545 545 }
546 546
547 547 auto variableId = variableIt->second;
548 548
549 549 // Removes variable from synchronization group
550 550 auto synchronizationGroup = groupIt->second;
551 551 synchronizationGroup->removeVariableId(variableId);
552 552
553 553 // Removes link between variable and synchronization group
554 554 impl->m_VariableIdGroupIdMap.erase(variableId);
555 555 }
556 556
557 557 void VariableController::onRequestDataLoading(QVector<std::shared_ptr<Variable> > variables,
558 558 const SqpRange &range, bool synchronise)
559 559 {
560 560 // variables is assumed synchronized
561 561 // TODO: Asser variables synchronization
562 562 // we want to load data of the variable for the dateTime.
563 563 if (variables.isEmpty()) {
564 564 return;
565 565 }
566 566
567 567 auto varRequestId = QUuid::createUuid();
568 568 qCDebug(LOG_VariableController()) << "VariableController::onRequestDataLoading"
569 569 << QThread::currentThread()->objectName() << varRequestId
570 570 << range << synchronise;
571 571
572 572 if (!synchronise) {
573 573 auto varIds = std::list<QUuid>{};
574 574 for (const auto &var : variables) {
575 575 auto vId = impl->m_VariableToIdentifierMap.at(var);
576 576 varIds.push_back(vId);
577 577 }
578 578 impl->m_VarGroupIdToVarIds.insert(std::make_pair(varRequestId, varIds));
579 579 for (const auto &var : variables) {
580 580 qCDebug(LOG_VariableController()) << "processRequest for" << var->name() << varRequestId
581 581 << varIds.size();
582 582 impl->processRequest(var, range, varRequestId);
583 583 }
584 584 }
585 585 else {
586 586 auto vId = impl->m_VariableToIdentifierMap.at(variables.first());
587 587 auto varIdToGroupIdIt = impl->m_VariableIdGroupIdMap.find(vId);
588 588 if (varIdToGroupIdIt != impl->m_VariableIdGroupIdMap.cend()) {
589 589 auto groupId = varIdToGroupIdIt->second;
590 590
591 591 auto vSynchronizationGroup
592 592 = impl->m_GroupIdToVariableSynchronizationGroupMap.at(groupId);
593 593 auto vSyncIds = vSynchronizationGroup->getIds();
594 594
595 595 auto varIds = std::list<QUuid>{};
596 596 for (auto vId : vSyncIds) {
597 597 varIds.push_back(vId);
598 598 }
599 599 impl->m_VarGroupIdToVarIds.insert(std::make_pair(varRequestId, varIds));
600 600
601 601 for (auto vId : vSyncIds) {
602 602 auto var = impl->findVariable(vId);
603 603
604 604 // Don't process already processed var
605 605 if (var != nullptr) {
606 606 qCDebug(LOG_VariableController()) << "processRequest synchro for" << var->name()
607 607 << varRequestId;
608 608 auto vSyncRangeRequested
609 609 = variables.contains(var)
610 610 ? range
611 611 : computeSynchroRangeRequested(var->range(), range,
612 612 variables.first()->range());
613 613 qCDebug(LOG_VariableController()) << "synchro RR" << vSyncRangeRequested;
614 614 impl->processRequest(var, vSyncRangeRequested, varRequestId);
615 615 }
616 616 else {
617 617 qCCritical(LOG_VariableController())
618 618
619 619 << tr("Impossible to synchronize a null variable");
620 620 }
621 621 }
622 622 }
623 623 }
624 624
625 625 impl->updateVariables(varRequestId);
626 626 }
627 627
628 628
629 629 void VariableController::initialize()
630 630 {
631 631 qCDebug(LOG_VariableController()) << tr("VariableController init") << QThread::currentThread();
632 632 impl->m_WorkingMutex.lock();
633 633 qCDebug(LOG_VariableController()) << tr("VariableController init END");
634 634 }
635 635
636 636 void VariableController::finalize()
637 637 {
638 638 impl->m_WorkingMutex.unlock();
639 639 }
640 640
641 641 void VariableController::waitForFinish()
642 642 {
643 643 QMutexLocker locker{&impl->m_WorkingMutex};
644 644 }
645 645
646 646 AcquisitionZoomType VariableController::getZoomType(const SqpRange &range, const SqpRange &oldRange)
647 647 {
648 648 // t1.m_TStart <= t2.m_TStart && t2.m_TEnd <= t1.m_TEnd
649 649 auto zoomType = AcquisitionZoomType::Unknown;
650 650 if (range.m_TStart <= oldRange.m_TStart && oldRange.m_TEnd <= range.m_TEnd) {
651 651 qCDebug(LOG_VariableController()) << "zoomtype: ZoomOut";
652 652 zoomType = AcquisitionZoomType::ZoomOut;
653 653 }
654 654 else if (range.m_TStart > oldRange.m_TStart && range.m_TEnd > oldRange.m_TEnd) {
655 655 qCDebug(LOG_VariableController()) << "zoomtype: PanRight";
656 656 zoomType = AcquisitionZoomType::PanRight;
657 657 }
658 658 else if (range.m_TStart < oldRange.m_TStart && range.m_TEnd < oldRange.m_TEnd) {
659 659 qCDebug(LOG_VariableController()) << "zoomtype: PanLeft";
660 660 zoomType = AcquisitionZoomType::PanLeft;
661 661 }
662 662 else if (range.m_TStart > oldRange.m_TStart && oldRange.m_TEnd > range.m_TEnd) {
663 663 qCDebug(LOG_VariableController()) << "zoomtype: ZoomIn";
664 664 zoomType = AcquisitionZoomType::ZoomIn;
665 665 }
666 666 else {
667 667 qCDebug(LOG_VariableController()) << "getZoomType: Unknown type detected";
668 668 }
669 669 return zoomType;
670 670 }
671 671
672 672 void VariableController::VariableControllerPrivate::processRequest(std::shared_ptr<Variable> var,
673 673 const SqpRange &rangeRequested,
674 674 QUuid varRequestId)
675 675 {
676 676 auto itVar = m_VariableToIdentifierMap.find(var);
677 677 if (itVar == m_VariableToIdentifierMap.cend()) {
678 678 qCCritical(LOG_VariableController())
679 679 << tr("Impossible to process request for unknown variable");
680 680 return;
681 681 }
682 682
683 683 auto varId = itVar->second;
684 684
685 685 auto itVarHandler = m_VarIdToVarRequestHandler.find(varId);
686 686 if (itVarHandler == m_VarIdToVarRequestHandler.cend()) {
687 687 qCCritical(LOG_VariableController())
688 688 << tr("Impossible to process request for variable with unknown handler");
689 689 return;
690 690 }
691 691
692 692 auto oldRange = var->range();
693 693
694 694 auto varHandler = itVarHandler->second.get();
695 695
696 696 if (varHandler->m_State != VariableRequestHandlerState::OFF) {
697 697 oldRange = varHandler->m_RunningVarRequest.m_RangeRequested;
698 698 }
699 699
700 700 auto varRequest = VariableRequest{};
701 701 varRequest.m_VariableGroupId = varRequestId;
702 702 auto varStrategyRangesRequested
703 703 = m_VariableCacheStrategy->computeRange(oldRange, rangeRequested);
704 704 varRequest.m_RangeRequested = varStrategyRangesRequested.first;
705 705 varRequest.m_CacheRangeRequested = varStrategyRangesRequested.second;
706 706
707 707 switch (varHandler->m_State) {
708 708 case VariableRequestHandlerState::OFF: {
709 709 qCDebug(LOG_VariableController()) << tr("Process Request OFF")
710 710 << varRequest.m_RangeRequested
711 711 << varRequest.m_CacheRangeRequested;
712 712 varHandler->m_RunningVarRequest = varRequest;
713 713 varHandler->m_State = VariableRequestHandlerState::RUNNING;
714 714 executeVarRequest(var, varRequest);
715 715 break;
716 716 }
717 717 case VariableRequestHandlerState::RUNNING: {
718 718 qCDebug(LOG_VariableController()) << tr("Process Request RUNNING")
719 719 << varRequest.m_RangeRequested
720 720 << varRequest.m_CacheRangeRequested;
721 721 varHandler->m_State = VariableRequestHandlerState::PENDING;
722 722 varHandler->m_PendingVarRequest = varRequest;
723 723 break;
724 724 }
725 725 case VariableRequestHandlerState::PENDING: {
726 726 qCDebug(LOG_VariableController()) << tr("Process Request PENDING")
727 727 << varRequest.m_RangeRequested
728 728 << varRequest.m_CacheRangeRequested;
729 729 auto variableGroupIdToCancel = varHandler->m_PendingVarRequest.m_VariableGroupId;
730 730 cancelVariableRequest(variableGroupIdToCancel);
731 731 // Cancel variable can make state downgrade
732 732 varHandler->m_State = VariableRequestHandlerState::PENDING;
733 733 varHandler->m_PendingVarRequest = varRequest;
734 734
735 735 break;
736 736 }
737 737 default:
738 738 qCCritical(LOG_VariableController())
739 739 << QObject::tr("Unknown VariableRequestHandlerState");
740 740 }
741 741 }
742 742
743 743 std::shared_ptr<Variable>
744 744 VariableController::VariableControllerPrivate::findVariable(QUuid vIdentifier)
745 745 {
746 746 std::shared_ptr<Variable> var;
747 747 auto findReply = [vIdentifier](const auto &entry) { return vIdentifier == entry.second; };
748 748
749 749 auto end = m_VariableToIdentifierMap.cend();
750 750 auto it = std::find_if(m_VariableToIdentifierMap.cbegin(), end, findReply);
751 751 if (it != end) {
752 752 var = it->first;
753 753 }
754 754 else {
755 755 qCCritical(LOG_VariableController())
756 756 << tr("Impossible to find the variable with the identifier: ") << vIdentifier;
757 757 }
758 758
759 759 return var;
760 760 }
761 761
762 762 std::shared_ptr<IDataSeries> VariableController::VariableControllerPrivate::retrieveDataSeries(
763 763 const QVector<AcquisitionDataPacket> acqDataPacketVector)
764 764 {
765 765 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size")
766 766 << acqDataPacketVector.size();
767 767 std::shared_ptr<IDataSeries> dataSeries;
768 768 if (!acqDataPacketVector.isEmpty()) {
769 769 dataSeries = acqDataPacketVector[0].m_DateSeries;
770 770 for (int i = 1; i < acqDataPacketVector.size(); ++i) {
771 771 dataSeries->merge(acqDataPacketVector[i].m_DateSeries.get());
772 772 }
773 773 }
774 774 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size END")
775 775 << acqDataPacketVector.size();
776 776 return dataSeries;
777 777 }
778 778
779 779 void VariableController::VariableControllerPrivate::registerProvider(
780 780 std::shared_ptr<IDataProvider> provider)
781 781 {
782 782 if (m_ProviderSet.find(provider) == m_ProviderSet.end()) {
783 783 qCDebug(LOG_VariableController()) << tr("Registering of a new provider")
784 784 << provider->objectName();
785 785 m_ProviderSet.insert(provider);
786 786 connect(provider.get(), &IDataProvider::dataProvided, m_VariableAcquisitionWorker.get(),
787 787 &VariableAcquisitionWorker::onVariableDataAcquired);
788 788 connect(provider.get(), &IDataProvider::dataProvidedProgress,
789 789 m_VariableAcquisitionWorker.get(),
790 790 &VariableAcquisitionWorker::onVariableRetrieveDataInProgress);
791 791 connect(provider.get(), &IDataProvider::dataProvidedFailed,
792 792 m_VariableAcquisitionWorker.get(),
793 793 &VariableAcquisitionWorker::onVariableAcquisitionFailed);
794 794 }
795 795 else {
796 796 qCDebug(LOG_VariableController()) << tr("Cannot register provider, it already exists ");
797 797 }
798 798 }
799 799
800 800 QUuid VariableController::VariableControllerPrivate::acceptVariableRequest(
801 801 QUuid varId, std::shared_ptr<IDataSeries> dataSeries)
802 802 {
803 803 auto itVarHandler = m_VarIdToVarRequestHandler.find(varId);
804 804 if (itVarHandler == m_VarIdToVarRequestHandler.cend()) {
805 805 return QUuid();
806 806 }
807 807
808 808 auto varHandler = itVarHandler->second.get();
809 809 if (varHandler->m_State == VariableRequestHandlerState::OFF) {
810 810 qCCritical(LOG_VariableController())
811 811 << tr("acceptVariableRequest impossible on a variable with OFF state");
812 812 }
813 813
814 814 varHandler->m_RunningVarRequest.m_DataSeries = dataSeries;
815 815 varHandler->m_CanUpdate = true;
816 816
817 817 // Element traitΓ©, on a dΓ©jΓ  toutes les donnΓ©es necessaires
818 818 auto varGroupId = varHandler->m_RunningVarRequest.m_VariableGroupId;
819 819 qCDebug(LOG_VariableController()) << "Variable::acceptVariableRequest" << varGroupId
820 820 << m_VarGroupIdToVarIds.size();
821 821
822 822 return varHandler->m_RunningVarRequest.m_VariableGroupId;
823 823 }
824 824
825 825 void VariableController::VariableControllerPrivate::updateVariables(QUuid varRequestId)
826 826 {
827 827 qCDebug(LOG_VariableController()) << "VariableControllerPrivate::updateVariables"
828 828 << QThread::currentThread()->objectName() << varRequestId;
829 829
830 830 auto varGroupIdToVarIdsIt = m_VarGroupIdToVarIds.find(varRequestId);
831 831 if (varGroupIdToVarIdsIt == m_VarGroupIdToVarIds.end()) {
832 832 qCWarning(LOG_VariableController())
833 833 << tr("Impossible to updateVariables of unknown variables") << varRequestId;
834 834 return;
835 835 }
836 836
837 837 auto &varIds = varGroupIdToVarIdsIt->second;
838 838 auto varIdsEnd = varIds.end();
839 839 bool processVariableUpdate = true;
840 840 qCDebug(LOG_VariableController()) << "VariableControllerPrivate::updateVariables"
841 841 << varRequestId << varIds.size();
842 842 for (auto varIdsIt = varIds.begin(); (varIdsIt != varIdsEnd) && processVariableUpdate;
843 843 ++varIdsIt) {
844 844 auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt);
845 845 if (itVarHandler != m_VarIdToVarRequestHandler.cend()) {
846 846 processVariableUpdate &= itVarHandler->second->m_CanUpdate;
847 847 }
848 848 }
849 849
850 850 if (processVariableUpdate) {
851 851 qCDebug(LOG_VariableController()) << "Final update OK for the var request" << varIds.size();
852 852 for (auto varIdsIt = varIds.begin(); varIdsIt != varIdsEnd; ++varIdsIt) {
853 853 auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt);
854 854 if (itVarHandler != m_VarIdToVarRequestHandler.cend()) {
855 855 if (auto var = findVariable(*varIdsIt)) {
856 856 auto &varRequest = itVarHandler->second->m_RunningVarRequest;
857 857 var->setRange(varRequest.m_RangeRequested);
858 858 var->setCacheRange(varRequest.m_CacheRangeRequested);
859 859 qCDebug(LOG_VariableController()) << tr("1: onDataProvided")
860 860 << varRequest.m_RangeRequested
861 861 << varRequest.m_CacheRangeRequested;
862 862 qCDebug(LOG_VariableController()) << tr("2: onDataProvided var points before")
863 863 << var->nbPoints()
864 864 << varRequest.m_DataSeries->nbPoints();
865 865 var->mergeDataSeries(varRequest.m_DataSeries);
866 866 qCDebug(LOG_VariableController()) << tr("3: onDataProvided var points after")
867 867 << var->nbPoints();
868 868
869 869 emit var->updated();
870 870 qCDebug(LOG_VariableController()) << tr("Update OK");
871 871 }
872 872 else {
873 873 qCCritical(LOG_VariableController())
874 874 << tr("Impossible to update data to a null variable");
875 875 }
876 876 }
877 877 }
878 878 updateVariableRequest(varRequestId);
879 879
880 880 // cleaning varRequestId
881 881 qCDebug(LOG_VariableController()) << tr("m_VarGroupIdToVarIds erase") << varRequestId;
882 882 m_VarGroupIdToVarIds.erase(varRequestId);
883 883 }
884 884 }
885 885
886 886
887 887 void VariableController::VariableControllerPrivate::updateVariableRequest(QUuid varRequestId)
888 888 {
889 889 auto varGroupIdToVarIdsIt = m_VarGroupIdToVarIds.find(varRequestId);
890 890 if (varGroupIdToVarIdsIt == m_VarGroupIdToVarIds.end()) {
891 891 qCCritical(LOG_VariableController()) << QObject::tr(
892 892 "Impossible to updateVariableRequest since varGroupdId isn't here anymore");
893 893
894 894 return;
895 895 }
896 896
897 897 auto &varIds = varGroupIdToVarIdsIt->second;
898 898 auto varIdsEnd = varIds.end();
899 899 for (auto varIdsIt = varIds.begin(); (varIdsIt != varIdsEnd); ++varIdsIt) {
900 900 auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt);
901 901 if (itVarHandler != m_VarIdToVarRequestHandler.cend()) {
902 902
903 903 auto varHandler = itVarHandler->second.get();
904 904 varHandler->m_CanUpdate = false;
905 905
906 906
907 907 switch (varHandler->m_State) {
908 908 case VariableRequestHandlerState::OFF: {
909 909 qCCritical(LOG_VariableController())
910 910 << QObject::tr("Impossible to update a variable with handler in OFF state");
911 911 } break;
912 912 case VariableRequestHandlerState::RUNNING: {
913 913 varHandler->m_State = VariableRequestHandlerState::OFF;
914 914 varHandler->m_RunningVarRequest = VariableRequest{};
915 915 break;
916 916 }
917 917 case VariableRequestHandlerState::PENDING: {
918 918 varHandler->m_State = VariableRequestHandlerState::RUNNING;
919 919 varHandler->m_RunningVarRequest = varHandler->m_PendingVarRequest;
920 920 varHandler->m_PendingVarRequest = VariableRequest{};
921 921 auto var = findVariable(itVarHandler->first);
922 922 executeVarRequest(var, varHandler->m_RunningVarRequest);
923 923 break;
924 924 }
925 925 default:
926 926 qCCritical(LOG_VariableController())
927 927 << QObject::tr("Unknown VariableRequestHandlerState");
928 928 }
929 929 }
930 930 }
931 931 }
932 932
933 933
934 934 void VariableController::VariableControllerPrivate::cancelVariableRequest(QUuid varRequestId)
935 935 {
936 936 qCDebug(LOG_VariableController()) << tr("cancelVariableRequest") << varRequestId;
937 937
938 938 auto varGroupIdToVarIdsIt = m_VarGroupIdToVarIds.find(varRequestId);
939 939 if (varGroupIdToVarIdsIt == m_VarGroupIdToVarIds.end()) {
940 940 qCCritical(LOG_VariableController())
941 941 << tr("Impossible to cancelVariableRequest for unknown varGroupdId") << varRequestId;
942 942 return;
943 943 }
944 944
945 945 auto &varIds = varGroupIdToVarIdsIt->second;
946 946 auto varIdsEnd = varIds.end();
947 947 for (auto varIdsIt = varIds.begin(); (varIdsIt != varIdsEnd); ++varIdsIt) {
948 948 auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt);
949 949 if (itVarHandler != m_VarIdToVarRequestHandler.cend()) {
950 950
951 951 auto varHandler = itVarHandler->second.get();
952 952 varHandler->m_VarId = QUuid{};
953 953 switch (varHandler->m_State) {
954 954 case VariableRequestHandlerState::OFF: {
955 955 qCWarning(LOG_VariableController())
956 956 << QObject::tr("Impossible to cancel a variable with no running request");
957 957 break;
958 958 }
959 959 case VariableRequestHandlerState::RUNNING: {
960 960
961 961 if (varHandler->m_RunningVarRequest.m_VariableGroupId == varRequestId) {
962 962 auto var = findVariable(itVarHandler->first);
963 963 auto varProvider = m_VariableToProviderMap.at(var);
964 964 if (varProvider != nullptr) {
965 965 m_VariableAcquisitionWorker->abortProgressRequested(
966 966 itVarHandler->first);
967 967 }
968 968 m_VariableModel->setDataProgress(var, 0.0);
969 969 varHandler->m_CanUpdate = false;
970 970 varHandler->m_State = VariableRequestHandlerState::OFF;
971 971 varHandler->m_RunningVarRequest = VariableRequest{};
972 972 }
973 973 else {
974 974 // TODO: log Impossible to cancel the running variable request beacause its
975 975 // varRequestId isn't not the canceled one
976 976 }
977 977 break;
978 978 }
979 979 case VariableRequestHandlerState::PENDING: {
980 980 if (varHandler->m_RunningVarRequest.m_VariableGroupId == varRequestId) {
981 981 auto var = findVariable(itVarHandler->first);
982 982 auto varProvider = m_VariableToProviderMap.at(var);
983 983 if (varProvider != nullptr) {
984 984 m_VariableAcquisitionWorker->abortProgressRequested(
985 985 itVarHandler->first);
986 986 }
987 987 m_VariableModel->setDataProgress(var, 0.0);
988 988 varHandler->m_CanUpdate = false;
989 989 varHandler->m_State = VariableRequestHandlerState::RUNNING;
990 990 varHandler->m_RunningVarRequest = varHandler->m_PendingVarRequest;
991 991 varHandler->m_PendingVarRequest = VariableRequest{};
992 992 executeVarRequest(var, varHandler->m_RunningVarRequest);
993 993 }
994 994 else if (varHandler->m_PendingVarRequest.m_VariableGroupId == varRequestId) {
995 995 varHandler->m_State = VariableRequestHandlerState::RUNNING;
996 996 varHandler->m_PendingVarRequest = VariableRequest{};
997 997 }
998 998 else {
999 999 // TODO: log Impossible to cancel the variable request beacause its
1000 1000 // varRequestId isn't not the canceled one
1001 1001 }
1002 1002 break;
1003 1003 }
1004 1004 default:
1005 1005 qCCritical(LOG_VariableController())
1006 1006 << QObject::tr("Unknown VariableRequestHandlerState");
1007 1007 }
1008 1008 }
1009 1009 }
1010 1010 qCDebug(LOG_VariableController()) << tr("cancelVariableRequest: erase") << varRequestId;
1011 1011 m_VarGroupIdToVarIds.erase(varRequestId);
1012 1012 }
1013 1013
1014 1014 void VariableController::VariableControllerPrivate::executeVarRequest(std::shared_ptr<Variable> var,
1015 1015 VariableRequest &varRequest)
1016 1016 {
1017 1017 qCDebug(LOG_VariableController()) << tr("TORM: executeVarRequest");
1018 1018
1019 1019 auto varId = m_VariableToIdentifierMap.at(var);
1020 1020
1021 1021 auto varCacheRange = var->cacheRange();
1022 1022 auto varCacheRangeRequested = varRequest.m_CacheRangeRequested;
1023 1023 auto notInCacheRangeList
1024 1024 = Variable::provideNotInCacheRangeList(varCacheRange, varCacheRangeRequested);
1025 1025 auto inCacheRangeList
1026 1026 = Variable::provideInCacheRangeList(varCacheRange, varCacheRangeRequested);
1027 1027
1028 1028 if (!notInCacheRangeList.empty()) {
1029 1029
1030 1030 auto varProvider = m_VariableToProviderMap.at(var);
1031 1031 if (varProvider != nullptr) {
1032 1032 qCDebug(LOG_VariableController()) << "executeVarRequest " << varRequest.m_RangeRequested
1033 1033 << varRequest.m_CacheRangeRequested;
1034 1034 m_VariableAcquisitionWorker->pushVariableRequest(
1035 1035 varRequest.m_VariableGroupId, varId, varRequest.m_RangeRequested,
1036 1036 varRequest.m_CacheRangeRequested,
1037 1037 DataProviderParameters{std::move(notInCacheRangeList), var->metadata()},
1038 1038 varProvider);
1039 1039 }
1040 1040 else {
1041 1041 qCCritical(LOG_VariableController())
1042 1042 << "Impossible to provide data with a null provider";
1043 1043 }
1044 1044
1045 1045 if (!inCacheRangeList.empty()) {
1046 1046 emit q->updateVarDisplaying(var, inCacheRangeList.first());
1047 1047 }
1048 1048 }
1049 1049 else {
1050 1050 acceptVariableRequest(varId,
1051 1051 var->dataSeries()->subDataSeries(varRequest.m_CacheRangeRequested));
1052 1052 }
1053 1053 }
@@ -1,289 +1,295
1 1 #include "DragDropHelper.h"
2 2 #include "SqpApplication.h"
3 3 #include "Visualization/VisualizationDragDropContainer.h"
4 4 #include "Visualization/VisualizationDragWidget.h"
5 5 #include "Visualization/VisualizationWidget.h"
6 6 #include "Visualization/operations/FindVariableOperation.h"
7 7
8 8 #include "Variable/VariableController.h"
9 9
10 10 #include "Common/MimeTypesDef.h"
11 11 #include "Common/VisualizationDef.h"
12 12
13 13 #include <QDir>
14 14 #include <QDragEnterEvent>
15 15 #include <QDragMoveEvent>
16 16 #include <QScrollArea>
17 17 #include <QScrollBar>
18 18 #include <QTimer>
19 19 #include <QVBoxLayout>
20 20
21 21 const int SCROLL_SPEED = 5;
22 22 const int SCROLL_ZONE_SIZE = 50;
23 23
24 24 Q_LOGGING_CATEGORY(LOG_DragDropHelper, "DragDrophelper")
25 25
26 26 struct DragDropScroller::DragDropScrollerPrivate {
27 27
28 28 QList<QScrollArea *> m_ScrollAreas;
29 29 QScrollArea *m_CurrentScrollArea = nullptr;
30 30 std::unique_ptr<QTimer> m_Timer = nullptr;
31 31
32 32
33 33 enum class ScrollDirection { up, down, unknown };
34 34 ScrollDirection m_Direction = ScrollDirection::unknown;
35 35
36 36 explicit DragDropScrollerPrivate() : m_Timer{std::make_unique<QTimer>()}
37 37 {
38 38 m_Timer->setInterval(0);
39 39 }
40 40 };
41 41
42 42 DragDropScroller::DragDropScroller(QObject *parent)
43 43 : QObject{parent}, impl{spimpl::make_unique_impl<DragDropScrollerPrivate>()}
44 44 {
45 45 connect(impl->m_Timer.get(), &QTimer::timeout, this, &DragDropScroller::onTimer);
46 46 }
47 47
48 48 void DragDropScroller::addScrollArea(QScrollArea *scrollArea)
49 49 {
50 50 impl->m_ScrollAreas << scrollArea;
51 51 scrollArea->viewport()->setAcceptDrops(true);
52 52 }
53 53
54 54 void DragDropScroller::removeScrollArea(QScrollArea *scrollArea)
55 55 {
56 56 impl->m_ScrollAreas.removeAll(scrollArea);
57 57 scrollArea->viewport()->setAcceptDrops(false);
58 58 }
59 59
60 60 bool DragDropScroller::eventFilter(QObject *obj, QEvent *event)
61 61 {
62 62 if (event->type() == QEvent::DragMove) {
63 63 auto w = static_cast<QWidget *>(obj);
64 64
65 65 if (impl->m_CurrentScrollArea && impl->m_CurrentScrollArea->isAncestorOf(w)) {
66 66 auto moveEvent = static_cast<QDragMoveEvent *>(event);
67 67
68 68 auto pos = moveEvent->pos();
69 69 if (impl->m_CurrentScrollArea->viewport() != w) {
70 70 auto globalPos = w->mapToGlobal(moveEvent->pos());
71 71 pos = impl->m_CurrentScrollArea->viewport()->mapFromGlobal(globalPos);
72 72 }
73 73
74 74 auto isInTopZone = pos.y() > impl->m_CurrentScrollArea->viewport()->size().height()
75 75 - SCROLL_ZONE_SIZE;
76 76 auto isInBottomZone = pos.y() < SCROLL_ZONE_SIZE;
77 77
78 78 if (!isInTopZone && !isInBottomZone) {
79 79 impl->m_Direction = DragDropScrollerPrivate::ScrollDirection::unknown;
80 80 impl->m_Timer->stop();
81 81 }
82 82 else if (!impl->m_Timer->isActive()) {
83 83 impl->m_Direction = isInTopZone ? DragDropScrollerPrivate::ScrollDirection::up
84 84 : DragDropScrollerPrivate::ScrollDirection::down;
85 85 impl->m_Timer->start();
86 86 }
87 87 }
88 88 }
89 89 else if (event->type() == QEvent::DragEnter) {
90 90 auto w = static_cast<QWidget *>(obj);
91 91
92 92 for (auto scrollArea : impl->m_ScrollAreas) {
93 93 if (impl->m_CurrentScrollArea != scrollArea && scrollArea->isAncestorOf(w)) {
94 94 auto enterEvent = static_cast<QDragEnterEvent *>(event);
95 95 enterEvent->acceptProposedAction();
96 96 enterEvent->setDropAction(Qt::IgnoreAction);
97 97 impl->m_CurrentScrollArea = scrollArea;
98 98 break;
99 99 }
100 100 }
101 101 }
102 102 else if (event->type() == QEvent::DragLeave) {
103 103 if (impl->m_CurrentScrollArea) {
104 104 if (!QRect(QPoint(), impl->m_CurrentScrollArea->size())
105 105 .contains(impl->m_CurrentScrollArea->mapFromGlobal(QCursor::pos()))) {
106 106 impl->m_CurrentScrollArea = nullptr;
107 107 impl->m_Direction = DragDropScrollerPrivate::ScrollDirection::unknown;
108 108 impl->m_Timer->stop();
109 109 }
110 110 }
111 111 }
112 112 else if (event->type() == QEvent::Drop) {
113 113 if (impl->m_CurrentScrollArea) {
114 114 impl->m_CurrentScrollArea = nullptr;
115 115 impl->m_Direction = DragDropScrollerPrivate::ScrollDirection::unknown;
116 116 impl->m_Timer->stop();
117 117 }
118 118 }
119 119
120 120 return false;
121 121 }
122 122
123 123 void DragDropScroller::onTimer()
124 124 {
125 125 if (impl->m_CurrentScrollArea) {
126 126 auto mvt = 0;
127 127 switch (impl->m_Direction) {
128 128 case DragDropScrollerPrivate::ScrollDirection::up:
129 129 mvt = SCROLL_SPEED;
130 130 break;
131 131 case DragDropScrollerPrivate::ScrollDirection::down:
132 132 mvt = -SCROLL_SPEED;
133 133 break;
134 134 default:
135 135 break;
136 136 }
137 137
138 138 impl->m_CurrentScrollArea->verticalScrollBar()->setValue(
139 139 impl->m_CurrentScrollArea->verticalScrollBar()->value() + mvt);
140 140 }
141 141 }
142 142
143 143 struct DragDropHelper::DragDropHelperPrivate {
144 144
145 145 VisualizationDragWidget *m_CurrentDragWidget = nullptr;
146 146 std::unique_ptr<QWidget> m_PlaceHolder = nullptr;
147 147 std::unique_ptr<DragDropScroller> m_DragDropScroller = nullptr;
148 148 QString m_ImageTempUrl; // Temporary file for image url generated by the drag & drop. Not using
149 149 // QTemporaryFile to have a name which is not generated.
150 150
151 151 explicit DragDropHelperPrivate()
152 152 : m_PlaceHolder{std::make_unique<QWidget>()},
153 153 m_DragDropScroller{std::make_unique<DragDropScroller>()}
154 154 {
155 155 m_PlaceHolder->setStyleSheet("background-color: #BBD5EE; border:2px solid #2A7FD4");
156 156 sqpApp->installEventFilter(m_DragDropScroller.get());
157 157
158 158
159 159 m_ImageTempUrl = QDir::temp().absoluteFilePath("Scqlop_graph.png");
160 160 }
161 161
162 162 void preparePlaceHolder() const
163 163 {
164 164 if (m_CurrentDragWidget) {
165 165 m_PlaceHolder->setMinimumSize(m_CurrentDragWidget->size());
166 166 m_PlaceHolder->setSizePolicy(m_CurrentDragWidget->sizePolicy());
167 167 }
168 168 else {
169 169 // Configuration of the placeHolder when there is no dragWidget
170 170 // (for instance with a drag from a variable)
171 171
172 172 m_PlaceHolder->setMinimumSize(0, GRAPH_MINIMUM_HEIGHT);
173 173 m_PlaceHolder->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
174 174 }
175 175 }
176 176 };
177 177
178 178
179 179 DragDropHelper::DragDropHelper() : impl{spimpl::make_unique_impl<DragDropHelperPrivate>()}
180 180 {
181 181 }
182 182
183 183 DragDropHelper::~DragDropHelper()
184 184 {
185 185 QFile::remove(impl->m_ImageTempUrl);
186 186 }
187 187
188 188 void DragDropHelper::resetDragAndDrop()
189 189 {
190 190 setCurrentDragWidget(nullptr);
191 191 }
192 192
193 193 void DragDropHelper::setCurrentDragWidget(VisualizationDragWidget *dragWidget)
194 194 {
195 195 impl->m_CurrentDragWidget = dragWidget;
196 196 }
197 197
198 198 VisualizationDragWidget *DragDropHelper::getCurrentDragWidget() const
199 199 {
200 200 return impl->m_CurrentDragWidget;
201 201 }
202 202
203 203
204 204 QWidget &DragDropHelper::placeHolder() const
205 205 {
206 206 return *impl->m_PlaceHolder;
207 207 }
208 208
209 209 void DragDropHelper::insertPlaceHolder(QVBoxLayout *layout, int index)
210 210 {
211 211 removePlaceHolder();
212 212 impl->preparePlaceHolder();
213 213 layout->insertWidget(index, impl->m_PlaceHolder.get());
214 214 impl->m_PlaceHolder->show();
215 215 }
216 216
217 217 void DragDropHelper::removePlaceHolder()
218 218 {
219 219 auto parentWidget = impl->m_PlaceHolder->parentWidget();
220 220 if (parentWidget) {
221 221 parentWidget->layout()->removeWidget(impl->m_PlaceHolder.get());
222 222 impl->m_PlaceHolder->setParent(nullptr);
223 223 impl->m_PlaceHolder->hide();
224 224 }
225 225 }
226 226
227 227 bool DragDropHelper::isPlaceHolderSet() const
228 228 {
229 229 return impl->m_PlaceHolder->parentWidget();
230 230 }
231 231
232 232 void DragDropHelper::addDragDropScrollArea(QScrollArea *scrollArea)
233 233 {
234 234 impl->m_DragDropScroller->addScrollArea(scrollArea);
235 235 }
236 236
237 237 void DragDropHelper::removeDragDropScrollArea(QScrollArea *scrollArea)
238 238 {
239 239 impl->m_DragDropScroller->removeScrollArea(scrollArea);
240 240 }
241 241
242 242 QUrl DragDropHelper::imageTemporaryUrl(const QImage &image) const
243 243 {
244 244 image.save(impl->m_ImageTempUrl);
245 245 return QUrl::fromLocalFile(impl->m_ImageTempUrl);
246 246 }
247 247
248 248 bool DragDropHelper::checkMimeDataForVisualization(const QMimeData *mimeData,
249 249 VisualizationDragDropContainer *dropContainer)
250 250 {
251 if (!mimeData || !dropContainer) {
252 qCWarning(LOG_DragDropHelper()) << QObject::tr(
253 "DragDropHelper::checkMimeDataForVisualization, invalid input parameters.");
254 Q_ASSERT(false);
255 }
256
251 257 auto result = true;
252 258
253 259 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
254 260 auto variables = sqpApp->variableController().variablesForMimeData(
255 261 mimeData->data(MIME_TYPE_VARIABLE_LIST));
256 262
257 263 if (variables.count() == 1) {
258 264 // Check that the viariable is not already in a graph
259 265
260 266 // Search for the top level VisualizationWidget
261 267 auto parent = dropContainer->parentWidget();
262 268 while (parent && qobject_cast<VisualizationWidget *>(parent) == nullptr) {
263 269 parent = parent->parentWidget();
264 270 }
265 271
266 272 if (parent) {
267 273 auto visualizationWidget = static_cast<VisualizationWidget *>(parent);
268 274
269 275 FindVariableOperation findVariableOperation{variables.first()};
270 276 visualizationWidget->accept(&findVariableOperation);
271 277 auto variableContainers = findVariableOperation.result();
272 278 if (!variableContainers.empty()) {
273 279 result = false;
274 280 }
275 281 }
276 282 else {
277 283 qCWarning(LOG_DragDropHelper()) << QObject::tr(
278 284 "DragDropHelper::checkMimeDataForVisualization, the parent "
279 285 "VisualizationWidget cannot be found.");
280 286 result = false;
281 287 }
282 288 }
283 289 else {
284 290 result = false;
285 291 }
286 292 }
287 293
288 294 return result;
289 295 }
@@ -1,385 +1,385
1 1 #include "Visualization/VisualizationGraphWidget.h"
2 2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 3 #include "Visualization/VisualizationDefs.h"
4 4 #include "Visualization/VisualizationGraphHelper.h"
5 5 #include "Visualization/VisualizationGraphRenderingDelegate.h"
6 6 #include "Visualization/VisualizationZoneWidget.h"
7 7 #include "ui_VisualizationGraphWidget.h"
8 8
9 9 #include <Common/MimeTypesDef.h>
10 10 #include <Data/ArrayData.h>
11 11 #include <Data/IDataSeries.h>
12 12 #include <DragDropHelper.h>
13 13 #include <Settings/SqpSettingsDefs.h>
14 14 #include <SqpApplication.h>
15 15 #include <Variable/Variable.h>
16 16 #include <Variable/VariableController.h>
17 17
18 18 #include <unordered_map>
19 19
20 20 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
21 21
22 22 namespace {
23 23
24 24 /// Key pressed to enable zoom on horizontal axis
25 25 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::NoModifier;
26 26
27 27 /// Key pressed to enable zoom on vertical axis
28 28 const auto VERTICAL_ZOOM_MODIFIER = Qt::ControlModifier;
29 29
30 30 } // namespace
31 31
32 32 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
33 33
34 34 explicit VisualizationGraphWidgetPrivate(const QString &name)
35 35 : m_Name{name},
36 36 m_DoAcquisition{true},
37 37 m_IsCalibration{false},
38 38 m_RenderingDelegate{nullptr}
39 39 {
40 40 }
41 41
42 42 QString m_Name;
43 43 // 1 variable -> n qcpplot
44 44 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
45 45 bool m_DoAcquisition;
46 46 bool m_IsCalibration;
47 47 QCPItemTracer *m_TextTracer;
48 48 /// Delegate used to attach rendering features to the plot
49 49 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
50 50 };
51 51
52 52 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
53 53 : VisualizationDragWidget{parent},
54 54 ui{new Ui::VisualizationGraphWidget},
55 55 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
56 56 {
57 57 ui->setupUi(this);
58 58
59 59 // 'Close' options : widget is deleted when closed
60 60 setAttribute(Qt::WA_DeleteOnClose);
61 61
62 62 // Set qcpplot properties :
63 63 // - Drag (on x-axis) and zoom are enabled
64 64 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
65 65 ui->widget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectItems);
66 66 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal);
67 67
68 68 // The delegate must be initialized after the ui as it uses the plot
69 69 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
70 70
71 71 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
72 72 connect(ui->widget, &QCustomPlot::mouseRelease, this,
73 73 &VisualizationGraphWidget::onMouseRelease);
74 74 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
75 75 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
76 76 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
77 77 &QCPAxis::rangeChanged),
78 78 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
79 79
80 80 // Activates menu when right clicking on the graph
81 81 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
82 82 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
83 83 &VisualizationGraphWidget::onGraphMenuRequested);
84 84
85 85 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
86 86 &VariableController::onRequestDataLoading);
87 87
88 88 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
89 89 &VisualizationGraphWidget::onUpdateVarDisplaying);
90 90 }
91 91
92 92
93 93 VisualizationGraphWidget::~VisualizationGraphWidget()
94 94 {
95 95 delete ui;
96 96 }
97 97
98 98 VisualizationZoneWidget *VisualizationGraphWidget::parentZoneWidget() const noexcept
99 99 {
100 100 auto parent = parentWidget();
101 101 while (parent != nullptr && !qobject_cast<VisualizationZoneWidget *>(parent)) {
102 102 parent = parent->parentWidget();
103 103 }
104 104
105 105 return qobject_cast<VisualizationZoneWidget *>(parent);
106 106 }
107 107
108 108 void VisualizationGraphWidget::enableAcquisition(bool enable)
109 109 {
110 110 impl->m_DoAcquisition = enable;
111 111 }
112 112
113 113 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
114 114 {
115 115 // Uses delegate to create the qcpplot components according to the variable
116 116 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
117 117 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
118 118
119 119 // Set axes properties according to the units of the data series
120 120 /// @todo : for the moment, no control is performed on the axes: the units and the tickers
121 121 /// are fixed for the default x-axis and y-axis of the plot, and according to the new graph
122 122 auto xAxisUnit = Unit{};
123 123 auto valuesUnit = Unit{};
124 124
125 125 if (auto dataSeries = variable->dataSeries()) {
126 126 dataSeries->lockRead();
127 127 xAxisUnit = dataSeries->xAxisUnit();
128 128 valuesUnit = dataSeries->valuesUnit();
129 129 dataSeries->unlock();
130 130 }
131 131 impl->m_RenderingDelegate->setAxesProperties(xAxisUnit, valuesUnit);
132 132
133 133 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
134 134
135 135 this->enableAcquisition(false);
136 136 this->setGraphRange(range);
137 137 this->enableAcquisition(true);
138 138
139 139 emit requestDataLoading(QVector<std::shared_ptr<Variable> >() << variable, range, false);
140 140
141 141 emit variableAdded(variable);
142 142 }
143 143
144 144 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
145 145 {
146 146 // Each component associated to the variable :
147 147 // - is removed from qcpplot (which deletes it)
148 148 // - is no longer referenced in the map
149 149 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
150 150 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
151 151 emit variableAboutToBeRemoved(variable);
152 152
153 153 auto &plottablesMap = variableIt->second;
154 154
155 155 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
156 156 plottableIt != plottableEnd;) {
157 157 ui->widget->removePlottable(plottableIt->second);
158 158 plottableIt = plottablesMap.erase(plottableIt);
159 159 }
160 160
161 161 impl->m_VariableToPlotMultiMap.erase(variableIt);
162 162 }
163 163
164 164 // Updates graph
165 165 ui->widget->replot();
166 166 }
167 167
168 168 QList<std::shared_ptr<Variable> > VisualizationGraphWidget::variables() const
169 169 {
170 170 auto variables = QList<std::shared_ptr<Variable> >{};
171 171 for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap);
172 172 it != std::cend(impl->m_VariableToPlotMultiMap); ++it) {
173 173 variables << it->first;
174 174 }
175 175
176 176 return variables;
177 177 }
178 178
179 179 void VisualizationGraphWidget::setYRange(const SqpRange &range)
180 180 {
181 181 ui->widget->yAxis->setRange(range.m_TStart, range.m_TEnd);
182 182 }
183 183
184 184 SqpRange VisualizationGraphWidget::graphRange() const noexcept
185 185 {
186 186 auto graphRange = ui->widget->xAxis->range();
187 187 return SqpRange{graphRange.lower, graphRange.upper};
188 188 }
189 189
190 190 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
191 191 {
192 192 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
193 193 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
194 194 ui->widget->replot();
195 195 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
196 196 }
197 197
198 198 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
199 199 {
200 200 if (visitor) {
201 201 visitor->visit(this);
202 202 }
203 203 else {
204 204 qCCritical(LOG_VisualizationGraphWidget())
205 205 << tr("Can't visit widget : the visitor is null");
206 206 }
207 207 }
208 208
209 209 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
210 210 {
211 211 /// @todo : for the moment, a graph can always accomodate a variable
212 212 Q_UNUSED(variable);
213 213 return true;
214 214 }
215 215
216 216 bool VisualizationGraphWidget::contains(const Variable &variable) const
217 217 {
218 218 // Finds the variable among the keys of the map
219 219 auto variablePtr = &variable;
220 220 auto findVariable
221 221 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
222 222
223 223 auto end = impl->m_VariableToPlotMultiMap.cend();
224 224 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
225 225 return it != end;
226 226 }
227 227
228 228 QString VisualizationGraphWidget::name() const
229 229 {
230 230 return impl->m_Name;
231 231 }
232 232
233 233 QMimeData *VisualizationGraphWidget::mimeData() const
234 234 {
235 235 auto mimeData = new QMimeData;
236 mimeData->setData(MIME_TYPE_GRAPH, QByteArray());
236 mimeData->setData(MIME_TYPE_GRAPH, QByteArray{});
237 237
238 238 return mimeData;
239 239 }
240 240
241 241 bool VisualizationGraphWidget::isDragAllowed() const
242 242 {
243 243 return true;
244 244 }
245 245
246 246 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
247 247 {
248 248 Q_UNUSED(event);
249 249
250 250 // Prevents that all variables will be removed from graph when it will be closed
251 251 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
252 252 emit variableAboutToBeRemoved(variableEntry.first);
253 253 }
254 254 }
255 255
256 256 void VisualizationGraphWidget::enterEvent(QEvent *event)
257 257 {
258 258 Q_UNUSED(event);
259 259 impl->m_RenderingDelegate->showGraphOverlay(true);
260 260 }
261 261
262 262 void VisualizationGraphWidget::leaveEvent(QEvent *event)
263 263 {
264 264 Q_UNUSED(event);
265 265 impl->m_RenderingDelegate->showGraphOverlay(false);
266 266 }
267 267
268 268 QCustomPlot &VisualizationGraphWidget::plot() noexcept
269 269 {
270 270 return *ui->widget;
271 271 }
272 272
273 273 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
274 274 {
275 275 QMenu graphMenu{};
276 276
277 277 // Iterates on variables (unique keys)
278 278 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
279 279 end = impl->m_VariableToPlotMultiMap.cend();
280 280 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
281 281 // 'Remove variable' action
282 282 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
283 283 [ this, var = it->first ]() { removeVariable(var); });
284 284 }
285 285
286 286 if (!graphMenu.isEmpty()) {
287 287 graphMenu.exec(QCursor::pos());
288 288 }
289 289 }
290 290
291 291 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
292 292 {
293 293 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: VisualizationGraphWidget::onRangeChanged")
294 294 << QThread::currentThread()->objectName() << "DoAcqui"
295 295 << impl->m_DoAcquisition;
296 296
297 297 auto graphRange = SqpRange{t1.lower, t1.upper};
298 298 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
299 299
300 300 if (impl->m_DoAcquisition) {
301 301 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
302 302
303 303 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
304 304 end = impl->m_VariableToPlotMultiMap.end();
305 305 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
306 306 variableUnderGraphVector.push_back(it->first);
307 307 }
308 308 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange,
309 309 !impl->m_IsCalibration);
310 310
311 311 if (!impl->m_IsCalibration) {
312 312 qCDebug(LOG_VisualizationGraphWidget())
313 313 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
314 314 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
315 315 emit synchronize(graphRange, oldGraphRange);
316 316 }
317 317 }
318 318 }
319 319
320 320 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
321 321 {
322 322 // Handles plot rendering when mouse is moving
323 323 impl->m_RenderingDelegate->onMouseMove(event);
324 324
325 325 VisualizationDragWidget::mouseMoveEvent(event);
326 326 }
327 327
328 328 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
329 329 {
330 330 auto zoomOrientations = QFlags<Qt::Orientation>{};
331 331
332 332 // Lambda that enables a zoom orientation if the key modifier related to this orientation
333 333 // has
334 334 // been pressed
335 335 auto enableOrientation
336 336 = [&zoomOrientations, event](const auto &orientation, const auto &modifier) {
337 337 auto orientationEnabled = event->modifiers().testFlag(modifier);
338 338 zoomOrientations.setFlag(orientation, orientationEnabled);
339 339 };
340 340 enableOrientation(Qt::Vertical, VERTICAL_ZOOM_MODIFIER);
341 341 enableOrientation(Qt::Horizontal, HORIZONTAL_ZOOM_MODIFIER);
342 342
343 343 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
344 344 }
345 345
346 346 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
347 347 {
348 348 impl->m_IsCalibration = event->modifiers().testFlag(Qt::ControlModifier);
349 349
350 350 plot().setInteraction(QCP::iRangeDrag, !event->modifiers().testFlag(Qt::AltModifier));
351 351
352 352 VisualizationDragWidget::mousePressEvent(event);
353 353 }
354 354
355 355 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
356 356 {
357 357 impl->m_IsCalibration = false;
358 358 }
359 359
360 360 void VisualizationGraphWidget::onDataCacheVariableUpdated()
361 361 {
362 362 auto graphRange = ui->widget->xAxis->range();
363 363 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
364 364
365 365 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
366 366 auto variable = variableEntry.first;
367 367 qCDebug(LOG_VisualizationGraphWidget())
368 368 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
369 369 qCDebug(LOG_VisualizationGraphWidget())
370 370 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
371 371 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
372 372 VisualizationGraphHelper::updateData(variableEntry.second, variable->dataSeries(),
373 373 variable->range());
374 374 }
375 375 }
376 376 }
377 377
378 378 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
379 379 const SqpRange &range)
380 380 {
381 381 auto it = impl->m_VariableToPlotMultiMap.find(variable);
382 382 if (it != impl->m_VariableToPlotMultiMap.end()) {
383 383 VisualizationGraphHelper::updateData(it->second, variable->dataSeries(), range);
384 384 }
385 385 }
@@ -1,294 +1,299
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 "Variable/VariableController.h"
9 9
10 10 #include "Common/MimeTypesDef.h"
11 11
12 12 #include "DragDropHelper.h"
13 13 #include "SqpApplication.h"
14 14
15 15 Q_LOGGING_CATEGORY(LOG_VisualizationTabWidget, "VisualizationTabWidget")
16 16
17 17 namespace {
18 18
19 19 /// Generates a default name for a new zone, according to the number of zones already displayed in
20 20 /// the tab
21 21 QString defaultZoneName(const QLayout &layout)
22 22 {
23 23 auto count = 0;
24 24 for (auto i = 0; i < layout.count(); ++i) {
25 25 if (dynamic_cast<VisualizationZoneWidget *>(layout.itemAt(i)->widget())) {
26 26 count++;
27 27 }
28 28 }
29 29
30 30 return QObject::tr("Zone %1").arg(count + 1);
31 31 }
32 32
33 33 /**
34 34 * Applies a function to all zones of the tab represented by its layout
35 35 * @param layout the layout that contains zones
36 36 * @param fun the function to apply to each zone
37 37 */
38 38 template <typename Fun>
39 39 void processZones(QLayout &layout, Fun fun)
40 40 {
41 41 for (auto i = 0; i < layout.count(); ++i) {
42 42 if (auto item = layout.itemAt(i)) {
43 43 if (auto visualizationZoneWidget
44 44 = dynamic_cast<VisualizationZoneWidget *>(item->widget())) {
45 45 fun(*visualizationZoneWidget);
46 46 }
47 47 }
48 48 }
49 49 }
50 50
51 51 } // namespace
52 52
53 53 struct VisualizationTabWidget::VisualizationTabWidgetPrivate {
54 54 explicit VisualizationTabWidgetPrivate(const QString &name) : m_Name{name} {}
55 55
56 56 QString m_Name;
57 57
58 58 void dropGraph(int index, VisualizationTabWidget *tabWidget);
59 59 void dropZone(int index, VisualizationTabWidget *tabWidget);
60 60 void dropVariables(const QList<std::shared_ptr<Variable> > &variables, int index,
61 61 VisualizationTabWidget *tabWidget);
62 62 };
63 63
64 64 VisualizationTabWidget::VisualizationTabWidget(const QString &name, QWidget *parent)
65 65 : QWidget{parent},
66 66 ui{new Ui::VisualizationTabWidget},
67 67 impl{spimpl::make_unique_impl<VisualizationTabWidgetPrivate>(name)}
68 68 {
69 69 ui->setupUi(this);
70 70
71 71 ui->dragDropContainer->setAcceptedMimeTypes(
72 72 {MIME_TYPE_GRAPH, MIME_TYPE_ZONE, MIME_TYPE_VARIABLE_LIST});
73 73 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccured, this,
74 74 &VisualizationTabWidget::dropMimeData);
75 75 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
76 76 return sqpApp->dragDropHelper().checkMimeDataForVisualization(mimeData,
77 77 ui->dragDropContainer);
78 78 });
79 79 sqpApp->dragDropHelper().addDragDropScrollArea(ui->scrollArea);
80 80
81 81 // Widget is deleted when closed
82 82 setAttribute(Qt::WA_DeleteOnClose);
83 83 }
84 84
85 85 VisualizationTabWidget::~VisualizationTabWidget()
86 86 {
87 87 sqpApp->dragDropHelper().removeDragDropScrollArea(ui->scrollArea);
88 88 delete ui;
89 89 }
90 90
91 91 void VisualizationTabWidget::addZone(VisualizationZoneWidget *zoneWidget)
92 92 {
93 93 ui->dragDropContainer->addDragWidget(zoneWidget);
94 94 }
95 95
96 96 void VisualizationTabWidget::insertZone(int index, VisualizationZoneWidget *zoneWidget)
97 97 {
98 98 ui->dragDropContainer->insertDragWidget(index, zoneWidget);
99 99 }
100 100
101 101 VisualizationZoneWidget *VisualizationTabWidget::createZone(std::shared_ptr<Variable> variable)
102 102 {
103 103 return createZone({variable}, -1);
104 104 }
105 105
106 106 VisualizationZoneWidget *
107 107 VisualizationTabWidget::createZone(const QList<std::shared_ptr<Variable> > &variables, int index)
108 108 {
109 109 auto zoneWidget = createEmptyZone(index);
110 110
111 111 // Creates a new graph into the zone
112 112 zoneWidget->createGraph(variables, index);
113 113
114 114 return zoneWidget;
115 115 }
116 116
117 117 VisualizationZoneWidget *VisualizationTabWidget::createEmptyZone(int index)
118 118 {
119 119 auto zoneWidget
120 120 = new VisualizationZoneWidget{defaultZoneName(*ui->dragDropContainer->layout()), this};
121 121 this->insertZone(index, zoneWidget);
122 122
123 123 return zoneWidget;
124 124 }
125 125
126 126 void VisualizationTabWidget::accept(IVisualizationWidgetVisitor *visitor)
127 127 {
128 128 if (visitor) {
129 129 visitor->visitEnter(this);
130 130
131 131 // Apply visitor to zone children: widgets different from zones are not visited (no action)
132 132 processZones(tabLayout(), [visitor](VisualizationZoneWidget &zoneWidget) {
133 133 zoneWidget.accept(visitor);
134 134 });
135 135
136 136 visitor->visitLeave(this);
137 137 }
138 138 else {
139 139 qCCritical(LOG_VisualizationTabWidget()) << tr("Can't visit widget : the visitor is null");
140 140 }
141 141 }
142 142
143 143 bool VisualizationTabWidget::canDrop(const Variable &variable) const
144 144 {
145 145 // A tab can always accomodate a variable
146 146 Q_UNUSED(variable);
147 147 return true;
148 148 }
149 149
150 150 bool VisualizationTabWidget::contains(const Variable &variable) const
151 151 {
152 152 Q_UNUSED(variable);
153 153 return false;
154 154 }
155 155
156 156 QString VisualizationTabWidget::name() const
157 157 {
158 158 return impl->m_Name;
159 159 }
160 160
161 161 void VisualizationTabWidget::closeEvent(QCloseEvent *event)
162 162 {
163 163 // Closes zones in the tab
164 164 processZones(tabLayout(), [](VisualizationZoneWidget &zoneWidget) { zoneWidget.close(); });
165 165
166 166 QWidget::closeEvent(event);
167 167 }
168 168
169 169 QLayout &VisualizationTabWidget::tabLayout() const noexcept
170 170 {
171 171 return *ui->dragDropContainer->layout();
172 172 }
173 173
174 174 void VisualizationTabWidget::dropMimeData(int index, const QMimeData *mimeData)
175 175 {
176 176 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
177 177 impl->dropGraph(index, this);
178 178 }
179 179 else if (mimeData->hasFormat(MIME_TYPE_ZONE)) {
180 180 impl->dropZone(index, this);
181 181 }
182 182 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
183 183 auto variables = sqpApp->variableController().variablesForMimeData(
184 184 mimeData->data(MIME_TYPE_VARIABLE_LIST));
185 185 impl->dropVariables(variables, index, this);
186 186 }
187 187 else {
188 188 qCWarning(LOG_VisualizationZoneWidget())
189 189 << tr("VisualizationTabWidget::dropMimeData, unknown MIME data received.");
190 190 }
191 191 }
192 192
193 193 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropGraph(
194 194 int index, VisualizationTabWidget *tabWidget)
195 195 {
196 196 auto &helper = sqpApp->dragDropHelper();
197 197
198 198 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
199 199 if (!graphWidget) {
200 200 qCWarning(LOG_VisualizationZoneWidget())
201 201 << tr("VisualizationTabWidget::dropGraph, drop aborted, the dropped graph is not "
202 202 "found or invalid.");
203 203 Q_ASSERT(false);
204 204 return;
205 205 }
206 206
207 207 auto parentDragDropContainer
208 208 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
209 209 if (!parentDragDropContainer) {
210 210 qCWarning(LOG_VisualizationZoneWidget())
211 211 << tr("VisualizationTabWidget::dropGraph, drop aborted, the parent container of "
212 212 "the dropped graph is not found.");
213 213 Q_ASSERT(false);
214 214 return;
215 215 }
216 216
217 217 auto nbGraph = parentDragDropContainer->countDragWidget();
218 218
219 219 const auto &variables = graphWidget->variables();
220 220
221 221 if (!variables.isEmpty()) {
222 222 // Abort the requests for the variables (if any)
223 223 // Commented, because it's not sure if it's needed or not
224 224 // for (const auto& var : variables)
225 225 //{
226 226 // sqpApp->variableController().onAbortProgressRequested(var);
227 227 //}
228 228
229 229 if (nbGraph == 1) {
230 230 // This is the only graph in the previous zone, close the zone
231 231 graphWidget->parentZoneWidget()->close();
232 232 }
233 233 else {
234 234 // Close the graph
235 235 graphWidget->close();
236 236 }
237 237
238 238 tabWidget->createZone(variables, index);
239 239 }
240 240 else {
241 241 // The graph is empty, create an empty zone and move the graph inside
242 242
243 243 auto parentZoneWidget = graphWidget->parentZoneWidget();
244 244
245 245 parentDragDropContainer->layout()->removeWidget(graphWidget);
246 246
247 247 auto zoneWidget = tabWidget->createEmptyZone(index);
248 248 zoneWidget->addGraph(graphWidget);
249 249
250 250 // Close the old zone if it was the only graph inside
251 251 if (nbGraph == 1) {
252 252 parentZoneWidget->close();
253 253 }
254 254 }
255 255 }
256 256
257 257 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropZone(
258 258 int index, VisualizationTabWidget *tabWidget)
259 259 {
260 260 auto &helper = sqpApp->dragDropHelper();
261 261
262 262 auto zoneWidget = qobject_cast<VisualizationZoneWidget *>(helper.getCurrentDragWidget());
263 263 if (!zoneWidget) {
264 264 qCWarning(LOG_VisualizationZoneWidget())
265 265 << tr("VisualizationTabWidget::dropZone, drop aborted, the dropped zone is not "
266 266 "found or invalid.");
267 267 Q_ASSERT(false);
268 268 return;
269 269 }
270 270
271 271 auto parentDragDropContainer
272 272 = qobject_cast<VisualizationDragDropContainer *>(zoneWidget->parentWidget());
273 273 if (!parentDragDropContainer) {
274 274 qCWarning(LOG_VisualizationZoneWidget())
275 275 << tr("VisualizationTabWidget::dropZone, drop aborted, the parent container of "
276 276 "the dropped zone is not found.");
277 277 Q_ASSERT(false);
278 278 return;
279 279 }
280 280
281 281 // Simple move of the zone, no variable operation associated
282 282 parentDragDropContainer->layout()->removeWidget(zoneWidget);
283 283 tabWidget->ui->dragDropContainer->insertDragWidget(index, zoneWidget);
284 284 }
285 285
286 286 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropVariables(
287 287 const QList<std::shared_ptr<Variable> > &variables, int index,
288 288 VisualizationTabWidget *tabWidget)
289 289 {
290 // Note: we are sure that there is a single and compatible variable here
291 // because the AcceptMimeDataFunction, set on the drop container, makes the check before the
292 // drop can occur.
290 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
291 // compatible variable here
292 if (variables.count() > 1) {
293 qCWarning(LOG_VisualizationZoneWidget())
294 << tr("VisualizationTabWidget::dropVariables, dropping multiple variables, operation "
295 "aborted.");
296 return;
297
293 298 tabWidget->createZone(variables, index);
294 299 }
@@ -1,484 +1,468
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 <Variable/Variable.h>
14 14 #include <Variable/VariableController.h>
15 15
16 16 #include <Visualization/operations/FindVariableOperation.h>
17 17
18 18 #include <DragDropHelper.h>
19 19 #include <QUuid>
20 20 #include <SqpApplication.h>
21 21 #include <cmath>
22 22
23 23 #include <QLayout>
24 24
25 25 Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget")
26 26
27 27 namespace {
28 28
29 29
30 30 /// Generates a default name for a new graph, according to the number of graphs already displayed in
31 31 /// the zone
32 32 QString defaultGraphName(const QLayout &layout)
33 33 {
34 34 auto count = 0;
35 35 for (auto i = 0; i < layout.count(); ++i) {
36 36 if (dynamic_cast<VisualizationGraphWidget *>(layout.itemAt(i)->widget())) {
37 37 count++;
38 38 }
39 39 }
40 40
41 41 return QObject::tr("Graph %1").arg(count + 1);
42 42 }
43 43
44 44 /**
45 45 * Applies a function to all graphs of the zone represented by its layout
46 46 * @param layout the layout that contains graphs
47 47 * @param fun the function to apply to each graph
48 48 */
49 49 template <typename Fun>
50 50 void processGraphs(QLayout &layout, Fun fun)
51 51 {
52 52 for (auto i = 0; i < layout.count(); ++i) {
53 53 if (auto item = layout.itemAt(i)) {
54 54 if (auto visualizationGraphWidget
55 55 = dynamic_cast<VisualizationGraphWidget *>(item->widget())) {
56 56 fun(*visualizationGraphWidget);
57 57 }
58 58 }
59 59 }
60 60 }
61 61
62 62 } // namespace
63 63
64 64 struct VisualizationZoneWidget::VisualizationZoneWidgetPrivate {
65 65
66 66 explicit VisualizationZoneWidgetPrivate()
67 67 : m_SynchronisationGroupId{QUuid::createUuid()},
68 68 m_Synchronizer{std::make_unique<QCustomPlotSynchronizer>()}
69 69 {
70 70 }
71 71 QUuid m_SynchronisationGroupId;
72 72 std::unique_ptr<IGraphSynchronizer> m_Synchronizer;
73 73
74 74 void dropGraph(int index, VisualizationZoneWidget *zoneWidget);
75 75 void dropVariables(const QList<std::shared_ptr<Variable> > &variables, int index,
76 76 VisualizationZoneWidget *zoneWidget);
77 77 };
78 78
79 79 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent)
80 80 : VisualizationDragWidget{parent},
81 81 ui{new Ui::VisualizationZoneWidget},
82 82 impl{spimpl::make_unique_impl<VisualizationZoneWidgetPrivate>()}
83 83 {
84 84 ui->setupUi(this);
85 85
86 86 ui->zoneNameLabel->setText(name);
87 87
88 88 ui->dragDropContainer->setAcceptedMimeTypes({MIME_TYPE_GRAPH, MIME_TYPE_VARIABLE_LIST});
89 89 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
90 90 return sqpApp->dragDropHelper().checkMimeDataForVisualization(mimeData,
91 91 ui->dragDropContainer);
92 92 });
93 93 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccured, this,
94 94 &VisualizationZoneWidget::dropMimeData);
95 95
96 96 // 'Close' options : widget is deleted when closed
97 97 setAttribute(Qt::WA_DeleteOnClose);
98 98 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close);
99 99 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
100 100
101 101 // Synchronisation id
102 102 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronizationGroupId",
103 103 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
104 104 }
105 105
106 106 VisualizationZoneWidget::~VisualizationZoneWidget()
107 107 {
108 108 delete ui;
109 109 }
110 110
111 111 void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget)
112 112 {
113 113 // Synchronize new graph with others in the zone
114 114 impl->m_Synchronizer->addGraph(*graphWidget);
115 115
116 116 ui->dragDropContainer->addDragWidget(graphWidget);
117 117 }
118 118
119 119 void VisualizationZoneWidget::insertGraph(int index, VisualizationGraphWidget *graphWidget)
120 120 {
121 121 // Synchronize new graph with others in the zone
122 122 impl->m_Synchronizer->addGraph(*graphWidget);
123 123
124 124 ui->dragDropContainer->insertDragWidget(index, graphWidget);
125 125 }
126 126
127 127 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable)
128 128 {
129 129 return createGraph(variable, -1);
130 130 }
131 131
132 132 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable,
133 133 int index)
134 134 {
135 135 auto graphWidget
136 136 = new VisualizationGraphWidget{defaultGraphName(*ui->dragDropContainer->layout()), this};
137 137
138 138
139 139 // Set graph properties
140 140 graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
141 141 graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT);
142 142
143 143
144 144 // Lambda to synchronize zone widget
145 145 auto synchronizeZoneWidget = [this, graphWidget](const SqpRange &graphRange,
146 146 const SqpRange &oldGraphRange) {
147 147
148 148 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
149 149 auto frameLayout = ui->dragDropContainer->layout();
150 150 for (auto i = 0; i < frameLayout->count(); ++i) {
151 151 auto graphChild
152 152 = dynamic_cast<VisualizationGraphWidget *>(frameLayout->itemAt(i)->widget());
153 153 if (graphChild && (graphChild != graphWidget)) {
154 154
155 155 auto graphChildRange = graphChild->graphRange();
156 156 switch (zoomType) {
157 157 case AcquisitionZoomType::ZoomIn: {
158 158 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
159 159 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
160 160 graphChildRange.m_TStart += deltaLeft;
161 161 graphChildRange.m_TEnd -= deltaRight;
162 162 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomIn");
163 163 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
164 164 << deltaLeft;
165 165 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
166 166 << deltaRight;
167 167 qCDebug(LOG_VisualizationZoneWidget())
168 168 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
169 169
170 170 break;
171 171 }
172 172
173 173 case AcquisitionZoomType::ZoomOut: {
174 174 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomOut");
175 175 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
176 176 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
177 177 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
178 178 << deltaLeft;
179 179 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
180 180 << deltaRight;
181 181 qCDebug(LOG_VisualizationZoneWidget())
182 182 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
183 183 graphChildRange.m_TStart -= deltaLeft;
184 184 graphChildRange.m_TEnd += deltaRight;
185 185 break;
186 186 }
187 187 case AcquisitionZoomType::PanRight: {
188 188 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanRight");
189 189 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
190 190 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
191 191 graphChildRange.m_TStart += deltaLeft;
192 192 graphChildRange.m_TEnd += deltaRight;
193 193 qCDebug(LOG_VisualizationZoneWidget())
194 194 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
195 195 break;
196 196 }
197 197 case AcquisitionZoomType::PanLeft: {
198 198 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanLeft");
199 199 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
200 200 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
201 201 graphChildRange.m_TStart -= deltaLeft;
202 202 graphChildRange.m_TEnd -= deltaRight;
203 203 break;
204 204 }
205 205 case AcquisitionZoomType::Unknown: {
206 206 qCDebug(LOG_VisualizationZoneWidget())
207 207 << tr("Impossible to synchronize: zoom type unknown");
208 208 break;
209 209 }
210 210 default:
211 211 qCCritical(LOG_VisualizationZoneWidget())
212 212 << tr("Impossible to synchronize: zoom type not take into account");
213 213 // No action
214 214 break;
215 215 }
216 216 graphChild->enableAcquisition(false);
217 217 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range before: ")
218 218 << graphChild->graphRange();
219 219 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range after : ")
220 220 << graphChildRange;
221 221 qCDebug(LOG_VisualizationZoneWidget())
222 222 << tr("TORM: child dt") << graphChildRange.m_TEnd - graphChildRange.m_TStart;
223 223 graphChild->setGraphRange(graphChildRange);
224 224 graphChild->enableAcquisition(true);
225 225 }
226 226 }
227 227 };
228 228
229 229 // connection for synchronization
230 230 connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget);
231 231 connect(graphWidget, &VisualizationGraphWidget::variableAdded, this,
232 232 &VisualizationZoneWidget::onVariableAdded);
233 233 connect(graphWidget, &VisualizationGraphWidget::variableAboutToBeRemoved, this,
234 234 &VisualizationZoneWidget::onVariableAboutToBeRemoved);
235 235
236 236 auto range = SqpRange{};
237 237
238 238 // Apply visitor to graph children
239 239 auto layout = ui->dragDropContainer->layout();
240 240 if (layout->count() > 0) {
241 241 // Case of a new graph in a existant zone
242 242 if (auto visualizationGraphWidget
243 243 = dynamic_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
244 244 range = visualizationGraphWidget->graphRange();
245 245 }
246 246 }
247 247 else {
248 248 // Case of a new graph as the first of the zone
249 249 range = variable->range();
250 250 }
251 251
252 252 this->insertGraph(index, graphWidget);
253 253
254 254 graphWidget->addVariable(variable, range);
255 255
256 256 // get y using variable range
257 257 if (auto dataSeries = variable->dataSeries()) {
258 258 dataSeries->lockRead();
259 259 auto valuesBounds
260 260 = dataSeries->valuesBounds(variable->range().m_TStart, variable->range().m_TEnd);
261 261 auto end = dataSeries->cend();
262 262 if (valuesBounds.first != end && valuesBounds.second != end) {
263 263 auto rangeValue = [](const auto &value) { return std::isnan(value) ? 0. : value; };
264 264
265 265 auto minValue = rangeValue(valuesBounds.first->minValue());
266 266 auto maxValue = rangeValue(valuesBounds.second->maxValue());
267 267
268 268 graphWidget->setYRange(SqpRange{minValue, maxValue});
269 269 }
270 270 dataSeries->unlock();
271 271 }
272 272
273 273 return graphWidget;
274 274 }
275 275
276 276 VisualizationGraphWidget *
277 277 VisualizationZoneWidget::createGraph(const QList<std::shared_ptr<Variable> > variables, int index)
278 278 {
279 279 if (variables.isEmpty()) {
280 280 return nullptr;
281 281 }
282 282
283 283 auto graphWidget = createGraph(variables.first(), index);
284 284 for (auto variableIt = variables.cbegin() + 1; variableIt != variables.cend(); ++variableIt) {
285 285 graphWidget->addVariable(*variableIt, graphWidget->graphRange());
286 286 }
287 287
288 288 return graphWidget;
289 289 }
290 290
291 291 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
292 292 {
293 293 if (visitor) {
294 294 visitor->visitEnter(this);
295 295
296 296 // Apply visitor to graph children: widgets different from graphs are not visited (no
297 297 // action)
298 298 processGraphs(
299 299 *ui->dragDropContainer->layout(),
300 300 [visitor](VisualizationGraphWidget &graphWidget) { graphWidget.accept(visitor); });
301 301
302 302 visitor->visitLeave(this);
303 303 }
304 304 else {
305 305 qCCritical(LOG_VisualizationZoneWidget()) << tr("Can't visit widget : the visitor is null");
306 306 }
307 307 }
308 308
309 309 bool VisualizationZoneWidget::canDrop(const Variable &variable) const
310 310 {
311 311 // A tab can always accomodate a variable
312 312 Q_UNUSED(variable);
313 313 return true;
314 314 }
315 315
316 316 bool VisualizationZoneWidget::contains(const Variable &variable) const
317 317 {
318 318 Q_UNUSED(variable);
319 319 return false;
320 320 }
321 321
322 322 QString VisualizationZoneWidget::name() const
323 323 {
324 324 return ui->zoneNameLabel->text();
325 325 }
326 326
327 327 QMimeData *VisualizationZoneWidget::mimeData() const
328 328 {
329 329 auto mimeData = new QMimeData;
330 mimeData->setData(MIME_TYPE_ZONE, QByteArray());
330 mimeData->setData(MIME_TYPE_ZONE, QByteArray{});
331 331
332 332 return mimeData;
333 333 }
334 334
335 335 bool VisualizationZoneWidget::isDragAllowed() const
336 336 {
337 337 return true;
338 338 }
339 339
340 340 void VisualizationZoneWidget::closeEvent(QCloseEvent *event)
341 341 {
342 342 // Closes graphs in the zone
343 343 processGraphs(*ui->dragDropContainer->layout(),
344 344 [](VisualizationGraphWidget &graphWidget) { graphWidget.close(); });
345 345
346 346 // Delete synchronization group from variable controller
347 347 QMetaObject::invokeMethod(&sqpApp->variableController(), "onRemoveSynchronizationGroupId",
348 348 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
349 349
350 350 QWidget::closeEvent(event);
351 351 }
352 352
353 353 void VisualizationZoneWidget::onVariableAdded(std::shared_ptr<Variable> variable)
354 354 {
355 355 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronized",
356 356 Qt::QueuedConnection, Q_ARG(std::shared_ptr<Variable>, variable),
357 357 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
358 358 }
359 359
360 360 void VisualizationZoneWidget::onVariableAboutToBeRemoved(std::shared_ptr<Variable> variable)
361 361 {
362 362 QMetaObject::invokeMethod(&sqpApp->variableController(), "desynchronize", Qt::QueuedConnection,
363 363 Q_ARG(std::shared_ptr<Variable>, variable),
364 364 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
365 365 }
366 366
367 367 void VisualizationZoneWidget::dropMimeData(int index, const QMimeData *mimeData)
368 368 {
369 369 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
370 370 impl->dropGraph(index, this);
371 371 }
372 372 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
373 373 auto variables = sqpApp->variableController().variablesForMimeData(
374 374 mimeData->data(MIME_TYPE_VARIABLE_LIST));
375 375 impl->dropVariables(variables, index, this);
376 376 }
377 377 else {
378 378 qCWarning(LOG_VisualizationZoneWidget())
379 379 << tr("VisualizationZoneWidget::dropMimeData, unknown MIME data received.");
380 380 }
381 381 }
382 382
383 383 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropGraph(
384 384 int index, VisualizationZoneWidget *zoneWidget)
385 385 {
386 386 auto &helper = sqpApp->dragDropHelper();
387 387
388 388 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
389 389 if (!graphWidget) {
390 390 qCWarning(LOG_VisualizationZoneWidget())
391 391 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the dropped graph is not "
392 392 "found or invalid.");
393 393 Q_ASSERT(false);
394 394 return;
395 395 }
396 396
397 397 auto parentDragDropContainer
398 398 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
399 399 if (!parentDragDropContainer) {
400 400 qCWarning(LOG_VisualizationZoneWidget())
401 401 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the parent container of "
402 402 "the dropped graph is not found.");
403 403 Q_ASSERT(false);
404 404 return;
405 405 }
406 406
407 407 const auto &variables = graphWidget->variables();
408 408
409 409 if (parentDragDropContainer != zoneWidget->ui->dragDropContainer && !variables.isEmpty()) {
410 410 // The drop didn't occur in the same zone
411 411
412 412 // Abort the requests for the variables (if any)
413 413 // Commented, because it's not sure if it's needed or not
414 414 // for (const auto& var : variables)
415 415 //{
416 416 // sqpApp->variableController().onAbortProgressRequested(var);
417 417 //}
418 418
419 419 auto previousParentZoneWidget = graphWidget->parentZoneWidget();
420 420 auto nbGraph = parentDragDropContainer->countDragWidget();
421 421 if (nbGraph == 1) {
422 422 // This is the only graph in the previous zone, close the zone
423 423 previousParentZoneWidget->close();
424 424 }
425 425 else {
426 426 // Close the graph
427 427 graphWidget->close();
428 428 }
429 429
430 430 // Creates the new graph in the zone
431 431 zoneWidget->createGraph(variables, index);
432 432 }
433 433 else {
434 434 // The drop occurred in the same zone or the graph is empty
435 435 // Simple move of the graph, no variable operation associated
436 436 parentDragDropContainer->layout()->removeWidget(graphWidget);
437 437
438 438 if (variables.isEmpty() && parentDragDropContainer != zoneWidget->ui->dragDropContainer) {
439 439 // The graph is empty and dropped in a different zone.
440 440 // Take the range of the first graph in the zone (if existing).
441 441 auto layout = zoneWidget->ui->dragDropContainer->layout();
442 442 if (layout->count() > 0) {
443 443 if (auto visualizationGraphWidget
444 444 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
445 445 graphWidget->setGraphRange(visualizationGraphWidget->graphRange());
446 446 }
447 447 }
448 448 }
449 449
450 450 zoneWidget->ui->dragDropContainer->insertDragWidget(index, graphWidget);
451 451 }
452 452 }
453 453
454 454 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropVariables(
455 455 const QList<std::shared_ptr<Variable> > &variables, int index,
456 456 VisualizationZoneWidget *zoneWidget)
457 457 {
458 // Search for the top level VisualizationWidget
459 auto parent = zoneWidget->parentWidget();
460 while (parent && qobject_cast<VisualizationWidget *>(parent) == nullptr) {
461 parent = parent->parentWidget();
462 }
463
464 if (!parent) {
458 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
459 // compatible variable here
460 if (variables.count() > 1) {
465 461 qCWarning(LOG_VisualizationZoneWidget())
466 << tr("VisualizationZoneWidget::dropVariables, drop aborted, the parent "
467 "VisualizationWidget cannot be found.");
468 Q_ASSERT(false);
462 << tr("VisualizationZoneWidget::dropVariables, dropping multiple variables, operation "
463 "aborted.");
469 464 return;
470 465 }
471 466
472 auto visualizationWidget = static_cast<VisualizationWidget *>(parent);
473
474 // Search for the first variable which can be dropped
475 for (auto variable : variables) {
476 FindVariableOperation findVariableOperation{variable};
477 visualizationWidget->accept(&findVariableOperation);
478 auto variableContainers = findVariableOperation.result();
479 if (variableContainers.empty()) {
480 zoneWidget->createGraph(variable, index);
481 break;
482 }
483 }
467 zoneWidget->createGraph({variable}, index);
484 468 }
@@ -1,33 +1,49
1 1 <?xml version="1.0" encoding="UTF-8"?>
2 2 <ui version="4.0">
3 3 <class>DataSourceWidget</class>
4 4 <widget class="QWidget" name="DataSourceWidget">
5 5 <property name="geometry">
6 6 <rect>
7 7 <x>0</x>
8 8 <y>0</y>
9 9 <width>400</width>
10 10 <height>300</height>
11 11 </rect>
12 12 </property>
13 13 <property name="windowTitle">
14 14 <string>Data sources</string>
15 15 </property>
16 16 <layout class="QGridLayout" name="gridLayout">
17 17 <item row="0" column="0">
18 18 <widget class="QLineEdit" name="filterLineEdit"/>
19 19 </item>
20 20 <item row="1" column="0">
21 <widget class="QTreeWidget" name="treeWidget">
21 <widget class="DataSourceTreeWidget" name="treeWidget">
22 <property name="dragEnabled">
23 <bool>true</bool>
24 </property>
25 <property name="dragDropMode">
26 <enum>QAbstractItemView::DragOnly</enum>
27 </property>
28 <property name="selectionMode">
29 <enum>QAbstractItemView::ExtendedSelection</enum>
30 </property>
22 31 <column>
23 32 <property name="text">
24 33 <string notr="true">1</string>
25 34 </property>
26 35 </column>
27 36 </widget>
28 37 </item>
29 38 </layout>
30 39 </widget>
40 <customwidgets>
41 <customwidget>
42 <class>DataSourceTreeWidget</class>
43 <extends>QTreeWidget</extends>
44 <header>DataSource/DataSourceTreeWidget.h</header>
45 </customwidget>
46 </customwidgets>
31 47 <resources/>
32 48 <connections/>
33 49 </ui>
General Comments 0
You need to be logged in to leave comments. Login now