KanoopGuiQt 1.3.0
Qt GUI utility library
Loading...
Searching...
No Matches
treeviewbase.h
1/******************************************************************************************
2**
3** treeviewbase.h
4**
5** Moved from my Tesseract Engineering repo to open-source
6**
7** Author: Stephen Punak
8** Created: Sun Oct 22 17:41:53 2023
9**
10******************************************************************************************/
11#ifndef TREEVIEWBASE_H
12#define TREEVIEWBASE_H
13#include <Kanoop/entitymetadata.h>
14
15#include <QTreeView>
16
17#include <Kanoop/utility/loggingbaseclass.h>
18#include <Kanoop/gui/libkanoopgui.h>
19
20class QSortFilterProxyModel;
21class QStyledItemDelegate;
23
24/**
25 * @brief QTreeView subclass integrating AbstractItemModel with rich navigation helpers.
26 *
27 * TreeViewBase wraps its source model in a QSortFilterProxyModel and provides helpers
28 * for UUID-based navigation, text-based forward/backward search, recursive collapse,
29 * column visibility management, header state persistence, and delegate assignment.
30 */
31class LIBKANOOPGUI_EXPORT TreeViewBase : public QTreeView,
32 public LoggingBaseClass
33{
34 Q_OBJECT
35public:
36 /**
37 * @brief Construct with an optional parent widget.
38 * @param parent Optional QWidget parent
39 */
40 TreeViewBase(QWidget* parent = nullptr);
41
42 /**
43 * @brief Return the entity type of the item at a view position.
44 * @param pos View-local position
45 * @return Entity type integer, or -1 if no item at that position
46 */
47 int entityTypeAtPos(const QPoint& pos);
48
49 /**
50 * @brief Return the EntityMetadata of the currently selected item.
51 * @return EntityMetadata for the current item
52 */
53 virtual EntityMetadata currentMetadata() const;
54
55 /**
56 * @brief Return the EntityMetadata of the item at a view position.
57 * @param pos View-local position
58 * @return EntityMetadata at that position
59 */
60 virtual EntityMetadata metadataAtPos(const QPoint& pos) const;
61
62 /**
63 * @brief Return the first index whose item UUID matches.
64 * @param uuid UUID to search for
65 * @return First matching index, or invalid index if not found
66 */
67 virtual QModelIndex firstIndexOfEntityUuid(const QUuid& uuid) const;
68
69 /**
70 * @brief Return all indexes whose item UUID matches.
71 * @param uuid UUID to search for
72 * @return List of matching indexes
73 */
74 virtual QModelIndexList indexesOfUuid(const QUuid& uuid) const;
75
76 /**
77 * @brief Select the item with the given UUID and optionally scroll to it.
78 * @param uuid UUID of the item to select
79 * @param scrollHint How to scroll to make the item visible
80 */
81 virtual void setCurrentUuid(const QUuid& uuid, ScrollHint scrollHint = EnsureVisible);
82
83 /**
84 * @brief Set the current index and optionally scroll to it.
85 * @param index Index to make current
86 * @param scrollHint How to scroll to make the item visible
87 */
88 virtual void setCurrentIndex(const QModelIndex& index, ScrollHint scrollHint = EnsureVisible);
89
90 /**
91 * @brief Find the next index whose display text matches, searching forward.
92 * @param text Text to search for
93 * @param fromIndex Starting index for the search
94 * @return Next matching index, or invalid index if not found
95 */
96 virtual QModelIndex findNextMatch(const QString& text, const QModelIndex& fromIndex) const;
97
98 /**
99 * @brief Find the previous index whose display text matches, searching backward.
100 * @param text Text to search for
101 * @param fromIndex Starting index for the backward search
102 * @return Previous matching index, or invalid index if not found
103 */
104 virtual QModelIndex findPreviousMatch(const QString& text, const QModelIndex& fromIndex) const;
105
106 /**
107 * @brief Return the deepest last child of the given index.
108 * @param from Starting index
109 * @return Last descendant index
110 */
111 virtual QModelIndex finalChildIndex(const QModelIndex& from) const;
112
113 /**
114 * @brief Return the next index in display order after from.
115 * @param from Reference index
116 * @return Next index, or invalid if at the end
117 */
118 virtual QModelIndex nextIndex(const QModelIndex& from) const;
119
120 /**
121 * @brief Return the previous index in display order before from.
122 * @param from Reference index
123 * @return Previous index, or invalid if at the beginning
124 */
125 virtual QModelIndex previousIndex(const QModelIndex& from) const;
126
127 /**
128 * @brief Search backward from start for indexes matching a role value.
129 * @param start Index to begin searching from
130 * @param role Model role to compare
131 * @param value Value to match
132 * @param hits Maximum number of matches to return
133 * @param flags Match flags
134 * @return List of matching indexes in reverse order
135 */
136 virtual QModelIndexList matchBackwards(const QModelIndex &start, int role,
137 const QVariant &value, int hits = 1,
138 Qt::MatchFlags flags = Qt::MatchFlags(Qt::MatchStartsWith|Qt::MatchWrap)) const;
139
140 /**
141 * @brief Return the current source model index (mapped through the proxy).
142 * @return Source model index corresponding to the current view index
143 */
144 QModelIndex currentSourceIndex() const;
145
146 /**
147 * @brief Save the header and expansion state to a byte array.
148 * @return Serialized state
149 */
150 QByteArray saveState() const;
151
152 /**
153 * @brief Restore header and expansion state from a byte array.
154 * @param state Previously saved state
155 */
156 void restoreState(const QByteArray& state);
157
158 /** @brief Restore horizontal header state (column widths/order) from settings. */
160
161 /**
162 * @brief Set the model, wrapping it in an internal sort/filter proxy.
163 * @param model Model to display (should derive from AbstractItemModel)
164 */
165 virtual void setModel(QAbstractItemModel* model) override;
166
167 /**
168 * @brief Set the selection model.
169 * @param selectionModel Selection model to use
170 */
171 virtual void setSelectionModel(QItemSelectionModel* selectionModel) override;
172
173 /**
174 * @brief Return the underlying AbstractItemModel (without the proxy).
175 * @return Pointer to the source model
176 */
177 AbstractItemModel* sourceModel() const { return _sourceModel; }
178
179 /**
180 * @brief Return the internal sort/filter proxy model.
181 * @return Pointer to the proxy model
182 */
183 QSortFilterProxyModel* proxyModel() const { return _proxyModel; }
184
185 /**
186 * @brief Recursively collapse index and all its descendants up to a depth limit.
187 * @param index Root index to collapse from
188 * @param depth Maximum depth to collapse (-1 for unlimited)
189 */
190 void collapseRecursively(const QModelIndex& index, int depth = -1);
191
192 /**
193 * @brief Return whether the deepest expanded leaf under index is expanded.
194 * @param index Root index to check
195 * @param recursive Whether to check recursively
196 * @return true if the leaf is expanded
197 */
198 bool isLeafExpanded(const QModelIndex& index, bool recursive = true) const;
199
200 /**
201 * @brief Return whether the given index is visible in the current viewport.
202 * @param index Index to check
203 * @return true if the index row is within the visible area
204 */
205 bool isIndexVisible(const QModelIndex& index) const;
206
207 /**
208 * @brief Assign a custom item delegate to the column of the given header type.
209 * @param type Column header type identifier
210 * @param delegate Delegate to install
211 */
212 void setColumnDelegate(int type, QStyledItemDelegate* delegate);
213
214 /**
215 * @brief Return the column index for a given header type.
216 * @param headerType Header type identifier
217 * @return Column index, or -1 if not found
218 */
219 int columnForHeaderType(int headerType) const;
220
221 /**
222 * @brief Show or hide columns identified by header types.
223 * @param headerTypes List of header type identifiers
224 * @param visible true to show, false to hide
225 * @param exclusive If true, hide all other columns
226 */
227 void setColumnTypesVisible(const QList<int>& headerTypes, bool visible, bool exclusive = false);
228
229 /**
230 * @brief Show or hide columns by column index.
231 * @param columns List of column indexes
232 * @param visible true to show, false to hide
233 * @param exclusive If true, hide all other columns
234 */
235 void setColumnsVisible(const QList<int>& columns, bool visible, bool exclusive = false);
236
237public slots:
238 /**
239 * @brief Refresh the display of a set of columns.
240 * @param columns Column indexes to refresh
241 */
242 virtual void refreshVisibleColumns(const QList<int>& columns);
243
244 /**
245 * @brief Refresh the display of a set of source model indexes.
246 * @param indexes Source model indexes to refresh
247 */
248 virtual void refreshVisibleIndexes(const QModelIndexList& indexes);
249
250 /**
251 * @brief Refresh a single source model index.
252 * @param sourceIndex Source model index to refresh
253 */
254 virtual void refreshIndex(const QModelIndex& sourceIndex);
255
256 /** @brief Remove all items from the view model. */
257 virtual void clear();
258
259protected:
260 /**
261 * @brief Walk ancestors of the current index to find one with the given entity type.
262 * @param entityMetadataType Entity type to search for
263 * @return EntityMetadata of the first matching ancestor
264 */
265 EntityMetadata findCurrentParent(int entityMetadataType) const;
266
267 /**
268 * @brief Walk ancestors of index to find one with the given entity type.
269 * @param index Starting index
270 * @param entityMetadataType Entity type to search for
271 * @return EntityMetadata of the first matching ancestor
272 */
273 EntityMetadata findFirstParent(const QModelIndex& index, int entityMetadataType) const;
274
275 /**
276 * @brief Return all ancestor indexes of index.
277 * @param index Starting index
278 * @return List of ancestor indexes from nearest to root
279 */
280 QModelIndexList findParents(const QModelIndex& index) const;
281
282 /**
283 * @brief Map a list of view indexes to their source model equivalents.
284 * @param indexes Proxy model indexes to map
285 * @return Corresponding source model indexes
286 */
287 QModelIndexList mapToSource(const QModelIndexList& indexes) const;
288
289 /**
290 * @brief Override to add application-specific items to the header context menu.
291 * @param menu Menu to populate
292 * @param globalPos Global cursor position when the menu was requested
293 */
294 virtual void addHeaderContextMenuItems(QMenu* menu, const QPoint& globalPos) { Q_UNUSED(menu) Q_UNUSED(globalPos) }
295
296 /** @brief Log a model index at the given log level. */
297 static void logIndex(const char* file, int lineNumber, Log::LogLevel level, const QModelIndex& index, const QString& text);
298 /** @brief Test whether index matches value under role using flags, appending to foundIndexes. */
299 static bool testMatch(const QModelIndex& index, int role, const QVariant &value, Qt::MatchFlags flags, QModelIndexList& foundIndexes);
300
301private:
302 AbstractItemModel* _sourceModel = nullptr;
303 QSortFilterProxyModel* _proxyModel = nullptr;
304 QMap<int, QStyledItemDelegate*> _columnDelegates;
305
306 QAction* _actionColSettings = nullptr;
307 QAction* _actionHideCol = nullptr;
308 QAction* _actionAutoResizeCols = nullptr;
309 QAction* _actionResetCols = nullptr;
310
311 QPoint _contextMenuPos;
312
313signals:
314 /** @brief Emitted when an item is selected programmatically. */
315 void itemProgramaticallySelected(const QModelIndex& index);
316 /** @brief Emitted when the header is resized or reordered. */
318 /** @brief Emitted when the current selection changes. */
320 /**
321 * @brief Emitted when the current index changes.
322 * @param index The newly current index
323 */
324 void currentIndexChanged(const QModelIndex& index);
325
326 /** @brief Emitted when an entity is added. */
327 void entityAdded(const EntityMetadata& metadata);
328 /** @brief Emitted when an entity is deleted. */
329 void entityDeleted(const EntityMetadata& metadata);
330 /** @brief Emitted when an entity is updated. */
331 void entityUpdated(const EntityMetadata& metadata);
332
333private slots:
334 virtual void onHorizontalHeaderResized(int /*logicalIndex*/, int /*oldSize*/, int /*newSize*/);
335
336 void onHeaderContextMenuRequested();
337 void onColumnSettingsClicked();
338 void onHideColumnClicked();
339 void onAutoResizeColumnsClicked();
340 void onResetColumnsClicked();
341 void onCurrentSelectionChanged(const QModelIndex& current, const QModelIndex& previous);
342};
343
344#endif // TREEVIEWBASE_H
Extended QAbstractItemModel providing EntityMetadata-based item lookup and header management.
QTreeView subclass integrating AbstractItemModel with rich navigation helpers.
void headerChanged()
Emitted when the header is resized or reordered.
virtual void addHeaderContextMenuItems(QMenu *menu, const QPoint &globalPos)
Override to add application-specific items to the header context menu.
void setColumnDelegate(int type, QStyledItemDelegate *delegate)
Assign a custom item delegate to the column of the given header type.
EntityMetadata findCurrentParent(int entityMetadataType) const
Walk ancestors of the current index to find one with the given entity type.
QSortFilterProxyModel * proxyModel() const
Return the internal sort/filter proxy model.
void entityAdded(const EntityMetadata &metadata)
Emitted when an entity is added.
virtual void setCurrentIndex(const QModelIndex &index, ScrollHint scrollHint=EnsureVisible)
Set the current index and optionally scroll to it.
QModelIndex currentSourceIndex() const
Return the current source model index (mapped through the proxy).
static void logIndex(const char *file, int lineNumber, Log::LogLevel level, const QModelIndex &index, const QString &text)
Log a model index at the given log level.
void currentIndexChanged(const QModelIndex &index)
Emitted when the current index changes.
void setColumnsVisible(const QList< int > &columns, bool visible, bool exclusive=false)
Show or hide columns by column index.
virtual QModelIndex previousIndex(const QModelIndex &from) const
Return the previous index in display order before from.
EntityMetadata findFirstParent(const QModelIndex &index, int entityMetadataType) const
Walk ancestors of index to find one with the given entity type.
void restoreState(const QByteArray &state)
Restore header and expansion state from a byte array.
virtual QModelIndex findPreviousMatch(const QString &text, const QModelIndex &fromIndex) const
Find the previous index whose display text matches, searching backward.
bool isIndexVisible(const QModelIndex &index) const
Return whether the given index is visible in the current viewport.
int columnForHeaderType(int headerType) const
Return the column index for a given header type.
void currentSelectionChanged()
Emitted when the current selection changes.
QModelIndexList mapToSource(const QModelIndexList &indexes) const
Map a list of view indexes to their source model equivalents.
QByteArray saveState() const
Save the header and expansion state to a byte array.
void restoreHeaderStates()
Restore horizontal header state (column widths/order) from settings.
static bool testMatch(const QModelIndex &index, int role, const QVariant &value, Qt::MatchFlags flags, QModelIndexList &foundIndexes)
Test whether index matches value under role using flags, appending to foundIndexes.
QModelIndexList findParents(const QModelIndex &index) const
Return all ancestor indexes of index.
void entityUpdated(const EntityMetadata &metadata)
Emitted when an entity is updated.
virtual QModelIndex nextIndex(const QModelIndex &from) const
Return the next index in display order after from.
virtual QModelIndexList indexesOfUuid(const QUuid &uuid) const
Return all indexes whose item UUID matches.
bool isLeafExpanded(const QModelIndex &index, bool recursive=true) const
Return whether the deepest expanded leaf under index is expanded.
TreeViewBase(QWidget *parent=nullptr)
Construct with an optional parent widget.
virtual EntityMetadata metadataAtPos(const QPoint &pos) const
Return the EntityMetadata of the item at a view position.
virtual EntityMetadata currentMetadata() const
Return the EntityMetadata of the currently selected item.
virtual QModelIndex firstIndexOfEntityUuid(const QUuid &uuid) const
Return the first index whose item UUID matches.
void itemProgramaticallySelected(const QModelIndex &index)
Emitted when an item is selected programmatically.
AbstractItemModel * sourceModel() const
Return the underlying AbstractItemModel (without the proxy).
virtual void clear()
Remove all items from the view model.
virtual void setSelectionModel(QItemSelectionModel *selectionModel) override
Set the selection model.
virtual QModelIndex findNextMatch(const QString &text, const QModelIndex &fromIndex) const
Find the next index whose display text matches, searching forward.
virtual QModelIndex finalChildIndex(const QModelIndex &from) const
Return the deepest last child of the given index.
virtual QModelIndexList matchBackwards(const QModelIndex &start, int role, const QVariant &value, int hits=1, Qt::MatchFlags flags=Qt::MatchFlags(Qt::MatchStartsWith|Qt::MatchWrap)) const
Search backward from start for indexes matching a role value.
virtual void setModel(QAbstractItemModel *model) override
Set the model, wrapping it in an internal sort/filter proxy.
void setColumnTypesVisible(const QList< int > &headerTypes, bool visible, bool exclusive=false)
Show or hide columns identified by header types.
void collapseRecursively(const QModelIndex &index, int depth=-1)
Recursively collapse index and all its descendants up to a depth limit.
virtual void refreshVisibleIndexes(const QModelIndexList &indexes)
Refresh the display of a set of source model indexes.
virtual void refreshIndex(const QModelIndex &sourceIndex)
Refresh a single source model index.
void entityDeleted(const EntityMetadata &metadata)
Emitted when an entity is deleted.
int entityTypeAtPos(const QPoint &pos)
Return the entity type of the item at a view position.
virtual void setCurrentUuid(const QUuid &uuid, ScrollHint scrollHint=EnsureVisible)
Select the item with the given UUID and optionally scroll to it.
virtual void refreshVisibleColumns(const QList< int > &columns)
Refresh the display of a set of columns.