KanoopGuiQt 1.3.0
Qt GUI utility library
Loading...
Searching...
No Matches
abstractitemmodel.h
1/******************************************************************************************
2**
3** abstractitemmodel.h
4**
5** Extends the native Qt QAbstractItemModel to provide additional funtionality which
6** I've found useful over the years.
7**
8** Most of the methods provide a default implementation of QAbstractItemModel and most
9** other methods as self-explainitory if you are familiar with the Qt Abstract Model.
10**
11** It is intended to work with objects inherited from AbstractModelItem.
12**
13** Moved from my Tesseract Engineering repo to open-source
14**
15** Author: Stephen Punak
16** Created: Fri Oct 27 09:12:34 2023
17**
18******************************************************************************************/
19#ifndef ABSTRACTITEMMODEL_H
20#define ABSTRACTITEMMODEL_H
21#include <QAbstractItemModel>
22#include <Kanoop/gui/abstractmodelitem.h>
23#include <Kanoop/gui/tableheader.h>
24#include <Kanoop/utility/loggingbaseclass.h>
25
26/**
27 * @brief Extended QAbstractItemModel providing EntityMetadata-based item lookup and header management.
28 *
29 * Subclass this together with AbstractModelItem to build tree, table, or list models.
30 * Column and row headers are managed internally; entity lookup helpers search by type or UUID.
31 */
32class LIBKANOOPGUI_EXPORT AbstractItemModel : public QAbstractItemModel,
33 public LoggingBaseClass
34{
35 Q_OBJECT
36public:
37 /** @brief Construct with an optional parent. */
38 AbstractItemModel(QObject* parent = nullptr);
39
40 /**
41 * @brief Construct with a logging category and optional parent.
42 * @param loggingCategory Category name used for log output
43 * @param parent Optional QObject parent
44 */
45 AbstractItemModel(const QString& loggingCategory, QObject* parent = nullptr);
46
47 /** @brief Destructor — deletes all root items. */
49 qDeleteAll(_rootItems);
50 }
51
52 // EntityMetadata Helpers
53 /**
54 * @brief Return all indexes whose item has the given entity type.
55 * @param type Entity type to search for
56 * @return List of matching model indexes
57 */
58 virtual QModelIndexList indexesOfEntityType(int type) const;
59
60 /**
61 * @brief Return all indexes matching entity type and a role value.
62 * @param type Entity type to search for
63 * @param data Value to match against the given role
64 * @param role Model role to compare (default Qt::DisplayRole)
65 * @return List of matching model indexes
66 */
67 virtual QModelIndexList indexesOfEntity(int type, const QVariant &data, int role = Qt::DisplayRole) const;
68
69 /**
70 * @brief Return all indexes whose item UUID matches.
71 * @param uuid UUID to search for
72 * @return List of matching model indexes
73 */
74 virtual QModelIndexList indexesOfEntityUuid(const QUuid& uuid) const;
75
76 /**
77 * @brief Return the first index whose item has the given entity type.
78 * @param type Entity type to search for
79 * @return First matching index, or invalid index if not found
80 */
81 virtual QModelIndex firstIndexOfEntityType(int type) const;
82
83 /**
84 * @brief Return the first index matching entity type and a role value.
85 * @param type Entity type to search for
86 * @param data Value to match against the given role
87 * @param role Model role to compare (default Qt::DisplayRole)
88 * @return First matching index, or invalid index if not found
89 */
90 virtual QModelIndex firstIndexOfEntity(int type, const QVariant &data, int role = Qt::DisplayRole) const;
91
92 /**
93 * @brief Return the first index whose item UUID matches.
94 * @param uuid UUID to search for
95 * @return First matching index, or invalid index if not found
96 */
97 virtual QModelIndex firstIndexOfEntityUuid(const QUuid& uuid) const;
98
99 /**
100 * @brief Return the first child index under parent with the given entity type.
101 * @param parent Parent index to search under
102 * @param type Entity type to search for
103 * @param recursive Whether to search recursively (default true)
104 * @return First matching child index, or invalid index if not found
105 */
106 virtual QModelIndex firstIndexOfChildEntityType(const QModelIndex& parent, int type, bool recursive = true) const;
107
108 /**
109 * @brief Return the first child index under parent whose UUID matches.
110 * @param parent Parent index to search under
111 * @param uuid UUID to search for
112 * @param recursive Whether to search recursively (default true)
113 * @return First matching child index, or invalid index if not found
114 */
115 virtual QModelIndex firstIndexOfChildEntityUuid(const QModelIndex& parent, const QUuid& uuid, bool recursive = true) const;
116
117 /**
118 * @brief Return the first match starting from startSearchIndex.
119 * @param startSearchIndex Index to begin searching from
120 * @param role Model role to compare
121 * @param value Value to match
122 * @param flags Match flags
123 * @return First matching index, or invalid index if not found
124 */
125 virtual QModelIndex firstMatch(const QModelIndex& startSearchIndex, int role, const QVariant& value, Qt::MatchFlags flags = Qt::MatchFlags(Qt::MatchStartsWith|Qt::MatchWrap)) const;
126
127 /**
128 * @brief Return the first match anywhere in the model.
129 * @param role Model role to compare
130 * @param value Value to match
131 * @param flags Match flags
132 * @return First matching index, or invalid index if not found
133 */
134 virtual QModelIndex firstMatch(int role, const QVariant& value, Qt::MatchFlags flags = Qt::MatchFlags(Qt::MatchStartsWith|Qt::MatchWrap)) const;
135
136 /**
137 * @brief Return child indexes under parent, optionally filtered by entity type.
138 * @param parent Parent index
139 * @param type Entity type filter (-1 to return all types)
140 * @param recursive Whether to search recursively (default true)
141 * @return List of matching child indexes
142 */
143 virtual QModelIndexList childIndexes(const QModelIndex& parent, int type = -1, bool recursive = true) const;
144
145 /**
146 * @brief Return all column headers as a sorted list.
147 * @return List of TableHeader objects ordered by column index
148 */
150
151 /**
152 * @brief Return the column header for a given section.
153 * @param section Column section index
154 * @return TableHeader for that section
155 */
156 TableHeader columnHeader(int section) const { return _columnHeaders.value(section); }
157
158 /**
159 * @brief Return the row header for a given row.
160 * @param row Row index
161 * @return TableHeader for that row
162 */
163 TableHeader rowHeader(int row) const { return _rowHeaders.value(row); }
164
165 /**
166 * @brief Return the column index for a header type.
167 * @param type Header type identifier
168 * @return Column index, or -1 if not found
169 */
170 int columnForHeader(int type) const;
171
172 /**
173 * @brief Return all persistent model indexes.
174 * @return List of persistent indexes currently held by the model
175 */
176 QModelIndexList getPersistentIndexes() const;
177
178 /**
179 * @brief Emit dataChanged for the rectangular region from topLeft to bottomRight.
180 * @param topLeft Top-left corner of the changed region
181 * @param bottomRight Bottom-right corner of the changed region
182 */
183 virtual void refresh(const QModelIndex& topLeft, const QModelIndex& bottomRight);
184
185 // QAbstractItemModel interface
186 /** @brief Return the model index for the item at row/column under parent. */
187 virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
188#if NEEDS_TESTING
189 virtual QModelIndex sibling(int row, int column, const QModelIndex& idx) const override;
190#endif
191 /** @brief Return the parent index of a child index. */
192 virtual QModelIndex parent(const QModelIndex &child) const override;
193 /** @brief Return the number of rows under parent. */
194 virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override;
195 /** @brief Return the number of columns under parent. */
196 virtual int columnCount(const QModelIndex &parent = QModelIndex()) const override;
197 /** @brief Return the data for the given index and role. */
198 virtual QVariant data(const QModelIndex &index, int role) const override;
199 /** @brief Return header data for the given section, orientation, and role. */
200 virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
201 /** @brief Remove count rows starting at row under parentIndex. */
202 virtual bool removeRows(int row, int count, const QModelIndex& parentIndex) override;
203 /** @brief Return true if parent has child items. */
204 virtual bool hasChildren(const QModelIndex& parent) const override;
205 /** @brief Set header data for the given section, orientation, and role. */
206 virtual bool setHeaderData(int section, Qt::Orientation orientation, const QVariant& value, int role) override;
207
208 /**
209 * @brief Show or hide the column whose header has the given type.
210 * @param type Column header type identifier
211 * @param visible Whether to make the column visible
212 */
213 void setColumnHeaderVisible(int type, bool visible);
214
215 /**
216 * @brief Format a QModelIndex as a debug string.
217 * @param index Index to format
218 * @param includeText Whether to include display text (default false)
219 * @return Human-readable string describing the index
220 */
221 static QString indexToString(const QModelIndex& index, bool includeText = false);
222
223protected:
224 /** @brief Return the list of root items. */
225 AbstractModelItem::List rootItems() const { return _rootItems; }
226 /** @brief Return a mutable reference to the root items list. */
227 AbstractModelItem::List& rootItemsRef() { return _rootItems; }
228 /** @brief Return a const copy of the root items list. */
229 const AbstractModelItem::List rootItemsConst() const { return _rootItems; }
230 /** @brief Return the number of root items. */
231 int rootItemCount() const { return _rootItems.count(); }
232
233 /**
234 * @brief Insert an item at the given row among root items.
235 * @param row Insertion row index
236 * @param item Item to insert
237 * @return Pointer to the inserted item
238 */
240
241 /**
242 * @brief Append an item to the root items list.
243 * @param item Item to append
244 * @return Pointer to the appended item
245 */
247
248 /**
249 * @brief Append multiple items to the root items list.
250 * @param items Items to append
251 */
252 void appendRootItems(QList<AbstractModelItem*> items);
253
254 /**
255 * @brief Append a column header with the given type and display text.
256 * @param type Column type identifier
257 * @param text Header display text
258 */
259 void appendColumnHeader(int type, const QString& text);
260
261 /**
262 * @brief Append a column header with a custom text color.
263 * @param type Column type identifier
264 * @param columnTextColor Text color for cells in this column
265 * @param text Header display text
266 */
267 void appendColumnHeader(int type, const QColor& columnTextColor, const QString& text);
268
269 /**
270 * @brief Insert a column header at the given index.
271 * @param type Column type identifier
272 * @param index Position to insert at
273 * @param text Header display text
274 */
275 void insertColumnHeader(int type, int index, const QString& text);
276
277 /** @brief Append a column header (ad-hoc alias for appendColumnHeader). */
278 void appendAdHocColumnHeader(int type, const QString& value) { appendColumnHeader(type, value); }
279
280 /** @brief Insert a column header at the given index (ad-hoc alias for insertColumnHeader). */
281 void insertAdHocColumnHeader(int type, int index, const QString& value) { insertColumnHeader(type, index, value); }
282
283 /**
284 * @brief Delete the column header at the given section.
285 * @param section Section index to remove
286 */
287 void deleteColumnHeader(int section);
288
289 /**
290 * @brief Append a row header with optional display text.
291 * @param type Row type identifier
292 * @param value Optional display text
293 */
294 void appendRowHeader(int type, const QString& value = QString());
295
296 /** @brief Append a row header (ad-hoc alias for appendRowHeader). */
297 void appendAdHocRowHeader(int type, const QString& value) { appendRowHeader(type, value); }
298
299 /**
300 * @brief Change the display text of a column header.
301 * @param section Section index to update
302 * @param text New display text
303 */
304 void setColumnHeaderText(int section, const QString& text);
305
306 /**
307 * @brief Associate an EntityMetadata with a column header type.
308 * @param type Column type identifier
309 * @param metadata Metadata to associate
310 */
311 void setColumnHeaderEntityMetadata(int type, const EntityMetadata& metadata);
312
313 /**
314 * @brief Retrieve the EntityMetadata for a column header type.
315 * @param type Column type identifier
316 * @return Associated EntityMetadata
317 */
318 EntityMetadata columnEntityMetadata(int type) const;
319
320 /**
321 * @brief Set the text color for all cells in the column of the given type.
322 * @param type Column type identifier
323 * @param color Text color to apply
324 */
325 void setColumnTextColor(int type, const QColor& color);
326
327 /**
328 * @brief Delete a root item from the model.
329 * @param item Root item to delete
330 */
332
333 /**
334 * @brief Delete all root items with the given UUID.
335 * @param uuid UUID to match
336 */
337 void deleteRootItems(const QUuid& uuid);
338
339 /**
340 * @brief Delete all root items matching the given EntityMetadata.
341 * @param metadata Metadata to match
342 */
343 void deleteRootItems(const EntityMetadata& metadata);
344
345 /**
346 * @brief Delete any item (at any level) with the given UUID.
347 * @param uuid UUID to match
348 */
349 void deleteItem(const QUuid& uuid);
350
351 /**
352 * @brief Update the item at itemIndex with new metadata and emit dataChanged.
353 * @param itemIndex Index of the item to update
354 * @param metadata New metadata to apply
355 */
356 void updateItemAtIndex(const QModelIndex& itemIndex, const EntityMetadata &metadata);
357
358 /**
359 * @brief Update items at multiple indexes with new metadata.
360 * @param indexes Indexes of items to update
361 * @param metadata New metadata to apply
362 */
363 void updateItemsAtIndexes(const QModelIndexList& indexes, const EntityMetadata &metadata);
364
365 /** @brief Emit dataChanged for the entire model. */
367
368 /**
369 * @brief Find all items of type T in the model (root and their children).
370 * @tparam T Pointer type of items to find (must derive from AbstractModelItem)
371 * @return List of matching items cast to T
372 */
373 template <typename T>
374 QList<T> findItems() const
375 {
376 QList<T> result;
377 for(AbstractModelItem* item : rootItems()) {
378 T candidate = dynamic_cast<T>(item);
379 if(candidate != nullptr) {
380 result.append(candidate);
381 }
382 result.append(item->findChildren<T>(true));
383 }
384 return result;
385 }
386
387 /**
388 * @brief Find the first direct child of parentIndex matching a role/value pair.
389 * @param parentIndex Parent index to search under
390 * @param value Value to match
391 * @param role Role to compare
392 * @return First matching child index, or invalid index
393 */
394 QModelIndex findFirstDirectChild(const QModelIndex& parentIndex, const QVariant& value, int role) const;
395
396 /** @brief Return the column headers as an int-keyed map. */
397 TableHeader::IntMap columnHeadersIntMap() const { return _columnHeaders; }
398 /** @brief Return the row headers as an int-keyed map. */
399 TableHeader::IntMap rowHeadersIntMap() const { return _rowHeaders; }
400
401 /**
402 * @brief Emit dataChanged for all columns of the given row index.
403 * @param rowIndex Row index whose data changed
404 */
405 void emitRowChanged(const QModelIndex &rowIndex);
406
407public:
408 /**
409 * @brief Format a QModelIndex as a debug string (static alias).
410 * @param index Index to format
411 * @param includeText Whether to include display text
412 * @return Human-readable string
413 */
414 static QString toString(const QModelIndex& index, bool includeText = false);
415
416private:
417 /** @brief Shared constructor initialization. */
418 void commonInit();
419
420 AbstractModelItem::List _rootItems;
421
422 TableHeader::IntMap _columnHeaders;
423 TableHeader::IntMap _rowHeaders;
424
425 friend class AbstractModelItem;
426
427signals:
428 /** @brief Emitted after an entity is added to the model. */
429 void entityAdded(const EntityMetadata& metadata);
430 /** @brief Emitted after an entity is deleted from the model. */
431 void entityDeleted(const EntityMetadata& metadata);
432 /** @brief Emitted after an entity in the model is updated. */
433 void entityUpdated(const EntityMetadata& metadata);
434
435public slots:
436 /** @brief Remove all root items from the model. */
437 virtual void clear();
438 /** @brief Handle an entity-added event (no-op by default). */
439 virtual void addEntity(const EntityMetadata& metadata) { Q_UNUSED(metadata) }
440 /** @brief Handle an entity-deleted event (no-op by default). */
441 virtual void deleteEntity(const EntityMetadata& metadata) { Q_UNUSED(metadata) }
442 /** @brief Handle an entity-updated event (no-op by default). */
443 virtual void updateEntity(const EntityMetadata& metadata) { Q_UNUSED(metadata) }
444};
445
446#endif // ABSTRACTITEMMODEL_H
Extended QAbstractItemModel providing EntityMetadata-based item lookup and header management.
TableHeader columnHeader(int section) const
Return the column header for a given section.
const AbstractModelItem::List rootItemsConst() const
Return a const copy of the root items list.
virtual QModelIndex firstIndexOfChildEntityType(const QModelIndex &parent, int type, bool recursive=true) const
Return the first child index under parent with the given entity type.
virtual QVariant data(const QModelIndex &index, int role) const override
Return the data for the given index and role.
virtual QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
Return the model index for the item at row/column under parent.
void appendAdHocColumnHeader(int type, const QString &value)
Append a column header (ad-hoc alias for appendColumnHeader).
void refreshAll()
Emit dataChanged for the entire model.
QModelIndexList getPersistentIndexes() const
Return all persistent model indexes.
EntityMetadata columnEntityMetadata(int type) const
Retrieve the EntityMetadata for a column header type.
void updateItemAtIndex(const QModelIndex &itemIndex, const EntityMetadata &metadata)
Update the item at itemIndex with new metadata and emit dataChanged.
void appendRowHeader(int type, const QString &value=QString())
Append a row header with optional display text.
TableHeader::IntMap columnHeadersIntMap() const
Return the column headers as an int-keyed map.
void deleteRootItems(const EntityMetadata &metadata)
Delete all root items matching the given EntityMetadata.
void appendColumnHeader(int type, const QString &text)
Append a column header with the given type and display text.
void deleteColumnHeader(int section)
Delete the column header at the given section.
AbstractModelItem::List & rootItemsRef()
Return a mutable reference to the root items list.
TableHeader rowHeader(int row) const
Return the row header for a given row.
virtual void deleteEntity(const EntityMetadata &metadata)
Handle an entity-deleted event (no-op by default).
void setColumnHeaderText(int section, const QString &text)
Change the display text of a column header.
virtual QModelIndex firstIndexOfEntity(int type, const QVariant &data, int role=Qt::DisplayRole) const
Return the first index matching entity type and a role value.
QModelIndex findFirstDirectChild(const QModelIndex &parentIndex, const QVariant &value, int role) const
Find the first direct child of parentIndex matching a role/value pair.
AbstractItemModel(QObject *parent=nullptr)
Construct with an optional parent.
virtual QModelIndex firstMatch(const QModelIndex &startSearchIndex, int role, const QVariant &value, Qt::MatchFlags flags=Qt::MatchFlags(Qt::MatchStartsWith|Qt::MatchWrap)) const
Return the first match starting from startSearchIndex.
void setColumnTextColor(int type, const QColor &color)
Set the text color for all cells in the column of the given type.
virtual ~AbstractItemModel()
Destructor — deletes all root items.
virtual QModelIndex firstIndexOfEntityUuid(const QUuid &uuid) const
Return the first index whose item UUID matches.
void setColumnHeaderVisible(int type, bool visible)
Show or hide the column whose header has the given type.
virtual QModelIndex firstIndexOfChildEntityUuid(const QModelIndex &parent, const QUuid &uuid, bool recursive=true) const
Return the first child index under parent whose UUID matches.
static QString toString(const QModelIndex &index, bool includeText=false)
Format a QModelIndex as a debug string (static alias).
AbstractModelItem::List rootItems() const
Return the list of root items.
virtual QModelIndex parent(const QModelIndex &child) const override
Return the parent index of a child index.
void appendColumnHeader(int type, const QColor &columnTextColor, const QString &text)
Append a column header with a custom text color.
void emitRowChanged(const QModelIndex &rowIndex)
Emit dataChanged for all columns of the given row index.
virtual bool hasChildren(const QModelIndex &parent) const override
Return true if parent has child items.
void entityAdded(const EntityMetadata &metadata)
Emitted after an entity is added to the model.
virtual void refresh(const QModelIndex &topLeft, const QModelIndex &bottomRight)
Emit dataChanged for the rectangular region from topLeft to bottomRight.
AbstractModelItem * insertRootItem(int row, AbstractModelItem *item)
Insert an item at the given row among root items.
virtual void addEntity(const EntityMetadata &metadata)
Handle an entity-added event (no-op by default).
int rootItemCount() const
Return the number of root items.
AbstractModelItem * appendRootItem(AbstractModelItem *item)
Append an item to the root items list.
void deleteItem(const QUuid &uuid)
Delete any item (at any level) with the given UUID.
void updateItemsAtIndexes(const QModelIndexList &indexes, const EntityMetadata &metadata)
Update items at multiple indexes with new metadata.
virtual QModelIndex firstMatch(int role, const QVariant &value, Qt::MatchFlags flags=Qt::MatchFlags(Qt::MatchStartsWith|Qt::MatchWrap)) const
Return the first match anywhere in the model.
virtual QModelIndex firstIndexOfEntityType(int type) const
Return the first index whose item has the given entity type.
virtual bool removeRows(int row, int count, const QModelIndex &parentIndex) override
Remove count rows starting at row under parentIndex.
void appendRootItems(QList< AbstractModelItem * > items)
Append multiple items to the root items list.
AbstractItemModel(const QString &loggingCategory, QObject *parent=nullptr)
Construct with a logging category and optional parent.
virtual QModelIndexList childIndexes(const QModelIndex &parent, int type=-1, bool recursive=true) const
Return child indexes under parent, optionally filtered by entity type.
TableHeader::IntMap rowHeadersIntMap() const
Return the row headers as an int-keyed map.
int columnForHeader(int type) const
Return the column index for a header type.
void entityUpdated(const EntityMetadata &metadata)
Emitted after an entity in the model is updated.
void entityDeleted(const EntityMetadata &metadata)
Emitted after an entity is deleted from the model.
virtual bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role) override
Set header data for the given section, orientation, and role.
void setColumnHeaderEntityMetadata(int type, const EntityMetadata &metadata)
Associate an EntityMetadata with a column header type.
static QString indexToString(const QModelIndex &index, bool includeText=false)
Format a QModelIndex as a debug string.
TableHeader::List columnHeaders() const
Return all column headers as a sorted list.
QList< T > findItems() const
Find all items of type T in the model (root and their children).
void deleteRootItems(const QUuid &uuid)
Delete all root items with the given UUID.
virtual QModelIndexList indexesOfEntityUuid(const QUuid &uuid) const
Return all indexes whose item UUID matches.
virtual QModelIndexList indexesOfEntity(int type, const QVariant &data, int role=Qt::DisplayRole) const
Return all indexes matching entity type and a role value.
virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const override
Return header data for the given section, orientation, and role.
virtual int rowCount(const QModelIndex &parent=QModelIndex()) const override
Return the number of rows under parent.
virtual void clear()
Remove all root items from the model.
void deleteRootItem(AbstractModelItem *item)
Delete a root item from the model.
virtual int columnCount(const QModelIndex &parent=QModelIndex()) const override
Return the number of columns under parent.
void insertColumnHeader(int type, int index, const QString &text)
Insert a column header at the given index.
void insertAdHocColumnHeader(int type, int index, const QString &value)
Insert a column header at the given index (ad-hoc alias for insertColumnHeader).
void appendAdHocRowHeader(int type, const QString &value)
Append a row header (ad-hoc alias for appendRowHeader).
virtual void updateEntity(const EntityMetadata &metadata)
Handle an entity-updated event (no-op by default).
virtual QModelIndexList indexesOfEntityType(int type) const
Return all indexes whose item has the given entity type.
A list of AbstractModelItem pointers with UUID and entity-type search helpers.
Base class for items managed by AbstractItemModel.
An int-keyed map of TableHeader objects with bulk-operation helpers.
A list of TableHeader objects with name and type search helpers.
Descriptor for a single column or row header in a model/view.
Definition tableheader.h:30