Coverage Report

Created: 2026-04-12 06:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wt/src/Wt/WModelIndex.h
Line
Count
Source
1
// This may look like C code, but it's really -*- C++ -*-
2
/*
3
 * Copyright (C) 2008 Emweb bv, Herent, Belgium.
4
 *
5
 * See the LICENSE file for terms of use.
6
 */
7
#ifndef WMODEL_INDEX_H_
8
#define WMODEL_INDEX_H_
9
10
#include <vector>
11
#include <set>
12
#include <unordered_set>
13
14
#include <Wt/WDllDefs.h>
15
#include <Wt/WFlags.h>
16
#include <Wt/WAny.h>
17
18
namespace Wt {
19
20
class WAbstractItemModel;
21
class WModelIndex;
22
23
  namespace Chart {
24
    class WCartesianChart;
25
    class WPieChart;
26
  }
27
28
#ifndef WT_TARGET_JAVA
29
 /*! \brief A set of WModelIndexes
30
 */
31
typedef std::set<WModelIndex> WModelIndexSet;
32
33
extern std::size_t hash_value(const Wt::WModelIndex& index);
34
#else
35
typedef std::treeset<WModelIndex> WModelIndexSet;
36
#endif
37
38
#ifdef WT_TARGET_JAVA
39
#define constexpr
40
#endif // WT_TARGET_JAVA
41
42
/*! \defgroup modelview Model/view system
43
 *  \brief Classes that implement %Wt's model/view system.
44
 *
45
 * <h2>1. Models</h2>
46
 *
47
 * The library provides support for tabular, tree-like and tree-table like
48
 * models. All of these implement WAbstractItemModel.
49
 *
50
 * <h3>Concrete model implementations</h3>
51
 *
52
 * The following concrete model implementations are provided:
53
 * - Wt::WStandardItemModel: a full general purpose model, which stores data
54
 *   in memory.
55
 * - Wt::WStringListModel: a low-height single column model, useful for simple
56
 *   list views
57
 * - Wt::Dbo::QueryModel: a database query backed model
58
 *
59
 * <h3>Proxy model implementations</h3>
60
 *
61
 * Proxy models are helper models which wrap around another model, to
62
 * provide additional functionality on top of the existing model. The
63
 * following propy models:
64
 *
65
 * - Wt::WSortFilterProxyModel: provides sorting and filtering support
66
 * - Wt::WAggregateProxyModel: provides column aggregation (useful only for
67
 *   views that implement column aggregation such as WAbstractItemView's).
68
 *
69
 * <h3>Abstract models</h3>
70
 *
71
 * Abstract models cannot be instantiated as such, but are the base point
72
 * for custom model implementations:
73
 *
74
 * - Wt::WAbstractItemModel: abstract base class of all models
75
 * - Wt::WAbstractTableModel: abstract base class for tabular models
76
 * - Wt::WAbstractProxyModel: abstract base class for proxy models.
77
 *
78
 * <h2>2. Views</h2>
79
 *
80
 * <h3>Item-based views</h3>
81
 *
82
 * - WComboBox: a combo box
83
 * - WSelectionBox: a selection box
84
 * - WTableView: a table view (with editing support)
85
 * - WTreeView: a tree(-table) view (with editing support)
86
 * - WSuggestionPopup: an intelligent input-driven combo box
87
 *
88
 * <h3>Graphical views</h3>
89
 *
90
 * - Chart::WCartesianChart: 2D cartesian chart
91
 * - Chart::WPieChart: pie charts
92
 *
93
 * <h2>3. Helper classes</h2>
94
 *
95
 * <h3>Model indexes</h3>
96
 *
97
 * WModelIndex represents an index to an item of a WAbstractItemModel,
98
 * identified by a row, column and parent node.
99
 *
100
 * <h3>Item delegates</h3>
101
 *
102
 * Item delegates are used by WTableView and WTreeView to render a
103
 * single item and to provide editing support.
104
 *
105
 * The abstract base class is WAbstractItemDelegate, and a default
106
 * implementation is provided by WItemDelegate.
107
 */
108
109
/*! \brief Enumeration that indicates a role for a data item.
110
 *
111
 * A single data item can have data associated with it corresponding
112
 * to different roles. Each role may be used by the corresponding view
113
 * class in a different way.
114
 *
115
 * \sa WModelIndex::data()
116
 *
117
 * \ingroup modelview
118
 */
119
class WT_API ItemDataRole final {
120
public:
121
  /*! \brief Create a new role with a certain int value.
122
   */
123
  constexpr ItemDataRole(int role) noexcept
124
0
    : role_(role)
125
0
  { }
126
127
  /*! \brief Returns the underlying int of this role.
128
   */
129
  constexpr int value() const noexcept
130
0
  {
131
0
    return role_;
132
0
  }
133
134
  constexpr bool operator== (const ItemDataRole &rhs) const noexcept
135
0
  {
136
0
    return role_ == rhs.role_;
137
0
  }
138
139
  constexpr bool operator!= (const ItemDataRole &rhs) const noexcept
140
0
  {
141
0
    return role_ != rhs.role_;
142
0
  }
143
144
  constexpr bool operator< (const ItemDataRole &rhs) const noexcept
145
0
  {
146
0
    return role_ < rhs.role_;
147
0
  }
148
149
#if !defined(WT_TARGET_JAVA) || defined(DOXYGEN_ONLY)
150
  static constexpr const int Display = 0;       //!< Role for textual representation
151
  static constexpr const int Decoration = 1;    //!< Role for the url of an icon
152
  static constexpr const int Edit = 2;          //!< Role for the edited value
153
  static constexpr const int StyleClass = 3;    //!< Role for the style class
154
155
  /*! Role that indicates the check state.
156
   *
157
   * Data for this role should be a <tt>bool</tt>. When the
158
   * Wt::ItemFlag::Tristate flag is set for the item, data for this role
159
   * should be of type Wt::CheckState.
160
   */
161
  static constexpr const int Checked = 4;
162
  static constexpr const int ToolTip = 5;         //!< Role for a (plain) tooltip
163
  static constexpr const int Link = 6;            //!< Role for a link
164
  static constexpr const int MimeType = 7;        //!< Role for mime type information
165
  static constexpr const int Level = 8;           //!< Level in aggregation, for header data.
166
167
  static constexpr const int MarkerPenColor = 16;    //!< Marker pen color (for Chart::WCartesianChart)
168
  static constexpr const int MarkerBrushColor = 17;  //!< Marker brush color (for Chart::WCartesianChart)
169
  static constexpr const int MarkerScaleFactor = 20; //!< Marker size (for Chart::WCartesianChart)
170
  static constexpr const int MarkerType = 21; //!< Marker type (for Chart::WCartesianChart)
171
  static constexpr const int BarPenColor = 18;   //!< Bar pen color (for Chart::WCartesianChart)
172
  static constexpr const int BarBrushColor = 19; //!< Bar brush color (for Chart::WCartesianChart)
173
174
  static constexpr const int User = 32;           //!< First role reserved for user purposes
175
#else
176
  static const ItemDataRole Display;
177
  static const ItemDataRole Decoration;
178
  static const ItemDataRole Edit;
179
  static const ItemDataRole StyleClass;
180
  static const ItemDataRole Checked;
181
  static const ItemDataRole ToolTip;
182
  static const ItemDataRole Link;
183
  static const ItemDataRole MimeType;
184
  static const ItemDataRole Level;
185
  static const ItemDataRole MarkerPenColor;
186
  static const ItemDataRole MarkerBrushColor;
187
  static const ItemDataRole MarkerScaleFactor;
188
  static const ItemDataRole MarkerType;
189
  static const ItemDataRole BarPenColor;
190
  static const ItemDataRole BarBrushColor;
191
  static const ItemDataRole User;
192
#endif
193
194
private:
195
  int role_;
196
};
197
198
/*! \brief Flags that indicate data item options
199
 *
200
 * \sa WModelIndex::flags()
201
 *
202
 * \ingroup modelview
203
 */
204
enum class ItemFlag {
205
  Selectable = 0x1,       //!< Item can be selected
206
  Editable = 0x2,         //!< Item can be edited
207
  UserCheckable = 0x4,    //!< Item can be checked (checkbox is enabled)
208
  DragEnabled = 0x8,      //!< Item can be dragged
209
  DropEnabled = 0x10,     //!< Item can be a drop target
210
  /*! Item has tree states.
211
   *
212
   * When set, Wt::ItemDataRole::Checked data is of type
213
   * Wt::CheckState
214
   */
215
  Tristate = 0x20,
216
  XHTMLText = 0x40,        //!< Item's text (ItemDataRole::Display, ItemDataRole::ToolTip) is HTML
217
  Dirty = 0x80,            //!< Item's value has been modified
218
  DeferredToolTip = 0x100 //!< Item's tooltip is deferred
219
};
220
221
W_DECLARE_OPERATORS_FOR_FLAGS(ItemFlag)
222
223
/*! \brief Enumeration that indicates a sort order.
224
 *
225
 * \ingroup modelview
226
 */
227
enum class SortOrder {
228
  Ascending,  //!< Ascending sort order
229
  Descending  //!< Descending sort order
230
};
231
232
/*! \brief Enumeration that indicates a drop action.
233
 *
234
 * \sa WAbstractItemModel::dropEvent()
235
 *
236
 * \ingroup modelview
237
 */
238
enum class DropAction {
239
  Copy = 0x1, //!< Copy the selection
240
  Move = 0x2  //!< Move the selection (deleting originals)
241
};
242
243
/*! \class WModelIndex Wt/WModelIndex.h Wt/WModelIndex.h
244
 *  \brief A value class that describes an index to an item in a data model.
245
 *
246
 * Indexes are used to indicate a particular item in a
247
 * WAbstractItemModel. An index points to the item by identifying its
248
 * row and column location within a parent model index.
249
 *
250
 * An index is immutable.
251
 *
252
 * The default constructor creates an <i>invalid index</i>, which by
253
 * convention indicates the parent of top level indexes. Thus, a model
254
 * that specifies only a list or table of data (but no hierarchical
255
 * data) would have as valid indexes only indexes that specify the
256
 * <i>invalid</i> model index as parent.
257
 *
258
 * Upon the model's choice, model indexes for hierarchical models may
259
 * have an internal Id represented by a int64_t (internalId()), a
260
 * pointer (internalPointer()).
261
 *
262
 * Indexes are created by the model, within the protected
263
 * WAbstractItemModel::createIndex() methods. In this way, models can
264
 * define an internal pointer or id suitable for identifying parent
265
 * items in the model.
266
 *
267
 * When a model's geometry changes due to row or column insertions or
268
 * removals, you may need to update your indexes, as otherwise they
269
 * may no longer point to the same item (but instead still to the same
270
 * row/column). Thus, if you store indexes and want to support model
271
 * changes such as row or columns insertions/removals, then you need
272
 * to react to the corresponding signals such as
273
 * WAbstractItemModel::rowsInserted() to update these indexes
274
 * (i.e. shift them), or even remove them when the corresponding
275
 * row/column has been removed.
276
 *
277
 * When a model's layout changes (it is rearranging its contents for
278
 * example in response to a sort operation), a similar problem
279
 * arises. Some models support tracking of indexes over layout
280
 * changes, using <i>raw</i> indexes. In reaction to
281
 * WAbstractItemModel::layoutAboutToBeChanged(), you should encode any
282
 * index which you wish to recover after the layout change using
283
 * encodeAsRawIndex(), and in WAbstractItemModel::layoutChanged() you
284
 * can obtain an index that points to the same item using
285
 * decodeFromRawIndex().
286
 *
287
 * \sa WAbstractItemModel
288
 *
289
 * \ingroup modelview
290
 */
291
class WT_API WModelIndex
292
{
293
public:
294
  /*! \brief Create an invalid WModelIndex.
295
   *
296
   * Returns a model index for which isValid() return \c false.
297
   */
298
  WModelIndex();
299
300
  /*! \brief Returns the column for this model index.
301
   *
302
   * \sa row()
303
   */
304
0
  int column() const { return column_; }
305
306
  /*! \brief Returns the row for this model index.
307
   *
308
   * \sa column()
309
   */
310
0
  int row() const { return row_; }
311
312
  /*! \brief Returns the internal pointer.
313
   *
314
   * The internal pointer is used by the model to retrieve the corresponding
315
   * data.
316
   *
317
   * This is only defined when the model created the index using
318
   * WAbstractItemModel::createIndex(int, int, void *) const.
319
   *
320
   * \sa internalId(),
321
   * \sa WAbstractItemModel::createIndex(int, int, void *) const
322
   */
323
0
  void *internalPointer() const { return reinterpret_cast<void*>(internalId_); }
324
325
  /*! \brief Returns the internal id.
326
   *
327
   * The internal id is used by the model to retrieve the
328
   * corresponding data.
329
   *
330
   * This is only defined when the model created the index using
331
   * WAbstractItemModel::createIndex(int, int, uint64_t) const.
332
   *
333
   * \sa internalPointer()
334
   * \sa WAbstractItemModel::createIndex(int, int, uint64_t) const
335
   */
336
0
  ::uint64_t internalId() const { return internalId_; }
337
338
  /*! \brief Returns a model index for a child item.
339
   *
340
   * This is a convenience method, and is only defined for indexes
341
   * that are valid().
342
   *
343
   * It has the same function as WAbstractItemModel::index() but is
344
   * less general because the latter expression may also be used to
345
   * retrieve top level children, i.e. when \p index is invalid.
346
   *
347
   * \sa WAbstractItemModel::index(), isValid()
348
   */
349
  WModelIndex child(int row, int column) const;
350
351
  /*! \brief Returns an index to the parent.
352
   *
353
   * This is a convenience method for WAbstractItemModel::parent().
354
   *
355
   * For a top level data item, the parent() is an invalid index (see
356
   * WModelIndex()).
357
   *
358
   * \sa WAbstractItemModel::parent()
359
   */
360
  WModelIndex parent() const;
361
362
  /*! \brief Returns data in the model at this index.
363
   *
364
   * This is a convenience method for WAbstractItemModel::data().
365
   *
366
   * \sa WAbstractItemModel::data()
367
   * \sa ItemDataRole
368
   */
369
  cpp17::any data(ItemDataRole role = ItemDataRole::Display) const;
370
371
  /*! \brief Returns the flags for this item.
372
   *
373
   * This is a convenience method for WAbstractItemModel::flags().
374
   *
375
   * \sa WAbstractItemModel::flags()
376
   * \sa ItemFlag
377
   */
378
  WFlags<ItemFlag> flags() const;
379
380
  /*! \brief Returns whether the index is a real valid index.
381
   *
382
   * Returns \c true when the index points to a valid data item,
383
   * i.e. at a valid row() and column().
384
   *
385
   * An index may be invalid for two reasons:
386
   *  - an operation requested an index that was out of model bounds,
387
   *  - or, the index corresponds to the model's top level root item, and is
388
   *    thus the parent index for top level items.
389
   */
390
0
  bool isValid() const { return model_ != nullptr; }
391
392
  /*! \brief Returns the model to which this (valid) index is bound.
393
   *
394
   * This returns the model that created the model index.
395
   */
396
0
  const WAbstractItemModel *model() const { return model_; }
397
398
  /*! \brief Comparison operator.
399
   *
400
   * Returns \c true only if the indexes point at the same data, in the
401
   * same model.
402
   */
403
  bool operator== (const WModelIndex& other) const;
404
405
  /*! \brief Comparison operator.
406
   *
407
   * \sa operator==()
408
   */
409
  bool operator!= (const WModelIndex& other) const;
410
411
  /*! \brief Comparison operator.
412
   *
413
   * Returns \c true if the index comes topologically before \p other.
414
   *
415
   * Topological order follows the order in which the indexes would be
416
   * displayed in a tree table view, from top to bottom followed by
417
   * left to right.
418
   *
419
   * An invalid index comes before all other indexes.
420
   * Indexes \link encodeAsRawIndex() encoded as raw index\endlink
421
   * come after the invalid index and before all other indexes, and
422
   * are ordered according to their internalId().
423
   */
424
  bool operator< (const WModelIndex& other) const;
425
426
  /*! \brief Encode to raw index (before a layout change).
427
   *
428
   * Use this method to encode an index for which you want to recover
429
   * an index after the layout change to the same item (which may
430
   * still be in the model, but at a different location).
431
   *
432
   * An index that has been encoded as a raw index cannot be used for
433
   * anything but decodeFromRawIndex() at a later point.
434
   *
435
   * \sa WAbstractItemModel::toRawIndex(), WAbstractItemModel::layoutAboutToBeChanged()
436
   * \sa decodeFromRawIndex()
437
   */
438
  void encodeAsRawIndex();
439
440
  /*! \brief Decodes a raw index (after a layout change).
441
   *
442
   * A raw index can be decoded, within the context of a model that has been
443
   * re-layed out.
444
   *
445
   * This method returns a new index that points to the same item, or,
446
   * WModelIndex() if the underlying model did not support encoding to
447
   * raw indexes, or, if the item to which the index previously
448
   * pointed, is no longer part of the model.
449
   *
450
   * \sa WAbstractItemModel::fromRawIndex(), WAbstractItemModel::layoutChanged()
451
   * \sa encodeAsRawIndex()
452
   */
453
  WModelIndex decodeFromRawIndex() const;
454
455
  /*! \brief Returns the depth (in a hierarchical model).
456
   *
457
   * A top level index has depth 0.
458
   */
459
  int depth() const;
460
461
  /*! \brief Utility method for converting an entire set of indexes to raw.
462
   *
463
   * \sa encodeAsRawIndex()
464
   */
465
  static void encodeAsRawIndexes(WModelIndexSet& indexes);
466
467
  /*! \brief Utility method for converting an entire set of indexes to raw.
468
   *
469
   * \sa encodeAsRawIndex()
470
   */
471
  static void encodeAsRawIndexes(std::unordered_set<WModelIndex>& indexes);
472
473
  /*! \brief Utility method to decode an entire set of raw indexes.
474
   *
475
   * \sa decodeFromRawIndex()
476
   */
477
  static
478
    WModelIndexSet decodeFromRawIndexes(const WModelIndexSet& encodedIndexes);
479
480
  /*! \brief Utility method to decode an entire set of raw indexes.
481
   *
482
   * \sa decodeFromRawIndex()
483
   */
484
  static std::unordered_set<WModelIndex> decodeFromRawIndexes(const std::unordered_set<WModelIndex>& encodedIndexes);
485
486
  struct UnorderedLess {
487
    bool operator()(const WModelIndex& i1, const WModelIndex& i2) const;
488
  };
489
490
  /*! \brief Returns whether i2 is an ancestor of i1
491
   */
492
  static bool isAncestor(const Wt::WModelIndex& i1, const Wt::WModelIndex& i2);
493
494
private:
495
  const WAbstractItemModel *model_;
496
  int row_, column_;
497
  ::uint64_t internalId_;
498
499
  WModelIndex(int row, int column, const WAbstractItemModel *model, void *ptr);
500
  WModelIndex(int row, int column, const WAbstractItemModel *model,
501
              ::uint64_t id);
502
503
  friend class WAbstractItemModel;
504
505
  template<class Result>
506
  friend class Dbo::QueryModel;
507
508
  WModelIndex ancestor(int depth) const;
509
510
  bool isRawIndex() const;
511
};
512
513
/*! \brief List of indexes
514
 *
515
 * The list is defined as std::vector<WModelIndex>.
516
 */
517
typedef std::vector<WModelIndex> WModelIndexList;
518
519
}
520
521
#ifndef WT_TARGET_JAVA
522
namespace std {
523
  template<>
524
  struct hash<Wt::WModelIndex>
525
  {
526
    std::size_t operator()(const Wt::WModelIndex& index) const
527
0
    {
528
0
      return Wt::hash_value(index);
529
0
    }
530
  };
531
532
  template<>
533
  struct equal_to<Wt::WModelIndex>
534
  {
535
    bool operator()(const Wt::WModelIndex& index1, const Wt::WModelIndex& index2) const
536
0
    {
537
0
      return index1 == index2;
538
0
    }
539
  };
540
}
541
#endif // WT_TARGET_JAVA
542
543
/*! @} */
544
545
#endif // WMODEL_INDEX_H_