1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qtablewidget.h"
5
6#include <qpainter.h>
7#include <private/qtablewidget_p.h>
8
9#include <algorithm>
10
11QT_BEGIN_NAMESPACE
12
13QTableModel::QTableModel(int rows, int columns, QTableWidget *parent)
14 : QAbstractTableModel(parent),
15 prototype(nullptr),
16 tableItems(rows * columns, 0),
17 verticalHeaderItems(rows, 0),
18 horizontalHeaderItems(columns, 0)
19{}
20
21QTableModel::~QTableModel()
22{
23 clear();
24 delete prototype;
25}
26
27bool QTableModel::insertRows(int row, int count, const QModelIndex &)
28{
29 if (count < 1 || row < 0 || row > verticalHeaderItems.size())
30 return false;
31
32 beginInsertRows(parent: QModelIndex(), first: row, last: row + count - 1);
33 int rc = verticalHeaderItems.size();
34 int cc = horizontalHeaderItems.size();
35 verticalHeaderItems.insert(i: row, n: count, t: 0);
36 if (rc == 0)
37 tableItems.resize(size: cc * count);
38 else
39 tableItems.insert(i: tableIndex(row, column: 0), n: cc * count, t: 0);
40 endInsertRows();
41 return true;
42}
43
44bool QTableModel::insertColumns(int column, int count, const QModelIndex &)
45{
46 if (count < 1 || column < 0 || column > horizontalHeaderItems.size())
47 return false;
48
49 beginInsertColumns(parent: QModelIndex(), first: column, last: column + count - 1);
50 int rc = verticalHeaderItems.size();
51 int cc = horizontalHeaderItems.size();
52 horizontalHeaderItems.insert(i: column, n: count, t: 0);
53 if (cc == 0)
54 tableItems.resize(size: rc * count);
55 else
56 for (int row = 0; row < rc; ++row)
57 tableItems.insert(i: tableIndex(row, column), n: count, t: 0);
58 endInsertColumns();
59 return true;
60}
61
62bool QTableModel::removeRows(int row, int count, const QModelIndex &)
63{
64 if (count < 1 || row < 0 || row + count > verticalHeaderItems.size())
65 return false;
66
67 beginRemoveRows(parent: QModelIndex(), first: row, last: row + count - 1);
68 int i = tableIndex(row, column: 0);
69 int n = count * columnCount();
70 QTableWidgetItem *oldItem = nullptr;
71 for (int j = i; j < n + i; ++j) {
72 oldItem = tableItems.at(i: j);
73 if (oldItem)
74 oldItem->view = nullptr;
75 delete oldItem;
76 }
77 tableItems.remove(i: qMax(a: i, b: 0), n);
78 for (int v = row; v < row + count; ++v) {
79 oldItem = verticalHeaderItems.at(i: v);
80 if (oldItem)
81 oldItem->view = nullptr;
82 delete oldItem;
83 }
84 verticalHeaderItems.remove(i: row, n: count);
85 endRemoveRows();
86 return true;
87}
88
89bool QTableModel::removeColumns(int column, int count, const QModelIndex &)
90{
91 if (count < 1 || column < 0 || column + count > horizontalHeaderItems.size())
92 return false;
93
94 beginRemoveColumns(parent: QModelIndex(), first: column, last: column + count - 1);
95 QTableWidgetItem *oldItem = nullptr;
96 for (int row = rowCount() - 1; row >= 0; --row) {
97 int i = tableIndex(row, column);
98 for (int j = i; j < i + count; ++j) {
99 oldItem = tableItems.at(i: j);
100 if (oldItem)
101 oldItem->view = nullptr;
102 delete oldItem;
103 }
104 tableItems.remove(i, n: count);
105 }
106 for (int h=column; h<column+count; ++h) {
107 oldItem = horizontalHeaderItems.at(i: h);
108 if (oldItem)
109 oldItem->view = nullptr;
110 delete oldItem;
111 }
112 horizontalHeaderItems.remove(i: column, n: count);
113 endRemoveColumns();
114 return true;
115}
116
117bool QTableModel::moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild)
118{
119 if (sourceRow < 0
120 || sourceRow + count - 1 >= rowCount(parent: sourceParent)
121 || destinationChild < 0
122 || destinationChild > rowCount(parent: destinationParent)
123 || sourceRow == destinationChild
124 || sourceRow == destinationChild - 1
125 || count <= 0
126 || sourceParent.isValid()
127 || destinationParent.isValid()) {
128 return false;
129 }
130 if (!beginMoveRows(sourceParent, sourceFirst: sourceRow, sourceLast: sourceRow + count - 1, destinationParent, destinationRow: destinationChild))
131 return false;
132
133 // Table items
134 int numItems = count * columnCount();
135 int fromIndex = tableIndex(row: sourceRow, column: 0);
136 int destinationIndex = tableIndex(row: destinationChild, column: 0);
137 if (destinationChild < sourceRow)
138 fromIndex += numItems - 1;
139 else
140 destinationIndex--;
141 while (numItems--)
142 tableItems.move(from: fromIndex, to: destinationIndex);
143
144 // Header items
145 int fromRow = sourceRow;
146 if (destinationChild < sourceRow)
147 fromRow += count - 1;
148 else
149 destinationChild--;
150 while (count--)
151 verticalHeaderItems.move(from: fromRow, to: destinationChild);
152
153 endMoveRows();
154 return true;
155}
156
157void QTableModel::setItem(int row, int column, QTableWidgetItem *item)
158{
159 int i = tableIndex(row, column);
160 if (i < 0 || i >= tableItems.size())
161 return;
162 QTableWidgetItem *oldItem = tableItems.at(i);
163 if (item == oldItem)
164 return;
165
166 // remove old
167 if (oldItem)
168 oldItem->view = nullptr;
169 delete tableItems.at(i);
170
171 QTableWidget *view = qobject_cast<QTableWidget*>(object: QObject::parent());
172
173 // set new
174 if (item)
175 item->d->id = i;
176 tableItems[i] = item;
177
178 if (view && view->isSortingEnabled()
179 && view->horizontalHeader()->sortIndicatorSection() == column) {
180 // sorted insertion
181 Qt::SortOrder order = view->horizontalHeader()->sortIndicatorOrder();
182 QList<QTableWidgetItem *> colItems = columnItems(column);
183 if (row < colItems.size())
184 colItems.remove(i: row);
185 int sortedRow;
186 if (item == nullptr) {
187 // move to after all non-0 (sortable) items
188 sortedRow = colItems.size();
189 } else {
190 QList<QTableWidgetItem *>::iterator it;
191 it = sortedInsertionIterator(begin: colItems.begin(), end: colItems.end(), order, item);
192 sortedRow = qMax(a: (int)(it - colItems.begin()), b: 0);
193 }
194 if (sortedRow != row) {
195 const int destinationChild = sortedRow > row ? sortedRow + 1 : sortedRow;
196 moveRows(sourceParent: QModelIndex(), sourceRow: row, count: 1, destinationParent: QModelIndex(), destinationChild);
197 return;
198 }
199 }
200 QModelIndex idx = QAbstractTableModel::index(row, column);
201 emit dataChanged(topLeft: idx, bottomRight: idx);
202}
203
204QTableWidgetItem *QTableModel::takeItem(int row, int column)
205{
206 long i = tableIndex(row, column);
207 QTableWidgetItem *itm = tableItems.value(i);
208 if (itm) {
209 itm->view = nullptr;
210 itm->d->id = -1;
211 tableItems[i] = 0;
212 const QModelIndex ind = index(row, column);
213 emit dataChanged(topLeft: ind, bottomRight: ind);
214 }
215 return itm;
216}
217
218QTableWidgetItem *QTableModel::item(int row, int column) const
219{
220 return item(index: index(row, column));
221}
222
223QTableWidgetItem *QTableModel::item(const QModelIndex &index) const
224{
225 if (!isValid(index))
226 return nullptr;
227 return tableItems.at(i: tableIndex(row: index.row(), column: index.column()));
228}
229
230void QTableModel::removeItem(QTableWidgetItem *item)
231{
232 int i = tableItems.indexOf(t: item);
233 if (i != -1) {
234 QModelIndex idx = index(item);
235 tableItems[i] = nullptr;
236 emit dataChanged(topLeft: idx, bottomRight: idx);
237 return;
238 }
239
240 i = verticalHeaderItems.indexOf(t: item);
241
242 if (i != -1) {
243 verticalHeaderItems[i] = 0;
244 emit headerDataChanged(orientation: Qt::Vertical, first: i, last: i);
245 return;
246 }
247 i = horizontalHeaderItems.indexOf(t: item);
248 if (i != -1) {
249 horizontalHeaderItems[i] = 0;
250 emit headerDataChanged(orientation: Qt::Horizontal, first: i, last: i);
251 return;
252 }
253}
254
255void QTableModel::setHorizontalHeaderItem(int section, QTableWidgetItem *item)
256{
257 if (section < 0 || section >= horizontalHeaderItems.size())
258 return;
259 QTableWidgetItem *oldItem = horizontalHeaderItems.at(i: section);
260 if (item == oldItem)
261 return;
262
263 if (oldItem)
264 oldItem->view = nullptr;
265 delete oldItem;
266
267 QTableWidget *view = qobject_cast<QTableWidget*>(object: QObject::parent());
268
269 if (item) {
270 item->view = view;
271 item->d->headerItem = true;
272 }
273 horizontalHeaderItems[section] = item;
274 emit headerDataChanged(orientation: Qt::Horizontal, first: section, last: section);
275}
276
277void QTableModel::setVerticalHeaderItem(int section, QTableWidgetItem *item)
278{
279 if (section < 0 || section >= verticalHeaderItems.size())
280 return;
281 QTableWidgetItem *oldItem = verticalHeaderItems.at(i: section);
282 if (item == oldItem)
283 return;
284
285 if (oldItem)
286 oldItem->view = nullptr;
287 delete oldItem;
288
289 QTableWidget *view = qobject_cast<QTableWidget*>(object: QObject::parent());
290
291 if (item) {
292 item->view = view;
293 item->d->headerItem = true;
294 }
295 verticalHeaderItems[section] = item;
296 emit headerDataChanged(orientation: Qt::Vertical, first: section, last: section);
297}
298
299QTableWidgetItem *QTableModel::takeHorizontalHeaderItem(int section)
300{
301 if (section < 0 || section >= horizontalHeaderItems.size())
302 return nullptr;
303 QTableWidgetItem *itm = horizontalHeaderItems.at(i: section);
304 if (itm) {
305 itm->view = nullptr;
306 itm->d->headerItem = false;
307 horizontalHeaderItems[section] = 0;
308 }
309 return itm;
310}
311
312QTableWidgetItem *QTableModel::takeVerticalHeaderItem(int section)
313{
314 if (section < 0 || section >= verticalHeaderItems.size())
315 return nullptr;
316 QTableWidgetItem *itm = verticalHeaderItems.at(i: section);
317 if (itm) {
318 itm->view = nullptr;
319 itm->d->headerItem = false;
320 verticalHeaderItems[section] = 0;
321 }
322 return itm;
323}
324
325QTableWidgetItem *QTableModel::horizontalHeaderItem(int section)
326{
327 return horizontalHeaderItems.value(i: section);
328}
329
330QTableWidgetItem *QTableModel::verticalHeaderItem(int section)
331{
332 return verticalHeaderItems.value(i: section);
333}
334
335QModelIndex QTableModel::index(const QTableWidgetItem *item) const
336{
337 if (!item)
338 return QModelIndex();
339 int i = -1;
340 const int id = item->d->id;
341 if (id >= 0 && id < tableItems.size() && tableItems.at(i: id) == item) {
342 i = id;
343 } else { // we need to search for the item
344 i = tableItems.indexOf(t: const_cast<QTableWidgetItem*>(item));
345 if (i == -1) // not found
346 return QModelIndex();
347 }
348 int row = i / columnCount();
349 int col = i % columnCount();
350 return QAbstractTableModel::index(row, column: col);
351}
352
353void QTableModel::setRowCount(int rows)
354{
355 int rc = verticalHeaderItems.size();
356 if (rows < 0 || rc == rows)
357 return;
358 if (rc < rows)
359 insertRows(row: qMax(a: rc, b: 0), count: rows - rc);
360 else
361 removeRows(row: qMax(a: rows, b: 0), count: rc - rows);
362}
363
364void QTableModel::setColumnCount(int columns)
365{
366 int cc = horizontalHeaderItems.size();
367 if (columns < 0 || cc == columns)
368 return;
369 if (cc < columns)
370 insertColumns(column: qMax(a: cc, b: 0), count: columns - cc);
371 else
372 removeColumns(column: qMax(a: columns, b: 0), count: cc - columns);
373}
374
375int QTableModel::rowCount(const QModelIndex &parent) const
376{
377 return parent.isValid() ? 0 : verticalHeaderItems.size();
378}
379
380int QTableModel::columnCount(const QModelIndex &parent) const
381{
382 return parent.isValid() ? 0 : horizontalHeaderItems.size();
383}
384
385QVariant QTableModel::data(const QModelIndex &index, int role) const
386{
387 QTableWidgetItem *itm = item(index);
388 if (itm)
389 return itm->data(role);
390 return QVariant();
391}
392
393bool QTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
394{
395 if (!index.isValid())
396 return false;
397
398 QTableWidgetItem *itm = item(index);
399 if (itm) {
400 itm->setData(role, value);
401 return true;
402 }
403
404 // don't create dummy table items for empty values
405 if (!value.isValid())
406 return false;
407
408 QTableWidget *view = qobject_cast<QTableWidget*>(object: QObject::parent());
409 if (!view)
410 return false;
411
412 itm = createItem();
413 itm->setData(role, value);
414 view->setItem(row: index.row(), column: index.column(), item: itm);
415 return true;
416}
417
418QMap<int, QVariant> QTableModel::itemData(const QModelIndex &index) const
419{
420 QMap<int, QVariant> roles;
421 QTableWidgetItem *itm = item(index);
422 if (itm) {
423 for (int i = 0; i < itm->values.size(); ++i) {
424 roles.insert(key: itm->values.at(i).role,
425 value: itm->values.at(i).value);
426 }
427 }
428 return roles;
429}
430
431// reimplemented to ensure that only one dataChanged() signal is emitted
432bool QTableModel::setItemData(const QModelIndex &index, const QMap<int, QVariant> &roles)
433{
434 if (!index.isValid())
435 return false;
436
437 QTableWidget *view = qobject_cast<QTableWidget*>(object: QObject::parent());
438 QTableWidgetItem *itm = item(index);
439 if (itm) {
440 itm->view = nullptr; // prohibits item from calling itemChanged()
441 QList<int> rolesVec;
442 for (QMap<int, QVariant>::ConstIterator it = roles.constBegin(); it != roles.constEnd(); ++it) {
443 const int role = (it.key() == Qt::EditRole ? Qt::DisplayRole : it.key());
444 if (itm->data(role) != it.value()) {
445 itm->setData(role, value: it.value());
446 rolesVec += role;
447 if (role == Qt::DisplayRole)
448 rolesVec += Qt::EditRole;
449 }
450 }
451 itm->view = view;
452 if (!rolesVec.isEmpty())
453 itemChanged(item: itm, roles: rolesVec);
454 return true;
455 }
456
457 if (!view)
458 return false;
459
460 itm = createItem();
461 for (QMap<int, QVariant>::ConstIterator it = roles.constBegin(); it != roles.constEnd(); ++it)
462 itm->setData(role: it.key(), value: it.value());
463 view->setItem(row: index.row(), column: index.column(), item: itm);
464 return true;
465}
466
467bool QTableModel::clearItemData(const QModelIndex &index)
468{
469 if (!checkIndex(index, options: CheckIndexOption::IndexIsValid))
470 return false;
471 QTableWidgetItem *itm = item(index);
472 if (!itm)
473 return false;
474 const auto beginIter = itm->values.cbegin();
475 const auto endIter = itm->values.cend();
476 if (std::all_of(first: beginIter, last: endIter, pred: [](const QWidgetItemData& data) -> bool { return !data.value.isValid(); }))
477 return true; //it's already cleared
478 itm->values.clear();
479 emit dataChanged(topLeft: index, bottomRight: index, roles: QList<int> {});
480 return true;
481}
482
483Qt::ItemFlags QTableModel::flags(const QModelIndex &index) const
484{
485 if (!index.isValid())
486 return Qt::ItemIsDropEnabled;
487 if (QTableWidgetItem *itm = item(index))
488 return itm->flags();
489 return (Qt::ItemIsEditable
490 |Qt::ItemIsSelectable
491 |Qt::ItemIsUserCheckable
492 |Qt::ItemIsEnabled
493 |Qt::ItemIsDragEnabled
494 |Qt::ItemIsDropEnabled);
495}
496
497void QTableModel::sort(int column, Qt::SortOrder order)
498{
499 QList<QPair<QTableWidgetItem *, int>> sortable;
500 QList<int> unsortable;
501 const int numRows = rowCount();
502
503 sortable.reserve(asize: numRows);
504 unsortable.reserve(asize: numRows);
505
506 for (int row = 0; row < numRows; ++row) {
507 if (QTableWidgetItem *itm = item(row, column))
508 sortable.append(t: QPair<QTableWidgetItem*,int>(itm, row));
509 else
510 unsortable.append(t: row);
511 }
512
513 const auto compare = (order == Qt::AscendingOrder ? &itemLessThan : &itemGreaterThan);
514 std::stable_sort(first: sortable.begin(), last: sortable.end(), comp: compare);
515
516 QList<QTableWidgetItem *> sorted_table(tableItems.size());
517 QModelIndexList from;
518 QModelIndexList to;
519 const int numColumns = columnCount();
520 from.reserve(asize: numRows * numColumns);
521 to.reserve(asize: numRows * numColumns);
522 for (int i = 0; i < numRows; ++i) {
523 int r = (i < sortable.size()
524 ? sortable.at(i).second
525 : unsortable.at(i: i - sortable.size()));
526 for (int c = 0; c < numColumns; ++c) {
527 sorted_table[tableIndex(row: i, column: c)] = item(row: r, column: c);
528 from.append(t: createIndex(arow: r, acolumn: c));
529 to.append(t: createIndex(arow: i, acolumn: c));
530 }
531 }
532
533 emit layoutAboutToBeChanged(parents: {}, hint: QAbstractItemModel::VerticalSortHint);
534
535 tableItems = sorted_table;
536 changePersistentIndexList(from, to); // ### slow
537
538 emit layoutChanged(parents: {}, hint: QAbstractItemModel::VerticalSortHint);
539}
540
541/*
542 \internal
543
544 Ensures that rows in the interval [start, end] are
545 sorted according to the contents of column \a column
546 and the given sort \a order.
547*/
548void QTableModel::ensureSorted(int column, Qt::SortOrder order,
549 int start, int end)
550{
551 int count = end - start + 1;
552 QList<QPair<QTableWidgetItem *, int>> sorting;
553 sorting.reserve(asize: count);
554 for (int row = start; row <= end; ++row) {
555 QTableWidgetItem *itm = item(row, column);
556 if (itm == nullptr) {
557 // no more sortable items (all 0-items are
558 // at the end of the table when it is sorted)
559 break;
560 }
561 sorting.append(t: QPair<QTableWidgetItem*,int>(itm, row));
562 }
563
564 const auto compare = (order == Qt::AscendingOrder ? &itemLessThan : &itemGreaterThan);
565 std::stable_sort(first: sorting.begin(), last: sorting.end(), comp: compare);
566 QModelIndexList oldPersistentIndexes, newPersistentIndexes;
567 QList<QTableWidgetItem *> newTable = tableItems;
568 QList<QTableWidgetItem *> newVertical = verticalHeaderItems;
569 QList<QTableWidgetItem *> colItems = columnItems(column);
570 QList<QTableWidgetItem *>::iterator vit = colItems.begin();
571 qsizetype distanceFromBegin = 0;
572 bool changed = false;
573 for (int i = 0; i < sorting.size(); ++i) {
574 distanceFromBegin = std::distance(first: colItems.begin(), last: vit);
575 int oldRow = sorting.at(i).second;
576 QTableWidgetItem *item = colItems.at(i: oldRow);
577 colItems.remove(i: oldRow);
578 vit = sortedInsertionIterator(begin: colItems.begin() + distanceFromBegin, end: colItems.end(), order,
579 item);
580 int newRow = qMax(a: (int)(vit - colItems.begin()), b: 0);
581 if ((newRow < oldRow) && !(*item < *colItems.at(i: oldRow - 1)) && !(*colItems.at(i: oldRow - 1) < *item))
582 newRow = oldRow;
583 vit = colItems.insert(before: vit, t: item);
584 if (newRow != oldRow) {
585 if (!changed) {
586 emit layoutAboutToBeChanged(parents: {}, hint: QAbstractItemModel::VerticalSortHint);
587 oldPersistentIndexes = persistentIndexList();
588 newPersistentIndexes = oldPersistentIndexes;
589 changed = true;
590 }
591 // move the items @ oldRow to newRow
592 int cc = columnCount();
593 QList<QTableWidgetItem *> rowItems(cc);
594 for (int j = 0; j < cc; ++j)
595 rowItems[j] = newTable.at(i: tableIndex(row: oldRow, column: j));
596 newTable.remove(i: tableIndex(row: oldRow, column: 0), n: cc);
597 newTable.insert(i: tableIndex(row: newRow, column: 0), n: cc, t: 0);
598 for (int j = 0; j < cc; ++j)
599 newTable[tableIndex(row: newRow, column: j)] = rowItems.at(i: j);
600 QTableWidgetItem *header = newVertical.at(i: oldRow);
601 newVertical.remove(i: oldRow);
602 newVertical.insert(i: newRow, t: header);
603 // update persistent indexes
604 updateRowIndexes(indexes&: newPersistentIndexes, movedFromRow: oldRow, movedToRow: newRow);
605 // the index of the remaining rows may have changed
606 for (int j = i + 1; j < sorting.size(); ++j) {
607 int otherRow = sorting.at(i: j).second;
608 if (oldRow < otherRow && newRow >= otherRow)
609 --sorting[j].second;
610 else if (oldRow > otherRow && newRow <= otherRow)
611 ++sorting[j].second;
612 }
613 }
614 }
615
616 if (changed) {
617 tableItems = newTable;
618 verticalHeaderItems = newVertical;
619 changePersistentIndexList(from: oldPersistentIndexes,
620 to: newPersistentIndexes);
621 emit layoutChanged(parents: {}, hint: QAbstractItemModel::VerticalSortHint);
622 }
623}
624
625/*
626 \internal
627
628 Returns the non-0 items in column \a column.
629*/
630QList<QTableWidgetItem *> QTableModel::columnItems(int column) const
631{
632 QList<QTableWidgetItem *> items;
633 int rc = rowCount();
634 items.reserve(asize: rc);
635 for (int row = 0; row < rc; ++row) {
636 QTableWidgetItem *itm = item(row, column);
637 if (itm == nullptr) {
638 // no more sortable items (all 0-items are
639 // at the end of the table when it is sorted)
640 break;
641 }
642 items.append(t: itm);
643 }
644 return items;
645}
646
647/*
648 \internal
649
650 Adjusts the row of each index in \a indexes if necessary, given
651 that a row of items has been moved from row \a movedFrom to row
652 \a movedTo.
653*/
654void QTableModel::updateRowIndexes(QModelIndexList &indexes,
655 int movedFromRow, int movedToRow)
656{
657 QModelIndexList::iterator it;
658 for (it = indexes.begin(); it != indexes.end(); ++it) {
659 int oldRow = (*it).row();
660 int newRow = oldRow;
661 if (oldRow == movedFromRow)
662 newRow = movedToRow;
663 else if (movedFromRow < oldRow && movedToRow >= oldRow)
664 newRow = oldRow - 1;
665 else if (movedFromRow > oldRow && movedToRow <= oldRow)
666 newRow = oldRow + 1;
667 if (newRow != oldRow)
668 *it = index(row: newRow, column: (*it).column(), parent: (*it).parent());
669 }
670}
671
672/*
673 \internal
674
675 Returns an iterator to the item where \a item should be
676 inserted in the interval (\a begin, \a end) according to
677 the given sort \a order.
678*/
679QList<QTableWidgetItem *>::iterator
680QTableModel::sortedInsertionIterator(const QList<QTableWidgetItem *>::iterator &begin,
681 const QList<QTableWidgetItem *>::iterator &end,
682 Qt::SortOrder order, QTableWidgetItem *item)
683{
684 if (order == Qt::AscendingOrder)
685 return std::lower_bound(first: begin, last: end, val: item, comp: QTableModelLessThan());
686 return std::lower_bound(first: begin, last: end, val: item, comp: QTableModelGreaterThan());
687}
688
689bool QTableModel::itemLessThan(const QPair<QTableWidgetItem*,int> &left,
690 const QPair<QTableWidgetItem*,int> &right)
691{
692 return *(left.first) < *(right.first);
693}
694
695bool QTableModel::itemGreaterThan(const QPair<QTableWidgetItem*,int> &left,
696 const QPair<QTableWidgetItem*,int> &right)
697{
698 return (*(right.first) < *(left .first));
699}
700
701QVariant QTableModel::headerData(int section, Qt::Orientation orientation, int role) const
702{
703 if (section < 0)
704 return QVariant();
705
706 QTableWidgetItem *itm = nullptr;
707 if (orientation == Qt::Horizontal && section < horizontalHeaderItems.size())
708 itm = horizontalHeaderItems.at(i: section);
709 else if (orientation == Qt::Vertical && section < verticalHeaderItems.size())
710 itm = verticalHeaderItems.at(i: section);
711 else
712 return QVariant(); // section is out of bounds
713
714 if (itm)
715 return itm->data(role);
716 if (role == Qt::DisplayRole)
717 return section + 1;
718 return QVariant();
719}
720
721bool QTableModel::setHeaderData(int section, Qt::Orientation orientation,
722 const QVariant &value, int role)
723{
724 if (section < 0 ||
725 (orientation == Qt::Horizontal && horizontalHeaderItems.size() <= section) ||
726 (orientation == Qt::Vertical && verticalHeaderItems.size() <= section))
727 return false;
728
729 QTableWidgetItem *itm = nullptr;
730 if (orientation == Qt::Horizontal)
731 itm = horizontalHeaderItems.at(i: section);
732 else
733 itm = verticalHeaderItems.at(i: section);
734 if (itm) {
735 itm->setData(role, value);
736 return true;
737 }
738 return false;
739}
740
741bool QTableModel::isValid(const QModelIndex &index) const
742{
743 return (index.isValid()
744 && index.row() < verticalHeaderItems.size()
745 && index.column() < horizontalHeaderItems.size());
746}
747
748void QTableModel::clear()
749{
750 for (int j = 0; j < verticalHeaderItems.size(); ++j) {
751 if (verticalHeaderItems.at(i: j)) {
752 verticalHeaderItems.at(i: j)->view = nullptr;
753 delete verticalHeaderItems.at(i: j);
754 verticalHeaderItems[j] = 0;
755 }
756 }
757 for (int k = 0; k < horizontalHeaderItems.size(); ++k) {
758 if (horizontalHeaderItems.at(i: k)) {
759 horizontalHeaderItems.at(i: k)->view = nullptr;
760 delete horizontalHeaderItems.at(i: k);
761 horizontalHeaderItems[k] = 0;
762 }
763 }
764 clearContents();
765}
766
767void QTableModel::clearContents()
768{
769 beginResetModel();
770 for (int i = 0; i < tableItems.size(); ++i) {
771 if (tableItems.at(i)) {
772 tableItems.at(i)->view = nullptr;
773 delete tableItems.at(i);
774 tableItems[i] = 0;
775 }
776 }
777 endResetModel();
778}
779
780void QTableModel::itemChanged(QTableWidgetItem *item, const QList<int> &roles)
781{
782 if (!item)
783 return;
784 if (item->d->headerItem) {
785 int row = verticalHeaderItems.indexOf(t: item);
786 if (row >= 0) {
787 emit headerDataChanged(orientation: Qt::Vertical, first: row, last: row);
788 } else {
789 int column = horizontalHeaderItems.indexOf(t: item);
790 if (column >= 0)
791 emit headerDataChanged(orientation: Qt::Horizontal, first: column, last: column);
792 }
793 } else {
794 QModelIndex idx = index(item);
795 if (idx.isValid())
796 emit dataChanged(topLeft: idx, bottomRight: idx, roles);
797 }
798}
799
800QTableWidgetItem* QTableModel::createItem() const
801{
802 return prototype ? prototype->clone() : new QTableWidgetItem;
803}
804
805const QTableWidgetItem *QTableModel::itemPrototype() const
806{
807 return prototype;
808}
809
810void QTableModel::setItemPrototype(const QTableWidgetItem *item)
811{
812 if (prototype != item) {
813 delete prototype;
814 prototype = item;
815 }
816}
817
818QStringList QTableModel::mimeTypes() const
819{
820 const QTableWidget *view = qobject_cast<const QTableWidget*>(object: QObject::parent());
821 return (view ? view->mimeTypes() : QStringList());
822}
823
824QMimeData *QTableModel::internalMimeData() const
825{
826 return QAbstractTableModel::mimeData(indexes: cachedIndexes);
827}
828
829QMimeData *QTableModel::mimeData(const QModelIndexList &indexes) const
830{
831 QList<QTableWidgetItem*> items;
832 const int indexesCount = indexes.size();
833 items.reserve(asize: indexesCount);
834 for (int i = 0; i < indexesCount; ++i)
835 items << item(index: indexes.at(i));
836 const QTableWidget *view = qobject_cast<const QTableWidget*>(object: QObject::parent());
837
838 // cachedIndexes is a little hack to avoid copying from QModelIndexList to
839 // QList<QTreeWidgetItem*> and back again in the view
840 cachedIndexes = indexes;
841 QMimeData *mimeData = (view ? view->mimeData(items) : nullptr);
842 cachedIndexes.clear();
843 return mimeData;
844}
845
846bool QTableModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
847 int row , int column, const QModelIndex &index)
848{
849 if (index.isValid()) {
850 row = index.row();
851 column = index.column();
852 } else if (row == -1 || column == -1) { // The user dropped outside the table.
853 row = rowCount();
854 column = 0;
855 } else { // The user dropped between two rows
856 // This means inserting a row, which only makes sense at column 0
857 column = 0;
858 }
859
860 QTableWidget *view = qobject_cast<QTableWidget*>(object: QObject::parent());
861 return (view ? view->dropMimeData(row, column, data, action) : false);
862}
863
864Qt::DropActions QTableModel::supportedDropActions() const
865{
866 const QTableWidget *view = qobject_cast<const QTableWidget*>(object: QObject::parent());
867 return (view ? view->supportedDropActions() : Qt::DropActions(Qt::IgnoreAction));
868}
869
870/*!
871 \class QTableWidgetSelectionRange
872
873 \brief The QTableWidgetSelectionRange class provides a way to interact with
874 selection in a model without using model indexes and a selection model.
875
876 \ingroup model-view
877 \inmodule QtWidgets
878
879 The QTableWidgetSelectionRange class stores the top left and bottom
880 right rows and columns of a selection range in a table. The
881 selections in the table may consist of several selection ranges.
882
883 \note If the item within the selection range is marked as not selectable,
884 e.g., \c{itemFlags() & Qt::ItemIsSelectable == 0} then it will not appear
885 in the selection range.
886
887 \sa QTableWidget
888*/
889
890/*!
891 \fn QTableWidgetSelectionRange::QTableWidgetSelectionRange()
892
893 Constructs an empty table selection range, i.e. a range
894 whose rowCount() and columnCount() are 0.
895
896 \sa topRow(), leftColumn(), bottomRow(), rightColumn()
897*/
898
899/*!
900 \fn QTableWidgetSelectionRange::QTableWidgetSelectionRange(int top, int left, int bottom, int right)
901
902 Constructs the table selection range from the given \a top, \a
903 left, \a bottom and \a right table rows and columns.
904
905 \sa topRow(), leftColumn(), bottomRow(), rightColumn()
906*/
907
908/*!
909 \fn bool QTableWidgetSelectionRange::operator==(const QTableWidgetSelectionRange &lhs, const QTableWidgetSelectionRange &rhs)
910 \since 6.3
911
912 Returns true if \a lhs and \a rhs are equal, otherwise returns false.
913*/
914
915/*!
916 \fn bool QTableWidgetSelectionRange::operator!=(const QTableWidgetSelectionRange &lhs, const QTableWidgetSelectionRange &rhs)
917 \since 6.3
918
919 Returns true if \a lhs and \a rhs are not equal, otherwise returns false.
920*/
921
922/*!
923 \fn int QTableWidgetSelectionRange::topRow() const
924
925 Returns the top row of the range.
926
927 \sa bottomRow(), leftColumn(), rowCount()
928*/
929
930/*!
931 \fn int QTableWidgetSelectionRange::bottomRow() const
932
933 Returns the bottom row of the range.
934
935 \sa topRow(), rightColumn(), rowCount()
936*/
937
938/*!
939 \fn int QTableWidgetSelectionRange::leftColumn() const
940
941 Returns the left column of the range.
942
943 \sa rightColumn(), topRow(), columnCount()
944*/
945
946/*!
947 \fn int QTableWidgetSelectionRange::rightColumn() const
948
949 Returns the right column of the range.
950
951 \sa leftColumn(), bottomRow(), columnCount()
952*/
953
954/*!
955 \since 4.1
956 \fn int QTableWidgetSelectionRange::rowCount() const
957
958 Returns the number of rows in the range.
959
960 This is equivalent to bottomRow() - topRow() + 1.
961
962 \sa columnCount(), topRow(), bottomRow()
963*/
964
965/*!
966 \since 4.1
967 \fn int QTableWidgetSelectionRange::columnCount() const
968
969 Returns the number of columns in the range.
970
971 This is equivalent to rightColumn() - leftColumn() + 1.
972
973 \sa rowCount(), leftColumn(), rightColumn()
974*/
975
976/*!
977 \class QTableWidgetItem
978 \brief The QTableWidgetItem class provides an item for use with the
979 QTableWidget class.
980
981 \ingroup model-view
982 \inmodule QtWidgets
983
984 Table items are used to hold pieces of information for table widgets.
985 Items usually contain text, icons, or checkboxes
986
987 The QTableWidgetItem class is a convenience class that replaces the
988 \c QTableItem class in Qt 3. It provides an item for use with
989 the QTableWidget class.
990
991 Top-level items are constructed without a parent then inserted at the
992 position specified by a pair of row and column numbers:
993
994 \snippet qtablewidget-using/mainwindow.cpp 3
995
996 Each item can have its own background brush which is set with
997 the setBackground() function. The current background brush can be
998 found with background().
999 The text label for each item can be rendered with its own font and brush.
1000 These are specified with the setFont() and setForeground() functions,
1001 and read with font() and foreground().
1002
1003 By default, items are enabled, editable, selectable, checkable, and can be
1004 used both as the source of a drag and drop operation and as a drop target.
1005 Each item's flags can be changed by calling setFlags() with the appropriate
1006 value (see \l{Qt::ItemFlags}). Checkable items can be checked and unchecked
1007 with the setCheckState() function. The corresponding checkState() function
1008 indicates whether the item is currently checked.
1009
1010 \section1 Subclassing
1011
1012 When subclassing QTableWidgetItem to provide custom items, it is possible to
1013 define new types for them so that they can be distinguished from standard
1014 items. The constructors for subclasses that require this feature need to
1015 call the base class constructor with a new type value equal to or greater
1016 than \l UserType.
1017
1018 \sa QTableWidget, {Model/View Programming}, QListWidgetItem, QTreeWidgetItem
1019*/
1020
1021/*!
1022 \fn int QTableWidgetItem::row() const
1023 \since 4.2
1024
1025 Returns the row of the item in the table.
1026 If the item is not in a table, this function will return -1.
1027
1028 \sa column()
1029*/
1030
1031/*!
1032 \fn int QTableWidgetItem::column() const
1033 \since 4.2
1034
1035 Returns the column of the item in the table.
1036 If the item is not in a table, this function will return -1.
1037
1038 \sa row()
1039*/
1040
1041/*!
1042 \fn QSize QTableWidgetItem::sizeHint() const
1043 \since 4.1
1044
1045 Returns the size hint set for the table item.
1046*/
1047
1048/*!
1049 \fn void QTableWidgetItem::setSizeHint(const QSize &size)
1050 \since 4.1
1051
1052 Sets the size hint for the table item to be \a size.
1053 If no size hint is set or \a size is invalid, the item
1054 delegate will compute the size hint based on the item data.
1055*/
1056
1057/*!
1058 \fn Qt::CheckState QTableWidgetItem::checkState() const
1059
1060 Returns the checked state of the table item.
1061
1062 \sa flags()
1063*/
1064
1065/*!
1066 \fn void QTableWidgetItem::setCheckState(Qt::CheckState state)
1067
1068 Sets the check state of the table item to be \a state.
1069*/
1070
1071/*!
1072 \fn QTableWidget *QTableWidgetItem::tableWidget() const
1073
1074 Returns the table widget that contains the item.
1075*/
1076
1077/*!
1078 \fn bool QTableWidgetItem::isSelected() const
1079 \since 4.2
1080
1081 Returns \c true if the item is selected, otherwise returns \c false.
1082
1083 \sa setSelected()
1084*/
1085bool QTableWidgetItem::isSelected() const
1086{
1087 if (!view || !view->selectionModel())
1088 return false;
1089 const QTableModel *model = qobject_cast<const QTableModel*>(object: view->model());
1090 if (!model)
1091 return false;
1092 const QModelIndex index = model->index(item: this);
1093 return view->selectionModel()->isSelected(index);
1094}
1095
1096/*!
1097 \fn void QTableWidgetItem::setSelected(bool select)
1098 \since 4.2
1099
1100 Sets the selected state of the item to \a select.
1101
1102 \sa isSelected()
1103*/
1104void QTableWidgetItem::setSelected(bool select)
1105{
1106 if (!view || !view->selectionModel())
1107 return;
1108 const QTableModel *model = qobject_cast<const QTableModel*>(object: view->model());
1109 if (!model)
1110 return;
1111 const QModelIndex index = model->index(item: this);
1112 view->selectionModel()->select(index, command: select ? QItemSelectionModel::Select : QItemSelectionModel::Deselect);
1113}
1114
1115/*!
1116 \fn Qt::ItemFlags QTableWidgetItem::flags() const
1117
1118 Returns the flags used to describe the item. These determine whether
1119 the item can be checked, edited, and selected.
1120
1121 \sa setFlags()
1122*/
1123
1124/*!
1125 \fn void QTableWidgetItem::setFlags(Qt::ItemFlags flags)
1126
1127 Sets the flags for the item to the given \a flags. These determine whether
1128 the item can be selected or modified.
1129
1130 \sa flags()
1131*/
1132void QTableWidgetItem::setFlags(Qt::ItemFlags aflags)
1133{
1134 itemFlags = aflags;
1135 if (QTableModel *model = tableModel())
1136 model->itemChanged(item: this);
1137}
1138
1139
1140/*!
1141 \fn QString QTableWidgetItem::text() const
1142
1143 Returns the item's text.
1144
1145 \sa setText()
1146*/
1147
1148/*!
1149 \fn void QTableWidgetItem::setText(const QString &text)
1150
1151 Sets the item's text to the \a text specified.
1152
1153 \sa text(), setFont(), setForeground()
1154*/
1155
1156/*!
1157 \fn QIcon QTableWidgetItem::icon() const
1158
1159 Returns the item's icon.
1160
1161 \sa setIcon(), {QAbstractItemView::iconSize}{iconSize}
1162*/
1163
1164/*!
1165 \fn void QTableWidgetItem::setIcon(const QIcon &icon)
1166
1167 Sets the item's icon to the \a icon specified.
1168
1169 \sa icon(), setText(), {QAbstractItemView::iconSize}{iconSize}
1170*/
1171
1172/*!
1173 \fn QString QTableWidgetItem::statusTip() const
1174
1175 Returns the item's status tip.
1176
1177 \sa setStatusTip()
1178*/
1179
1180/*!
1181 \fn void QTableWidgetItem::setStatusTip(const QString &statusTip)
1182
1183 Sets the status tip for the table item to the text specified by
1184 \a statusTip. QTableWidget mouse tracking needs to be enabled for this
1185 feature to work.
1186
1187 \sa statusTip(), setToolTip(), setWhatsThis()
1188*/
1189
1190/*!
1191 \fn QString QTableWidgetItem::toolTip() const
1192
1193 Returns the item's tooltip.
1194
1195 \sa setToolTip()
1196*/
1197
1198/*!
1199 \fn void QTableWidgetItem::setToolTip(const QString &toolTip)
1200
1201 Sets the item's tooltip to the string specified by \a toolTip.
1202
1203 \sa toolTip(), setStatusTip(), setWhatsThis()
1204*/
1205
1206/*!
1207 \fn QString QTableWidgetItem::whatsThis() const
1208
1209 Returns the item's "What's This?" help.
1210
1211 \sa setWhatsThis()
1212*/
1213
1214/*!
1215 \fn void QTableWidgetItem::setWhatsThis(const QString &whatsThis)
1216
1217 Sets the item's "What's This?" help to the string specified by \a whatsThis.
1218
1219 \sa whatsThis(), setStatusTip(), setToolTip()
1220*/
1221
1222/*!
1223 \fn QFont QTableWidgetItem::font() const
1224
1225 Returns the font used to render the item's text.
1226
1227 \sa setFont()
1228*/
1229
1230/*!
1231 \fn void QTableWidgetItem::setFont(const QFont &font)
1232
1233 Sets the font used to display the item's text to the given \a font.
1234
1235 \sa font(), setText(), setForeground()
1236*/
1237
1238/*!
1239 \fn QBrush QTableWidgetItem::background() const
1240 \since 4.2
1241
1242 Returns the brush used to render the item's background.
1243
1244 \sa foreground()
1245*/
1246
1247/*!
1248 \fn void QTableWidgetItem::setBackground(const QBrush &brush)
1249 \since 4.2
1250
1251 Sets the item's background brush to the specified \a brush.
1252 Setting a default-constructed brush will let the view use the
1253 default color from the style.
1254
1255 \sa setForeground()
1256*/
1257
1258/*!
1259 \fn QBrush QTableWidgetItem::foreground() const
1260 \since 4.2
1261
1262 Returns the brush used to render the item's foreground (e.g. text).
1263
1264 \sa background()
1265*/
1266
1267/*!
1268 \fn void QTableWidgetItem::setForeground(const QBrush &brush)
1269 \since 4.2
1270
1271 Sets the item's foreground brush to the specified \a brush.
1272 Setting a default-constructed brush will let the view use the
1273 default color from the style.
1274
1275 \sa setBackground()
1276*/
1277
1278/*!
1279 \if defined(qt7)
1280
1281 \fn Qt::Alignment QTableWidgetItem::textAlignment() const
1282
1283 Returns the text alignment for the list item.
1284
1285 \else
1286
1287 \fn int QTableWidgetItem::textAlignment() const
1288
1289 Returns the text alignment for the item's text.
1290
1291 \note This function returns an int for historical reasons. It will
1292 be corrected to return Qt::Alignment in Qt 7.
1293
1294 \sa Qt::Alignment
1295
1296 \endif
1297*/
1298
1299/*!
1300 \obsolete [6.4] Use the overload that takes a Qt::Alignment argument.
1301
1302 \fn void QTableWidgetItem::setTextAlignment(int alignment)
1303
1304 Sets the text alignment for the item's text to the \a alignment
1305 specified.
1306
1307 \sa Qt::Alignment
1308*/
1309
1310/*!
1311 \since 6.4
1312
1313 \fn void QTableWidgetItem::setTextAlignment(Qt::Alignment alignment)
1314
1315 Sets the text alignment for the item's text to the \a alignment
1316 specified.
1317*/
1318
1319/*!
1320 \fn void QTableWidgetItem::setTextAlignment(Qt::AlignmentFlag alignment)
1321 \internal
1322*/
1323
1324/*!
1325 Constructs a table item of the specified \a type that does not belong
1326 to any table.
1327
1328 \sa type()
1329*/
1330QTableWidgetItem::QTableWidgetItem(int type)
1331 : rtti(type), view(nullptr), d(new QTableWidgetItemPrivate(this)),
1332 itemFlags(Qt::ItemIsEditable
1333 |Qt::ItemIsSelectable
1334 |Qt::ItemIsUserCheckable
1335 |Qt::ItemIsEnabled
1336 |Qt::ItemIsDragEnabled
1337 |Qt::ItemIsDropEnabled)
1338{
1339}
1340
1341/*!
1342 Constructs a table item with the given \a text.
1343
1344 \sa type()
1345*/
1346QTableWidgetItem::QTableWidgetItem(const QString &text, int type)
1347 : rtti(type), view(nullptr), d(new QTableWidgetItemPrivate(this)),
1348 itemFlags(Qt::ItemIsEditable
1349 |Qt::ItemIsSelectable
1350 |Qt::ItemIsUserCheckable
1351 |Qt::ItemIsEnabled
1352 |Qt::ItemIsDragEnabled
1353 |Qt::ItemIsDropEnabled)
1354{
1355 setData(role: Qt::DisplayRole, value: text);
1356}
1357
1358/*!
1359 Constructs a table item with the given \a icon and \a text.
1360
1361 \sa type()
1362*/
1363QTableWidgetItem::QTableWidgetItem(const QIcon &icon, const QString &text, int type)
1364 : rtti(type), view(nullptr), d(new QTableWidgetItemPrivate(this)),
1365 itemFlags(Qt::ItemIsEditable
1366 |Qt::ItemIsSelectable
1367 |Qt::ItemIsUserCheckable
1368 |Qt::ItemIsEnabled
1369 |Qt::ItemIsDragEnabled
1370 |Qt::ItemIsDropEnabled)
1371{
1372 setData(role: Qt::DecorationRole, value: icon);
1373 setData(role: Qt::DisplayRole, value: text);
1374}
1375
1376/*!
1377 Destroys the table item.
1378*/
1379QTableWidgetItem::~QTableWidgetItem()
1380{
1381 if (QTableModel *model = tableModel())
1382 model->removeItem(item: this);
1383 delete d;
1384}
1385
1386/*!
1387 Creates a copy of the item.
1388*/
1389QTableWidgetItem *QTableWidgetItem::clone() const
1390{
1391 return new QTableWidgetItem(*this);
1392}
1393
1394/*!
1395 Sets the item's data for the given \a role to the specified \a value.
1396
1397 \note The default implementation treats Qt::EditRole and Qt::DisplayRole as
1398 referring to the same data.
1399
1400 \sa Qt::ItemDataRole, data()
1401*/
1402void QTableWidgetItem::setData(int role, const QVariant &value)
1403{
1404 bool found = false;
1405 role = (role == Qt::EditRole ? Qt::DisplayRole : role);
1406 for (int i = 0; i < values.size(); ++i) {
1407 if (values.at(i).role == role) {
1408 if (values[i].value == value)
1409 return;
1410
1411 values[i].value = value;
1412 found = true;
1413 break;
1414 }
1415 }
1416 if (!found)
1417 values.append(t: QWidgetItemData(role, value));
1418 if (QTableModel *model = tableModel())
1419 {
1420 const QList<int> roles((role == Qt::DisplayRole)
1421 ? QList<int>({ Qt::DisplayRole, Qt::EditRole })
1422 : QList<int>({ role }));
1423 model->itemChanged(item: this, roles);
1424 }
1425}
1426
1427/*!
1428 Returns the item's data for the given \a role.
1429*/
1430QVariant QTableWidgetItem::data(int role) const
1431{
1432 role = (role == Qt::EditRole ? Qt::DisplayRole : role);
1433 for (const auto &value : values) {
1434 if (value.role == role)
1435 return value.value;
1436 }
1437 return QVariant();
1438}
1439
1440/*!
1441 Returns \c true if the item is less than the \a other item; otherwise returns
1442 false.
1443*/
1444bool QTableWidgetItem::operator<(const QTableWidgetItem &other) const
1445{
1446 const QVariant v1 = data(role: Qt::DisplayRole), v2 = other.data(role: Qt::DisplayRole);
1447 return QAbstractItemModelPrivate::variantLessThan(v1, v2);
1448}
1449
1450#ifndef QT_NO_DATASTREAM
1451
1452/*!
1453 Reads the item from stream \a in.
1454
1455 \sa write()
1456*/
1457void QTableWidgetItem::read(QDataStream &in)
1458{
1459 in >> values;
1460}
1461
1462/*!
1463 Writes the item to stream \a out.
1464
1465 \sa read()
1466*/
1467void QTableWidgetItem::write(QDataStream &out) const
1468{
1469 out << values;
1470}
1471
1472/*!
1473 \internal
1474 returns the QTableModel if a view is set
1475*/
1476QTableModel *QTableWidgetItem::tableModel() const
1477{
1478 return (view ? qobject_cast<QTableModel*>(object: view->model()) : nullptr);
1479}
1480
1481
1482/*!
1483 \relates QTableWidgetItem
1484
1485 Reads a table widget item from stream \a in into \a item.
1486
1487 This operator uses QTableWidgetItem::read().
1488
1489 \sa {Serializing Qt Data Types}
1490*/
1491QDataStream &operator>>(QDataStream &in, QTableWidgetItem &item)
1492{
1493 item.read(in);
1494 return in;
1495}
1496
1497/*!
1498 \relates QTableWidgetItem
1499
1500 Writes the table widget item \a item to stream \a out.
1501
1502 This operator uses QTableWidgetItem::write().
1503
1504 \sa {Serializing Qt Data Types}
1505*/
1506QDataStream &operator<<(QDataStream &out, const QTableWidgetItem &item)
1507{
1508 item.write(out);
1509 return out;
1510}
1511
1512#endif // QT_NO_DATASTREAM
1513
1514/*!
1515 \since 4.1
1516
1517 Constructs a copy of \a other. Note that type() and tableWidget()
1518 are not copied.
1519
1520 This function is useful when reimplementing clone().
1521
1522 \sa data(), flags()
1523*/
1524QTableWidgetItem::QTableWidgetItem(const QTableWidgetItem &other)
1525 : rtti(Type), values(other.values), view(nullptr),
1526 d(new QTableWidgetItemPrivate(this)),
1527 itemFlags(other.itemFlags)
1528{
1529}
1530
1531/*!
1532 Assigns \a other's data and flags to this item. Note that type()
1533 and tableWidget() are not copied.
1534
1535 This function is useful when reimplementing clone().
1536
1537 \sa data(), flags()
1538*/
1539QTableWidgetItem &QTableWidgetItem::operator=(const QTableWidgetItem &other)
1540{
1541 values = other.values;
1542 itemFlags = other.itemFlags;
1543 return *this;
1544}
1545
1546/*!
1547 \class QTableWidget
1548 \brief The QTableWidget class provides an item-based table view with a default model.
1549
1550 \ingroup model-view
1551 \inmodule QtWidgets
1552
1553 \image fusion-tableview.png
1554
1555 Table widgets provide standard table display facilities for applications.
1556 The items in a QTableWidget are provided by QTableWidgetItem.
1557
1558 If you want a table that uses your own data model you should
1559 use QTableView rather than this class.
1560
1561 Table widgets can be constructed with the required numbers of rows and
1562 columns:
1563
1564 \snippet qtablewidget-using/mainwindow.cpp 0
1565
1566 Alternatively, tables can be constructed without a given size and resized
1567 later:
1568
1569 \snippet qtablewidget-resizing/mainwindow.cpp 0
1570 \snippet qtablewidget-resizing/mainwindow.cpp 1
1571
1572 Items are created outside the table (with no parent widget) and inserted
1573 into the table with setItem():
1574
1575 \snippet qtablewidget-resizing/mainwindow.cpp 2
1576
1577 If you want to enable sorting in your table widget, do so after you
1578 have populated it with items, otherwise sorting may interfere with
1579 the insertion order (see setItem() for details).
1580
1581 Tables can be given both horizontal and vertical headers. The simplest way
1582 to create the headers is to supply a list of strings to the
1583 setHorizontalHeaderLabels() and setVerticalHeaderLabels() functions. These
1584 will provide simple textual headers for the table's columns and rows.
1585 More sophisticated headers can be created from existing table items
1586 that are usually constructed outside the table. For example, we can
1587 construct a table item with an icon and aligned text, and use it as the
1588 header for a particular column:
1589
1590 \snippet qtablewidget-using/mainwindow.cpp 2
1591
1592 The number of rows in the table can be found with rowCount(), and the
1593 number of columns with columnCount(). The table can be cleared with the
1594 clear() function.
1595
1596 \sa QTableWidgetItem, QTableView, {Model/View Programming}
1597*/
1598
1599/*!
1600 \property QTableWidget::rowCount
1601 \brief the number of rows in the table
1602
1603 By default, for a table constructed without row and column counts,
1604 this property contains a value of 0.
1605*/
1606
1607/*!
1608 \property QTableWidget::columnCount
1609 \brief the number of columns in the table
1610
1611 By default, for a table constructed without row and column counts,
1612 this property contains a value of 0.
1613*/
1614
1615void QTableWidgetPrivate::setup()
1616{
1617 Q_Q(QTableWidget);
1618 connections = {
1619 // view signals
1620 QObjectPrivate::connect(sender: q, signal: &QTableWidget::pressed,
1621 receiverPrivate: this, slot: &QTableWidgetPrivate::emitItemPressed),
1622 QObjectPrivate::connect(sender: q, signal: &QTableWidget::clicked,
1623 receiverPrivate: this, slot: &QTableWidgetPrivate::emitItemClicked),
1624 QObjectPrivate::connect(sender: q, signal: &QTableWidget::doubleClicked,
1625 receiverPrivate: this, slot: &QTableWidgetPrivate::emitItemDoubleClicked),
1626 QObjectPrivate::connect(sender: q, signal: &QTableWidget::activated,
1627 receiverPrivate: this, slot: &QTableWidgetPrivate::emitItemActivated),
1628 QObjectPrivate::connect(sender: q, signal: &QTableWidget::entered,
1629 receiverPrivate: this, slot: &QTableWidgetPrivate::emitItemEntered),
1630 // model signals
1631 QObjectPrivate::connect(sender: model, signal: &QAbstractItemModel::dataChanged,
1632 receiverPrivate: this, slot: &QTableWidgetPrivate::emitItemChanged),
1633 // selection signals
1634 QObjectPrivate::connect(sender: q->selectionModel(), signal: &QItemSelectionModel::currentChanged,
1635 receiverPrivate: this, slot: &QTableWidgetPrivate::emitCurrentItemChanged),
1636 QObject::connect(sender: q->selectionModel(), signal: &QItemSelectionModel::selectionChanged,
1637 context: q, slot: &QTableWidget::itemSelectionChanged),
1638 // sorting
1639 QObjectPrivate::connect(sender: model, signal: &QAbstractItemModel::dataChanged,
1640 receiverPrivate: this, slot: &QTableWidgetPrivate::dataChanged),
1641 QObjectPrivate::connect(sender: model, signal: &QAbstractItemModel::columnsRemoved,
1642 receiverPrivate: this, slot: &QTableWidgetPrivate::sort)
1643 };
1644}
1645
1646void QTableWidgetPrivate::clearConnections()
1647{
1648 for (const QMetaObject::Connection &connection : connections)
1649 QObject::disconnect(connection);
1650}
1651
1652void QTableWidgetPrivate::emitItemPressed(const QModelIndex &index)
1653{
1654 Q_Q(QTableWidget);
1655 if (QTableWidgetItem *item = tableModel()->item(index))
1656 emit q->itemPressed(item);
1657 emit q->cellPressed(row: index.row(), column: index.column());
1658}
1659
1660void QTableWidgetPrivate::emitItemClicked(const QModelIndex &index)
1661{
1662 Q_Q(QTableWidget);
1663 if (QTableWidgetItem *item = tableModel()->item(index))
1664 emit q->itemClicked(item);
1665 emit q->cellClicked(row: index.row(), column: index.column());
1666}
1667
1668void QTableWidgetPrivate::emitItemDoubleClicked(const QModelIndex &index)
1669{
1670 Q_Q(QTableWidget);
1671 if (QTableWidgetItem *item = tableModel()->item(index))
1672 emit q->itemDoubleClicked(item);
1673 emit q->cellDoubleClicked(row: index.row(), column: index.column());
1674}
1675
1676void QTableWidgetPrivate::emitItemActivated(const QModelIndex &index)
1677{
1678 Q_Q(QTableWidget);
1679 if (QTableWidgetItem *item = tableModel()->item(index))
1680 emit q->itemActivated(item);
1681 emit q->cellActivated(row: index.row(), column: index.column());
1682}
1683
1684void QTableWidgetPrivate::emitItemEntered(const QModelIndex &index)
1685{
1686 Q_Q(QTableWidget);
1687 if (QTableWidgetItem *item = tableModel()->item(index))
1688 emit q->itemEntered(item);
1689 emit q->cellEntered(row: index.row(), column: index.column());
1690}
1691
1692void QTableWidgetPrivate::emitItemChanged(const QModelIndex &index)
1693{
1694 Q_Q(QTableWidget);
1695 if (QTableWidgetItem *item = tableModel()->item(index))
1696 emit q->itemChanged(item);
1697 emit q->cellChanged(row: index.row(), column: index.column());
1698}
1699
1700void QTableWidgetPrivate::emitCurrentItemChanged(const QModelIndex &current,
1701 const QModelIndex &previous)
1702{
1703 Q_Q(QTableWidget);
1704 QTableWidgetItem *currentItem = tableModel()->item(index: current);
1705 QTableWidgetItem *previousItem = tableModel()->item(index: previous);
1706 if (currentItem || previousItem)
1707 emit q->currentItemChanged(current: currentItem, previous: previousItem);
1708 emit q->currentCellChanged(currentRow: current.row(), currentColumn: current.column(), previousRow: previous.row(), previousColumn: previous.column());
1709}
1710
1711void QTableWidgetPrivate::sort()
1712{
1713 if (sortingEnabled) {
1714 int column = horizontalHeader->sortIndicatorSection();
1715 Qt::SortOrder order = horizontalHeader->sortIndicatorOrder();
1716 model->sort(column, order);
1717 }
1718}
1719
1720void QTableWidgetPrivate::dataChanged(const QModelIndex &topLeft,
1721 const QModelIndex &bottomRight)
1722{
1723 if (sortingEnabled && topLeft.isValid() && bottomRight.isValid()) {
1724 int column = horizontalHeader->sortIndicatorSection();
1725 if (column >= topLeft.column() && column <= bottomRight.column()) {
1726 Qt::SortOrder order = horizontalHeader->sortIndicatorOrder();
1727 tableModel()->ensureSorted(column, order, start: topLeft.row(), end: bottomRight.row());
1728 }
1729 }
1730}
1731
1732/*!
1733 \fn void QTableWidget::itemPressed(QTableWidgetItem *item)
1734
1735 This signal is emitted whenever an item in the table is pressed.
1736 The \a item specified is the item that was pressed.
1737*/
1738
1739/*!
1740 \fn void QTableWidget::itemClicked(QTableWidgetItem *item)
1741
1742 This signal is emitted whenever an item in the table is clicked.
1743 The \a item specified is the item that was clicked.
1744*/
1745
1746/*!
1747 \fn void QTableWidget::itemDoubleClicked(QTableWidgetItem *item)
1748
1749 This signal is emitted whenever an item in the table is double
1750 clicked. The \a item specified is the item that was double clicked.
1751*/
1752
1753/*!
1754 \fn void QTableWidget::itemActivated(QTableWidgetItem *item)
1755
1756 This signal is emitted when the specified \a item has been activated
1757*/
1758
1759/*!
1760 \fn void QTableWidget::itemEntered(QTableWidgetItem *item)
1761
1762 This signal is emitted when the mouse cursor enters an item. The
1763 \a item is the item entered.
1764
1765 This signal is only emitted when mouseTracking is turned on, or when a
1766 mouse button is pressed while moving into an item.
1767*/
1768
1769/*!
1770 \fn void QTableWidget::itemChanged(QTableWidgetItem *item)
1771
1772 This signal is emitted whenever the data of \a item has changed.
1773*/
1774
1775/*!
1776 \fn void QTableWidget::currentItemChanged(QTableWidgetItem *current, QTableWidgetItem *previous)
1777
1778 This signal is emitted whenever the current item changes. The \a
1779 previous item is the item that previously had the focus, \a
1780 current is the new current item.
1781*/
1782
1783/*!
1784 \fn void QTableWidget::itemSelectionChanged()
1785
1786 This signal is emitted whenever the selection changes.
1787
1788 \sa selectedItems(), QTableWidgetItem::isSelected()
1789*/
1790
1791
1792/*!
1793 \since 4.1
1794 \fn void QTableWidget::cellPressed(int row, int column)
1795
1796 This signal is emitted whenever a cell in the table is pressed.
1797 The \a row and \a column specified is the cell that was pressed.
1798*/
1799
1800/*!
1801 \since 4.1
1802 \fn void QTableWidget::cellClicked(int row, int column)
1803
1804 This signal is emitted whenever a cell in the table is clicked.
1805 The \a row and \a column specified is the cell that was clicked.
1806*/
1807
1808/*!
1809 \since 4.1
1810 \fn void QTableWidget::cellDoubleClicked(int row, int column)
1811
1812 This signal is emitted whenever a cell in the table is double
1813 clicked. The \a row and \a column specified is the cell that was
1814 double clicked.
1815*/
1816
1817/*!
1818 \since 4.1
1819 \fn void QTableWidget::cellActivated(int row, int column)
1820
1821 This signal is emitted when the cell specified by \a row and \a column
1822 has been activated
1823*/
1824
1825/*!
1826 \since 4.1
1827 \fn void QTableWidget::cellEntered(int row, int column)
1828
1829 This signal is emitted when the mouse cursor enters a cell. The
1830 cell is specified by \a row and \a column.
1831
1832 This signal is only emitted when mouseTracking is turned on, or when a
1833 mouse button is pressed while moving into an item.
1834*/
1835
1836/*!
1837 \since 4.1
1838 \fn void QTableWidget::cellChanged(int row, int column)
1839
1840 This signal is emitted whenever the data of the item in the cell
1841 specified by \a row and \a column has changed.
1842*/
1843
1844/*!
1845 \since 4.1
1846 \fn void QTableWidget::currentCellChanged(int currentRow, int currentColumn, int previousRow, int previousColumn)
1847
1848 This signal is emitted whenever the current cell changes. The cell
1849 specified by \a previousRow and \a previousColumn is the cell that
1850 previously had the focus, the cell specified by \a currentRow and \a
1851 currentColumn is the new current cell.
1852*/
1853
1854/*!
1855 \since 4.3
1856 \fn void QTableWidget::removeCellWidget(int row, int column)
1857
1858 Removes the widget set on the cell indicated by \a row and \a column.
1859*/
1860
1861/*!
1862 \fn QTableWidgetItem *QTableWidget::itemAt(int ax, int ay) const
1863
1864 Returns the item at the position equivalent to QPoint(\a{ax}, \a{ay}) in
1865 the table widget's coordinate system, or returns \nullptr if the specified point
1866 is not covered by an item in the table widget.
1867
1868 \sa item()
1869*/
1870
1871/*!
1872 \enum QTableWidgetItem::ItemType
1873
1874 This enum describes the types that are used to describe table widget items.
1875
1876 \value Type The default type for table widget items.
1877 \value UserType The minimum value for custom types. Values below UserType are
1878 reserved by Qt.
1879
1880 You can define new user types in QTableWidgetItem subclasses to ensure that
1881 custom items are treated specially.
1882
1883 \sa type()
1884*/
1885
1886/*!
1887 \fn int QTableWidgetItem::type() const
1888
1889 Returns the type passed to the QTableWidgetItem constructor.
1890*/
1891
1892/*!
1893 Creates a new table view with the given \a parent.
1894*/
1895QTableWidget::QTableWidget(QWidget *parent)
1896 : QTableView(*new QTableWidgetPrivate, parent)
1897{
1898 Q_D(QTableWidget);
1899 QTableView::setModel(new QTableModel(0, 0, this));
1900 d->setup();
1901}
1902
1903/*!
1904 Creates a new table view with the given \a rows and \a columns, and with the given \a parent.
1905*/
1906QTableWidget::QTableWidget(int rows, int columns, QWidget *parent)
1907 : QTableView(*new QTableWidgetPrivate, parent)
1908{
1909 Q_D(QTableWidget);
1910 QTableView::setModel(new QTableModel(rows, columns, this));
1911 d->setup();
1912}
1913
1914/*!
1915 Destroys this QTableWidget.
1916*/
1917QTableWidget::~QTableWidget()
1918{
1919 Q_D(QTableWidget);
1920 d->clearConnections();
1921}
1922
1923/*!
1924 Sets the number of rows in this table's model to \a rows. If
1925 this is less than rowCount(), the data in the unwanted rows
1926 is discarded.
1927
1928 \sa setColumnCount()
1929*/
1930void QTableWidget::setRowCount(int rows)
1931{
1932 Q_D(QTableWidget);
1933 d->tableModel()->setRowCount(rows);
1934}
1935
1936/*!
1937 Returns the number of rows.
1938*/
1939
1940int QTableWidget::rowCount() const
1941{
1942 Q_D(const QTableWidget);
1943 return d->model->rowCount();
1944}
1945
1946/*!
1947 Sets the number of columns in this table's model to \a columns. If
1948 this is less than columnCount(), the data in the unwanted columns
1949 is discarded.
1950
1951 \sa setRowCount()
1952*/
1953void QTableWidget::setColumnCount(int columns)
1954{
1955 Q_D(QTableWidget);
1956 d->tableModel()->setColumnCount(columns);
1957}
1958
1959/*!
1960 Returns the number of columns.
1961*/
1962
1963int QTableWidget::columnCount() const
1964{
1965 Q_D(const QTableWidget);
1966 return d->model->columnCount();
1967}
1968
1969/*!
1970 Returns the row for the \a item.
1971*/
1972int QTableWidget::row(const QTableWidgetItem *item) const
1973{
1974 Q_D(const QTableWidget);
1975 return d->tableModel()->index(item).row();
1976}
1977
1978/*!
1979 Returns the column for the \a item.
1980*/
1981int QTableWidget::column(const QTableWidgetItem *item) const
1982{
1983 Q_D(const QTableWidget);
1984 return d->tableModel()->index(item).column();
1985}
1986
1987
1988/*!
1989 Returns the item for the given \a row and \a column if one has been set; otherwise
1990 returns \nullptr.
1991
1992 \sa setItem()
1993*/
1994QTableWidgetItem *QTableWidget::item(int row, int column) const
1995{
1996 Q_D(const QTableWidget);
1997 return d->tableModel()->item(row, column);
1998}
1999
2000/*!
2001 Sets the item for the given \a row and \a column to \a item.
2002
2003 The table takes ownership of the item.
2004
2005 Note that if sorting is enabled (see
2006 \l{QTableView::sortingEnabled} {sortingEnabled}) and \a column is
2007 the current sort column, the \a row will be moved to the sorted
2008 position determined by \a item.
2009
2010 If you want to set several items of a particular row (say, by
2011 calling setItem() in a loop), you may want to turn off sorting
2012 before doing so, and turn it back on afterwards; this will allow
2013 you to use the same \a row argument for all items in the same row
2014 (i.e. setItem() will not move the row).
2015
2016 \sa item(), takeItem()
2017*/
2018void QTableWidget::setItem(int row, int column, QTableWidgetItem *item)
2019{
2020 Q_D(QTableWidget);
2021 if (item) {
2022 if (Q_UNLIKELY(item->view)) {
2023 qWarning(msg: "QTableWidget: cannot insert an item that is already owned by another QTableWidget");
2024 } else {
2025 item->view = this;
2026 d->tableModel()->setItem(row, column, item);
2027 }
2028 } else {
2029 delete takeItem(row, column);
2030 }
2031}
2032
2033/*!
2034 Removes the item at \a row and \a column from the table without deleting it.
2035*/
2036QTableWidgetItem *QTableWidget::takeItem(int row, int column)
2037{
2038 Q_D(QTableWidget);
2039 QTableWidgetItem *item = d->tableModel()->takeItem(row, column);
2040 if (item)
2041 item->view = nullptr;
2042 return item;
2043}
2044
2045/*!
2046 Returns the vertical header item for row \a row.
2047*/
2048QTableWidgetItem *QTableWidget::verticalHeaderItem(int row) const
2049{
2050 Q_D(const QTableWidget);
2051 return d->tableModel()->verticalHeaderItem(section: row);
2052}
2053
2054/*!
2055 Sets the vertical header item for row \a row to \a item.
2056*/
2057void QTableWidget::setVerticalHeaderItem(int row, QTableWidgetItem *item)
2058{
2059 Q_D(QTableWidget);
2060 if (item) {
2061 item->view = this;
2062 d->tableModel()->setVerticalHeaderItem(section: row, item);
2063 } else {
2064 delete takeVerticalHeaderItem(row);
2065 }
2066}
2067
2068/*!
2069 \since 4.1
2070 Removes the vertical header item at \a row from the header without deleting it.
2071*/
2072QTableWidgetItem *QTableWidget::takeVerticalHeaderItem(int row)
2073{
2074 Q_D(QTableWidget);
2075 QTableWidgetItem *itm = d->tableModel()->takeVerticalHeaderItem(section: row);
2076 if (itm)
2077 itm->view = nullptr;
2078 return itm;
2079}
2080
2081/*!
2082 Returns the horizontal header item for column, \a column, if one has been
2083 set; otherwise returns \nullptr.
2084*/
2085QTableWidgetItem *QTableWidget::horizontalHeaderItem(int column) const
2086{
2087 Q_D(const QTableWidget);
2088 return d->tableModel()->horizontalHeaderItem(section: column);
2089}
2090
2091/*!
2092 Sets the horizontal header item for column \a column to \a item.
2093 If necessary, the column count is increased to fit the item.
2094 The previous header item (if there was one) is deleted.
2095*/
2096void QTableWidget::setHorizontalHeaderItem(int column, QTableWidgetItem *item)
2097{
2098 Q_D(QTableWidget);
2099 if (item) {
2100 item->view = this;
2101 d->tableModel()->setHorizontalHeaderItem(section: column, item);
2102 } else {
2103 delete takeHorizontalHeaderItem(column);
2104 }
2105}
2106
2107/*!
2108 \since 4.1
2109 Removes the horizontal header item at \a column from the header without deleting it.
2110*/
2111QTableWidgetItem *QTableWidget::takeHorizontalHeaderItem(int column)
2112{
2113 Q_D(QTableWidget);
2114 QTableWidgetItem *itm = d->tableModel()->takeHorizontalHeaderItem(section: column);
2115 if (itm)
2116 itm->view = nullptr;
2117 return itm;
2118}
2119
2120/*!
2121 Sets the vertical header labels using \a labels.
2122*/
2123void QTableWidget::setVerticalHeaderLabels(const QStringList &labels)
2124{
2125 Q_D(QTableWidget);
2126 QTableModel *model = d->tableModel();
2127 QTableWidgetItem *item = nullptr;
2128 for (int i = 0; i < model->rowCount() && i < labels.size(); ++i) {
2129 item = model->verticalHeaderItem(section: i);
2130 if (!item) {
2131 item = model->createItem();
2132 setVerticalHeaderItem(row: i, item);
2133 }
2134 item->setText(labels.at(i));
2135 }
2136}
2137
2138/*!
2139 Sets the horizontal header labels using \a labels.
2140*/
2141void QTableWidget::setHorizontalHeaderLabels(const QStringList &labels)
2142{
2143 Q_D(QTableWidget);
2144 QTableModel *model = d->tableModel();
2145 QTableWidgetItem *item = nullptr;
2146 for (int i = 0; i < model->columnCount() && i < labels.size(); ++i) {
2147 item = model->horizontalHeaderItem(section: i);
2148 if (!item) {
2149 item = model->createItem();
2150 setHorizontalHeaderItem(column: i, item);
2151 }
2152 item->setText(labels.at(i));
2153 }
2154}
2155
2156/*!
2157 Returns the row of the current item.
2158
2159 \sa currentColumn(), setCurrentCell()
2160*/
2161int QTableWidget::currentRow() const
2162{
2163 return currentIndex().row();
2164}
2165
2166/*!
2167 Returns the column of the current item.
2168
2169 \sa currentRow(), setCurrentCell()
2170*/
2171int QTableWidget::currentColumn() const
2172{
2173 return currentIndex().column();
2174}
2175
2176/*!
2177 Returns the current item.
2178
2179 \sa setCurrentItem()
2180*/
2181QTableWidgetItem *QTableWidget::currentItem() const
2182{
2183 Q_D(const QTableWidget);
2184 return d->tableModel()->item(index: currentIndex());
2185}
2186
2187/*!
2188 Sets the current item to \a item.
2189
2190 Unless the selection mode is \l{QAbstractItemView::}{NoSelection},
2191 the item is also selected.
2192
2193 \sa currentItem(), setCurrentCell()
2194*/
2195void QTableWidget::setCurrentItem(QTableWidgetItem *item)
2196{
2197 Q_D(QTableWidget);
2198 setCurrentIndex(d->tableModel()->index(item));
2199}
2200
2201/*!
2202 \since 4.4
2203
2204 Sets the current item to be \a item, using the given \a command.
2205
2206 \sa currentItem(), setCurrentCell()
2207*/
2208void QTableWidget::setCurrentItem(QTableWidgetItem *item, QItemSelectionModel::SelectionFlags command)
2209{
2210 Q_D(QTableWidget);
2211 d->selectionModel->setCurrentIndex(index: d->tableModel()->index(item), command);
2212}
2213
2214/*!
2215 \since 4.1
2216
2217 Sets the current cell to be the cell at position (\a row, \a
2218 column).
2219
2220 Depending on the current \l{QAbstractItemView::SelectionMode}{selection mode},
2221 the cell may also be selected.
2222
2223 \sa setCurrentItem(), currentRow(), currentColumn()
2224*/
2225void QTableWidget::setCurrentCell(int row, int column)
2226{
2227 setCurrentIndex(model()->index(row, column, parent: QModelIndex()));
2228}
2229
2230/*!
2231 \since 4.4
2232
2233 Sets the current cell to be the cell at position (\a row, \a
2234 column), using the given \a command.
2235
2236 \sa setCurrentItem(), currentRow(), currentColumn()
2237*/
2238void QTableWidget::setCurrentCell(int row, int column, QItemSelectionModel::SelectionFlags command)
2239{
2240 Q_D(QTableWidget);
2241 d->selectionModel->setCurrentIndex(index: model()->index(row, column, parent: QModelIndex()), command);
2242}
2243
2244/*!
2245 Sorts all the rows in the table widget based on \a column and \a order.
2246*/
2247void QTableWidget::sortItems(int column, Qt::SortOrder order)
2248{
2249 Q_D(QTableWidget);
2250 d->model->sort(column, order);
2251 horizontalHeader()->setSortIndicator(logicalIndex: column, order);
2252}
2253
2254/*!
2255 \internal
2256*/
2257void QTableWidget::setSortingEnabled(bool enable)
2258{
2259 QTableView::setSortingEnabled(enable);
2260}
2261
2262/*!
2263 \internal
2264*/
2265bool QTableWidget::isSortingEnabled() const
2266{
2267 return QTableView::isSortingEnabled();
2268}
2269
2270/*!
2271 Starts editing the \a item if it is editable.
2272*/
2273
2274void QTableWidget::editItem(QTableWidgetItem *item)
2275{
2276 Q_D(QTableWidget);
2277 if (!item)
2278 return;
2279 edit(index: d->tableModel()->index(item));
2280}
2281
2282/*!
2283 Opens an editor for the give \a item. The editor remains open after editing.
2284
2285 \sa closePersistentEditor(), isPersistentEditorOpen()
2286*/
2287void QTableWidget::openPersistentEditor(QTableWidgetItem *item)
2288{
2289 Q_D(QTableWidget);
2290 if (!item)
2291 return;
2292 QModelIndex index = d->tableModel()->index(item);
2293 QAbstractItemView::openPersistentEditor(index);
2294}
2295
2296/*!
2297 Closes the persistent editor for \a item.
2298
2299 \sa openPersistentEditor(), isPersistentEditorOpen()
2300*/
2301void QTableWidget::closePersistentEditor(QTableWidgetItem *item)
2302{
2303 Q_D(QTableWidget);
2304 if (!item)
2305 return;
2306 QModelIndex index = d->tableModel()->index(item);
2307 QAbstractItemView::closePersistentEditor(index);
2308}
2309
2310/*!
2311 \since 5.10
2312
2313 Returns whether a persistent editor is open for item \a item.
2314
2315 \sa openPersistentEditor(), closePersistentEditor()
2316*/
2317bool QTableWidget::isPersistentEditorOpen(QTableWidgetItem *item) const
2318{
2319 Q_D(const QTableWidget);
2320 const QModelIndex index = d->tableModel()->index(item);
2321 return QAbstractItemView::isPersistentEditorOpen(index);
2322}
2323
2324/*!
2325 \since 4.1
2326
2327 Returns the widget displayed in the cell in the given \a row and \a column.
2328
2329 \note The table takes ownership of the widget.
2330
2331 \sa setCellWidget()
2332*/
2333QWidget *QTableWidget::cellWidget(int row, int column) const
2334{
2335 QModelIndex index = model()->index(row, column, parent: QModelIndex());
2336 return QAbstractItemView::indexWidget(index);
2337}
2338
2339/*!
2340 \since 4.1
2341
2342 Sets the given \a widget to be displayed in the cell in the given \a row
2343 and \a column, passing the ownership of the widget to the table.
2344
2345 If cell widget A is replaced with cell widget B, cell widget A will be
2346 deleted. For example, in the code snippet below, the QLineEdit object will
2347 be deleted.
2348
2349 \snippet code/src_gui_itemviews_qtablewidget.cpp 0
2350
2351 \sa cellWidget()
2352*/
2353void QTableWidget::setCellWidget(int row, int column, QWidget *widget)
2354{
2355 QModelIndex index = model()->index(row, column, parent: QModelIndex());
2356 QAbstractItemView::setIndexWidget(index, widget);
2357}
2358
2359/*!
2360 Selects or deselects the \a range depending on \a select.
2361*/
2362void QTableWidget::setRangeSelected(const QTableWidgetSelectionRange &range, bool select)
2363{
2364 if (!model()->hasIndex(row: range.topRow(), column: range.leftColumn(), parent: rootIndex()) ||
2365 !model()->hasIndex(row: range.bottomRow(), column: range.rightColumn(), parent: rootIndex()))
2366 return;
2367
2368 QModelIndex topLeft = model()->index(row: range.topRow(), column: range.leftColumn(), parent: rootIndex());
2369 QModelIndex bottomRight = model()->index(row: range.bottomRow(), column: range.rightColumn(), parent: rootIndex());
2370
2371 selectionModel()->select(selection: QItemSelection(topLeft, bottomRight),
2372 command: select ? QItemSelectionModel::Select : QItemSelectionModel::Deselect);
2373}
2374
2375/*!
2376 Returns a list of all selected ranges.
2377
2378 \sa QTableWidgetSelectionRange
2379*/
2380
2381QList<QTableWidgetSelectionRange> QTableWidget::selectedRanges() const
2382{
2383 const QList<QItemSelectionRange> ranges = selectionModel()->selection();
2384 QList<QTableWidgetSelectionRange> result;
2385 const int rangesCount = ranges.size();
2386 result.reserve(asize: rangesCount);
2387 for (int i = 0; i < rangesCount; ++i)
2388 result.append(t: {ranges.at(i).top(),
2389 ranges.at(i).left(),
2390 ranges.at(i).bottom(),
2391 ranges.at(i).right()});
2392 return result;
2393}
2394
2395/*!
2396 Returns a list of all selected items.
2397
2398 This function returns a list of pointers to the contents of the
2399 selected cells. Use the selectedIndexes() function to retrieve the
2400 complete selection \e including empty cells.
2401
2402 \sa selectedIndexes()
2403*/
2404
2405QList<QTableWidgetItem*> QTableWidget::selectedItems() const
2406{
2407 Q_D(const QTableWidget);
2408 const QModelIndexList indexes = selectionModel()->selectedIndexes();
2409 QList<QTableWidgetItem*> items;
2410 for (const auto &index : indexes) {
2411 if (isIndexHidden(index))
2412 continue;
2413 QTableWidgetItem *item = d->tableModel()->item(index);
2414 if (item)
2415 items.append(t: item);
2416 }
2417 return items;
2418}
2419
2420/*!
2421 Finds items that matches the \a text using the given \a flags.
2422*/
2423
2424QList<QTableWidgetItem*> QTableWidget::findItems(const QString &text, Qt::MatchFlags flags) const
2425{
2426 Q_D(const QTableWidget);
2427 QModelIndexList indexes;
2428 for (int column = 0; column < columnCount(); ++column)
2429 indexes += d->model->match(start: model()->index(row: 0, column, parent: QModelIndex()),
2430 role: Qt::DisplayRole, value: text, hits: -1, flags);
2431 QList<QTableWidgetItem*> items;
2432 const int indexCount = indexes.size();
2433 items.reserve(asize: indexCount);
2434 for (int i = 0; i < indexCount; ++i)
2435 items.append(t: d->tableModel()->item(index: indexes.at(i)));
2436 return items;
2437}
2438
2439/*!
2440 Returns the visual row of the given \a logicalRow.
2441*/
2442
2443int QTableWidget::visualRow(int logicalRow) const
2444{
2445 return verticalHeader()->visualIndex(logicalIndex: logicalRow);
2446}
2447
2448/*!
2449 Returns the visual column of the given \a logicalColumn.
2450*/
2451
2452int QTableWidget::visualColumn(int logicalColumn) const
2453{
2454 return horizontalHeader()->visualIndex(logicalIndex: logicalColumn);
2455}
2456
2457/*!
2458 \fn QTableWidgetItem *QTableWidget::itemAt(const QPoint &point) const
2459
2460 Returns a pointer to the item at the given \a point, or returns \nullptr if
2461 \a point is not covered by an item in the table widget.
2462
2463 \sa item()
2464*/
2465
2466QTableWidgetItem *QTableWidget::itemAt(const QPoint &p) const
2467{
2468 Q_D(const QTableWidget);
2469 return d->tableModel()->item(index: indexAt(p));
2470}
2471
2472/*!
2473 Returns the rectangle on the viewport occupied by the item at \a item.
2474*/
2475QRect QTableWidget::visualItemRect(const QTableWidgetItem *item) const
2476{
2477 Q_D(const QTableWidget);
2478 if (!item)
2479 return QRect();
2480 QModelIndex index = d->tableModel()->index(item: const_cast<QTableWidgetItem*>(item));
2481 Q_ASSERT(index.isValid());
2482 return visualRect(index);
2483}
2484
2485/*!
2486 Scrolls the view if necessary to ensure that the \a item is visible.
2487 The \a hint parameter specifies more precisely where the
2488 \a item should be located after the operation.
2489*/
2490
2491void QTableWidget::scrollToItem(const QTableWidgetItem *item, QAbstractItemView::ScrollHint hint)
2492{
2493 Q_D(QTableWidget);
2494 if (!item)
2495 return;
2496 QModelIndex index = d->tableModel()->index(item: const_cast<QTableWidgetItem*>(item));
2497 Q_ASSERT(index.isValid());
2498 QTableView::scrollTo(index, hint);
2499}
2500
2501/*!
2502 Returns the item prototype used by the table.
2503
2504 \sa setItemPrototype()
2505*/
2506const QTableWidgetItem *QTableWidget::itemPrototype() const
2507{
2508 Q_D(const QTableWidget);
2509 return d->tableModel()->itemPrototype();
2510}
2511
2512/*!
2513 Sets the item prototype for the table to the specified \a item.
2514
2515 The table widget will use the item prototype clone function when it needs
2516 to create a new table item. For example when the user is editing
2517 in an empty cell. This is useful when you have a QTableWidgetItem
2518 subclass and want to make sure that QTableWidget creates instances of
2519 your subclass.
2520
2521 The table takes ownership of the prototype.
2522
2523 \sa itemPrototype()
2524*/
2525void QTableWidget::setItemPrototype(const QTableWidgetItem *item)
2526{
2527 Q_D(QTableWidget);
2528 d->tableModel()->setItemPrototype(item);
2529}
2530
2531/*!
2532 Inserts an empty row into the table at \a row.
2533*/
2534void QTableWidget::insertRow(int row)
2535{
2536 Q_D(QTableWidget);
2537 d->tableModel()->insertRows(row);
2538}
2539
2540/*!
2541 Inserts an empty column into the table at \a column.
2542*/
2543void QTableWidget::insertColumn(int column)
2544{
2545 Q_D(QTableWidget);
2546 d->tableModel()->insertColumns(column);
2547}
2548
2549/*!
2550 Removes the row \a row and all its items from the table.
2551*/
2552void QTableWidget::removeRow(int row)
2553{
2554 Q_D(QTableWidget);
2555 d->tableModel()->removeRows(row);
2556}
2557
2558/*!
2559 Removes the column \a column and all its items from the table.
2560*/
2561void QTableWidget::removeColumn(int column)
2562{
2563 Q_D(QTableWidget);
2564 d->tableModel()->removeColumns(column);
2565}
2566
2567/*!
2568 Removes all items in the view.
2569 This will also remove all selections and headers.
2570 If you don't want to remove the headers, use
2571 QTableWidget::clearContents().
2572 The table dimensions stay the same.
2573*/
2574
2575void QTableWidget::clear()
2576{
2577 Q_D(QTableWidget);
2578 selectionModel()->clear();
2579 d->tableModel()->clear();
2580}
2581
2582/*!
2583 \since 4.2
2584
2585 Removes all items not in the headers from the view.
2586 This will also remove all selections.
2587 The table dimensions stay the same.
2588*/
2589void QTableWidget::clearContents()
2590{
2591 Q_D(QTableWidget);
2592 selectionModel()->clear();
2593 d->tableModel()->clearContents();
2594}
2595
2596/*!
2597 Returns a list of MIME types that can be used to describe a list of
2598 tablewidget items.
2599
2600 \sa mimeData()
2601*/
2602QStringList QTableWidget::mimeTypes() const
2603{
2604 return d_func()->tableModel()->QAbstractTableModel::mimeTypes();
2605}
2606
2607/*!
2608 Returns an object that contains a serialized description of the specified
2609 \a items. The format used to describe the items is obtained from the
2610 mimeTypes() function.
2611
2612 If the list of items is empty, \nullptr is returned rather than a
2613 serialized empty list.
2614*/
2615QMimeData *QTableWidget::mimeData(const QList<QTableWidgetItem *> &items) const
2616{
2617 Q_D(const QTableWidget);
2618
2619 QModelIndexList &cachedIndexes = d->tableModel()->cachedIndexes;
2620
2621 // if non empty, it's called from the model's own mimeData
2622 if (cachedIndexes.isEmpty()) {
2623 cachedIndexes.reserve(asize: items.size());
2624 for (QTableWidgetItem *item : items)
2625 cachedIndexes << indexFromItem(item);
2626
2627 QMimeData *result = d->tableModel()->internalMimeData();
2628
2629 cachedIndexes.clear();
2630 return result;
2631 }
2632
2633 return d->tableModel()->internalMimeData();
2634}
2635
2636/*!
2637 Handles the \a data supplied by a drag and drop operation that ended with
2638 the given \a action in the given \a row and \a column.
2639 Returns \c true if the data and action can be handled by the model;
2640 otherwise returns \c false.
2641
2642 \sa supportedDropActions()
2643*/
2644bool QTableWidget::dropMimeData(int row, int column, const QMimeData *data, Qt::DropAction action)
2645{
2646 QModelIndex idx;
2647#if QT_CONFIG(draganddrop)
2648 if (dropIndicatorPosition() == QAbstractItemView::OnItem) {
2649 // QAbstractTableModel::dropMimeData will overwrite on the index if row == -1 and column == -1
2650 idx = model()->index(row, column);
2651 row = -1;
2652 column = -1;
2653 }
2654#endif
2655 return d_func()->tableModel()->QAbstractTableModel::dropMimeData(data, action , row, column, parent: idx);
2656}
2657
2658/*!
2659 Returns the drop actions supported by this view.
2660
2661 \sa Qt::DropActions
2662*/
2663Qt::DropActions QTableWidget::supportedDropActions() const
2664{
2665 return d_func()->tableModel()->QAbstractTableModel::supportedDropActions() | Qt::MoveAction;
2666}
2667
2668/*!
2669 Returns a list of pointers to the items contained in the \a data object.
2670 If the object was not created by a QTreeWidget in the same process, the list
2671 is empty.
2672
2673*/
2674QList<QTableWidgetItem*> QTableWidget::items(const QMimeData *data) const
2675{
2676 const QTableWidgetMimeData *twd = qobject_cast<const QTableWidgetMimeData*>(object: data);
2677 if (twd)
2678 return twd->items;
2679 return QList<QTableWidgetItem*>();
2680}
2681
2682/*!
2683 Returns the QModelIndex associated with the given \a item.
2684
2685 \note In Qt versions prior to 5.10, this function took a non-\c{const} \a item.
2686*/
2687
2688QModelIndex QTableWidget::indexFromItem(const QTableWidgetItem *item) const
2689{
2690 Q_D(const QTableWidget);
2691 return d->tableModel()->index(item);
2692}
2693
2694/*!
2695 Returns a pointer to the QTableWidgetItem associated with the given \a index.
2696*/
2697
2698QTableWidgetItem *QTableWidget::itemFromIndex(const QModelIndex &index) const
2699{
2700 Q_D(const QTableWidget);
2701 return d->tableModel()->item(index);
2702}
2703
2704/*!
2705 \internal
2706*/
2707void QTableWidget::setModel(QAbstractItemModel * /*model*/)
2708{
2709 Q_ASSERT(!"QTableWidget::setModel() - Changing the model of the QTableWidget is not allowed.");
2710}
2711
2712/*! \reimp */
2713bool QTableWidget::event(QEvent *e)
2714{
2715 return QTableView::event(event: e);
2716}
2717
2718#if QT_CONFIG(draganddrop)
2719/*! \reimp */
2720void QTableWidget::dropEvent(QDropEvent *event) {
2721 Q_D(QTableWidget);
2722 if (event->source() == this && (event->dropAction() == Qt::MoveAction ||
2723 dragDropMode() == QAbstractItemView::InternalMove)) {
2724 QModelIndex topIndex;
2725 int col = -1;
2726 int row = -1;
2727 // check whether a subclass has already accepted the event, ie. moved the data
2728 if (!event->isAccepted() && d->dropOn(event, row: &row, col: &col, index: &topIndex) && row == -1 && col == -1) {
2729 // Drop onto item
2730 const QModelIndexList indexes = selectedIndexes();
2731 int top = INT_MAX;
2732 int left = INT_MAX;
2733 for (const auto &index : indexes) {
2734 top = qMin(a: index.row(), b: top);
2735 left = qMin(a: index.column(), b: left);
2736 }
2737 QList<QTableWidgetItem *> taken;
2738 const int indexesCount = indexes.size();
2739 taken.reserve(asize: indexesCount);
2740 for (const auto &index : indexes)
2741 taken.append(t: takeItem(row: index.row(), column: index.column()));
2742
2743 for (const auto &index : indexes) {
2744 int r = index.row() - top + topIndex.row();
2745 int c = index.column() - left + topIndex.column();
2746 setItem(row: r, column: c, item: taken.takeFirst());
2747 }
2748
2749 event->accept();
2750 }
2751 // either we or a subclass accepted the drop event, so assume that the data was
2752 // moved and that QAbstractItemView shouldn't remove the source when QDrag::exec returns
2753 if (event->isAccepted())
2754 d->dropEventMoved = true;
2755 }
2756
2757 QTableView::dropEvent(event);
2758}
2759#endif
2760
2761QT_END_NAMESPACE
2762
2763#include "moc_qtablewidget.cpp"
2764#include "moc_qtablewidget_p.cpp"
2765

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

source code of qtbase/src/widgets/itemviews/qtablewidget.cpp