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

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