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

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