diff --git a/app/src/MainWindow.cpp b/app/src/MainWindow.cpp index d89ff54..6fbd08b 100644 --- a/app/src/MainWindow.cpp +++ b/app/src/MainWindow.cpp @@ -183,12 +183,10 @@ MainWindow::MainWindow(QWidget *parent) connect(timeWidget, SIGNAL(timeUpdated(SqpDateTime)), &sqpApp->timeController(), SLOT(onTimeToUpdate(SqpDateTime))); - qRegisterMetaType(); connect(&sqpApp->timeController(), SIGNAL(timeUpdated(SqpDateTime)), &sqpApp->variableController(), SLOT(onDateTimeOnSelection(SqpDateTime))); // Widgets / widgets connections - qRegisterMetaType >(); // For the following connections, we use DirectConnection to allow each widget that can // potentially attach a menu to the variable's menu to do so before this menu is displayed. diff --git a/core/include/Common/MetaTypes.h b/core/include/Common/MetaTypes.h new file mode 100644 index 0000000..1fb61b0 --- /dev/null +++ b/core/include/Common/MetaTypes.h @@ -0,0 +1,46 @@ +#ifndef SCIQLOP_METATYPES_H +#define SCIQLOP_METATYPES_H + +#include + +/** + * Struct used to create an instance that registers a type in Qt for signals / slots mechanism + * @tparam T the type to register + */ +template +struct MetaTypeRegistry { + explicit MetaTypeRegistry() { qRegisterMetaType(); } +}; + +/** + * This macro can be used to : + * - declare a type as a Qt meta type + * - and register it (through a static instance) at the launch of SciQlop, so it can be passed in + * Qt signals/slots + * + * It can be used both in .h or in .cpp files + * + * @param NAME name of the instance under which the type will be registered (in uppercase) + * @param TYPE type to register + * + * Example: + * ~~~cpp + * // The following macro : + * // - declares std::shared_ptr as a Qt meta type + * // - registers it through an instance named VAR_SHARED_PTR + * SCIQLOP_REGISTER_META_TYPE(VAR_SHARED_PTR, std::shared_ptr) + * + * // The following macro : + * // - declares a raw pointer of Variable as a Qt meta type + * // - registers it through an instance named VAR_RAW_PTR + * SCIQLOP_REGISTER_META_TYPE(VAR_RAW_PTR, Variable*) + * ~~~ + * + */ +// clang-format off +#define SCIQLOP_REGISTER_META_TYPE(NAME, TYPE) \ +Q_DECLARE_METATYPE(TYPE) \ +const auto NAME = MetaTypeRegistry{}; \ +// clang-format on + +#endif // SCIQLOP_METATYPES_H diff --git a/core/include/Data/DataSeries.h b/core/include/Data/DataSeries.h index 46ee991..e94b9c4 100644 --- a/core/include/Data/DataSeries.h +++ b/core/include/Data/DataSeries.h @@ -26,12 +26,14 @@ class DataSeries : public IDataSeries { public: /// @sa IDataSeries::xAxisData() std::shared_ptr > xAxisData() override { return m_XAxisData; } + const std::shared_ptr > xAxisData() const { return m_XAxisData; } /// @sa IDataSeries::xAxisUnit() Unit xAxisUnit() const override { return m_XAxisUnit; } /// @return the values dataset - std::shared_ptr > valuesData() const { return m_ValuesData; } + std::shared_ptr > valuesData() { return m_ValuesData; } + const std::shared_ptr > valuesData() const { return m_ValuesData; } /// @sa IDataSeries::valuesUnit() Unit valuesUnit() const override { return m_ValuesUnit; } @@ -60,6 +62,27 @@ protected: { } + /// Copy ctor + explicit DataSeries(const DataSeries &other) + : m_XAxisData{std::make_shared >(*other.m_XAxisData)}, + m_XAxisUnit{other.m_XAxisUnit}, + m_ValuesData{std::make_shared >(*other.m_ValuesData)}, + m_ValuesUnit{other.m_ValuesUnit} + { + } + + /// Assignment operator + template + DataSeries &operator=(DataSeries other) + { + std::swap(m_XAxisData, other.m_XAxisData); + std::swap(m_XAxisUnit, other.m_XAxisUnit); + std::swap(m_ValuesData, other.m_ValuesData); + std::swap(m_ValuesUnit, other.m_ValuesUnit); + + return *this; + } + private: std::shared_ptr > m_XAxisData; Unit m_XAxisUnit; diff --git a/core/include/Data/IDataProvider.h b/core/include/Data/IDataProvider.h index cde7f5e..6f4b5b6 100644 --- a/core/include/Data/IDataProvider.h +++ b/core/include/Data/IDataProvider.h @@ -5,6 +5,8 @@ #include +#include + #include class DataProviderParameters; @@ -24,7 +26,7 @@ class IDataProvider : public QObject { public: virtual ~IDataProvider() noexcept = default; - virtual std::unique_ptr + virtual std::shared_ptr retrieveData(const DataProviderParameters ¶meters) const = 0; @@ -33,7 +35,8 @@ public: signals: void dataProvided(std::shared_ptr dateSerie, const SqpDateTime &dateTime); }; + // Required for using shared_ptr in signals/slots -Q_DECLARE_METATYPE(std::shared_ptr) +SCIQLOP_REGISTER_META_TYPE(IDATAPROVIDER_PTR_REGISTRY, std::shared_ptr) #endif // SCIQLOP_IDATAPROVIDER_H diff --git a/core/include/Data/IDataSeries.h b/core/include/Data/IDataSeries.h index bbea31f..af1b2b2 100644 --- a/core/include/Data/IDataSeries.h +++ b/core/include/Data/IDataSeries.h @@ -1,10 +1,10 @@ #ifndef SCIQLOP_IDATASERIES_H #define SCIQLOP_IDATASERIES_H +#include #include -#include #include template @@ -41,14 +41,19 @@ public: /// Returns the x-axis dataset virtual std::shared_ptr > xAxisData() = 0; + /// Returns the x-axis dataset (as const) + virtual const std::shared_ptr > xAxisData() const = 0; + virtual Unit xAxisUnit() const = 0; virtual Unit valuesUnit() const = 0; virtual void merge(IDataSeries *dataSeries) = 0; + + virtual std::unique_ptr clone() const = 0; }; // Required for using shared_ptr in signals/slots -Q_DECLARE_METATYPE(std::shared_ptr) +SCIQLOP_REGISTER_META_TYPE(IDATASERIES_PTR_REGISTRY, std::shared_ptr) #endif // SCIQLOP_IDATASERIES_H diff --git a/core/include/Data/ScalarSeries.h b/core/include/Data/ScalarSeries.h index 69d68e1..03d69cc 100644 --- a/core/include/Data/ScalarSeries.h +++ b/core/include/Data/ScalarSeries.h @@ -23,6 +23,8 @@ public: * @param value the value data */ void setData(int index, double x, double value) noexcept; + + std::unique_ptr clone() const; }; #endif // SCIQLOP_SCALARSERIES_H diff --git a/core/include/Data/SqpDateTime.h b/core/include/Data/SqpDateTime.h index c0f73c1..0a936e2 100644 --- a/core/include/Data/SqpDateTime.h +++ b/core/include/Data/SqpDateTime.h @@ -6,6 +6,8 @@ #include #include +#include + /** * @brief The SqpDateTime struct holds the information of time parameters */ @@ -37,6 +39,6 @@ inline QDebug operator<<(QDebug d, SqpDateTime obj) } // Required for using shared_ptr in signals/slots -Q_DECLARE_METATYPE(SqpDateTime) +SCIQLOP_REGISTER_META_TYPE(SQPDATETIME_REGISTRY, SqpDateTime) #endif // SCIQLOP_SQPDATETIME_H diff --git a/core/include/Variable/Variable.h b/core/include/Variable/Variable.h index 21ea2e7..1bd730c 100644 --- a/core/include/Variable/Variable.h +++ b/core/include/Variable/Variable.h @@ -3,10 +3,10 @@ #include - #include #include +#include #include Q_DECLARE_LOGGING_CATEGORY(LOG_Variable) @@ -36,10 +36,9 @@ public: bool contains(const SqpDateTime &dateTime); bool intersect(const SqpDateTime &dateTime); - void setDataSeries(std::unique_ptr dataSeries) noexcept; public slots: - void onAddDataSeries(std::shared_ptr dataSeries) noexcept; + void setDataSeries(std::shared_ptr dataSeries) noexcept; signals: void updated(); @@ -50,6 +49,6 @@ private: }; // Required for using shared_ptr in signals/slots -Q_DECLARE_METATYPE(std::shared_ptr) +SCIQLOP_REGISTER_META_TYPE(VARIABLE_PTR_REGISTRY, std::shared_ptr) #endif // SCIQLOP_VARIABLE_H diff --git a/core/include/Variable/VariableModel.h b/core/include/Variable/VariableModel.h index 07f60fc..02b204b 100644 --- a/core/include/Variable/VariableModel.h +++ b/core/include/Variable/VariableModel.h @@ -30,7 +30,7 @@ public: */ std::shared_ptr createVariable(const QString &name, const SqpDateTime &dateTime, - std::unique_ptr defaultDataSeries) noexcept; + std::shared_ptr defaultDataSeries) noexcept; std::shared_ptr variable(int index) const; diff --git a/core/src/Data/ScalarSeries.cpp b/core/src/Data/ScalarSeries.cpp index 90718a5..2673da9 100644 --- a/core/src/Data/ScalarSeries.cpp +++ b/core/src/Data/ScalarSeries.cpp @@ -11,3 +11,8 @@ void ScalarSeries::setData(int index, double x, double value) noexcept xAxisData()->setData(index, x); valuesData()->setData(index, value); } + +std::unique_ptr ScalarSeries::clone() const +{ + return std::make_unique(*this); +} diff --git a/core/src/Variable/Variable.cpp b/core/src/Variable/Variable.cpp index 899ca31..7f98687 100644 --- a/core/src/Variable/Variable.cpp +++ b/core/src/Variable/Variable.cpp @@ -55,16 +55,18 @@ void Variable::setDateTime(const SqpDateTime &dateTime) noexcept impl->m_DateTime = dateTime; } -void Variable::setDataSeries(std::unique_ptr dataSeries) noexcept +void Variable::setDataSeries(std::shared_ptr dataSeries) noexcept { - if (!impl->m_DataSeries) { - impl->m_DataSeries = std::move(dataSeries); + if (!dataSeries) { + /// @todo ALX : log + return; } -} -void Variable::onAddDataSeries(std::shared_ptr dataSeries) noexcept -{ - if (impl->m_DataSeries) { + // Inits the data series of the variable + if (!impl->m_DataSeries) { + impl->m_DataSeries = dataSeries->clone(); + } + else { impl->m_DataSeries->merge(dataSeries.get()); emit updated(); diff --git a/core/src/Variable/VariableController.cpp b/core/src/Variable/VariableController.cpp index b348b95..41021cb 100644 --- a/core/src/Variable/VariableController.cpp +++ b/core/src/Variable/VariableController.cpp @@ -21,7 +21,7 @@ namespace { /// @todo Generates default dataseries, according to the provider passed in parameter. This method /// will be deleted when the timerange is recovered from SciQlop -std::unique_ptr generateDefaultDataSeries(const IDataProvider &provider, +std::shared_ptr generateDefaultDataSeries(const IDataProvider &provider, const SqpDateTime &dateTime) noexcept { auto parameters = DataProviderParameters{dateTime}; @@ -104,10 +104,8 @@ void VariableController::createVariable(const QString &name, // store the provider impl->m_VariableToProviderMap[newVariable] = provider; - qRegisterMetaType >(); - qRegisterMetaType(); connect(provider.get(), &IDataProvider::dataProvided, newVariable.get(), - &Variable::onAddDataSeries); + &Variable::setDataSeries); // store in cache diff --git a/core/src/Variable/VariableModel.cpp b/core/src/Variable/VariableModel.cpp index e92a27a..f03350b 100644 --- a/core/src/Variable/VariableModel.cpp +++ b/core/src/Variable/VariableModel.cpp @@ -54,7 +54,7 @@ VariableModel::VariableModel(QObject *parent) std::shared_ptr VariableModel::createVariable(const QString &name, const SqpDateTime &dateTime, - std::unique_ptr defaultDataSeries) noexcept + std::shared_ptr defaultDataSeries) noexcept { auto insertIndex = rowCount(); beginInsertRows({}, insertIndex, insertIndex); diff --git a/gui/include/Visualization/VisualizationTabWidget.h b/gui/include/Visualization/VisualizationTabWidget.h index 6c25cc8..d4816ef 100644 --- a/gui/include/Visualization/VisualizationTabWidget.h +++ b/gui/include/Visualization/VisualizationTabWidget.h @@ -41,6 +41,9 @@ public: QString name() const override; private: + /// @return the layout of tab in which zones are added + QLayout &tabLayout() const noexcept; + Ui::VisualizationTabWidget *ui; class VisualizationTabWidgetPrivate; diff --git a/gui/src/SqpApplication.cpp b/gui/src/SqpApplication.cpp index 4a57fa0..4c221ba 100644 --- a/gui/src/SqpApplication.cpp +++ b/gui/src/SqpApplication.cpp @@ -23,14 +23,12 @@ public: // /////////////////////////////// // // VariableController <-> DataSourceController - qRegisterMetaType >(); connect(m_DataSourceController.get(), SIGNAL(variableCreationRequested(const QString &, std::shared_ptr)), m_VariableController.get(), SLOT(createVariable(const QString &, std::shared_ptr))); // VariableController <-> VisualizationController - qRegisterMetaType >(); connect(m_VariableController.get(), SIGNAL(variableCreated(std::shared_ptr)), m_VisualizationController.get(), SIGNAL(variableCreated(std::shared_ptr))); diff --git a/gui/src/Visualization/VisualizationTabWidget.cpp b/gui/src/Visualization/VisualizationTabWidget.cpp index 8b404dd..6040c45 100644 --- a/gui/src/Visualization/VisualizationTabWidget.cpp +++ b/gui/src/Visualization/VisualizationTabWidget.cpp @@ -48,12 +48,12 @@ VisualizationTabWidget::~VisualizationTabWidget() void VisualizationTabWidget::addZone(VisualizationZoneWidget *zoneWidget) { - this->layout()->addWidget(zoneWidget); + tabLayout().addWidget(zoneWidget); } VisualizationZoneWidget *VisualizationTabWidget::createZone(std::shared_ptr variable) { - auto zoneWidget = new VisualizationZoneWidget{defaultZoneName(*layout()), this}; + auto zoneWidget = new VisualizationZoneWidget{defaultZoneName(tabLayout()), this}; this->addZone(zoneWidget); // Creates a new graph into the zone @@ -68,8 +68,9 @@ void VisualizationTabWidget::accept(IVisualizationWidgetVisitor *visitor) visitor->visitEnter(this); // Apply visitor to zone children - for (auto i = 0; i < layout()->count(); ++i) { - if (auto item = layout()->itemAt(i)) { + auto &layout = tabLayout(); + for (auto i = 0; i < layout.count(); ++i) { + if (auto item = layout.itemAt(i)) { // Widgets different from zones are not visited (no action) if (auto visualizationZoneWidget = dynamic_cast(item->widget())) { @@ -96,3 +97,8 @@ QString VisualizationTabWidget::name() const { return impl->m_Name; } + +QLayout &VisualizationTabWidget::tabLayout() const noexcept +{ + return *ui->scrollAreaWidgetContents->layout(); +} diff --git a/gui/src/Visualization/VisualizationZoneWidget.cpp b/gui/src/Visualization/VisualizationZoneWidget.cpp index 2a4eb95..7fe59b7 100644 --- a/gui/src/Visualization/VisualizationZoneWidget.cpp +++ b/gui/src/Visualization/VisualizationZoneWidget.cpp @@ -10,6 +10,9 @@ Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget") namespace { +/// Minimum height for graph added in zones (in pixels) +const auto GRAPH_MINIMUM_HEIGHT = 300; + /// Generates a default name for a new graph, according to the number of graphs already displayed in /// the zone QString defaultGraphName(const QLayout &layout) @@ -53,6 +56,11 @@ VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptrvisualizationZoneFrame->layout()), this}; + + // Set graph properties + graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding); + graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT); + this->addGraph(graphWidget); graphWidget->addVariable(variable); diff --git a/gui/src/Visualization/operations/GenerateVariableMenuOperation.cpp b/gui/src/Visualization/operations/GenerateVariableMenuOperation.cpp index 2bd5ae2..37f1955 100644 --- a/gui/src/Visualization/operations/GenerateVariableMenuOperation.cpp +++ b/gui/src/Visualization/operations/GenerateVariableMenuOperation.cpp @@ -18,6 +18,18 @@ struct GenerateVariableMenuOperation::GenerateVariableMenuOperationPrivate { { } + void visitRootEnter() + { + // Creates the root menu + m_MenuBuilder.addMenu(QObject::tr("Plot")); + } + + void visitRootLeave() + { + // Closes the root menu + m_MenuBuilder.closeMenu(); + } + void visitNodeEnter(const IVisualizationWidget &container) { // Opens a new menu associated to the node @@ -60,12 +72,16 @@ void GenerateVariableMenuOperation::visitEnter(VisualizationWidget *widget) { // VisualizationWidget is not intended to accommodate a variable Q_UNUSED(widget) + + impl->visitRootEnter(); } void GenerateVariableMenuOperation::visitLeave(VisualizationWidget *widget) { // VisualizationWidget is not intended to accommodate a variable Q_UNUSED(widget) + + impl->visitRootLeave(); } void GenerateVariableMenuOperation::visitEnter(VisualizationTabWidget *tabWidget) diff --git a/gui/ui/Visualization/VisualizationTabWidget.ui b/gui/ui/Visualization/VisualizationTabWidget.ui index 96002e1..c39c764 100644 --- a/gui/ui/Visualization/VisualizationTabWidget.ui +++ b/gui/ui/Visualization/VisualizationTabWidget.ui @@ -13,7 +13,47 @@ Form - + + + 0 + + + 0 + + + 0 + + + 0 + + + + + background-color: transparent; + + + QFrame::NoFrame + + + QFrame::Sunken + + + true + + + + + 0 + 0 + 400 + 300 + + + + + + + diff --git a/plugins/mockplugin/include/CosinusProvider.h b/plugins/mockplugin/include/CosinusProvider.h index 218623a..bd5be77 100644 --- a/plugins/mockplugin/include/CosinusProvider.h +++ b/plugins/mockplugin/include/CosinusProvider.h @@ -13,7 +13,7 @@ Q_DECLARE_LOGGING_CATEGORY(LOG_CosinusProvider) class CosinusProvider : public IDataProvider { public: /// @sa IDataProvider::retrieveData() - std::unique_ptr + std::shared_ptr retrieveData(const DataProviderParameters ¶meters) const override; void requestDataLoading(const QVector &dateTimeList) override; diff --git a/plugins/mockplugin/src/CosinusProvider.cpp b/plugins/mockplugin/src/CosinusProvider.cpp index ee66ccf..0f4ae0b 100644 --- a/plugins/mockplugin/src/CosinusProvider.cpp +++ b/plugins/mockplugin/src/CosinusProvider.cpp @@ -9,47 +9,11 @@ Q_LOGGING_CATEGORY(LOG_CosinusProvider, "CosinusProvider") -std::unique_ptr +std::shared_ptr CosinusProvider::retrieveData(const DataProviderParameters ¶meters) const { auto dateTime = parameters.m_Time; - // Gets the timerange from the parameters - auto start = dateTime.m_TStart; - auto end = dateTime.m_TEnd; - - - // We assure that timerange is valid - if (end < start) { - std::swap(start, end); - } - - // Generates scalar series containing cosinus values (one value per second) - auto scalarSeries - = std::make_unique(end - start, Unit{QStringLiteral("t"), true}, Unit{}); - - auto dataIndex = 0; - for (auto time = start; time < end; ++time, ++dataIndex) { - scalarSeries->setData(dataIndex, time, std::cos(time)); - } - - return scalarSeries; -} - -void CosinusProvider::requestDataLoading(const QVector &dateTimeList) -{ - // NOTE: Try to use multithread if possible - for (const auto &dateTime : dateTimeList) { - - auto scalarSeries = this->retrieveDataSeries(dateTime); - - emit dataProvided(scalarSeries, dateTime); - } -} - - -std::shared_ptr CosinusProvider::retrieveDataSeries(const SqpDateTime &dateTime) -{ auto dataIndex = 0; // Gets the timerange from the parameters @@ -72,3 +36,12 @@ std::shared_ptr CosinusProvider::retrieveDataSeries(const SqpDateTi } return scalarSeries; } + +void CosinusProvider::requestDataLoading(const QVector &dateTimeList) +{ + // NOTE: Try to use multithread if possible + for (const auto &dateTime : dateTimeList) { + auto scalarSeries = this->retrieveData(DataProviderParameters{dateTime}); + emit dataProvided(scalarSeries, dateTime); + } +}