##// END OF EJS Templates
Fixes crashes on release when duplicating/renaming a variable
Alexandre Leroux -
r722:1590606c0dcd
parent child
Show More
@@ -1,232 +1,239
1 1 #include <Variable/RenameVariableDialog.h>
2 2 #include <Variable/Variable.h>
3 3 #include <Variable/VariableController.h>
4 4 #include <Variable/VariableInspectorWidget.h>
5 5 #include <Variable/VariableMenuHeaderWidget.h>
6 6 #include <Variable/VariableModel.h>
7 7
8 8 #include <ui_VariableInspectorWidget.h>
9 9
10 10 #include <QMouseEvent>
11 11 #include <QSortFilterProxyModel>
12 12 #include <QStyledItemDelegate>
13 13 #include <QWidgetAction>
14 14
15 15 #include <SqpApplication.h>
16 16
17 17 Q_LOGGING_CATEGORY(LOG_VariableInspectorWidget, "VariableInspectorWidget")
18 18
19 19
20 20 class QProgressBarItemDelegate : public QStyledItemDelegate {
21 21
22 22 public:
23 23 QProgressBarItemDelegate(QObject *parent) : QStyledItemDelegate{parent} {}
24 24
25 25 void paint(QPainter *painter, const QStyleOptionViewItem &option,
26 26 const QModelIndex &index) const
27 27 {
28 28 auto data = index.data(Qt::DisplayRole);
29 29 auto progressData = index.data(VariableRoles::ProgressRole);
30 30 if (data.isValid() && progressData.isValid()) {
31 31 auto name = data.value<QString>();
32 32 auto progress = progressData.value<double>();
33 33 if (progress > 0) {
34 34 auto cancelButtonWidth = 20;
35 35 auto progressBarOption = QStyleOptionProgressBar{};
36 36 auto progressRect = option.rect;
37 37 progressRect.setWidth(progressRect.width() - cancelButtonWidth);
38 38 progressBarOption.rect = progressRect;
39 39 progressBarOption.minimum = 0;
40 40 progressBarOption.maximum = 100;
41 41 progressBarOption.progress = progress;
42 42 progressBarOption.text
43 43 = QString("%1 %2").arg(name).arg(QString::number(progress, 'f', 2) + "%");
44 44 progressBarOption.textVisible = true;
45 45 progressBarOption.textAlignment = Qt::AlignCenter;
46 46
47 47
48 48 QApplication::style()->drawControl(QStyle::CE_ProgressBar, &progressBarOption,
49 49 painter);
50 50
51 51 // Cancel button
52 52 auto buttonRect = QRect(progressRect.right(), option.rect.top(), cancelButtonWidth,
53 53 option.rect.height());
54 54 auto buttonOption = QStyleOptionButton{};
55 55 buttonOption.rect = buttonRect;
56 56 buttonOption.text = "X";
57 57
58 58 QApplication::style()->drawControl(QStyle::CE_PushButton, &buttonOption, painter);
59 59 }
60 60 else {
61 61 QStyledItemDelegate::paint(painter, option, index);
62 62 }
63 63 }
64 64 else {
65 65 QStyledItemDelegate::paint(painter, option, index);
66 66 }
67 67 }
68 68
69 69 bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option,
70 70 const QModelIndex &index)
71 71 {
72 72 if (event->type() == QEvent::MouseButtonRelease) {
73 73 auto data = index.data(Qt::DisplayRole);
74 74 auto progressData = index.data(VariableRoles::ProgressRole);
75 75 if (data.isValid() && progressData.isValid()) {
76 76 auto cancelButtonWidth = 20;
77 77 auto progressRect = option.rect;
78 78 progressRect.setWidth(progressRect.width() - cancelButtonWidth);
79 79 // Cancel button
80 80 auto buttonRect = QRect(progressRect.right(), option.rect.top(), cancelButtonWidth,
81 81 option.rect.height());
82 82
83 83 auto e = (QMouseEvent *)event;
84 84 auto clickX = e->x();
85 85 auto clickY = e->y();
86 86
87 87 auto x = buttonRect.left(); // the X coordinate
88 88 auto y = buttonRect.top(); // the Y coordinate
89 89 auto w = buttonRect.width(); // button width
90 90 auto h = buttonRect.height(); // button height
91 91
92 92 if (clickX > x && clickX < x + w) {
93 93 if (clickY > y && clickY < y + h) {
94 94 auto variableModel = sqpApp->variableController().variableModel();
95 95 variableModel->abortProgress(index);
96 96 }
97 97 return true;
98 98 }
99 99 else {
100 100 return QStyledItemDelegate::editorEvent(event, model, option, index);
101 101 }
102 102 }
103 103 else {
104 104 return QStyledItemDelegate::editorEvent(event, model, option, index);
105 105 }
106 106 }
107 107 else {
108 108 return QStyledItemDelegate::editorEvent(event, model, option, index);
109 109 }
110 110
111 111
112 112 return QStyledItemDelegate::editorEvent(event, model, option, index);
113 113 }
114 114 };
115 115
116 116 VariableInspectorWidget::VariableInspectorWidget(QWidget *parent)
117 117 : QWidget{parent},
118 118 ui{new Ui::VariableInspectorWidget},
119 119 m_ProgressBarItemDelegate{new QProgressBarItemDelegate{this}}
120 120 {
121 121 ui->setupUi(this);
122 122
123 123 // Sets model for table
124 124 // auto sortFilterModel = new QSortFilterProxyModel{this};
125 125 // sortFilterModel->setSourceModel(sqpApp->variableController().variableModel());
126 126
127 127 auto variableModel = sqpApp->variableController().variableModel();
128 128 ui->tableView->setModel(variableModel);
129 129
130 130 // Adds extra signal/slot between view and model, so the view can be updated instantly when
131 131 // there is a change of data in the model
132 132 connect(variableModel, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), this,
133 133 SLOT(refresh()));
134 134
135 135 ui->tableView->setSelectionModel(sqpApp->variableController().variableSelectionModel());
136 136 ui->tableView->setItemDelegateForColumn(0, m_ProgressBarItemDelegate);
137 137
138 138 // Fixes column sizes
139 139 auto model = ui->tableView->model();
140 140 const auto count = model->columnCount();
141 141 for (auto i = 0; i < count; ++i) {
142 142 ui->tableView->setColumnWidth(
143 143 i, model->headerData(i, Qt::Horizontal, Qt::SizeHintRole).toSize().width());
144 144 }
145 145
146 146 // Sets selection options
147 147 ui->tableView->setSelectionBehavior(QTableView::SelectRows);
148 148 ui->tableView->setSelectionMode(QTableView::ExtendedSelection);
149 149
150 150 // Connection to show a menu when right clicking on the tree
151 151 ui->tableView->setContextMenuPolicy(Qt::CustomContextMenu);
152 152 connect(ui->tableView, &QTableView::customContextMenuRequested, this,
153 153 &VariableInspectorWidget::onTableMenuRequested);
154 154 }
155 155
156 156 VariableInspectorWidget::~VariableInspectorWidget()
157 157 {
158 158 delete ui;
159 159 }
160 160
161 161 void VariableInspectorWidget::onTableMenuRequested(const QPoint &pos) noexcept
162 162 {
163 163 auto selectedRows = ui->tableView->selectionModel()->selectedRows();
164 164
165 165 // Gets the model to retrieve the underlying selected variables
166 166 auto model = sqpApp->variableController().variableModel();
167 167 auto selectedVariables = QVector<std::shared_ptr<Variable> >{};
168 168 for (const auto &selectedRow : qAsConst(selectedRows)) {
169 169 if (auto selectedVariable = model->variable(selectedRow.row())) {
170 170 selectedVariables.push_back(selectedVariable);
171 171 }
172 172 }
173 173
174 174 QMenu tableMenu{};
175 175
176 176 // Emits a signal so that potential receivers can populate the menu before displaying it
177 177 emit tableMenuAboutToBeDisplayed(&tableMenu, selectedVariables);
178 178
179 179 // Adds menu-specific actions
180 180 if (!selectedVariables.isEmpty()) {
181 181 tableMenu.addSeparator();
182 182
183 183 // 'Rename' and 'Duplicate' actions (only if one variable selected)
184 184 if (selectedVariables.size() == 1) {
185 185 auto selectedVariable = selectedVariables.front();
186 186
187 auto duplicateFun = [&selectedVariable]() {
188 sqpApp->variableController().cloneVariable(selectedVariable);
187 auto duplicateFun = [varW = std::weak_ptr<Variable>(selectedVariable)]()
188 {
189 if (auto var = varW.lock()) {
190 sqpApp->variableController().cloneVariable(var);
191 }
189 192 };
190 193
191 194 tableMenu.addAction(tr("Duplicate"), duplicateFun);
192 195
193 auto renameFun = [&selectedVariable, &model, this]() {
194 // Generates forbidden names (names associated to existing variables)
195 auto allVariables = model->variables();
196 auto forbiddenNames = QVector<QString>(allVariables.size());
197 std::transform(allVariables.cbegin(), allVariables.cend(), forbiddenNames.begin(),
198 [](const auto &variable) { return variable->name(); });
199
200 RenameVariableDialog dialog{selectedVariable->name(), forbiddenNames, this};
201 if (dialog.exec() == QDialog::Accepted) {
202 selectedVariable->setName(dialog.name());
196 auto renameFun = [ varW = std::weak_ptr<Variable>(selectedVariable), &model, this ]()
197 {
198 if (auto var = varW.lock()) {
199 // Generates forbidden names (names associated to existing variables)
200 auto allVariables = model->variables();
201 auto forbiddenNames = QVector<QString>(allVariables.size());
202 std::transform(allVariables.cbegin(), allVariables.cend(),
203 forbiddenNames.begin(),
204 [](const auto &variable) { return variable->name(); });
205
206 RenameVariableDialog dialog{var->name(), forbiddenNames, this};
207 if (dialog.exec() == QDialog::Accepted) {
208 var->setName(dialog.name());
209 }
203 210 }
204 211 };
205 212
206 213 tableMenu.addAction(tr("Rename..."), renameFun);
207 214 }
208 215
209 216 // 'Delete' action
210 217 auto deleteFun = [&selectedVariables]() {
211 218 sqpApp->variableController().deleteVariables(selectedVariables);
212 219 };
213 220
214 221 tableMenu.addAction(QIcon{":/icones/delete.png"}, tr("Delete"), deleteFun);
215 222 }
216 223
217 224 if (!tableMenu.isEmpty()) {
218 225 // Generates menu header (inserted before first action)
219 226 auto firstAction = tableMenu.actions().first();
220 227 auto headerAction = new QWidgetAction{&tableMenu};
221 228 headerAction->setDefaultWidget(new VariableMenuHeaderWidget{selectedVariables, &tableMenu});
222 229 tableMenu.insertAction(firstAction, headerAction);
223 230
224 231 // Displays menu
225 232 tableMenu.exec(QCursor::pos());
226 233 }
227 234 }
228 235
229 236 void VariableInspectorWidget::refresh() noexcept
230 237 {
231 238 ui->tableView->viewport()->update();
232 239 }
General Comments 0
You need to be logged in to leave comments. Login now