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