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 */ ItemDataRole(int role)123 constexpr ItemDataRole(int role) noexcept 124 : role_(role) 125 { } 126 127 /*! \brief Returns the underlying int of this role. 128 */ value()129 constexpr int value() const noexcept 130 { 131 return role_; 132 } 133 134 constexpr bool operator== (const ItemDataRole &rhs) const noexcept 135 { 136 return role_ == rhs.role_; 137 } 138 139 constexpr bool operator!= (const ItemDataRole &rhs) const noexcept 140 { 141 return role_ != rhs.role_; 142 } 143 144 constexpr bool operator< (const ItemDataRole &rhs) const noexcept 145 { 146 return role_ < rhs.role_; 147 } 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 */ column()304 int column() const { return column_; } 305 306 /*! \brief Returns the row for this model index. 307 * 308 * \sa column() 309 */ row()310 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 */ internalPointer()323 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 */ internalId()336 ::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 */ isValid()390 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 */ model()396 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 WModelIndex ancestor(int depth) const; 506 507 bool isRawIndex() const; 508 }; 509 510 /*! \brief List of indexes 511 * 512 * The list is defined as std::vector<WModelIndex>. 513 */ 514 typedef std::vector<WModelIndex> WModelIndexList; 515 516 } 517 518 #ifndef WT_TARGET_JAVA 519 namespace std { 520 template<> 521 struct hash<Wt::WModelIndex> 522 { 523 std::size_t operator()(const Wt::WModelIndex& index) const 524 { 525 return Wt::hash_value(index); 526 } 527 }; 528 529 template<> 530 struct equal_to<Wt::WModelIndex> 531 { 532 bool operator()(const Wt::WModelIndex& index1, const Wt::WModelIndex& index2) const 533 { 534 return index1 == index2; 535 } 536 }; 537 } 538 #endif // WT_TARGET_JAVA 539 540 /*! @} */ 541 542 #endif // WMODEL_INDEX_H_ 543