| 1 | // Copyright (C) 2025 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 | // Qt-Security score:significant reason:default |
| 4 | |
| 5 | #include "qrangemodel.h" |
| 6 | #include <QtCore/qsize.h> |
| 7 | |
| 8 | #include <QtCore/private/qabstractitemmodel_p.h> |
| 9 | |
| 10 | QT_BEGIN_NAMESPACE |
| 11 | |
| 12 | class QRangeModelPrivate : QAbstractItemModelPrivate |
| 13 | { |
| 14 | Q_DECLARE_PUBLIC(QRangeModel) |
| 15 | |
| 16 | public: |
| 17 | explicit QRangeModelPrivate(std::unique_ptr<QRangeModelImplBase, QRangeModelImplBase::Deleter> impl) |
| 18 | : impl(std::move(impl)) |
| 19 | {} |
| 20 | |
| 21 | private: |
| 22 | std::unique_ptr<QRangeModelImplBase, QRangeModelImplBase::Deleter> impl; |
| 23 | mutable QHash<int, QByteArray> m_roleNames; |
| 24 | }; |
| 25 | |
| 26 | QRangeModel::QRangeModel(QRangeModelImplBase *impl, QObject *parent) |
| 27 | : QAbstractItemModel(*new QRangeModelPrivate({impl, {}}), parent) |
| 28 | { |
| 29 | } |
| 30 | |
| 31 | /*! |
| 32 | \class QRangeModel |
| 33 | \inmodule QtCore |
| 34 | \since 6.10 |
| 35 | \ingroup model-view |
| 36 | \brief QRangeModel implements QAbstractItemModel for any C++ range. |
| 37 | \reentrant |
| 38 | |
| 39 | QRangeModel can make the data in any sequentially iterable C++ type |
| 40 | available to the \l{Model/View Programming}{model/view framework} of Qt. |
| 41 | This makes it easy to display existing data structures in the Qt Widgets |
| 42 | and Qt Quick item views, and to allow the user of the application to |
| 43 | manipulate the data using a graphical user interface. |
| 44 | |
| 45 | To use QRangeModel, instantiate it with a C++ range and set it as |
| 46 | the model of one or more views: |
| 47 | |
| 48 | \snippet qrangemodel/main.cpp array |
| 49 | |
| 50 | \section1 Constructing the model |
| 51 | |
| 52 | The range can be any C++ type for which the standard methods |
| 53 | \c{std::begin} and \c{std::end} are implemented, and for which the |
| 54 | returned iterator type satisfies \c{std::forward_iterator}. Certain model |
| 55 | operations will perform better if \c{std::size} is available, and if the |
| 56 | iterator satisfies \c{std::random_access_iterator}. |
| 57 | |
| 58 | The range must be provided when constructing the model; there is no API to |
| 59 | set the range later, and there is no API to retrieve the range from the |
| 60 | model. The range can be provided by value, reference wrapper, or pointer. |
| 61 | How the model was constructed defines whether changes through the model API |
| 62 | will modify the original data. |
| 63 | |
| 64 | When constructed by value, the model makes a copy of the range, and |
| 65 | QAbstractItemModel APIs that modify the model, such as setData() or |
| 66 | insertRows(), have no impact on the original range. |
| 67 | |
| 68 | \snippet qrangemodel/main.cpp value |
| 69 | |
| 70 | As there is no API to retrieve the range again, constructing the model from |
| 71 | a range by value is mostly only useful for displaying read-only data. |
| 72 | Changes to the data can be monitored using the signals emitted by the |
| 73 | model, such as \l{QAbstractItemModel}{dataChanged()}. |
| 74 | |
| 75 | To make modifications of the model affect the original range, provide the |
| 76 | range either by pointer: |
| 77 | |
| 78 | \snippet qrangemodel/main.cpp pointer |
| 79 | |
| 80 | or through a reference wrapper: |
| 81 | |
| 82 | \snippet qrangemodel/main.cpp reference_wrapper |
| 83 | |
| 84 | In this case, QAbstractItemModel APIs that modify the model also modify the |
| 85 | range. Methods that modify the structure of the range, such as insertRows() |
| 86 | or removeColumns(), use standard C++ container APIs \c{resize()}, |
| 87 | \c{insert()}, \c{erase()}, in addition to dereferencing a mutating iterator |
| 88 | to set or clear the data. |
| 89 | |
| 90 | \note Once the model has been constructed and passed on to a view, the |
| 91 | range that the model operates on must no longer be modified directly. Views |
| 92 | on the model wouldn't be informed about the changes, and structural changes |
| 93 | are likely to corrupt instances of QPersistentModelIndex that the model |
| 94 | maintains. |
| 95 | |
| 96 | The caller must make sure that the range's lifetime exceeds the lifetime of |
| 97 | the model. |
| 98 | |
| 99 | Use smart pointers to make sure that the range is only deleted when all |
| 100 | clients are done with it. |
| 101 | |
| 102 | \snippet qrangemodel/main.cpp smart_pointer |
| 103 | |
| 104 | QRangeModel supports both shared and unique pointers. |
| 105 | |
| 106 | \section2 Read-only or mutable |
| 107 | |
| 108 | For ranges that are const objects, for which access always yields constant |
| 109 | values, or where the required container APIs are not available, |
| 110 | QRangeModel implements write-access APIs to do nothing and return |
| 111 | \c{false}. In the example using \c{std::array}, the model cannot add or |
| 112 | remove rows, as the number of entries in a C++ array is fixed. But the |
| 113 | values can be changed using setData(), and the user can trigger editing of |
| 114 | the values in the list view. By making the array const, the values also |
| 115 | become read-only. |
| 116 | |
| 117 | \snippet qrangemodel/main.cpp const_array |
| 118 | |
| 119 | The values are also read-only if the element type is const, like in |
| 120 | |
| 121 | \snippet qrangemodel/main.cpp const_values |
| 122 | |
| 123 | In the above examples using \c{std::vector}, the model can add or remove |
| 124 | rows, and the data can be changed. Passing the range as a constant |
| 125 | reference will make the model read-only. |
| 126 | |
| 127 | \snippet qrangemodel/main.cpp const_ref |
| 128 | |
| 129 | \note If the values in the range are const, then it's also not possible |
| 130 | to remove or insert columns and rows through the QAbstractItemModel API. |
| 131 | For more granular control, implement \l{the C++ tuple protocol}. |
| 132 | |
| 133 | \section1 Rows and columns |
| 134 | |
| 135 | The elements in the range are interpreted as rows of the model. Depending |
| 136 | on the type of these row elements, QRangeModel exposes the range as a |
| 137 | list, a table, or a tree. |
| 138 | |
| 139 | If the row elements are simple values, then the range gets represented as a |
| 140 | list. |
| 141 | |
| 142 | \snippet qrangemodel/main.cpp list_of_int |
| 143 | |
| 144 | If the type of the row elements is an iterable range, such as a vector, |
| 145 | list, or array, then the range gets represented as a table. |
| 146 | |
| 147 | \snippet qrangemodel/main.cpp grid_of_numbers |
| 148 | |
| 149 | If the row type provides the standard C++ container APIs \c{resize()}, |
| 150 | \c{insert()}, \c{erase()}, then columns can be added and removed via |
| 151 | insertColumns() and removeColumns(). All rows are required to have |
| 152 | the same number of columns. |
| 153 | |
| 154 | \section2 Structs and gadgets as rows |
| 155 | |
| 156 | If the row type implements \l{the C++ tuple protocol}, then the range gets |
| 157 | represented as a table with a fixed number of columns. |
| 158 | |
| 159 | \snippet qrangemodel/main.cpp pair_int_QString |
| 160 | |
| 161 | An easier and more flexible alternative to implementing the tuple protocol |
| 162 | for a C++ type is to use Qt's \l{Meta-Object System}{meta-object system} to |
| 163 | declare a type with \l{Qt's Property System}{properties}. This can be a |
| 164 | value type that is declared as a \l{Q_GADGET}{gadget}, or a QObject subclass. |
| 165 | |
| 166 | \snippet qrangemodel/main.cpp gadget |
| 167 | |
| 168 | Using QObject subclasses allows properties to be \l{Qt Bindable Properties} |
| 169 | {bindable}, or to have change notification signals. However, using QObject |
| 170 | instances for items has significant memory overhead. |
| 171 | |
| 172 | Using Qt gadgets or objects is more convenient and can be more flexible |
| 173 | than implementing the tuple protocol. Those types are also directly |
| 174 | accessible from within QML. However, the access through \l{the property system} |
| 175 | comes with some runtime overhead. For performance critical models, consider |
| 176 | implementing the tuple protocol for compile-time generation of the access |
| 177 | code. |
| 178 | |
| 179 | \section2 Multi-role items |
| 180 | |
| 181 | The type of the items that the implementations of data(), setData(), |
| 182 | clearItemData() etc. operate on can be the same across the entire model - |
| 183 | like in the \c{gridOfNumbers} example above. But the range can also have |
| 184 | different item types for different columns, like in the \c{numberNames} |
| 185 | case. |
| 186 | |
| 187 | By default, the value gets used for the Qt::DisplayRole and Qt::EditRole |
| 188 | roles. Most views expect the value to be |
| 189 | \l{QVariant::canConvert}{convertible to and from a QString} (but a custom |
| 190 | delegate might provide more flexibility). |
| 191 | |
| 192 | \section3 Associative containers with multiple roles |
| 193 | |
| 194 | If the item is an associative container that uses \c{int}, |
| 195 | \l{Qt::ItemDataRole}, or QString as the key type, and QVariant as the |
| 196 | mapped type, then QRangeModel interprets that container as the storage |
| 197 | of the data for multiple roles. The data() and setData() functions return |
| 198 | and modify the mapped value in the container, and setItemData() modifies all |
| 199 | provided values, itemData() returns all stored values, and clearItemData() |
| 200 | clears the entire container. |
| 201 | |
| 202 | \snippet qrangemodel/main.cpp color_map |
| 203 | |
| 204 | The most efficient data type to use as the key is Qt::ItemDataRole or |
| 205 | \c{int}. When using \c{int}, itemData() returns the container as is, and |
| 206 | doesn't have to create a copy of the data. |
| 207 | |
| 208 | \section3 Gadgets and Objects as multi-role items |
| 209 | |
| 210 | Gadgets and QObject types can also be represented as multi-role items. The |
| 211 | \l{The Property System}{properties} of those items will be used for the |
| 212 | role for which the \l{roleNames()}{name of a role} matches. If all items |
| 213 | hold the same type of gadget or QObject, then the \l{roleNames()} |
| 214 | implementation in QRangeModel will return the list of properties of that |
| 215 | type. |
| 216 | |
| 217 | \snippet qrangemodel/main.cpp color_gadget_decl |
| 218 | \snippet qrangemodel/main.cpp color_gadget_impl |
| 219 | \snippet qrangemodel/main.cpp color_gadget_end |
| 220 | |
| 221 | When used in a table, this is the default representation for gadgets: |
| 222 | |
| 223 | \snippet qrangemodel/main.cpp color_gadget_table |
| 224 | |
| 225 | When used in a list, these types are however by default represented as |
| 226 | multi-column rows, with each property represented as a separate column. To |
| 227 | force a gadget to be represented as a multi-role item in a list, declare |
| 228 | the gadget as a multi-role type by specializing QRoleModel::RowOptions, |
| 229 | with a \c{static constexpr auto rowCategory} member variable set to |
| 230 | MultiRoleItem. |
| 231 | |
| 232 | \snippet qrangemodel/main.cpp color_gadget_decl |
| 233 | \dots |
| 234 | \snippet qrangemodel/main.cpp color_gadget_end |
| 235 | \snippet qrangemodel/main.cpp color_gadget_multi_role_gadget |
| 236 | |
| 237 | You can also wrap such types into a single-element tuple, turning the list |
| 238 | into a table with a single column: |
| 239 | |
| 240 | \snippet qrangemodel/main.cpp color_gadget_single_column |
| 241 | |
| 242 | In this case, note that direct access to the elements in the list data |
| 243 | needs to use \c{std::get}: |
| 244 | |
| 245 | \snippet qrangemodel/main.cpp color_gadget_single_column_access_get |
| 246 | |
| 247 | or alternatively a structured binding: |
| 248 | |
| 249 | \snippet qrangemodel/main.cpp color_gadget_single_column_access_sb |
| 250 | |
| 251 | \section2 Rows as values or pointers |
| 252 | |
| 253 | In the examples so far, we have always used QRangeModel with ranges that |
| 254 | hold values. QRangeModel can also operate on ranges that hold pointers, |
| 255 | including smart pointers. This allows QRangeModel to operate on ranges of |
| 256 | polymorph types, such as QObject subclasses. |
| 257 | |
| 258 | \snippet qrangemodel/main.cpp object_0 |
| 259 | \dots |
| 260 | \snippet qrangemodel/main.cpp object_1 |
| 261 | |
| 262 | \snippet qrangemodel/main.cpp vector_of_objects_0 |
| 263 | \dots |
| 264 | \snippet qrangemodel/main.cpp vector_of_objects_1 |
| 265 | \snippet qrangemodel/main.cpp vector_of_objects_2 |
| 266 | |
| 267 | As with values, the type of the row defines whether the range is |
| 268 | represented as a list, table, or tree. Rows that are QObjects will present |
| 269 | each property as a column, unless the QRangeModel::RowOptions template is |
| 270 | specialized to declare the type as a multi-role item. |
| 271 | |
| 272 | \snippet qrangemodel/main.cpp vector_of_multirole_objects_0 |
| 273 | \snippet qrangemodel/main.cpp vector_of_multirole_objects_1 |
| 274 | \dots |
| 275 | \snippet qrangemodel/main.cpp vector_of_multirole_objects_2 |
| 276 | |
| 277 | \note If the range holds raw pointers, then you have to construct |
| 278 | QRangeModel from a pointer or reference wrapper of the range. Otherwise the |
| 279 | ownership of the data becomes ambiguous, and a copy of the range would |
| 280 | still be operating on the same actual row data, resulting in unexpected |
| 281 | side effects. |
| 282 | |
| 283 | \section2 Subclassing QRangeModel |
| 284 | |
| 285 | Subclassing QRangeModel makes it possible to add convenient APIs that take |
| 286 | the data type and structure of the range into account. |
| 287 | |
| 288 | \snippet qrangemodel/main.cpp subclass_header |
| 289 | |
| 290 | When doing so, add the range as a private member, and call the QRangeModel |
| 291 | constructor with a reference wrapper or pointer to that member. This |
| 292 | properly encapsulates the data and avoids direct access. |
| 293 | |
| 294 | \snippet qrangemodel/main.cpp subclass_API |
| 295 | |
| 296 | Add member functions to provide type-safe access to the data, using the |
| 297 | QAbstractItemModel API to perform any operation that modifies the range. |
| 298 | Read-only access can directly operate on the data structure. |
| 299 | |
| 300 | \section1 Trees of data |
| 301 | |
| 302 | QRangeModel can represent a data structure as a tree model. Such a |
| 303 | tree data structure needs to be homomorphic: on all levels of the tree, the |
| 304 | list of child rows needs to use the exact same representation as the tree |
| 305 | itself. In addition, the row type needs be of a static size: either a gadget |
| 306 | or QObject type, or a type that implements the {C++ tuple protocol}. |
| 307 | |
| 308 | To represent such data as a tree, QRangeModel has to be able to traverse the |
| 309 | data structure: for any given row, the model needs to be able to retrieve |
| 310 | the parent row, and the optional span of children. These traversal functions |
| 311 | can be provided implicitly through the row type, or through an explicit |
| 312 | protocol type. |
| 313 | |
| 314 | \section2 Implicit tree traversal protocol |
| 315 | |
| 316 | \snippet qrangemodel/main.cpp tree_protocol_0 |
| 317 | |
| 318 | The tree itself is a vector of \c{TreeRow} values. See \l{Tree Rows as |
| 319 | pointers or values} for the considerations on whether to use values or |
| 320 | pointers of items for the rows. |
| 321 | |
| 322 | \snippet qrangemodel/main.cpp tree_protocol_1 |
| 323 | |
| 324 | The row class can be of any fixed-size type described above: a type that |
| 325 | implements the tuple protocol, a gadget, or a QObject. In this example, we |
| 326 | use a gadget. |
| 327 | |
| 328 | Each row item needs to maintain a pointer to the parent row, as well as an |
| 329 | optional range of child rows. That range has to be identical to the range |
| 330 | structure used for the tree itself. |
| 331 | |
| 332 | Making the row type default constructible is optional, and allows the model |
| 333 | to construct new row data elements, for instance in the insertRow() or |
| 334 | moveRows() implementations. |
| 335 | |
| 336 | \snippet qrangemodel/main.cpp tree_protocol_2 |
| 337 | |
| 338 | The tree traversal protocol can then be implemented as member functions of |
| 339 | the row data type. A const \c{parentRow()} function has to return a pointer |
| 340 | to a const row item; and the \c{childRows()} function has to return a |
| 341 | reference to a const \c{std::optional} that can hold the optional child |
| 342 | range. |
| 343 | |
| 344 | These two functions are sufficient for the model to navigate the tree as a |
| 345 | read-only data structure. To allow the user to edit data in a view, and the |
| 346 | model to implement mutating model APIs such as insertRows(), removeRows(), |
| 347 | and moveRows(), we have to implement additional functions for write-access: |
| 348 | |
| 349 | \snippet qrangemodel/main.cpp tree_protocol_3 |
| 350 | |
| 351 | The model calls the \c{setParentRow()} function and mutable \c{childRows()} |
| 352 | overload to move or insert rows into an existing tree branch, and to update |
| 353 | the parent pointer should the old value have become invalid. The non-const |
| 354 | overload of \c{childRows()} provides in addition write-access to the row |
| 355 | data. |
| 356 | |
| 357 | \note The model performs setting the parent of a row, removing that row |
| 358 | from the old parent, and adding it to the list of the new parent's children, |
| 359 | as separate steps. This keeps the protocol interface small. |
| 360 | |
| 361 | \dots |
| 362 | \snippet qrangemodel/main.cpp tree_protocol_4 |
| 363 | |
| 364 | The rest of the class implementation is not relevant for the model, but |
| 365 | a \c{addChild()} helper provides us with a convenient way to construct the |
| 366 | initial state of the tree. |
| 367 | |
| 368 | \snippet qrangemodel/main.cpp tree_protocol_5 |
| 369 | |
| 370 | A QRangeModel instantiated with an instance of such a range will |
| 371 | represent the data as a tree. |
| 372 | |
| 373 | \snippet qrangemodel/main.cpp tree_protocol_6 |
| 374 | |
| 375 | \section2 Tree traversal protocol in a separate class |
| 376 | |
| 377 | The tree traversal protocol can also be implemented in a separate class. |
| 378 | |
| 379 | \snippet qrangemodel/main.cpp explicit_tree_protocol_0 |
| 380 | |
| 381 | Pass an instance of this protocol implementation to the QRangeModel |
| 382 | constructor: |
| 383 | |
| 384 | \snippet qrangemodel/main.cpp explicit_tree_protocol_1 |
| 385 | |
| 386 | \section2 Tree Rows as pointers or values |
| 387 | |
| 388 | The row type of the data range can be either a value, or a pointer. In |
| 389 | the code above we have been using the tree rows as values in a vector, |
| 390 | which avoids that we have to deal with explicit memory management. However, |
| 391 | a vector as a contiguous block of memory invalidates all iterators and |
| 392 | references when it has to reallocate the storage, or when inserting or |
| 393 | removing elements. This impacts the pointer to the parent item, which is |
| 394 | the location of the parent row within the vector. Making sure that this |
| 395 | parent (and QPersistentModelIndex instances referring to items within it) |
| 396 | stays valid can incurr substantial performance overhead. The |
| 397 | QRangeModel implementation has to assume that all references into the |
| 398 | range become invalid when modifying the range. |
| 399 | |
| 400 | Alternatively, we can also use a range of row pointers as the tree type: |
| 401 | |
| 402 | \snippet qrangemodel/main.cpp tree_of_pointers_0 |
| 403 | |
| 404 | In this case, we have to allocate all TreeRow instances explicitly using |
| 405 | operator \c{new}, and implement the destructor to \c{delete} all items in |
| 406 | the vector of children. |
| 407 | |
| 408 | \snippet qrangemodel/main.cpp tree_of_pointers_1 |
| 409 | \snippet qrangemodel/main.cpp tree_of_pointers_2 |
| 410 | |
| 411 | Before we can construct a model that represents this data as a tree, we need |
| 412 | to also implement the tree traversal protocol. |
| 413 | |
| 414 | \snippet qrangemodel/main.cpp tree_of_pointers_3 |
| 415 | |
| 416 | An explicit protocol implementation for mutable trees of pointers has to |
| 417 | provide two additional member functions, \c{newRow()} and |
| 418 | \c{deleteRow(RowType *)}. |
| 419 | |
| 420 | \snippet qrangemodel/main.cpp tree_of_pointers_4 |
| 421 | |
| 422 | The model will call those functions when creating new rows in insertRows(), |
| 423 | and when removing rows in removeRows(). In addition, if the model has |
| 424 | ownership of the data, then it will also delete all top-level rows upon |
| 425 | destruction. Note how in this example, we move the tree into the model, so |
| 426 | we must no longer perform any operations on it. QRangeModel, when |
| 427 | constructed by moving tree-data with row-pointers into it, will take |
| 428 | ownership of the data, and delete the row pointers in it's destructor. |
| 429 | |
| 430 | Using pointers as rows comes with some memory allocation and management |
| 431 | overhead. However, the references to the row items remain stable, even when |
| 432 | they are moved around in the range, or when the range reallocates. This can |
| 433 | significantly reduce the cost of making modifications to the model's |
| 434 | structure when using insertRows(), removeRows(), or moveRows(). |
| 435 | |
| 436 | Each choice has different performance and memory overhead trade-offs. The |
| 437 | best option depends on the exact use case and data structure used. |
| 438 | |
| 439 | \section2 The C++ tuple protocol |
| 440 | |
| 441 | As seen in the \c{numberNames} example above, the row type can be a tuple, |
| 442 | and in fact any type that implements the tuple protocol. This protocol is |
| 443 | implemented by specializing \c{std::tuple_size} and \c{std::tuple_element}, |
| 444 | and overloading the unqualified \c{get} function. Do so for your custom row |
| 445 | type to make existing structured data available to the model/view framework |
| 446 | in Qt. |
| 447 | |
| 448 | \snippet qrangemodel/main.cpp tuple_protocol |
| 449 | |
| 450 | In the above implementation, the \c{title} and \c{author} values of the |
| 451 | \c{Book} type are returned as \c{const}, so the model flags items in those |
| 452 | two columns as read-only. The user won't be able to trigger editing, and |
| 453 | setData() does nothing and returns false. For \c{summary} and \c{rating} |
| 454 | the implementation returns the same value category as the book, so when |
| 455 | \c{get} is called with a mutable reference to a \c{Book}, then it will |
| 456 | return a mutable reference of the respective variable. The model makes |
| 457 | those columns editable, both for the user and for programmatic access. |
| 458 | |
| 459 | \note The implementation of \c{get} above requires C++23. |
| 460 | |
| 461 | \sa {Model/View Programming} |
| 462 | */ |
| 463 | |
| 464 | /*! |
| 465 | \class QRangeModel::RowOptions |
| 466 | \inmodule QtCore |
| 467 | \ingroup model-view |
| 468 | \brief The RowOptions template provides a customization point to control |
| 469 | how QRangeModel represents types used as rows. |
| 470 | \since 6.10 |
| 471 | |
| 472 | Specialize this template for the type used in your range, and add the |
| 473 | relevant members. |
| 474 | |
| 475 | \table |
| 476 | \header |
| 477 | \li Member |
| 478 | \li Values |
| 479 | \row |
| 480 | \li static constexpr RowCategory rowCategory |
| 481 | \li RowCategory |
| 482 | \endtable |
| 483 | |
| 484 | \snippet qrangemodel/main.cpp color_gadget_decl |
| 485 | \dots |
| 486 | \snippet qrangemodel/main.cpp color_gadget_end |
| 487 | \snippet qrangemodel/main.cpp color_gadget_multi_role_gadget |
| 488 | |
| 489 | */ |
| 490 | |
| 491 | /*! |
| 492 | \enum QRangeModel::RowCategory |
| 493 | |
| 494 | This enum describes how QRangeModel should present the elements of the |
| 495 | range it was constructed with. |
| 496 | |
| 497 | \value Default |
| 498 | QRangeModel decides how to present the rows. |
| 499 | \value MultiRoleItem |
| 500 | QRangeModel will present items with a meta object as multi-role |
| 501 | items, also when used in a one-dimensional range. |
| 502 | |
| 503 | Specialize the RowOptions template for your type, and add a public member |
| 504 | variable \c{static constexpr auto rowCategory} with one of the values from |
| 505 | this enum. |
| 506 | |
| 507 | \sa RowOptions |
| 508 | */ |
| 509 | |
| 510 | /*! |
| 511 | \fn template <typename Range, QRangeModelDetails::if_table_range<Range>> QRangeModel::QRangeModel(Range &&range, QObject *parent) |
| 512 | \fn template <typename Range, QRangeModelDetails::if_tree_range<Range>> QRangeModel::QRangeModel(Range &&range, QObject *parent) |
| 513 | \fn template <typename Range, typename Protocol, QRangeModelDetails::if_tree_range<Range, Protocol>> QRangeModel::QRangeModel(Range &&range, Protocol &&protocol, QObject *parent) |
| 514 | |
| 515 | Constructs a QRangeModel instance that operates on the data in \a range. |
| 516 | The \a range has to be a sequential range for which \c{std::begin} and |
| 517 | \c{std::end} are available. If \a protocol is provided, then the model |
| 518 | will represent the range as a tree using the protocol implementation. The |
| 519 | model instance becomes a child of \a parent. |
| 520 | |
| 521 | The \a range can be a pointer or reference wrapper, in which case mutating |
| 522 | model APIs (such as \l{setData()} or \l{insertRow()}) will modify the data |
| 523 | in the referenced range instance. If \a range is a value (or moved into the |
| 524 | model), then connect to the signals emitted by the model to respond to |
| 525 | changes to the data. |
| 526 | |
| 527 | QRangeModel will not access the \a range while being constructed. This |
| 528 | makes it legal to pass a pointer or reference to a range object that is not |
| 529 | fully constructed yet to this constructor, for example when \l{Subclassing |
| 530 | QRangeModel}{subclassing QRangeModel}. |
| 531 | |
| 532 | If the \a range was moved into the model, then the range and all data in it |
| 533 | will be destroyed upon destruction of the model. |
| 534 | |
| 535 | \note While the model does not take ownership of the range object otherwise, |
| 536 | you must not modify the \a range directly once the model has been constructed |
| 537 | and and passed on to a view. Such modifications will not emit signals |
| 538 | necessary to keep model users (other models or views) synchronized with the |
| 539 | model, resulting in inconsistent results, undefined behavior, and crashes. |
| 540 | */ |
| 541 | |
| 542 | /*! |
| 543 | Destroys the QRangeModel. |
| 544 | |
| 545 | The range that the model was constructed from is not accessed, and only |
| 546 | destroyed if the model was constructed from a moved-in range. |
| 547 | */ |
| 548 | QRangeModel::~QRangeModel() = default; |
| 549 | |
| 550 | /*! |
| 551 | \reimp |
| 552 | |
| 553 | Returns the index of the model item at \a row and \a column in \a parent. |
| 554 | |
| 555 | Passing a valid parent produces an invalid index for models that operate on |
| 556 | list and table ranges. |
| 557 | |
| 558 | \sa parent() |
| 559 | */ |
| 560 | QModelIndex QRangeModel::index(int row, int column, const QModelIndex &parent) const |
| 561 | { |
| 562 | Q_D(const QRangeModel); |
| 563 | return d->impl->call<QRangeModelImplBase::Index>(args&: row, args&: column, args: parent); |
| 564 | } |
| 565 | |
| 566 | /*! |
| 567 | \reimp |
| 568 | |
| 569 | Returns the parent of the item at the \a child index. |
| 570 | |
| 571 | This function always produces an invalid index for models that operate on |
| 572 | list and table ranges. For models operation on a tree, this function |
| 573 | returns the index for the row item returned by the parent() implementation |
| 574 | of the tree traversal protocol. |
| 575 | |
| 576 | \sa index(), hasChildren() |
| 577 | */ |
| 578 | QModelIndex QRangeModel::parent(const QModelIndex &child) const |
| 579 | { |
| 580 | Q_D(const QRangeModel); |
| 581 | return d->impl->call<QRangeModelImplBase::Parent>(args: child); |
| 582 | } |
| 583 | |
| 584 | /*! |
| 585 | \reimp |
| 586 | |
| 587 | Returns the sibling at \a row and \a column for the item at \a index, or an |
| 588 | invalid QModelIndex if there is no sibling at that location. |
| 589 | |
| 590 | This implementation is significantly faster than going through the parent() |
| 591 | of the \a index. |
| 592 | |
| 593 | \sa index(), QModelIndex::row(), QModelIndex::column() |
| 594 | */ |
| 595 | QModelIndex QRangeModel::sibling(int row, int column, const QModelIndex &index) const |
| 596 | { |
| 597 | Q_D(const QRangeModel); |
| 598 | return d->impl->call<QRangeModelImplBase::Sibling>(args&: row, args&: column, args: index); |
| 599 | } |
| 600 | |
| 601 | /*! |
| 602 | \reimp |
| 603 | |
| 604 | Returns the number of rows under the given \a parent. This is the number of |
| 605 | items in the root range for an invalid \a parent index. |
| 606 | |
| 607 | If the \a parent index is valid, then this function always returns 0 for |
| 608 | models that operate on list and table ranges. For trees, this returns the |
| 609 | size of the range returned by the childRows() implementation of the tree |
| 610 | traversal protocol. |
| 611 | |
| 612 | \sa columnCount(), insertRows(), hasChildren() |
| 613 | */ |
| 614 | int QRangeModel::rowCount(const QModelIndex &parent) const |
| 615 | { |
| 616 | Q_D(const QRangeModel); |
| 617 | return d->impl->call<QRangeModelImplBase::RowCount>(args: parent); |
| 618 | } |
| 619 | |
| 620 | /*! |
| 621 | \reimp |
| 622 | |
| 623 | Returns the number of columns of the model. This function returns the same |
| 624 | value for all \a parent indexes. |
| 625 | |
| 626 | For models operating on a statically sized row type, this returned value is |
| 627 | always the same throughout the lifetime of the model. For models operating |
| 628 | on dynamically sized row type, the model returns the number of items in the |
| 629 | first row, or 0 if the model has no rows. |
| 630 | |
| 631 | \sa rowCount, insertColumns() |
| 632 | */ |
| 633 | int QRangeModel::columnCount(const QModelIndex &parent) const |
| 634 | { |
| 635 | Q_D(const QRangeModel); |
| 636 | return d->impl->call<QRangeModelImplBase::ColumnCount>(args: parent); |
| 637 | } |
| 638 | |
| 639 | /*! |
| 640 | \reimp |
| 641 | |
| 642 | Returns the item flags for the given \a index. |
| 643 | |
| 644 | The implementation returns a combination of flags that enables the item |
| 645 | (\c ItemIsEnabled) and allows it to be selected (\c ItemIsSelectable). For |
| 646 | models operating on a range with mutable data, it also sets the flag |
| 647 | that allows the item to be editable (\c ItemIsEditable). |
| 648 | |
| 649 | \sa Qt::ItemFlags |
| 650 | */ |
| 651 | Qt::ItemFlags QRangeModel::flags(const QModelIndex &index) const |
| 652 | { |
| 653 | Q_D(const QRangeModel); |
| 654 | return d->impl->call<QRangeModelImplBase::Flags>(args: index); |
| 655 | } |
| 656 | |
| 657 | /*! |
| 658 | \reimp |
| 659 | |
| 660 | Returns the data for the given \a role and \a section in the header with |
| 661 | the specified \a orientation. |
| 662 | |
| 663 | For horizontal headers, the section number corresponds to the column |
| 664 | number. Similarly, for vertical headers, the section number corresponds to |
| 665 | the row number. |
| 666 | |
| 667 | For the horizontal header and the Qt::DisplayRole \a role, models that |
| 668 | operate on a range that uses an array as the row type return \a section. If |
| 669 | the row type is a tuple, then the implementation returns the name of the |
| 670 | type at \a section. For rows that are a gadget or QObject type, this |
| 671 | function returns the name of the property at the index of \a section. |
| 672 | |
| 673 | For the vertical header, this function always returns the result of the |
| 674 | default implementation in QAbstractItemModel. |
| 675 | |
| 676 | \sa Qt::ItemDataRole, setHeaderData(), QHeaderView |
| 677 | */ |
| 678 | QVariant QRangeModel::(int section, Qt::Orientation orientation, int role) const |
| 679 | { |
| 680 | Q_D(const QRangeModel); |
| 681 | return d->impl->call<QRangeModelImplBase::HeaderData>(args&: section, args&: orientation, args&: role); |
| 682 | } |
| 683 | |
| 684 | /*! |
| 685 | \reimp |
| 686 | */ |
| 687 | bool QRangeModel::(int section, Qt::Orientation orientation, const QVariant &data, |
| 688 | int role) |
| 689 | { |
| 690 | return QAbstractItemModel::setHeaderData(section, orientation, value: data, role); |
| 691 | } |
| 692 | |
| 693 | /*! |
| 694 | \reimp |
| 695 | |
| 696 | Returns the data stored under the given \a role for the value in the |
| 697 | range referred to by the \a index. |
| 698 | |
| 699 | If the item type for that index is an associative container that maps from |
| 700 | either \c{int}, Qt::ItemDataRole, or QString to a QVariant, then the role |
| 701 | data is looked up in that container and returned. |
| 702 | |
| 703 | If the item is a gadget or QObject, then the implementation returns the |
| 704 | value of the item's property matching the \a role entry in the roleNames() |
| 705 | mapping. |
| 706 | |
| 707 | Otherwise, the implementation returns a QVariant constructed from the item |
| 708 | via \c{QVariant::fromValue()} for \c{Qt::DisplayRole} or \c{Qt::EditRole}. |
| 709 | For other roles, the implementation returns an \b invalid |
| 710 | (default-constructed) QVariant. |
| 711 | |
| 712 | \sa Qt::ItemDataRole, setData(), headerData() |
| 713 | */ |
| 714 | QVariant QRangeModel::data(const QModelIndex &index, int role) const |
| 715 | { |
| 716 | Q_D(const QRangeModel); |
| 717 | return d->impl->call<QRangeModelImplBase::Data>(args: index, args&: role); |
| 718 | } |
| 719 | |
| 720 | /*! |
| 721 | \reimp |
| 722 | |
| 723 | Sets the \a role data for the item at \a index to \a data. |
| 724 | |
| 725 | If the item type for that \a index is an associative container that maps |
| 726 | from either \c{int}, Qt::ItemDataRole, or QString to a QVariant, then |
| 727 | \a data is stored in that container for the key specified by \a role. |
| 728 | |
| 729 | If the item is a gadget or QObject, then \a data is written to the item's |
| 730 | property matching the \a role entry in the the roleNames() mapping. The |
| 731 | function returns \c{true} if a property was found and if \a data stored a |
| 732 | value that could be converted to the required type, otherwise returns |
| 733 | \c{false}. |
| 734 | |
| 735 | Otherwise, this implementation assigns the value in \a data to the item at |
| 736 | the \a index in the range for \c{Qt::DisplayRole} and \c{Qt::EditRole}, |
| 737 | and returns \c{true}. For other roles, the implementation returns |
| 738 | \c{false}. |
| 739 | |
| 740 | //! [read-only-setData] |
| 741 | For models operating on a read-only range, or on a read-only column in |
| 742 | a row type that implements \l{the C++ tuple protocol}, this implementation |
| 743 | returns \c{false} immediately. |
| 744 | //! [read-only-setData] |
| 745 | */ |
| 746 | bool QRangeModel::setData(const QModelIndex &index, const QVariant &data, int role) |
| 747 | { |
| 748 | Q_D(QRangeModel); |
| 749 | return d->impl->call<QRangeModelImplBase::SetData>(args: index, args: data, args&: role); |
| 750 | } |
| 751 | |
| 752 | /*! |
| 753 | \reimp |
| 754 | |
| 755 | Returns a map with values for all predefined roles in the model for the |
| 756 | item at the given \a index. |
| 757 | |
| 758 | If the item type for that \a index is an associative container that maps |
| 759 | from either \c{int}, Qt::ItemDataRole, or QString to a QVariant, then the |
| 760 | data from that container is returned. |
| 761 | |
| 762 | If the item type is a gadget or QObject subclass, then the values of those |
| 763 | properties that match a \l{roleNames()}{role name} are returned. |
| 764 | |
| 765 | If the item is not an associative container, gadget, or QObject subclass, |
| 766 | then this calls the base class implementation. |
| 767 | |
| 768 | \sa setItemData(), Qt::ItemDataRole, data() |
| 769 | */ |
| 770 | QMap<int, QVariant> QRangeModel::itemData(const QModelIndex &index) const |
| 771 | { |
| 772 | Q_D(const QRangeModel); |
| 773 | return d->impl->call<QRangeModelImplBase::ItemData>(args: index); |
| 774 | } |
| 775 | |
| 776 | /*! |
| 777 | \reimp |
| 778 | |
| 779 | If the item type for that \a index is an associative container that maps |
| 780 | from either \c{int} or Qt::ItemDataRole to a QVariant, then the entries in |
| 781 | \a data are stored in that container. If the associative container maps from |
| 782 | QString to QVariant, then only those values in \a data are stored for which |
| 783 | there is a mapping in the \l{roleNames()}{role names} table. |
| 784 | |
| 785 | If the item type is a gadget or QObject subclass, then those properties that |
| 786 | match a \l{roleNames()}{role name} are set to the corresponding value in |
| 787 | \a data. |
| 788 | |
| 789 | Roles for which there is no entry in \a data are not modified. |
| 790 | |
| 791 | For item types that can be copied, this implementation is transactional, |
| 792 | and returns true if all the entries from \a data could be stored. If any |
| 793 | entry could not be updated, then the original container is not modified at |
| 794 | all, and the function returns false. |
| 795 | |
| 796 | If the item is not an associative container, gadget, or QObject subclass, |
| 797 | then this calls the base class implementation, which calls setData() for |
| 798 | each entry in \a data. |
| 799 | |
| 800 | \sa itemData(), setData(), Qt::ItemDataRole |
| 801 | */ |
| 802 | bool QRangeModel::setItemData(const QModelIndex &index, const QMap<int, QVariant> &data) |
| 803 | { |
| 804 | Q_D(QRangeModel); |
| 805 | return d->impl->call<QRangeModelImplBase::SetItemData>(args: index, args: data); |
| 806 | } |
| 807 | |
| 808 | /*! |
| 809 | \reimp |
| 810 | |
| 811 | Replaces the value stored in the range at \a index with a default- |
| 812 | constructed value. |
| 813 | |
| 814 | \include qrangemodel.cpp read-only-setData |
| 815 | */ |
| 816 | bool QRangeModel::clearItemData(const QModelIndex &index) |
| 817 | { |
| 818 | Q_D(QRangeModel); |
| 819 | return d->impl->call<QRangeModelImplBase::ClearItemData>(args: index); |
| 820 | } |
| 821 | |
| 822 | /* |
| 823 | //! [column-change-requirement] |
| 824 | \note A dynamically sized row type needs to provide a \c{\1} member function. |
| 825 | |
| 826 | For models operating on a read-only range, or on a range with a |
| 827 | statically sized row type (such as a tuple, array, or struct), this |
| 828 | implementation does nothing and returns \c{false} immediately. This is |
| 829 | always the case for tree models. |
| 830 | //! [column-change-requirement] |
| 831 | */ |
| 832 | |
| 833 | /*! |
| 834 | \reimp |
| 835 | |
| 836 | Inserts \a count empty columns before the item at \a column in all rows |
| 837 | of the range at \a parent. Returns \c{true} if successful; otherwise |
| 838 | returns \c{false}. |
| 839 | |
| 840 | \include qrangemodel.cpp {column-change-requirement} {insert(const_iterator, size_t, value_type)} |
| 841 | */ |
| 842 | bool QRangeModel::insertColumns(int column, int count, const QModelIndex &parent) |
| 843 | { |
| 844 | Q_D(QRangeModel); |
| 845 | return d->impl->call<QRangeModelImplBase::InsertColumns>(args&: column, args&: count, args: parent); |
| 846 | } |
| 847 | |
| 848 | /*! |
| 849 | \reimp |
| 850 | |
| 851 | Removes \a count columns from the item at \a column on in all rows of the |
| 852 | range at \a parent. Returns \c{true} if successful, otherwise returns |
| 853 | \c{false}. |
| 854 | |
| 855 | \include qrangemodel.cpp {column-change-requirement} {erase(const_iterator, size_t)} |
| 856 | */ |
| 857 | bool QRangeModel::removeColumns(int column, int count, const QModelIndex &parent) |
| 858 | { |
| 859 | Q_D(QRangeModel); |
| 860 | return d->impl->call<QRangeModelImplBase::RemoveColumns>(args&: column, args&: count, args: parent); |
| 861 | } |
| 862 | |
| 863 | /*! |
| 864 | \reimp |
| 865 | |
| 866 | Moves \a count columns starting with the given \a sourceColumn under parent |
| 867 | \a sourceParent to column \a destinationColumn under parent \a destinationParent. |
| 868 | |
| 869 | Returns \c{true} if the columns were successfully moved; otherwise returns |
| 870 | \c{false}. |
| 871 | */ |
| 872 | bool QRangeModel::moveColumns(const QModelIndex &sourceParent, int sourceColumn, int count, |
| 873 | const QModelIndex &destinationParent, int destinationColumn) |
| 874 | { |
| 875 | Q_D(QRangeModel); |
| 876 | return d->impl->call<QRangeModelImplBase::MoveColumns>( |
| 877 | args: sourceParent, args&: sourceColumn, args&: count, |
| 878 | args: destinationParent, args&: destinationColumn); |
| 879 | } |
| 880 | |
| 881 | /* |
| 882 | //! [row-change-requirement] |
| 883 | \note The range needs to be dynamically sized and provide a \c{\1} |
| 884 | member function. |
| 885 | |
| 886 | For models operating on a read-only or statically-sized range (such as |
| 887 | an array), this implementation does nothing and returns \c{false} |
| 888 | immediately. |
| 889 | //! [row-change-requirement] |
| 890 | */ |
| 891 | |
| 892 | /*! |
| 893 | \reimp |
| 894 | |
| 895 | Inserts \a count empty rows before the given \a row into the range at |
| 896 | \a parent. Returns \c{true} if successful; otherwise returns \c{false}. |
| 897 | |
| 898 | \include qrangemodel.cpp {row-change-requirement} {insert(const_iterator, size_t, value_type)} |
| 899 | |
| 900 | \note For ranges with a dynamically sized column type, the column needs |
| 901 | to provide a \c{resize(size_t)} member function. |
| 902 | */ |
| 903 | bool QRangeModel::insertRows(int row, int count, const QModelIndex &parent) |
| 904 | { |
| 905 | Q_D(QRangeModel); |
| 906 | return d->impl->call<QRangeModelImplBase::InsertRows>(args&: row, args&: count, args: parent); |
| 907 | } |
| 908 | |
| 909 | /*! |
| 910 | \reimp |
| 911 | |
| 912 | Removes \a count rows from the range at \a parent, starting with the |
| 913 | given \a row. Returns \c{true} if successful, otherwise returns \c{false}. |
| 914 | |
| 915 | \include qrangemodel.cpp {row-change-requirement} {erase(const_iterator, size_t)} |
| 916 | */ |
| 917 | bool QRangeModel::removeRows(int row, int count, const QModelIndex &parent) |
| 918 | { |
| 919 | Q_D(QRangeModel); |
| 920 | return d->impl->call<QRangeModelImplBase::RemoveRows>(args&: row, args&: count, args: parent); |
| 921 | } |
| 922 | |
| 923 | /*! |
| 924 | \reimp |
| 925 | |
| 926 | Moves \a count rows starting with the given \a sourceRow under parent |
| 927 | \a sourceParent to row \a destinationRow under parent \a destinationParent. |
| 928 | |
| 929 | Returns \c{true} if the rows were successfully moved; otherwise returns |
| 930 | \c{false}. |
| 931 | */ |
| 932 | bool QRangeModel::moveRows(const QModelIndex &sourceParent, int sourceRow, int count, |
| 933 | const QModelIndex &destinationParent, int destinationRow) |
| 934 | { |
| 935 | Q_D(QRangeModel); |
| 936 | return d->impl->call<QRangeModelImplBase::MoveRows>( |
| 937 | args: sourceParent, args&: sourceRow, args&: count, |
| 938 | args: destinationParent, args&: destinationRow); |
| 939 | } |
| 940 | |
| 941 | /*! |
| 942 | \reimp |
| 943 | */ |
| 944 | bool QRangeModel::canFetchMore(const QModelIndex &parent) const |
| 945 | { |
| 946 | return QAbstractItemModel::canFetchMore(parent); |
| 947 | } |
| 948 | |
| 949 | /*! |
| 950 | \reimp |
| 951 | */ |
| 952 | void QRangeModel::fetchMore(const QModelIndex &parent) |
| 953 | { |
| 954 | QAbstractItemModel::fetchMore(parent); |
| 955 | } |
| 956 | |
| 957 | /*! |
| 958 | \reimp |
| 959 | */ |
| 960 | bool QRangeModel::hasChildren(const QModelIndex &parent) const |
| 961 | { |
| 962 | return QAbstractItemModel::hasChildren(parent); |
| 963 | } |
| 964 | |
| 965 | /*! |
| 966 | \reimp |
| 967 | */ |
| 968 | QModelIndex QRangeModel::buddy(const QModelIndex &index) const |
| 969 | { |
| 970 | return QAbstractItemModel::buddy(index); |
| 971 | } |
| 972 | |
| 973 | /*! |
| 974 | \reimp |
| 975 | */ |
| 976 | bool QRangeModel::canDropMimeData(const QMimeData *data, Qt::DropAction action, |
| 977 | int row, int column, const QModelIndex &parent) const |
| 978 | { |
| 979 | return QAbstractItemModel::canDropMimeData(data, action, row, column, parent); |
| 980 | } |
| 981 | |
| 982 | /*! |
| 983 | \reimp |
| 984 | */ |
| 985 | bool QRangeModel::dropMimeData(const QMimeData *data, Qt::DropAction action, |
| 986 | int row, int column, const QModelIndex &parent) |
| 987 | { |
| 988 | return QAbstractItemModel::dropMimeData(data, action, row, column, parent); |
| 989 | } |
| 990 | |
| 991 | /*! |
| 992 | \reimp |
| 993 | */ |
| 994 | QMimeData *QRangeModel::mimeData(const QModelIndexList &indexes) const |
| 995 | { |
| 996 | return QAbstractItemModel::mimeData(indexes); |
| 997 | } |
| 998 | |
| 999 | /*! |
| 1000 | \reimp |
| 1001 | */ |
| 1002 | QStringList QRangeModel::mimeTypes() const |
| 1003 | { |
| 1004 | return QAbstractItemModel::mimeTypes(); |
| 1005 | } |
| 1006 | |
| 1007 | /*! |
| 1008 | \reimp |
| 1009 | */ |
| 1010 | QModelIndexList QRangeModel::match(const QModelIndex &start, int role, const QVariant &value, |
| 1011 | int hits, Qt::MatchFlags flags) const |
| 1012 | { |
| 1013 | return QAbstractItemModel::match(start, role, value, hits, flags); |
| 1014 | } |
| 1015 | |
| 1016 | /*! |
| 1017 | \reimp |
| 1018 | */ |
| 1019 | void QRangeModel::multiData(const QModelIndex &index, QModelRoleDataSpan roleDataSpan) const |
| 1020 | { |
| 1021 | QAbstractItemModel::multiData(index, roleDataSpan); |
| 1022 | } |
| 1023 | |
| 1024 | |
| 1025 | /*! |
| 1026 | \property QRangeModel::roleNames |
| 1027 | \brief the role names for the model. |
| 1028 | |
| 1029 | If all columns in the range are of the same type, and if that type provides |
| 1030 | a meta object (i.e., it is a gadget, or a QObject subclass), then this |
| 1031 | property holds the names of the properties of that type, mapped to values of |
| 1032 | Qt::ItemDataRole values from Qt::UserRole and up. In addition, a role |
| 1033 | "modelData" provides access to the gadget or QObject instance. |
| 1034 | |
| 1035 | Override this default behavior by setting this property explicitly to a non- |
| 1036 | empty mapping. Setting this property to an empty mapping, or using |
| 1037 | resetRoleNames(), restores the default behavior. |
| 1038 | |
| 1039 | \sa QAbstractItemModel::roleNames() |
| 1040 | */ |
| 1041 | |
| 1042 | QHash<int, QByteArray> QRangeModelImplBase::roleNamesForMetaObject(const QAbstractItemModel &model, |
| 1043 | const QMetaObject &metaObject) |
| 1044 | { |
| 1045 | const auto defaults = model.QAbstractItemModel::roleNames(); |
| 1046 | QHash<int, QByteArray> result = {{Qt::RangeModelDataRole, "modelData" }}; |
| 1047 | int offset = metaObject.propertyOffset(); |
| 1048 | for (int i = offset; i < metaObject.propertyCount(); ++i) { |
| 1049 | const auto name = metaObject.property(index: i).name(); |
| 1050 | const int defaultRole = defaults.key(value: name, defaultKey: -1); |
| 1051 | if (defaultRole != -1) { |
| 1052 | ++offset; |
| 1053 | result[defaultRole] = name; |
| 1054 | } else { |
| 1055 | result[Qt::UserRole + i - offset] = name; |
| 1056 | } |
| 1057 | } |
| 1058 | return result; |
| 1059 | } |
| 1060 | |
| 1061 | QHash<int, QByteArray> QRangeModelImplBase::roleNamesForSimpleType() |
| 1062 | { |
| 1063 | // just a plain value |
| 1064 | return QHash<int, QByteArray>{ |
| 1065 | {Qt::DisplayRole, "display" }, |
| 1066 | {Qt::EditRole, "edit" }, |
| 1067 | {Qt::RangeModelDataRole, "modelData" }, |
| 1068 | }; |
| 1069 | } |
| 1070 | |
| 1071 | /*! |
| 1072 | \reimp |
| 1073 | |
| 1074 | \note Overriding this function in a QRangeModel subclass is possible, |
| 1075 | but might break the behavior of the property. |
| 1076 | */ |
| 1077 | QHash<int, QByteArray> QRangeModel::roleNames() const |
| 1078 | { |
| 1079 | Q_D(const QRangeModel); |
| 1080 | if (d->m_roleNames.isEmpty()) |
| 1081 | d->m_roleNames = d->impl->call<QRangeModelImplBase::RoleNames>(); |
| 1082 | |
| 1083 | return d->m_roleNames; |
| 1084 | } |
| 1085 | |
| 1086 | void QRangeModel::setRoleNames(const QHash<int, QByteArray> &names) |
| 1087 | { |
| 1088 | Q_D(QRangeModel); |
| 1089 | if (d->m_roleNames == names) |
| 1090 | return; |
| 1091 | beginResetModel(); |
| 1092 | d->impl->call<QRangeModelImplBase::InvalidateCaches>(); |
| 1093 | d->m_roleNames = names; |
| 1094 | endResetModel(); |
| 1095 | Q_EMIT roleNamesChanged(); |
| 1096 | } |
| 1097 | |
| 1098 | void QRangeModel::resetRoleNames() |
| 1099 | { |
| 1100 | setRoleNames({}); |
| 1101 | } |
| 1102 | |
| 1103 | /*! |
| 1104 | \reimp |
| 1105 | */ |
| 1106 | void QRangeModel::sort(int column, Qt::SortOrder order) |
| 1107 | { |
| 1108 | return QAbstractItemModel::sort(column, order); |
| 1109 | } |
| 1110 | |
| 1111 | /*! |
| 1112 | \reimp |
| 1113 | */ |
| 1114 | QSize QRangeModel::span(const QModelIndex &index) const |
| 1115 | { |
| 1116 | return QAbstractItemModel::span(index); |
| 1117 | } |
| 1118 | |
| 1119 | /*! |
| 1120 | \reimp |
| 1121 | */ |
| 1122 | Qt::DropActions QRangeModel::supportedDragActions() const |
| 1123 | { |
| 1124 | return QAbstractItemModel::supportedDragActions(); |
| 1125 | } |
| 1126 | |
| 1127 | /*! |
| 1128 | \reimp |
| 1129 | */ |
| 1130 | Qt::DropActions QRangeModel::supportedDropActions() const |
| 1131 | { |
| 1132 | return QAbstractItemModel::supportedDropActions(); |
| 1133 | } |
| 1134 | |
| 1135 | /*! |
| 1136 | \reimp |
| 1137 | */ |
| 1138 | void QRangeModel::resetInternalData() |
| 1139 | { |
| 1140 | QAbstractItemModel::resetInternalData(); |
| 1141 | } |
| 1142 | |
| 1143 | /*! |
| 1144 | \reimp |
| 1145 | */ |
| 1146 | bool QRangeModel::event(QEvent *event) |
| 1147 | { |
| 1148 | return QAbstractItemModel::event(event); |
| 1149 | } |
| 1150 | |
| 1151 | /*! |
| 1152 | \reimp |
| 1153 | */ |
| 1154 | bool QRangeModel::eventFilter(QObject *object, QEvent *event) |
| 1155 | { |
| 1156 | return QAbstractItemModel::eventFilter(watched: object, event); |
| 1157 | } |
| 1158 | |
| 1159 | QT_END_NAMESPACE |
| 1160 | |
| 1161 | #include "moc_qrangemodel.cpp" |
| 1162 | |