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