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