1 | // Copyright (C) 2016 The Qt Company Ltd. |
---|---|
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #include "qstandarditemmodel.h" |
5 | |
6 | #include <QtCore/qdatetime.h> |
7 | #include <QtCore/qlist.h> |
8 | #include <QtCore/qmap.h> |
9 | #include <QtCore/qpair.h> |
10 | #include <QtCore/qvariant.h> |
11 | #include <QtCore/qstringlist.h> |
12 | #include <QtCore/qbitarray.h> |
13 | #include <QtCore/qmimedata.h> |
14 | #include <QtCore/qiodevice.h> |
15 | #include <private/qduplicatetracker_p.h> |
16 | #include <private/qstandarditemmodel_p.h> |
17 | #include <qdebug.h> |
18 | #include <algorithm> |
19 | |
20 | QT_BEGIN_NAMESPACE |
21 | |
22 | // Used internally to store the flags |
23 | namespace { |
24 | constexpr auto DataFlagsRole = Qt::ItemDataRole(Qt::UserRole - 1); |
25 | } |
26 | |
27 | static inline QString qStandardItemModelDataListMimeType() |
28 | { |
29 | return QStringLiteral("application/x-qstandarditemmodeldatalist"); |
30 | } |
31 | |
32 | class QStandardItemModelLessThan |
33 | { |
34 | public: |
35 | inline QStandardItemModelLessThan() |
36 | { } |
37 | |
38 | inline bool operator()(const QPair<QStandardItem*, int> &l, |
39 | const QPair<QStandardItem*, int> &r) const |
40 | { |
41 | return *(l.first) < *(r.first); |
42 | } |
43 | }; |
44 | |
45 | class QStandardItemModelGreaterThan |
46 | { |
47 | public: |
48 | inline QStandardItemModelGreaterThan() |
49 | { } |
50 | |
51 | inline bool operator()(const QPair<QStandardItem*, int> &l, |
52 | const QPair<QStandardItem*, int> &r) const |
53 | { |
54 | return *(r.first) < *(l.first); |
55 | } |
56 | }; |
57 | |
58 | /*! |
59 | \internal |
60 | */ |
61 | QPair<int, int> QStandardItemPrivate::position() const |
62 | { |
63 | if (QStandardItem *par = parent) { |
64 | int idx = par->d_func()->childIndex(child: q_func()); |
65 | if (idx == -1) |
66 | return QPair<int, int>(-1, -1); |
67 | return QPair<int, int>(idx / par->columnCount(), idx % par->columnCount()); |
68 | } |
69 | // ### support header items? |
70 | return QPair<int, int>(-1, -1); |
71 | } |
72 | |
73 | /*! |
74 | \internal |
75 | */ |
76 | void QStandardItemPrivate::setChild(int row, int column, QStandardItem *item, |
77 | bool emitChanged) |
78 | { |
79 | Q_Q(QStandardItem); |
80 | if (item == q) { |
81 | qWarning(msg: "QStandardItem::setChild: Can't make an item a child of itself %p", |
82 | item); |
83 | return; |
84 | } |
85 | if ((row < 0) || (column < 0)) |
86 | return; |
87 | if (rows <= row) |
88 | q->setRowCount(row + 1); |
89 | if (columns <= column) |
90 | q->setColumnCount(column + 1); |
91 | int index = childIndex(row, column); |
92 | Q_ASSERT(index != -1); |
93 | QStandardItem *oldItem = children.at(i: index); |
94 | if (item == oldItem) |
95 | return; |
96 | |
97 | if (model && emitChanged) { |
98 | emit model->layoutAboutToBeChanged(); |
99 | } |
100 | |
101 | if (item) { |
102 | if (item->d_func()->parent == nullptr) { |
103 | item->d_func()->setParentAndModel(par: q, mod: model); |
104 | } else { |
105 | qWarning(msg: "QStandardItem::setChild: Ignoring duplicate insertion of item %p", |
106 | item); |
107 | return; |
108 | } |
109 | } |
110 | |
111 | // setting the model to nullptr invalidates the persistent index which we want to avoid |
112 | if (!item && oldItem) |
113 | oldItem->d_func()->setModel(nullptr); |
114 | |
115 | children.replace(i: index, t: item); |
116 | |
117 | // since now indexFromItem() does no longer return a valid index, the persistent index |
118 | // will not be invalidated anymore |
119 | if (oldItem) |
120 | oldItem->d_func()->setModel(nullptr); |
121 | delete oldItem; |
122 | |
123 | if (item) |
124 | item->d_func()->lastKnownIndex = index; |
125 | |
126 | if (model && emitChanged) |
127 | emit model->layoutChanged(); |
128 | |
129 | if (emitChanged && model) { |
130 | if (item) { |
131 | model->d_func()->itemChanged(item); |
132 | } else { |
133 | const QModelIndex idx = model->index(row, column, parent: q->index()); |
134 | emit model->dataChanged(topLeft: idx, bottomRight: idx); |
135 | } |
136 | } |
137 | } |
138 | |
139 | |
140 | /*! |
141 | \internal |
142 | */ |
143 | void QStandardItemPrivate::changeFlags(bool enable, Qt::ItemFlags f) |
144 | { |
145 | Q_Q(QStandardItem); |
146 | Qt::ItemFlags flags = q->flags(); |
147 | if (enable) |
148 | flags |= f; |
149 | else |
150 | flags &= ~f; |
151 | q->setFlags(flags); |
152 | } |
153 | |
154 | /*! |
155 | \internal |
156 | */ |
157 | void QStandardItemPrivate::childDeleted(QStandardItem *child) |
158 | { |
159 | int index = childIndex(child); |
160 | Q_ASSERT(index != -1); |
161 | const auto modelIndex = child->index(); |
162 | children.replace(i: index, t: nullptr); |
163 | emit model->dataChanged(topLeft: modelIndex, bottomRight: modelIndex); |
164 | } |
165 | |
166 | namespace { |
167 | |
168 | struct ByNormalizedRole |
169 | { |
170 | static int normalizedRole(int role) |
171 | { |
172 | return role == Qt::EditRole ? Qt::DisplayRole : role; |
173 | } |
174 | |
175 | bool operator()(const QStandardItemData& standardItemData, const std::pair<const int &, const QVariant&>& roleMapIt) const |
176 | { |
177 | return standardItemData.role < normalizedRole(role: roleMapIt.first); |
178 | } |
179 | bool operator()(const std::pair<const int&, const QVariant &>& roleMapIt, const QStandardItemData& standardItemData) const |
180 | { |
181 | return normalizedRole(role: roleMapIt.first) < standardItemData.role; |
182 | } |
183 | |
184 | }; |
185 | |
186 | /* |
187 | Based on std::transform with a twist. The inputs are iterators of <int, QVariant> pair. |
188 | The variant is checked for validity and if not valid, that element is not taken into account |
189 | which means that the resulting output might be shorter than the input. |
190 | */ |
191 | template<class Input, class OutputIt> |
192 | OutputIt roleMapStandardItemDataTransform(Input first1, Input last1, OutputIt d_first) |
193 | { |
194 | while (first1 != last1) { |
195 | if ((*first1).second.isValid()) |
196 | *d_first++ = QStandardItemData(*first1); |
197 | ++first1; |
198 | } |
199 | return d_first; |
200 | } |
201 | |
202 | |
203 | /* |
204 | Based on std::set_union with a twist. The idea is to create a union of both inputs |
205 | with an additional constraint: if an input contains an invalid variant, it means |
206 | that this one should not be taken into account for generating the output. |
207 | */ |
208 | template<class Input1, class Input2, |
209 | class OutputIt, class Compare> |
210 | OutputIt roleMapStandardItemDataUnion(Input1 first1, Input1 last1, |
211 | Input2 first2, Input2 last2, |
212 | OutputIt d_first, Compare comp) |
213 | { |
214 | for (; first1 != last1; ++d_first) { |
215 | if (first2 == last2) { |
216 | return roleMapStandardItemDataTransform(first1, last1, d_first); |
217 | } |
218 | if (comp(*first2, *first1)) { |
219 | *d_first = *first2++; |
220 | } else { |
221 | if ((*first1).second.isValid()) |
222 | *d_first = QStandardItemData(*first1); |
223 | if (!comp(*first1, *first2)) |
224 | ++first2; |
225 | ++first1; |
226 | } |
227 | } |
228 | return std::copy(first2, last2, d_first); |
229 | } |
230 | } |
231 | |
232 | /*! |
233 | \internal |
234 | */ |
235 | void QStandardItemPrivate::setItemData(const QMap<int, QVariant> &roles) |
236 | { |
237 | Q_Q(QStandardItem); |
238 | |
239 | auto byRole = [](const QStandardItemData& item1, const QStandardItemData& item2) { |
240 | return item1.role < item2.role; |
241 | }; |
242 | |
243 | std::sort(first: values.begin(), last: values.end(), comp: byRole); |
244 | |
245 | /* |
246 | Create a list of QStandardItemData that will contain the original values |
247 | if the matching role is not contained in roles, the new value if it is and |
248 | if the new value is an invalid QVariant, it will be removed. |
249 | */ |
250 | QList<QStandardItemData> newValues; |
251 | newValues.reserve(asize: values.size()); |
252 | roleMapStandardItemDataUnion(first1: roles.keyValueBegin(), |
253 | last1: roles.keyValueEnd(), |
254 | first2: values.cbegin(), last2: values.cend(), |
255 | d_first: std::back_inserter(x&: newValues), comp: ByNormalizedRole()); |
256 | |
257 | if (newValues != values) { |
258 | values.swap(other&: newValues); |
259 | if (model) { |
260 | QList<int> roleKeys; |
261 | roleKeys.reserve(asize: roles.size() + 1); |
262 | bool hasEditRole = false; |
263 | bool hasDisplayRole = false; |
264 | for (auto it = roles.keyBegin(); it != roles.keyEnd(); ++it) { |
265 | roleKeys.push_back(t: *it); |
266 | if (*it == Qt::EditRole) |
267 | hasEditRole = true; |
268 | else if (*it == Qt::DisplayRole) |
269 | hasDisplayRole = true; |
270 | } |
271 | if (hasEditRole && !hasDisplayRole) |
272 | roleKeys.push_back(t: Qt::DisplayRole); |
273 | else if (!hasEditRole && hasDisplayRole) |
274 | roleKeys.push_back(t: Qt::EditRole); |
275 | model->d_func()->itemChanged(item: q, roles: roleKeys); |
276 | } |
277 | } |
278 | } |
279 | |
280 | /*! |
281 | \internal |
282 | */ |
283 | QMap<int, QVariant> QStandardItemPrivate::itemData() const |
284 | { |
285 | QMap<int, QVariant> result; |
286 | for (const auto &data : values) { |
287 | if (data.role != DataFlagsRole) |
288 | result.insert(key: data.role, value: data.value); |
289 | } |
290 | return result; |
291 | } |
292 | |
293 | /*! |
294 | \internal |
295 | */ |
296 | void QStandardItemPrivate::sortChildren(int column, Qt::SortOrder order) |
297 | { |
298 | Q_Q(QStandardItem); |
299 | if (column >= columnCount()) |
300 | return; |
301 | |
302 | QList<QPair<QStandardItem*, int> > sortable; |
303 | QList<int> unsortable; |
304 | |
305 | sortable.reserve(asize: rowCount()); |
306 | unsortable.reserve(asize: rowCount()); |
307 | |
308 | for (int row = 0; row < rowCount(); ++row) { |
309 | QStandardItem *itm = q->child(row, column); |
310 | if (itm) |
311 | sortable.append(t: QPair<QStandardItem*,int>(itm, row)); |
312 | else |
313 | unsortable.append(t: row); |
314 | } |
315 | |
316 | if (order == Qt::AscendingOrder) { |
317 | QStandardItemModelLessThan lt; |
318 | std::stable_sort(first: sortable.begin(), last: sortable.end(), comp: lt); |
319 | } else { |
320 | QStandardItemModelGreaterThan gt; |
321 | std::stable_sort(first: sortable.begin(), last: sortable.end(), comp: gt); |
322 | } |
323 | |
324 | QModelIndexList changedPersistentIndexesFrom, changedPersistentIndexesTo; |
325 | QList<QStandardItem*> sorted_children(children.size()); |
326 | for (int i = 0; i < rowCount(); ++i) { |
327 | int r = (i < sortable.size() |
328 | ? sortable.at(i).second |
329 | : unsortable.at(i: i - sortable.size())); |
330 | for (int c = 0; c < columnCount(); ++c) { |
331 | QStandardItem *itm = q->child(row: r, column: c); |
332 | sorted_children[childIndex(row: i, column: c)] = itm; |
333 | if (model) { |
334 | QModelIndex from = model->createIndex(arow: r, acolumn: c, adata: q); |
335 | if (model->d_func()->persistent.indexes.contains(key: from)) { |
336 | QModelIndex to = model->createIndex(arow: i, acolumn: c, adata: q); |
337 | changedPersistentIndexesFrom.append(t: from); |
338 | changedPersistentIndexesTo.append(t: to); |
339 | } |
340 | } |
341 | } |
342 | } |
343 | |
344 | children = sorted_children; |
345 | |
346 | if (model) { |
347 | model->changePersistentIndexList(from: changedPersistentIndexesFrom, to: changedPersistentIndexesTo); |
348 | } |
349 | |
350 | QList<QStandardItem*>::iterator it; |
351 | for (it = children.begin(); it != children.end(); ++it) { |
352 | if (*it) |
353 | (*it)->d_func()->sortChildren(column, order); |
354 | } |
355 | } |
356 | |
357 | /*! |
358 | \internal |
359 | set the model of this item and all its children |
360 | */ |
361 | void QStandardItemPrivate::setModel(QStandardItemModel *mod) |
362 | { |
363 | if (children.isEmpty()) { |
364 | if (model) |
365 | model->d_func()->invalidatePersistentIndex(index: model->indexFromItem(item: q_ptr)); |
366 | model = mod; |
367 | } else { |
368 | QStack<QStandardItem*> stack; |
369 | stack.push(t: q_ptr); |
370 | while (!stack.isEmpty()) { |
371 | QStandardItem *itm = stack.pop(); |
372 | if (itm->d_func()->model) { |
373 | itm->d_func()->model->d_func()->invalidatePersistentIndex(index: itm->d_func()->model->indexFromItem(item: itm)); |
374 | } |
375 | itm->d_func()->model = mod; |
376 | const QList<QStandardItem*> &childList = itm->d_func()->children; |
377 | for (int i = 0; i < childList.size(); ++i) { |
378 | QStandardItem *chi = childList.at(i); |
379 | if (chi) |
380 | stack.push(t: chi); |
381 | } |
382 | } |
383 | } |
384 | } |
385 | |
386 | /*! |
387 | \internal |
388 | */ |
389 | QStandardItemModelPrivate::QStandardItemModelPrivate() |
390 | : root(new QStandardItem), itemPrototype(nullptr) |
391 | { |
392 | root->setFlags(Qt::ItemIsDropEnabled); |
393 | } |
394 | |
395 | /*! |
396 | \internal |
397 | */ |
398 | QStandardItemModelPrivate::~QStandardItemModelPrivate() |
399 | { |
400 | } |
401 | |
402 | /*! |
403 | \internal |
404 | */ |
405 | void QStandardItemModelPrivate::init() |
406 | { |
407 | Q_Q(QStandardItemModel); |
408 | QObject::connect(sender: q, SIGNAL(dataChanged(QModelIndex,QModelIndex)), |
409 | receiver: q, SLOT(_q_emitItemChanged(QModelIndex,QModelIndex))); |
410 | roleNames = QAbstractItemModelPrivate::defaultRoleNames(); |
411 | } |
412 | |
413 | /*! |
414 | \internal |
415 | */ |
416 | void QStandardItemModelPrivate::_q_emitItemChanged(const QModelIndex &topLeft, |
417 | const QModelIndex &bottomRight) |
418 | { |
419 | Q_Q(QStandardItemModel); |
420 | QModelIndex parent = topLeft.parent(); |
421 | for (int row = topLeft.row(); row <= bottomRight.row(); ++row) { |
422 | for (int column = topLeft.column(); column <= bottomRight.column(); ++column) { |
423 | QModelIndex index = q->index(row, column, parent); |
424 | if (QStandardItem *item = itemFromIndex(index)) |
425 | emit q->itemChanged(item); |
426 | } |
427 | } |
428 | } |
429 | |
430 | /*! |
431 | \internal |
432 | */ |
433 | bool QStandardItemPrivate::insertRows(int row, const QList<QStandardItem*> &items) |
434 | { |
435 | Q_Q(QStandardItem); |
436 | if ((row < 0) || (row > rowCount()) || items.isEmpty()) |
437 | return false; |
438 | int count = items.size(); |
439 | if (model) |
440 | model->d_func()->rowsAboutToBeInserted(parent: q, start: row, end: row + count - 1); |
441 | if (rowCount() == 0) { |
442 | if (columnCount() == 0) |
443 | q->setColumnCount(1); |
444 | children.resize(size: columnCount() * count); |
445 | rows = count; |
446 | } else { |
447 | rows += count; |
448 | int index = childIndex(row, column: 0); |
449 | if (index != -1) |
450 | children.insert(i: index, n: columnCount() * count, t: nullptr); |
451 | } |
452 | for (int i = 0; i < items.size(); ++i) { |
453 | QStandardItem *item = items.at(i); |
454 | item->d_func()->model = model; |
455 | item->d_func()->parent = q; |
456 | int index = childIndex(row: i + row, column: 0); |
457 | children.replace(i: index, t: item); |
458 | if (item) |
459 | item->d_func()->lastKnownIndex = index; |
460 | } |
461 | if (model) |
462 | model->d_func()->rowsInserted(parent: q, row, count); |
463 | return true; |
464 | } |
465 | |
466 | bool QStandardItemPrivate::insertRows(int row, int count, const QList<QStandardItem*> &items) |
467 | { |
468 | Q_Q(QStandardItem); |
469 | if ((count < 1) || (row < 0) || (row > rowCount()) || count == 0) |
470 | return false; |
471 | if (model) |
472 | model->d_func()->rowsAboutToBeInserted(parent: q, start: row, end: row + count - 1); |
473 | if (rowCount() == 0) { |
474 | children.resize(size: columnCount() * count); |
475 | rows = count; |
476 | } else { |
477 | rows += count; |
478 | int index = childIndex(row, column: 0); |
479 | if (index != -1) |
480 | children.insert(i: index, n: columnCount() * count, t: nullptr); |
481 | } |
482 | if (!items.isEmpty()) { |
483 | int index = childIndex(row, column: 0); |
484 | int limit = qMin(a: items.size(), b: columnCount() * count); |
485 | for (int i = 0; i < limit; ++i) { |
486 | QStandardItem *item = items.at(i); |
487 | if (item) { |
488 | if (item->d_func()->parent == nullptr) { |
489 | item->d_func()->setParentAndModel(par: q, mod: model); |
490 | } else { |
491 | qWarning(msg: "QStandardItem::insertRows: Ignoring duplicate insertion of item %p", |
492 | item); |
493 | item = nullptr; |
494 | } |
495 | } |
496 | children.replace(i: index, t: item); |
497 | if (item) |
498 | item->d_func()->lastKnownIndex = index; |
499 | ++index; |
500 | } |
501 | } |
502 | if (model) |
503 | model->d_func()->rowsInserted(parent: q, row, count); |
504 | return true; |
505 | } |
506 | |
507 | /*! |
508 | \internal |
509 | */ |
510 | bool QStandardItemPrivate::insertColumns(int column, int count, const QList<QStandardItem*> &items) |
511 | { |
512 | Q_Q(QStandardItem); |
513 | if ((count < 1) || (column < 0) || (column > columnCount()) || count == 0) |
514 | return false; |
515 | if (model) |
516 | model->d_func()->columnsAboutToBeInserted(parent: q, start: column, end: column + count - 1); |
517 | if (columnCount() == 0) { |
518 | children.resize(size: rowCount() * count); |
519 | columns = count; |
520 | } else { |
521 | columns += count; |
522 | int index = childIndex(row: 0, column); |
523 | for (int row = 0; row < rowCount(); ++row) { |
524 | children.insert(i: index, n: count, t: nullptr); |
525 | index += columnCount(); |
526 | } |
527 | } |
528 | if (!items.isEmpty()) { |
529 | int limit = qMin(a: items.size(), b: rowCount() * count); |
530 | for (int i = 0; i < limit; ++i) { |
531 | QStandardItem *item = items.at(i); |
532 | if (item) { |
533 | if (item->d_func()->parent == nullptr) { |
534 | item->d_func()->setParentAndModel(par: q, mod: model); |
535 | } else { |
536 | qWarning(msg: "QStandardItem::insertColumns: Ignoring duplicate insertion of item %p", |
537 | item); |
538 | item = nullptr; |
539 | } |
540 | } |
541 | int r = i / count; |
542 | int c = column + (i % count); |
543 | int index = childIndex(row: r, column: c); |
544 | children.replace(i: index, t: item); |
545 | if (item) |
546 | item->d_func()->lastKnownIndex = index; |
547 | } |
548 | } |
549 | if (model) |
550 | model->d_func()->columnsInserted(parent: q, column, count); |
551 | return true; |
552 | } |
553 | |
554 | /*! |
555 | \internal |
556 | */ |
557 | void QStandardItemModelPrivate::itemChanged(QStandardItem *item, const QList<int> &roles) |
558 | { |
559 | Q_Q(QStandardItemModel); |
560 | Q_ASSERT(item); |
561 | if (item->d_func()->parent == nullptr) { |
562 | // Header item |
563 | int idx = columnHeaderItems.indexOf(t: item); |
564 | if (idx != -1) { |
565 | emit q->headerDataChanged(orientation: Qt::Horizontal, first: idx, last: idx); |
566 | } else { |
567 | idx = rowHeaderItems.indexOf(t: item); |
568 | if (idx != -1) |
569 | emit q->headerDataChanged(orientation: Qt::Vertical, first: idx, last: idx); |
570 | } |
571 | } else { |
572 | // Normal item |
573 | const QModelIndex index = q->indexFromItem(item); |
574 | emit q->dataChanged(topLeft: index, bottomRight: index, roles); |
575 | } |
576 | } |
577 | |
578 | /*! |
579 | \internal |
580 | */ |
581 | void QStandardItemModelPrivate::rowsAboutToBeInserted(QStandardItem *parent, |
582 | int start, int end) |
583 | { |
584 | Q_Q(QStandardItemModel); |
585 | QModelIndex index = q->indexFromItem(item: parent); |
586 | q->beginInsertRows(parent: index, first: start, last: end); |
587 | } |
588 | |
589 | /*! |
590 | \internal |
591 | */ |
592 | void QStandardItemModelPrivate::columnsAboutToBeInserted(QStandardItem *parent, |
593 | int start, int end) |
594 | { |
595 | Q_Q(QStandardItemModel); |
596 | QModelIndex index = q->indexFromItem(item: parent); |
597 | q->beginInsertColumns(parent: index, first: start, last: end); |
598 | } |
599 | |
600 | /*! |
601 | \internal |
602 | */ |
603 | void QStandardItemModelPrivate::rowsAboutToBeRemoved(QStandardItem *parent, |
604 | int start, int end) |
605 | { |
606 | Q_Q(QStandardItemModel); |
607 | QModelIndex index = q->indexFromItem(item: parent); |
608 | q->beginRemoveRows(parent: index, first: start, last: end); |
609 | } |
610 | |
611 | /*! |
612 | \internal |
613 | */ |
614 | void QStandardItemModelPrivate::columnsAboutToBeRemoved(QStandardItem *parent, |
615 | int start, int end) |
616 | { |
617 | Q_Q(QStandardItemModel); |
618 | QModelIndex index = q->indexFromItem(item: parent); |
619 | q->beginRemoveColumns(parent: index, first: start, last: end); |
620 | } |
621 | |
622 | /*! |
623 | \internal |
624 | */ |
625 | void QStandardItemModelPrivate::rowsInserted(QStandardItem *parent, |
626 | int row, int count) |
627 | { |
628 | Q_Q(QStandardItemModel); |
629 | if (parent == root.data()) |
630 | rowHeaderItems.insert(i: row, n: count, t: nullptr); |
631 | q->endInsertRows(); |
632 | } |
633 | |
634 | /*! |
635 | \internal |
636 | */ |
637 | void QStandardItemModelPrivate::columnsInserted(QStandardItem *parent, |
638 | int column, int count) |
639 | { |
640 | Q_Q(QStandardItemModel); |
641 | if (parent == root.data()) |
642 | columnHeaderItems.insert(i: column, n: count, t: nullptr); |
643 | q->endInsertColumns(); |
644 | } |
645 | |
646 | /*! |
647 | \internal |
648 | */ |
649 | void QStandardItemModelPrivate::rowsRemoved(QStandardItem *parent, |
650 | int row, int count) |
651 | { |
652 | Q_Q(QStandardItemModel); |
653 | if (parent == root.data()) { |
654 | for (int i = row; i < row + count; ++i) { |
655 | QStandardItem *oldItem = rowHeaderItems.at(i); |
656 | if (oldItem) |
657 | oldItem->d_func()->setModel(nullptr); |
658 | delete oldItem; |
659 | } |
660 | rowHeaderItems.remove(i: row, n: count); |
661 | } |
662 | q->endRemoveRows(); |
663 | } |
664 | |
665 | /*! |
666 | \internal |
667 | */ |
668 | void QStandardItemModelPrivate::columnsRemoved(QStandardItem *parent, |
669 | int column, int count) |
670 | { |
671 | Q_Q(QStandardItemModel); |
672 | if (parent == root.data()) { |
673 | for (int i = column; i < column + count; ++i) { |
674 | QStandardItem *oldItem = columnHeaderItems.at(i); |
675 | if (oldItem) |
676 | oldItem->d_func()->setModel(nullptr); |
677 | delete oldItem; |
678 | } |
679 | columnHeaderItems.remove(i: column, n: count); |
680 | } |
681 | q->endRemoveColumns(); |
682 | } |
683 | |
684 | /*! |
685 | \class QStandardItem |
686 | \brief The QStandardItem class provides an item for use with the |
687 | QStandardItemModel class. |
688 | \since 4.2 |
689 | \ingroup model-view |
690 | \inmodule QtGui |
691 | |
692 | Items usually contain text, icons, or checkboxes. |
693 | |
694 | Each item can have its own background brush which is set with the |
695 | setBackground() function. The current background brush can be found with |
696 | background(). The text label for each item can be rendered with its own |
697 | font and brush. These are specified with the setFont() and setForeground() |
698 | functions, and read with font() and foreground(). |
699 | |
700 | By default, items are enabled, editable, selectable, checkable, and can be |
701 | used both as the source of a drag and drop operation and as a drop target. |
702 | Each item's flags can be changed by calling setFlags(). Checkable items |
703 | can be checked and unchecked with the setCheckState() function. The |
704 | corresponding checkState() function indicates whether the item is |
705 | currently checked. |
706 | |
707 | You can store application-specific data in an item by calling setData(). |
708 | |
709 | Each item can have a two-dimensional table of child items. This makes it |
710 | possible to build hierarchies of items. The typical hierarchy is the tree, |
711 | in which case the child table is a table with a single column (a list). |
712 | |
713 | The dimensions of the child table can be set with setRowCount() and |
714 | setColumnCount(). Items can be positioned in the child table with |
715 | setChild(). Get a pointer to a child item with child(). New rows and |
716 | columns of children can also be inserted with insertRow() and |
717 | insertColumn(), or appended with appendRow() and appendColumn(). When |
718 | using the append and insert functions, the dimensions of the child table |
719 | will grow as needed. |
720 | |
721 | An existing row of children can be removed with removeRow() or takeRow(); |
722 | correspondingly, a column can be removed with removeColumn() or |
723 | takeColumn(). |
724 | |
725 | An item's children can be sorted by calling sortChildren(). |
726 | |
727 | \section1 Subclassing |
728 | |
729 | When subclassing QStandardItem to provide custom items, it is possible to |
730 | define new types for them so that they can be distinguished from the base |
731 | class. The type() function should be reimplemented to return a new type |
732 | value equal to or greater than \l UserType. |
733 | |
734 | Reimplement data() and setData() if you want to perform custom handling of |
735 | data queries and/or control how an item's data is represented. |
736 | |
737 | Reimplement clone() if you want QStandardItemModel to be able to create |
738 | instances of your custom item class on demand (see |
739 | QStandardItemModel::setItemPrototype()). |
740 | |
741 | Reimplement read() and write() if you want to control how items are |
742 | represented in their serialized form. |
743 | |
744 | Reimplement \l{operator<()} if you want to control the semantics of item |
745 | comparison. \l{operator<()} determines the sorted order when sorting items |
746 | with sortChildren() or with QStandardItemModel::sort(). |
747 | |
748 | \sa QStandardItemModel, {Item View Convenience Classes}, {Model/View Programming} |
749 | */ |
750 | |
751 | /*! |
752 | \enum QStandardItem::ItemType |
753 | |
754 | This enum describes the types that are used to describe standard items. |
755 | |
756 | \value Type The default type for standard items. |
757 | \value UserType The minimum value for custom types. Values below UserType are |
758 | reserved by Qt. |
759 | |
760 | You can define new user types in QStandardItem subclasses to ensure that |
761 | custom items are treated specially; for example, when items are sorted. |
762 | |
763 | \sa type() |
764 | */ |
765 | |
766 | /*! |
767 | Constructs an item. |
768 | */ |
769 | QStandardItem::QStandardItem() |
770 | : QStandardItem(*new QStandardItemPrivate) |
771 | { |
772 | } |
773 | |
774 | /*! |
775 | Constructs an item with the given \a text. |
776 | */ |
777 | QStandardItem::QStandardItem(const QString &text) |
778 | : QStandardItem(*new QStandardItemPrivate) |
779 | { |
780 | setText(text); |
781 | } |
782 | |
783 | /*! |
784 | Constructs an item with the given \a icon and \a text. |
785 | */ |
786 | QStandardItem::QStandardItem(const QIcon &icon, const QString &text) |
787 | : QStandardItem(text) |
788 | { |
789 | setIcon(icon); |
790 | } |
791 | |
792 | /*! |
793 | Constructs an item with \a rows rows and \a columns columns of child items. |
794 | */ |
795 | QStandardItem::QStandardItem(int rows, int columns) |
796 | : QStandardItem(*new QStandardItemPrivate) |
797 | { |
798 | setRowCount(rows); |
799 | setColumnCount(columns); |
800 | } |
801 | |
802 | /*! |
803 | \internal |
804 | */ |
805 | QStandardItem::QStandardItem(QStandardItemPrivate &dd) |
806 | : d_ptr(&dd) |
807 | { |
808 | Q_D(QStandardItem); |
809 | d->q_ptr = this; |
810 | } |
811 | |
812 | /*! |
813 | Constructs a copy of \a other. Note that model() is |
814 | not copied. |
815 | |
816 | This function is useful when reimplementing clone(). |
817 | */ |
818 | QStandardItem::QStandardItem(const QStandardItem &other) |
819 | : d_ptr(new QStandardItemPrivate) |
820 | { |
821 | Q_D(QStandardItem); |
822 | d->q_ptr = this; |
823 | operator=(other); |
824 | } |
825 | |
826 | /*! |
827 | Assigns \a other's data and flags to this item. Note that |
828 | type() and model() are not copied. |
829 | |
830 | This function is useful when reimplementing clone(). |
831 | */ |
832 | QStandardItem &QStandardItem::operator=(const QStandardItem &other) |
833 | { |
834 | Q_D(QStandardItem); |
835 | d->values = other.d_func()->values; |
836 | return *this; |
837 | } |
838 | |
839 | /*! |
840 | Destructs the item. |
841 | This causes the item's children to be destructed as well. |
842 | */ |
843 | QStandardItem::~QStandardItem() |
844 | { |
845 | Q_D(QStandardItem); |
846 | for (QStandardItem *child : std::as_const(t&: d->children)) { |
847 | if (child) |
848 | child->d_func()->setModel(nullptr); |
849 | delete child; |
850 | } |
851 | d->children.clear(); |
852 | if (d->parent && d->model) |
853 | d->parent->d_func()->childDeleted(child: this); |
854 | } |
855 | |
856 | /*! |
857 | Returns the item's parent item, or \nullptr if the item has no parent. |
858 | \note For toplevel items parent() returns \nullptr. To receive toplevel |
859 | item's parent use QStandardItemModel::invisibleRootItem() instead. |
860 | |
861 | \sa child(), QStandardItemModel::invisibleRootItem() |
862 | */ |
863 | QStandardItem *QStandardItem::parent() const |
864 | { |
865 | Q_D(const QStandardItem); |
866 | if (!d->model || (d->model->d_func()->root.data() != d->parent)) |
867 | return d->parent; |
868 | return nullptr; |
869 | } |
870 | |
871 | /*! |
872 | Sets the item's data for the given \a role to the specified \a value. |
873 | |
874 | If you subclass QStandardItem and reimplement this function, your |
875 | reimplementation should: |
876 | \list |
877 | \li call emitDataChanged() if you do not call the base implementation of |
878 | setData(). This will ensure that e.g. views using the model are notified |
879 | of the changes |
880 | \li call the base implementation for roles you don't handle, otherwise |
881 | setting flags, e.g. by calling setFlags(), setCheckable(), setEditable() |
882 | etc., will not work. |
883 | \endlist |
884 | |
885 | \note The default implementation treats Qt::EditRole and Qt::DisplayRole |
886 | as referring to the same data. |
887 | |
888 | \sa Qt::ItemDataRole, data(), setFlags() |
889 | */ |
890 | void QStandardItem::setData(const QVariant &value, int role) |
891 | { |
892 | Q_D(QStandardItem); |
893 | role = (role == Qt::EditRole) ? Qt::DisplayRole : role; |
894 | const QList<int> roles((role == Qt::DisplayRole) ? |
895 | QList<int>({Qt::DisplayRole, Qt::EditRole}) : |
896 | QList<int>({role})); |
897 | for (auto it = d->values.begin(); it != d->values.end(); ++it) { |
898 | if ((*it).role == role) { |
899 | if (value.isValid()) { |
900 | if ((*it).value.userType() == value.userType() && (*it).value == value) |
901 | return; |
902 | (*it).value = value; |
903 | } else { |
904 | // Don't need to assign proper it after erase() since we |
905 | // return unconditionally in this code path. |
906 | d->values.erase(pos: it); |
907 | } |
908 | if (d->model) |
909 | d->model->d_func()->itemChanged(item: this, roles); |
910 | return; |
911 | } |
912 | } |
913 | d->values.append(t: QStandardItemData(role, value)); |
914 | if (d->model) |
915 | d->model->d_func()->itemChanged(item: this, roles); |
916 | } |
917 | |
918 | /*! |
919 | \since 5.12 |
920 | Removes all the data from all roles previously set. |
921 | \sa data(), setData() |
922 | */ |
923 | void QStandardItem::clearData() |
924 | { |
925 | Q_D(QStandardItem); |
926 | if (d->values.isEmpty()) |
927 | return; |
928 | d->values.clear(); |
929 | if (d->model) |
930 | d->model->d_func()->itemChanged(item: this, roles: QList<int>{}); |
931 | } |
932 | |
933 | /*! |
934 | Returns the item's data for the given \a role, or an invalid |
935 | QVariant if there is no data for the role. |
936 | |
937 | If you reimplement this function, your reimplementation should call |
938 | the base implementation for roles you don't handle, otherwise getting |
939 | flags, e.g. by calling flags(), isCheckable(), isEditable() etc., |
940 | will not work. |
941 | |
942 | \note The default implementation treats Qt::EditRole and Qt::DisplayRole |
943 | as referring to the same data. |
944 | */ |
945 | QVariant QStandardItem::data(int role) const |
946 | { |
947 | Q_D(const QStandardItem); |
948 | const int r = (role == Qt::EditRole) ? Qt::DisplayRole : role; |
949 | for (const auto &value : d->values) { |
950 | if (value.role == r) |
951 | return value.value; |
952 | } |
953 | return QVariant(); |
954 | } |
955 | |
956 | /*! |
957 | \since 6.0 |
958 | |
959 | Fills the \a roleDataSpan span with the data from this item. |
960 | |
961 | The default implementation simply calls data() for each role |
962 | in the span. |
963 | |
964 | \sa data() |
965 | */ |
966 | void QStandardItem::multiData(QModelRoleDataSpan roleDataSpan) const |
967 | { |
968 | for (auto &roleData : roleDataSpan) |
969 | roleData.setData(data(role: roleData.role())); |
970 | } |
971 | |
972 | /*! |
973 | \since 4.4 |
974 | |
975 | Causes the model associated with this item to emit a |
976 | \l{QAbstractItemModel::dataChanged()}{dataChanged}() signal for this |
977 | item. |
978 | |
979 | You normally only need to call this function if you have subclassed |
980 | QStandardItem and reimplemented data() and/or setData(). |
981 | |
982 | \sa setData() |
983 | */ |
984 | void QStandardItem::emitDataChanged() |
985 | { |
986 | Q_D(QStandardItem); |
987 | if (d->model) |
988 | d->model->d_func()->itemChanged(item: this); |
989 | } |
990 | |
991 | /*! |
992 | Sets the item flags for the item to \a flags. |
993 | |
994 | The item flags determine how the user can interact with the item. |
995 | This is often used to disable an item. |
996 | |
997 | \sa flags(), setData() |
998 | */ |
999 | void QStandardItem::setFlags(Qt::ItemFlags flags) |
1000 | { |
1001 | setData(value: (int)flags, role: DataFlagsRole); |
1002 | } |
1003 | |
1004 | /*! |
1005 | Returns the item flags for the item. |
1006 | |
1007 | The item flags determine how the user can interact with the item. |
1008 | |
1009 | By default, items are enabled, editable, selectable, checkable, and can be |
1010 | used both as the source of a drag and drop operation and as a drop target. |
1011 | |
1012 | \sa setFlags() |
1013 | */ |
1014 | Qt::ItemFlags QStandardItem::flags() const |
1015 | { |
1016 | QVariant v = data(role: DataFlagsRole); |
1017 | if (!v.isValid()) |
1018 | return (Qt::ItemIsSelectable|Qt::ItemIsEnabled|Qt::ItemIsEditable |
1019 | |Qt::ItemIsDragEnabled|Qt::ItemIsDropEnabled); |
1020 | return Qt::ItemFlags(v.toInt()); |
1021 | } |
1022 | |
1023 | /*! |
1024 | \fn QString QStandardItem::text() const |
1025 | |
1026 | Returns the item's text. This is the text that's presented to the user |
1027 | in a view. |
1028 | |
1029 | \sa setText() |
1030 | */ |
1031 | |
1032 | /*! |
1033 | \fn void QStandardItem::setText(const QString &text) |
1034 | |
1035 | Sets the item's text to the \a text specified. |
1036 | |
1037 | \sa text(), setFont(), setForeground() |
1038 | */ |
1039 | |
1040 | /*! |
1041 | \fn QIcon QStandardItem::icon() const |
1042 | |
1043 | Returns the item's icon. |
1044 | |
1045 | \sa setIcon(), {QAbstractItemView::iconSize}{iconSize} |
1046 | */ |
1047 | |
1048 | /*! |
1049 | \fn void QStandardItem::setIcon(const QIcon &icon) |
1050 | |
1051 | Sets the item's icon to the \a icon specified. |
1052 | */ |
1053 | |
1054 | /*! |
1055 | \fn QString QStandardItem::statusTip() const |
1056 | |
1057 | Returns the item's status tip. |
1058 | |
1059 | \sa setStatusTip(), toolTip(), whatsThis() |
1060 | */ |
1061 | |
1062 | /*! |
1063 | \fn void QStandardItem::setStatusTip(const QString &statusTip) |
1064 | |
1065 | Sets the item's status tip to the string specified by \a statusTip. |
1066 | |
1067 | \sa statusTip(), setToolTip(), setWhatsThis() |
1068 | */ |
1069 | |
1070 | /*! |
1071 | \fn QString QStandardItem::toolTip() const |
1072 | |
1073 | Returns the item's tooltip. |
1074 | |
1075 | \sa setToolTip(), statusTip(), whatsThis() |
1076 | */ |
1077 | |
1078 | /*! |
1079 | \fn void QStandardItem::setToolTip(const QString &toolTip) |
1080 | |
1081 | Sets the item's tooltip to the string specified by \a toolTip. |
1082 | |
1083 | \sa toolTip(), setStatusTip(), setWhatsThis() |
1084 | */ |
1085 | |
1086 | /*! |
1087 | \fn QString QStandardItem::whatsThis() const |
1088 | |
1089 | Returns the item's "What's This?" help. |
1090 | |
1091 | \sa setWhatsThis(), toolTip(), statusTip() |
1092 | */ |
1093 | |
1094 | /*! |
1095 | \fn void QStandardItem::setWhatsThis(const QString &whatsThis) |
1096 | |
1097 | Sets the item's "What's This?" help to the string specified by \a whatsThis. |
1098 | |
1099 | \sa whatsThis(), setStatusTip(), setToolTip() |
1100 | */ |
1101 | |
1102 | /*! |
1103 | \fn QFont QStandardItem::font() const |
1104 | |
1105 | Returns the font used to render the item's text. |
1106 | |
1107 | \sa setFont() |
1108 | */ |
1109 | |
1110 | /*! |
1111 | \fn void QStandardItem::setFont(const QFont &font) |
1112 | |
1113 | Sets the font used to display the item's text to the given \a font. |
1114 | |
1115 | \sa font(), setText(), setForeground() |
1116 | */ |
1117 | |
1118 | /*! |
1119 | \fn QBrush QStandardItem::background() const |
1120 | |
1121 | Returns the brush used to render the item's background. |
1122 | |
1123 | \sa foreground(), setBackground() |
1124 | */ |
1125 | |
1126 | /*! |
1127 | \fn void QStandardItem::setBackground(const QBrush &brush) |
1128 | |
1129 | Sets the item's background brush to the specified \a brush. |
1130 | |
1131 | \sa background(), setForeground() |
1132 | */ |
1133 | |
1134 | /*! |
1135 | \fn QBrush QStandardItem::foreground() const |
1136 | |
1137 | Returns the brush used to render the item's foreground (e.g. text). |
1138 | |
1139 | \sa setForeground(), background() |
1140 | */ |
1141 | |
1142 | /*! |
1143 | \fn void QStandardItem::setForeground(const QBrush &brush) |
1144 | |
1145 | Sets the brush used to display the item's foreground (e.g. text) to the |
1146 | given \a brush. |
1147 | |
1148 | \sa foreground(), setBackground(), setFont() |
1149 | */ |
1150 | |
1151 | /*! |
1152 | \fn int QStandardItem::textAlignment() const |
1153 | |
1154 | Returns the text alignment for the item's text. |
1155 | */ |
1156 | |
1157 | /*! |
1158 | \fn void QStandardItem::setTextAlignment(Qt::Alignment alignment) |
1159 | |
1160 | Sets the text alignment for the item's text to the \a alignment |
1161 | specified. |
1162 | |
1163 | \sa textAlignment() |
1164 | */ |
1165 | |
1166 | /*! |
1167 | \fn QSize QStandardItem::sizeHint() const |
1168 | |
1169 | Returns the size hint set for the item, or an invalid QSize if no |
1170 | size hint has been set. |
1171 | |
1172 | If no size hint has been set, the item delegate will compute the |
1173 | size hint based on the item data. |
1174 | |
1175 | \sa setSizeHint() |
1176 | */ |
1177 | |
1178 | /*! |
1179 | \fn void QStandardItem::setSizeHint(const QSize &size) |
1180 | |
1181 | Sets the size hint for the item to be \a size. |
1182 | If no size hint is set, the item delegate will compute the |
1183 | size hint based on the item data. |
1184 | |
1185 | \sa sizeHint() |
1186 | */ |
1187 | |
1188 | /*! |
1189 | \fn Qt::CheckState QStandardItem::checkState() const |
1190 | |
1191 | Returns the checked state of the item. |
1192 | |
1193 | \sa setCheckState(), isCheckable() |
1194 | */ |
1195 | |
1196 | /*! |
1197 | \fn void QStandardItem::setCheckState(Qt::CheckState state) |
1198 | |
1199 | Sets the check state of the item to be \a state. |
1200 | |
1201 | \sa checkState(), setCheckable() |
1202 | */ |
1203 | |
1204 | /*! |
1205 | \fn QString QStandardItem::accessibleText() const |
1206 | |
1207 | Returns the item's accessible text. |
1208 | |
1209 | The accessible text is used by assistive technologies (i.e. for users who |
1210 | cannot use conventional means of interaction). |
1211 | |
1212 | \sa setAccessibleText(), accessibleDescription() |
1213 | */ |
1214 | |
1215 | /*! |
1216 | \fn void QStandardItem::setAccessibleText(const QString &accessibleText) |
1217 | |
1218 | Sets the item's accessible text to the string specified by \a accessibleText. |
1219 | |
1220 | The accessible text is used by assistive technologies (i.e. for users who |
1221 | cannot use conventional means of interaction). |
1222 | |
1223 | \sa accessibleText(), setAccessibleDescription() |
1224 | */ |
1225 | |
1226 | /*! |
1227 | \fn QString QStandardItem::accessibleDescription() const |
1228 | |
1229 | Returns the item's accessible description. |
1230 | |
1231 | The accessible description is used by assistive technologies (i.e. for |
1232 | users who cannot use conventional means of interaction). |
1233 | |
1234 | \sa setAccessibleDescription(), accessibleText() |
1235 | */ |
1236 | |
1237 | /*! |
1238 | \fn void QStandardItem::setAccessibleDescription(const QString &accessibleDescription) |
1239 | |
1240 | Sets the item's accessible description to the string specified by \a |
1241 | accessibleDescription. |
1242 | |
1243 | The accessible description is used by assistive technologies (i.e. for |
1244 | users who cannot use conventional means of interaction). |
1245 | |
1246 | \sa accessibleDescription(), setAccessibleText() |
1247 | */ |
1248 | |
1249 | /*! |
1250 | Sets whether the item is enabled. If \a enabled is true, the item is enabled, |
1251 | meaning that the user can interact with the item; if \a enabled is false, the |
1252 | user cannot interact with the item. |
1253 | |
1254 | This flag takes precedence over the other item flags; e.g. if an item is not |
1255 | enabled, it cannot be selected by the user, even if the Qt::ItemIsSelectable |
1256 | flag has been set. |
1257 | |
1258 | \sa isEnabled(), Qt::ItemIsEnabled, setFlags() |
1259 | */ |
1260 | void QStandardItem::setEnabled(bool enabled) |
1261 | { |
1262 | Q_D(QStandardItem); |
1263 | d->changeFlags(enable: enabled, f: Qt::ItemIsEnabled); |
1264 | } |
1265 | |
1266 | /*! |
1267 | \fn bool QStandardItem::isEnabled() const |
1268 | |
1269 | Returns whether the item is enabled. |
1270 | |
1271 | When an item is enabled, the user can interact with it. The possible |
1272 | types of interaction are specified by the other item flags, such as |
1273 | isEditable() and isSelectable(). |
1274 | |
1275 | The default value is true. |
1276 | |
1277 | \sa setEnabled(), flags() |
1278 | */ |
1279 | |
1280 | /*! |
1281 | Sets whether the item is editable. If \a editable is true, the item can be |
1282 | edited by the user; otherwise, the user cannot edit the item. |
1283 | |
1284 | How the user can edit items in a view is determined by the view's edit |
1285 | triggers; see QAbstractItemView::editTriggers. |
1286 | |
1287 | \sa isEditable(), setFlags() |
1288 | */ |
1289 | void QStandardItem::setEditable(bool editable) |
1290 | { |
1291 | Q_D(QStandardItem); |
1292 | d->changeFlags(enable: editable, f: Qt::ItemIsEditable); |
1293 | } |
1294 | |
1295 | /*! |
1296 | \fn bool QStandardItem::isEditable() const |
1297 | |
1298 | Returns whether the item can be edited by the user. |
1299 | |
1300 | When an item is editable (and enabled), the user can edit the item by |
1301 | invoking one of the view's edit triggers; see |
1302 | QAbstractItemView::editTriggers. |
1303 | |
1304 | The default value is true. |
1305 | |
1306 | \sa setEditable(), flags() |
1307 | */ |
1308 | |
1309 | /*! |
1310 | Sets whether the item is selectable. If \a selectable is true, the item |
1311 | can be selected by the user; otherwise, the user cannot select the item. |
1312 | |
1313 | You can control the selection behavior and mode by manipulating their |
1314 | view properties; see QAbstractItemView::selectionMode and |
1315 | QAbstractItemView::selectionBehavior. |
1316 | |
1317 | \sa isSelectable(), setFlags() |
1318 | */ |
1319 | void QStandardItem::setSelectable(bool selectable) |
1320 | { |
1321 | Q_D(QStandardItem); |
1322 | d->changeFlags(enable: selectable, f: Qt::ItemIsSelectable); |
1323 | } |
1324 | |
1325 | /*! |
1326 | \fn bool QStandardItem::isSelectable() const |
1327 | |
1328 | Returns whether the item is selectable by the user. |
1329 | |
1330 | The default value is true. |
1331 | |
1332 | \sa setSelectable(), flags() |
1333 | */ |
1334 | |
1335 | /*! |
1336 | Sets whether the item is user-checkable. If \a checkable is true, the |
1337 | item can be checked by the user; otherwise, the user cannot check |
1338 | the item. |
1339 | |
1340 | The item delegate will render a checkable item with a check box next to the |
1341 | item's text. |
1342 | |
1343 | \sa isCheckable(), setCheckState(), setUserTristate(), setAutoTristate() |
1344 | */ |
1345 | void QStandardItem::setCheckable(bool checkable) |
1346 | { |
1347 | Q_D(QStandardItem); |
1348 | if (checkable && !isCheckable()) { |
1349 | // make sure there's data for the checkstate role |
1350 | if (!data(role: Qt::CheckStateRole).isValid()) |
1351 | setData(value: Qt::Unchecked, role: Qt::CheckStateRole); |
1352 | } |
1353 | d->changeFlags(enable: checkable, f: Qt::ItemIsUserCheckable); |
1354 | } |
1355 | |
1356 | /*! |
1357 | \fn bool QStandardItem::isCheckable() const |
1358 | |
1359 | Returns whether the item is user-checkable. |
1360 | |
1361 | The default value is false. |
1362 | |
1363 | \sa setCheckable(), checkState(), isUserTristate(), isAutoTristate() |
1364 | */ |
1365 | |
1366 | /*! |
1367 | Determines that the item is tristate and controlled by QTreeWidget if \a tristate |
1368 | is \c true. |
1369 | This enables automatic management of the state of parent items in QTreeWidget |
1370 | (checked if all children are checked, unchecked if all children are unchecked, |
1371 | or partially checked if only some children are checked). |
1372 | |
1373 | \since 5.6 |
1374 | \sa isAutoTristate(), setCheckable(), setCheckState() |
1375 | */ |
1376 | void QStandardItem::setAutoTristate(bool tristate) |
1377 | { |
1378 | Q_D(QStandardItem); |
1379 | d->changeFlags(enable: tristate, f: Qt::ItemIsAutoTristate); |
1380 | } |
1381 | |
1382 | /*! |
1383 | \fn bool QStandardItem::isAutoTristate() const |
1384 | |
1385 | Returns whether the item is tristate and is controlled by QTreeWidget. |
1386 | |
1387 | The default value is false. |
1388 | |
1389 | \since 5.6 |
1390 | \sa setAutoTristate(), isCheckable(), checkState() |
1391 | */ |
1392 | |
1393 | /*! |
1394 | Sets whether the item is tristate and controlled by the user. |
1395 | If \a tristate is true, the user can cycle through three separate states; |
1396 | otherwise, the item is checkable with two states. |
1397 | (Note that this also requires that the item is checkable; see isCheckable().) |
1398 | |
1399 | \since 5.6 |
1400 | \sa isUserTristate(), setCheckable(), setCheckState() |
1401 | */ |
1402 | void QStandardItem::setUserTristate(bool tristate) |
1403 | { |
1404 | Q_D(QStandardItem); |
1405 | d->changeFlags(enable: tristate, f: Qt::ItemIsUserTristate); |
1406 | } |
1407 | |
1408 | /*! |
1409 | \fn bool QStandardItem::isUserTristate() const |
1410 | \since 5.6 |
1411 | |
1412 | Returns whether the item is tristate; that is, if it's checkable with three |
1413 | separate states and the user can cycle through all three states. |
1414 | |
1415 | The default value is false. |
1416 | |
1417 | \sa setUserTristate(), isCheckable(), checkState() |
1418 | */ |
1419 | |
1420 | #if QT_CONFIG(draganddrop) |
1421 | |
1422 | /*! |
1423 | Sets whether the item is drag enabled. If \a dragEnabled is true, the item |
1424 | can be dragged by the user; otherwise, the user cannot drag the item. |
1425 | |
1426 | Note that you also need to ensure that item dragging is enabled in the view; |
1427 | see QAbstractItemView::dragEnabled. |
1428 | |
1429 | \sa isDragEnabled(), setDropEnabled(), setFlags() |
1430 | */ |
1431 | void QStandardItem::setDragEnabled(bool dragEnabled) |
1432 | { |
1433 | Q_D(QStandardItem); |
1434 | d->changeFlags(enable: dragEnabled, f: Qt::ItemIsDragEnabled); |
1435 | } |
1436 | |
1437 | /*! |
1438 | \fn bool QStandardItem::isDragEnabled() const |
1439 | |
1440 | Returns whether the item is drag enabled. An item that is drag enabled can |
1441 | be dragged by the user. |
1442 | |
1443 | The default value is true. |
1444 | |
1445 | Note that item dragging must be enabled in the view for dragging to work; |
1446 | see QAbstractItemView::dragEnabled. |
1447 | |
1448 | \sa setDragEnabled(), isDropEnabled(), flags() |
1449 | */ |
1450 | |
1451 | /*! |
1452 | Sets whether the item is drop enabled. If \a dropEnabled is true, the item |
1453 | can be used as a drop target; otherwise, it cannot. |
1454 | |
1455 | Note that you also need to ensure that drops are enabled in the view; see |
1456 | QWidget::acceptDrops(); and that the model supports the desired drop actions; |
1457 | see QAbstractItemModel::supportedDropActions(). |
1458 | |
1459 | \sa isDropEnabled(), setDragEnabled(), setFlags() |
1460 | */ |
1461 | void QStandardItem::setDropEnabled(bool dropEnabled) |
1462 | { |
1463 | Q_D(QStandardItem); |
1464 | d->changeFlags(enable: dropEnabled, f: Qt::ItemIsDropEnabled); |
1465 | } |
1466 | |
1467 | /*! |
1468 | \fn bool QStandardItem::isDropEnabled() const |
1469 | |
1470 | Returns whether the item is drop enabled. When an item is drop enabled, it |
1471 | can be used as a drop target. |
1472 | |
1473 | The default value is true. |
1474 | |
1475 | \sa setDropEnabled(), isDragEnabled(), flags() |
1476 | */ |
1477 | |
1478 | #endif // QT_CONFIG(draganddrop) |
1479 | |
1480 | /*! |
1481 | Returns the row where the item is located in its parent's child table, or |
1482 | -1 if the item has no parent. |
1483 | |
1484 | \sa column(), parent() |
1485 | */ |
1486 | int QStandardItem::row() const |
1487 | { |
1488 | Q_D(const QStandardItem); |
1489 | QPair<int, int> pos = d->position(); |
1490 | return pos.first; |
1491 | } |
1492 | |
1493 | /*! |
1494 | Returns the column where the item is located in its parent's child table, |
1495 | or -1 if the item has no parent. |
1496 | |
1497 | \sa row(), parent() |
1498 | */ |
1499 | int QStandardItem::column() const |
1500 | { |
1501 | Q_D(const QStandardItem); |
1502 | QPair<int, int> pos = d->position(); |
1503 | return pos.second; |
1504 | } |
1505 | |
1506 | /*! |
1507 | Returns the QModelIndex associated with this item. |
1508 | |
1509 | When you need to invoke item functionality in a QModelIndex-based API (e.g. |
1510 | QAbstractItemView), you can call this function to obtain an index that |
1511 | corresponds to the item's location in the model. |
1512 | |
1513 | If the item is not associated with a model, an invalid QModelIndex is |
1514 | returned. |
1515 | |
1516 | \sa model(), QStandardItemModel::itemFromIndex() |
1517 | */ |
1518 | QModelIndex QStandardItem::index() const |
1519 | { |
1520 | Q_D(const QStandardItem); |
1521 | return d->model ? d->model->indexFromItem(item: this) : QModelIndex(); |
1522 | } |
1523 | |
1524 | /*! |
1525 | Returns the QStandardItemModel that this item belongs to. |
1526 | |
1527 | If the item is not a child of another item that belongs to the model, this |
1528 | function returns \nullptr. |
1529 | |
1530 | \sa index() |
1531 | */ |
1532 | QStandardItemModel *QStandardItem::model() const |
1533 | { |
1534 | Q_D(const QStandardItem); |
1535 | return d->model; |
1536 | } |
1537 | |
1538 | /*! |
1539 | Sets the number of child item rows to \a rows. If this is less than |
1540 | rowCount(), the data in the unwanted rows is discarded. |
1541 | |
1542 | \sa rowCount(), setColumnCount() |
1543 | */ |
1544 | void QStandardItem::setRowCount(int rows) |
1545 | { |
1546 | int rc = rowCount(); |
1547 | if (rc == rows) |
1548 | return; |
1549 | if (rc < rows) |
1550 | insertRows(row: qMax(a: rc, b: 0), count: rows - rc); |
1551 | else |
1552 | removeRows(row: qMax(a: rows, b: 0), count: rc - rows); |
1553 | } |
1554 | |
1555 | /*! |
1556 | Returns the number of child item rows that the item has. |
1557 | |
1558 | \sa setRowCount(), columnCount() |
1559 | */ |
1560 | int QStandardItem::rowCount() const |
1561 | { |
1562 | Q_D(const QStandardItem); |
1563 | return d->rowCount(); |
1564 | } |
1565 | |
1566 | /*! |
1567 | Sets the number of child item columns to \a columns. If this is less than |
1568 | columnCount(), the data in the unwanted columns is discarded. |
1569 | |
1570 | \sa columnCount(), setRowCount() |
1571 | */ |
1572 | void QStandardItem::setColumnCount(int columns) |
1573 | { |
1574 | int cc = columnCount(); |
1575 | if (cc == columns) |
1576 | return; |
1577 | if (cc < columns) |
1578 | insertColumns(column: qMax(a: cc, b: 0), count: columns - cc); |
1579 | else |
1580 | removeColumns(column: qMax(a: columns, b: 0), count: cc - columns); |
1581 | } |
1582 | |
1583 | /*! |
1584 | Returns the number of child item columns that the item has. |
1585 | |
1586 | \sa setColumnCount(), rowCount() |
1587 | */ |
1588 | int QStandardItem::columnCount() const |
1589 | { |
1590 | Q_D(const QStandardItem); |
1591 | return d->columnCount(); |
1592 | } |
1593 | |
1594 | /*! |
1595 | Inserts a row at \a row containing \a items. If necessary, the column |
1596 | count is increased to the size of \a items. |
1597 | |
1598 | \sa insertRows(), insertColumn() |
1599 | */ |
1600 | void QStandardItem::insertRow(int row, const QList<QStandardItem*> &items) |
1601 | { |
1602 | Q_D(QStandardItem); |
1603 | if (row < 0) |
1604 | return; |
1605 | if (columnCount() < items.size()) |
1606 | setColumnCount(items.size()); |
1607 | d->insertRows(row, count: 1, items); |
1608 | } |
1609 | |
1610 | /*! |
1611 | Inserts \a items at \a row. The column count won't be changed. |
1612 | |
1613 | \sa insertRow(), insertColumn() |
1614 | */ |
1615 | void QStandardItem::insertRows(int row, const QList<QStandardItem*> &items) |
1616 | { |
1617 | Q_D(QStandardItem); |
1618 | if (row < 0) |
1619 | return; |
1620 | d->insertRows(row, items); |
1621 | } |
1622 | |
1623 | /*! |
1624 | Inserts a column at \a column containing \a items. If necessary, |
1625 | the row count is increased to the size of \a items. |
1626 | |
1627 | \sa insertColumns(), insertRow() |
1628 | */ |
1629 | void QStandardItem::insertColumn(int column, const QList<QStandardItem*> &items) |
1630 | { |
1631 | Q_D(QStandardItem); |
1632 | if (column < 0) |
1633 | return; |
1634 | if (rowCount() < items.size()) |
1635 | setRowCount(items.size()); |
1636 | d->insertColumns(column, count: 1, items); |
1637 | } |
1638 | |
1639 | /*! |
1640 | Inserts \a count rows of child items at row \a row. |
1641 | |
1642 | \sa insertRow(), insertColumns() |
1643 | */ |
1644 | void QStandardItem::insertRows(int row, int count) |
1645 | { |
1646 | Q_D(QStandardItem); |
1647 | if (rowCount() < row) { |
1648 | count += row - rowCount(); |
1649 | row = rowCount(); |
1650 | } |
1651 | d->insertRows(row, count, items: QList<QStandardItem*>()); |
1652 | } |
1653 | |
1654 | /*! |
1655 | Inserts \a count columns of child items at column \a column. |
1656 | |
1657 | \sa insertColumn(), insertRows() |
1658 | */ |
1659 | void QStandardItem::insertColumns(int column, int count) |
1660 | { |
1661 | Q_D(QStandardItem); |
1662 | if (columnCount() < column) { |
1663 | count += column - columnCount(); |
1664 | column = columnCount(); |
1665 | } |
1666 | d->insertColumns(column, count, items: QList<QStandardItem*>()); |
1667 | } |
1668 | |
1669 | /*! |
1670 | \fn void QStandardItem::appendRow(const QList<QStandardItem*> &items) |
1671 | |
1672 | Appends a row containing \a items. If necessary, the column count is |
1673 | increased to the size of \a items. |
1674 | |
1675 | \sa insertRow() |
1676 | */ |
1677 | |
1678 | /*! |
1679 | \fn void QStandardItem::appendRows(const QList<QStandardItem*> &items) |
1680 | |
1681 | Appends rows containing \a items. The column count will not change. |
1682 | |
1683 | \sa insertRow() |
1684 | */ |
1685 | |
1686 | /*! |
1687 | \fn void QStandardItem::appendColumn(const QList<QStandardItem*> &items) |
1688 | |
1689 | Appends a column containing \a items. If necessary, the row count is |
1690 | increased to the size of \a items. |
1691 | |
1692 | \sa insertColumn() |
1693 | */ |
1694 | |
1695 | /*! |
1696 | \fn bool QStandardItemModel::insertRow(int row, const QModelIndex &parent) |
1697 | |
1698 | Inserts a single row before the given \a row in the child items of the |
1699 | \a parent specified. Returns \c true if the row is inserted; otherwise |
1700 | returns \c false. |
1701 | |
1702 | \sa insertRows(), insertColumn(), removeRow() |
1703 | */ |
1704 | |
1705 | /*! |
1706 | \fn bool QStandardItemModel::insertColumn(int column, const QModelIndex &parent) |
1707 | |
1708 | Inserts a single column before the given \a column in the child items of |
1709 | the \a parent specified. Returns \c true if the column is inserted; otherwise |
1710 | returns \c false. |
1711 | |
1712 | \sa insertColumns(), insertRow(), removeColumn() |
1713 | */ |
1714 | |
1715 | /*! |
1716 | \fn QStandardItem::insertRow(int row, QStandardItem *item) |
1717 | \overload |
1718 | |
1719 | Inserts a row at \a row containing \a item. |
1720 | |
1721 | When building a list or a tree that has only one column, this function |
1722 | provides a convenient way to insert a single new item. |
1723 | */ |
1724 | |
1725 | /*! |
1726 | \fn QStandardItem::appendRow(QStandardItem *item) |
1727 | \overload |
1728 | |
1729 | Appends a row containing \a item. |
1730 | |
1731 | When building a list or a tree that has only one column, this function |
1732 | provides a convenient way to append a single new item. |
1733 | */ |
1734 | |
1735 | /*! |
1736 | Removes the given \a row. The items that were in the row are deleted. |
1737 | |
1738 | \sa takeRow(), removeRows(), removeColumn() |
1739 | */ |
1740 | void QStandardItem::removeRow(int row) |
1741 | { |
1742 | removeRows(row, count: 1); |
1743 | } |
1744 | |
1745 | /*! |
1746 | Removes the given \a column. The items that were in the |
1747 | column are deleted. |
1748 | |
1749 | \sa takeColumn(), removeColumns(), removeRow() |
1750 | */ |
1751 | void QStandardItem::removeColumn(int column) |
1752 | { |
1753 | removeColumns(column, count: 1); |
1754 | } |
1755 | |
1756 | /*! |
1757 | Removes \a count rows at row \a row. The items that were in those rows are |
1758 | deleted. |
1759 | |
1760 | \sa removeRow(), removeColumn() |
1761 | */ |
1762 | void QStandardItem::removeRows(int row, int count) |
1763 | { |
1764 | Q_D(QStandardItem); |
1765 | if ((count < 1) || (row < 0) || ((row + count) > rowCount())) |
1766 | return; |
1767 | if (d->model) |
1768 | d->model->d_func()->rowsAboutToBeRemoved(parent: this, start: row, end: row + count - 1); |
1769 | int i = d->childIndex(row, column: 0); |
1770 | int n = count * d->columnCount(); |
1771 | for (int j = i; j < n+i; ++j) { |
1772 | QStandardItem *oldItem = d->children.at(i: j); |
1773 | if (oldItem) |
1774 | oldItem->d_func()->setModel(nullptr); |
1775 | delete oldItem; |
1776 | } |
1777 | d->children.remove(i: qMax(a: i, b: 0), n); |
1778 | d->rows -= count; |
1779 | if (d->model) |
1780 | d->model->d_func()->rowsRemoved(parent: this, row, count); |
1781 | } |
1782 | |
1783 | /*! |
1784 | Removes \a count columns at column \a column. The items that were in those |
1785 | columns are deleted. |
1786 | |
1787 | \sa removeColumn(), removeRows() |
1788 | */ |
1789 | void QStandardItem::removeColumns(int column, int count) |
1790 | { |
1791 | Q_D(QStandardItem); |
1792 | if ((count < 1) || (column < 0) || ((column + count) > columnCount())) |
1793 | return; |
1794 | if (d->model) |
1795 | d->model->d_func()->columnsAboutToBeRemoved(parent: this, start: column, end: column + count - 1); |
1796 | for (int row = d->rowCount() - 1; row >= 0; --row) { |
1797 | int i = d->childIndex(row, column); |
1798 | for (int j=i; j<i+count; ++j) { |
1799 | QStandardItem *oldItem = d->children.at(i: j); |
1800 | if (oldItem) |
1801 | oldItem->d_func()->setModel(nullptr); |
1802 | delete oldItem; |
1803 | } |
1804 | d->children.remove(i, n: count); |
1805 | } |
1806 | d->columns -= count; |
1807 | if (d->model) |
1808 | d->model->d_func()->columnsRemoved(parent: this, column, count); |
1809 | } |
1810 | |
1811 | /*! |
1812 | Returns \c true if this item has any children; otherwise returns \c false. |
1813 | |
1814 | \sa rowCount(), columnCount(), child() |
1815 | */ |
1816 | bool QStandardItem::hasChildren() const |
1817 | { |
1818 | return (rowCount() > 0) && (columnCount() > 0); |
1819 | } |
1820 | |
1821 | /*! |
1822 | Sets the child item at (\a row, \a column) to \a item. This item (the parent |
1823 | item) takes ownership of \a item. If necessary, the row count and column |
1824 | count are increased to fit the item. |
1825 | |
1826 | \note Passing \nullptr as \a item removes the item. |
1827 | |
1828 | \sa child() |
1829 | */ |
1830 | void QStandardItem::setChild(int row, int column, QStandardItem *item) |
1831 | { |
1832 | Q_D(QStandardItem); |
1833 | d->setChild(row, column, item, emitChanged: true); |
1834 | } |
1835 | |
1836 | /*! |
1837 | \fn QStandardItem::setChild(int row, QStandardItem *item) |
1838 | \overload |
1839 | |
1840 | Sets the child at \a row to \a item. |
1841 | */ |
1842 | |
1843 | /*! |
1844 | Returns the child item at (\a row, \a column) if one has been set; otherwise |
1845 | returns \nullptr. |
1846 | |
1847 | \sa setChild(), takeChild(), parent() |
1848 | */ |
1849 | QStandardItem *QStandardItem::child(int row, int column) const |
1850 | { |
1851 | Q_D(const QStandardItem); |
1852 | int index = d->childIndex(row, column); |
1853 | if (index == -1) |
1854 | return nullptr; |
1855 | return d->children.at(i: index); |
1856 | } |
1857 | |
1858 | /*! |
1859 | Removes the child item at (\a row, \a column) without deleting it, and returns |
1860 | a pointer to the item. If there was no child at the given location, then |
1861 | this function returns \nullptr. |
1862 | |
1863 | Note that this function, unlike takeRow() and takeColumn(), does not affect |
1864 | the dimensions of the child table. |
1865 | |
1866 | \sa child(), takeRow(), takeColumn() |
1867 | */ |
1868 | QStandardItem *QStandardItem::takeChild(int row, int column) |
1869 | { |
1870 | Q_D(QStandardItem); |
1871 | QStandardItem *item = nullptr; |
1872 | int index = d->childIndex(row, column); |
1873 | if (index != -1) { |
1874 | QModelIndex changedIdx; |
1875 | item = d->children.at(i: index); |
1876 | if (item) { |
1877 | QStandardItemPrivate *const item_d = item->d_func(); |
1878 | if (d->model) { |
1879 | QStandardItemModelPrivate *const model_d = d->model->d_func(); |
1880 | const int savedRows = item_d->rows; |
1881 | const int savedCols = item_d->columns; |
1882 | const QVector<QStandardItem*> savedChildren = item_d->children; |
1883 | if (savedRows > 0) { |
1884 | model_d->rowsAboutToBeRemoved(parent: item, start: 0, end: savedRows - 1); |
1885 | item_d->rows = 0; |
1886 | item_d->children = QVector<QStandardItem*>(); //slightly faster than clear |
1887 | model_d->rowsRemoved(parent: item, row: 0, count: savedRows); |
1888 | } |
1889 | if (savedCols > 0) { |
1890 | model_d->columnsAboutToBeRemoved(parent: item, start: 0, end: savedCols - 1); |
1891 | item_d->columns = 0; |
1892 | item_d->children = QVector<QStandardItem*>(); //slightly faster than clear |
1893 | model_d->columnsRemoved(parent: item, column: 0, count: savedCols); |
1894 | } |
1895 | item_d->rows = savedRows; |
1896 | item_d->columns = savedCols; |
1897 | item_d->children = savedChildren; |
1898 | changedIdx = d->model->indexFromItem(item); |
1899 | } |
1900 | item_d->setParentAndModel(par: nullptr, mod: nullptr); |
1901 | } |
1902 | d->children.replace(i: index, t: nullptr); |
1903 | if (changedIdx.isValid()) |
1904 | d->model->dataChanged(topLeft: changedIdx, bottomRight: changedIdx); |
1905 | } |
1906 | return item; |
1907 | } |
1908 | |
1909 | /*! |
1910 | Removes \a row without deleting the row items, and returns a list of |
1911 | pointers to the removed items. For items in the row that have not been |
1912 | set, the corresponding pointers in the list will be \nullptr. |
1913 | |
1914 | \sa removeRow(), insertRow(), takeColumn() |
1915 | */ |
1916 | QList<QStandardItem*> QStandardItem::takeRow(int row) |
1917 | { |
1918 | Q_D(QStandardItem); |
1919 | QList<QStandardItem*> items; |
1920 | if ((row < 0) || (row >= rowCount())) |
1921 | return items; |
1922 | if (d->model) |
1923 | d->model->d_func()->rowsAboutToBeRemoved(parent: this, start: row, end: row); |
1924 | |
1925 | int index = d->childIndex(row, column: 0); // Will return -1 if there are no columns |
1926 | if (index != -1) { |
1927 | int col_count = d->columnCount(); |
1928 | items.reserve(asize: col_count); |
1929 | for (int column = 0; column < col_count; ++column) { |
1930 | QStandardItem *ch = d->children.at(i: index + column); |
1931 | if (ch) |
1932 | ch->d_func()->setParentAndModel(par: nullptr, mod: nullptr); |
1933 | items.append(t: ch); |
1934 | } |
1935 | d->children.remove(i: index, n: col_count); |
1936 | } |
1937 | d->rows--; |
1938 | if (d->model) |
1939 | d->model->d_func()->rowsRemoved(parent: this, row, count: 1); |
1940 | return items; |
1941 | } |
1942 | |
1943 | /*! |
1944 | Removes \a column without deleting the column items, and returns a list of |
1945 | pointers to the removed items. For items in the column that have not been |
1946 | set, the corresponding pointers in the list will be \nullptr. |
1947 | |
1948 | \sa removeColumn(), insertColumn(), takeRow() |
1949 | */ |
1950 | QList<QStandardItem*> QStandardItem::takeColumn(int column) |
1951 | { |
1952 | Q_D(QStandardItem); |
1953 | QList<QStandardItem*> items; |
1954 | if ((column < 0) || (column >= columnCount())) |
1955 | return items; |
1956 | if (d->model) |
1957 | d->model->d_func()->columnsAboutToBeRemoved(parent: this, start: column, end: column); |
1958 | |
1959 | const int rowCount = d->rowCount(); |
1960 | items.reserve(asize: rowCount); |
1961 | for (int row = rowCount - 1; row >= 0; --row) { |
1962 | int index = d->childIndex(row, column); |
1963 | QStandardItem *ch = d->children.at(i: index); |
1964 | if (ch) |
1965 | ch->d_func()->setParentAndModel(par: nullptr, mod: nullptr); |
1966 | d->children.remove(i: index); |
1967 | items.prepend(t: ch); |
1968 | } |
1969 | d->columns--; |
1970 | if (d->model) |
1971 | d->model->d_func()->columnsRemoved(parent: this, column, count: 1); |
1972 | return items; |
1973 | } |
1974 | |
1975 | /*! |
1976 | Returns \c true if this item is less than \a other; otherwise returns \c false. |
1977 | |
1978 | The default implementation uses the data for the item's sort role (see |
1979 | QStandardItemModel::sortRole) to perform the comparison if the item |
1980 | belongs to a model; otherwise, the data for the item's Qt::DisplayRole |
1981 | (text()) is used to perform the comparison. |
1982 | |
1983 | sortChildren() and QStandardItemModel::sort() use this function when |
1984 | sorting items. If you want custom sorting, you can subclass QStandardItem |
1985 | and reimplement this function. |
1986 | */ |
1987 | bool QStandardItem::operator<(const QStandardItem &other) const |
1988 | { |
1989 | const int role = model() ? model()->sortRole() : Qt::DisplayRole; |
1990 | const QVariant l = data(role), r = other.data(role); |
1991 | return QAbstractItemModelPrivate::isVariantLessThan(left: l, right: r); |
1992 | } |
1993 | |
1994 | /*! |
1995 | Sorts the children of the item using the given \a order, by the values in |
1996 | the given \a column. |
1997 | |
1998 | \note This function is recursive, therefore it sorts the children of the |
1999 | item, its grandchildren, etc. |
2000 | |
2001 | \sa {operator<()} |
2002 | */ |
2003 | void QStandardItem::sortChildren(int column, Qt::SortOrder order) |
2004 | { |
2005 | Q_D(QStandardItem); |
2006 | if ((column < 0) || (rowCount() == 0)) |
2007 | return; |
2008 | |
2009 | QList<QPersistentModelIndex> parents; |
2010 | if (d->model) { |
2011 | parents << index(); |
2012 | emit d->model->layoutAboutToBeChanged(parents, hint: QAbstractItemModel::VerticalSortHint); |
2013 | } |
2014 | d->sortChildren(column, order); |
2015 | if (d->model) |
2016 | emit d->model->layoutChanged(parents, hint: QAbstractItemModel::VerticalSortHint); |
2017 | } |
2018 | |
2019 | /*! |
2020 | Returns a copy of this item. The item's children are not copied. |
2021 | |
2022 | When subclassing QStandardItem, you can reimplement this function |
2023 | to provide QStandardItemModel with a factory that it can use to |
2024 | create new items on demand. |
2025 | |
2026 | \sa QStandardItemModel::setItemPrototype(), operator=() |
2027 | */ |
2028 | QStandardItem *QStandardItem::clone() const |
2029 | { |
2030 | return new QStandardItem(*this); |
2031 | } |
2032 | |
2033 | /*! |
2034 | Returns the type of this item. The type is used to distinguish custom |
2035 | items from the base class. When subclassing QStandardItem, you should |
2036 | reimplement this function and return a new value greater than or equal |
2037 | to \l UserType. |
2038 | |
2039 | \sa QStandardItem::Type |
2040 | */ |
2041 | int QStandardItem::type() const |
2042 | { |
2043 | return Type; |
2044 | } |
2045 | |
2046 | #ifndef QT_NO_DATASTREAM |
2047 | |
2048 | /*! |
2049 | Reads the item from stream \a in. Only the data and flags of the item are |
2050 | read, not the child items. |
2051 | |
2052 | \sa write() |
2053 | */ |
2054 | void QStandardItem::read(QDataStream &in) |
2055 | { |
2056 | Q_D(QStandardItem); |
2057 | in >> d->values; |
2058 | qint32 flags; |
2059 | in >> flags; |
2060 | setFlags(Qt::ItemFlags(flags)); |
2061 | } |
2062 | |
2063 | /*! |
2064 | Writes the item to stream \a out. Only the data and flags of the item |
2065 | are written, not the child items. |
2066 | |
2067 | \sa read() |
2068 | */ |
2069 | void QStandardItem::write(QDataStream &out) const |
2070 | { |
2071 | Q_D(const QStandardItem); |
2072 | out << d->values; |
2073 | out << flags(); |
2074 | } |
2075 | |
2076 | /*! |
2077 | \relates QStandardItem |
2078 | \since 4.2 |
2079 | |
2080 | Reads a QStandardItem from stream \a in into \a item. |
2081 | |
2082 | This operator uses QStandardItem::read(). |
2083 | |
2084 | \sa {Serializing Qt Data Types} |
2085 | */ |
2086 | QDataStream &operator>>(QDataStream &in, QStandardItem &item) |
2087 | { |
2088 | item.read(in); |
2089 | return in; |
2090 | } |
2091 | |
2092 | /*! |
2093 | \relates QStandardItem |
2094 | \since 4.2 |
2095 | |
2096 | Writes the QStandardItem \a item to stream \a out. |
2097 | |
2098 | This operator uses QStandardItem::write(). |
2099 | |
2100 | \sa {Serializing Qt Data Types} |
2101 | */ |
2102 | QDataStream &operator<<(QDataStream &out, const QStandardItem &item) |
2103 | { |
2104 | item.write(out); |
2105 | return out; |
2106 | } |
2107 | |
2108 | #endif // QT_NO_DATASTREAM |
2109 | |
2110 | /*! |
2111 | \class QStandardItemModel |
2112 | \brief The QStandardItemModel class provides a generic model for storing custom data. |
2113 | \ingroup model-view |
2114 | \inmodule QtGui |
2115 | |
2116 | QStandardItemModel can be used as a repository for standard Qt |
2117 | data types. It is one of the \l {Model/View Classes} and is part |
2118 | of Qt's \l {Model/View Programming}{model/view} framework. |
2119 | |
2120 | QStandardItemModel provides a classic item-based approach to working with |
2121 | the model. The items in a QStandardItemModel are provided by |
2122 | QStandardItem. |
2123 | |
2124 | QStandardItemModel implements the QAbstractItemModel interface, which |
2125 | means that the model can be used to provide data in any view that supports |
2126 | that interface (such as QListView, QTableView and QTreeView, and your own |
2127 | custom views). For performance and flexibility, you may want to subclass |
2128 | QAbstractItemModel to provide support for different kinds of data |
2129 | repositories. For example, the QFileSystemModel provides a model interface |
2130 | to the underlying file system. |
2131 | |
2132 | When you want a list or tree, you typically create an empty |
2133 | QStandardItemModel and use appendRow() to add items to the model, and |
2134 | item() to access an item. If your model represents a table, you typically |
2135 | pass the dimensions of the table to the QStandardItemModel constructor and |
2136 | use setItem() to position items into the table. You can also use setRowCount() |
2137 | and setColumnCount() to alter the dimensions of the model. To insert items, |
2138 | use insertRow() or insertColumn(), and to remove items, use removeRow() or |
2139 | removeColumn(). |
2140 | |
2141 | You can set the header labels of your model with setHorizontalHeaderLabels() |
2142 | and setVerticalHeaderLabels(). |
2143 | |
2144 | You can search for items in the model with findItems(), and sort the model by |
2145 | calling sort(). |
2146 | |
2147 | Call clear() to remove all items from the model. |
2148 | |
2149 | An example usage of QStandardItemModel to create a table: |
2150 | |
2151 | \snippet code/src_gui_itemviews_qstandarditemmodel.cpp 0 |
2152 | |
2153 | An example usage of QStandardItemModel to create a tree: |
2154 | |
2155 | \snippet code/src_gui_itemviews_qstandarditemmodel.cpp 1 |
2156 | |
2157 | After setting the model on a view, you typically want to react to user |
2158 | actions, such as an item being clicked. Since a QAbstractItemView provides |
2159 | QModelIndex-based signals and functions, you need a way to obtain the |
2160 | QStandardItem that corresponds to a given QModelIndex, and vice |
2161 | versa. itemFromIndex() and indexFromItem() provide this mapping. Typical |
2162 | usage of itemFromIndex() includes obtaining the item at the current index |
2163 | in a view, and obtaining the item that corresponds to an index carried by |
2164 | a QAbstractItemView signal, such as QAbstractItemView::clicked(). First |
2165 | you connect the view's signal to a slot in your class: |
2166 | |
2167 | \snippet code/src_gui_itemviews_qstandarditemmodel.cpp 2 |
2168 | |
2169 | When you receive the signal, you call itemFromIndex() on the given model |
2170 | index to get a pointer to the item: |
2171 | |
2172 | \snippet code/src_gui_itemviews_qstandarditemmodel.cpp 3 |
2173 | |
2174 | Conversely, you must obtain the QModelIndex of an item when you want to |
2175 | invoke a model/view function that takes an index as argument. You can |
2176 | obtain the index either by using the model's indexFromItem() function, or, |
2177 | equivalently, by calling QStandardItem::index(): |
2178 | |
2179 | \snippet code/src_gui_itemviews_qstandarditemmodel.cpp 4 |
2180 | |
2181 | You are, of course, not required to use the item-based approach; you could |
2182 | instead rely entirely on the QAbstractItemModel interface when working with |
2183 | the model, or use a combination of the two as appropriate. |
2184 | |
2185 | \sa QStandardItem, {Model/View Programming}, QAbstractItemModel, |
2186 | {itemviews/simpletreemodel}{Simple Tree Model example}, |
2187 | {Item View Convenience Classes} |
2188 | */ |
2189 | |
2190 | /*! |
2191 | \fn void QStandardItemModel::itemChanged(QStandardItem *item) |
2192 | \since 4.2 |
2193 | |
2194 | This signal is emitted whenever the data of \a item has changed. |
2195 | */ |
2196 | |
2197 | /*! |
2198 | Constructs a new item model with the given \a parent. |
2199 | */ |
2200 | QStandardItemModel::QStandardItemModel(QObject *parent) |
2201 | : QAbstractItemModel(*new QStandardItemModelPrivate, parent) |
2202 | { |
2203 | Q_D(QStandardItemModel); |
2204 | d->init(); |
2205 | d->root->d_func()->setModel(this); |
2206 | } |
2207 | |
2208 | /*! |
2209 | Constructs a new item model that initially has \a rows rows and \a columns |
2210 | columns, and that has the given \a parent. |
2211 | */ |
2212 | QStandardItemModel::QStandardItemModel(int rows, int columns, QObject *parent) |
2213 | : QAbstractItemModel(*new QStandardItemModelPrivate, parent) |
2214 | { |
2215 | Q_D(QStandardItemModel); |
2216 | d->init(); |
2217 | d->root->insertColumns(column: 0, count: columns); |
2218 | d->columnHeaderItems.insert(i: 0, n: columns, t: nullptr); |
2219 | d->root->insertRows(row: 0, count: rows); |
2220 | d->rowHeaderItems.insert(i: 0, n: rows, t: nullptr); |
2221 | d->root->d_func()->setModel(this); |
2222 | } |
2223 | |
2224 | /*! |
2225 | \internal |
2226 | */ |
2227 | QStandardItemModel::QStandardItemModel(QStandardItemModelPrivate &dd, QObject *parent) |
2228 | : QAbstractItemModel(dd, parent) |
2229 | { |
2230 | Q_D(QStandardItemModel); |
2231 | d->init(); |
2232 | } |
2233 | |
2234 | /*! |
2235 | Destructs the model. The model destroys all its items. |
2236 | */ |
2237 | QStandardItemModel::~QStandardItemModel() |
2238 | { |
2239 | Q_D(QStandardItemModel); |
2240 | delete d->itemPrototype; |
2241 | qDeleteAll(c: d->columnHeaderItems); |
2242 | qDeleteAll(c: d->rowHeaderItems); |
2243 | d->root.reset(); |
2244 | } |
2245 | |
2246 | /*! |
2247 | Sets the item role names to \a roleNames. |
2248 | */ |
2249 | void QStandardItemModel::setItemRoleNames(const QHash<int,QByteArray> &roleNames) |
2250 | { |
2251 | Q_D(QStandardItemModel); |
2252 | d->roleNames = roleNames; |
2253 | } |
2254 | |
2255 | /*! |
2256 | reimp |
2257 | */ |
2258 | QHash<int, QByteArray> QStandardItemModel::roleNames() const |
2259 | { |
2260 | Q_D(const QStandardItemModel); |
2261 | return d->roleNames; |
2262 | } |
2263 | |
2264 | /*! |
2265 | Removes all items (including header items) from the model and sets the |
2266 | number of rows and columns to zero. |
2267 | |
2268 | \sa removeColumns(), removeRows() |
2269 | */ |
2270 | void QStandardItemModel::clear() |
2271 | { |
2272 | Q_D(QStandardItemModel); |
2273 | beginResetModel(); |
2274 | d->root.reset(other: new QStandardItem); |
2275 | d->root->setFlags(Qt::ItemIsDropEnabled); |
2276 | d->root->d_func()->setModel(this); |
2277 | qDeleteAll(c: d->columnHeaderItems); |
2278 | d->columnHeaderItems.clear(); |
2279 | qDeleteAll(c: d->rowHeaderItems); |
2280 | d->rowHeaderItems.clear(); |
2281 | endResetModel(); |
2282 | } |
2283 | |
2284 | /*! |
2285 | \since 4.2 |
2286 | |
2287 | Returns a pointer to the QStandardItem associated with the given \a index. |
2288 | |
2289 | Calling this function is typically the initial step when processing |
2290 | QModelIndex-based signals from a view, such as |
2291 | QAbstractItemView::activated(). In your slot, you call itemFromIndex(), |
2292 | with the QModelIndex carried by the signal as argument, to obtain a |
2293 | pointer to the corresponding QStandardItem. |
2294 | |
2295 | Note that this function will lazily create an item for the index (using |
2296 | itemPrototype()), and set it in the parent item's child table, if no item |
2297 | already exists at that index. |
2298 | |
2299 | If \a index is an invalid index, this function returns \nullptr. |
2300 | |
2301 | \sa indexFromItem() |
2302 | */ |
2303 | QStandardItem *QStandardItemModel::itemFromIndex(const QModelIndex &index) const |
2304 | { |
2305 | Q_D(const QStandardItemModel); |
2306 | if ((index.row() < 0) || (index.column() < 0) || (index.model() != this)) |
2307 | return nullptr; |
2308 | QStandardItem *parent = static_cast<QStandardItem*>(index.internalPointer()); |
2309 | if (parent == nullptr) |
2310 | return nullptr; |
2311 | QStandardItem *item = parent->child(row: index.row(), column: index.column()); |
2312 | // lazy part |
2313 | if (item == nullptr) { |
2314 | item = d->createItem(); |
2315 | parent->d_func()->setChild(row: index.row(), column: index.column(), item); |
2316 | } |
2317 | return item; |
2318 | } |
2319 | |
2320 | /*! |
2321 | \since 4.2 |
2322 | |
2323 | Returns the QModelIndex associated with the given \a item. |
2324 | |
2325 | Use this function when you want to perform an operation that requires the |
2326 | QModelIndex of the item, such as |
2327 | QAbstractItemView::scrollTo(). QStandardItem::index() is provided as |
2328 | convenience; it is equivalent to calling this function. |
2329 | |
2330 | \sa itemFromIndex(), QStandardItem::index() |
2331 | */ |
2332 | QModelIndex QStandardItemModel::indexFromItem(const QStandardItem *item) const |
2333 | { |
2334 | if (item && item->d_func()->parent) { |
2335 | QPair<int, int> pos = item->d_func()->position(); |
2336 | return createIndex(arow: pos.first, acolumn: pos.second, adata: item->d_func()->parent); |
2337 | } |
2338 | return QModelIndex(); |
2339 | } |
2340 | |
2341 | /*! |
2342 | \since 4.2 |
2343 | |
2344 | Sets the number of rows in this model to \a rows. If |
2345 | this is less than rowCount(), the data in the unwanted rows |
2346 | is discarded. |
2347 | |
2348 | \sa setColumnCount() |
2349 | */ |
2350 | void QStandardItemModel::setRowCount(int rows) |
2351 | { |
2352 | Q_D(QStandardItemModel); |
2353 | d->root->setRowCount(rows); |
2354 | } |
2355 | |
2356 | /*! |
2357 | \since 4.2 |
2358 | |
2359 | Sets the number of columns in this model to \a columns. If |
2360 | this is less than columnCount(), the data in the unwanted columns |
2361 | is discarded. |
2362 | |
2363 | \sa setRowCount() |
2364 | */ |
2365 | void QStandardItemModel::setColumnCount(int columns) |
2366 | { |
2367 | Q_D(QStandardItemModel); |
2368 | d->root->setColumnCount(columns); |
2369 | } |
2370 | |
2371 | /*! |
2372 | \since 4.2 |
2373 | |
2374 | Sets the item for the given \a row and \a column to \a item. The model |
2375 | takes ownership of the item. If necessary, the row count and column count |
2376 | are increased to fit the item. The previous item at the given location (if |
2377 | there was one) is deleted. |
2378 | |
2379 | \sa item() |
2380 | */ |
2381 | void QStandardItemModel::setItem(int row, int column, QStandardItem *item) |
2382 | { |
2383 | Q_D(QStandardItemModel); |
2384 | d->root->d_func()->setChild(row, column, item, emitChanged: true); |
2385 | } |
2386 | |
2387 | /*! |
2388 | \fn QStandardItemModel::setItem(int row, QStandardItem *item) |
2389 | \overload |
2390 | */ |
2391 | |
2392 | /*! |
2393 | \since 4.2 |
2394 | |
2395 | Returns the item for the given \a row and \a column if one has been set; |
2396 | otherwise returns \nullptr. |
2397 | |
2398 | \sa setItem(), takeItem(), itemFromIndex() |
2399 | */ |
2400 | QStandardItem *QStandardItemModel::item(int row, int column) const |
2401 | { |
2402 | Q_D(const QStandardItemModel); |
2403 | return d->root->child(row, column); |
2404 | } |
2405 | |
2406 | /*! |
2407 | \since 4.2 |
2408 | |
2409 | Returns the model's invisible root item. |
2410 | |
2411 | The invisible root item provides access to the model's top-level items |
2412 | through the QStandardItem API, making it possible to write functions that |
2413 | can treat top-level items and their children in a uniform way; for |
2414 | example, recursive functions involving a tree model. |
2415 | |
2416 | \note Calling \l{QAbstractItemModel::index()}{index()} on the QStandardItem object |
2417 | retrieved from this function is not valid. |
2418 | */ |
2419 | QStandardItem *QStandardItemModel::invisibleRootItem() const |
2420 | { |
2421 | Q_D(const QStandardItemModel); |
2422 | return d->root.data(); |
2423 | } |
2424 | |
2425 | /*! |
2426 | \since 4.2 |
2427 | |
2428 | Sets the horizontal header item for \a column to \a item. The model takes |
2429 | ownership of the item. If necessary, the column count is increased to fit |
2430 | the item. The previous header item (if there was one) is deleted. |
2431 | |
2432 | \sa horizontalHeaderItem(), setHorizontalHeaderLabels(), |
2433 | setVerticalHeaderItem() |
2434 | */ |
2435 | void QStandardItemModel::setHorizontalHeaderItem(int column, QStandardItem *item) |
2436 | { |
2437 | Q_D(QStandardItemModel); |
2438 | if (column < 0) |
2439 | return; |
2440 | if (columnCount() <= column) |
2441 | setColumnCount(column + 1); |
2442 | |
2443 | QStandardItem *oldItem = d->columnHeaderItems.at(i: column); |
2444 | if (item == oldItem) |
2445 | return; |
2446 | |
2447 | if (item) { |
2448 | if (item->model() == nullptr) { |
2449 | item->d_func()->setModel(this); |
2450 | } else { |
2451 | qWarning(msg: "QStandardItem::setHorizontalHeaderItem: Ignoring duplicate insertion of item %p", |
2452 | item); |
2453 | return; |
2454 | } |
2455 | } |
2456 | |
2457 | if (oldItem) |
2458 | oldItem->d_func()->setModel(nullptr); |
2459 | delete oldItem; |
2460 | |
2461 | d->columnHeaderItems.replace(i: column, t: item); |
2462 | emit headerDataChanged(orientation: Qt::Horizontal, first: column, last: column); |
2463 | } |
2464 | |
2465 | /*! |
2466 | \since 4.2 |
2467 | |
2468 | Returns the horizontal header item for \a column if one has been set; |
2469 | otherwise returns \nullptr. |
2470 | |
2471 | \sa setHorizontalHeaderItem(), verticalHeaderItem() |
2472 | */ |
2473 | QStandardItem *QStandardItemModel::horizontalHeaderItem(int column) const |
2474 | { |
2475 | Q_D(const QStandardItemModel); |
2476 | if ((column < 0) || (column >= columnCount())) |
2477 | return nullptr; |
2478 | return d->columnHeaderItems.at(i: column); |
2479 | } |
2480 | |
2481 | /*! |
2482 | \since 4.2 |
2483 | |
2484 | Sets the vertical header item for \a row to \a item. The model takes |
2485 | ownership of the item. If necessary, the row count is increased to fit the |
2486 | item. The previous header item (if there was one) is deleted. |
2487 | |
2488 | \sa verticalHeaderItem(), setVerticalHeaderLabels(), |
2489 | setHorizontalHeaderItem() |
2490 | */ |
2491 | void QStandardItemModel::setVerticalHeaderItem(int row, QStandardItem *item) |
2492 | { |
2493 | Q_D(QStandardItemModel); |
2494 | if (row < 0) |
2495 | return; |
2496 | if (rowCount() <= row) |
2497 | setRowCount(row + 1); |
2498 | |
2499 | QStandardItem *oldItem = d->rowHeaderItems.at(i: row); |
2500 | if (item == oldItem) |
2501 | return; |
2502 | |
2503 | if (item) { |
2504 | if (item->model() == nullptr) { |
2505 | item->d_func()->setModel(this); |
2506 | } else { |
2507 | qWarning(msg: "QStandardItem::setVerticalHeaderItem: Ignoring duplicate insertion of item %p", |
2508 | item); |
2509 | return; |
2510 | } |
2511 | } |
2512 | |
2513 | if (oldItem) |
2514 | oldItem->d_func()->setModel(nullptr); |
2515 | delete oldItem; |
2516 | |
2517 | d->rowHeaderItems.replace(i: row, t: item); |
2518 | emit headerDataChanged(orientation: Qt::Vertical, first: row, last: row); |
2519 | } |
2520 | |
2521 | /*! |
2522 | \since 4.2 |
2523 | |
2524 | Returns the vertical header item for row \a row if one has been set; |
2525 | otherwise returns \nullptr. |
2526 | |
2527 | \sa setVerticalHeaderItem(), horizontalHeaderItem() |
2528 | */ |
2529 | QStandardItem *QStandardItemModel::verticalHeaderItem(int row) const |
2530 | { |
2531 | Q_D(const QStandardItemModel); |
2532 | if ((row < 0) || (row >= rowCount())) |
2533 | return nullptr; |
2534 | return d->rowHeaderItems.at(i: row); |
2535 | } |
2536 | |
2537 | /*! |
2538 | \since 4.2 |
2539 | |
2540 | Sets the horizontal header labels using \a labels. If necessary, the |
2541 | column count is increased to the size of \a labels. |
2542 | |
2543 | \sa setHorizontalHeaderItem() |
2544 | */ |
2545 | void QStandardItemModel::setHorizontalHeaderLabels(const QStringList &labels) |
2546 | { |
2547 | Q_D(QStandardItemModel); |
2548 | if (columnCount() < labels.size()) |
2549 | setColumnCount(labels.size()); |
2550 | for (int i = 0; i < labels.size(); ++i) { |
2551 | QStandardItem *item = horizontalHeaderItem(column: i); |
2552 | if (!item) { |
2553 | item = d->createItem(); |
2554 | setHorizontalHeaderItem(column: i, item); |
2555 | } |
2556 | item->setText(labels.at(i)); |
2557 | } |
2558 | } |
2559 | |
2560 | /*! |
2561 | \since 4.2 |
2562 | |
2563 | Sets the vertical header labels using \a labels. If necessary, the row |
2564 | count is increased to the size of \a labels. |
2565 | |
2566 | \sa setVerticalHeaderItem() |
2567 | */ |
2568 | void QStandardItemModel::setVerticalHeaderLabels(const QStringList &labels) |
2569 | { |
2570 | Q_D(QStandardItemModel); |
2571 | if (rowCount() < labels.size()) |
2572 | setRowCount(labels.size()); |
2573 | for (int i = 0; i < labels.size(); ++i) { |
2574 | QStandardItem *item = verticalHeaderItem(row: i); |
2575 | if (!item) { |
2576 | item = d->createItem(); |
2577 | setVerticalHeaderItem(row: i, item); |
2578 | } |
2579 | item->setText(labels.at(i)); |
2580 | } |
2581 | } |
2582 | |
2583 | /*! |
2584 | \since 4.2 |
2585 | |
2586 | Sets the item prototype for the model to the specified \a item. The model |
2587 | takes ownership of the prototype. |
2588 | |
2589 | The item prototype acts as a QStandardItem factory, by relying on the |
2590 | QStandardItem::clone() function. To provide your own prototype, subclass |
2591 | QStandardItem, reimplement QStandardItem::clone() and set the prototype to |
2592 | be an instance of your custom class. Whenever QStandardItemModel needs to |
2593 | create an item on demand (for instance, when a view or item delegate calls |
2594 | setData())), the new items will be instances of your custom class. |
2595 | |
2596 | \sa itemPrototype(), QStandardItem::clone() |
2597 | */ |
2598 | void QStandardItemModel::setItemPrototype(const QStandardItem *item) |
2599 | { |
2600 | Q_D(QStandardItemModel); |
2601 | if (d->itemPrototype != item) { |
2602 | delete d->itemPrototype; |
2603 | d->itemPrototype = item; |
2604 | } |
2605 | } |
2606 | |
2607 | /*! |
2608 | \since 4.2 |
2609 | |
2610 | Returns the item prototype used by the model. The model uses the item |
2611 | prototype as an item factory when it needs to construct new items on |
2612 | demand (for instance, when a view or item delegate calls setData()). |
2613 | |
2614 | \sa setItemPrototype() |
2615 | */ |
2616 | const QStandardItem *QStandardItemModel::itemPrototype() const |
2617 | { |
2618 | Q_D(const QStandardItemModel); |
2619 | return d->itemPrototype; |
2620 | } |
2621 | |
2622 | /*! |
2623 | \since 4.2 |
2624 | |
2625 | Returns a list of items that match the given \a text, using the given \a |
2626 | flags, in the given \a column. |
2627 | */ |
2628 | QList<QStandardItem*> QStandardItemModel::findItems(const QString &text, |
2629 | Qt::MatchFlags flags, int column) const |
2630 | { |
2631 | QModelIndexList indexes = match(start: index(row: 0, column, parent: QModelIndex()), |
2632 | role: Qt::DisplayRole, value: text, hits: -1, flags); |
2633 | QList<QStandardItem*> items; |
2634 | const int numIndexes = indexes.size(); |
2635 | items.reserve(asize: numIndexes); |
2636 | for (int i = 0; i < numIndexes; ++i) |
2637 | items.append(t: itemFromIndex(index: indexes.at(i))); |
2638 | return items; |
2639 | } |
2640 | |
2641 | /*! |
2642 | \since 4.2 |
2643 | |
2644 | Appends a row containing \a items. If necessary, the column count is |
2645 | increased to the size of \a items. |
2646 | |
2647 | \sa insertRow(), appendColumn() |
2648 | */ |
2649 | void QStandardItemModel::appendRow(const QList<QStandardItem*> &items) |
2650 | { |
2651 | invisibleRootItem()->appendRow(aitems: items); |
2652 | } |
2653 | |
2654 | /*! |
2655 | \since 4.2 |
2656 | |
2657 | Appends a column containing \a items. If necessary, the row count is |
2658 | increased to the size of \a items. |
2659 | |
2660 | \sa insertColumn(), appendRow() |
2661 | */ |
2662 | void QStandardItemModel::appendColumn(const QList<QStandardItem*> &items) |
2663 | { |
2664 | invisibleRootItem()->appendColumn(aitems: items); |
2665 | } |
2666 | |
2667 | /*! |
2668 | \since 4.2 |
2669 | \fn QStandardItemModel::appendRow(QStandardItem *item) |
2670 | \overload |
2671 | |
2672 | When building a list or a tree that has only one column, this function |
2673 | provides a convenient way to append a single new \a item. |
2674 | */ |
2675 | |
2676 | /*! |
2677 | \since 4.2 |
2678 | |
2679 | Inserts a row at \a row containing \a items. If necessary, the column |
2680 | count is increased to the size of \a items. |
2681 | |
2682 | \sa takeRow(), appendRow(), insertColumn() |
2683 | */ |
2684 | void QStandardItemModel::insertRow(int row, const QList<QStandardItem*> &items) |
2685 | { |
2686 | invisibleRootItem()->insertRow(row, items); |
2687 | } |
2688 | |
2689 | /*! |
2690 | \since 4.2 |
2691 | |
2692 | \fn void QStandardItemModel::insertRow(int row, QStandardItem *item) |
2693 | \overload |
2694 | |
2695 | Inserts a row at \a row containing \a item. |
2696 | |
2697 | When building a list or a tree that has only one column, this function |
2698 | provides a convenient way to append a single new item. |
2699 | */ |
2700 | |
2701 | /*! |
2702 | \since 4.2 |
2703 | |
2704 | Inserts a column at \a column containing \a items. If necessary, the row |
2705 | count is increased to the size of \a items. |
2706 | |
2707 | \sa takeColumn(), appendColumn(), insertRow() |
2708 | */ |
2709 | void QStandardItemModel::insertColumn(int column, const QList<QStandardItem*> &items) |
2710 | { |
2711 | invisibleRootItem()->insertColumn(column, items); |
2712 | } |
2713 | |
2714 | /*! |
2715 | \since 4.2 |
2716 | |
2717 | Removes the item at (\a row, \a column) without deleting it. The model |
2718 | releases ownership of the item. |
2719 | |
2720 | \sa item(), takeRow(), takeColumn() |
2721 | */ |
2722 | QStandardItem *QStandardItemModel::takeItem(int row, int column) |
2723 | { |
2724 | Q_D(QStandardItemModel); |
2725 | return d->root->takeChild(row, column); |
2726 | } |
2727 | |
2728 | /*! |
2729 | \since 4.2 |
2730 | |
2731 | Removes the given \a row without deleting the row items, and returns a |
2732 | list of pointers to the removed items. The model releases ownership of the |
2733 | items. For items in the row that have not been set, the corresponding |
2734 | pointers in the list will be \nullptr. |
2735 | |
2736 | \sa takeColumn() |
2737 | */ |
2738 | QList<QStandardItem*> QStandardItemModel::takeRow(int row) |
2739 | { |
2740 | Q_D(QStandardItemModel); |
2741 | return d->root->takeRow(row); |
2742 | } |
2743 | |
2744 | /*! |
2745 | \since 4.2 |
2746 | |
2747 | Removes the given \a column without deleting the column items, and returns |
2748 | a list of pointers to the removed items. The model releases ownership of |
2749 | the items. For items in the column that have not been set, the |
2750 | corresponding pointers in the list will be \nullptr. |
2751 | |
2752 | \sa takeRow() |
2753 | */ |
2754 | QList<QStandardItem*> QStandardItemModel::takeColumn(int column) |
2755 | { |
2756 | Q_D(QStandardItemModel); |
2757 | return d->root->takeColumn(column); |
2758 | } |
2759 | |
2760 | /*! |
2761 | \since 4.2 |
2762 | |
2763 | Removes the horizontal header item at \a column from the header without |
2764 | deleting it, and returns a pointer to the item. The model releases |
2765 | ownership of the item. |
2766 | |
2767 | \sa horizontalHeaderItem(), takeVerticalHeaderItem() |
2768 | */ |
2769 | QStandardItem *QStandardItemModel::takeHorizontalHeaderItem(int column) |
2770 | { |
2771 | Q_D(QStandardItemModel); |
2772 | if ((column < 0) || (column >= columnCount())) |
2773 | return nullptr; |
2774 | QStandardItem *headerItem = d->columnHeaderItems.at(i: column); |
2775 | if (headerItem) { |
2776 | headerItem->d_func()->setParentAndModel(par: nullptr, mod: nullptr); |
2777 | d->columnHeaderItems.replace(i: column, t: nullptr); |
2778 | } |
2779 | return headerItem; |
2780 | } |
2781 | |
2782 | /*! |
2783 | \since 4.2 |
2784 | |
2785 | Removes the vertical header item at \a row from the header without |
2786 | deleting it, and returns a pointer to the item. The model releases |
2787 | ownership of the item. |
2788 | |
2789 | \sa verticalHeaderItem(), takeHorizontalHeaderItem() |
2790 | */ |
2791 | QStandardItem *QStandardItemModel::takeVerticalHeaderItem(int row) |
2792 | { |
2793 | Q_D(QStandardItemModel); |
2794 | if ((row < 0) || (row >= rowCount())) |
2795 | return nullptr; |
2796 | QStandardItem *headerItem = d->rowHeaderItems.at(i: row); |
2797 | if (headerItem) { |
2798 | headerItem->d_func()->setParentAndModel(par: nullptr, mod: nullptr); |
2799 | d->rowHeaderItems.replace(i: row, t: nullptr); |
2800 | } |
2801 | return headerItem; |
2802 | } |
2803 | |
2804 | /*! |
2805 | \since 4.2 |
2806 | \property QStandardItemModel::sortRole |
2807 | \brief the item role that is used to query the model's data when sorting items |
2808 | |
2809 | The default value is Qt::DisplayRole. |
2810 | |
2811 | \sa sort(), QStandardItem::sortChildren() |
2812 | */ |
2813 | int QStandardItemModel::sortRole() const |
2814 | { |
2815 | Q_D(const QStandardItemModel); |
2816 | return d->sortRole; |
2817 | } |
2818 | |
2819 | void QStandardItemModel::setSortRole(int role) |
2820 | { |
2821 | Q_D(QStandardItemModel); |
2822 | d->sortRole = role; |
2823 | } |
2824 | |
2825 | QBindable<int> QStandardItemModel::bindableSortRole() |
2826 | { |
2827 | Q_D(QStandardItemModel); |
2828 | return &d->sortRole; |
2829 | } |
2830 | |
2831 | /*! |
2832 | \reimp |
2833 | */ |
2834 | int QStandardItemModel::columnCount(const QModelIndex &parent) const |
2835 | { |
2836 | Q_D(const QStandardItemModel); |
2837 | QStandardItem *item = d->itemFromIndex(index: parent); |
2838 | return item ? item->columnCount() : 0; |
2839 | } |
2840 | |
2841 | /*! |
2842 | \reimp |
2843 | */ |
2844 | QVariant QStandardItemModel::data(const QModelIndex &index, int role) const |
2845 | { |
2846 | Q_D(const QStandardItemModel); |
2847 | QStandardItem *item = d->itemFromIndex(index); |
2848 | return item ? item->data(role) : QVariant(); |
2849 | } |
2850 | |
2851 | /*! |
2852 | \reimp |
2853 | */ |
2854 | void QStandardItemModel::multiData(const QModelIndex &index, QModelRoleDataSpan roleDataSpan) const |
2855 | { |
2856 | // Cannot offer a better implementation; users may be overriding |
2857 | // data(), and thus multiData() may fall out of sync for them. |
2858 | // The base class' implementation will simply call data() in a loop, |
2859 | // so it's fine. |
2860 | QAbstractItemModel::multiData(index, roleDataSpan); |
2861 | } |
2862 | |
2863 | /*! |
2864 | \reimp |
2865 | */ |
2866 | Qt::ItemFlags QStandardItemModel::flags(const QModelIndex &index) const |
2867 | { |
2868 | Q_D(const QStandardItemModel); |
2869 | if (!d->indexValid(index)) |
2870 | return d->root->flags(); |
2871 | QStandardItem *item = d->itemFromIndex(index); |
2872 | if (item) |
2873 | return item->flags(); |
2874 | return Qt::ItemIsSelectable |
2875 | |Qt::ItemIsEnabled |
2876 | |Qt::ItemIsEditable |
2877 | |Qt::ItemIsDragEnabled |
2878 | |Qt::ItemIsDropEnabled; |
2879 | } |
2880 | |
2881 | /*! |
2882 | \reimp |
2883 | */ |
2884 | bool QStandardItemModel::hasChildren(const QModelIndex &parent) const |
2885 | { |
2886 | Q_D(const QStandardItemModel); |
2887 | QStandardItem *item = d->itemFromIndex(index: parent); |
2888 | return item ? item->hasChildren() : false; |
2889 | } |
2890 | |
2891 | /*! |
2892 | \reimp |
2893 | */ |
2894 | QVariant QStandardItemModel::headerData(int section, Qt::Orientation orientation, int role) const |
2895 | { |
2896 | Q_D(const QStandardItemModel); |
2897 | if ((section < 0) |
2898 | || ((orientation == Qt::Horizontal) && (section >= columnCount())) |
2899 | || ((orientation == Qt::Vertical) && (section >= rowCount()))) { |
2900 | return QVariant(); |
2901 | } |
2902 | QStandardItem *headerItem = nullptr; |
2903 | if (orientation == Qt::Horizontal) |
2904 | headerItem = d->columnHeaderItems.at(i: section); |
2905 | else if (orientation == Qt::Vertical) |
2906 | headerItem = d->rowHeaderItems.at(i: section); |
2907 | return headerItem ? headerItem->data(role) |
2908 | : QAbstractItemModel::headerData(section, orientation, role); |
2909 | } |
2910 | |
2911 | /*! |
2912 | \reimp |
2913 | |
2914 | QStandardItemModel supports both copy and move. |
2915 | */ |
2916 | Qt::DropActions QStandardItemModel::supportedDropActions () const |
2917 | { |
2918 | return Qt::CopyAction | Qt::MoveAction; |
2919 | } |
2920 | |
2921 | /*! |
2922 | \reimp |
2923 | */ |
2924 | QModelIndex QStandardItemModel::index(int row, int column, const QModelIndex &parent) const |
2925 | { |
2926 | Q_D(const QStandardItemModel); |
2927 | QStandardItem *parentItem = d->itemFromIndex(index: parent); |
2928 | if ((parentItem == nullptr) |
2929 | || (row < 0) |
2930 | || (column < 0) |
2931 | || (row >= parentItem->rowCount()) |
2932 | || (column >= parentItem->columnCount())) { |
2933 | return QModelIndex(); |
2934 | } |
2935 | return createIndex(arow: row, acolumn: column, adata: parentItem); |
2936 | } |
2937 | |
2938 | /*! |
2939 | \reimp |
2940 | */ |
2941 | bool QStandardItemModel::insertColumns(int column, int count, const QModelIndex &parent) |
2942 | { |
2943 | Q_D(QStandardItemModel); |
2944 | QStandardItem *item = parent.isValid() ? itemFromIndex(index: parent) : d->root.data(); |
2945 | if (item == nullptr) |
2946 | return false; |
2947 | return item->d_func()->insertColumns(column, count, items: QList<QStandardItem*>()); |
2948 | } |
2949 | |
2950 | /*! |
2951 | \reimp |
2952 | */ |
2953 | bool QStandardItemModel::insertRows(int row, int count, const QModelIndex &parent) |
2954 | { |
2955 | Q_D(QStandardItemModel); |
2956 | QStandardItem *item = parent.isValid() ? itemFromIndex(index: parent) : d->root.data(); |
2957 | if (item == nullptr) |
2958 | return false; |
2959 | return item->d_func()->insertRows(row, count, items: QList<QStandardItem*>()); |
2960 | } |
2961 | |
2962 | /*! |
2963 | \reimp |
2964 | */ |
2965 | QMap<int, QVariant> QStandardItemModel::itemData(const QModelIndex &index) const |
2966 | { |
2967 | Q_D(const QStandardItemModel); |
2968 | const QStandardItem *const item = d->itemFromIndex(index); |
2969 | if (!item || item == d->root.data()) |
2970 | return QMap<int, QVariant>(); |
2971 | return item->d_func()->itemData(); |
2972 | } |
2973 | |
2974 | /*! |
2975 | \reimp |
2976 | */ |
2977 | QModelIndex QStandardItemModel::parent(const QModelIndex &child) const |
2978 | { |
2979 | Q_D(const QStandardItemModel); |
2980 | if (!d->indexValid(index: child)) |
2981 | return QModelIndex(); |
2982 | QStandardItem *parentItem = static_cast<QStandardItem*>(child.internalPointer()); |
2983 | return indexFromItem(item: parentItem); |
2984 | } |
2985 | |
2986 | /*! |
2987 | \reimp |
2988 | */ |
2989 | bool QStandardItemModel::removeColumns(int column, int count, const QModelIndex &parent) |
2990 | { |
2991 | Q_D(QStandardItemModel); |
2992 | QStandardItem *item = d->itemFromIndex(index: parent); |
2993 | if ((item == nullptr) || (count < 1) || (column < 0) || ((column + count) > item->columnCount())) |
2994 | return false; |
2995 | item->removeColumns(column, count); |
2996 | return true; |
2997 | } |
2998 | |
2999 | /*! |
3000 | \reimp |
3001 | */ |
3002 | bool QStandardItemModel::removeRows(int row, int count, const QModelIndex &parent) |
3003 | { |
3004 | Q_D(QStandardItemModel); |
3005 | QStandardItem *item = d->itemFromIndex(index: parent); |
3006 | if ((item == nullptr) || (count < 1) || (row < 0) || ((row + count) > item->rowCount())) |
3007 | return false; |
3008 | item->removeRows(row, count); |
3009 | return true; |
3010 | } |
3011 | |
3012 | /*! |
3013 | \reimp |
3014 | */ |
3015 | int QStandardItemModel::rowCount(const QModelIndex &parent) const |
3016 | { |
3017 | Q_D(const QStandardItemModel); |
3018 | QStandardItem *item = d->itemFromIndex(index: parent); |
3019 | return item ? item->rowCount() : 0; |
3020 | } |
3021 | |
3022 | /*! |
3023 | \reimp |
3024 | */ |
3025 | bool QStandardItemModel::setData(const QModelIndex &index, const QVariant &value, int role) |
3026 | { |
3027 | if (!index.isValid()) |
3028 | return false; |
3029 | QStandardItem *item = itemFromIndex(index); |
3030 | if (item == nullptr) |
3031 | return false; |
3032 | item->setData(value, role); |
3033 | return true; |
3034 | } |
3035 | |
3036 | /*! |
3037 | \reimp |
3038 | */ |
3039 | bool QStandardItemModel::clearItemData(const QModelIndex &index) |
3040 | { |
3041 | if (!checkIndex(index, options: CheckIndexOption::IndexIsValid)) |
3042 | return false; |
3043 | Q_D(QStandardItemModel); |
3044 | QStandardItem *item = d->itemFromIndex(index); |
3045 | if (!item) |
3046 | return false; |
3047 | item->clearData(); |
3048 | return true; |
3049 | } |
3050 | |
3051 | /*! |
3052 | \reimp |
3053 | */ |
3054 | bool QStandardItemModel::setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role) |
3055 | { |
3056 | Q_D(QStandardItemModel); |
3057 | if ((section < 0) |
3058 | || ((orientation == Qt::Horizontal) && (section >= columnCount())) |
3059 | || ((orientation == Qt::Vertical) && (section >= rowCount()))) { |
3060 | return false; |
3061 | } |
3062 | QStandardItem *headerItem = nullptr; |
3063 | if (orientation == Qt::Horizontal) { |
3064 | headerItem = d->columnHeaderItems.at(i: section); |
3065 | if (headerItem == nullptr) { |
3066 | headerItem = d->createItem(); |
3067 | headerItem->d_func()->setModel(this); |
3068 | d->columnHeaderItems.replace(i: section, t: headerItem); |
3069 | } |
3070 | } else if (orientation == Qt::Vertical) { |
3071 | headerItem = d->rowHeaderItems.at(i: section); |
3072 | if (headerItem == nullptr) { |
3073 | headerItem = d->createItem(); |
3074 | headerItem->d_func()->setModel(this); |
3075 | d->rowHeaderItems.replace(i: section, t: headerItem); |
3076 | } |
3077 | } |
3078 | if (headerItem) { |
3079 | headerItem->setData(value, role); |
3080 | return true; |
3081 | } |
3082 | return false; |
3083 | } |
3084 | |
3085 | /*! |
3086 | \reimp |
3087 | */ |
3088 | bool QStandardItemModel::setItemData(const QModelIndex &index, const QMap<int, QVariant> &roles) |
3089 | { |
3090 | QStandardItem *item = itemFromIndex(index); |
3091 | if (item == nullptr) |
3092 | return false; |
3093 | item->d_func()->setItemData(roles); |
3094 | return true; |
3095 | } |
3096 | |
3097 | /*! |
3098 | \reimp |
3099 | */ |
3100 | void QStandardItemModel::sort(int column, Qt::SortOrder order) |
3101 | { |
3102 | Q_D(QStandardItemModel); |
3103 | d->root->sortChildren(column, order); |
3104 | } |
3105 | |
3106 | /*! |
3107 | \reimp |
3108 | */ |
3109 | QStringList QStandardItemModel::mimeTypes() const |
3110 | { |
3111 | return QAbstractItemModel::mimeTypes() << qStandardItemModelDataListMimeType(); |
3112 | } |
3113 | |
3114 | /*! |
3115 | \reimp |
3116 | */ |
3117 | QMimeData *QStandardItemModel::mimeData(const QModelIndexList &indexes) const |
3118 | { |
3119 | std::unique_ptr<QMimeData> data(QAbstractItemModel::mimeData(indexes)); |
3120 | if (!data) |
3121 | return nullptr; |
3122 | |
3123 | const QString format = qStandardItemModelDataListMimeType(); |
3124 | if (!mimeTypes().contains(str: format)) |
3125 | return data.release(); |
3126 | QByteArray encoded; |
3127 | QDataStream stream(&encoded, QIODevice::WriteOnly); |
3128 | |
3129 | QSet<QStandardItem*> itemsSet; |
3130 | QStack<QStandardItem*> stack; |
3131 | itemsSet.reserve(asize: indexes.size()); |
3132 | stack.reserve(asize: indexes.size()); |
3133 | for (int i = 0; i < indexes.size(); ++i) { |
3134 | if (QStandardItem *item = itemFromIndex(index: indexes.at(i))) { |
3135 | itemsSet << item; |
3136 | stack.push(t: item); |
3137 | } else { |
3138 | qWarning(msg: "QStandardItemModel::mimeData: No item associated with invalid index"); |
3139 | return nullptr; |
3140 | } |
3141 | } |
3142 | |
3143 | //remove duplicates children |
3144 | { |
3145 | QDuplicateTracker<QStandardItem *> seen; |
3146 | while (!stack.isEmpty()) { |
3147 | QStandardItem *itm = stack.pop(); |
3148 | if (seen.hasSeen(s: itm)) |
3149 | continue; |
3150 | |
3151 | const QList<QStandardItem*> &childList = itm->d_func()->children; |
3152 | for (int i = 0; i < childList.size(); ++i) { |
3153 | QStandardItem *chi = childList.at(i); |
3154 | if (chi) { |
3155 | itemsSet.remove(value: chi); |
3156 | stack.push(t: chi); |
3157 | } |
3158 | } |
3159 | } |
3160 | } |
3161 | |
3162 | stack.reserve(asize: itemsSet.size()); |
3163 | for (QStandardItem *item : std::as_const(t&: itemsSet)) |
3164 | stack.push(t: item); |
3165 | |
3166 | //stream everything recursively |
3167 | while (!stack.isEmpty()) { |
3168 | QStandardItem *item = stack.pop(); |
3169 | if (itemsSet.contains(value: item)) //if the item is selection 'top-level', stream its position |
3170 | stream << item->row() << item->column(); |
3171 | |
3172 | stream << *item << item->columnCount() << int(item->d_ptr->children.size()); |
3173 | stack += item->d_ptr->children; |
3174 | } |
3175 | |
3176 | data->setData(mimetype: format, data: encoded); |
3177 | return data.release(); |
3178 | } |
3179 | |
3180 | |
3181 | /* \internal |
3182 | Used by QStandardItemModel::dropMimeData |
3183 | stream out an item and his children |
3184 | */ |
3185 | void QStandardItemModelPrivate::decodeDataRecursive(QDataStream &stream, QStandardItem *item) |
3186 | { |
3187 | int colCount, childCount; |
3188 | stream >> *item; |
3189 | stream >> colCount >> childCount; |
3190 | item->setColumnCount(colCount); |
3191 | |
3192 | int childPos = childCount; |
3193 | |
3194 | while(childPos > 0) { |
3195 | childPos--; |
3196 | QStandardItem *child = createItem(); |
3197 | decodeDataRecursive(stream, item: child); |
3198 | item->setChild( row: childPos / colCount, column: childPos % colCount, item: child); |
3199 | } |
3200 | } |
3201 | |
3202 | |
3203 | /*! |
3204 | \reimp |
3205 | */ |
3206 | bool QStandardItemModel::dropMimeData(const QMimeData *data, Qt::DropAction action, |
3207 | int row, int column, const QModelIndex &parent) |
3208 | { |
3209 | Q_D(QStandardItemModel); |
3210 | // check if the action is supported |
3211 | if (!data || !(action == Qt::CopyAction || action == Qt::MoveAction)) |
3212 | return false; |
3213 | // check if the format is supported |
3214 | const QString format = qStandardItemModelDataListMimeType(); |
3215 | if (!data->hasFormat(mimetype: format)) |
3216 | return QAbstractItemModel::dropMimeData(data, action, row, column, parent); |
3217 | |
3218 | if (row > rowCount(parent)) |
3219 | row = rowCount(parent); |
3220 | if (row == -1) |
3221 | row = rowCount(parent); |
3222 | if (column == -1) |
3223 | column = 0; |
3224 | |
3225 | // decode and insert |
3226 | QByteArray encoded = data->data(mimetype: format); |
3227 | QDataStream stream(&encoded, QIODevice::ReadOnly); |
3228 | |
3229 | |
3230 | //code based on QAbstractItemModel::decodeData |
3231 | // adapted to work with QStandardItem |
3232 | int top = INT_MAX; |
3233 | int left = INT_MAX; |
3234 | int bottom = 0; |
3235 | int right = 0; |
3236 | QList<int> rows, columns; |
3237 | QList<QStandardItem *> items; |
3238 | |
3239 | while (!stream.atEnd()) { |
3240 | int r, c; |
3241 | QStandardItem *item = d->createItem(); |
3242 | stream >> r >> c; |
3243 | d->decodeDataRecursive(stream, item); |
3244 | |
3245 | rows.append(t: r); |
3246 | columns.append(t: c); |
3247 | items.append(t: item); |
3248 | top = qMin(a: r, b: top); |
3249 | left = qMin(a: c, b: left); |
3250 | bottom = qMax(a: r, b: bottom); |
3251 | right = qMax(a: c, b: right); |
3252 | } |
3253 | |
3254 | // insert the dragged items into the table, use a bit array to avoid overwriting items, |
3255 | // since items from different tables can have the same row and column |
3256 | int dragRowCount = 0; |
3257 | int dragColumnCount = right - left + 1; |
3258 | |
3259 | // Compute the number of continuous rows upon insertion and modify the rows to match |
3260 | QList<int> rowsToInsert(bottom + 1); |
3261 | for (int i = 0; i < rows.size(); ++i) |
3262 | rowsToInsert[rows.at(i)] = 1; |
3263 | for (int i = 0; i < rowsToInsert.size(); ++i) { |
3264 | if (rowsToInsert.at(i) == 1){ |
3265 | rowsToInsert[i] = dragRowCount; |
3266 | ++dragRowCount; |
3267 | } |
3268 | } |
3269 | for (int i = 0; i < rows.size(); ++i) |
3270 | rows[i] = top + rowsToInsert.at(i: rows.at(i)); |
3271 | |
3272 | QBitArray isWrittenTo(dragRowCount * dragColumnCount); |
3273 | |
3274 | // make space in the table for the dropped data |
3275 | int colCount = columnCount(parent); |
3276 | if (colCount < dragColumnCount + column) { |
3277 | insertColumns(column: colCount, count: dragColumnCount + column - colCount, parent); |
3278 | colCount = columnCount(parent); |
3279 | } |
3280 | insertRows(row, count: dragRowCount, parent); |
3281 | |
3282 | row = qMax(a: 0, b: row); |
3283 | column = qMax(a: 0, b: column); |
3284 | |
3285 | QStandardItem *parentItem = itemFromIndex (index: parent); |
3286 | if (!parentItem) |
3287 | parentItem = invisibleRootItem(); |
3288 | |
3289 | QList<QPersistentModelIndex> newIndexes(items.size()); |
3290 | // set the data in the table |
3291 | for (int j = 0; j < items.size(); ++j) { |
3292 | int relativeRow = rows.at(i: j) - top; |
3293 | int relativeColumn = columns.at(i: j) - left; |
3294 | int destinationRow = relativeRow + row; |
3295 | int destinationColumn = relativeColumn + column; |
3296 | int flat = (relativeRow * dragColumnCount) + relativeColumn; |
3297 | // if the item was already written to, or we just can't fit it in the table, create a new row |
3298 | if (destinationColumn >= colCount || isWrittenTo.testBit(i: flat)) { |
3299 | destinationColumn = qBound(min: column, val: destinationColumn, max: colCount - 1); |
3300 | destinationRow = row + dragRowCount; |
3301 | insertRows(row: row + dragRowCount, count: 1, parent); |
3302 | flat = (dragRowCount * dragColumnCount) + relativeColumn; |
3303 | isWrittenTo.resize(size: ++dragRowCount * dragColumnCount); |
3304 | } |
3305 | if (!isWrittenTo.testBit(i: flat)) { |
3306 | newIndexes[j] = index(row: destinationRow, column: destinationColumn, parent: parentItem->index()); |
3307 | isWrittenTo.setBit(flat); |
3308 | } |
3309 | } |
3310 | |
3311 | for(int k = 0; k < newIndexes.size(); k++) { |
3312 | if (newIndexes.at(i: k).isValid()) { |
3313 | parentItem->setChild(row: newIndexes.at(i: k).row(), column: newIndexes.at(i: k).column(), item: items.at(i: k)); |
3314 | } else { |
3315 | delete items.at(i: k); |
3316 | } |
3317 | } |
3318 | |
3319 | return true; |
3320 | } |
3321 | |
3322 | QT_END_NAMESPACE |
3323 | |
3324 | #include "moc_qstandarditemmodel.cpp" |
3325 |
Definitions
- DataFlagsRole
- qStandardItemModelDataListMimeType
- QStandardItemModelLessThan
- QStandardItemModelLessThan
- operator()
- QStandardItemModelGreaterThan
- QStandardItemModelGreaterThan
- operator()
- position
- setChild
- changeFlags
- childDeleted
- ByNormalizedRole
- normalizedRole
- operator()
- operator()
- roleMapStandardItemDataTransform
- roleMapStandardItemDataUnion
- setItemData
- itemData
- sortChildren
- setModel
- QStandardItemModelPrivate
- ~QStandardItemModelPrivate
- init
- _q_emitItemChanged
- insertRows
- insertRows
- insertColumns
- itemChanged
- rowsAboutToBeInserted
- columnsAboutToBeInserted
- rowsAboutToBeRemoved
- columnsAboutToBeRemoved
- rowsInserted
- columnsInserted
- rowsRemoved
- columnsRemoved
- QStandardItem
- QStandardItem
- QStandardItem
- QStandardItem
- QStandardItem
- QStandardItem
- operator=
- ~QStandardItem
- parent
- setData
- clearData
- data
- multiData
- emitDataChanged
- setFlags
- flags
- setEnabled
- setEditable
- setSelectable
- setCheckable
- setAutoTristate
- setUserTristate
- setDragEnabled
- setDropEnabled
- row
- column
- index
- model
- setRowCount
- rowCount
- setColumnCount
- columnCount
- insertRow
- insertRows
- insertColumn
- insertRows
- insertColumns
- removeRow
- removeColumn
- removeRows
- removeColumns
- hasChildren
- setChild
- child
- takeChild
- takeRow
- takeColumn
- operator<
- sortChildren
- clone
- type
- read
- write
- operator>>
- operator<<
- QStandardItemModel
- QStandardItemModel
- QStandardItemModel
- ~QStandardItemModel
- setItemRoleNames
- roleNames
- clear
- itemFromIndex
- indexFromItem
- setRowCount
- setColumnCount
- setItem
- item
- invisibleRootItem
- setHorizontalHeaderItem
- horizontalHeaderItem
- setVerticalHeaderItem
- verticalHeaderItem
- setHorizontalHeaderLabels
- setVerticalHeaderLabels
- setItemPrototype
- itemPrototype
- findItems
- appendRow
- appendColumn
- insertRow
- insertColumn
- takeItem
- takeRow
- takeColumn
- takeHorizontalHeaderItem
- takeVerticalHeaderItem
- sortRole
- setSortRole
- bindableSortRole
- columnCount
- data
- multiData
- flags
- hasChildren
- headerData
- supportedDropActions
- index
- insertColumns
- insertRows
- itemData
- parent
- removeColumns
- removeRows
- rowCount
- setData
- clearItemData
- setHeaderData
- setItemData
- sort
- mimeTypes
- mimeData
- decodeDataRecursive
Start learning QML with our Intro Training
Find out more