14QTableModel::QTableModel(
int rows,
int columns, QTableWidget *parent)
15 : QAbstractTableModel(parent),
17 tableItems(rows * columns, 0),
18 verticalHeaderItems(rows, 0),
19 horizontalHeaderItems(columns, 0)
28bool QTableModel::insertRows(
int row,
int count,
const QModelIndex &)
30 if (count < 1 || row < 0 || row > verticalHeaderItems.size())
33 beginInsertRows(QModelIndex(), row, row + count - 1);
34 int rc = verticalHeaderItems.size();
35 int cc = horizontalHeaderItems.size();
36 verticalHeaderItems.insert(row, count, 0);
38 tableItems.resize(cc * count);
40 tableItems.insert(tableIndex(row, 0), cc * count, 0);
45bool QTableModel::insertColumns(
int column,
int count,
const QModelIndex &)
47 if (count < 1 || column < 0 || column > horizontalHeaderItems.size())
50 beginInsertColumns(QModelIndex(), column, column + count - 1);
51 int rc = verticalHeaderItems.size();
52 int cc = horizontalHeaderItems.size();
53 horizontalHeaderItems.insert(column, count, 0);
55 tableItems.resize(rc * count);
57 for (
int row = 0; row < rc; ++row)
58 tableItems.insert(tableIndex(row, column), count, 0);
63bool QTableModel::removeRows(
int row,
int count,
const QModelIndex &)
65 if (count < 1 || row < 0 || row + count > verticalHeaderItems.size())
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);
75 oldItem->view =
nullptr;
78 tableItems.remove(qMax(i, 0), n);
79 for (
int v = row; v < row + count; ++v) {
80 oldItem = verticalHeaderItems.at(v);
82 oldItem->view =
nullptr;
85 verticalHeaderItems.remove(row, count);
90bool QTableModel::removeColumns(
int column,
int count,
const QModelIndex &)
92 if (count < 1 || column < 0 || column + count > horizontalHeaderItems.size())
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);
102 oldItem->view =
nullptr;
105 tableItems.remove(i, count);
107 for (
int h=column; h<column+count; ++h) {
108 oldItem = horizontalHeaderItems.at(h);
110 oldItem->view =
nullptr;
113 horizontalHeaderItems.remove(column, count);
118bool QTableModel::moveRows(
const QModelIndex &sourceParent,
int sourceRow,
int count,
const QModelIndex &destinationParent,
int destinationChild)
121 || sourceRow + count - 1 >= rowCount(sourceParent)
122 || destinationChild < 0
123 || destinationChild > rowCount(destinationParent)
124 || sourceRow == destinationChild
125 || sourceRow == destinationChild - 1
127 || sourceParent.isValid()
128 || destinationParent.isValid()) {
131 if (!beginMoveRows(sourceParent, sourceRow, sourceRow + count - 1, destinationParent, destinationChild))
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;
143 tableItems.move(fromIndex, destinationIndex);
146 int fromRow = sourceRow;
147 if (destinationChild < sourceRow)
148 fromRow += count - 1;
152 verticalHeaderItems.move(fromRow, destinationChild);
158void QTableModel::setItem(
int row,
int column, QTableWidgetItem *item)
160 int i = tableIndex(row, column);
161 if (i < 0 || i >= tableItems.size())
163 QTableWidgetItem *oldItem = tableItems.at(i);
169 oldItem->view =
nullptr;
170 delete tableItems.at(i);
172 QTableWidget *view =
this->view();
177 tableItems[i] = item;
179 if (view && view->isSortingEnabled()
180 && view->horizontalHeader()->sortIndicatorSection() == column) {
182 Qt::SortOrder order = view->horizontalHeader()->sortIndicatorOrder();
183 QList<QTableWidgetItem *> colItems = columnItems(column);
184 if (row < colItems.size())
185 colItems.remove(row);
187 if (item ==
nullptr) {
189 sortedRow = colItems.size();
191 QList<QTableWidgetItem *>::iterator it;
192 it = sortedInsertionIterator(colItems.begin(), colItems.end(), order, item);
193 sortedRow = qMax((
int)(it - colItems.begin()), 0);
195 if (sortedRow != row) {
196 const int destinationChild = sortedRow > row ? sortedRow + 1 : sortedRow;
197 moveRows(QModelIndex(), row, 1, QModelIndex(), destinationChild);
201 QModelIndex idx = QAbstractTableModel::index(row, column);
202 emit dataChanged(idx, idx);
231void QTableModel::removeItem(QTableWidgetItem *item)
233 int i = tableItems.indexOf(item);
235 QModelIndex idx = index(item);
236 tableItems[i] =
nullptr;
237 emit dataChanged(idx, idx);
241 i = verticalHeaderItems.indexOf(item);
244 verticalHeaderItems[i] = 0;
245 emit headerDataChanged(Qt::Vertical, i, i);
248 i = horizontalHeaderItems.indexOf(item);
250 horizontalHeaderItems[i] = 0;
251 emit headerDataChanged(Qt::Horizontal, i, i);
256void QTableModel::setHorizontalHeaderItem(
int section, QTableWidgetItem *item)
258 if (section < 0 || section >= horizontalHeaderItems.size())
260 QTableWidgetItem *oldItem = horizontalHeaderItems.at(section);
265 oldItem->view =
nullptr;
268 QTableWidget *view =
this->view();
272 item->d->headerItem =
true;
274 horizontalHeaderItems[section] = item;
275 emit headerDataChanged(Qt::Horizontal, section, section);
433bool QTableModel::setItemData(
const QModelIndex &index,
const QMap<
int, QVariant> &roles)
435 if (!index.isValid())
438 QTableWidget *view =
this->view();
439 QTableWidgetItem *itm = item(index);
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());
448 if (role == Qt::DisplayRole)
449 rolesVec += Qt::EditRole;
453 if (!rolesVec.isEmpty())
454 itemChanged(itm, rolesVec);
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);
468bool QTableModel::clearItemData(
const QModelIndex &index)
470 if (!checkIndex(index, CheckIndexOption::IndexIsValid))
472 QTableWidgetItem *itm = item(index);
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(); }))
480 emit dataChanged(index, index, QList<
int> {});
498void QTableModel::sort(
int column, Qt::SortOrder order)
500 QList<std::pair<QTableWidgetItem *,
int>> sortable;
501 QList<
int> unsortable;
502 const int numRows = rowCount();
504 sortable.reserve(numRows);
505 unsortable.reserve(numRows);
507 for (
int row = 0; row < numRows; ++row) {
508 if (QTableWidgetItem *itm = item(row, column))
509 sortable.emplace_back(itm, row);
511 unsortable.append(row);
514 const auto compare = (order == Qt::AscendingOrder ? &itemLessThan : &itemGreaterThan);
515 std::stable_sort(sortable.begin(), sortable.end(), compare);
517 QList<QTableWidgetItem *> sorted_table(tableItems.size());
518 QModelIndexList from;
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));
534 emit layoutAboutToBeChanged({}, QAbstractItemModel::VerticalSortHint);
536 tableItems = sorted_table;
537 changePersistentIndexList(from, to);
539 emit layoutChanged({}, QAbstractItemModel::VerticalSortHint);
549void QTableModel::ensureSorted(
int column, Qt::SortOrder order,
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) {
562 sorting.emplace_back(itm, row);
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,
581 int newRow = qMax((
int)(vit - colItems.begin()), 0);
582 if ((newRow < oldRow) && !(*item < *colItems.at(oldRow - 1)) && !(*colItems.at(oldRow - 1) < *item))
584 vit = colItems.insert(vit, item);
585 if (newRow != oldRow) {
587 emit layoutAboutToBeChanged({}, QAbstractItemModel::VerticalSortHint);
588 oldPersistentIndexes = persistentIndexList();
589 newPersistentIndexes = oldPersistentIndexes;
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);
605 updateRowIndexes(newPersistentIndexes, oldRow, newRow);
607 for (
int j = i + 1; j < sorting.size(); ++j) {
608 int otherRow = sorting.at(j).second;
609 if (oldRow < otherRow && newRow >= otherRow)
611 else if (oldRow > otherRow && newRow <= otherRow)
618 tableItems = newTable;
619 verticalHeaderItems = newVertical;
620 changePersistentIndexList(oldPersistentIndexes,
621 newPersistentIndexes);
622 emit layoutChanged({}, QAbstractItemModel::VerticalSortHint);
655void QTableModel::updateRowIndexes(QModelIndexList &indexes,
656 int movedFromRow,
int movedToRow)
658 QModelIndexList::iterator it;
659 for (it = indexes.begin(); it != indexes.end(); ++it) {
660 int oldRow = (*it).row();
662 if (oldRow == movedFromRow)
664 else if (movedFromRow < oldRow && movedToRow >= oldRow)
666 else if (movedFromRow > oldRow && movedToRow <= oldRow)
668 if (newRow != oldRow)
669 *it = index(newRow, (*it).column(), (*it).parent());
681QTableModel::sortedInsertionIterator(
const QList<QTableWidgetItem *>::iterator &begin,
682 const QList<QTableWidgetItem *>::iterator &end,
683 Qt::SortOrder order, QTableWidgetItem *item)
685 if (order == Qt::AscendingOrder)
686 return std::lower_bound(begin, end, item, QTableModelLessThan());
687 return std::lower_bound(begin, end, item, QTableModelGreaterThan());
702QVariant QTableModel::headerData(
int section, Qt::Orientation orientation,
int role)
const
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);
716 return itm->data(role);
717 if (role == Qt::DisplayRole)
722bool QTableModel::setHeaderData(
int section, Qt::Orientation orientation,
723 const QVariant &value,
int role)
726 (orientation == Qt::Horizontal && horizontalHeaderItems.size() <= section) ||
727 (orientation == Qt::Vertical && verticalHeaderItems.size() <= section))
730 QTableWidgetItem *itm =
nullptr;
731 if (orientation == Qt::Horizontal)
732 itm = horizontalHeaderItems.at(section);
734 itm = verticalHeaderItems.at(section);
736 itm->setData(role, value);
749void QTableModel::clear()
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;
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;
781void QTableModel::itemChanged(QTableWidgetItem *item,
const QList<
int> &roles)
785 if (item->d->headerItem) {
786 int row = verticalHeaderItems.indexOf(item);
788 emit headerDataChanged(Qt::Vertical, row, row);
790 int column = horizontalHeaderItems.indexOf(item);
792 emit headerDataChanged(Qt::Horizontal, column, column);
795 QModelIndex idx = index(item);
797 emit dataChanged(idx, idx, roles);
832QMimeData *QTableModel::mimeData(
const QModelIndexList &indexes)
const
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();
843 cachedIndexes = indexes;
844 QMimeData *mimeData = (view ? view->mimeData(items) :
nullptr);
845 cachedIndexes.clear();
1403void QTableWidgetItem::setData(
int role,
const QVariant &value)
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)
1412 values[i].value = value;
1418 values.append(QWidgetItemData(role, value));
1419 if (QTableModel *model = tableModel())
1421 const QList<
int> roles((role == Qt::DisplayRole)
1422 ? QList<
int>({ Qt::DisplayRole, Qt::EditRole })
1423 : QList<
int>({ role }));
1424 model->itemChanged(
this, roles);
1614void QTableWidgetPrivate::setup()
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),
1630 QObjectPrivate::connect(model, &QAbstractItemModel::dataChanged,
1631 this, &QTableWidgetPrivate::emitItemChanged),
1633 QObjectPrivate::connect(q->selectionModel(), &QItemSelectionModel::currentChanged,
1634 this, &QTableWidgetPrivate::emitCurrentItemChanged),
1635 QObject::connect(q->selectionModel(), &QItemSelectionModel::selectionChanged,
1636 q, &QTableWidget::itemSelectionChanged),
1638 QObjectPrivate::connect(model, &QAbstractItemModel::dataChanged,
1639 this, &QTableWidgetPrivate::dataChanged),
1640 QObjectPrivate::connect(model, &QAbstractItemModel::columnsRemoved,
1641 this, &QTableWidgetPrivate::sort)
1699void QTableWidgetPrivate::emitCurrentItemChanged(
const QModelIndex ¤t,
1700 const QModelIndex &previous)
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());
1719void QTableWidgetPrivate::dataChanged(
const QModelIndex &topLeft,
1720 const QModelIndex &bottomRight)
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());
2341void QTableWidget::setRangeSelected(
const QTableWidgetSelectionRange &range,
bool select)
2343 if (!model()->hasIndex(range.topRow(), range.leftColumn(), rootIndex()) ||
2344 !model()->hasIndex(range.bottomRow(), range.rightColumn(), rootIndex()))
2347 QModelIndex topLeft = model()->index(range.topRow(), range.leftColumn(), rootIndex());
2348 QModelIndex bottomRight = model()->index(range.bottomRow(), range.rightColumn(), rootIndex());
2350 selectionModel()->select(QItemSelection(topLeft, bottomRight),
2351 select ? QItemSelectionModel::Select : QItemSelectionModel::Deselect);
2360QList<QTableWidgetSelectionRange> QTableWidget::selectedRanges()
const
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()});
2403QList<QTableWidgetItem*> QTableWidget::findItems(
const QString &text, Qt::MatchFlags flags)
const
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)));
2592QMimeData *QTableWidget::mimeData(
const QList<QTableWidgetItem *> &items)
const
2594 Q_D(
const QTableWidget);
2596 QModelIndexList &cachedIndexes = d->tableModel()->cachedIndexes;
2599 if (cachedIndexes.isEmpty()) {
2600 cachedIndexes.reserve(items.size());
2601 for (QTableWidgetItem *item : items)
2602 cachedIndexes << indexFromItem(item);
2604 QMimeData *result = d->tableModel()->internalMimeData();
2606 cachedIndexes.clear();
2610 return d->tableModel()->internalMimeData();
2621bool QTableWidget::dropMimeData(
int row,
int column,
const QMimeData *data, Qt::DropAction action)
2624#if QT_CONFIG(draganddrop)
2625 if (dropIndicatorPosition() == QAbstractItemView::OnItem) {
2627 idx = model()->index(row, column);
2632 return d_func()->tableModel()->QAbstractTableModel::dropMimeData(data, action , row, column, idx);