diff --git a/app/src/MainWindow.cpp b/app/src/MainWindow.cpp index e9ecc3b..4e11f1c 100644 --- a/app/src/MainWindow.cpp +++ b/app/src/MainWindow.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -33,6 +34,7 @@ #include #include #include +#include #include //#include @@ -75,89 +77,96 @@ MainWindow::MainWindow(QWidget *parent) m_Ui->splitter->setCollapsible(LEFTINSPECTORSIDEPANESPLITTERINDEX, false); m_Ui->splitter->setCollapsible(RIGHTINSPECTORSIDEPANESPLITTERINDEX, false); - // NOTE: These lambda could be factorized. Be careful of theirs parameters - // Lambda that defines what's happened when clicking on the leftSidePaneInspector open button - auto openLeftInspector = [this](bool checked) { - // Update of the last opened geometry - if (checked) { - impl->m_LastOpenLeftInspectorSize = m_Ui->leftMainInspectorWidget->size(); - } + auto leftSidePane = m_Ui->leftInspectorSidePane->sidePane(); + auto openLeftInspectorAction = new QAction{QIcon{ + ":/icones/previous.png", + }, + tr("Show/hide the left inspector"), this}; - auto startSize = impl->m_LastOpenLeftInspectorSize; - auto endSize = startSize; - endSize.setWidth(0); - auto currentSizes = m_Ui->splitter->sizes(); - if (checked) { - // adjust sizes individually here, e.g. - currentSizes[LEFTMAININSPECTORWIDGETSPLITTERINDEX] - -= impl->m_LastOpenLeftInspectorSize.width(); - currentSizes[VIEWPLITTERINDEX] += impl->m_LastOpenLeftInspectorSize.width(); - m_Ui->splitter->setSizes(currentSizes); - } - else { - // adjust sizes individually here, e.g. - currentSizes[LEFTMAININSPECTORWIDGETSPLITTERINDEX] - += impl->m_LastOpenLeftInspectorSize.width(); - currentSizes[VIEWPLITTERINDEX] -= impl->m_LastOpenLeftInspectorSize.width(); - m_Ui->splitter->setSizes(currentSizes); - } + auto spacerLeftTop = new QWidget{}; + spacerLeftTop->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - }; + auto spacerLeftBottom = new QWidget{}; + spacerLeftBottom->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + + leftSidePane->addWidget(spacerLeftTop); + leftSidePane->addAction(openLeftInspectorAction); + leftSidePane->addWidget(spacerLeftBottom); + + + auto rightSidePane = m_Ui->rightInspectorSidePane->sidePane(); + auto openRightInspectorAction = new QAction{QIcon{ + ":/icones/next.png", + }, + tr("Show/hide the right inspector"), this}; + + auto spacerRightTop = new QWidget{}; + spacerRightTop->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + + auto spacerRightBottom = new QWidget{}; + spacerRightBottom->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + + rightSidePane->addWidget(spacerRightTop); + rightSidePane->addAction(openRightInspectorAction); + rightSidePane->addWidget(spacerRightBottom); + + openLeftInspectorAction->setCheckable(true); + openRightInspectorAction->setCheckable(true); + + auto openInspector = [this](bool checked, bool right, auto action) { + + action->setIcon(QIcon{(checked xor right) ? ":/icones/next.png" : ":/icones/previous.png"}); - // Lambda that defines what's happened when clicking on the SidePaneInspector open button - auto openRightInspector = [this](bool checked) { + auto &lastInspectorSize + = right ? impl->m_LastOpenRightInspectorSize : impl->m_LastOpenLeftInspectorSize; + + auto nextInspectorSize = right ? m_Ui->rightMainInspectorWidget->size() + : m_Ui->leftMainInspectorWidget->size(); // Update of the last opened geometry if (checked) { - impl->m_LastOpenRightInspectorSize = m_Ui->rightMainInspectorWidget->size(); + lastInspectorSize = nextInspectorSize; } - auto startSize = impl->m_LastOpenRightInspectorSize; + auto startSize = lastInspectorSize; auto endSize = startSize; endSize.setWidth(0); + auto splitterInspectorIndex + = right ? RIGHTMAININSPECTORWIDGETSPLITTERINDEX : LEFTMAININSPECTORWIDGETSPLITTERINDEX; + auto currentSizes = m_Ui->splitter->sizes(); if (checked) { // adjust sizes individually here, e.g. - currentSizes[RIGHTMAININSPECTORWIDGETSPLITTERINDEX] - -= impl->m_LastOpenRightInspectorSize.width(); - currentSizes[VIEWPLITTERINDEX] += impl->m_LastOpenRightInspectorSize.width(); + currentSizes[splitterInspectorIndex] -= lastInspectorSize.width(); + currentSizes[VIEWPLITTERINDEX] += lastInspectorSize.width(); m_Ui->splitter->setSizes(currentSizes); } else { // adjust sizes individually here, e.g. - currentSizes[RIGHTMAININSPECTORWIDGETSPLITTERINDEX] - += impl->m_LastOpenRightInspectorSize.width(); - currentSizes[VIEWPLITTERINDEX] -= impl->m_LastOpenRightInspectorSize.width(); + currentSizes[splitterInspectorIndex] += lastInspectorSize.width(); + currentSizes[VIEWPLITTERINDEX] -= lastInspectorSize.width(); m_Ui->splitter->setSizes(currentSizes); } }; - QToolBar *leftSidePane = m_Ui->leftInspectorSidePane->sidePane(); - auto openLeftInspectorAction = leftSidePane->addAction( - QIcon{ - ":/icones/openInspector.png", - }, - tr("Show/hide the left inspector"), openLeftInspector); - - openLeftInspectorAction->setCheckable(true); - - auto rightSidePane = m_Ui->rightInspectorSidePane->sidePane(); - auto openRightInspectorAction = rightSidePane->addAction( - QIcon{ - ":/icones/openInspector.png", - }, - tr("Show/hide the right inspector"), openRightInspector); - - openRightInspectorAction->setCheckable(true); + connect(openLeftInspectorAction, &QAction::triggered, + [openInspector, openLeftInspectorAction](bool checked) { + openInspector(checked, false, openLeftInspectorAction); + }); + connect(openRightInspectorAction, &QAction::triggered, + [openInspector, openRightInspectorAction](bool checked) { + openInspector(checked, true, openRightInspectorAction); + }); this->menuBar()->addAction(tr("File")); auto mainToolBar = this->addToolBar(QStringLiteral("MainToolBar")); - mainToolBar->addAction(QStringLiteral("A1")); + + mainToolBar->addWidget(new TimeWidget{}); // Widgets / controllers connections connect(&sqpApp->dataSourceController(), SIGNAL(dataSourceItemSet(DataSourceItem *)), diff --git a/app/ui/MainWindow.ui b/app/ui/MainWindow.ui index 1b9b0ff..30bc87a 100644 --- a/app/ui/MainWindow.ui +++ b/app/ui/MainWindow.ui @@ -77,7 +77,7 @@ - + @@ -126,7 +126,7 @@ 0 0 800 - 28 + 26 @@ -152,6 +152,12 @@
DataSource/DataSourceWidget.h
1 + + VariableInspectorWidget + QWidget +
Variable/VariableInspectorWidget.h
+ 1 +
diff --git a/core/include/Data/ArrayData.h b/core/include/Data/ArrayData.h new file mode 100644 index 0000000..b08f0c2 --- /dev/null +++ b/core/include/Data/ArrayData.h @@ -0,0 +1,56 @@ +#ifndef SCIQLOP_ARRAYDATA_H +#define SCIQLOP_ARRAYDATA_H + +#include + +/** + * @brief The ArrayData class represents a dataset for a data series. + * + * A dataset can be unidimensional or two-dimensional. This property is determined by the Dim + * template-parameter. + * + * @tparam Dim the dimension of the ArrayData (one or two) + * @sa IDataSeries + */ +template +class ArrayData { +public: + /** + * Ctor for a unidimensional ArrayData + * @param nbColumns the number of values the ArrayData will hold + */ + template > + explicit ArrayData(int nbColumns) : m_Data{1, QVector{}} + { + m_Data[0].resize(nbColumns); + } + + /** + * Sets a data at a specified index. The index has to be valid to be effective + * @param index the index to which the data will be set + * @param data the data to set + * @remarks this method is only available for a unidimensional ArrayData + */ + template > + void setData(int index, double data) noexcept + { + if (index >= 0 && index < m_Data.at(0).size()) { + m_Data[0].replace(index, data); + } + } + + /** + * @return the data as a vector + * @remarks this method is only available for a unidimensional ArrayData + */ + template > + QVector data() const noexcept + { + return m_Data.at(0); + } + +private: + QVector > m_Data; +}; + +#endif // SCIQLOP_ARRAYDATA_H diff --git a/core/include/Data/DataProviderParameters.h b/core/include/Data/DataProviderParameters.h new file mode 100644 index 0000000..496f171 --- /dev/null +++ b/core/include/Data/DataProviderParameters.h @@ -0,0 +1,16 @@ +#ifndef SCIQLOP_DATAPROVIDERPARAMETERS_H +#define SCIQLOP_DATAPROVIDERPARAMETERS_H + +/** + * @brief The DataProviderParameters struct holds the information needed to retrieve data from a + * data provider + * @sa IDataProvider + */ +struct DataProviderParameters { + /// Start time + double m_TStart; + /// End time + double m_TEnd; +}; + +#endif // SCIQLOP_DATAPROVIDERPARAMETERS_H diff --git a/core/include/Data/DataSeries.h b/core/include/Data/DataSeries.h new file mode 100644 index 0000000..f4315f0 --- /dev/null +++ b/core/include/Data/DataSeries.h @@ -0,0 +1,50 @@ +#ifndef SCIQLOP_DATASERIES_H +#define SCIQLOP_DATASERIES_H + +#include +#include + +#include + +/** + * @brief The DataSeries class is the base (abstract) implementation of IDataSeries. + * + * It proposes to set a dimension for the values ​​data + * + * @tparam Dim The dimension of the values data + * + */ +template +class DataSeries : public IDataSeries { +public: + /// @sa IDataSeries::xAxisData() + std::shared_ptr > xAxisData() override { return m_XAxisData; } + + /// @sa IDataSeries::xAxisUnit() + QString xAxisUnit() const override { return m_XAxisUnit; } + + /// @return the values dataset + std::shared_ptr > valuesData() const { return m_ValuesData; } + + /// @sa IDataSeries::valuesUnit() + QString valuesUnit() const override { return m_ValuesUnit; } + +protected: + /// Protected ctor (DataSeries is abstract) + explicit DataSeries(std::shared_ptr > xAxisData, const QString &xAxisUnit, + std::shared_ptr > valuesData, const QString &valuesUnit) + : m_XAxisData{xAxisData}, + m_XAxisUnit{xAxisUnit}, + m_ValuesData{valuesData}, + m_ValuesUnit{valuesUnit} + { + } + +private: + std::shared_ptr > m_XAxisData; + QString m_XAxisUnit; + std::shared_ptr > m_ValuesData; + QString m_ValuesUnit; +}; + +#endif // SCIQLOP_DATASERIES_H diff --git a/core/include/Data/IDataProvider.h b/core/include/Data/IDataProvider.h new file mode 100644 index 0000000..0b83f2b --- /dev/null +++ b/core/include/Data/IDataProvider.h @@ -0,0 +1,25 @@ +#ifndef SCIQLOP_IDATAPROVIDER_H +#define SCIQLOP_IDATAPROVIDER_H + +#include + +class DataProviderParameters; +class IDataSeries; + +/** + * @brief The IDataProvider interface aims to declare a data provider. + * + * A data provider is an entity that generates data and returns it according to various parameters + * (time interval, product to retrieve the data, etc.) + * + * @sa IDataSeries + */ +class IDataProvider { +public: + virtual ~IDataProvider() noexcept = default; + + virtual std::unique_ptr + retrieveData(const DataProviderParameters ¶meters) const = 0; +}; + +#endif // SCIQLOP_IDATAPROVIDER_H diff --git a/core/include/Data/IDataSeries.h b/core/include/Data/IDataSeries.h new file mode 100644 index 0000000..0278a8e --- /dev/null +++ b/core/include/Data/IDataSeries.h @@ -0,0 +1,37 @@ +#ifndef SCIQLOP_IDATASERIES_H +#define SCIQLOP_IDATASERIES_H + +#include + +#include + +template +class ArrayData; + +/** + * @brief The IDataSeries aims to declare a data series. + * + * A data series is an entity that contains at least : + * - one dataset representing the x-axis + * - one dataset representing the values + * + * Each dataset is represented by an ArrayData, and is associated with a unit. + * + * An ArrayData can be unidimensional or two-dimensional, depending on the implementation of the + * IDataSeries. The x-axis dataset is always unidimensional. + * + * @sa ArrayData + */ +class IDataSeries { +public: + virtual ~IDataSeries() noexcept = default; + + /// Returns the x-axis dataset + virtual std::shared_ptr > xAxisData() = 0; + + virtual QString xAxisUnit() const = 0; + + virtual QString valuesUnit() const = 0; +}; + +#endif // SCIQLOP_IDATASERIES_H diff --git a/core/include/Data/ScalarSeries.h b/core/include/Data/ScalarSeries.h new file mode 100644 index 0000000..5dd39b0 --- /dev/null +++ b/core/include/Data/ScalarSeries.h @@ -0,0 +1,28 @@ +#ifndef SCIQLOP_SCALARSERIES_H +#define SCIQLOP_SCALARSERIES_H + +#include + +/** + * @brief The ScalarSeries class is the implementation for a data series representing a scalar. + */ +class ScalarSeries : public DataSeries<1> { +public: + /** + * Ctor + * @param size the number of data the series will hold + * @param xAxisUnit x-axis unit + * @param valuesUnit values unit + */ + explicit ScalarSeries(int size, const QString &xAxisUnit, const QString &valuesUnit); + + /** + * Sets data for a specific index. The index has to be valid to be effective + * @param index the index to which the data will be set + * @param x the x-axis data + * @param value the value data + */ + void setData(int index, double x, double value) noexcept; +}; + +#endif // SCIQLOP_SCALARSERIES_H diff --git a/core/include/DataSource/DataSourceController.h b/core/include/DataSource/DataSourceController.h index 6d3df61..3a495e9 100644 --- a/core/include/DataSource/DataSourceController.h +++ b/core/include/DataSource/DataSourceController.h @@ -10,6 +10,7 @@ Q_DECLARE_LOGGING_CATEGORY(LOG_DataSourceController) class DataSourceItem; +class IDataProvider; /** * @brief The DataSourceController class aims to make the link between SciQlop and its plugins. This @@ -42,6 +43,23 @@ public: void setDataSourceItem(const QUuid &dataSourceUid, std::unique_ptr dataSourceItem) noexcept; + /** + * Sets the data provider used to retrieve data from of a data source. The controller takes + * ownership of the provider. + * @param dataSourceUid the unique id with which the data source has been registered into the + * controller. If it is invalid, the method has no effect. + * @param dataProvider the provider of the data source + * @sa registerDataSource() + */ + void setDataProvider(const QUuid &dataSourceUid, + std::unique_ptr dataProvider) noexcept; + + /** + * Loads an item (product) as a variable in SciQlop + * @param productItem the item to load + */ + void loadProductItem(const DataSourceItem &productItem) noexcept; + public slots: /// Manage init/end of the controller void initialize(); diff --git a/core/include/DataSource/DataSourceItem.h b/core/include/DataSource/DataSourceItem.h index 193a495..4ff7629 100644 --- a/core/include/DataSource/DataSourceItem.h +++ b/core/include/DataSource/DataSourceItem.h @@ -6,6 +6,8 @@ #include #include +class DataSourceItemAction; + /** * Possible types of an item */ @@ -21,6 +23,16 @@ class DataSourceItem { public: explicit DataSourceItem(DataSourceItemType type, QVector data = {}); + /// @return the actions of the item as a vector + QVector actions() const noexcept; + + /** + * Adds an action to the item. The item takes ownership of the action, and the action is + * automatically associated to the item + * @param action the action to add + */ + void addAction(std::unique_ptr action) noexcept; + /** * Adds a child to the item. The item takes ownership of the child. * @param child the child to add @@ -43,6 +55,8 @@ public: */ QVariant data(int dataIndex) const noexcept; + QString name() const noexcept; + /** * Get the item's parent * @return a pointer to the parent if it exists, nullptr if the item is a root diff --git a/core/include/DataSource/DataSourceItemAction.h b/core/include/DataSource/DataSourceItemAction.h new file mode 100644 index 0000000..1e64959 --- /dev/null +++ b/core/include/DataSource/DataSourceItemAction.h @@ -0,0 +1,48 @@ +#ifndef SCIQLOP_DATASOURCEITEMACTION_H +#define SCIQLOP_DATASOURCEITEMACTION_H + +#include + +#include +#include + +Q_DECLARE_LOGGING_CATEGORY(LOG_DataSourceItemAction) + +class DataSourceItem; + +/** + * @brief The DataSourceItemAction class represents an action on a data source item. + * + * An action is a function that will be executed when the slot execute() is called. + */ +class DataSourceItemAction : public QObject { + + Q_OBJECT + +public: + /// Signature of the function associated to the action + using ExecuteFunction = std::function; + + /** + * Ctor + * @param name the name of the action + * @param fun the function that will be called when the action is executed + * @sa execute() + */ + explicit DataSourceItemAction(const QString &name, ExecuteFunction fun); + + QString name() const noexcept; + + /// Sets the data source item concerned by the action + void setDataSourceItem(DataSourceItem *dataSourceItem) noexcept; + +public slots: + /// Executes the action + void execute(); + +private: + class DataSourceItemActionPrivate; + spimpl::unique_impl_ptr impl; +}; + +#endif // SCIQLOP_DATASOURCEITEMACTION_H diff --git a/core/include/Variable/Variable.h b/core/include/Variable/Variable.h new file mode 100644 index 0000000..ff5f718 --- /dev/null +++ b/core/include/Variable/Variable.h @@ -0,0 +1,20 @@ +#ifndef SCIQLOP_VARIABLE_H +#define SCIQLOP_VARIABLE_H + +#include + +/** + * @brief The Variable struct represents a variable in SciQlop. + */ +struct Variable { + explicit Variable(const QString &name, const QString &unit, const QString &mission) + : m_Name{name}, m_Unit{unit}, m_Mission{mission} + { + } + + QString m_Name; + QString m_Unit; + QString m_Mission; +}; + +#endif // SCIQLOP_VARIABLE_H diff --git a/core/include/Variable/VariableController.h b/core/include/Variable/VariableController.h new file mode 100644 index 0000000..d25da2b --- /dev/null +++ b/core/include/Variable/VariableController.h @@ -0,0 +1,43 @@ +#ifndef SCIQLOP_VARIABLECONTROLLER_H +#define SCIQLOP_VARIABLECONTROLLER_H + +#include +#include + +#include + +class Variable; +class VariableModel; + +Q_DECLARE_LOGGING_CATEGORY(LOG_VariableController) + +/** + * @brief The VariableController class aims to handle the variables in SciQlop. + */ +class VariableController : public QObject { + Q_OBJECT +public: + explicit VariableController(QObject *parent = 0); + virtual ~VariableController(); + + /** + * Creates a new variable + * @param name the name of the new variable + * @return the variable if it was created successfully, nullptr otherwise + */ + Variable *createVariable(const QString &name) noexcept; + + VariableModel *variableModel() noexcept; + +public slots: + void initialize(); + void finalize(); + +private: + void waitForFinish(); + + class VariableControllerPrivate; + spimpl::unique_impl_ptr impl; +}; + +#endif // SCIQLOP_VARIABLECONTROLLER_H diff --git a/core/include/Variable/VariableModel.h b/core/include/Variable/VariableModel.h new file mode 100644 index 0000000..074da18 --- /dev/null +++ b/core/include/Variable/VariableModel.h @@ -0,0 +1,41 @@ +#ifndef SCIQLOP_VARIABLEMODEL_H +#define SCIQLOP_VARIABLEMODEL_H + +#include + +#include +#include + +Q_DECLARE_LOGGING_CATEGORY(LOG_VariableModel) + +class Variable; + +/** + * @brief The VariableModel class aims to hold the variables that have been created in SciQlop + */ +class VariableModel : public QAbstractTableModel { +public: + explicit VariableModel(QObject *parent = nullptr); + + /** + * Creates a new variable in the model + * @param name the name of the new variable + * @return the variable if it was created successfully, nullptr otherwise + */ + Variable *createVariable(const QString &name) noexcept; + + // /////////////////////////// // + // QAbstractTableModel methods // + // /////////////////////////// // + virtual int columnCount(const QModelIndex &parent = QModelIndex{}) const override; + virtual int rowCount(const QModelIndex &parent = QModelIndex{}) const override; + virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + virtual QVariant headerData(int section, Qt::Orientation orientation, + int role = Qt::DisplayRole) const override; + +private: + class VariableModelPrivate; + spimpl::unique_impl_ptr impl; +}; + +#endif // SCIQLOP_VARIABLEMODEL_H diff --git a/core/src/Data/ScalarSeries.cpp b/core/src/Data/ScalarSeries.cpp new file mode 100644 index 0000000..f3f4fc2 --- /dev/null +++ b/core/src/Data/ScalarSeries.cpp @@ -0,0 +1,13 @@ +#include + +ScalarSeries::ScalarSeries(int size, const QString &xAxisUnit, const QString &valuesUnit) + : DataSeries{std::make_shared >(size), xAxisUnit, + std::make_shared >(size), valuesUnit} +{ +} + +void ScalarSeries::setData(int index, double x, double value) noexcept +{ + xAxisData()->setData(index, x); + valuesData()->setData(index, value); +} diff --git a/core/src/DataSource/DataSourceController.cpp b/core/src/DataSource/DataSourceController.cpp index c8066c1..fc0bd48 100644 --- a/core/src/DataSource/DataSourceController.cpp +++ b/core/src/DataSource/DataSourceController.cpp @@ -1,6 +1,8 @@ #include #include +#include + #include #include @@ -16,6 +18,8 @@ public: QHash m_DataSources; /// Data sources structures std::map > m_DataSourceItems; + /// Data providers registered + std::map > m_DataProviders; }; DataSourceController::DataSourceController(QObject *parent) @@ -59,6 +63,24 @@ void DataSourceController::setDataSourceItem( } } +void DataSourceController::setDataProvider(const QUuid &dataSourceUid, + std::unique_ptr dataProvider) noexcept +{ + if (impl->m_DataSources.contains(dataSourceUid)) { + impl->m_DataProviders.insert(std::make_pair(dataSourceUid, std::move(dataProvider))); + } + else { + qCWarning(LOG_DataSourceController()) << tr("Can't set data provider for uid %1 : no data " + "source has been registered with the uid") + .arg(dataSourceUid.toString()); + } +} + +void DataSourceController::loadProductItem(const DataSourceItem &productItem) noexcept +{ + /// @todo ALX +} + void DataSourceController::initialize() { qCDebug(LOG_DataSourceController()) << tr("DataSourceController init") diff --git a/core/src/DataSource/DataSourceItem.cpp b/core/src/DataSource/DataSourceItem.cpp index 43c884b..c794bc2 100644 --- a/core/src/DataSource/DataSourceItem.cpp +++ b/core/src/DataSource/DataSourceItem.cpp @@ -1,10 +1,18 @@ #include +#include #include +namespace { + +/// Index of the 'name' value in the item +const auto NAME_INDEX = 0; + +} // namespace + struct DataSourceItem::DataSourceItemPrivate { explicit DataSourceItemPrivate(DataSourceItemType type, QVector data) - : m_Parent{nullptr}, m_Children{}, m_Type{type}, m_Data{std::move(data)} + : m_Parent{nullptr}, m_Children{}, m_Type{type}, m_Data{std::move(data)}, m_Actions{} { } @@ -12,6 +20,7 @@ struct DataSourceItem::DataSourceItemPrivate { std::vector > m_Children; DataSourceItemType m_Type; QVector m_Data; + std::vector > m_Actions; }; DataSourceItem::DataSourceItem(DataSourceItemType type, QVector data) @@ -19,6 +28,22 @@ DataSourceItem::DataSourceItem(DataSourceItemType type, QVector data) { } +QVector DataSourceItem::actions() const noexcept +{ + QVector result{}; + + std::transform(std::cbegin(impl->m_Actions), std::cend(impl->m_Actions), + std::back_inserter(result), [](const auto &action) { return action.get(); }); + + return result; +} + +void DataSourceItem::addAction(std::unique_ptr action) noexcept +{ + action->setDataSourceItem(this); + impl->m_Actions.push_back(std::move(action)); +} + void DataSourceItem::appendChild(std::unique_ptr child) noexcept { child->impl->m_Parent = this; @@ -45,6 +70,11 @@ QVariant DataSourceItem::data(int dataIndex) const noexcept return impl->m_Data.value(dataIndex); } +QString DataSourceItem::name() const noexcept +{ + return data(NAME_INDEX).toString(); +} + DataSourceItem *DataSourceItem::parentItem() const noexcept { return impl->m_Parent; diff --git a/core/src/DataSource/DataSourceItemAction.cpp b/core/src/DataSource/DataSourceItemAction.cpp new file mode 100644 index 0000000..e791e8f --- /dev/null +++ b/core/src/DataSource/DataSourceItemAction.cpp @@ -0,0 +1,42 @@ +#include + +Q_LOGGING_CATEGORY(LOG_DataSourceItemAction, "DataSourceItemAction") + +struct DataSourceItemAction::DataSourceItemActionPrivate { + explicit DataSourceItemActionPrivate(const QString &name, + DataSourceItemAction::ExecuteFunction fun) + : m_Name{name}, m_Fun{std::move(fun)}, m_DataSourceItem{nullptr} + { + } + + QString m_Name; + DataSourceItemAction::ExecuteFunction m_Fun; + /// Item associated to the action (can be null, in which case the action will not be executed) + DataSourceItem *m_DataSourceItem; +}; + +DataSourceItemAction::DataSourceItemAction(const QString &name, ExecuteFunction fun) + : impl{spimpl::make_unique_impl(name, std::move(fun))} +{ +} + +QString DataSourceItemAction::name() const noexcept +{ + return impl->m_Name; +} + +void DataSourceItemAction::setDataSourceItem(DataSourceItem *dataSourceItem) noexcept +{ + impl->m_DataSourceItem = dataSourceItem; +} + +void DataSourceItemAction::execute() +{ + if (impl->m_DataSourceItem) { + impl->m_Fun(*impl->m_DataSourceItem); + } + else { + qCDebug(LOG_DataSourceItemAction()) + << tr("Can't execute action : no item has been associated"); + } +} diff --git a/core/src/Variable/VariableController.cpp b/core/src/Variable/VariableController.cpp new file mode 100644 index 0000000..8c05bd9 --- /dev/null +++ b/core/src/Variable/VariableController.cpp @@ -0,0 +1,59 @@ +#include +#include + +#include +#include + +Q_LOGGING_CATEGORY(LOG_VariableController, "VariableController") + +struct VariableController::VariableControllerPrivate { + explicit VariableControllerPrivate(VariableController *parent) + : m_WorkingMutex{}, m_VariableModel{new VariableModel{parent}} + { + } + + QMutex m_WorkingMutex; + /// Variable model. The VariableController has the ownership + VariableModel *m_VariableModel; +}; + +VariableController::VariableController(QObject *parent) + : QObject{parent}, impl{spimpl::make_unique_impl(this)} +{ + qCDebug(LOG_VariableController()) << tr("VariableController construction") + << QThread::currentThread(); +} + +VariableController::~VariableController() +{ + qCDebug(LOG_VariableController()) << tr("VariableController destruction") + << QThread::currentThread(); + this->waitForFinish(); +} + +Variable *VariableController::createVariable(const QString &name) noexcept +{ + return impl->m_VariableModel->createVariable(name); +} + +VariableModel *VariableController::variableModel() noexcept +{ + return impl->m_VariableModel; +} + +void VariableController::initialize() +{ + qCDebug(LOG_VariableController()) << tr("VariableController init") << QThread::currentThread(); + impl->m_WorkingMutex.lock(); + qCDebug(LOG_VariableController()) << tr("VariableController init END"); +} + +void VariableController::finalize() +{ + impl->m_WorkingMutex.unlock(); +} + +void VariableController::waitForFinish() +{ + QMutexLocker locker{&impl->m_WorkingMutex}; +} diff --git a/core/src/Variable/VariableModel.cpp b/core/src/Variable/VariableModel.cpp new file mode 100644 index 0000000..75389d5 --- /dev/null +++ b/core/src/Variable/VariableModel.cpp @@ -0,0 +1,115 @@ +#include + +#include + +Q_LOGGING_CATEGORY(LOG_VariableModel, "VariableModel") + +namespace { + +// Column indexes +const auto NAME_COLUMN = 0; +const auto UNIT_COLUMN = 1; +const auto MISSION_COLUMN = 2; +const auto NB_COLUMNS = 3; + +} // namespace + +struct VariableModel::VariableModelPrivate { + /// Variables created in SciQlop + std::vector > m_Variables; +}; + +VariableModel::VariableModel(QObject *parent) + : QAbstractTableModel{parent}, impl{spimpl::make_unique_impl()} +{ +} + +Variable *VariableModel::createVariable(const QString &name) noexcept +{ + auto insertIndex = rowCount(); + beginInsertRows({}, insertIndex, insertIndex); + + /// @todo For the moment, the other data of the variable is initialized with default values + auto variable + = std::make_unique(name, QStringLiteral("unit"), QStringLiteral("mission")); + impl->m_Variables.push_back(std::move(variable)); + + endInsertRows(); + + return impl->m_Variables.at(insertIndex).get(); +} + +int VariableModel::columnCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent); + + return NB_COLUMNS; +} + +int VariableModel::rowCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent); + + return impl->m_Variables.size(); +} + +QVariant VariableModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) { + return QVariant{}; + } + + if (index.row() < 0 || index.row() >= rowCount()) { + return QVariant{}; + } + + if (role == Qt::DisplayRole) { + if (auto variable = impl->m_Variables.at(index.row()).get()) { + switch (index.column()) { + case NAME_COLUMN: + return variable->m_Name; + case UNIT_COLUMN: + return variable->m_Unit; + case MISSION_COLUMN: + return variable->m_Mission; + default: + // No action + break; + } + + qWarning(LOG_VariableModel()) + << tr("Can't get data (unknown column %1)").arg(index.column()); + } + else { + qWarning(LOG_VariableModel()) << tr("Can't get data (no variable)"); + } + } + + return QVariant{}; +} + +QVariant VariableModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (role != Qt::DisplayRole) { + return QVariant{}; + } + + if (orientation == Qt::Horizontal) { + switch (section) { + case NAME_COLUMN: + return tr("Name"); + case UNIT_COLUMN: + return tr("Unit"); + case MISSION_COLUMN: + return tr("Mission"); + default: + // No action + break; + } + + qWarning(LOG_VariableModel()) + << tr("Can't get header data (unknown column %1)").arg(section); + } + + return QVariant{}; +} diff --git a/core/vera-exclusions/exclusions.txt b/core/vera-exclusions/exclusions.txt index 7b0007c..24fe3c3 100644 --- a/core/vera-exclusions/exclusions.txt +++ b/core/vera-exclusions/exclusions.txt @@ -4,3 +4,10 @@ Common/spimpl\.h:\d+:.* # Ignore false positive relative to two class definitions in a same file DataSourceItem\.h:\d+:.*IPSIS_S01.* +# Ignore false positive relative to a template class +ArrayData\.h:\d+:.*IPSIS_S04_VARIABLE.*found: (D) +ArrayData\.h:\d+:.*IPSIS_S06.*found: (D) +ArrayData\.h:\d+:.*IPSIS_S06.*found: (Dim) + +# Ignore false positive relative to an alias +DataSourceItemAction\.h:\d+:.*IPSIS_S06.*found: (ExecuteFunction) diff --git a/gui/include/DataSource/DataSourceTreeWidgetItem.h b/gui/include/DataSource/DataSourceTreeWidgetItem.h index 02b0122..842e5ba 100644 --- a/gui/include/DataSource/DataSourceTreeWidgetItem.h +++ b/gui/include/DataSource/DataSourceTreeWidgetItem.h @@ -24,6 +24,9 @@ public: virtual QVariant data(int column, int role) const override; virtual void setData(int column, int role, const QVariant &value) override; + /// @return the actions associated to the item + QList actions() const noexcept; + private: class DataSourceTreeWidgetItemPrivate; spimpl::unique_impl_ptr impl; diff --git a/gui/include/DataSource/DataSourceWidget.h b/gui/include/DataSource/DataSourceWidget.h index 19d351f..4134f86 100644 --- a/gui/include/DataSource/DataSourceWidget.h +++ b/gui/include/DataSource/DataSourceWidget.h @@ -1,10 +1,12 @@ #ifndef SCIQLOP_DATASOURCEWIDGET_H #define SCIQLOP_DATASOURCEWIDGET_H -#include - #include +namespace Ui { +class DataSourceWidget; +} // Ui + class DataSourceItem; /** @@ -26,8 +28,11 @@ public slots: void addDataSource(DataSourceItem *dataSource) noexcept; private: - class DataSourceWidgetPrivate; - spimpl::unique_impl_ptr impl; + Ui::DataSourceWidget *ui; + +private slots: + /// Slot called when right clicking on an item in the tree (displays a menu) + void onTreeMenuRequested(const QPoint &pos) noexcept; }; #endif // SCIQLOP_DATASOURCEWIDGET_H diff --git a/gui/include/SqpApplication.h b/gui/include/SqpApplication.h index db80758..daa7440 100644 --- a/gui/include/SqpApplication.h +++ b/gui/include/SqpApplication.h @@ -16,6 +16,7 @@ Q_DECLARE_LOGGING_CATEGORY(LOG_SqpApplication) #define sqpApp (static_cast(QCoreApplication::instance())) class DataSourceController; +class VariableController; class VisualizationController; /** @@ -35,8 +36,9 @@ public: void initialize(); /// Accessors for the differents sciqlop controllers - DataSourceController &dataSourceController() const noexcept; - VisualizationController &visualizationController() const noexcept; + DataSourceController &dataSourceController() noexcept; + VariableController &variableController() noexcept; + VisualizationController &visualizationController() noexcept; private: class SqpApplicationPrivate; diff --git a/gui/include/TimeWidget/TimeWidget.h b/gui/include/TimeWidget/TimeWidget.h new file mode 100644 index 0000000..014bea1 --- /dev/null +++ b/gui/include/TimeWidget/TimeWidget.h @@ -0,0 +1,21 @@ +#ifndef SCIQLOP_TIMEWIDGET_H +#define SCIQLOP_TIMEWIDGET_H + +#include + +namespace Ui { +class TimeWidget; +} // Ui + +class TimeWidget : public QWidget { + Q_OBJECT + +public: + explicit TimeWidget(QWidget *parent = 0); + virtual ~TimeWidget(); + +private: + Ui::TimeWidget *ui; +}; + +#endif // SCIQLOP_ SQPSIDEPANE_H diff --git a/gui/include/Variable/VariableInspectorWidget.h b/gui/include/Variable/VariableInspectorWidget.h new file mode 100644 index 0000000..c4d5f41 --- /dev/null +++ b/gui/include/Variable/VariableInspectorWidget.h @@ -0,0 +1,26 @@ +#ifndef SCIQLOP_VARIABLEINSPECTORWIDGET_H +#define SCIQLOP_VARIABLEINSPECTORWIDGET_H + +#include + +namespace Ui { +class VariableInspectorWidget; +} // Ui + +/** + * @brief The VariableInspectorWidget class representes represents the variable inspector, from + * which it is possible to view the loaded variables, handle them or trigger their display in + * visualization + */ +class VariableInspectorWidget : public QWidget { + Q_OBJECT + +public: + explicit VariableInspectorWidget(QWidget *parent = 0); + virtual ~VariableInspectorWidget(); + +private: + Ui::VariableInspectorWidget *ui; +}; + +#endif // SCIQLOP_VARIABLEINSPECTORWIDGET_H diff --git a/gui/include/Visualization/IVisualizationWidget.h b/gui/include/Visualization/IVisualizationWidget.h new file mode 100644 index 0000000..18a4fd8 --- /dev/null +++ b/gui/include/Visualization/IVisualizationWidget.h @@ -0,0 +1,24 @@ +#ifndef SCIQLOP_IVISUALIZATIONWIDGET_H +#define SCIQLOP_IVISUALIZATIONWIDGET_H + +#include "Visualization/IVisualizationWidgetVisitor.h" + +#include +#include + +/** + * @brief The IVisualizationWidget handles the visualization widget. + */ +class IVisualizationWidget { + +public: + virtual ~IVisualizationWidget() = default; + + /// Initializes the plugin + virtual void accept(IVisualizationWidget *visitor) = 0; + virtual void close() = 0; + virtual QString name() const = 0; +}; + + +#endif // SCIQLOP_IVISUALIZATIONWIDGET_H diff --git a/gui/include/Visualization/IVisualizationWidgetVisitor.h b/gui/include/Visualization/IVisualizationWidgetVisitor.h new file mode 100644 index 0000000..33ce5b9 --- /dev/null +++ b/gui/include/Visualization/IVisualizationWidgetVisitor.h @@ -0,0 +1,25 @@ +#ifndef SCIQLOP_IVISUALIZATIONWIDGETVISITOR_H +#define SCIQLOP_IVISUALIZATIONWIDGETVISITOR_H + + +class VisualizationWidget; +class VisualizationTabWidget; +class VisualizationZoneWidget; +class VisualizationGraphWidget; + +/** + * @brief The IVisualizationWidgetVisitor handles the visualization widget vistor pattern. + */ +class IVisualizationWidgetVisitor { + +public: + virtual ~IVisualizationWidgetVisitor() = default; + + virtual void visit(VisualizationWidget *widget) = 0; + virtual void visit(VisualizationTabWidget *tabWidget) = 0; + virtual void visit(VisualizationZoneWidget *zoneWidget) = 0; + virtual void visit(VisualizationGraphWidget *graphWidget) = 0; +}; + + +#endif // SCIQLOP_IVISUALIZATIONWIDGETVISITOR_H diff --git a/gui/include/Visualization/VisualizationGraphWidget.h b/gui/include/Visualization/VisualizationGraphWidget.h index b1f5e7f..fc927c9 100644 --- a/gui/include/Visualization/VisualizationGraphWidget.h +++ b/gui/include/Visualization/VisualizationGraphWidget.h @@ -1,21 +1,39 @@ #ifndef SCIQLOP_VISUALIZATIONGRAPHWIDGET_H #define SCIQLOP_VISUALIZATIONGRAPHWIDGET_H +#include "Visualization/IVisualizationWidget.h" + #include +#include + +#include + +class Variable; + namespace Ui { class VisualizationGraphWidget; } // namespace Ui -class VisualizationGraphWidget : public QWidget { +class VisualizationGraphWidget : public QWidget, public IVisualizationWidget { Q_OBJECT public: explicit VisualizationGraphWidget(QWidget *parent = 0); virtual ~VisualizationGraphWidget(); + void addVariable(std::shared_ptr variable); + + // IVisualizationWidget interface + void accept(IVisualizationWidget *visitor) override; + void close() override; + QString name() const; + private: Ui::VisualizationGraphWidget *ui; + + class VisualizationGraphWidgetPrivate; + spimpl::unique_impl_ptr impl; }; #endif // SCIQLOP_VISUALIZATIONGRAPHWIDGET_H diff --git a/gui/include/Visualization/VisualizationTabWidget.h b/gui/include/Visualization/VisualizationTabWidget.h index a3a9d49..8ba996e 100644 --- a/gui/include/Visualization/VisualizationTabWidget.h +++ b/gui/include/Visualization/VisualizationTabWidget.h @@ -1,19 +1,37 @@ #ifndef SCIQLOP_VISUALIZATIONTABWIDGET_H #define SCIQLOP_VISUALIZATIONTABWIDGET_H +#include "Visualization/IVisualizationWidget.h" + #include +class VisualizationZoneWidget; + namespace Ui { class VisualizationTabWidget; } // namespace Ui -class VisualizationTabWidget : public QWidget { +class VisualizationTabWidget : public QWidget, public IVisualizationWidget { Q_OBJECT public: explicit VisualizationTabWidget(QWidget *parent = 0); virtual ~VisualizationTabWidget(); + /// Add a zone widget + void addZone(VisualizationZoneWidget *zoneWidget); + + /// Create a zone using a Variable + VisualizationZoneWidget *createZone(); + + /// Remove a zone + void removeZone(VisualizationZoneWidget *zone); + + // IVisualizationWidget interface + void accept(IVisualizationWidget *visitor) override; + void close() override; + QString name() const override; + private: Ui::VisualizationTabWidget *ui; }; diff --git a/gui/include/Visualization/VisualizationWidget.h b/gui/include/Visualization/VisualizationWidget.h index 280783a..b4af372 100644 --- a/gui/include/Visualization/VisualizationWidget.h +++ b/gui/include/Visualization/VisualizationWidget.h @@ -1,22 +1,40 @@ #ifndef SCIQLOP_VISUALIZATIONWIDGET_H #define SCIQLOP_VISUALIZATIONWIDGET_H +#include "Visualization/IVisualizationWidget.h" + #include #include +class VisualizationTabWidget; + Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationWidget) namespace Ui { class VisualizationWidget; } // namespace Ui -class VisualizationWidget : public QWidget { +class VisualizationWidget : public QWidget, public IVisualizationWidget { Q_OBJECT public: explicit VisualizationWidget(QWidget *parent = 0); virtual ~VisualizationWidget(); + /// Add a zone widget + virtual void addTab(VisualizationTabWidget *tabWidget); + + /// Create a tab using a Variable + VisualizationTabWidget *createTab(); + + /// Remove a tab + void removeTab(VisualizationTabWidget *tab); + + // IVisualizationWidget interface + void accept(IVisualizationWidget *visitor) override; + void close() override; + QString name() const; + private: Ui::VisualizationWidget *ui; }; diff --git a/gui/include/Visualization/VisualizationZoneWidget.h b/gui/include/Visualization/VisualizationZoneWidget.h index ba591f1..bdb08bf 100644 --- a/gui/include/Visualization/VisualizationZoneWidget.h +++ b/gui/include/Visualization/VisualizationZoneWidget.h @@ -1,19 +1,37 @@ #ifndef SCIQLOP_VISUALIZATIONZONEWIDGET_H #define SCIQLOP_VISUALIZATIONZONEWIDGET_H +#include "Visualization/IVisualizationWidget.h" + +class VisualizationGraphWidget; + #include namespace Ui { class VisualizationZoneWidget; } // Ui -class VisualizationZoneWidget : public QWidget { +class VisualizationZoneWidget : public QWidget, public IVisualizationWidget { Q_OBJECT public: explicit VisualizationZoneWidget(QWidget *parent = 0); virtual ~VisualizationZoneWidget(); + /// Add a graph widget + void addGraph(VisualizationGraphWidget *graphWidget); + + /// Create a graph using a Variable + VisualizationGraphWidget *createGraph(); + + /// Remove a graph + void removeGraph(VisualizationGraphWidget *graph); + + // IVisualizationWidget interface + void accept(IVisualizationWidget *visitor) override; + void close() override; + QString name() const override; + private: Ui::VisualizationZoneWidget *ui; }; diff --git a/gui/resources/icones/next.png b/gui/resources/icones/next.png new file mode 100644 index 0000000000000000000000000000000000000000..b70248b705e281885153a05ade514e565a13560b GIT binary patch literal 4413 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 literal 0 Hc$@?U+#X$GB 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 literal 0 Hc$@ icones/openInspector.png + icones/next.png + icones/previous.png diff --git a/gui/src/DataSource/DataSourceTreeWidgetItem.cpp b/gui/src/DataSource/DataSourceTreeWidgetItem.cpp index 236f0b4..07b8735 100644 --- a/gui/src/DataSource/DataSourceTreeWidgetItem.cpp +++ b/gui/src/DataSource/DataSourceTreeWidgetItem.cpp @@ -1,8 +1,11 @@ #include +#include #include #include +#include + Q_LOGGING_CATEGORY(LOG_DataSourceTreeWidgetItem, "DataSourceTreeWidgetItem") namespace { @@ -40,6 +43,9 @@ struct DataSourceTreeWidgetItem::DataSourceTreeWidgetItemPrivate { /// Model used to retrieve data source information const DataSourceItem *m_Data; + /// Actions associated to the item. The parent of the item (QTreeWidget) takes the ownership of + /// the actions + QList m_Actions; }; DataSourceTreeWidgetItem::DataSourceTreeWidgetItem(const DataSourceItem *data, int type) @@ -54,6 +60,21 @@ DataSourceTreeWidgetItem::DataSourceTreeWidgetItem(QTreeWidget *parent, const Da { // Sets the icon depending on the data source setIcon(0, itemIcon(impl->m_Data)); + + // Generates tree actions based on the item actions + auto createTreeAction = [this, &parent](const auto &itemAction) { + auto treeAction = new QAction{itemAction->name(), parent}; + + // Executes item action when tree action is triggered + QObject::connect(treeAction, &QAction::triggered, itemAction, + &DataSourceItemAction::execute); + + return treeAction; + }; + + auto itemActions = impl->m_Data->actions(); + std::transform(std::cbegin(itemActions), std::cend(itemActions), + std::back_inserter(impl->m_Actions), createTreeAction); } QVariant DataSourceTreeWidgetItem::data(int column, int role) const @@ -73,3 +94,8 @@ void DataSourceTreeWidgetItem::setData(int column, int role, const QVariant &val QTreeWidgetItem::setData(column, role, value); } } + +QList DataSourceTreeWidgetItem::actions() const noexcept +{ + return impl->m_Actions; +} diff --git a/gui/src/DataSource/DataSourceWidget.cpp b/gui/src/DataSource/DataSourceWidget.cpp index 79749aa..0209719 100644 --- a/gui/src/DataSource/DataSourceWidget.cpp +++ b/gui/src/DataSource/DataSourceWidget.cpp @@ -5,6 +5,8 @@ #include #include +#include + namespace { /// Number of columns displayed in the tree @@ -33,24 +35,18 @@ DataSourceTreeWidgetItem *createTreeWidgetItem(DataSourceItem *dataSource) } // namespace -class DataSourceWidget::DataSourceWidgetPrivate { -public: - explicit DataSourceWidgetPrivate(DataSourceWidget &widget) - : m_Ui{std::make_unique()} - { - m_Ui->setupUi(&widget); - - // Set tree properties - m_Ui->treeWidget->setColumnCount(TREE_NB_COLUMNS); - m_Ui->treeWidget->setHeaderLabels(TREE_HEADER_LABELS); - } +DataSourceWidget::DataSourceWidget(QWidget *parent) : QWidget{parent}, ui{new Ui::DataSourceWidget} +{ + ui->setupUi(this); - std::unique_ptr m_Ui; -}; + // Set tree properties + ui->treeWidget->setColumnCount(TREE_NB_COLUMNS); + ui->treeWidget->setHeaderLabels(TREE_HEADER_LABELS); + ui->treeWidget->setContextMenuPolicy(Qt::CustomContextMenu); -DataSourceWidget::DataSourceWidget(QWidget *parent) - : QWidget{parent}, impl{spimpl::make_unique_impl(*this)} -{ + // Connection to show a menu when right clicking on the tree + connect(ui->treeWidget, &QTreeWidget::customContextMenuRequested, this, + &DataSourceWidget::onTreeMenuRequested); } void DataSourceWidget::addDataSource(DataSourceItem *dataSource) noexcept @@ -58,6 +54,19 @@ void DataSourceWidget::addDataSource(DataSourceItem *dataSource) noexcept // Creates the item associated to the source and adds it to the tree widget. The tree widget // takes the ownership of the item if (dataSource) { - impl->m_Ui->treeWidget->addTopLevelItem(createTreeWidgetItem(dataSource)); + ui->treeWidget->addTopLevelItem(createTreeWidgetItem(dataSource)); + } +} + +void DataSourceWidget::onTreeMenuRequested(const QPoint &pos) noexcept +{ + // Retrieves the selected item in the tree, and build the menu from its actions + if (auto selectedItem = dynamic_cast(ui->treeWidget->itemAt(pos))) { + QMenu treeMenu{}; + treeMenu.addActions(selectedItem->actions()); + + if (!treeMenu.isEmpty()) { + treeMenu.exec(mapToGlobal(pos)); + } } } diff --git a/gui/src/SidePane/SqpSidePane.cpp b/gui/src/SidePane/SqpSidePane.cpp index 72e6ea9..ac7494f 100644 --- a/gui/src/SidePane/SqpSidePane.cpp +++ b/gui/src/SidePane/SqpSidePane.cpp @@ -34,13 +34,6 @@ SqpSidePane::SqpSidePane(QWidget *parent) : QWidget{parent}, ui{new Ui::SqpSideP this->layout()->addWidget(m_SidePaneToolbar); m_SidePaneToolbar->setStyleSheet(SQPSIDEPANESTYLESHEET); - - this->setStyleSheet( - " QWidget {" - "background: red;" - - "border: 1px;" - " }"); } SqpSidePane::~SqpSidePane() diff --git a/gui/src/SqpApplication.cpp b/gui/src/SqpApplication.cpp index 0a69f1f..dc45d7f 100644 --- a/gui/src/SqpApplication.cpp +++ b/gui/src/SqpApplication.cpp @@ -2,6 +2,7 @@ #include #include +#include #include Q_LOGGING_CATEGORY(LOG_SqpApplication, "SqpApplication") @@ -10,9 +11,11 @@ class SqpApplication::SqpApplicationPrivate { public: SqpApplicationPrivate() : m_DataSourceController{std::make_unique()}, + m_VariableController{std::make_unique()}, m_VisualizationController{std::make_unique()} { m_DataSourceController->moveToThread(&m_DataSourceControllerThread); + m_VariableController->moveToThread(&m_VariableControllerThread); m_VisualizationController->moveToThread(&m_VisualizationControllerThread); } @@ -22,13 +25,18 @@ public: m_DataSourceControllerThread.quit(); m_DataSourceControllerThread.wait(); + m_VariableControllerThread.quit(); + m_VariableControllerThread.wait(); + m_VisualizationControllerThread.quit(); m_VisualizationControllerThread.wait(); } std::unique_ptr m_DataSourceController; + std::unique_ptr m_VariableController; std::unique_ptr m_VisualizationController; QThread m_DataSourceControllerThread; + QThread m_VariableControllerThread; QThread m_VisualizationControllerThread; }; @@ -43,6 +51,11 @@ SqpApplication::SqpApplication(int &argc, char **argv) connect(&impl->m_DataSourceControllerThread, &QThread::finished, impl->m_DataSourceController.get(), &DataSourceController::finalize); + connect(&impl->m_VariableControllerThread, &QThread::started, impl->m_VariableController.get(), + &VariableController::initialize); + connect(&impl->m_VariableControllerThread, &QThread::finished, impl->m_VariableController.get(), + &VariableController::finalize); + connect(&impl->m_VisualizationControllerThread, &QThread::started, impl->m_VisualizationController.get(), &VisualizationController::initialize); connect(&impl->m_VisualizationControllerThread, &QThread::finished, @@ -50,6 +63,7 @@ SqpApplication::SqpApplication(int &argc, char **argv) impl->m_DataSourceControllerThread.start(); + impl->m_VariableControllerThread.start(); impl->m_VisualizationControllerThread.start(); } @@ -61,12 +75,17 @@ void SqpApplication::initialize() { } -DataSourceController &SqpApplication::dataSourceController() const noexcept +DataSourceController &SqpApplication::dataSourceController() noexcept { return *impl->m_DataSourceController; } -VisualizationController &SqpApplication::visualizationController() const noexcept +VariableController &SqpApplication::variableController() noexcept +{ + return *impl->m_VariableController; +} + +VisualizationController &SqpApplication::visualizationController() noexcept { return *impl->m_VisualizationController; } diff --git a/gui/src/TimeWidget/TimeWidget.cpp b/gui/src/TimeWidget/TimeWidget.cpp new file mode 100644 index 0000000..69cdd16 --- /dev/null +++ b/gui/src/TimeWidget/TimeWidget.cpp @@ -0,0 +1,12 @@ +#include "TimeWidget/TimeWidget.h" +#include "ui_TimeWidget.h" + +TimeWidget::TimeWidget(QWidget *parent) : QWidget{parent}, ui{new Ui::TimeWidget} +{ + ui->setupUi(this); +} + +TimeWidget::~TimeWidget() +{ + delete ui; +} diff --git a/gui/src/Variable/VariableInspectorWidget.cpp b/gui/src/Variable/VariableInspectorWidget.cpp new file mode 100644 index 0000000..7a788b7 --- /dev/null +++ b/gui/src/Variable/VariableInspectorWidget.cpp @@ -0,0 +1,26 @@ +#include +#include +#include + +#include + +#include + +#include + +VariableInspectorWidget::VariableInspectorWidget(QWidget *parent) + : QWidget{parent}, ui{new Ui::VariableInspectorWidget} +{ + ui->setupUi(this); + + // Sets model for table + auto sortFilterModel = new QSortFilterProxyModel{this}; + sortFilterModel->setSourceModel(sqpApp->variableController().variableModel()); + + ui->tableView->setModel(sortFilterModel); +} + +VariableInspectorWidget::~VariableInspectorWidget() +{ + delete ui; +} diff --git a/gui/src/Visualization/VisualizationGraphWidget.cpp b/gui/src/Visualization/VisualizationGraphWidget.cpp index 275198e..792c566 100644 --- a/gui/src/Visualization/VisualizationGraphWidget.cpp +++ b/gui/src/Visualization/VisualizationGraphWidget.cpp @@ -1,8 +1,21 @@ #include "Visualization/VisualizationGraphWidget.h" #include "ui_VisualizationGraphWidget.h" +#include + +#include + +struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate { + + // 1 variable -> n qcpplot + std::unordered_map, std::unique_ptr > + m_VariableToPlotMap; +}; + VisualizationGraphWidget::VisualizationGraphWidget(QWidget *parent) - : QWidget(parent), ui(new Ui::VisualizationGraphWidget) + : QWidget{parent}, + ui{new Ui::VisualizationGraphWidget}, + impl{spimpl::make_unique_impl()} { ui->setupUi(this); } @@ -11,3 +24,24 @@ VisualizationGraphWidget::~VisualizationGraphWidget() { delete ui; } + +void VisualizationGraphWidget::addVariable(std::shared_ptr variable) +{ + // todo: first check is variable contains data then check how many plot have to be created +} + +void VisualizationGraphWidget::accept(IVisualizationWidget *visitor) +{ + // TODO: manage the visitor +} + +void VisualizationGraphWidget::close() +{ + // The main view cannot be directly closed. + return; +} + +QString VisualizationGraphWidget::name() const +{ + return QStringLiteral("MainView"); +} diff --git a/gui/src/Visualization/VisualizationTabWidget.cpp b/gui/src/Visualization/VisualizationTabWidget.cpp index 7a3655a..4061a08 100644 --- a/gui/src/Visualization/VisualizationTabWidget.cpp +++ b/gui/src/Visualization/VisualizationTabWidget.cpp @@ -1,6 +1,9 @@ #include "Visualization/VisualizationTabWidget.h" #include "ui_VisualizationTabWidget.h" +#include "Visualization/VisualizationZoneWidget.h" + + VisualizationTabWidget::VisualizationTabWidget(QWidget *parent) : QWidget{parent}, ui{new Ui::VisualizationTabWidget} { @@ -11,3 +14,36 @@ VisualizationTabWidget::~VisualizationTabWidget() { delete ui; } + +void VisualizationTabWidget::addZone(VisualizationZoneWidget *zoneWidget) +{ + this->layout()->addWidget(zoneWidget); +} + +VisualizationZoneWidget *VisualizationTabWidget::createZone() +{ + auto zoneWidget = new VisualizationZoneWidget{this}; + this->addZone(zoneWidget); + + return zoneWidget; +} + +void VisualizationTabWidget::removeZone(VisualizationZoneWidget *zone) +{ +} + +void VisualizationTabWidget::accept(IVisualizationWidget *visitor) +{ + // TODO: manage the visitor +} + +void VisualizationTabWidget::close() +{ + // The main view cannot be directly closed. + return; +} + +QString VisualizationTabWidget::name() const +{ + return QStringLiteral("MainView"); +} diff --git a/gui/src/Visualization/VisualizationWidget.cpp b/gui/src/Visualization/VisualizationWidget.cpp index 91c1f61..5fa0cda 100644 --- a/gui/src/Visualization/VisualizationWidget.cpp +++ b/gui/src/Visualization/VisualizationWidget.cpp @@ -1,12 +1,11 @@ #include "Visualization/VisualizationWidget.h" #include "Visualization/VisualizationTabWidget.h" +#include "Visualization/qcustomplot.h" + #include "ui_VisualizationWidget.h" -#include #include -#include "iostream" - Q_LOGGING_CATEGORY(LOG_VisualizationWidget, "VisualizationWidget") VisualizationWidget::VisualizationWidget(QWidget *parent) @@ -19,6 +18,12 @@ VisualizationWidget::VisualizationWidget(QWidget *parent) addTabViewButton->setCursor(Qt::ArrowCursor); addTabViewButton->setAutoRaise(true); ui->tabWidget->setCornerWidget(addTabViewButton, Qt::TopRightCorner); + auto width = ui->tabWidget->cornerWidget()->width(); + auto height = ui->tabWidget->cornerWidget()->height(); + addTabViewButton->setMinimumHeight(height); + addTabViewButton->setMinimumWidth(width); + ui->tabWidget->setMinimumHeight(height); + ui->tabWidget->setMinimumWidth(width); auto addTabView = [&]() { auto index = ui->tabWidget->addTab(new VisualizationTabWidget(ui->tabWidget), @@ -41,3 +46,35 @@ VisualizationWidget::~VisualizationWidget() { delete ui; } + +void VisualizationWidget::addTab(VisualizationTabWidget *tabWidget) +{ + // NOTE: check is this method has to be deleted because of its dupplicated version visible as + // lambda function (in the constructor) +} + +VisualizationTabWidget *VisualizationWidget::createTab() +{ +} + +void VisualizationWidget::removeTab(VisualizationTabWidget *tab) +{ + // NOTE: check is this method has to be deleted because of its dupplicated version visible as + // lambda function (in the constructor) +} + +void VisualizationWidget::accept(IVisualizationWidget *visitor) +{ + // TODO: manage the visitor +} + +void VisualizationWidget::close() +{ + // The main view cannot be directly closed. + return; +} + +QString VisualizationWidget::name() const +{ + return QStringLiteral("MainView"); +} diff --git a/gui/src/Visualization/VisualizationZoneWidget.cpp b/gui/src/Visualization/VisualizationZoneWidget.cpp index ea7a0fb..ba4aa14 100644 --- a/gui/src/Visualization/VisualizationZoneWidget.cpp +++ b/gui/src/Visualization/VisualizationZoneWidget.cpp @@ -1,6 +1,8 @@ #include "Visualization/VisualizationZoneWidget.h" #include "ui_VisualizationZoneWidget.h" +#include "Visualization/VisualizationGraphWidget.h" + VisualizationZoneWidget::VisualizationZoneWidget(QWidget *parent) : QWidget{parent}, ui{new Ui::VisualizationZoneWidget} { @@ -11,3 +13,36 @@ VisualizationZoneWidget::~VisualizationZoneWidget() { delete ui; } + +void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget) +{ + ui->visualizationZoneFrame->layout()->addWidget(graphWidget); +} + +VisualizationGraphWidget *VisualizationZoneWidget::createGraph() +{ + auto graphWidget = new VisualizationGraphWidget{this}; + this->addGraph(graphWidget); + + return graphWidget; +} + +void VisualizationZoneWidget::removeGraph(VisualizationGraphWidget *graph) +{ +} + +void VisualizationZoneWidget::accept(IVisualizationWidget *visitor) +{ + // TODO: manage the visitor +} + +void VisualizationZoneWidget::close() +{ + // The main view cannot be directly closed. + return; +} + +QString VisualizationZoneWidget::name() const +{ + return QStringLiteral("MainView"); +} diff --git a/gui/ui/sidepane/SqpSidePane.ui b/gui/ui/SidePane/SqpSidePane.ui similarity index 100% rename from gui/ui/sidepane/SqpSidePane.ui rename to gui/ui/SidePane/SqpSidePane.ui diff --git a/gui/ui/TimeWidget/TimeWidget.ui b/gui/ui/TimeWidget/TimeWidget.ui new file mode 100644 index 0000000..67cc2c2 --- /dev/null +++ b/gui/ui/TimeWidget/TimeWidget.ui @@ -0,0 +1,85 @@ + + + TimeWidget + + + + 0 + 0 + 716 + 48 + + + + + 0 + 0 + + + + Form + + + + + + + 0 + 0 + + + + TStart : + + + + + + + + 0 + 0 + + + + dd/MM/yyyy HH:mm:ss:zzz + + + true + + + + + + + + 0 + 0 + + + + TEnd : + + + + + + + + 0 + 0 + + + + dd/MM/yyyy HH:mm:ss:zzz + + + true + + + + + + + + diff --git a/gui/ui/Variable/VariableInspectorWidget.ui b/gui/ui/Variable/VariableInspectorWidget.ui new file mode 100644 index 0000000..24fdb97 --- /dev/null +++ b/gui/ui/Variable/VariableInspectorWidget.ui @@ -0,0 +1,31 @@ + + + VariableInspectorWidget + + + + 0 + 0 + 400 + 300 + + + + Variables + + + + + + true + + + true + + + + + + + + diff --git a/gui/ui/visualization/VisualizationGraphWidget.ui b/gui/ui/Visualization/VisualizationGraphWidget.ui similarity index 60% rename from gui/ui/visualization/VisualizationGraphWidget.ui rename to gui/ui/Visualization/VisualizationGraphWidget.ui index c7c4fd0..bcecbc4 100644 --- a/gui/ui/visualization/VisualizationGraphWidget.ui +++ b/gui/ui/Visualization/VisualizationGraphWidget.ui @@ -1,9 +1,7 @@ + - - - VisualizationGraphWidget - + 0 @@ -15,7 +13,20 @@ Form + + + + + - + + + QCustomPlot + QWidget +
Visualization/qcustomplot.h
+ 1 +
+
+
diff --git a/gui/ui/visualization/VisualizationTabWidget.ui b/gui/ui/Visualization/VisualizationTabWidget.ui similarity index 78% rename from gui/ui/visualization/VisualizationTabWidget.ui rename to gui/ui/Visualization/VisualizationTabWidget.ui index 543adda..96002e1 100644 --- a/gui/ui/visualization/VisualizationTabWidget.ui +++ b/gui/ui/Visualization/VisualizationTabWidget.ui @@ -1,9 +1,7 @@ + - - - VisualizationTabWidget - + 0 @@ -15,7 +13,8 @@ Form + - + diff --git a/gui/ui/visualization/VisualizationWidget.ui b/gui/ui/Visualization/VisualizationWidget.ui similarity index 100% rename from gui/ui/visualization/VisualizationWidget.ui rename to gui/ui/Visualization/VisualizationWidget.ui diff --git a/gui/ui/visualization/VisualizationZoneWidget.ui b/gui/ui/Visualization/VisualizationZoneWidget.ui similarity index 60% rename from gui/ui/visualization/VisualizationZoneWidget.ui rename to gui/ui/Visualization/VisualizationZoneWidget.ui index ca440d1..fa0dae3 100644 --- a/gui/ui/visualization/VisualizationZoneWidget.ui +++ b/gui/ui/Visualization/VisualizationZoneWidget.ui @@ -1,9 +1,7 @@ + - - - VisualizationZoneWidget - + 0 @@ -15,7 +13,20 @@ Form + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + - + diff --git a/plugins/mockplugin/CMakeLists.txt b/plugins/mockplugin/CMakeLists.txt index 356eb49..916ee86 100644 --- a/plugins/mockplugin/CMakeLists.txt +++ b/plugins/mockplugin/CMakeLists.txt @@ -77,6 +77,12 @@ SCIQLOP_SET_TO_PARENT_SCOPE(CHECKSTYLE_INPUT_FILES) #LIST(APPEND CHECKSTYLE_EXCLUSION_FILES ${CMAKE_CURRENT_SOURCE_DIR}/vera-exclusions/exclusions.txt) SCIQLOP_SET_TO_PARENT_SCOPE(CHECKSTYLE_EXCLUSION_FILES) +# Temporary target to copy to plugins dir +find_package(sciqlop-mockplugin) +ADD_CUSTOM_TARGET(plugins + COMMAND ${CMAKE_COMMAND} -E copy ${SCIQLOP-MOCKPLUGIN_LIBRARIES} "${LIBRARY_OUTPUT_PATH}/plugins/${SCIQLOP-MOCKPLUGIN_LIBRARIES_NAME}" +) + # # Compile the tests # diff --git a/plugins/mockplugin/cmake/Findsciqlop-mockplugin.cmake b/plugins/mockplugin/cmake/Findsciqlop-mockplugin.cmake index 0c0d764..6fcdcc3 100644 --- a/plugins/mockplugin/cmake/Findsciqlop-mockplugin.cmake +++ b/plugins/mockplugin/cmake/Findsciqlop-mockplugin.cmake @@ -16,6 +16,7 @@ if(WIN32) set (OS_LIB_EXTENSION "dll") endif(WIN32) # TODO: Add Mac Support -set(SCIQLOP-MOCKPLUGIN_LIBRARIES ${LIBRARY_OUTPUT_PATH}/libsciqlop_mockplugin${DEBUG_SUFFIX}.${OS_LIB_EXTENSION}) +set(SCIQLOP-MOCKPLUGIN_LIBRARIES_NAME "libsciqlop_mockplugin${DEBUG_SUFFIX}.${OS_LIB_EXTENSION}") +set(SCIQLOP-MOCKPLUGIN_LIBRARIES "${LIBRARY_OUTPUT_PATH}/${SCIQLOP-MOCKPLUGIN_LIBRARIES_NAME}") set(SCIQLOP-MOCKPLUGIN_FOUND TRUE) diff --git a/plugins/mockplugin/include/CosinusProvider.h b/plugins/mockplugin/include/CosinusProvider.h new file mode 100644 index 0000000..cc48a53 --- /dev/null +++ b/plugins/mockplugin/include/CosinusProvider.h @@ -0,0 +1,16 @@ +#ifndef SCIQLOP_COSINUSPROVIDER_H +#define SCIQLOP_COSINUSPROVIDER_H + +#include + +/** + * @brief The CosinusProvider class is an example of how a data provider can generate data + */ +class CosinusProvider : public IDataProvider { +public: + /// @sa IDataProvider::retrieveData() + std::unique_ptr + retrieveData(const DataProviderParameters ¶meters) const override; +}; + +#endif // SCIQLOP_COSINUSPROVIDER_H diff --git a/plugins/mockplugin/include/MockPlugin.h b/plugins/mockplugin/include/MockPlugin.h index 7d18987..889705e 100644 --- a/plugins/mockplugin/include/MockPlugin.h +++ b/plugins/mockplugin/include/MockPlugin.h @@ -18,10 +18,6 @@ class MockPlugin : public QObject, public IPlugin { public: /// @sa IPlugin::initialize() void initialize() override; - -private: - /// Creates the data source item relative to the plugin - std::unique_ptr createDataSourceItem() const noexcept; }; #endif // SCIQLOP_MOCKPLUGIN_H diff --git a/plugins/mockplugin/src/CosinusProvider.cpp b/plugins/mockplugin/src/CosinusProvider.cpp new file mode 100644 index 0000000..8240f30 --- /dev/null +++ b/plugins/mockplugin/src/CosinusProvider.cpp @@ -0,0 +1,30 @@ +#include "CosinusProvider.h" + +#include +#include + +#include + +std::unique_ptr +CosinusProvider::retrieveData(const DataProviderParameters ¶meters) const +{ + // Gets the timerange from the parameters + auto start = parameters.m_TStart; + auto end = parameters.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, QStringLiteral("t"), QStringLiteral("")); + + auto dataIndex = 0; + for (auto time = start; time < end; ++time, ++dataIndex) { + scalarSeries->setData(dataIndex, time, std::cos(time)); + } + + return scalarSeries; +} diff --git a/plugins/mockplugin/src/MockPlugin.cpp b/plugins/mockplugin/src/MockPlugin.cpp index 599ad04..79d95d2 100644 --- a/plugins/mockplugin/src/MockPlugin.cpp +++ b/plugins/mockplugin/src/MockPlugin.cpp @@ -1,7 +1,9 @@ -#include +#include "MockPlugin.h" +#include "CosinusProvider.h" #include #include +#include #include @@ -12,34 +14,36 @@ namespace { /// Name of the data source const auto DATA_SOURCE_NAME = QStringLiteral("MMS"); -} // namespace +/// Creates the data provider relative to the plugin +std::unique_ptr createDataProvider() noexcept +{ + return std::make_unique(); +} -void MockPlugin::initialize() +std::unique_ptr createProductItem(const QString &productName) { - if (auto app = sqpApp) { - // Registers to the data source controller - auto &dataSourceController = app->dataSourceController(); - auto dataSourceUid = dataSourceController.registerDataSource(DATA_SOURCE_NAME); + auto result = std::make_unique(DataSourceItemType::PRODUCT, + QVector{productName}); - dataSourceController.setDataSourceItem(dataSourceUid, createDataSourceItem()); - } - else { - qCWarning(LOG_MockPlugin()) << tr("Can't access to SciQlop application"); - } + // Add action to load product from DataSourceController + result->addAction(std::make_unique( + QObject::tr("Load %1 product").arg(productName), [productName](DataSourceItem &item) { + if (auto app = sqpApp) { + app->dataSourceController().loadProductItem(item); + } + })); + + return result; } -std::unique_ptr MockPlugin::createDataSourceItem() const noexcept +/// Creates the data source item relative to the plugin +std::unique_ptr createDataSourceItem() noexcept { // Magnetic field products - auto fgmProduct = std::make_unique(DataSourceItemType::PRODUCT, - QVector{QStringLiteral("FGM")}); - auto scProduct = std::make_unique(DataSourceItemType::PRODUCT, - QVector{QStringLiteral("SC")}); - auto magneticFieldFolder = std::make_unique( DataSourceItemType::NODE, QVector{QStringLiteral("Magnetic field")}); - magneticFieldFolder->appendChild(std::move(fgmProduct)); - magneticFieldFolder->appendChild(std::move(scProduct)); + magneticFieldFolder->appendChild(createProductItem(QStringLiteral("FGM"))); + magneticFieldFolder->appendChild(createProductItem(QStringLiteral("SC"))); // Electric field products auto electricFieldFolder = std::make_unique( @@ -51,5 +55,25 @@ std::unique_ptr MockPlugin::createDataSourceItem() const noexcep root->appendChild(std::move(magneticFieldFolder)); root->appendChild(std::move(electricFieldFolder)); - return std::move(root); + return root; +} + +} // namespace + +void MockPlugin::initialize() +{ + if (auto app = sqpApp) { + // Registers to the data source controller + auto &dataSourceController = app->dataSourceController(); + auto dataSourceUid = dataSourceController.registerDataSource(DATA_SOURCE_NAME); + + // Sets data source tree + dataSourceController.setDataSourceItem(dataSourceUid, createDataSourceItem()); + + // Sets data provider + dataSourceController.setDataProvider(dataSourceUid, createDataProvider()); + } + else { + qCWarning(LOG_MockPlugin()) << tr("Can't access to SciQlop application"); + } }