Line |
Branch |
Exec |
Source |
1 |
|
|
/***************************************************************************** |
2 |
|
|
* |
3 |
|
|
* Copyright (C) 2012-2022 Florian Pose <fp@igh.de> |
4 |
|
|
* 2013 Dr. Wilhelm Hagemeister <hm@igh-essen.com> |
5 |
|
|
* |
6 |
|
|
* This file is part of the QtPdCom library. |
7 |
|
|
* |
8 |
|
|
* The QtPdCom library is free software: you can redistribute it and/or modify |
9 |
|
|
* it under the terms of the GNU Lesser General Public License as published by |
10 |
|
|
* the Free Software Foundation, either version 3 of the License, or (at your |
11 |
|
|
* option) any later version. |
12 |
|
|
* |
13 |
|
|
* The QtPdCom library is distributed in the hope that it will be useful, but |
14 |
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
15 |
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public |
16 |
|
|
* License for more details. |
17 |
|
|
* |
18 |
|
|
* You should have received a copy of the GNU Lesser General Public License |
19 |
|
|
* along with the QtPdCom Library. If not, see <http://www.gnu.org/licenses/>. |
20 |
|
|
* |
21 |
|
|
****************************************************************************/ |
22 |
|
|
|
23 |
|
|
#include "TableModel.h" |
24 |
|
|
#include "TableModelImpl.h" |
25 |
|
|
|
26 |
|
|
using QtPdCom::TableModel; |
27 |
|
|
|
28 |
|
|
#include <QDebug> |
29 |
|
|
|
30 |
|
|
/****************************************************************************/ |
31 |
|
|
|
32 |
|
|
/** Constructor. |
33 |
|
|
*/ |
34 |
|
✗ |
TableModel::TableModel(QObject *parent): |
35 |
|
|
QAbstractTableModel(parent), |
36 |
|
✗ |
impl(new TableModel::Impl(this)) |
37 |
|
|
{ |
38 |
|
✗ |
connect(&impl->valueHighlightRow, |
39 |
|
|
SIGNAL(valueChanged()), |
40 |
|
|
this, |
41 |
|
|
SLOT(highlightRowChanged())); |
42 |
|
✗ |
connect(&impl->visibleRowCount, |
43 |
|
|
SIGNAL(valueChanged()), |
44 |
|
|
this, |
45 |
|
|
SLOT(visibleRowCountChanged())); |
46 |
|
|
} |
47 |
|
|
|
48 |
|
|
/****************************************************************************/ |
49 |
|
|
|
50 |
|
|
/** Destructor. |
51 |
|
|
*/ |
52 |
|
✗ |
TableModel::~TableModel() |
53 |
|
|
{ |
54 |
|
✗ |
impl->valueHighlightRow.clearVariable(); |
55 |
|
✗ |
clearColumns(); |
56 |
|
|
} |
57 |
|
|
|
58 |
|
|
/****************************************************************************/ |
59 |
|
|
|
60 |
|
✗ |
void TableModel::insertColumn(TableColumn *col, int position) |
61 |
|
|
{ |
62 |
|
✗ |
if (position < 0 || position > impl->columnVector.count()) { |
63 |
|
✗ |
position = impl->columnVector.count(); |
64 |
|
|
} |
65 |
|
|
|
66 |
|
✗ |
beginInsertColumns(QModelIndex(), position, position); |
67 |
|
✗ |
impl->columnVector.insert(position, col); |
68 |
|
✗ |
endInsertColumns(); |
69 |
|
|
|
70 |
|
✗ |
QObject::connect( |
71 |
|
|
col, |
72 |
|
|
SIGNAL(dimensionChanged()), |
73 |
|
|
this, |
74 |
|
|
SLOT(dimensionChanged())); |
75 |
|
✗ |
QObject::connect( |
76 |
|
|
col, |
77 |
|
|
SIGNAL(headerChanged()), |
78 |
|
|
this, |
79 |
|
|
SLOT(columnHeaderChanged())); |
80 |
|
✗ |
QObject::connect(col, SIGNAL(valueChanged()), this, SLOT(valueChanged())); |
81 |
|
|
|
82 |
|
✗ |
impl->updateRows(); |
83 |
|
|
} |
84 |
|
|
|
85 |
|
|
/****************************************************************************/ |
86 |
|
|
|
87 |
|
|
/** Adds a column. |
88 |
|
|
*/ |
89 |
|
✗ |
void TableModel::addColumn(TableColumn *column) |
90 |
|
|
{ |
91 |
|
✗ |
insertColumn(column, -1); |
92 |
|
|
} |
93 |
|
|
|
94 |
|
|
/****************************************************************************/ |
95 |
|
|
|
96 |
|
✗ |
void QtPdCom::TableModel::removeColumn(TableColumn *column) |
97 |
|
|
{ |
98 |
|
✗ |
const auto idx = impl->columnVector.indexOf(column); |
99 |
|
✗ |
if (idx == -1) { |
100 |
|
✗ |
return; |
101 |
|
|
} |
102 |
|
|
|
103 |
|
✗ |
beginRemoveColumns(QModelIndex(), idx, idx); |
104 |
|
✗ |
impl->columnVector.remove(idx); |
105 |
|
✗ |
endRemoveColumns(); |
106 |
|
|
|
107 |
|
✗ |
QObject::disconnect( |
108 |
|
|
column, |
109 |
|
|
SIGNAL(dimensionChanged()), |
110 |
|
|
this, |
111 |
|
|
SLOT(dimensionChanged())); |
112 |
|
✗ |
QObject::disconnect( |
113 |
|
|
column, |
114 |
|
|
SIGNAL(headerChanged()), |
115 |
|
|
this, |
116 |
|
|
SLOT(columnHeaderChanged())); |
117 |
|
✗ |
QObject::disconnect( |
118 |
|
|
column, |
119 |
|
|
SIGNAL(valueChanged()), |
120 |
|
|
this, |
121 |
|
|
SLOT(valueChanged())); |
122 |
|
|
|
123 |
|
✗ |
impl->updateRows(); |
124 |
|
|
} |
125 |
|
|
|
126 |
|
|
/****************************************************************************/ |
127 |
|
|
|
128 |
|
|
/** Clears the Columns. |
129 |
|
|
*/ |
130 |
|
✗ |
void TableModel::clearColumns() |
131 |
|
|
{ |
132 |
|
✗ |
beginRemoveColumns(QModelIndex(), 0, impl->columnVector.count() - 1); |
133 |
|
✗ |
impl->columnVector.clear(); |
134 |
|
✗ |
endRemoveColumns(); |
135 |
|
|
|
136 |
|
✗ |
for (const auto column : impl->columnVector) { |
137 |
|
✗ |
QObject::disconnect( |
138 |
|
|
column, |
139 |
|
|
SIGNAL(dimensionChanged()), |
140 |
|
|
this, |
141 |
|
|
SLOT(dimensionChanged())); |
142 |
|
✗ |
QObject::disconnect( |
143 |
|
|
column, |
144 |
|
|
SIGNAL(headerChanged()), |
145 |
|
|
this, |
146 |
|
|
SLOT(columnHeaderChanged())); |
147 |
|
✗ |
QObject::disconnect( |
148 |
|
|
column, |
149 |
|
|
SIGNAL(valueChanged()), |
150 |
|
|
this, |
151 |
|
|
SLOT(valueChanged())); |
152 |
|
|
} |
153 |
|
|
|
154 |
|
✗ |
impl->updateRows(); |
155 |
|
|
} |
156 |
|
|
|
157 |
|
|
/****************************************************************************/ |
158 |
|
|
|
159 |
|
✗ |
bool TableModel::isEditing() const |
160 |
|
|
{ |
161 |
|
✗ |
bool editing = false; |
162 |
|
|
|
163 |
|
✗ |
for (const auto column : impl->columnVector) { |
164 |
|
✗ |
if (column->isEditing()) { |
165 |
|
✗ |
editing = true; |
166 |
|
✗ |
break; |
167 |
|
|
} |
168 |
|
|
} |
169 |
|
|
|
170 |
|
✗ |
return editing; |
171 |
|
|
} |
172 |
|
|
|
173 |
|
|
/****************************************************************************/ |
174 |
|
|
|
175 |
|
✗ |
unsigned int TableModel::getRowCapacity() const |
176 |
|
|
{ |
177 |
|
✗ |
return impl->rowCapacity; |
178 |
|
|
} |
179 |
|
|
|
180 |
|
|
/****************************************************************************/ |
181 |
|
|
|
182 |
|
✗ |
bool TableModel::hasVisibleRowsVariable() const |
183 |
|
|
{ |
184 |
|
✗ |
return impl->visibleRowCount.hasVariable(); |
185 |
|
|
} |
186 |
|
|
|
187 |
|
|
/****************************************************************************/ |
188 |
|
|
|
189 |
|
|
/** Implements the model interface. |
190 |
|
|
* |
191 |
|
|
* \returns Number of rows. |
192 |
|
|
*/ |
193 |
|
✗ |
int TableModel::rowCount(const QModelIndex &index) const |
194 |
|
|
{ |
195 |
|
✗ |
if (!index.isValid()) { |
196 |
|
✗ |
return impl->rows; |
197 |
|
|
} |
198 |
|
|
else { |
199 |
|
✗ |
return 0; |
200 |
|
|
} |
201 |
|
|
} |
202 |
|
|
|
203 |
|
|
/****************************************************************************/ |
204 |
|
|
|
205 |
|
|
/** Implements the model interface. |
206 |
|
|
* |
207 |
|
|
* \returns Number of columns. |
208 |
|
|
*/ |
209 |
|
✗ |
int TableModel::columnCount(const QModelIndex &index) const |
210 |
|
|
{ |
211 |
|
✗ |
if (!index.isValid()) { |
212 |
|
✗ |
return impl->columnVector.count(); |
213 |
|
|
} |
214 |
|
|
else { |
215 |
|
✗ |
return 0; |
216 |
|
|
} |
217 |
|
|
} |
218 |
|
|
|
219 |
|
|
/****************************************************************************/ |
220 |
|
|
|
221 |
|
|
/** Implements the Model interface. |
222 |
|
|
*/ |
223 |
|
✗ |
QVariant TableModel::data(const QModelIndex &index, int role) const |
224 |
|
|
{ |
225 |
|
✗ |
if (!index.isValid()) { |
226 |
|
✗ |
return QVariant(); |
227 |
|
|
} |
228 |
|
|
|
229 |
|
✗ |
return impl->columnVector[index.column()]->data(index.row(), role); |
230 |
|
|
} |
231 |
|
|
|
232 |
|
|
/****************************************************************************/ |
233 |
|
|
|
234 |
|
|
/** Implements the Model interface. |
235 |
|
|
*/ |
236 |
|
|
QVariant |
237 |
|
✗ |
TableModel::headerData(int section, Qt::Orientation o, int role) const |
238 |
|
|
{ |
239 |
|
✗ |
if (o != Qt::Horizontal) { |
240 |
|
✗ |
return QVariant(); |
241 |
|
|
} |
242 |
|
|
|
243 |
|
✗ |
return impl->columnVector[section]->headerData(role); |
244 |
|
|
} |
245 |
|
|
|
246 |
|
|
/****************************************************************************/ |
247 |
|
|
|
248 |
|
|
/** Implements the Model interface. |
249 |
|
|
*/ |
250 |
|
✗ |
Qt::ItemFlags TableModel::flags(const QModelIndex &index) const |
251 |
|
|
{ |
252 |
|
✗ |
Qt::ItemFlags f; |
253 |
|
|
|
254 |
|
✗ |
if (index.isValid()) { |
255 |
|
✗ |
f = impl->columnVector[index.column()]->flags(index.row()); |
256 |
|
✗ |
f |= Qt::ItemIsSelectable; |
257 |
|
|
} |
258 |
|
|
|
259 |
|
✗ |
return f; |
260 |
|
|
} |
261 |
|
|
|
262 |
|
|
/****************************************************************************/ |
263 |
|
|
|
264 |
|
✗ |
bool TableModel::setData( |
265 |
|
|
const QModelIndex &index, |
266 |
|
|
const QVariant &value, |
267 |
|
|
int role) |
268 |
|
|
{ |
269 |
|
✗ |
if (!index.isValid()) { |
270 |
|
✗ |
return false; |
271 |
|
|
} |
272 |
|
|
|
273 |
|
✗ |
bool ret = impl->columnVector[index.column()]->setData( |
274 |
|
✗ |
index.row(), |
275 |
|
✗ |
value.toString(), |
276 |
|
✗ |
role); |
277 |
|
|
|
278 |
|
✗ |
emit editingChanged(isEditing()); |
279 |
|
|
|
280 |
|
✗ |
return ret; |
281 |
|
|
} |
282 |
|
|
|
283 |
|
|
/****************************************************************************/ |
284 |
|
|
|
285 |
|
✗ |
bool TableModel::removeRows(int row, int count, const QModelIndex &parent) |
286 |
|
|
{ |
287 |
|
✗ |
if (row < 0 || count <= 0 || parent.isValid()) { |
288 |
|
✗ |
return false; |
289 |
|
|
} |
290 |
|
|
|
291 |
|
✗ |
if (!hasVisibleRowsVariable()) { |
292 |
|
✗ |
return false; |
293 |
|
|
} |
294 |
|
|
|
295 |
|
✗ |
if (row + count > impl->visibleRows) { |
296 |
|
✗ |
return false; |
297 |
|
|
} |
298 |
|
|
|
299 |
|
✗ |
impl->ensureEditing(); |
300 |
|
|
|
301 |
|
✗ |
beginRemoveRows(parent, row, row + count - 1); |
302 |
|
✗ |
for (const auto column : impl->columnVector) { |
303 |
|
✗ |
column->impl->deleteRow(row, count); |
304 |
|
|
} |
305 |
|
✗ |
endRemoveRows(); |
306 |
|
✗ |
impl->visibleRows -= count; |
307 |
|
✗ |
impl->updateRows(); |
308 |
|
✗ |
return true; |
309 |
|
|
} |
310 |
|
|
|
311 |
|
|
/****************************************************************************/ |
312 |
|
|
|
313 |
|
✗ |
void TableModel::setHighlightRowVariable( |
314 |
|
|
PdCom::Variable pv, |
315 |
|
|
const PdCom::Selector &selector, |
316 |
|
|
const Transmission &transmission) |
317 |
|
|
{ |
318 |
|
✗ |
clearHighlightRowVariable(); |
319 |
|
|
|
320 |
|
✗ |
if (pv.empty()) { |
321 |
|
✗ |
return; |
322 |
|
|
} |
323 |
|
|
|
324 |
|
✗ |
impl->valueHighlightRow.setVariable(pv, selector, transmission); |
325 |
|
|
} |
326 |
|
|
|
327 |
|
|
/****************************************************************************/ |
328 |
|
|
|
329 |
|
✗ |
void TableModel::setHighlightRowVariable( |
330 |
|
|
PdCom::Process *process, |
331 |
|
|
const QString &path, |
332 |
|
|
const PdCom::Selector &selector, |
333 |
|
|
const Transmission &transmission) |
334 |
|
|
{ |
335 |
|
✗ |
clearHighlightRowVariable(); |
336 |
|
|
|
337 |
|
✗ |
if (not process or path.isEmpty()) { |
338 |
|
✗ |
return; |
339 |
|
|
} |
340 |
|
|
|
341 |
|
✗ |
impl->valueHighlightRow |
342 |
|
✗ |
.setVariable(process, path, selector, transmission); |
343 |
|
|
} |
344 |
|
|
|
345 |
|
|
/****************************************************************************/ |
346 |
|
|
|
347 |
|
✗ |
void TableModel::clearHighlightRowVariable() |
348 |
|
|
{ |
349 |
|
✗ |
impl->valueHighlightRow.clearVariable(); |
350 |
|
|
|
351 |
|
✗ |
for (const auto column : impl->columnVector) { |
352 |
|
✗ |
column->setHighlightRow(-1); |
353 |
|
|
} |
354 |
|
|
} |
355 |
|
|
|
356 |
|
|
/****************************************************************************/ |
357 |
|
|
|
358 |
|
✗ |
int TableModel::fromCsv( |
359 |
|
|
const QString csvData, |
360 |
|
|
QChar separator, |
361 |
|
|
int startRow, |
362 |
|
|
int startColumn, |
363 |
|
|
const QLocale &locale) |
364 |
|
|
{ |
365 |
|
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) |
366 |
|
|
const auto lines = csvData.split(QChar('\n'), Qt::SkipEmptyParts); |
367 |
|
|
#else |
368 |
|
✗ |
const auto lines = csvData.split(QChar('\n'), QString::SkipEmptyParts); |
369 |
|
|
#endif |
370 |
|
✗ |
if (startRow < 0 || startRow >= lines.size() || startColumn < 0) { |
371 |
|
✗ |
return -ERANGE; |
372 |
|
|
} |
373 |
|
✗ |
int row = 0; |
374 |
|
✗ |
const bool wasEditing = isEditing(); |
375 |
|
|
|
376 |
|
✗ |
for (; row < (lines.size() - startRow); ++row) { |
377 |
|
✗ |
const auto line = lines[row + startRow].split(separator); |
378 |
|
✗ |
if (startColumn >= line.size()) { |
379 |
|
✗ |
return -ERANGE; |
380 |
|
|
} |
381 |
|
|
const auto columnEnd = std::min<int>( |
382 |
|
✗ |
impl->columnVector.size(), |
383 |
|
✗ |
line.size() - startColumn); |
384 |
|
✗ |
for (int column = 0; column < columnEnd; ++column) { |
385 |
|
✗ |
impl->columnVector[column]->impl->setRow( |
386 |
|
|
line[column + startColumn], |
387 |
|
|
row, |
388 |
|
|
locale); |
389 |
|
|
} |
390 |
|
|
} |
391 |
|
✗ |
if (!wasEditing && isEditing()) { |
392 |
|
✗ |
emit editingChanged(true); |
393 |
|
|
} |
394 |
|
|
|
395 |
|
✗ |
impl->visibleRows = |
396 |
|
✗ |
std::min<int>(row, impl->visibleRows + impl->rowCapacity); |
397 |
|
✗ |
impl->updateRows(); |
398 |
|
|
|
399 |
|
✗ |
emit dataChanged( |
400 |
|
✗ |
index(0, 0), |
401 |
|
✗ |
index(rowCount({}) - 1, impl->columnVector.size() - 1)); |
402 |
|
✗ |
return row; |
403 |
|
|
} |
404 |
|
|
|
405 |
|
|
/****************************************************************************/ |
406 |
|
|
|
407 |
|
✗ |
void TableModel::setVisibleRowsVariable( |
408 |
|
|
PdCom::Variable pv, |
409 |
|
|
const PdCom::Selector &selector, |
410 |
|
|
const Transmission &transmission) |
411 |
|
|
{ |
412 |
|
✗ |
clearVisibleRowsVariable(); |
413 |
|
|
|
414 |
|
✗ |
if (pv.empty()) { |
415 |
|
✗ |
return; |
416 |
|
|
} |
417 |
|
|
|
418 |
|
✗ |
impl->visibleRowCount.setVariable(pv, selector, transmission); |
419 |
|
|
} |
420 |
|
|
|
421 |
|
|
/****************************************************************************/ |
422 |
|
|
|
423 |
|
✗ |
void TableModel::setVisibleRowsVariable( |
424 |
|
|
PdCom::Process *process, |
425 |
|
|
const QString &path, |
426 |
|
|
const PdCom::Selector &selector, |
427 |
|
|
const Transmission &transmission) |
428 |
|
|
{ |
429 |
|
✗ |
clearVisibleRowsVariable(); |
430 |
|
|
|
431 |
|
✗ |
if (not process or path.isEmpty()) { |
432 |
|
✗ |
return; |
433 |
|
|
} |
434 |
|
|
|
435 |
|
✗ |
impl->visibleRowCount.setVariable(process, path, selector, transmission); |
436 |
|
|
} |
437 |
|
|
|
438 |
|
|
/****************************************************************************/ |
439 |
|
|
|
440 |
|
✗ |
void TableModel::setHighlightColor(QColor hc, int idx) |
441 |
|
|
{ |
442 |
|
✗ |
if (idx <= -1) { |
443 |
|
✗ |
for (const auto column : impl->columnVector) { |
444 |
|
✗ |
column->setHighlightColor(hc); |
445 |
|
|
} |
446 |
|
|
} |
447 |
|
✗ |
else if (idx < impl->columnVector.size()) { |
448 |
|
✗ |
impl->columnVector[idx]->setHighlightColor(hc); |
449 |
|
|
} |
450 |
|
|
} |
451 |
|
|
|
452 |
|
|
/****************************************************************************/ |
453 |
|
|
|
454 |
|
✗ |
void TableModel::setDisabledColor(QColor dc, int idx) |
455 |
|
|
{ |
456 |
|
✗ |
if (idx <= -1) { |
457 |
|
✗ |
for (const auto column : impl->columnVector) { |
458 |
|
✗ |
column->setDisabledColor(dc); |
459 |
|
|
} |
460 |
|
|
} |
461 |
|
✗ |
else if (idx < impl->columnVector.size()) { |
462 |
|
✗ |
impl->columnVector[idx]->setDisabledColor(dc); |
463 |
|
|
} |
464 |
|
|
} |
465 |
|
|
|
466 |
|
|
/****************************************************************************/ |
467 |
|
|
|
468 |
|
✗ |
void TableModel::clearVisibleRowsVariable() |
469 |
|
|
{ |
470 |
|
✗ |
impl->visibleRowCount.clearVariable(); |
471 |
|
✗ |
impl->visibleRows = UINT_MAX; |
472 |
|
✗ |
impl->updateRows(); |
473 |
|
|
} |
474 |
|
|
|
475 |
|
|
/****************************************************************************/ |
476 |
|
|
|
477 |
|
|
/** Commits all edited data. |
478 |
|
|
*/ |
479 |
|
✗ |
void TableModel::commit() |
480 |
|
|
{ |
481 |
|
✗ |
for (const auto column : impl->columnVector) { |
482 |
|
✗ |
column->commit(); |
483 |
|
|
} |
484 |
|
|
|
485 |
|
✗ |
if (impl->visibleRowCount.hasVariable() |
486 |
|
✗ |
&& impl->visibleRowCount.getVariable().isWriteable()) { |
487 |
|
✗ |
impl->visibleRowCount.writeValue(impl->visibleRows); |
488 |
|
|
} |
489 |
|
|
|
490 |
|
✗ |
emit editingChanged(false); |
491 |
|
|
} |
492 |
|
|
|
493 |
|
|
/****************************************************************************/ |
494 |
|
|
|
495 |
|
|
/** Reverts all edited data. |
496 |
|
|
*/ |
497 |
|
✗ |
void TableModel::revert() |
498 |
|
|
{ |
499 |
|
✗ |
for (const auto column : impl->columnVector) { |
500 |
|
✗ |
column->revert(); |
501 |
|
|
} |
502 |
|
|
|
503 |
|
✗ |
if (impl->visibleRowCount.hasData()) { |
504 |
|
✗ |
impl->visibleRows = impl->visibleRowCount.getValue(); |
505 |
|
|
} |
506 |
|
|
else { |
507 |
|
✗ |
impl->visibleRows = UINT_MAX; |
508 |
|
|
} |
509 |
|
✗ |
impl->updateRows(); |
510 |
|
|
|
511 |
|
✗ |
emit editingChanged(false); |
512 |
|
|
} |
513 |
|
|
|
514 |
|
|
/****************************************************************************/ |
515 |
|
|
|
516 |
|
|
/** updates the visibleRowCount variable. |
517 |
|
|
|
518 |
|
|
*/ |
519 |
|
✗ |
void TableModel::addRow() |
520 |
|
|
{ |
521 |
|
✗ |
if (impl->rowCapacity > 0) { |
522 |
|
✗ |
++impl->visibleRows; |
523 |
|
✗ |
impl->updateRows(); |
524 |
|
|
|
525 |
|
✗ |
impl->ensureEditing(); |
526 |
|
|
} |
527 |
|
|
} |
528 |
|
|
|
529 |
|
|
/** updates the visibleRowCount variable with initialization. |
530 |
|
|
if value is a scalar all columns will be initialized with the same value |
531 |
|
|
otherwise must be a QVariantList |
532 |
|
|
*/ |
533 |
|
✗ |
void TableModel::addRowAndCopyLast() |
534 |
|
|
{ |
535 |
|
✗ |
if (impl->rowCapacity <= 0) { |
536 |
|
✗ |
return; |
537 |
|
|
} |
538 |
|
|
|
539 |
|
✗ |
if (impl->visibleRows <= 0) { |
540 |
|
|
// no row available, so nothing to copy |
541 |
|
✗ |
addRow(); |
542 |
|
✗ |
return; |
543 |
|
|
} |
544 |
|
|
|
545 |
|
✗ |
const bool wasEditing = isEditing(); |
546 |
|
|
|
547 |
|
|
/* and initialize with prev row data */ |
548 |
|
✗ |
for (const auto &column : impl->columnVector) { |
549 |
|
✗ |
const auto columnRows = column->getRows(); |
550 |
|
✗ |
if (columnRows == 0 || impl->visibleRows >= columnRows) { |
551 |
|
✗ |
continue; |
552 |
|
|
} |
553 |
|
✗ |
const auto v = column->data(impl->visibleRows - 1, Qt::DisplayRole) |
554 |
|
✗ |
.toString(); |
555 |
|
✗ |
column->setData(impl->visibleRows, v, Qt::EditRole); |
556 |
|
|
} |
557 |
|
✗ |
++impl->visibleRows; |
558 |
|
✗ |
impl->updateRows(); |
559 |
|
|
|
560 |
|
✗ |
if (!wasEditing) { |
561 |
|
✗ |
emit dataChanged( |
562 |
|
✗ |
index(0, 0), |
563 |
|
✗ |
index(impl->visibleRows - 1, impl->columnVector.count() - 1), |
564 |
|
|
{Qt::BackgroundRole}); |
565 |
|
|
|
566 |
|
✗ |
emit editingChanged(true); |
567 |
|
|
} |
568 |
|
|
} |
569 |
|
|
|
570 |
|
|
/****************************************************************************/ |
571 |
|
|
|
572 |
|
|
/** updates the visibleRowCount variable. |
573 |
|
|
|
574 |
|
|
*/ |
575 |
|
✗ |
bool TableModel::insertRows( |
576 |
|
|
int position, |
577 |
|
|
int count, |
578 |
|
|
const QModelIndex &parent) |
579 |
|
|
{ |
580 |
|
✗ |
if (impl->rowCapacity < count || impl->columnVector.empty()) { |
581 |
|
✗ |
return false; |
582 |
|
|
} |
583 |
|
✗ |
if (parent.isValid() || !hasVisibleRowsVariable()) { |
584 |
|
✗ |
return false; |
585 |
|
|
} |
586 |
|
✗ |
const bool wasEditing = isEditing(); |
587 |
|
✗ |
for (const auto column : impl->columnVector) { |
588 |
|
✗ |
column->impl->insertRow(position, count); |
589 |
|
|
} |
590 |
|
|
|
591 |
|
✗ |
QModelIndex topLeft = index(position, 0); |
592 |
|
✗ |
QModelIndex bottomRight = |
593 |
|
✗ |
index(impl->visibleRows - 1, impl->columnVector.count() - 1); |
594 |
|
✗ |
emit dataChanged(topLeft, bottomRight); |
595 |
|
✗ |
impl->visibleRowCount.writeValue(impl->visibleRows + 1); |
596 |
|
|
|
597 |
|
✗ |
if (!wasEditing) { |
598 |
|
✗ |
emit dataChanged( |
599 |
|
✗ |
index(0, 0), |
600 |
|
✗ |
index(impl->visibleRows - 1, impl->columnVector.count() - 1), |
601 |
|
|
{Qt::BackgroundRole}); |
602 |
|
|
|
603 |
|
✗ |
emit editingChanged(true); |
604 |
|
|
} |
605 |
|
✗ |
return true; |
606 |
|
|
} |
607 |
|
|
|
608 |
|
|
/****************************************************************************/ |
609 |
|
|
|
610 |
|
✗ |
void TableModel::remRow() |
611 |
|
|
{ |
612 |
|
✗ |
removeRows(impl->visibleRows - 1, 1, {}); |
613 |
|
|
} |
614 |
|
|
|
615 |
|
|
/****************************************************************************/ |
616 |
|
|
|
617 |
|
|
/** Calculates the number of table rows. |
618 |
|
|
*/ |
619 |
|
✗ |
void TableModel::Impl::updateRows() |
620 |
|
|
{ |
621 |
|
|
ColumnVector::const_iterator it; |
622 |
|
✗ |
unsigned int maxRows = 0; |
623 |
|
|
|
624 |
|
✗ |
for (it = columnVector.begin(); it != columnVector.end(); it++) { |
625 |
|
✗ |
unsigned int r = (*it)->getRows(); |
626 |
|
✗ |
if (r > maxRows) { |
627 |
|
✗ |
maxRows = r; |
628 |
|
|
} |
629 |
|
|
} |
630 |
|
|
|
631 |
|
✗ |
if (maxRows > visibleRows) { |
632 |
|
✗ |
rowCapacity = maxRows - visibleRows; |
633 |
|
✗ |
maxRows = visibleRows; |
634 |
|
|
} |
635 |
|
|
else { |
636 |
|
✗ |
rowCapacity = 0; |
637 |
|
|
} |
638 |
|
|
|
639 |
|
✗ |
if (maxRows > rows) { |
640 |
|
✗ |
parent->beginInsertRows(QModelIndex(), rows, maxRows - 1); |
641 |
|
✗ |
rows = maxRows; |
642 |
|
✗ |
parent->endInsertRows(); |
643 |
|
|
} |
644 |
|
✗ |
else if (maxRows < rows) { |
645 |
|
✗ |
parent->beginRemoveRows(QModelIndex(), maxRows, rows - 1); |
646 |
|
✗ |
rows = maxRows; |
647 |
|
✗ |
parent->endRemoveRows(); |
648 |
|
|
} |
649 |
|
|
} |
650 |
|
|
|
651 |
|
|
/****************************************************************************/ |
652 |
|
|
|
653 |
|
✗ |
void QtPdCom::TableModel::Impl::ensureEditing() |
654 |
|
|
{ |
655 |
|
✗ |
if (parent->isEditing()) { |
656 |
|
✗ |
return; |
657 |
|
|
} |
658 |
|
|
|
659 |
|
✗ |
for (const auto column : columnVector) { |
660 |
|
✗ |
column->impl->ensureEditData(); |
661 |
|
|
} |
662 |
|
|
|
663 |
|
✗ |
emit parent->dataChanged( |
664 |
|
✗ |
parent->index(0, 0), |
665 |
|
✗ |
parent->index(visibleRows - 1, columnVector.count() - 1), |
666 |
|
|
{Qt::BackgroundRole}); |
667 |
|
|
|
668 |
|
✗ |
emit parent->editingChanged(true); |
669 |
|
|
} |
670 |
|
|
|
671 |
|
|
/****************************************************************************/ |
672 |
|
|
|
673 |
|
|
/** Reacts on process variable dimension changes. |
674 |
|
|
*/ |
675 |
|
✗ |
void TableModel::dimensionChanged() |
676 |
|
|
{ |
677 |
|
✗ |
impl->updateRows(); |
678 |
|
|
} |
679 |
|
|
|
680 |
|
|
/****************************************************************************/ |
681 |
|
|
|
682 |
|
|
/** Reacts on header data changes. |
683 |
|
|
*/ |
684 |
|
✗ |
void TableModel::columnHeaderChanged() |
685 |
|
|
{ |
686 |
|
✗ |
TableColumn *col = dynamic_cast<TableColumn *>(sender()); |
687 |
|
✗ |
int j = impl->columnVector.indexOf(col); |
688 |
|
|
|
689 |
|
✗ |
if (j > -1) { |
690 |
|
✗ |
headerDataChanged(Qt::Horizontal, j, j); |
691 |
|
|
} |
692 |
|
|
} |
693 |
|
|
|
694 |
|
|
/****************************************************************************/ |
695 |
|
|
|
696 |
|
|
/** Reacts on process variable changes. |
697 |
|
|
*/ |
698 |
|
✗ |
void TableModel::valueChanged() |
699 |
|
|
{ |
700 |
|
✗ |
TableColumn *col = dynamic_cast<TableColumn *>(sender()); |
701 |
|
|
|
702 |
|
✗ |
int j = impl->columnVector.indexOf(col); |
703 |
|
✗ |
if (j > -1) { |
704 |
|
✗ |
QModelIndex topLeft = index(0, j); |
705 |
|
✗ |
QModelIndex bottomRight = |
706 |
|
✗ |
index(qMin(col->getRows(), impl->rows) - 1, j); |
707 |
|
✗ |
emit dataChanged(topLeft, bottomRight); |
708 |
|
|
/* qDebug() << "Table changes: " << topLeft.row() |
709 |
|
|
* << topLeft.column() << bottomRight.row() |
710 |
|
|
* << bottomRight.column(); */ |
711 |
|
|
} |
712 |
|
|
} |
713 |
|
|
|
714 |
|
|
/****************************************************************************/ |
715 |
|
|
|
716 |
|
✗ |
void TableModel::highlightRowChanged() |
717 |
|
|
{ |
718 |
|
✗ |
unsigned int row = -1; |
719 |
|
|
|
720 |
|
✗ |
if (impl->valueHighlightRow.hasData()) { |
721 |
|
✗ |
row = impl->valueHighlightRow.getValue(); |
722 |
|
|
} |
723 |
|
|
|
724 |
|
✗ |
for (const auto column : impl->columnVector) { |
725 |
|
✗ |
column->setHighlightRow(row); |
726 |
|
|
} |
727 |
|
|
|
728 |
|
✗ |
if ((impl->columnVector.count() > 0) && (row < impl->rows)) { |
729 |
|
✗ |
QModelIndex topLeft = index(row, 0); |
730 |
|
✗ |
QModelIndex bottomRight = index(row, impl->columnVector.count() - 1); |
731 |
|
✗ |
emit dataChanged(topLeft, bottomRight); |
732 |
|
|
} |
733 |
|
|
} |
734 |
|
|
|
735 |
|
|
/****************************************************************************/ |
736 |
|
|
|
737 |
|
✗ |
void TableModel::visibleRowCountChanged() |
738 |
|
|
{ |
739 |
|
✗ |
if (impl->visibleRowCount.hasData() && !isEditing()) { |
740 |
|
✗ |
impl->visibleRows = impl->visibleRowCount.getValue(); |
741 |
|
✗ |
impl->updateRows(); |
742 |
|
|
} |
743 |
|
|
} |
744 |
|
|
|
745 |
|
|
/****************************************************************************/ |
746 |
|
|
|
747 |
|
✗ |
QHash<int, QByteArray> TableModel::roleNames() const |
748 |
|
|
{ |
749 |
|
|
// default role names |
750 |
|
✗ |
auto roles = QAbstractTableModel::roleNames(); |
751 |
|
|
|
752 |
|
|
// extended role names |
753 |
|
✗ |
roles[TableColumn::HighlightRole] = "highlight"; |
754 |
|
✗ |
roles[TableColumn::ValidRole] = "valid"; |
755 |
|
✗ |
roles[TableColumn::IsEnabledRole] = "isEnabled"; |
756 |
|
✗ |
roles[TableColumn::IsEditingRole] = "isEditing"; |
757 |
|
✗ |
roles[TableColumn::DecimalsRole] = "decimals"; |
758 |
|
✗ |
roles[TableColumn::LowerLimitRole] = "lowerLimit"; |
759 |
|
✗ |
roles[TableColumn::UpperLimitRole] = "upperLimit"; |
760 |
|
✗ |
return roles; |
761 |
|
|
} |
762 |
|
|
|
763 |
|
|
/****************************************************************************/ |
764 |
|
|
|
765 |
|
✗ |
QString TableModel::toCsv( |
766 |
|
|
bool includeHeader, |
767 |
|
|
QChar seperator, |
768 |
|
|
const QLocale &locale) const |
769 |
|
|
{ |
770 |
|
✗ |
QString ans; |
771 |
|
|
|
772 |
|
✗ |
if (impl->columnVector.empty()) { |
773 |
|
✗ |
return ""; |
774 |
|
|
} |
775 |
|
|
|
776 |
|
✗ |
const auto sanitziedHeader = [this](int idx) { |
777 |
|
✗ |
QString ans = impl->columnVector[idx]->getHeader(); |
778 |
|
✗ |
ans.replace('\n', ' '); |
779 |
|
✗ |
ans.replace('\r', QString()); |
780 |
|
✗ |
return ans; |
781 |
|
✗ |
}; |
782 |
|
|
|
783 |
|
✗ |
if (includeHeader) { |
784 |
|
✗ |
ans += sanitziedHeader(0); |
785 |
|
✗ |
for (int column = 1; column < impl->columnVector.count(); ++column) { |
786 |
|
✗ |
ans += seperator + sanitziedHeader(column); |
787 |
|
|
} |
788 |
|
✗ |
ans += '\n'; |
789 |
|
|
} |
790 |
|
|
|
791 |
|
✗ |
for (int row = 0; row < rowCount({}); ++row) { |
792 |
|
✗ |
ans += impl->columnVector[0]->impl->getRow(row, locale); |
793 |
|
✗ |
for (int column = 1; column < impl->columnVector.count(); ++column) { |
794 |
|
✗ |
ans += seperator |
795 |
|
✗ |
+ impl->columnVector[column]->impl->getRow(row, locale); |
796 |
|
|
} |
797 |
|
✗ |
ans += '\n'; |
798 |
|
|
} |
799 |
|
✗ |
return ans; |
800 |
|
|
} |
801 |
|
|
|
802 |
|
|
/****************************************************************************/ |
803 |
|
|
|