##// END OF EJS Templates
Merge branch 'feature/RenameVariable' into develop
Alexandre Leroux -
r639:6af26c25c341 merge
parent child
Show More
@@ -0,0 +1,31
1 #ifndef SCIQLOP_RENAMEVARIABLEDIALOG_H
2 #define SCIQLOP_RENAMEVARIABLEDIALOG_H
3
4 #include <QDialog>
5
6 namespace Ui {
7 class RenameVariableDialog;
8 } // Ui
9
10 /**
11 * @brief The RenameVariableDialog class represents the dialog to rename a variable
12 */
13 class RenameVariableDialog : public QDialog {
14 public:
15 explicit RenameVariableDialog(const QString &defaultName,
16 const QVector<QString> &forbiddenNames,
17 QWidget *parent = nullptr);
18 virtual ~RenameVariableDialog() noexcept;
19
20 QString name() const noexcept;
21
22 public slots:
23 void accept() override;
24
25 private:
26 Ui::RenameVariableDialog *ui;
27 QString m_DefaultName;
28 QVector<QString> m_ForbiddenNames;
29 };
30
31 #endif // SCIQLOP_RENAMEVARIABLEDIALOG_H
@@ -0,0 +1,63
1 #include "Variable/RenameVariableDialog.h"
2
3 #include <ui_RenameVariableDialog.h>
4
5 RenameVariableDialog::RenameVariableDialog(const QString &defaultName,
6 const QVector<QString> &forbiddenNames, QWidget *parent)
7 : QDialog{parent},
8 ui{new Ui::RenameVariableDialog},
9 m_DefaultName{defaultName},
10 m_ForbiddenNames{forbiddenNames}
11 {
12 ui->setupUi(this);
13
14 connect(ui->nameLineEdit, &QLineEdit::textChanged, [this]() { ui->errorLabel->hide(); });
15
16 ui->nameLineEdit->setText(defaultName);
17 ui->nameLineEdit->selectAll();
18 ui->nameLineEdit->setFocus();
19 }
20
21 RenameVariableDialog::~RenameVariableDialog() noexcept
22 {
23 delete ui;
24 }
25
26 QString RenameVariableDialog::name() const noexcept
27 {
28 return ui->nameLineEdit->text();
29 }
30
31 void RenameVariableDialog::accept()
32 {
33 auto invalidateInput = [this](const auto &error) {
34 ui->nameLineEdit->selectAll();
35 ui->nameLineEdit->setFocus();
36 ui->errorLabel->setText(error);
37 ui->errorLabel->show();
38 };
39
40 // Empty name
41 auto name = ui->nameLineEdit->text();
42 if (name.isEmpty()) {
43 invalidateInput(tr("A variable name must be specified"));
44 return;
45 }
46
47 // Same name when opening dialog
48 if (name.compare(m_DefaultName, Qt::CaseInsensitive) == 0) {
49 reject();
50 return;
51 }
52
53 // Forbidden name
54 auto isForbidden
55 = [&name](const auto &it) { return name.compare(it, Qt::CaseInsensitive) == 0; };
56 if (std::any_of(m_ForbiddenNames.cbegin(), m_ForbiddenNames.cend(), isForbidden)) {
57 invalidateInput(tr("'%1' is already used").arg(name));
58 return;
59 }
60
61 // Valid name
62 QDialog::accept();
63 }
@@ -0,0 +1,90
1 <?xml version="1.0" encoding="UTF-8"?>
2 <ui version="4.0">
3 <class>RenameVariableDialog</class>
4 <widget class="QDialog" name="RenameVariableDialog">
5 <property name="geometry">
6 <rect>
7 <x>0</x>
8 <y>0</y>
9 <width>379</width>
10 <height>109</height>
11 </rect>
12 </property>
13 <property name="windowTitle">
14 <string>Rename variable</string>
15 </property>
16 <layout class="QGridLayout" name="gridLayout">
17 <item row="2" column="0">
18 <spacer name="verticalSpacer">
19 <property name="orientation">
20 <enum>Qt::Vertical</enum>
21 </property>
22 <property name="sizeHint" stdset="0">
23 <size>
24 <width>20</width>
25 <height>40</height>
26 </size>
27 </property>
28 </spacer>
29 </item>
30 <item row="3" column="0">
31 <widget class="QDialogButtonBox" name="buttonBox">
32 <property name="orientation">
33 <enum>Qt::Horizontal</enum>
34 </property>
35 <property name="standardButtons">
36 <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
37 </property>
38 </widget>
39 </item>
40 <item row="0" column="0">
41 <widget class="QLineEdit" name="nameLineEdit"/>
42 </item>
43 <item row="1" column="0">
44 <widget class="QLabel" name="errorLabel">
45 <property name="styleSheet">
46 <string notr="true">color: rgb(255, 0, 0);</string>
47 </property>
48 <property name="text">
49 <string>Error label</string>
50 </property>
51 </widget>
52 </item>
53 </layout>
54 </widget>
55 <resources/>
56 <connections>
57 <connection>
58 <sender>buttonBox</sender>
59 <signal>accepted()</signal>
60 <receiver>RenameVariableDialog</receiver>
61 <slot>accept()</slot>
62 <hints>
63 <hint type="sourcelabel">
64 <x>248</x>
65 <y>254</y>
66 </hint>
67 <hint type="destinationlabel">
68 <x>157</x>
69 <y>274</y>
70 </hint>
71 </hints>
72 </connection>
73 <connection>
74 <sender>buttonBox</sender>
75 <signal>rejected()</signal>
76 <receiver>RenameVariableDialog</receiver>
77 <slot>reject()</slot>
78 <hints>
79 <hint type="sourcelabel">
80 <x>316</x>
81 <y>260</y>
82 </hint>
83 <hint type="destinationlabel">
84 <x>286</x>
85 <y>274</y>
86 </hint>
87 </hints>
88 </connection>
89 </connections>
90 </ui>
@@ -1,74 +1,75
1 #ifndef SCIQLOP_VARIABLE_H
1 #ifndef SCIQLOP_VARIABLE_H
2 #define SCIQLOP_VARIABLE_H
2 #define SCIQLOP_VARIABLE_H
3
3
4 #include "CoreGlobal.h"
4 #include "CoreGlobal.h"
5
5
6 #include <Data/DataSeriesIterator.h>
6 #include <Data/DataSeriesIterator.h>
7 #include <Data/SqpRange.h>
7 #include <Data/SqpRange.h>
8
8
9 #include <QLoggingCategory>
9 #include <QLoggingCategory>
10 #include <QObject>
10 #include <QObject>
11
11
12 #include <Common/MetaTypes.h>
12 #include <Common/MetaTypes.h>
13 #include <Common/spimpl.h>
13 #include <Common/spimpl.h>
14
14
15 Q_DECLARE_LOGGING_CATEGORY(LOG_Variable)
15 Q_DECLARE_LOGGING_CATEGORY(LOG_Variable)
16
16
17 class IDataSeries;
17 class IDataSeries;
18 class QString;
18 class QString;
19
19
20 /**
20 /**
21 * @brief The Variable class represents a variable in SciQlop.
21 * @brief The Variable class represents a variable in SciQlop.
22 */
22 */
23 class SCIQLOP_CORE_EXPORT Variable : public QObject {
23 class SCIQLOP_CORE_EXPORT Variable : public QObject {
24
24
25 Q_OBJECT
25 Q_OBJECT
26
26
27 public:
27 public:
28 explicit Variable(const QString &name, const SqpRange &dateTime,
28 explicit Variable(const QString &name, const SqpRange &dateTime,
29 const QVariantHash &metadata = {});
29 const QVariantHash &metadata = {});
30
30
31 QString name() const noexcept;
31 QString name() const noexcept;
32 void setName(const QString &name) noexcept;
32 SqpRange range() const noexcept;
33 SqpRange range() const noexcept;
33 void setRange(const SqpRange &range) noexcept;
34 void setRange(const SqpRange &range) noexcept;
34 SqpRange cacheRange() const noexcept;
35 SqpRange cacheRange() const noexcept;
35 void setCacheRange(const SqpRange &cacheRange) noexcept;
36 void setCacheRange(const SqpRange &cacheRange) noexcept;
36
37
37 /// Returns the real range of the variable, i.e. the min and max x-axis values of the data
38 /// Returns the real range of the variable, i.e. the min and max x-axis values of the data
38 /// series between the range of the variable. The real range is updated each time the variable
39 /// series between the range of the variable. The real range is updated each time the variable
39 /// range or the data series changed
40 /// range or the data series changed
40 /// @return the real range, invalid range if the data series is null or empty
41 /// @return the real range, invalid range if the data series is null or empty
41 /// @sa setDataSeries()
42 /// @sa setDataSeries()
42 /// @sa setRange()
43 /// @sa setRange()
43 SqpRange realRange() const noexcept;
44 SqpRange realRange() const noexcept;
44
45
45 /// @return the data of the variable, nullptr if there is no data
46 /// @return the data of the variable, nullptr if there is no data
46 std::shared_ptr<IDataSeries> dataSeries() const noexcept;
47 std::shared_ptr<IDataSeries> dataSeries() const noexcept;
47
48
48 QVariantHash metadata() const noexcept;
49 QVariantHash metadata() const noexcept;
49
50
50 bool contains(const SqpRange &range) const noexcept;
51 bool contains(const SqpRange &range) const noexcept;
51 bool intersect(const SqpRange &range) const noexcept;
52 bool intersect(const SqpRange &range) const noexcept;
52 bool isInside(const SqpRange &range) const noexcept;
53 bool isInside(const SqpRange &range) const noexcept;
53
54
54 bool cacheContains(const SqpRange &range) const noexcept;
55 bool cacheContains(const SqpRange &range) const noexcept;
55 bool cacheIntersect(const SqpRange &range) const noexcept;
56 bool cacheIntersect(const SqpRange &range) const noexcept;
56 bool cacheIsInside(const SqpRange &range) const noexcept;
57 bool cacheIsInside(const SqpRange &range) const noexcept;
57
58
58 QVector<SqpRange> provideNotInCacheRangeList(const SqpRange &range) const noexcept;
59 QVector<SqpRange> provideNotInCacheRangeList(const SqpRange &range) const noexcept;
59 QVector<SqpRange> provideInCacheRangeList(const SqpRange &range) const noexcept;
60 QVector<SqpRange> provideInCacheRangeList(const SqpRange &range) const noexcept;
60 void mergeDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept;
61 void mergeDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept;
61
62
62 signals:
63 signals:
63 void updated();
64 void updated();
64
65
65 private:
66 private:
66 class VariablePrivate;
67 class VariablePrivate;
67 spimpl::unique_impl_ptr<VariablePrivate> impl;
68 spimpl::unique_impl_ptr<VariablePrivate> impl;
68 };
69 };
69
70
70 // Required for using shared_ptr in signals/slots
71 // Required for using shared_ptr in signals/slots
71 SCIQLOP_REGISTER_META_TYPE(VARIABLE_PTR_REGISTRY, std::shared_ptr<Variable>)
72 SCIQLOP_REGISTER_META_TYPE(VARIABLE_PTR_REGISTRY, std::shared_ptr<Variable>)
72 SCIQLOP_REGISTER_META_TYPE(VARIABLE_PTR_VECTOR_REGISTRY, QVector<std::shared_ptr<Variable> >)
73 SCIQLOP_REGISTER_META_TYPE(VARIABLE_PTR_VECTOR_REGISTRY, QVector<std::shared_ptr<Variable> >)
73
74
74 #endif // SCIQLOP_VARIABLE_H
75 #endif // SCIQLOP_VARIABLE_H
@@ -1,80 +1,81
1 #ifndef SCIQLOP_VARIABLEMODEL_H
1 #ifndef SCIQLOP_VARIABLEMODEL_H
2 #define SCIQLOP_VARIABLEMODEL_H
2 #define SCIQLOP_VARIABLEMODEL_H
3
3
4 #include "CoreGlobal.h"
4 #include "CoreGlobal.h"
5
5
6 #include <Data/SqpRange.h>
6 #include <Data/SqpRange.h>
7
7
8 #include <QAbstractTableModel>
8 #include <QAbstractTableModel>
9 #include <QLoggingCategory>
9 #include <QLoggingCategory>
10
10
11 #include <Common/MetaTypes.h>
11 #include <Common/MetaTypes.h>
12 #include <Common/spimpl.h>
12 #include <Common/spimpl.h>
13
13
14 Q_DECLARE_LOGGING_CATEGORY(LOG_VariableModel)
14 Q_DECLARE_LOGGING_CATEGORY(LOG_VariableModel)
15
15
16 enum VariableRoles { ProgressRole = Qt::UserRole };
16 enum VariableRoles { ProgressRole = Qt::UserRole };
17
17
18
18
19 class IDataSeries;
19 class IDataSeries;
20 class Variable;
20 class Variable;
21
21
22 /**
22 /**
23 * @brief The VariableModel class aims to hold the variables that have been created in SciQlop
23 * @brief The VariableModel class aims to hold the variables that have been created in SciQlop
24 */
24 */
25 class SCIQLOP_CORE_EXPORT VariableModel : public QAbstractTableModel {
25 class SCIQLOP_CORE_EXPORT VariableModel : public QAbstractTableModel {
26 Q_OBJECT
26 Q_OBJECT
27 public:
27 public:
28 explicit VariableModel(QObject *parent = nullptr);
28 explicit VariableModel(QObject *parent = nullptr);
29
29
30 /**
30 /**
31 * Creates a new variable in the model
31 * Creates a new variable in the model
32 * @param name the name of the new variable
32 * @param name the name of the new variable
33 * @param dateTime the dateTime of the new variable
33 * @param dateTime the dateTime of the new variable
34 * @param metadata the metadata associated to the new variable
34 * @param metadata the metadata associated to the new variable
35 * @return the pointer to the new variable
35 * @return the pointer to the new variable
36 */
36 */
37 std::shared_ptr<Variable> createVariable(const QString &name, const SqpRange &dateTime,
37 std::shared_ptr<Variable> createVariable(const QString &name, const SqpRange &dateTime,
38 const QVariantHash &metadata) noexcept;
38 const QVariantHash &metadata) noexcept;
39
39
40 /**
40 /**
41 * Deletes a variable from the model, if it exists
41 * Deletes a variable from the model, if it exists
42 * @param variable the variable to delete
42 * @param variable the variable to delete
43 */
43 */
44 void deleteVariable(std::shared_ptr<Variable> variable) noexcept;
44 void deleteVariable(std::shared_ptr<Variable> variable) noexcept;
45
45
46
46
47 std::shared_ptr<Variable> variable(int index) const;
47 std::shared_ptr<Variable> variable(int index) const;
48 std::vector<std::shared_ptr<Variable> > variables() const;
48
49
49 void setDataProgress(std::shared_ptr<Variable> variable, double progress);
50 void setDataProgress(std::shared_ptr<Variable> variable, double progress);
50
51
51
52
52 // /////////////////////////// //
53 // /////////////////////////// //
53 // QAbstractTableModel methods //
54 // QAbstractTableModel methods //
54 // /////////////////////////// //
55 // /////////////////////////// //
55
56
56 virtual int columnCount(const QModelIndex &parent = QModelIndex{}) const override;
57 virtual int columnCount(const QModelIndex &parent = QModelIndex{}) const override;
57 virtual int rowCount(const QModelIndex &parent = QModelIndex{}) const override;
58 virtual int rowCount(const QModelIndex &parent = QModelIndex{}) const override;
58 virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
59 virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
59 virtual QVariant headerData(int section, Qt::Orientation orientation,
60 virtual QVariant headerData(int section, Qt::Orientation orientation,
60 int role = Qt::DisplayRole) const override;
61 int role = Qt::DisplayRole) const override;
61
62
62
63
63 void abortProgress(const QModelIndex &index);
64 void abortProgress(const QModelIndex &index);
64
65
65 signals:
66 signals:
66 void abortProgessRequested(std::shared_ptr<Variable> variable);
67 void abortProgessRequested(std::shared_ptr<Variable> variable);
67
68
68 private:
69 private:
69 class VariableModelPrivate;
70 class VariableModelPrivate;
70 spimpl::unique_impl_ptr<VariableModelPrivate> impl;
71 spimpl::unique_impl_ptr<VariableModelPrivate> impl;
71
72
72 private slots:
73 private slots:
73 /// Slot called when data of a variable has been updated
74 /// Slot called when data of a variable has been updated
74 void onVariableUpdated() noexcept;
75 void onVariableUpdated() noexcept;
75 };
76 };
76
77
77 // Registers QVector<int> metatype so it can be used in VariableModel::dataChanged() signal
78 // Registers QVector<int> metatype so it can be used in VariableModel::dataChanged() signal
78 SCIQLOP_REGISTER_META_TYPE(QVECTOR_INT_REGISTRY, QVector<int>)
79 SCIQLOP_REGISTER_META_TYPE(QVECTOR_INT_REGISTRY, QVector<int>)
79
80
80 #endif // SCIQLOP_VARIABLEMODEL_H
81 #endif // SCIQLOP_VARIABLEMODEL_H
@@ -1,270 +1,277
1 #include "Variable/Variable.h"
1 #include "Variable/Variable.h"
2
2
3 #include <Data/IDataSeries.h>
3 #include <Data/IDataSeries.h>
4 #include <Data/SqpRange.h>
4 #include <Data/SqpRange.h>
5
5
6 #include <QMutex>
6 #include <QMutex>
7 #include <QReadWriteLock>
7 #include <QReadWriteLock>
8 #include <QThread>
8 #include <QThread>
9
9
10 Q_LOGGING_CATEGORY(LOG_Variable, "Variable")
10 Q_LOGGING_CATEGORY(LOG_Variable, "Variable")
11
11
12 struct Variable::VariablePrivate {
12 struct Variable::VariablePrivate {
13 explicit VariablePrivate(const QString &name, const SqpRange &dateTime,
13 explicit VariablePrivate(const QString &name, const SqpRange &dateTime,
14 const QVariantHash &metadata)
14 const QVariantHash &metadata)
15 : m_Name{name},
15 : m_Name{name},
16 m_Range{dateTime},
16 m_Range{dateTime},
17 m_Metadata{metadata},
17 m_Metadata{metadata},
18 m_DataSeries{nullptr},
18 m_DataSeries{nullptr},
19 m_RealRange{INVALID_RANGE}
19 m_RealRange{INVALID_RANGE}
20 {
20 {
21 }
21 }
22
22
23 void lockRead() { m_Lock.lockForRead(); }
23 void lockRead() { m_Lock.lockForRead(); }
24 void lockWrite() { m_Lock.lockForWrite(); }
24 void lockWrite() { m_Lock.lockForWrite(); }
25 void unlock() { m_Lock.unlock(); }
25 void unlock() { m_Lock.unlock(); }
26
26
27 void purgeDataSeries()
27 void purgeDataSeries()
28 {
28 {
29 if (m_DataSeries) {
29 if (m_DataSeries) {
30 m_DataSeries->purge(m_CacheRange.m_TStart, m_CacheRange.m_TEnd);
30 m_DataSeries->purge(m_CacheRange.m_TStart, m_CacheRange.m_TEnd);
31 }
31 }
32 updateRealRange();
32 updateRealRange();
33 }
33 }
34
34
35 /// Updates real range according to current variable range and data series
35 /// Updates real range according to current variable range and data series
36 void updateRealRange()
36 void updateRealRange()
37 {
37 {
38 if (m_DataSeries) {
38 if (m_DataSeries) {
39 m_DataSeries->lockRead();
39 m_DataSeries->lockRead();
40 auto end = m_DataSeries->cend();
40 auto end = m_DataSeries->cend();
41 auto minXAxisIt = m_DataSeries->minXAxisData(m_Range.m_TStart);
41 auto minXAxisIt = m_DataSeries->minXAxisData(m_Range.m_TStart);
42 auto maxXAxisIt = m_DataSeries->maxXAxisData(m_Range.m_TEnd);
42 auto maxXAxisIt = m_DataSeries->maxXAxisData(m_Range.m_TEnd);
43
43
44 m_RealRange = (minXAxisIt != end && maxXAxisIt != end)
44 m_RealRange = (minXAxisIt != end && maxXAxisIt != end)
45 ? SqpRange{minXAxisIt->x(), maxXAxisIt->x()}
45 ? SqpRange{minXAxisIt->x(), maxXAxisIt->x()}
46 : INVALID_RANGE;
46 : INVALID_RANGE;
47 m_DataSeries->unlock();
47 m_DataSeries->unlock();
48 }
48 }
49 else {
49 else {
50 m_RealRange = INVALID_RANGE;
50 m_RealRange = INVALID_RANGE;
51 }
51 }
52 }
52 }
53
53
54 QString m_Name;
54 QString m_Name;
55
55
56 SqpRange m_Range;
56 SqpRange m_Range;
57 SqpRange m_CacheRange;
57 SqpRange m_CacheRange;
58 QVariantHash m_Metadata;
58 QVariantHash m_Metadata;
59 std::shared_ptr<IDataSeries> m_DataSeries;
59 std::shared_ptr<IDataSeries> m_DataSeries;
60 SqpRange m_RealRange;
60 SqpRange m_RealRange;
61
61
62 QReadWriteLock m_Lock;
62 QReadWriteLock m_Lock;
63 };
63 };
64
64
65 Variable::Variable(const QString &name, const SqpRange &dateTime, const QVariantHash &metadata)
65 Variable::Variable(const QString &name, const SqpRange &dateTime, const QVariantHash &metadata)
66 : impl{spimpl::make_unique_impl<VariablePrivate>(name, dateTime, metadata)}
66 : impl{spimpl::make_unique_impl<VariablePrivate>(name, dateTime, metadata)}
67 {
67 {
68 }
68 }
69
69
70 QString Variable::name() const noexcept
70 QString Variable::name() const noexcept
71 {
71 {
72 impl->lockRead();
72 impl->lockRead();
73 auto name = impl->m_Name;
73 auto name = impl->m_Name;
74 impl->unlock();
74 impl->unlock();
75 return name;
75 return name;
76 }
76 }
77
77
78 void Variable::setName(const QString &name) noexcept
79 {
80 impl->lockWrite();
81 impl->m_Name = name;
82 impl->unlock();
83 }
84
78 SqpRange Variable::range() const noexcept
85 SqpRange Variable::range() const noexcept
79 {
86 {
80 impl->lockRead();
87 impl->lockRead();
81 auto range = impl->m_Range;
88 auto range = impl->m_Range;
82 impl->unlock();
89 impl->unlock();
83 return range;
90 return range;
84 }
91 }
85
92
86 void Variable::setRange(const SqpRange &range) noexcept
93 void Variable::setRange(const SqpRange &range) noexcept
87 {
94 {
88 impl->lockWrite();
95 impl->lockWrite();
89 impl->m_Range = range;
96 impl->m_Range = range;
90 impl->updateRealRange();
97 impl->updateRealRange();
91 impl->unlock();
98 impl->unlock();
92 }
99 }
93
100
94 SqpRange Variable::cacheRange() const noexcept
101 SqpRange Variable::cacheRange() const noexcept
95 {
102 {
96 impl->lockRead();
103 impl->lockRead();
97 auto cacheRange = impl->m_CacheRange;
104 auto cacheRange = impl->m_CacheRange;
98 impl->unlock();
105 impl->unlock();
99 return cacheRange;
106 return cacheRange;
100 }
107 }
101
108
102 void Variable::setCacheRange(const SqpRange &cacheRange) noexcept
109 void Variable::setCacheRange(const SqpRange &cacheRange) noexcept
103 {
110 {
104 impl->lockWrite();
111 impl->lockWrite();
105 if (cacheRange != impl->m_CacheRange) {
112 if (cacheRange != impl->m_CacheRange) {
106 impl->m_CacheRange = cacheRange;
113 impl->m_CacheRange = cacheRange;
107 impl->purgeDataSeries();
114 impl->purgeDataSeries();
108 }
115 }
109 impl->unlock();
116 impl->unlock();
110 }
117 }
111
118
112 SqpRange Variable::realRange() const noexcept
119 SqpRange Variable::realRange() const noexcept
113 {
120 {
114 return impl->m_RealRange;
121 return impl->m_RealRange;
115 }
122 }
116
123
117 void Variable::mergeDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept
124 void Variable::mergeDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept
118 {
125 {
119 qCDebug(LOG_Variable()) << "TORM Variable::mergeDataSeries"
126 qCDebug(LOG_Variable()) << "TORM Variable::mergeDataSeries"
120 << QThread::currentThread()->objectName();
127 << QThread::currentThread()->objectName();
121 if (!dataSeries) {
128 if (!dataSeries) {
122 /// @todo ALX : log
129 /// @todo ALX : log
123 return;
130 return;
124 }
131 }
125
132
126 // Add or merge the data
133 // Add or merge the data
127 impl->lockWrite();
134 impl->lockWrite();
128 if (!impl->m_DataSeries) {
135 if (!impl->m_DataSeries) {
129 impl->m_DataSeries = dataSeries->clone();
136 impl->m_DataSeries = dataSeries->clone();
130 }
137 }
131 else {
138 else {
132 impl->m_DataSeries->merge(dataSeries.get());
139 impl->m_DataSeries->merge(dataSeries.get());
133 }
140 }
134 impl->purgeDataSeries();
141 impl->purgeDataSeries();
135 impl->unlock();
142 impl->unlock();
136 }
143 }
137
144
138 std::shared_ptr<IDataSeries> Variable::dataSeries() const noexcept
145 std::shared_ptr<IDataSeries> Variable::dataSeries() const noexcept
139 {
146 {
140 impl->lockRead();
147 impl->lockRead();
141 auto dataSeries = impl->m_DataSeries;
148 auto dataSeries = impl->m_DataSeries;
142 impl->unlock();
149 impl->unlock();
143
150
144 return dataSeries;
151 return dataSeries;
145 }
152 }
146
153
147 QVariantHash Variable::metadata() const noexcept
154 QVariantHash Variable::metadata() const noexcept
148 {
155 {
149 impl->lockRead();
156 impl->lockRead();
150 auto metadata = impl->m_Metadata;
157 auto metadata = impl->m_Metadata;
151 impl->unlock();
158 impl->unlock();
152 return metadata;
159 return metadata;
153 }
160 }
154
161
155 bool Variable::contains(const SqpRange &range) const noexcept
162 bool Variable::contains(const SqpRange &range) const noexcept
156 {
163 {
157 impl->lockRead();
164 impl->lockRead();
158 auto res = impl->m_Range.contains(range);
165 auto res = impl->m_Range.contains(range);
159 impl->unlock();
166 impl->unlock();
160 return res;
167 return res;
161 }
168 }
162
169
163 bool Variable::intersect(const SqpRange &range) const noexcept
170 bool Variable::intersect(const SqpRange &range) const noexcept
164 {
171 {
165
172
166 impl->lockRead();
173 impl->lockRead();
167 auto res = impl->m_Range.intersect(range);
174 auto res = impl->m_Range.intersect(range);
168 impl->unlock();
175 impl->unlock();
169 return res;
176 return res;
170 }
177 }
171
178
172 bool Variable::isInside(const SqpRange &range) const noexcept
179 bool Variable::isInside(const SqpRange &range) const noexcept
173 {
180 {
174 impl->lockRead();
181 impl->lockRead();
175 auto res = range.contains(SqpRange{impl->m_Range.m_TStart, impl->m_Range.m_TEnd});
182 auto res = range.contains(SqpRange{impl->m_Range.m_TStart, impl->m_Range.m_TEnd});
176 impl->unlock();
183 impl->unlock();
177 return res;
184 return res;
178 }
185 }
179
186
180 bool Variable::cacheContains(const SqpRange &range) const noexcept
187 bool Variable::cacheContains(const SqpRange &range) const noexcept
181 {
188 {
182 impl->lockRead();
189 impl->lockRead();
183 auto res = impl->m_CacheRange.contains(range);
190 auto res = impl->m_CacheRange.contains(range);
184 impl->unlock();
191 impl->unlock();
185 return res;
192 return res;
186 }
193 }
187
194
188 bool Variable::cacheIntersect(const SqpRange &range) const noexcept
195 bool Variable::cacheIntersect(const SqpRange &range) const noexcept
189 {
196 {
190 impl->lockRead();
197 impl->lockRead();
191 auto res = impl->m_CacheRange.intersect(range);
198 auto res = impl->m_CacheRange.intersect(range);
192 impl->unlock();
199 impl->unlock();
193 return res;
200 return res;
194 }
201 }
195
202
196 bool Variable::cacheIsInside(const SqpRange &range) const noexcept
203 bool Variable::cacheIsInside(const SqpRange &range) const noexcept
197 {
204 {
198 impl->lockRead();
205 impl->lockRead();
199 auto res = range.contains(SqpRange{impl->m_CacheRange.m_TStart, impl->m_CacheRange.m_TEnd});
206 auto res = range.contains(SqpRange{impl->m_CacheRange.m_TStart, impl->m_CacheRange.m_TEnd});
200 impl->unlock();
207 impl->unlock();
201 return res;
208 return res;
202 }
209 }
203
210
204
211
205 QVector<SqpRange> Variable::provideNotInCacheRangeList(const SqpRange &range) const noexcept
212 QVector<SqpRange> Variable::provideNotInCacheRangeList(const SqpRange &range) const noexcept
206 {
213 {
207 // This code assume that cach in contigue. Can return 0, 1 or 2 SqpRange
214 // This code assume that cach in contigue. Can return 0, 1 or 2 SqpRange
208
215
209 auto notInCache = QVector<SqpRange>{};
216 auto notInCache = QVector<SqpRange>{};
210
217
211 if (!this->cacheContains(range)) {
218 if (!this->cacheContains(range)) {
212 if (range.m_TEnd <= impl->m_CacheRange.m_TStart
219 if (range.m_TEnd <= impl->m_CacheRange.m_TStart
213 || range.m_TStart >= impl->m_CacheRange.m_TEnd) {
220 || range.m_TStart >= impl->m_CacheRange.m_TEnd) {
214 notInCache << range;
221 notInCache << range;
215 }
222 }
216 else if (range.m_TStart < impl->m_CacheRange.m_TStart
223 else if (range.m_TStart < impl->m_CacheRange.m_TStart
217 && range.m_TEnd <= impl->m_CacheRange.m_TEnd) {
224 && range.m_TEnd <= impl->m_CacheRange.m_TEnd) {
218 notInCache << SqpRange{range.m_TStart, impl->m_CacheRange.m_TStart};
225 notInCache << SqpRange{range.m_TStart, impl->m_CacheRange.m_TStart};
219 }
226 }
220 else if (range.m_TStart < impl->m_CacheRange.m_TStart
227 else if (range.m_TStart < impl->m_CacheRange.m_TStart
221 && range.m_TEnd > impl->m_CacheRange.m_TEnd) {
228 && range.m_TEnd > impl->m_CacheRange.m_TEnd) {
222 notInCache << SqpRange{range.m_TStart, impl->m_CacheRange.m_TStart}
229 notInCache << SqpRange{range.m_TStart, impl->m_CacheRange.m_TStart}
223 << SqpRange{impl->m_CacheRange.m_TEnd, range.m_TEnd};
230 << SqpRange{impl->m_CacheRange.m_TEnd, range.m_TEnd};
224 }
231 }
225 else if (range.m_TStart < impl->m_CacheRange.m_TEnd) {
232 else if (range.m_TStart < impl->m_CacheRange.m_TEnd) {
226 notInCache << SqpRange{impl->m_CacheRange.m_TEnd, range.m_TEnd};
233 notInCache << SqpRange{impl->m_CacheRange.m_TEnd, range.m_TEnd};
227 }
234 }
228 else {
235 else {
229 qCCritical(LOG_Variable()) << tr("Detection of unknown case.")
236 qCCritical(LOG_Variable()) << tr("Detection of unknown case.")
230 << QThread::currentThread();
237 << QThread::currentThread();
231 }
238 }
232 }
239 }
233
240
234 return notInCache;
241 return notInCache;
235 }
242 }
236
243
237 QVector<SqpRange> Variable::provideInCacheRangeList(const SqpRange &range) const noexcept
244 QVector<SqpRange> Variable::provideInCacheRangeList(const SqpRange &range) const noexcept
238 {
245 {
239 // This code assume that cach in contigue. Can return 0 or 1 SqpRange
246 // This code assume that cach in contigue. Can return 0 or 1 SqpRange
240
247
241 auto inCache = QVector<SqpRange>{};
248 auto inCache = QVector<SqpRange>{};
242
249
243
250
244 if (this->intersect(range)) {
251 if (this->intersect(range)) {
245 if (range.m_TStart <= impl->m_CacheRange.m_TStart
252 if (range.m_TStart <= impl->m_CacheRange.m_TStart
246 && range.m_TEnd >= impl->m_CacheRange.m_TStart
253 && range.m_TEnd >= impl->m_CacheRange.m_TStart
247 && range.m_TEnd < impl->m_CacheRange.m_TEnd) {
254 && range.m_TEnd < impl->m_CacheRange.m_TEnd) {
248 inCache << SqpRange{impl->m_CacheRange.m_TStart, range.m_TEnd};
255 inCache << SqpRange{impl->m_CacheRange.m_TStart, range.m_TEnd};
249 }
256 }
250
257
251 else if (range.m_TStart >= impl->m_CacheRange.m_TStart
258 else if (range.m_TStart >= impl->m_CacheRange.m_TStart
252 && range.m_TEnd <= impl->m_CacheRange.m_TEnd) {
259 && range.m_TEnd <= impl->m_CacheRange.m_TEnd) {
253 inCache << range;
260 inCache << range;
254 }
261 }
255 else if (range.m_TStart > impl->m_CacheRange.m_TStart
262 else if (range.m_TStart > impl->m_CacheRange.m_TStart
256 && range.m_TEnd > impl->m_CacheRange.m_TEnd) {
263 && range.m_TEnd > impl->m_CacheRange.m_TEnd) {
257 inCache << SqpRange{range.m_TStart, impl->m_CacheRange.m_TEnd};
264 inCache << SqpRange{range.m_TStart, impl->m_CacheRange.m_TEnd};
258 }
265 }
259 else if (range.m_TStart <= impl->m_CacheRange.m_TStart
266 else if (range.m_TStart <= impl->m_CacheRange.m_TStart
260 && range.m_TEnd >= impl->m_CacheRange.m_TEnd) {
267 && range.m_TEnd >= impl->m_CacheRange.m_TEnd) {
261 inCache << impl->m_CacheRange;
268 inCache << impl->m_CacheRange;
262 }
269 }
263 else {
270 else {
264 qCCritical(LOG_Variable()) << tr("Detection of unknown case.")
271 qCCritical(LOG_Variable()) << tr("Detection of unknown case.")
265 << QThread::currentThread();
272 << QThread::currentThread();
266 }
273 }
267 }
274 }
268
275
269 return inCache;
276 return inCache;
270 }
277 }
@@ -1,260 +1,265
1 #include <Variable/Variable.h>
1 #include <Variable/Variable.h>
2 #include <Variable/VariableModel.h>
2 #include <Variable/VariableModel.h>
3
3
4 #include <Common/DateUtils.h>
4 #include <Common/DateUtils.h>
5
5
6 #include <Data/IDataSeries.h>
6 #include <Data/IDataSeries.h>
7
7
8 #include <QSize>
8 #include <QSize>
9 #include <unordered_map>
9 #include <unordered_map>
10
10
11 Q_LOGGING_CATEGORY(LOG_VariableModel, "VariableModel")
11 Q_LOGGING_CATEGORY(LOG_VariableModel, "VariableModel")
12
12
13 namespace {
13 namespace {
14
14
15 // Column indexes
15 // Column indexes
16 const auto NAME_COLUMN = 0;
16 const auto NAME_COLUMN = 0;
17 const auto TSTART_COLUMN = 1;
17 const auto TSTART_COLUMN = 1;
18 const auto TEND_COLUMN = 2;
18 const auto TEND_COLUMN = 2;
19 const auto UNIT_COLUMN = 3;
19 const auto UNIT_COLUMN = 3;
20 const auto MISSION_COLUMN = 4;
20 const auto MISSION_COLUMN = 4;
21 const auto PLUGIN_COLUMN = 5;
21 const auto PLUGIN_COLUMN = 5;
22 const auto NB_COLUMNS = 6;
22 const auto NB_COLUMNS = 6;
23
23
24 // Column properties
24 // Column properties
25 const auto DEFAULT_HEIGHT = 25;
25 const auto DEFAULT_HEIGHT = 25;
26 const auto DEFAULT_WIDTH = 100;
26 const auto DEFAULT_WIDTH = 100;
27
27
28 struct ColumnProperties {
28 struct ColumnProperties {
29 ColumnProperties(const QString &name = {}, int width = DEFAULT_WIDTH,
29 ColumnProperties(const QString &name = {}, int width = DEFAULT_WIDTH,
30 int height = DEFAULT_HEIGHT)
30 int height = DEFAULT_HEIGHT)
31 : m_Name{name}, m_Width{width}, m_Height{height}
31 : m_Name{name}, m_Width{width}, m_Height{height}
32 {
32 {
33 }
33 }
34
34
35 QString m_Name;
35 QString m_Name;
36 int m_Width;
36 int m_Width;
37 int m_Height;
37 int m_Height;
38 };
38 };
39
39
40 const auto COLUMN_PROPERTIES = QHash<int, ColumnProperties>{
40 const auto COLUMN_PROPERTIES = QHash<int, ColumnProperties>{
41 {NAME_COLUMN, {QObject::tr("Name")}}, {TSTART_COLUMN, {QObject::tr("tStart"), 180}},
41 {NAME_COLUMN, {QObject::tr("Name")}}, {TSTART_COLUMN, {QObject::tr("tStart"), 180}},
42 {TEND_COLUMN, {QObject::tr("tEnd"), 180}}, {UNIT_COLUMN, {QObject::tr("Unit")}},
42 {TEND_COLUMN, {QObject::tr("tEnd"), 180}}, {UNIT_COLUMN, {QObject::tr("Unit")}},
43 {MISSION_COLUMN, {QObject::tr("Mission")}}, {PLUGIN_COLUMN, {QObject::tr("Plugin")}}};
43 {MISSION_COLUMN, {QObject::tr("Mission")}}, {PLUGIN_COLUMN, {QObject::tr("Plugin")}}};
44
44
45 /// Format for datetimes
45 /// Format for datetimes
46 const auto DATETIME_FORMAT = QStringLiteral("dd/MM/yyyy \nhh:mm:ss:zzz");
46 const auto DATETIME_FORMAT = QStringLiteral("dd/MM/yyyy \nhh:mm:ss:zzz");
47
47
48
48
49 } // namespace
49 } // namespace
50
50
51 struct VariableModel::VariableModelPrivate {
51 struct VariableModel::VariableModelPrivate {
52 /// Variables created in SciQlop
52 /// Variables created in SciQlop
53 std::vector<std::shared_ptr<Variable> > m_Variables;
53 std::vector<std::shared_ptr<Variable> > m_Variables;
54 std::unordered_map<std::shared_ptr<Variable>, double> m_VariableToProgress;
54 std::unordered_map<std::shared_ptr<Variable>, double> m_VariableToProgress;
55
55
56 /// Return the row index of the variable. -1 if it's not found
56 /// Return the row index of the variable. -1 if it's not found
57 int indexOfVariable(Variable *variable) const noexcept;
57 int indexOfVariable(Variable *variable) const noexcept;
58 };
58 };
59
59
60 VariableModel::VariableModel(QObject *parent)
60 VariableModel::VariableModel(QObject *parent)
61 : QAbstractTableModel{parent}, impl{spimpl::make_unique_impl<VariableModelPrivate>()}
61 : QAbstractTableModel{parent}, impl{spimpl::make_unique_impl<VariableModelPrivate>()}
62 {
62 {
63 }
63 }
64
64
65 std::shared_ptr<Variable> VariableModel::createVariable(const QString &name,
65 std::shared_ptr<Variable> VariableModel::createVariable(const QString &name,
66 const SqpRange &dateTime,
66 const SqpRange &dateTime,
67 const QVariantHash &metadata) noexcept
67 const QVariantHash &metadata) noexcept
68 {
68 {
69 auto insertIndex = rowCount();
69 auto insertIndex = rowCount();
70 beginInsertRows({}, insertIndex, insertIndex);
70 beginInsertRows({}, insertIndex, insertIndex);
71
71
72 auto variable = std::make_shared<Variable>(name, dateTime, metadata);
72 auto variable = std::make_shared<Variable>(name, dateTime, metadata);
73
73
74 impl->m_Variables.push_back(variable);
74 impl->m_Variables.push_back(variable);
75 connect(variable.get(), &Variable::updated, this, &VariableModel::onVariableUpdated);
75 connect(variable.get(), &Variable::updated, this, &VariableModel::onVariableUpdated);
76
76
77 endInsertRows();
77 endInsertRows();
78
78
79 return variable;
79 return variable;
80 }
80 }
81
81
82 void VariableModel::deleteVariable(std::shared_ptr<Variable> variable) noexcept
82 void VariableModel::deleteVariable(std::shared_ptr<Variable> variable) noexcept
83 {
83 {
84 if (!variable) {
84 if (!variable) {
85 qCCritical(LOG_Variable()) << "Can't delete a null variable from the model";
85 qCCritical(LOG_Variable()) << "Can't delete a null variable from the model";
86 return;
86 return;
87 }
87 }
88
88
89 // Finds variable in the model
89 // Finds variable in the model
90 auto begin = impl->m_Variables.cbegin();
90 auto begin = impl->m_Variables.cbegin();
91 auto end = impl->m_Variables.cend();
91 auto end = impl->m_Variables.cend();
92 auto it = std::find(begin, end, variable);
92 auto it = std::find(begin, end, variable);
93 if (it != end) {
93 if (it != end) {
94 auto removeIndex = std::distance(begin, it);
94 auto removeIndex = std::distance(begin, it);
95
95
96 // Deletes variable
96 // Deletes variable
97 beginRemoveRows({}, removeIndex, removeIndex);
97 beginRemoveRows({}, removeIndex, removeIndex);
98 impl->m_Variables.erase(it);
98 impl->m_Variables.erase(it);
99 endRemoveRows();
99 endRemoveRows();
100 }
100 }
101 else {
101 else {
102 qCritical(LOG_VariableModel())
102 qCritical(LOG_VariableModel())
103 << tr("Can't delete variable %1 from the model: the variable is not in the model")
103 << tr("Can't delete variable %1 from the model: the variable is not in the model")
104 .arg(variable->name());
104 .arg(variable->name());
105 }
105 }
106
106
107 // Removes variable from progress map
107 // Removes variable from progress map
108 impl->m_VariableToProgress.erase(variable);
108 impl->m_VariableToProgress.erase(variable);
109 }
109 }
110
110
111
111
112 std::shared_ptr<Variable> VariableModel::variable(int index) const
112 std::shared_ptr<Variable> VariableModel::variable(int index) const
113 {
113 {
114 return (index >= 0 && index < impl->m_Variables.size()) ? impl->m_Variables[index] : nullptr;
114 return (index >= 0 && index < impl->m_Variables.size()) ? impl->m_Variables[index] : nullptr;
115 }
115 }
116
116
117 std::vector<std::shared_ptr<Variable> > VariableModel::variables() const
118 {
119 return impl->m_Variables;
120 }
121
117 void VariableModel::setDataProgress(std::shared_ptr<Variable> variable, double progress)
122 void VariableModel::setDataProgress(std::shared_ptr<Variable> variable, double progress)
118 {
123 {
119 if (progress > 0.0) {
124 if (progress > 0.0) {
120 impl->m_VariableToProgress[variable] = progress;
125 impl->m_VariableToProgress[variable] = progress;
121 }
126 }
122 else {
127 else {
123 impl->m_VariableToProgress.erase(variable);
128 impl->m_VariableToProgress.erase(variable);
124 }
129 }
125 auto modelIndex = createIndex(impl->indexOfVariable(variable.get()), NAME_COLUMN);
130 auto modelIndex = createIndex(impl->indexOfVariable(variable.get()), NAME_COLUMN);
126
131
127 emit dataChanged(modelIndex, modelIndex);
132 emit dataChanged(modelIndex, modelIndex);
128 }
133 }
129
134
130 int VariableModel::columnCount(const QModelIndex &parent) const
135 int VariableModel::columnCount(const QModelIndex &parent) const
131 {
136 {
132 Q_UNUSED(parent);
137 Q_UNUSED(parent);
133
138
134 return NB_COLUMNS;
139 return NB_COLUMNS;
135 }
140 }
136
141
137 int VariableModel::rowCount(const QModelIndex &parent) const
142 int VariableModel::rowCount(const QModelIndex &parent) const
138 {
143 {
139 Q_UNUSED(parent);
144 Q_UNUSED(parent);
140
145
141 return impl->m_Variables.size();
146 return impl->m_Variables.size();
142 }
147 }
143
148
144 QVariant VariableModel::data(const QModelIndex &index, int role) const
149 QVariant VariableModel::data(const QModelIndex &index, int role) const
145 {
150 {
146 if (!index.isValid()) {
151 if (!index.isValid()) {
147 return QVariant{};
152 return QVariant{};
148 }
153 }
149
154
150 if (index.row() < 0 || index.row() >= rowCount()) {
155 if (index.row() < 0 || index.row() >= rowCount()) {
151 return QVariant{};
156 return QVariant{};
152 }
157 }
153
158
154 if (role == Qt::DisplayRole) {
159 if (role == Qt::DisplayRole) {
155 if (auto variable = impl->m_Variables.at(index.row()).get()) {
160 if (auto variable = impl->m_Variables.at(index.row()).get()) {
156 switch (index.column()) {
161 switch (index.column()) {
157 case NAME_COLUMN:
162 case NAME_COLUMN:
158 return variable->name();
163 return variable->name();
159 case TSTART_COLUMN: {
164 case TSTART_COLUMN: {
160 auto range = variable->realRange();
165 auto range = variable->realRange();
161 return range != INVALID_RANGE
166 return range != INVALID_RANGE
162 ? DateUtils::dateTime(range.m_TStart).toString(DATETIME_FORMAT)
167 ? DateUtils::dateTime(range.m_TStart).toString(DATETIME_FORMAT)
163 : QVariant{};
168 : QVariant{};
164 }
169 }
165 case TEND_COLUMN: {
170 case TEND_COLUMN: {
166 auto range = variable->realRange();
171 auto range = variable->realRange();
167 return range != INVALID_RANGE
172 return range != INVALID_RANGE
168 ? DateUtils::dateTime(range.m_TEnd).toString(DATETIME_FORMAT)
173 ? DateUtils::dateTime(range.m_TEnd).toString(DATETIME_FORMAT)
169 : QVariant{};
174 : QVariant{};
170 }
175 }
171 case UNIT_COLUMN:
176 case UNIT_COLUMN:
172 return variable->metadata().value(QStringLiteral("units"));
177 return variable->metadata().value(QStringLiteral("units"));
173 case MISSION_COLUMN:
178 case MISSION_COLUMN:
174 return variable->metadata().value(QStringLiteral("mission"));
179 return variable->metadata().value(QStringLiteral("mission"));
175 case PLUGIN_COLUMN:
180 case PLUGIN_COLUMN:
176 return variable->metadata().value(QStringLiteral("plugin"));
181 return variable->metadata().value(QStringLiteral("plugin"));
177 default:
182 default:
178 // No action
183 // No action
179 break;
184 break;
180 }
185 }
181
186
182 qWarning(LOG_VariableModel())
187 qWarning(LOG_VariableModel())
183 << tr("Can't get data (unknown column %1)").arg(index.column());
188 << tr("Can't get data (unknown column %1)").arg(index.column());
184 }
189 }
185 else {
190 else {
186 qWarning(LOG_VariableModel()) << tr("Can't get data (no variable)");
191 qWarning(LOG_VariableModel()) << tr("Can't get data (no variable)");
187 }
192 }
188 }
193 }
189 else if (role == VariableRoles::ProgressRole) {
194 else if (role == VariableRoles::ProgressRole) {
190 if (auto variable = impl->m_Variables.at(index.row())) {
195 if (auto variable = impl->m_Variables.at(index.row())) {
191
196
192 auto it = impl->m_VariableToProgress.find(variable);
197 auto it = impl->m_VariableToProgress.find(variable);
193 if (it != impl->m_VariableToProgress.cend()) {
198 if (it != impl->m_VariableToProgress.cend()) {
194 return it->second;
199 return it->second;
195 }
200 }
196 }
201 }
197 }
202 }
198
203
199 return QVariant{};
204 return QVariant{};
200 }
205 }
201
206
202 QVariant VariableModel::headerData(int section, Qt::Orientation orientation, int role) const
207 QVariant VariableModel::headerData(int section, Qt::Orientation orientation, int role) const
203 {
208 {
204 if (role != Qt::DisplayRole && role != Qt::SizeHintRole) {
209 if (role != Qt::DisplayRole && role != Qt::SizeHintRole) {
205 return QVariant{};
210 return QVariant{};
206 }
211 }
207
212
208 if (orientation == Qt::Horizontal) {
213 if (orientation == Qt::Horizontal) {
209 auto propertiesIt = COLUMN_PROPERTIES.find(section);
214 auto propertiesIt = COLUMN_PROPERTIES.find(section);
210 if (propertiesIt != COLUMN_PROPERTIES.cend()) {
215 if (propertiesIt != COLUMN_PROPERTIES.cend()) {
211 // Role is either DisplayRole or SizeHintRole
216 // Role is either DisplayRole or SizeHintRole
212 return (role == Qt::DisplayRole)
217 return (role == Qt::DisplayRole)
213 ? QVariant{propertiesIt->m_Name}
218 ? QVariant{propertiesIt->m_Name}
214 : QVariant{QSize{propertiesIt->m_Width, propertiesIt->m_Height}};
219 : QVariant{QSize{propertiesIt->m_Width, propertiesIt->m_Height}};
215 }
220 }
216 else {
221 else {
217 qWarning(LOG_VariableModel())
222 qWarning(LOG_VariableModel())
218 << tr("Can't get header data (unknown column %1)").arg(section);
223 << tr("Can't get header data (unknown column %1)").arg(section);
219 }
224 }
220 }
225 }
221
226
222 return QVariant{};
227 return QVariant{};
223 }
228 }
224
229
225 void VariableModel::abortProgress(const QModelIndex &index)
230 void VariableModel::abortProgress(const QModelIndex &index)
226 {
231 {
227 if (auto variable = impl->m_Variables.at(index.row())) {
232 if (auto variable = impl->m_Variables.at(index.row())) {
228 emit abortProgessRequested(variable);
233 emit abortProgessRequested(variable);
229 }
234 }
230 }
235 }
231
236
232 void VariableModel::onVariableUpdated() noexcept
237 void VariableModel::onVariableUpdated() noexcept
233 {
238 {
234 // Finds variable that has been updated in the model
239 // Finds variable that has been updated in the model
235 if (auto updatedVariable = dynamic_cast<Variable *>(sender())) {
240 if (auto updatedVariable = dynamic_cast<Variable *>(sender())) {
236 auto updatedVariableIndex = impl->indexOfVariable(updatedVariable);
241 auto updatedVariableIndex = impl->indexOfVariable(updatedVariable);
237
242
238 if (updatedVariableIndex > -1) {
243 if (updatedVariableIndex > -1) {
239 emit dataChanged(createIndex(updatedVariableIndex, 0),
244 emit dataChanged(createIndex(updatedVariableIndex, 0),
240 createIndex(updatedVariableIndex, columnCount() - 1));
245 createIndex(updatedVariableIndex, columnCount() - 1));
241 }
246 }
242 }
247 }
243 }
248 }
244
249
245 int VariableModel::VariableModelPrivate::indexOfVariable(Variable *variable) const noexcept
250 int VariableModel::VariableModelPrivate::indexOfVariable(Variable *variable) const noexcept
246 {
251 {
247 auto begin = std::cbegin(m_Variables);
252 auto begin = std::cbegin(m_Variables);
248 auto end = std::cend(m_Variables);
253 auto end = std::cend(m_Variables);
249 auto it
254 auto it
250 = std::find_if(begin, end, [variable](const auto &var) { return var.get() == variable; });
255 = std::find_if(begin, end, [variable](const auto &var) { return var.get() == variable; });
251
256
252 if (it != end) {
257 if (it != end) {
253 // Gets the index of the variable in the model: we assume here that views have the same
258 // Gets the index of the variable in the model: we assume here that views have the same
254 // order as the model
259 // order as the model
255 return std::distance(begin, it);
260 return std::distance(begin, it);
256 }
261 }
257 else {
262 else {
258 return -1;
263 return -1;
259 }
264 }
260 }
265 }
@@ -1,199 +1,222
1 #include <Variable/RenameVariableDialog.h>
2 #include <Variable/Variable.h>
1 #include <Variable/VariableController.h>
3 #include <Variable/VariableController.h>
2 #include <Variable/VariableInspectorWidget.h>
4 #include <Variable/VariableInspectorWidget.h>
3 #include <Variable/VariableMenuHeaderWidget.h>
5 #include <Variable/VariableMenuHeaderWidget.h>
4 #include <Variable/VariableModel.h>
6 #include <Variable/VariableModel.h>
5
7
6 #include <ui_VariableInspectorWidget.h>
8 #include <ui_VariableInspectorWidget.h>
7
9
8 #include <QMouseEvent>
10 #include <QMouseEvent>
9 #include <QSortFilterProxyModel>
11 #include <QSortFilterProxyModel>
10 #include <QStyledItemDelegate>
12 #include <QStyledItemDelegate>
11 #include <QWidgetAction>
13 #include <QWidgetAction>
12
14
13 #include <SqpApplication.h>
15 #include <SqpApplication.h>
14
16
15 Q_LOGGING_CATEGORY(LOG_VariableInspectorWidget, "VariableInspectorWidget")
17 Q_LOGGING_CATEGORY(LOG_VariableInspectorWidget, "VariableInspectorWidget")
16
18
17
19
18 class QProgressBarItemDelegate : public QStyledItemDelegate {
20 class QProgressBarItemDelegate : public QStyledItemDelegate {
19
21
20 public:
22 public:
21 QProgressBarItemDelegate(QObject *parent) : QStyledItemDelegate{parent} {}
23 QProgressBarItemDelegate(QObject *parent) : QStyledItemDelegate{parent} {}
22
24
23 void paint(QPainter *painter, const QStyleOptionViewItem &option,
25 void paint(QPainter *painter, const QStyleOptionViewItem &option,
24 const QModelIndex &index) const
26 const QModelIndex &index) const
25 {
27 {
26 auto data = index.data(Qt::DisplayRole);
28 auto data = index.data(Qt::DisplayRole);
27 auto progressData = index.data(VariableRoles::ProgressRole);
29 auto progressData = index.data(VariableRoles::ProgressRole);
28 if (data.isValid() && progressData.isValid()) {
30 if (data.isValid() && progressData.isValid()) {
29 auto name = data.value<QString>();
31 auto name = data.value<QString>();
30 auto progress = progressData.value<double>();
32 auto progress = progressData.value<double>();
31 if (progress > 0) {
33 if (progress > 0) {
32 auto cancelButtonWidth = 20;
34 auto cancelButtonWidth = 20;
33 auto progressBarOption = QStyleOptionProgressBar{};
35 auto progressBarOption = QStyleOptionProgressBar{};
34 auto progressRect = option.rect;
36 auto progressRect = option.rect;
35 progressRect.setWidth(progressRect.width() - cancelButtonWidth);
37 progressRect.setWidth(progressRect.width() - cancelButtonWidth);
36 progressBarOption.rect = progressRect;
38 progressBarOption.rect = progressRect;
37 progressBarOption.minimum = 0;
39 progressBarOption.minimum = 0;
38 progressBarOption.maximum = 100;
40 progressBarOption.maximum = 100;
39 progressBarOption.progress = progress;
41 progressBarOption.progress = progress;
40 progressBarOption.text
42 progressBarOption.text
41 = QString("%1 %2").arg(name).arg(QString::number(progress, 'f', 2) + "%");
43 = QString("%1 %2").arg(name).arg(QString::number(progress, 'f', 2) + "%");
42 progressBarOption.textVisible = true;
44 progressBarOption.textVisible = true;
43 progressBarOption.textAlignment = Qt::AlignCenter;
45 progressBarOption.textAlignment = Qt::AlignCenter;
44
46
45
47
46 QApplication::style()->drawControl(QStyle::CE_ProgressBar, &progressBarOption,
48 QApplication::style()->drawControl(QStyle::CE_ProgressBar, &progressBarOption,
47 painter);
49 painter);
48
50
49 // Cancel button
51 // Cancel button
50 auto buttonRect = QRect(progressRect.right(), option.rect.top(), cancelButtonWidth,
52 auto buttonRect = QRect(progressRect.right(), option.rect.top(), cancelButtonWidth,
51 option.rect.height());
53 option.rect.height());
52 auto buttonOption = QStyleOptionButton{};
54 auto buttonOption = QStyleOptionButton{};
53 buttonOption.rect = buttonRect;
55 buttonOption.rect = buttonRect;
54 buttonOption.text = "X";
56 buttonOption.text = "X";
55
57
56 QApplication::style()->drawControl(QStyle::CE_PushButton, &buttonOption, painter);
58 QApplication::style()->drawControl(QStyle::CE_PushButton, &buttonOption, painter);
57 }
59 }
58 else {
60 else {
59 QStyledItemDelegate::paint(painter, option, index);
61 QStyledItemDelegate::paint(painter, option, index);
60 }
62 }
61 }
63 }
62 else {
64 else {
63 QStyledItemDelegate::paint(painter, option, index);
65 QStyledItemDelegate::paint(painter, option, index);
64 }
66 }
65 }
67 }
66
68
67 bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option,
69 bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option,
68 const QModelIndex &index)
70 const QModelIndex &index)
69 {
71 {
70 if (event->type() == QEvent::MouseButtonRelease) {
72 if (event->type() == QEvent::MouseButtonRelease) {
71 auto data = index.data(Qt::DisplayRole);
73 auto data = index.data(Qt::DisplayRole);
72 auto progressData = index.data(VariableRoles::ProgressRole);
74 auto progressData = index.data(VariableRoles::ProgressRole);
73 if (data.isValid() && progressData.isValid()) {
75 if (data.isValid() && progressData.isValid()) {
74 auto cancelButtonWidth = 20;
76 auto cancelButtonWidth = 20;
75 auto progressRect = option.rect;
77 auto progressRect = option.rect;
76 progressRect.setWidth(progressRect.width() - cancelButtonWidth);
78 progressRect.setWidth(progressRect.width() - cancelButtonWidth);
77 // Cancel button
79 // Cancel button
78 auto buttonRect = QRect(progressRect.right(), option.rect.top(), cancelButtonWidth,
80 auto buttonRect = QRect(progressRect.right(), option.rect.top(), cancelButtonWidth,
79 option.rect.height());
81 option.rect.height());
80
82
81 auto e = (QMouseEvent *)event;
83 auto e = (QMouseEvent *)event;
82 auto clickX = e->x();
84 auto clickX = e->x();
83 auto clickY = e->y();
85 auto clickY = e->y();
84
86
85 auto x = buttonRect.left(); // the X coordinate
87 auto x = buttonRect.left(); // the X coordinate
86 auto y = buttonRect.top(); // the Y coordinate
88 auto y = buttonRect.top(); // the Y coordinate
87 auto w = buttonRect.width(); // button width
89 auto w = buttonRect.width(); // button width
88 auto h = buttonRect.height(); // button height
90 auto h = buttonRect.height(); // button height
89
91
90 if (clickX > x && clickX < x + w) {
92 if (clickX > x && clickX < x + w) {
91 if (clickY > y && clickY < y + h) {
93 if (clickY > y && clickY < y + h) {
92 auto variableModel = sqpApp->variableController().variableModel();
94 auto variableModel = sqpApp->variableController().variableModel();
93 variableModel->abortProgress(index);
95 variableModel->abortProgress(index);
94 }
96 }
95 }
97 }
96 else {
98 else {
97 QStyledItemDelegate::editorEvent(event, model, option, index);
99 QStyledItemDelegate::editorEvent(event, model, option, index);
98 }
100 }
99 }
101 }
100 else {
102 else {
101 QStyledItemDelegate::editorEvent(event, model, option, index);
103 QStyledItemDelegate::editorEvent(event, model, option, index);
102 }
104 }
103 }
105 }
104 else {
106 else {
105 QStyledItemDelegate::editorEvent(event, model, option, index);
107 QStyledItemDelegate::editorEvent(event, model, option, index);
106 }
108 }
107 }
109 }
108 };
110 };
109
111
110 VariableInspectorWidget::VariableInspectorWidget(QWidget *parent)
112 VariableInspectorWidget::VariableInspectorWidget(QWidget *parent)
111 : QWidget{parent},
113 : QWidget{parent},
112 ui{new Ui::VariableInspectorWidget},
114 ui{new Ui::VariableInspectorWidget},
113 m_ProgressBarItemDelegate{new QProgressBarItemDelegate{this}}
115 m_ProgressBarItemDelegate{new QProgressBarItemDelegate{this}}
114 {
116 {
115 ui->setupUi(this);
117 ui->setupUi(this);
116
118
117 // Sets model for table
119 // Sets model for table
118 // auto sortFilterModel = new QSortFilterProxyModel{this};
120 // auto sortFilterModel = new QSortFilterProxyModel{this};
119 // sortFilterModel->setSourceModel(sqpApp->variableController().variableModel());
121 // sortFilterModel->setSourceModel(sqpApp->variableController().variableModel());
120
122
121 auto variableModel = sqpApp->variableController().variableModel();
123 auto variableModel = sqpApp->variableController().variableModel();
122 ui->tableView->setModel(variableModel);
124 ui->tableView->setModel(variableModel);
123
125
124 // Adds extra signal/slot between view and model, so the view can be updated instantly when
126 // Adds extra signal/slot between view and model, so the view can be updated instantly when
125 // there is a change of data in the model
127 // there is a change of data in the model
126 connect(variableModel, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), this,
128 connect(variableModel, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), this,
127 SLOT(refresh()));
129 SLOT(refresh()));
128
130
129 ui->tableView->setSelectionModel(sqpApp->variableController().variableSelectionModel());
131 ui->tableView->setSelectionModel(sqpApp->variableController().variableSelectionModel());
130 ui->tableView->setItemDelegateForColumn(0, m_ProgressBarItemDelegate);
132 ui->tableView->setItemDelegateForColumn(0, m_ProgressBarItemDelegate);
131
133
132 // Fixes column sizes
134 // Fixes column sizes
133 auto model = ui->tableView->model();
135 auto model = ui->tableView->model();
134 const auto count = model->columnCount();
136 const auto count = model->columnCount();
135 for (auto i = 0; i < count; ++i) {
137 for (auto i = 0; i < count; ++i) {
136 ui->tableView->setColumnWidth(
138 ui->tableView->setColumnWidth(
137 i, model->headerData(i, Qt::Horizontal, Qt::SizeHintRole).toSize().width());
139 i, model->headerData(i, Qt::Horizontal, Qt::SizeHintRole).toSize().width());
138 }
140 }
139
141
140 // Sets selection options
142 // Sets selection options
141 ui->tableView->setSelectionBehavior(QTableView::SelectRows);
143 ui->tableView->setSelectionBehavior(QTableView::SelectRows);
142 ui->tableView->setSelectionMode(QTableView::ExtendedSelection);
144 ui->tableView->setSelectionMode(QTableView::ExtendedSelection);
143
145
144 // Connection to show a menu when right clicking on the tree
146 // Connection to show a menu when right clicking on the tree
145 ui->tableView->setContextMenuPolicy(Qt::CustomContextMenu);
147 ui->tableView->setContextMenuPolicy(Qt::CustomContextMenu);
146 connect(ui->tableView, &QTableView::customContextMenuRequested, this,
148 connect(ui->tableView, &QTableView::customContextMenuRequested, this,
147 &VariableInspectorWidget::onTableMenuRequested);
149 &VariableInspectorWidget::onTableMenuRequested);
148 }
150 }
149
151
150 VariableInspectorWidget::~VariableInspectorWidget()
152 VariableInspectorWidget::~VariableInspectorWidget()
151 {
153 {
152 delete ui;
154 delete ui;
153 }
155 }
154
156
155 void VariableInspectorWidget::onTableMenuRequested(const QPoint &pos) noexcept
157 void VariableInspectorWidget::onTableMenuRequested(const QPoint &pos) noexcept
156 {
158 {
157 auto selectedRows = ui->tableView->selectionModel()->selectedRows();
159 auto selectedRows = ui->tableView->selectionModel()->selectedRows();
158
160
159 // Gets the model to retrieve the underlying selected variables
161 // Gets the model to retrieve the underlying selected variables
160 auto model = sqpApp->variableController().variableModel();
162 auto model = sqpApp->variableController().variableModel();
161 auto selectedVariables = QVector<std::shared_ptr<Variable> >{};
163 auto selectedVariables = QVector<std::shared_ptr<Variable> >{};
162 for (const auto &selectedRow : qAsConst(selectedRows)) {
164 for (const auto &selectedRow : qAsConst(selectedRows)) {
163 if (auto selectedVariable = model->variable(selectedRow.row())) {
165 if (auto selectedVariable = model->variable(selectedRow.row())) {
164 selectedVariables.push_back(selectedVariable);
166 selectedVariables.push_back(selectedVariable);
165 }
167 }
166 }
168 }
167
169
168 QMenu tableMenu{};
170 QMenu tableMenu{};
169
171
170 // Emits a signal so that potential receivers can populate the menu before displaying it
172 // Emits a signal so that potential receivers can populate the menu before displaying it
171 emit tableMenuAboutToBeDisplayed(&tableMenu, selectedVariables);
173 emit tableMenuAboutToBeDisplayed(&tableMenu, selectedVariables);
172
174
173 // Adds menu-specific actions
175 // Adds menu-specific actions
174 if (!selectedVariables.isEmpty()) {
176 if (!selectedVariables.isEmpty()) {
177 tableMenu.addSeparator();
178
179 // 'Rename' action (only if one variable selected)
180 if (selectedVariables.size() == 1) {
181 auto selectedVariable = selectedVariables.front();
182
183 auto renameFun = [&selectedVariable, &model, this]() {
184 // Generates forbidden names (names associated to existing variables)
185 auto allVariables = model->variables();
186 auto forbiddenNames = QVector<QString>(allVariables.size());
187 std::transform(allVariables.cbegin(), allVariables.cend(), forbiddenNames.begin(),
188 [](const auto &variable) { return variable->name(); });
189
190 RenameVariableDialog dialog{selectedVariable->name(), forbiddenNames, this};
191 if (dialog.exec() == QDialog::Accepted) {
192 selectedVariable->setName(dialog.name());
193 }
194 };
195
196 tableMenu.addAction(tr("Rename..."), renameFun);
197 }
198
175 // 'Delete' action
199 // 'Delete' action
176 auto deleteFun = [&selectedVariables]() {
200 auto deleteFun = [&selectedVariables]() {
177 sqpApp->variableController().deleteVariables(selectedVariables);
201 sqpApp->variableController().deleteVariables(selectedVariables);
178 };
202 };
179
203
180 tableMenu.addSeparator();
181 tableMenu.addAction(QIcon{":/icones/delete.png"}, tr("Delete"), deleteFun);
204 tableMenu.addAction(QIcon{":/icones/delete.png"}, tr("Delete"), deleteFun);
182 }
205 }
183
206
184 if (!tableMenu.isEmpty()) {
207 if (!tableMenu.isEmpty()) {
185 // Generates menu header (inserted before first action)
208 // Generates menu header (inserted before first action)
186 auto firstAction = tableMenu.actions().first();
209 auto firstAction = tableMenu.actions().first();
187 auto headerAction = new QWidgetAction{&tableMenu};
210 auto headerAction = new QWidgetAction{&tableMenu};
188 headerAction->setDefaultWidget(new VariableMenuHeaderWidget{selectedVariables, &tableMenu});
211 headerAction->setDefaultWidget(new VariableMenuHeaderWidget{selectedVariables, &tableMenu});
189 tableMenu.insertAction(firstAction, headerAction);
212 tableMenu.insertAction(firstAction, headerAction);
190
213
191 // Displays menu
214 // Displays menu
192 tableMenu.exec(QCursor::pos());
215 tableMenu.exec(QCursor::pos());
193 }
216 }
194 }
217 }
195
218
196 void VariableInspectorWidget::refresh() noexcept
219 void VariableInspectorWidget::refresh() noexcept
197 {
220 {
198 ui->tableView->viewport()->update();
221 ui->tableView->viewport()->update();
199 }
222 }
General Comments 0
You need to be logged in to leave comments. Login now