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 = this->view();
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 = this->view();
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 = this->view();
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 = this->view();
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 = this->view();
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<std::pair<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.emplace_back(args&: itm, args&: 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<std::pair<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.emplace_back(args&: itm, args&: 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 std::pair<QTableWidgetItem*,int> &left,
690 const std::pair<QTableWidgetItem*,int> &right)
691{
692 return *(left.first) < *(right.first);
693}
694
695bool QTableModel::itemGreaterThan(const std::pair<QTableWidgetItem*,int> &left,
696 const std::pair<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 auto v = view();
821 if (v)
822 return v->mimeTypes();
823 return {};
824}
825
826QMimeData *QTableModel::internalMimeData() const
827{
828 return QAbstractTableModel::mimeData(indexes: cachedIndexes);
829}
830
831QMimeData *QTableModel::mimeData(const QModelIndexList &indexes) const
832{
833 QList<QTableWidgetItem*> items;
834 const int indexesCount = indexes.size();
835 items.reserve(asize: indexesCount);
836 for (int i = 0; i < indexesCount; ++i)
837 items << item(index: indexes.at(i));
838 const QTableWidget *view = this->view();
839
840 // cachedIndexes is a little hack to avoid copying from QModelIndexList to
841 // QList<QTreeWidgetItem*> and back again in the view
842 cachedIndexes = indexes;
843 QMimeData *mimeData = (view ? view->mimeData(items) : nullptr);
844 cachedIndexes.clear();
845 return mimeData;
846}
847
848bool QTableModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
849 int row , int column, const QModelIndex &index)
850{
851 if (index.isValid()) {
852 row = index.row();
853 column = index.column();
854 } else if (row == -1 || column == -1) { // The user dropped outside the table.
855 row = rowCount();
856 column = 0;
857 } else { // The user dropped between two rows
858 // This means inserting a row, which only makes sense at column 0
859 column = 0;
860 }
861
862 QTableWidget *view = this->view();
863 return (view ? view->dropMimeData(row, column, data, action) : false);
864}
865
866Qt::DropActions QTableModel::supportedDropActions() const
867{
868 const QTableWidget *view = this->view();
869 return (view ? view->supportedDropActions() : Qt::DropActions(Qt::IgnoreAction));
870}
871
872Qt::DropActions QTableModel::supportedDragActions() const
873{
874#if QT_CONFIG(draganddrop)
875 const QTableWidget *view = this->view();
876 return (view ? view->supportedDragActions() : Qt::DropActions(Qt::IgnoreAction));
877#else
878 return Qt::DropActions(Qt::IgnoreAction);
879#endif
880}
881
882/*!
883 \class QTableWidgetSelectionRange
884
885 \brief The QTableWidgetSelectionRange class provides a way to interact with
886 selection in a model without using model indexes and a selection model.
887
888 \ingroup model-view
889 \inmodule QtWidgets
890
891 The QTableWidgetSelectionRange class stores the top left and bottom
892 right rows and columns of a selection range in a table. The
893 selections in the table may consist of several selection ranges.
894
895 \note If the item within the selection range is marked as not selectable,
896 e.g., \c{itemFlags() & Qt::ItemIsSelectable == 0} then it will not appear
897 in the selection range.
898
899 \sa QTableWidget
900*/
901
902/*!
903 \fn QTableWidgetSelectionRange::QTableWidgetSelectionRange()
904
905 Constructs an empty table selection range, i.e. a range
906 whose rowCount() and columnCount() are 0.
907
908 \sa topRow(), leftColumn(), bottomRow(), rightColumn()
909*/
910
911/*!
912 \fn QTableWidgetSelectionRange::QTableWidgetSelectionRange(int top, int left, int bottom, int right)
913
914 Constructs the table selection range from the given \a top, \a
915 left, \a bottom and \a right table rows and columns.
916
917 \sa topRow(), leftColumn(), bottomRow(), rightColumn()
918*/
919
920/*!
921 \fn bool QTableWidgetSelectionRange::operator==(const QTableWidgetSelectionRange &lhs, const QTableWidgetSelectionRange &rhs)
922 \since 6.3
923
924 Returns true if \a lhs and \a rhs are equal, otherwise returns false.
925*/
926
927/*!
928 \fn bool QTableWidgetSelectionRange::operator!=(const QTableWidgetSelectionRange &lhs, const QTableWidgetSelectionRange &rhs)
929 \since 6.3
930
931 Returns true if \a lhs and \a rhs are not equal, otherwise returns false.
932*/
933
934/*!
935 \fn int QTableWidgetSelectionRange::topRow() const
936
937 Returns the top row of the range.
938
939 \sa bottomRow(), leftColumn(), rowCount()
940*/
941
942/*!
943 \fn int QTableWidgetSelectionRange::bottomRow() const
944
945 Returns the bottom row of the range.
946
947 \sa topRow(), rightColumn(), rowCount()
948*/
949
950/*!
951 \fn int QTableWidgetSelectionRange::leftColumn() const
952
953 Returns the left column of the range.
954
955 \sa rightColumn(), topRow(), columnCount()
956*/
957
958/*!
959 \fn int QTableWidgetSelectionRange::rightColumn() const
960
961 Returns the right column of the range.
962
963 \sa leftColumn(), bottomRow(), columnCount()
964*/
965
966/*!
967 \fn int QTableWidgetSelectionRange::rowCount() const
968
969 Returns the number of rows in the range.
970
971 This is equivalent to bottomRow() - topRow() + 1.
972
973 \sa columnCount(), topRow(), bottomRow()
974*/
975
976/*!
977 \fn int QTableWidgetSelectionRange::columnCount() const
978
979 Returns the number of columns in the range.
980
981 This is equivalent to rightColumn() - leftColumn() + 1.
982
983 \sa rowCount(), leftColumn(), rightColumn()
984*/
985
986/*!
987 \class QTableWidgetItem
988 \brief The QTableWidgetItem class provides an item for use with the
989 QTableWidget class.
990
991 \ingroup model-view
992 \inmodule QtWidgets
993
994 Table items are used to hold pieces of information for table widgets.
995 Items usually contain text, icons, or checkboxes
996
997 The QTableWidgetItem class is a convenience class that replaces the
998 \c QTableItem class in Qt 3. It provides an item for use with
999 the QTableWidget class.
1000
1001 Top-level items are constructed without a parent then inserted at the
1002 position specified by a pair of row and column numbers:
1003
1004 \snippet qtablewidget-using/mainwindow.cpp 3
1005
1006 Each item can have its own background brush which is set with
1007 the setBackground() function. The current background brush can be
1008 found with background().
1009 The text label for each item can be rendered with its own font and brush.
1010 These are specified with the setFont() and setForeground() functions,
1011 and read with font() and foreground().
1012
1013 By default, items are enabled, editable, selectable, checkable, and can be
1014 used both as the source of a drag and drop operation and as a drop target.
1015 Each item's flags can be changed by calling setFlags() with the appropriate
1016 value (see \l{Qt::ItemFlags}). Checkable items can be checked and unchecked
1017 with the setCheckState() function. The corresponding checkState() function
1018 indicates whether the item is currently checked.
1019
1020 \section1 Subclassing
1021
1022 When subclassing QTableWidgetItem to provide custom items, it is possible to
1023 define new types for them so that they can be distinguished from standard
1024 items. The constructors for subclasses that require this feature need to
1025 call the base class constructor with a new type value equal to or greater
1026 than \l UserType.
1027
1028 \sa QTableWidget, {Model/View Programming}, QListWidgetItem, QTreeWidgetItem
1029*/
1030
1031/*!
1032 \fn int QTableWidgetItem::row() const
1033
1034 Returns the row of the item in the table.
1035 If the item is not in a table, this function will return -1.
1036
1037 \sa column()
1038*/
1039
1040/*!
1041 \fn int QTableWidgetItem::column() const
1042
1043 Returns the column of the item in the table.
1044 If the item is not in a table, this function will return -1.
1045
1046 \sa row()
1047*/
1048
1049/*!
1050 \fn QSize QTableWidgetItem::sizeHint() const
1051
1052 Returns the size hint set for the table item.
1053*/
1054
1055/*!
1056 \fn void QTableWidgetItem::setSizeHint(const QSize &size)
1057
1058 Sets the size hint for the table item to be \a size.
1059 If no size hint is set or \a size is invalid, the item
1060 delegate will compute the size hint based on the item data.
1061*/
1062
1063/*!
1064 \fn Qt::CheckState QTableWidgetItem::checkState() const
1065
1066 Returns the checked state of the table item.
1067
1068 \sa flags()
1069*/
1070
1071/*!
1072 \fn void QTableWidgetItem::setCheckState(Qt::CheckState state)
1073
1074 Sets the check state of the table item to be \a state.
1075*/
1076
1077/*!
1078 \fn QTableWidget *QTableWidgetItem::tableWidget() const
1079
1080 Returns the table widget that contains the item.
1081*/
1082
1083/*!
1084 \fn bool QTableWidgetItem::isSelected() const
1085
1086 Returns \c true if the item is selected, otherwise returns \c false.
1087
1088 \sa setSelected()
1089*/
1090bool QTableWidgetItem::isSelected() const
1091{
1092 if (!view || !view->selectionModel())
1093 return false;
1094 const QTableModel *model = qobject_cast<const QTableModel*>(object: view->model());
1095 if (!model)
1096 return false;
1097 const QModelIndex index = model->index(item: this);
1098 return view->selectionModel()->isSelected(index);
1099}
1100
1101/*!
1102 \fn void QTableWidgetItem::setSelected(bool select)
1103
1104 Sets the selected state of the item to \a select.
1105
1106 \sa isSelected()
1107*/
1108void QTableWidgetItem::setSelected(bool select)
1109{
1110 if (!view || !view->selectionModel())
1111 return;
1112 const QTableModel *model = qobject_cast<const QTableModel*>(object: view->model());
1113 if (!model)
1114 return;
1115 const QModelIndex index = model->index(item: this);
1116 view->selectionModel()->select(index, command: select ? QItemSelectionModel::Select : QItemSelectionModel::Deselect);
1117}
1118
1119/*!
1120 \fn Qt::ItemFlags QTableWidgetItem::flags() const
1121
1122 Returns the flags used to describe the item. These determine whether
1123 the item can be checked, edited, and selected.
1124
1125 \sa setFlags()
1126*/
1127
1128/*!
1129 \fn void QTableWidgetItem::setFlags(Qt::ItemFlags flags)
1130
1131 Sets the flags for the item to the given \a flags. These determine whether
1132 the item can be selected or modified.
1133
1134 \sa flags()
1135*/
1136void QTableWidgetItem::setFlags(Qt::ItemFlags aflags)
1137{
1138 itemFlags = aflags;
1139 if (QTableModel *model = tableModel())
1140 model->itemChanged(item: this);
1141}
1142
1143
1144/*!
1145 \fn QString QTableWidgetItem::text() const
1146
1147 Returns the item's text.
1148
1149 \sa setText()
1150*/
1151
1152/*!
1153 \fn void QTableWidgetItem::setText(const QString &text)
1154
1155 Sets the item's text to the \a text specified.
1156
1157 \sa text(), setFont(), setForeground()
1158*/
1159
1160/*!
1161 \fn QIcon QTableWidgetItem::icon() const
1162
1163 Returns the item's icon.
1164
1165 \sa setIcon(), {QAbstractItemView::iconSize}{iconSize}
1166*/
1167
1168/*!
1169 \fn void QTableWidgetItem::setIcon(const QIcon &icon)
1170
1171 Sets the item's icon to the \a icon specified.
1172
1173 \sa icon(), setText(), {QAbstractItemView::iconSize}{iconSize}
1174*/
1175
1176/*!
1177 \fn QString QTableWidgetItem::statusTip() const
1178
1179 Returns the item's status tip.
1180
1181 \sa setStatusTip()
1182*/
1183
1184/*!
1185 \fn void QTableWidgetItem::setStatusTip(const QString &statusTip)
1186
1187 Sets the status tip for the table item to the text specified by
1188 \a statusTip. QTableWidget mouse tracking needs to be enabled for this
1189 feature to work.
1190
1191 \sa statusTip(), setToolTip(), setWhatsThis()
1192*/
1193
1194/*!
1195 \fn QString QTableWidgetItem::toolTip() const
1196
1197 Returns the item's tooltip.
1198
1199 \sa setToolTip()
1200*/
1201
1202/*!
1203 \fn void QTableWidgetItem::setToolTip(const QString &toolTip)
1204
1205 Sets the item's tooltip to the string specified by \a toolTip.
1206
1207 \sa toolTip(), setStatusTip(), setWhatsThis()
1208*/
1209
1210/*!
1211 \fn QString QTableWidgetItem::whatsThis() const
1212
1213 Returns the item's "What's This?" help.
1214
1215 \sa setWhatsThis()
1216*/
1217
1218/*!
1219 \fn void QTableWidgetItem::setWhatsThis(const QString &whatsThis)
1220
1221 Sets the item's "What's This?" help to the string specified by \a whatsThis.
1222
1223 \sa whatsThis(), setStatusTip(), setToolTip()
1224*/
1225
1226/*!
1227 \fn QFont QTableWidgetItem::font() const
1228
1229 Returns the font used to render the item's text.
1230
1231 \sa setFont()
1232*/
1233
1234/*!
1235 \fn void QTableWidgetItem::setFont(const QFont &font)
1236
1237 Sets the font used to display the item's text to the given \a font.
1238
1239 \sa font(), setText(), setForeground()
1240*/
1241
1242/*!
1243 \fn QBrush QTableWidgetItem::background() const
1244
1245 Returns the brush used to render the item's background.
1246
1247 \sa foreground()
1248*/
1249
1250/*!
1251 \fn void QTableWidgetItem::setBackground(const QBrush &brush)
1252
1253 Sets the item's background brush to the specified \a brush.
1254 Setting a default-constructed brush will let the view use the
1255 default color from the style.
1256
1257 \sa setForeground()
1258*/
1259
1260/*!
1261 \fn QBrush QTableWidgetItem::foreground() const
1262
1263 Returns the brush used to render the item's foreground (e.g. text).
1264
1265 \sa background()
1266*/
1267
1268/*!
1269 \fn void QTableWidgetItem::setForeground(const QBrush &brush)
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 Constructs a copy of \a other. Note that type() and tableWidget()
1516 are not copied.
1517
1518 This function is useful when reimplementing clone().
1519
1520 \sa data(), flags()
1521*/
1522QTableWidgetItem::QTableWidgetItem(const QTableWidgetItem &other)
1523 : rtti(Type), values(other.values), view(nullptr),
1524 d(new QTableWidgetItemPrivate(this)),
1525 itemFlags(other.itemFlags)
1526{
1527}
1528
1529/*!
1530 Assigns \a other's data and flags to this item. Note that type()
1531 and tableWidget() are not copied.
1532
1533 This function is useful when reimplementing clone().
1534
1535 \sa data(), flags()
1536*/
1537QTableWidgetItem &QTableWidgetItem::operator=(const QTableWidgetItem &other)
1538{
1539 values = other.values;
1540 itemFlags = other.itemFlags;
1541 return *this;
1542}
1543
1544/*!
1545 \class QTableWidget
1546 \brief The QTableWidget class provides an item-based table view with a default model.
1547
1548 \ingroup model-view
1549 \inmodule QtWidgets
1550
1551 \image fusion-tableview.png
1552
1553 Table widgets provide standard table display facilities for applications.
1554 The items in a QTableWidget are provided by QTableWidgetItem.
1555
1556 If you want a table that uses your own data model you should
1557 use QTableView rather than this class.
1558
1559 Table widgets can be constructed with the required numbers of rows and
1560 columns:
1561
1562 \snippet qtablewidget-using/mainwindow.cpp 0
1563
1564 Alternatively, tables can be constructed without a given size and resized
1565 later:
1566
1567 \snippet qtablewidget-resizing/mainwindow.cpp 0
1568 \snippet qtablewidget-resizing/mainwindow.cpp 1
1569
1570 Items are created outside the table (with no parent widget) and inserted
1571 into the table with setItem():
1572
1573 \snippet qtablewidget-resizing/mainwindow.cpp 2
1574
1575 If you want to enable sorting in your table widget, do so after you
1576 have populated it with items, otherwise sorting may interfere with
1577 the insertion order (see setItem() for details).
1578
1579 Tables can be given both horizontal and vertical headers. The simplest way
1580 to create the headers is to supply a list of strings to the
1581 setHorizontalHeaderLabels() and setVerticalHeaderLabels() functions. These
1582 will provide simple textual headers for the table's columns and rows.
1583 More sophisticated headers can be created from existing table items
1584 that are usually constructed outside the table. For example, we can
1585 construct a table item with an icon and aligned text, and use it as the
1586 header for a particular column:
1587
1588 \snippet qtablewidget-using/mainwindow.cpp 2
1589
1590 The number of rows in the table can be found with rowCount(), and the
1591 number of columns with columnCount(). The table can be cleared with the
1592 clear() function.
1593
1594 \sa QTableWidgetItem, QTableView, {Model/View Programming}
1595*/
1596
1597/*!
1598 \property QTableWidget::rowCount
1599 \brief the number of rows in the table
1600
1601 By default, for a table constructed without row and column counts,
1602 this property contains a value of 0.
1603*/
1604
1605/*!
1606 \property QTableWidget::columnCount
1607 \brief the number of columns in the table
1608
1609 By default, for a table constructed without row and column counts,
1610 this property contains a value of 0.
1611*/
1612
1613void QTableWidgetPrivate::setup()
1614{
1615 Q_Q(QTableWidget);
1616 connections = {
1617 // view signals
1618 QObjectPrivate::connect(sender: q, signal: &QTableWidget::pressed,
1619 receiverPrivate: this, slot: &QTableWidgetPrivate::emitItemPressed),
1620 QObjectPrivate::connect(sender: q, signal: &QTableWidget::clicked,
1621 receiverPrivate: this, slot: &QTableWidgetPrivate::emitItemClicked),
1622 QObjectPrivate::connect(sender: q, signal: &QTableWidget::doubleClicked,
1623 receiverPrivate: this, slot: &QTableWidgetPrivate::emitItemDoubleClicked),
1624 QObjectPrivate::connect(sender: q, signal: &QTableWidget::activated,
1625 receiverPrivate: this, slot: &QTableWidgetPrivate::emitItemActivated),
1626 QObjectPrivate::connect(sender: q, signal: &QTableWidget::entered,
1627 receiverPrivate: this, slot: &QTableWidgetPrivate::emitItemEntered),
1628 // model signals
1629 QObjectPrivate::connect(sender: model, signal: &QAbstractItemModel::dataChanged,
1630 receiverPrivate: this, slot: &QTableWidgetPrivate::emitItemChanged),
1631 // selection signals
1632 QObjectPrivate::connect(sender: q->selectionModel(), signal: &QItemSelectionModel::currentChanged,
1633 receiverPrivate: this, slot: &QTableWidgetPrivate::emitCurrentItemChanged),
1634 QObject::connect(sender: q->selectionModel(), signal: &QItemSelectionModel::selectionChanged,
1635 context: q, slot: &QTableWidget::itemSelectionChanged),
1636 // sorting
1637 QObjectPrivate::connect(sender: model, signal: &QAbstractItemModel::dataChanged,
1638 receiverPrivate: this, slot: &QTableWidgetPrivate::dataChanged),
1639 QObjectPrivate::connect(sender: model, signal: &QAbstractItemModel::columnsRemoved,
1640 receiverPrivate: this, slot: &QTableWidgetPrivate::sort)
1641 };
1642}
1643
1644void QTableWidgetPrivate::clearConnections()
1645{
1646 for (const QMetaObject::Connection &connection : connections)
1647 QObject::disconnect(connection);
1648}
1649
1650void QTableWidgetPrivate::emitItemPressed(const QModelIndex &index)
1651{
1652 Q_Q(QTableWidget);
1653 if (QTableWidgetItem *item = tableModel()->item(index))
1654 emit q->itemPressed(item);
1655 emit q->cellPressed(row: index.row(), column: index.column());
1656}
1657
1658void QTableWidgetPrivate::emitItemClicked(const QModelIndex &index)
1659{
1660 Q_Q(QTableWidget);
1661 if (QTableWidgetItem *item = tableModel()->item(index))
1662 emit q->itemClicked(item);
1663 emit q->cellClicked(row: index.row(), column: index.column());
1664}
1665
1666void QTableWidgetPrivate::emitItemDoubleClicked(const QModelIndex &index)
1667{
1668 Q_Q(QTableWidget);
1669 if (QTableWidgetItem *item = tableModel()->item(index))
1670 emit q->itemDoubleClicked(item);
1671 emit q->cellDoubleClicked(row: index.row(), column: index.column());
1672}
1673
1674void QTableWidgetPrivate::emitItemActivated(const QModelIndex &index)
1675{
1676 Q_Q(QTableWidget);
1677 if (QTableWidgetItem *item = tableModel()->item(index))
1678 emit q->itemActivated(item);
1679 emit q->cellActivated(row: index.row(), column: index.column());
1680}
1681
1682void QTableWidgetPrivate::emitItemEntered(const QModelIndex &index)
1683{
1684 Q_Q(QTableWidget);
1685 if (QTableWidgetItem *item = tableModel()->item(index))
1686 emit q->itemEntered(item);
1687 emit q->cellEntered(row: index.row(), column: index.column());
1688}
1689
1690void QTableWidgetPrivate::emitItemChanged(const QModelIndex &index)
1691{
1692 Q_Q(QTableWidget);
1693 if (QTableWidgetItem *item = tableModel()->item(index))
1694 emit q->itemChanged(item);
1695 emit q->cellChanged(row: index.row(), column: index.column());
1696}
1697
1698void QTableWidgetPrivate::emitCurrentItemChanged(const QModelIndex &current,
1699 const QModelIndex &previous)
1700{
1701 Q_Q(QTableWidget);
1702 QTableWidgetItem *currentItem = tableModel()->item(index: current);
1703 QTableWidgetItem *previousItem = tableModel()->item(index: previous);
1704 if (currentItem || previousItem)
1705 emit q->currentItemChanged(current: currentItem, previous: previousItem);
1706 emit q->currentCellChanged(currentRow: current.row(), currentColumn: current.column(), previousRow: previous.row(), previousColumn: previous.column());
1707}
1708
1709void QTableWidgetPrivate::sort()
1710{
1711 if (sortingEnabled) {
1712 int column = horizontalHeader->sortIndicatorSection();
1713 Qt::SortOrder order = horizontalHeader->sortIndicatorOrder();
1714 model->sort(column, order);
1715 }
1716}
1717
1718void QTableWidgetPrivate::dataChanged(const QModelIndex &topLeft,
1719 const QModelIndex &bottomRight)
1720{
1721 if (sortingEnabled && topLeft.isValid() && bottomRight.isValid()) {
1722 int column = horizontalHeader->sortIndicatorSection();
1723 if (column >= topLeft.column() && column <= bottomRight.column()) {
1724 Qt::SortOrder order = horizontalHeader->sortIndicatorOrder();
1725 tableModel()->ensureSorted(column, order, start: topLeft.row(), end: bottomRight.row());
1726 }
1727 }
1728}
1729
1730/*!
1731 \fn void QTableWidget::itemPressed(QTableWidgetItem *item)
1732
1733 This signal is emitted whenever an item in the table is pressed.
1734 The \a item specified is the item that was pressed.
1735*/
1736
1737/*!
1738 \fn void QTableWidget::itemClicked(QTableWidgetItem *item)
1739
1740 This signal is emitted whenever an item in the table is clicked.
1741 The \a item specified is the item that was clicked.
1742*/
1743
1744/*!
1745 \fn void QTableWidget::itemDoubleClicked(QTableWidgetItem *item)
1746
1747 This signal is emitted whenever an item in the table is double
1748 clicked. The \a item specified is the item that was double clicked.
1749*/
1750
1751/*!
1752 \fn void QTableWidget::itemActivated(QTableWidgetItem *item)
1753
1754 This signal is emitted when the specified \a item has been activated
1755*/
1756
1757/*!
1758 \fn void QTableWidget::itemEntered(QTableWidgetItem *item)
1759
1760 This signal is emitted when the mouse cursor enters an item. The
1761 \a item is the item entered.
1762
1763 This signal is only emitted when mouseTracking is turned on, or when a
1764 mouse button is pressed while moving into an item.
1765*/
1766
1767/*!
1768 \fn void QTableWidget::itemChanged(QTableWidgetItem *item)
1769
1770 This signal is emitted whenever the data of \a item has changed.
1771*/
1772
1773/*!
1774 \fn void QTableWidget::currentItemChanged(QTableWidgetItem *current, QTableWidgetItem *previous)
1775
1776 This signal is emitted whenever the current item changes. The \a
1777 previous item is the item that previously had the focus, \a
1778 current is the new current item.
1779*/
1780
1781/*!
1782 \fn void QTableWidget::itemSelectionChanged()
1783
1784 This signal is emitted whenever the selection changes.
1785
1786 \sa selectedItems(), QTableWidgetItem::isSelected()
1787*/
1788
1789
1790/*!
1791 \fn void QTableWidget::cellPressed(int row, int column)
1792
1793 This signal is emitted whenever a cell in the table is pressed.
1794 The \a row and \a column specified is the cell that was pressed.
1795*/
1796
1797/*!
1798 \fn void QTableWidget::cellClicked(int row, int column)
1799
1800 This signal is emitted whenever a cell in the table is clicked.
1801 The \a row and \a column specified is the cell that was clicked.
1802*/
1803
1804/*!
1805 \fn void QTableWidget::cellDoubleClicked(int row, int column)
1806
1807 This signal is emitted whenever a cell in the table is double
1808 clicked. The \a row and \a column specified is the cell that was
1809 double clicked.
1810*/
1811
1812/*!
1813 \fn void QTableWidget::cellActivated(int row, int column)
1814
1815 This signal is emitted when the cell specified by \a row and \a column
1816 has been activated
1817*/
1818
1819/*!
1820 \fn void QTableWidget::cellEntered(int row, int column)
1821
1822 This signal is emitted when the mouse cursor enters a cell. The
1823 cell is specified by \a row and \a column.
1824
1825 This signal is only emitted when mouseTracking is turned on, or when a
1826 mouse button is pressed while moving into an item.
1827*/
1828
1829/*!
1830 \fn void QTableWidget::cellChanged(int row, int column)
1831
1832 This signal is emitted whenever the data of the item in the cell
1833 specified by \a row and \a column has changed.
1834*/
1835
1836/*!
1837 \fn void QTableWidget::currentCellChanged(int currentRow, int currentColumn, int previousRow, int previousColumn)
1838
1839 This signal is emitted whenever the current cell changes. The cell
1840 specified by \a previousRow and \a previousColumn is the cell that
1841 previously had the focus, the cell specified by \a currentRow and \a
1842 currentColumn is the new current cell.
1843*/
1844
1845/*!
1846 \fn void QTableWidget::removeCellWidget(int row, int column)
1847
1848 Removes the widget set on the cell indicated by \a row and \a column.
1849*/
1850
1851/*!
1852 \fn QTableWidgetItem *QTableWidget::itemAt(int ax, int ay) const
1853
1854 Returns the item at the position equivalent to QPoint(\a{ax}, \a{ay}) in
1855 the table widget's coordinate system, or returns \nullptr if the specified point
1856 is not covered by an item in the table widget.
1857
1858 \sa item()
1859*/
1860
1861/*!
1862 \enum QTableWidgetItem::ItemType
1863
1864 This enum describes the types that are used to describe table widget items.
1865
1866 \value Type The default type for table widget items.
1867 \value UserType The minimum value for custom types. Values below UserType are
1868 reserved by Qt.
1869
1870 You can define new user types in QTableWidgetItem subclasses to ensure that
1871 custom items are treated specially.
1872
1873 \sa type()
1874*/
1875
1876/*!
1877 \fn int QTableWidgetItem::type() const
1878
1879 Returns the type passed to the QTableWidgetItem constructor.
1880*/
1881
1882/*!
1883 Creates a new table view with the given \a parent.
1884*/
1885QTableWidget::QTableWidget(QWidget *parent)
1886 : QTableView(*new QTableWidgetPrivate, parent)
1887{
1888 Q_D(QTableWidget);
1889 QTableView::setModel(new QTableModel(0, 0, this));
1890 d->setup();
1891}
1892
1893/*!
1894 Creates a new table view with the given \a rows and \a columns, and with the given \a parent.
1895*/
1896QTableWidget::QTableWidget(int rows, int columns, QWidget *parent)
1897 : QTableView(*new QTableWidgetPrivate, parent)
1898{
1899 Q_D(QTableWidget);
1900 QTableView::setModel(new QTableModel(rows, columns, this));
1901 d->setup();
1902}
1903
1904/*!
1905 Destroys this QTableWidget.
1906*/
1907QTableWidget::~QTableWidget()
1908{
1909 Q_D(QTableWidget);
1910 d->clearConnections();
1911}
1912
1913/*!
1914 Sets the number of rows in this table's model to \a rows. If
1915 this is less than rowCount(), the data in the unwanted rows
1916 is discarded.
1917
1918 \sa setColumnCount()
1919*/
1920void QTableWidget::setRowCount(int rows)
1921{
1922 Q_D(QTableWidget);
1923 d->tableModel()->setRowCount(rows);
1924}
1925
1926/*!
1927 Returns the number of rows.
1928*/
1929
1930int QTableWidget::rowCount() const
1931{
1932 Q_D(const QTableWidget);
1933 return d->model->rowCount();
1934}
1935
1936/*!
1937 Sets the number of columns in this table's model to \a columns. If
1938 this is less than columnCount(), the data in the unwanted columns
1939 is discarded.
1940
1941 \sa setRowCount()
1942*/
1943void QTableWidget::setColumnCount(int columns)
1944{
1945 Q_D(QTableWidget);
1946 d->tableModel()->setColumnCount(columns);
1947}
1948
1949/*!
1950 Returns the number of columns.
1951*/
1952
1953int QTableWidget::columnCount() const
1954{
1955 Q_D(const QTableWidget);
1956 return d->model->columnCount();
1957}
1958
1959/*!
1960 Returns the row for the \a item.
1961*/
1962int QTableWidget::row(const QTableWidgetItem *item) const
1963{
1964 Q_D(const QTableWidget);
1965 return d->tableModel()->index(item).row();
1966}
1967
1968/*!
1969 Returns the column for the \a item.
1970*/
1971int QTableWidget::column(const QTableWidgetItem *item) const
1972{
1973 Q_D(const QTableWidget);
1974 return d->tableModel()->index(item).column();
1975}
1976
1977
1978/*!
1979 Returns the item for the given \a row and \a column if one has been set; otherwise
1980 returns \nullptr.
1981
1982 \sa setItem()
1983*/
1984QTableWidgetItem *QTableWidget::item(int row, int column) const
1985{
1986 Q_D(const QTableWidget);
1987 return d->tableModel()->item(row, column);
1988}
1989
1990/*!
1991 Sets the item for the given \a row and \a column to \a item.
1992
1993 The table takes ownership of the item.
1994
1995 Note that if sorting is enabled (see
1996 \l{QTableView::sortingEnabled} {sortingEnabled}) and \a column is
1997 the current sort column, the \a row will be moved to the sorted
1998 position determined by \a item.
1999
2000 If you want to set several items of a particular row (say, by
2001 calling setItem() in a loop), you may want to turn off sorting
2002 before doing so, and turn it back on afterwards; this will allow
2003 you to use the same \a row argument for all items in the same row
2004 (i.e. setItem() will not move the row).
2005
2006 \sa item(), takeItem()
2007*/
2008void QTableWidget::setItem(int row, int column, QTableWidgetItem *item)
2009{
2010 Q_D(QTableWidget);
2011 if (item) {
2012 if (Q_UNLIKELY(item->view)) {
2013 qWarning(msg: "QTableWidget: cannot insert an item that is already owned by another QTableWidget");
2014 } else {
2015 item->view = this;
2016 d->tableModel()->setItem(row, column, item);
2017 }
2018 } else {
2019 delete takeItem(row, column);
2020 }
2021}
2022
2023/*!
2024 Removes the item at \a row and \a column from the table without deleting it.
2025*/
2026QTableWidgetItem *QTableWidget::takeItem(int row, int column)
2027{
2028 Q_D(QTableWidget);
2029 QTableWidgetItem *item = d->tableModel()->takeItem(row, column);
2030 if (item)
2031 item->view = nullptr;
2032 return item;
2033}
2034
2035/*!
2036 Returns the vertical header item for row \a row.
2037*/
2038QTableWidgetItem *QTableWidget::verticalHeaderItem(int row) const
2039{
2040 Q_D(const QTableWidget);
2041 return d->tableModel()->verticalHeaderItem(section: row);
2042}
2043
2044/*!
2045 Sets the vertical header item for row \a row to \a item.
2046*/
2047void QTableWidget::setVerticalHeaderItem(int row, QTableWidgetItem *item)
2048{
2049 Q_D(QTableWidget);
2050 if (item) {
2051 item->view = this;
2052 d->tableModel()->setVerticalHeaderItem(section: row, item);
2053 } else {
2054 delete takeVerticalHeaderItem(row);
2055 }
2056}
2057
2058/*!
2059 Removes the vertical header item at \a row from the header without deleting it.
2060*/
2061QTableWidgetItem *QTableWidget::takeVerticalHeaderItem(int row)
2062{
2063 Q_D(QTableWidget);
2064 QTableWidgetItem *itm = d->tableModel()->takeVerticalHeaderItem(section: row);
2065 if (itm)
2066 itm->view = nullptr;
2067 return itm;
2068}
2069
2070/*!
2071 Returns the horizontal header item for column, \a column, if one has been
2072 set; otherwise returns \nullptr.
2073*/
2074QTableWidgetItem *QTableWidget::horizontalHeaderItem(int column) const
2075{
2076 Q_D(const QTableWidget);
2077 return d->tableModel()->horizontalHeaderItem(section: column);
2078}
2079
2080/*!
2081 Sets the horizontal header item for column \a column to \a item.
2082 If necessary, the column count is increased to fit the item.
2083 The previous header item (if there was one) is deleted.
2084*/
2085void QTableWidget::setHorizontalHeaderItem(int column, QTableWidgetItem *item)
2086{
2087 Q_D(QTableWidget);
2088 if (item) {
2089 item->view = this;
2090 d->tableModel()->setHorizontalHeaderItem(section: column, item);
2091 } else {
2092 delete takeHorizontalHeaderItem(column);
2093 }
2094}
2095
2096/*!
2097 Removes the horizontal header item at \a column from the header without deleting it.
2098*/
2099QTableWidgetItem *QTableWidget::takeHorizontalHeaderItem(int column)
2100{
2101 Q_D(QTableWidget);
2102 QTableWidgetItem *itm = d->tableModel()->takeHorizontalHeaderItem(section: column);
2103 if (itm)
2104 itm->view = nullptr;
2105 return itm;
2106}
2107
2108/*!
2109 Sets the vertical header labels using \a labels.
2110*/
2111void QTableWidget::setVerticalHeaderLabels(const QStringList &labels)
2112{
2113 Q_D(QTableWidget);
2114 QTableModel *model = d->tableModel();
2115 QTableWidgetItem *item = nullptr;
2116 for (int i = 0; i < model->rowCount() && i < labels.size(); ++i) {
2117 item = model->verticalHeaderItem(section: i);
2118 if (!item) {
2119 item = model->createItem();
2120 setVerticalHeaderItem(row: i, item);
2121 }
2122 item->setText(labels.at(i));
2123 }
2124}
2125
2126/*!
2127 Sets the horizontal header labels using \a labels.
2128*/
2129void QTableWidget::setHorizontalHeaderLabels(const QStringList &labels)
2130{
2131 Q_D(QTableWidget);
2132 QTableModel *model = d->tableModel();
2133 QTableWidgetItem *item = nullptr;
2134 for (int i = 0; i < model->columnCount() && i < labels.size(); ++i) {
2135 item = model->horizontalHeaderItem(section: i);
2136 if (!item) {
2137 item = model->createItem();
2138 setHorizontalHeaderItem(column: i, item);
2139 }
2140 item->setText(labels.at(i));
2141 }
2142}
2143
2144/*!
2145 Returns the row of the current item.
2146
2147 \sa currentColumn(), setCurrentCell()
2148*/
2149int QTableWidget::currentRow() const
2150{
2151 return currentIndex().row();
2152}
2153
2154/*!
2155 Returns the column of the current item.
2156
2157 \sa currentRow(), setCurrentCell()
2158*/
2159int QTableWidget::currentColumn() const
2160{
2161 return currentIndex().column();
2162}
2163
2164/*!
2165 Returns the current item.
2166
2167 \sa setCurrentItem()
2168*/
2169QTableWidgetItem *QTableWidget::currentItem() const
2170{
2171 Q_D(const QTableWidget);
2172 return d->tableModel()->item(index: currentIndex());
2173}
2174
2175/*!
2176 Sets the current item to \a item.
2177
2178 Unless the selection mode is \l{QAbstractItemView::}{NoSelection},
2179 the item is also selected.
2180
2181 \sa currentItem(), setCurrentCell()
2182*/
2183void QTableWidget::setCurrentItem(QTableWidgetItem *item)
2184{
2185 Q_D(QTableWidget);
2186 setCurrentIndex(d->tableModel()->index(item));
2187}
2188
2189/*!
2190 Sets the current item to be \a item, using the given \a command.
2191
2192 \sa currentItem(), setCurrentCell()
2193*/
2194void QTableWidget::setCurrentItem(QTableWidgetItem *item, QItemSelectionModel::SelectionFlags command)
2195{
2196 Q_D(QTableWidget);
2197 d->selectionModel->setCurrentIndex(index: d->tableModel()->index(item), command);
2198}
2199
2200/*!
2201 Sets the current cell to be the cell at position (\a row, \a
2202 column).
2203
2204 Depending on the current \l{QAbstractItemView::SelectionMode}{selection mode},
2205 the cell may also be selected.
2206
2207 \sa setCurrentItem(), currentRow(), currentColumn()
2208*/
2209void QTableWidget::setCurrentCell(int row, int column)
2210{
2211 setCurrentIndex(model()->index(row, column, parent: QModelIndex()));
2212}
2213
2214/*!
2215 Sets the current cell to be the cell at position (\a row, \a
2216 column), using the given \a command.
2217
2218 \sa setCurrentItem(), currentRow(), currentColumn()
2219*/
2220void QTableWidget::setCurrentCell(int row, int column, QItemSelectionModel::SelectionFlags command)
2221{
2222 Q_D(QTableWidget);
2223 d->selectionModel->setCurrentIndex(index: model()->index(row, column, parent: QModelIndex()), command);
2224}
2225
2226/*!
2227 Sorts all the rows in the table widget based on \a column and \a order.
2228*/
2229void QTableWidget::sortItems(int column, Qt::SortOrder order)
2230{
2231 Q_D(QTableWidget);
2232 d->model->sort(column, order);
2233 horizontalHeader()->setSortIndicator(logicalIndex: column, order);
2234}
2235
2236/*!
2237 \internal
2238*/
2239void QTableWidget::setSortingEnabled(bool enable)
2240{
2241 QTableView::setSortingEnabled(enable);
2242}
2243
2244/*!
2245 \internal
2246*/
2247bool QTableWidget::isSortingEnabled() const
2248{
2249 return QTableView::isSortingEnabled();
2250}
2251
2252/*!
2253 Starts editing the \a item if it is editable.
2254*/
2255
2256void QTableWidget::editItem(QTableWidgetItem *item)
2257{
2258 Q_D(QTableWidget);
2259 if (!item)
2260 return;
2261 edit(index: d->tableModel()->index(item));
2262}
2263
2264/*!
2265 Opens an editor for the give \a item. The editor remains open after editing.
2266
2267 \sa closePersistentEditor(), isPersistentEditorOpen()
2268*/
2269void QTableWidget::openPersistentEditor(QTableWidgetItem *item)
2270{
2271 Q_D(QTableWidget);
2272 if (!item)
2273 return;
2274 QModelIndex index = d->tableModel()->index(item);
2275 QAbstractItemView::openPersistentEditor(index);
2276}
2277
2278/*!
2279 Closes the persistent editor for \a item.
2280
2281 \sa openPersistentEditor(), isPersistentEditorOpen()
2282*/
2283void QTableWidget::closePersistentEditor(QTableWidgetItem *item)
2284{
2285 Q_D(QTableWidget);
2286 if (!item)
2287 return;
2288 QModelIndex index = d->tableModel()->index(item);
2289 QAbstractItemView::closePersistentEditor(index);
2290}
2291
2292/*!
2293 \since 5.10
2294
2295 Returns whether a persistent editor is open for item \a item.
2296
2297 \sa openPersistentEditor(), closePersistentEditor()
2298*/
2299bool QTableWidget::isPersistentEditorOpen(QTableWidgetItem *item) const
2300{
2301 Q_D(const QTableWidget);
2302 const QModelIndex index = d->tableModel()->index(item);
2303 return QAbstractItemView::isPersistentEditorOpen(index);
2304}
2305
2306/*!
2307 Returns the widget displayed in the cell in the given \a row and \a column.
2308
2309 \note The table takes ownership of the widget.
2310
2311 \sa setCellWidget()
2312*/
2313QWidget *QTableWidget::cellWidget(int row, int column) const
2314{
2315 QModelIndex index = model()->index(row, column, parent: QModelIndex());
2316 return QAbstractItemView::indexWidget(index);
2317}
2318
2319/*!
2320 Sets the given \a widget to be displayed in the cell in the given \a row
2321 and \a column, passing the ownership of the widget to the table.
2322
2323 If cell widget A is replaced with cell widget B, cell widget A will be
2324 deleted. For example, in the code snippet below, the QLineEdit object will
2325 be deleted.
2326
2327 \snippet code/src_gui_itemviews_qtablewidget.cpp 0
2328
2329 \sa cellWidget()
2330*/
2331void QTableWidget::setCellWidget(int row, int column, QWidget *widget)
2332{
2333 QModelIndex index = model()->index(row, column, parent: QModelIndex());
2334 QAbstractItemView::setIndexWidget(index, widget);
2335}
2336
2337/*!
2338 Selects or deselects the \a range depending on \a select.
2339*/
2340void QTableWidget::setRangeSelected(const QTableWidgetSelectionRange &range, bool select)
2341{
2342 if (!model()->hasIndex(row: range.topRow(), column: range.leftColumn(), parent: rootIndex()) ||
2343 !model()->hasIndex(row: range.bottomRow(), column: range.rightColumn(), parent: rootIndex()))
2344 return;
2345
2346 QModelIndex topLeft = model()->index(row: range.topRow(), column: range.leftColumn(), parent: rootIndex());
2347 QModelIndex bottomRight = model()->index(row: range.bottomRow(), column: range.rightColumn(), parent: rootIndex());
2348
2349 selectionModel()->select(selection: QItemSelection(topLeft, bottomRight),
2350 command: select ? QItemSelectionModel::Select : QItemSelectionModel::Deselect);
2351}
2352
2353/*!
2354 Returns a list of all selected ranges.
2355
2356 \sa QTableWidgetSelectionRange
2357*/
2358
2359QList<QTableWidgetSelectionRange> QTableWidget::selectedRanges() const
2360{
2361 const QList<QItemSelectionRange> ranges = selectionModel()->selection();
2362 QList<QTableWidgetSelectionRange> result;
2363 const int rangesCount = ranges.size();
2364 result.reserve(asize: rangesCount);
2365 for (int i = 0; i < rangesCount; ++i)
2366 result.append(t: {ranges.at(i).top(),
2367 ranges.at(i).left(),
2368 ranges.at(i).bottom(),
2369 ranges.at(i).right()});
2370 return result;
2371}
2372
2373/*!
2374 Returns a list of all selected items.
2375
2376 This function returns a list of pointers to the contents of the
2377 selected cells. Use the selectedIndexes() function to retrieve the
2378 complete selection \e including empty cells.
2379
2380 \sa selectedIndexes()
2381*/
2382
2383QList<QTableWidgetItem*> QTableWidget::selectedItems() const
2384{
2385 Q_D(const QTableWidget);
2386 const QModelIndexList indexes = selectionModel()->selectedIndexes();
2387 QList<QTableWidgetItem*> items;
2388 for (const auto &index : indexes) {
2389 if (isIndexHidden(index))
2390 continue;
2391 QTableWidgetItem *item = d->tableModel()->item(index);
2392 if (item)
2393 items.append(t: item);
2394 }
2395 return items;
2396}
2397
2398/*!
2399 Finds items that matches the \a text using the given \a flags.
2400*/
2401
2402QList<QTableWidgetItem*> QTableWidget::findItems(const QString &text, Qt::MatchFlags flags) const
2403{
2404 Q_D(const QTableWidget);
2405 QModelIndexList indexes;
2406 for (int column = 0; column < columnCount(); ++column)
2407 indexes += d->model->match(start: model()->index(row: 0, column, parent: QModelIndex()),
2408 role: Qt::DisplayRole, value: text, hits: -1, flags);
2409 QList<QTableWidgetItem*> items;
2410 const int indexCount = indexes.size();
2411 items.reserve(asize: indexCount);
2412 for (int i = 0; i < indexCount; ++i)
2413 items.append(t: d->tableModel()->item(index: indexes.at(i)));
2414 return items;
2415}
2416
2417/*!
2418 Returns the visual row of the given \a logicalRow.
2419*/
2420
2421int QTableWidget::visualRow(int logicalRow) const
2422{
2423 return verticalHeader()->visualIndex(logicalIndex: logicalRow);
2424}
2425
2426/*!
2427 Returns the visual column of the given \a logicalColumn.
2428*/
2429
2430int QTableWidget::visualColumn(int logicalColumn) const
2431{
2432 return horizontalHeader()->visualIndex(logicalIndex: logicalColumn);
2433}
2434
2435/*!
2436 \fn QTableWidgetItem *QTableWidget::itemAt(const QPoint &point) const
2437
2438 Returns a pointer to the item at the given \a point, or returns \nullptr if
2439 \a point is not covered by an item in the table widget.
2440
2441 \sa item()
2442*/
2443
2444QTableWidgetItem *QTableWidget::itemAt(const QPoint &p) const
2445{
2446 Q_D(const QTableWidget);
2447 return d->tableModel()->item(index: indexAt(p));
2448}
2449
2450/*!
2451 Returns the rectangle on the viewport occupied by the item at \a item.
2452*/
2453QRect QTableWidget::visualItemRect(const QTableWidgetItem *item) const
2454{
2455 Q_D(const QTableWidget);
2456 if (!item)
2457 return QRect();
2458 QModelIndex index = d->tableModel()->index(item: const_cast<QTableWidgetItem*>(item));
2459 Q_ASSERT(index.isValid());
2460 return visualRect(index);
2461}
2462
2463/*!
2464 Scrolls the view if necessary to ensure that the \a item is visible.
2465 The \a hint parameter specifies more precisely where the
2466 \a item should be located after the operation.
2467*/
2468
2469void QTableWidget::scrollToItem(const QTableWidgetItem *item, QAbstractItemView::ScrollHint hint)
2470{
2471 Q_D(QTableWidget);
2472 if (!item)
2473 return;
2474 QModelIndex index = d->tableModel()->index(item: const_cast<QTableWidgetItem*>(item));
2475 Q_ASSERT(index.isValid());
2476 QTableView::scrollTo(index, hint);
2477}
2478
2479/*!
2480 Returns the item prototype used by the table.
2481
2482 \sa setItemPrototype()
2483*/
2484const QTableWidgetItem *QTableWidget::itemPrototype() const
2485{
2486 Q_D(const QTableWidget);
2487 return d->tableModel()->itemPrototype();
2488}
2489
2490/*!
2491 Sets the item prototype for the table to the specified \a item.
2492
2493 The table widget will use the item prototype clone function when it needs
2494 to create a new table item. For example when the user is editing
2495 in an empty cell. This is useful when you have a QTableWidgetItem
2496 subclass and want to make sure that QTableWidget creates instances of
2497 your subclass.
2498
2499 The table takes ownership of the prototype.
2500
2501 \sa itemPrototype()
2502*/
2503void QTableWidget::setItemPrototype(const QTableWidgetItem *item)
2504{
2505 Q_D(QTableWidget);
2506 d->tableModel()->setItemPrototype(item);
2507}
2508
2509/*!
2510 Inserts an empty row into the table at \a row.
2511*/
2512void QTableWidget::insertRow(int row)
2513{
2514 Q_D(QTableWidget);
2515 d->tableModel()->insertRows(row);
2516}
2517
2518/*!
2519 Inserts an empty column into the table at \a column.
2520*/
2521void QTableWidget::insertColumn(int column)
2522{
2523 Q_D(QTableWidget);
2524 d->tableModel()->insertColumns(column);
2525}
2526
2527/*!
2528 Removes the row \a row and all its items from the table.
2529*/
2530void QTableWidget::removeRow(int row)
2531{
2532 Q_D(QTableWidget);
2533 d->tableModel()->removeRows(row);
2534}
2535
2536/*!
2537 Removes the column \a column and all its items from the table.
2538*/
2539void QTableWidget::removeColumn(int column)
2540{
2541 Q_D(QTableWidget);
2542 d->tableModel()->removeColumns(column);
2543}
2544
2545/*!
2546 Removes all items in the view.
2547 This will also remove all selections and headers.
2548 If you don't want to remove the headers, use
2549 QTableWidget::clearContents().
2550 The table dimensions stay the same.
2551*/
2552
2553void QTableWidget::clear()
2554{
2555 Q_D(QTableWidget);
2556 selectionModel()->clear();
2557 d->tableModel()->clear();
2558}
2559
2560/*!
2561 Removes all items not in the headers from the view.
2562 This will also remove all selections.
2563 The table dimensions stay the same.
2564*/
2565void QTableWidget::clearContents()
2566{
2567 Q_D(QTableWidget);
2568 selectionModel()->clear();
2569 d->tableModel()->clearContents();
2570}
2571
2572/*!
2573 Returns a list of MIME types that can be used to describe a list of
2574 tablewidget items.
2575
2576 \sa mimeData()
2577*/
2578QStringList QTableWidget::mimeTypes() const
2579{
2580 return d_func()->tableModel()->QAbstractTableModel::mimeTypes();
2581}
2582
2583/*!
2584 Returns an object that contains a serialized description of the specified
2585 \a items. The format used to describe the items is obtained from the
2586 mimeTypes() function.
2587
2588 If the list of items is empty, \nullptr is returned rather than a
2589 serialized empty list.
2590*/
2591QMimeData *QTableWidget::mimeData(const QList<QTableWidgetItem *> &items) const
2592{
2593 Q_D(const QTableWidget);
2594
2595 QModelIndexList &cachedIndexes = d->tableModel()->cachedIndexes;
2596
2597 // if non empty, it's called from the model's own mimeData
2598 if (cachedIndexes.isEmpty()) {
2599 cachedIndexes.reserve(asize: items.size());
2600 for (QTableWidgetItem *item : items)
2601 cachedIndexes << indexFromItem(item);
2602
2603 QMimeData *result = d->tableModel()->internalMimeData();
2604
2605 cachedIndexes.clear();
2606 return result;
2607 }
2608
2609 return d->tableModel()->internalMimeData();
2610}
2611
2612/*!
2613 Handles the \a data supplied by a drag and drop operation that ended with
2614 the given \a action in the given \a row and \a column.
2615 Returns \c true if the data and action can be handled by the model;
2616 otherwise returns \c false.
2617
2618 \sa supportedDropActions(), supportedDragActions
2619*/
2620bool QTableWidget::dropMimeData(int row, int column, const QMimeData *data, Qt::DropAction action)
2621{
2622 QModelIndex idx;
2623#if QT_CONFIG(draganddrop)
2624 if (dropIndicatorPosition() == QAbstractItemView::OnItem) {
2625 // QAbstractTableModel::dropMimeData will overwrite on the index if row == -1 and column == -1
2626 idx = model()->index(row, column);
2627 row = -1;
2628 column = -1;
2629 }
2630#endif
2631 return d_func()->tableModel()->QAbstractTableModel::dropMimeData(data, action , row, column, parent: idx);
2632}
2633
2634/*!
2635 Returns the drop actions supported by this view.
2636
2637 \sa Qt::DropActions, supportedDragActions, dropMimeData()
2638*/
2639Qt::DropActions QTableWidget::supportedDropActions() const
2640{
2641 return d_func()->tableModel()->QAbstractTableModel::supportedDropActions() | Qt::MoveAction;
2642}
2643
2644#if QT_CONFIG(draganddrop)
2645/*!
2646 \property QTableWidget::supportedDragActions
2647 \brief the drag actions supported by this view
2648
2649 \since 6.10
2650 \sa Qt::DropActions, supportedDropActions()
2651*/
2652Qt::DropActions QTableWidget::supportedDragActions() const
2653{
2654 Q_D(const QTableWidget);
2655 return d->supportedDragActions.value_or(u: supportedDropActions());
2656}
2657
2658void QTableWidget::setSupportedDragActions(Qt::DropActions actions)
2659{
2660 Q_D(QTableWidget);
2661 d->supportedDragActions = actions;
2662}
2663#endif // QT_CONFIG(draganddrop)
2664
2665/*!
2666 Returns a list of pointers to the items contained in the \a data object.
2667 If the object was not created by a QTreeWidget in the same process, the list
2668 is empty.
2669
2670*/
2671QList<QTableWidgetItem*> QTableWidget::items(const QMimeData *data) const
2672{
2673 const QTableWidgetMimeData *twd = qobject_cast<const QTableWidgetMimeData*>(object: data);
2674 if (twd)
2675 return twd->items;
2676 return QList<QTableWidgetItem*>();
2677}
2678
2679/*!
2680 Returns the QModelIndex associated with the given \a item.
2681
2682 \note In Qt versions prior to 5.10, this function took a non-\c{const} \a item.
2683*/
2684
2685QModelIndex QTableWidget::indexFromItem(const QTableWidgetItem *item) const
2686{
2687 Q_D(const QTableWidget);
2688 return d->tableModel()->index(item);
2689}
2690
2691/*!
2692 Returns a pointer to the QTableWidgetItem associated with the given \a index.
2693*/
2694
2695QTableWidgetItem *QTableWidget::itemFromIndex(const QModelIndex &index) const
2696{
2697 Q_D(const QTableWidget);
2698 return d->tableModel()->item(index);
2699}
2700
2701/*!
2702 \internal
2703*/
2704void QTableWidget::setModel(QAbstractItemModel * /*model*/)
2705{
2706 Q_ASSERT(!"QTableWidget::setModel() - Changing the model of the QTableWidget is not allowed.");
2707}
2708
2709/*! \reimp */
2710bool QTableWidget::event(QEvent *e)
2711{
2712 return QTableView::event(event: e);
2713}
2714
2715#if QT_CONFIG(draganddrop)
2716/*! \reimp */
2717void QTableWidget::dropEvent(QDropEvent *event) {
2718 Q_D(QTableWidget);
2719 if (event->source() == this && (event->dropAction() == Qt::MoveAction ||
2720 dragDropMode() == QAbstractItemView::InternalMove)) {
2721 QModelIndex topIndex;
2722 int col = -1;
2723 int row = -1;
2724 // check whether a subclass has already accepted the event, ie. moved the data
2725 if (!event->isAccepted() && d->dropOn(event, row: &row, col: &col, index: &topIndex) && row == -1 && col == -1) {
2726 // Drop onto item
2727 const QModelIndexList indexes = selectedIndexes();
2728 int top = INT_MAX;
2729 int left = INT_MAX;
2730 for (const auto &index : indexes) {
2731 top = qMin(a: index.row(), b: top);
2732 left = qMin(a: index.column(), b: left);
2733 }
2734 QList<QTableWidgetItem *> taken;
2735 const int indexesCount = indexes.size();
2736 taken.reserve(asize: indexesCount);
2737 for (const auto &index : indexes)
2738 taken.append(t: takeItem(row: index.row(), column: index.column()));
2739
2740 for (const auto &index : indexes) {
2741 int r = index.row() - top + topIndex.row();
2742 int c = index.column() - left + topIndex.column();
2743 setItem(row: r, column: c, item: taken.takeFirst());
2744 }
2745
2746 event->accept();
2747 }
2748 // either we or a subclass accepted the drop event, so assume that the data was
2749 // moved and that QAbstractItemView shouldn't remove the source when QDrag::exec returns
2750 if (event->isAccepted())
2751 d->dropEventMoved = true;
2752 }
2753
2754 QTableView::dropEvent(event);
2755}
2756#endif
2757
2758QT_END_NAMESPACE
2759
2760#include "moc_qtablewidget.cpp"
2761#include "moc_qtablewidget_p.cpp"
2762

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