##// END OF EJS Templates
Fixes refresh problem in Variable widget
Alexandre Leroux -
r368:fc12ad933c3b
parent child
Show More
@@ -1,55 +1,63
1 1 #ifndef SCIQLOP_VARIABLEMODEL_H
2 2 #define SCIQLOP_VARIABLEMODEL_H
3 3
4 4
5 5 #include <Data/SqpDateTime.h>
6 6
7 7 #include <QAbstractTableModel>
8 8 #include <QLoggingCategory>
9 9
10 #include <Common/MetaTypes.h>
10 11 #include <Common/spimpl.h>
11 12
12 13 Q_DECLARE_LOGGING_CATEGORY(LOG_VariableModel)
13 14
14 15 class IDataSeries;
15 16 class Variable;
16 17
17 18 /**
18 19 * @brief The VariableModel class aims to hold the variables that have been created in SciQlop
19 20 */
20 21 class VariableModel : public QAbstractTableModel {
21 22 public:
22 23 explicit VariableModel(QObject *parent = nullptr);
23 24
24 25 /**
25 26 * Creates a new variable in the model
26 27 * @param name the name of the new variable
27 28 * @param dateTime the dateTime of the new variable
28 29 * @return the pointer to the new variable
29 30 */
30 31 std::shared_ptr<Variable> createVariable(const QString &name,
31 32 const SqpDateTime &dateTime) noexcept;
32 33
33 34 /**
34 35 * Deletes a variable from the model, if it exists
35 36 * @param variable the variable to delete
36 37 */
37 38 void deleteVariable(std::shared_ptr<Variable> variable) noexcept;
38 39
39 40 std::shared_ptr<Variable> variable(int index) const;
40 41
41 42 // /////////////////////////// //
42 43 // QAbstractTableModel methods //
43 44 // /////////////////////////// //
44 45 virtual int columnCount(const QModelIndex &parent = QModelIndex{}) const override;
45 46 virtual int rowCount(const QModelIndex &parent = QModelIndex{}) const override;
46 47 virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
47 48 virtual QVariant headerData(int section, Qt::Orientation orientation,
48 49 int role = Qt::DisplayRole) const override;
49 50
50 51 private:
51 52 class VariableModelPrivate;
52 53 spimpl::unique_impl_ptr<VariableModelPrivate> impl;
54
55 private slots:
56 /// Slot called when data of a variable has been updated
57 void onVariableUpdated() noexcept;
53 58 };
54 59
60 // Registers QVector<int> metatype so it can be used in VariableModel::dataChanged() signal
61 SCIQLOP_REGISTER_META_TYPE(QVECTOR_INT_REGISTRY, QVector<int>)
62
55 63 #endif // SCIQLOP_VARIABLEMODEL_H
@@ -1,179 +1,198
1 1 #include <Variable/Variable.h>
2 2 #include <Variable/VariableModel.h>
3 3
4 4 #include <Data/IDataSeries.h>
5 5
6 6 #include <QDateTime>
7 7 #include <QSize>
8 8
9 9 Q_LOGGING_CATEGORY(LOG_VariableModel, "VariableModel")
10 10
11 11 namespace {
12 12
13 13 // Column indexes
14 14 const auto NAME_COLUMN = 0;
15 15 const auto TSTART_COLUMN = 1;
16 16 const auto TEND_COLUMN = 2;
17 17 const auto NB_COLUMNS = 3;
18 18
19 19 // Column properties
20 20 const auto DEFAULT_HEIGHT = 25;
21 21 const auto DEFAULT_WIDTH = 100;
22 22
23 23 struct ColumnProperties {
24 24 ColumnProperties(const QString &name = {}, int width = DEFAULT_WIDTH,
25 25 int height = DEFAULT_HEIGHT)
26 26 : m_Name{name}, m_Width{width}, m_Height{height}
27 27 {
28 28 }
29 29
30 30 QString m_Name;
31 31 int m_Width;
32 32 int m_Height;
33 33 };
34 34
35 35 const auto COLUMN_PROPERTIES
36 36 = QHash<int, ColumnProperties>{{NAME_COLUMN, {QObject::tr("Name")}},
37 37 {TSTART_COLUMN, {QObject::tr("tStart"), 180}},
38 38 {TEND_COLUMN, {QObject::tr("tEnd"), 180}}};
39 39
40 40 /// Format for datetimes
41 41 const auto DATETIME_FORMAT = QStringLiteral("dd/MM/yyyy \nhh:mm:ss:zzz");
42 42
43 43 } // namespace
44 44
45 45 struct VariableModel::VariableModelPrivate {
46 46 /// Variables created in SciQlop
47 47 std::vector<std::shared_ptr<Variable> > m_Variables;
48 48 };
49 49
50 50 VariableModel::VariableModel(QObject *parent)
51 51 : QAbstractTableModel{parent}, impl{spimpl::make_unique_impl<VariableModelPrivate>()}
52 52 {
53 53 }
54 54
55 55 std::shared_ptr<Variable> VariableModel::createVariable(const QString &name,
56 56 const SqpDateTime &dateTime) noexcept
57 57 {
58 58 auto insertIndex = rowCount();
59 59 beginInsertRows({}, insertIndex, insertIndex);
60 60
61 61 /// @todo For the moment, the other data of the variable is initialized with default values
62 62 auto variable = std::make_shared<Variable>(name, QStringLiteral("unit"),
63 63 QStringLiteral("mission"), dateTime);
64 64
65 65 impl->m_Variables.push_back(variable);
66 connect(variable.get(), &Variable::updated, this, &VariableModel::onVariableUpdated);
66 67
67 68 endInsertRows();
68 69
69 70 return variable;
70 71 }
71 72
72 73 void VariableModel::deleteVariable(std::shared_ptr<Variable> variable) noexcept
73 74 {
74 75 if (!variable) {
75 76 qCCritical(LOG_Variable()) << "Can't delete a null variable from the model";
76 77 return;
77 78 }
78 79
79 80 // Finds variable in the model
80 81 auto begin = impl->m_Variables.cbegin();
81 82 auto end = impl->m_Variables.cend();
82 83 auto it = std::find(begin, end, variable);
83 84 if (it != end) {
84 85 auto removeIndex = std::distance(begin, it);
85 86
86 87 // Deletes variable
87 88 beginRemoveRows({}, removeIndex, removeIndex);
88 89 impl->m_Variables.erase(it);
89 90 endRemoveRows();
90 91 }
91 92 else {
92 93 qCritical(LOG_VariableModel())
93 94 << tr("Can't delete variable %1 from the model: the variable is not in the model")
94 95 .arg(variable->name());
95 96 }
96 97 }
97 98
98 99 std::shared_ptr<Variable> VariableModel::variable(int index) const
99 100 {
100 101 return (index >= 0 && index < impl->m_Variables.size()) ? impl->m_Variables[index] : nullptr;
101 102 }
102 103
103 104 int VariableModel::columnCount(const QModelIndex &parent) const
104 105 {
105 106 Q_UNUSED(parent);
106 107
107 108 return NB_COLUMNS;
108 109 }
109 110
110 111 int VariableModel::rowCount(const QModelIndex &parent) const
111 112 {
112 113 Q_UNUSED(parent);
113 114
114 115 return impl->m_Variables.size();
115 116 }
116 117
117 118 QVariant VariableModel::data(const QModelIndex &index, int role) const
118 119 {
119 120 if (!index.isValid()) {
120 121 return QVariant{};
121 122 }
122 123
123 124 if (index.row() < 0 || index.row() >= rowCount()) {
124 125 return QVariant{};
125 126 }
126 127
127 128 if (role == Qt::DisplayRole) {
128 129 if (auto variable = impl->m_Variables.at(index.row()).get()) {
129 130 /// Lambda function that builds the variant to return for a time value
130 131 auto dateTimeVariant = [](double time) {
131 132 auto dateTime = QDateTime::fromMSecsSinceEpoch(time * 1000.);
132 133 return dateTime.toString(DATETIME_FORMAT);
133 134 };
134 135
135 136 switch (index.column()) {
136 137 case NAME_COLUMN:
137 138 return variable->name();
138 139 case TSTART_COLUMN:
139 140 return dateTimeVariant(variable->dateTime().m_TStart);
140 141 case TEND_COLUMN:
141 142 return dateTimeVariant(variable->dateTime().m_TEnd);
142 143 default:
143 144 // No action
144 145 break;
145 146 }
146 147
147 148 qWarning(LOG_VariableModel())
148 149 << tr("Can't get data (unknown column %1)").arg(index.column());
149 150 }
150 151 else {
151 152 qWarning(LOG_VariableModel()) << tr("Can't get data (no variable)");
152 153 }
153 154 }
154 155
155 156 return QVariant{};
156 157 }
157 158
158 159 QVariant VariableModel::headerData(int section, Qt::Orientation orientation, int role) const
159 160 {
160 161 if (role != Qt::DisplayRole && role != Qt::SizeHintRole) {
161 162 return QVariant{};
162 163 }
163 164
164 165 if (orientation == Qt::Horizontal) {
165 166 auto propertiesIt = COLUMN_PROPERTIES.find(section);
166 167 if (propertiesIt != COLUMN_PROPERTIES.cend()) {
167 168 // Role is either DisplayRole or SizeHintRole
168 169 return (role == Qt::DisplayRole)
169 170 ? QVariant{propertiesIt->m_Name}
170 171 : QVariant{QSize{propertiesIt->m_Width, propertiesIt->m_Height}};
171 172 }
172 173 else {
173 174 qWarning(LOG_VariableModel())
174 175 << tr("Can't get header data (unknown column %1)").arg(section);
175 176 }
176 177 }
177 178
178 179 return QVariant{};
179 180 }
181
182 void VariableModel::onVariableUpdated() noexcept
183 {
184 // Finds variable that has been updated in the model
185 if (auto updatedVariable = dynamic_cast<Variable *>(sender())) {
186 auto begin = std::cbegin(impl->m_Variables);
187 auto end = std::cend(impl->m_Variables);
188 auto it = std::find_if(begin, end, [updatedVariable](const auto &variable) {
189 return variable.get() == updatedVariable;
190 });
191
192 if (it != end) {
193 auto updateVariableIndex = std::distance(begin, it);
194 emit dataChanged(createIndex(updateVariableIndex, 0),
195 createIndex(updateVariableIndex, columnCount() - 1));
196 }
197 }
198 }
@@ -1,50 +1,52
1 1 #ifndef SCIQLOP_VARIABLEINSPECTORWIDGET_H
2 2 #define SCIQLOP_VARIABLEINSPECTORWIDGET_H
3 3
4 4 #include <QLoggingCategory>
5 5 #include <QMenu>
6 6 #include <QWidget>
7 7
8 8 #include <memory>
9 9
10 10 Q_DECLARE_LOGGING_CATEGORY(LOG_VariableInspectorWidget)
11 11
12 12 class Variable;
13 13
14 14 namespace Ui {
15 15 class VariableInspectorWidget;
16 16 } // Ui
17 17
18 18 /**
19 19 * @brief The VariableInspectorWidget class representes represents the variable inspector, from
20 20 * which it is possible to view the loaded variables, handle them or trigger their display in
21 21 * visualization
22 22 */
23 23 class VariableInspectorWidget : public QWidget {
24 24 Q_OBJECT
25 25
26 26 public:
27 27 explicit VariableInspectorWidget(QWidget *parent = 0);
28 28 virtual ~VariableInspectorWidget();
29 29
30 30 signals:
31 31 /**
32 32 * Signal emitted before a menu concerning variables is displayed. It is used for other widgets
33 33 * to complete the menu.
34 34 * @param tableMenu the menu to be completed
35 35 * @param variables the variables concerned by the menu
36 36 * @remarks To make the dynamic addition of menus work, the connections to this signal must be
37 37 * in Qt :: DirectConnection
38 38 */
39 39 void tableMenuAboutToBeDisplayed(QMenu *tableMenu,
40 40 const QVector<std::shared_ptr<Variable> > &variables);
41 41
42 42 private:
43 43 Ui::VariableInspectorWidget *ui;
44 44
45 45 private slots:
46 46 /// Slot called when right clicking on an variable in the table (displays a menu)
47 47 void onTableMenuRequested(const QPoint &pos) noexcept;
48 /// Refreshes instantly the variable view
49 void refresh() noexcept;
48 50 };
49 51
50 52 #endif // SCIQLOP_VARIABLEINSPECTORWIDGET_H
@@ -1,89 +1,101
1 1 #include <Variable/VariableController.h>
2 2 #include <Variable/VariableInspectorWidget.h>
3 3 #include <Variable/VariableMenuHeaderWidget.h>
4 4 #include <Variable/VariableModel.h>
5 5
6 6 #include <ui_VariableInspectorWidget.h>
7 7
8 8 #include <QSortFilterProxyModel>
9 9 #include <QWidgetAction>
10 10
11 11 #include <SqpApplication.h>
12 12
13 13 Q_LOGGING_CATEGORY(LOG_VariableInspectorWidget, "VariableInspectorWidget")
14 14
15 15 VariableInspectorWidget::VariableInspectorWidget(QWidget *parent)
16 16 : QWidget{parent}, ui{new Ui::VariableInspectorWidget}
17 17 {
18 18 ui->setupUi(this);
19 19
20 20 // Sets model for table
21 21 // auto sortFilterModel = new QSortFilterProxyModel{this};
22 22 // sortFilterModel->setSourceModel(sqpApp->variableController().variableModel());
23 23
24 ui->tableView->setModel(sqpApp->variableController().variableModel());
24 auto variableModel = sqpApp->variableController().variableModel();
25 ui->tableView->setModel(variableModel);
26
27 // Adds extra signal/slot between view and model, so the view can be updated instantly when
28 // there is a change of data in the model
29 connect(variableModel, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), this,
30 SLOT(refresh()));
31
25 32 ui->tableView->setSelectionModel(sqpApp->variableController().variableSelectionModel());
26 33
27 34 // Fixes column sizes
28 35 auto model = ui->tableView->model();
29 36 const auto count = model->columnCount();
30 37 for (auto i = 0; i < count; ++i) {
31 38 ui->tableView->setColumnWidth(
32 39 i, model->headerData(i, Qt::Horizontal, Qt::SizeHintRole).toSize().width());
33 40 }
34 41
35 42 // Sets selection options
36 43 ui->tableView->setSelectionBehavior(QTableView::SelectRows);
37 44 ui->tableView->setSelectionMode(QTableView::ExtendedSelection);
38 45
39 46 // Connection to show a menu when right clicking on the tree
40 47 ui->tableView->setContextMenuPolicy(Qt::CustomContextMenu);
41 48 connect(ui->tableView, &QTableView::customContextMenuRequested, this,
42 49 &VariableInspectorWidget::onTableMenuRequested);
43 50 }
44 51
45 52 VariableInspectorWidget::~VariableInspectorWidget()
46 53 {
47 54 delete ui;
48 55 }
49 56
50 57 void VariableInspectorWidget::onTableMenuRequested(const QPoint &pos) noexcept
51 58 {
52 59 auto selectedRows = ui->tableView->selectionModel()->selectedRows();
53 60
54 61 // Gets the model to retrieve the underlying selected variables
55 62 auto model = sqpApp->variableController().variableModel();
56 63 auto selectedVariables = QVector<std::shared_ptr<Variable> >{};
57 64 for (const auto &selectedRow : qAsConst(selectedRows)) {
58 65 if (auto selectedVariable = model->variable(selectedRow.row())) {
59 66 selectedVariables.push_back(selectedVariable);
60 67 }
61 68 }
62 69
63 70 QMenu tableMenu{};
64 71
65 72 // Emits a signal so that potential receivers can populate the menu before displaying it
66 73 emit tableMenuAboutToBeDisplayed(&tableMenu, selectedVariables);
67 74
68 75 // Adds menu-specific actions
69 76 if (!selectedVariables.isEmpty()) {
70 77 // 'Delete' action
71 78 auto deleteFun = [&selectedVariables]() {
72 79 sqpApp->variableController().deleteVariables(selectedVariables);
73 80 };
74 81
75 82 tableMenu.addSeparator();
76 83 tableMenu.addAction(QIcon{":/icones/delete.png"}, tr("Delete"), deleteFun);
77 84 }
78 85
79 86 if (!tableMenu.isEmpty()) {
80 87 // Generates menu header (inserted before first action)
81 88 auto firstAction = tableMenu.actions().first();
82 89 auto headerAction = new QWidgetAction{&tableMenu};
83 90 headerAction->setDefaultWidget(new VariableMenuHeaderWidget{selectedVariables, &tableMenu});
84 91 tableMenu.insertAction(firstAction, headerAction);
85 92
86 93 // Displays menu
87 94 tableMenu.exec(mapToGlobal(pos));
88 95 }
89 96 }
97
98 void VariableInspectorWidget::refresh() noexcept
99 {
100 ui->tableView->viewport()->update();
101 }
General Comments 0
You need to be logged in to leave comments. Login now