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 WABSTRACT_PROXY_MODEL_H_
8 #define WABSTRACT_PROXY_MODEL_H_
9 
10 #include <Wt/WAbstractItemModel.h>
11 
12 namespace Wt {
13 
14 /*! \class WAbstractProxyModel Wt/WAbstractProxyModel.h Wt/WAbstractProxyModel.h
15  *  \brief An abstract proxy model for %Wt's item models.
16  *
17  * A proxy model does not store data, but presents data from a source
18  * model in another way. It may provide filtering, sorting, or other
19  * computed changes to the source model. A proxy model may be a fully
20  * functional model, that also allows modification of the underlying
21  * model.
22  *
23  * This abstract proxy model may be used as a starting point for
24  * implementing a custom proxy model, when WSortFilterProxyModel is
25  * not adequate. It implements data access and manipulation using the
26  * a virtual mapping method (mapToSource()) to access and manipulate
27  * the underlying sourceModel().
28  *
29  * \ingroup modelview
30  */
31 class WT_API WAbstractProxyModel : public WAbstractItemModel
32 {
33 public:
34   /*! \brief Constructor.
35    */
36   WAbstractProxyModel();
37 
38   /*! \brief Maps a source model index to the proxy model.
39    *
40    * This method returns a model index in the proxy model that
41    * corresponds to the model index \p sourceIndex in the source
42    * model. This method must only be implemented for source model
43    * indexes that are mapped and thus are the result of mapToSource().
44    *
45    * \sa mapToSource()
46    */
47   virtual WModelIndex mapFromSource(const WModelIndex& sourceIndex) const = 0;
48 
49   /*! \brief Maps a proxy model index to the source model.
50    *
51    * This method returns a model index in the source model that
52    * corresponds to the proxy model index \p proxyIndex.
53    *
54    * \sa mapFromSource()
55    */
56   virtual WModelIndex mapToSource(const WModelIndex& proxyIndex) const = 0;
57 
58   /*! \brief Sets the source model.
59    *
60    * The source model provides the actual data for the proxy
61    * model.
62    *
63    * Ownership of the source model is <i>not</i> transferred.
64    *
65    * Note that the source model's signals are not forwarded to
66    * the proxy model by default, but some specializations,
67    * like WBatchEditProxyModel and WSortFilterProxyModel do.
68    * If you want to reimplement data() with no changes to row
69    * or column indices, consider the use of WIdentityProxyModel.
70    */
71   virtual void setSourceModel(const std::shared_ptr<WAbstractItemModel>&
72 			      sourceModel);
73 
74   /*! \brief Returns the source model.
75    *
76    * \sa setSourceModel()
77    */
sourceModel()78   std::shared_ptr<WAbstractItemModel> sourceModel() const {
79     return sourceModel_;
80   }
81 
82   using WAbstractItemModel::setData;
83   using WAbstractItemModel::data;
84   using WAbstractItemModel::setHeaderData;
85 
86   /*! \brief Returns the data at a specific model index.
87    *
88    * The default proxy implementation translates the index to the
89    * source model, and calls sourceModel()->data() with this index.
90    */
91   virtual cpp17::any data(const WModelIndex& index,
92                        ItemDataRole role = ItemDataRole::Display) const override;
93 
94   /*! \brief Returns the row or column header data.
95    *
96    * The default proxy implementation constructs a dummy
97    * WModelIndex with the row set to 0 and column set to \c section
98    * if the orientation is Wt::Orientation::Horizontal, or with the
99    * row set to \c section and the column set to 0 if the orientation
100    * is Wt::Orientation::Vertical.
101    *
102    * The resulting section that is forwarded to sourceModel()->headerData()
103    * depends on how the WModelIndex is transformed with mapToSource().
104    */
105   virtual cpp17::any headerData(int section,
106 			     Orientation orientation = Orientation::Horizontal,
107                              ItemDataRole role = ItemDataRole::Display)
108     const override;
109 
110   /*! \brief Sets the data at the given model index.
111    *
112    * The default proxy implementation calls sourceModel()->setData(mapToSource(index), value, role)
113    */
114   virtual bool setData(const WModelIndex& index, const cpp17::any& value,
115                        ItemDataRole role = ItemDataRole::Edit) override;
116 
117   /*! \brief Sets the data at the given model index.
118    *
119    * The default proxy implementation calls sourceModel()->setData(mapToSource(index), values)
120    */
121   virtual bool setItemData(const WModelIndex& index, const DataMap& values)
122     override;
123 
124   /*! \brief Returns the flags for an item.
125    *
126    * The default proxy implementation calls sourceModel()->flags(mapToSource(index))
127    */
128   virtual WFlags<ItemFlag> flags(const WModelIndex& index) const override;
129 
130   /*! \brief Returns the flags for a header.
131    *
132    * The default proxy implementation constructs a dummy
133    * WModelIndex with the row set to 0 and column set to \c section
134    * if the orientation is Wt::Orientation::Horizontal, or with the
135    * row set to \c section and the column set to 0 if the orientation
136    * is Wt::Orientation::Vertical.
137    *
138    * The resulting section that is forwarded to sourceModel()->headerFlags()
139    * depends on how the WModelIndex is transformed with mapToSource().
140    */
141   virtual WFlags<HeaderFlag> headerFlags
142     (int section, Orientation orientation = Orientation::Horizontal)
143     const override;
144 
145   /*! \brief Inserts one or more columns.
146    *
147    * The default proxy implementation calls sourceModel()->insertColumns(column, count, parent)
148    */
149   virtual bool insertColumns(int column, int count,
150 			     const WModelIndex& parent = WModelIndex())
151     override;
152 
153   /*! \brief Removes columns.
154    *
155    * The default proxy implementation calls sourceModel()->removeColumns(column, count, parent)
156    */
157   virtual bool removeColumns(int column, int count,
158 			     const WModelIndex& parent = WModelIndex())
159     override;
160 
161   /*! \brief Returns a mime-type for dragging a set of indexes.
162    *
163    * The default proxy implementation calls sourceModel()->mimeType()
164    */
165   virtual std::string mimeType() const override;
166 
167   /*! \brief Returns a list of mime-types that could be accepted for a
168    *         drop event.
169    *
170    * The default proxy implementation calls sourceModel()->acceptDropMimeTypes()
171    */
172   virtual std::vector<std::string> acceptDropMimeTypes() const override;
173 
174   /*! \brief Handles a drop event.
175    *
176    * The default proxy implementation maps the given row and parent
177    * to the row and parent in the source model, and forwards the
178    * dropEvent call to the source model.
179    */
180   virtual void dropEvent(const WDropEvent& e, DropAction action,
181 			 int row, int column, const WModelIndex& parent)
182     override;
183 
184   /*! \brief Converts a model index to a raw pointer that remains valid
185    *         while the model's layout is changed.
186    *
187    * The default proxy implementation calls sourceModel()->toRawIndex(mapToSource(index))
188    */
189   virtual void *toRawIndex(const WModelIndex& index) const override;
190 
191   /*! \brief Converts a raw pointer to a model index.
192    *
193    * The default proxy implementation calls mapFromSource(sourceModel()->fromRawIndex(rawIndex))
194    */
195   virtual WModelIndex fromRawIndex(void *rawIndex) const override;
196 
197 protected:
198   /*! \brief Create a source model index.
199    *
200    * This is a utility function that allows you to create indexes in
201    * the source model. In this way, you can reuse the internal pointers of
202    * the source model in proxy model indexes, and convert a proxy model index
203    * back to the source model index using this method.
204    */
205   WModelIndex createSourceIndex(int row, int column, void *ptr) const;
206 
207   /*! \brief A base class for an item modeling a source index parent.
208    *
209    * Many mplementations of a proxy model will need to maintain a data
210    * structure per source model indexes, where they relate source rows or
211    * columns to proxy rows or columns, per hierarchical parent.
212    *
213    * It may be convenient to start from this item class as a base
214    * class so that shiftModelIndexes() can be used to update this data
215    * structure when the source model adds or removes rows.
216    *
217    * You will typically use your derived class of this item as the
218    * internal pointer for proxy model indexes: a proxy model index
219    * will have an item as internal pointer whose sourceIndex_ corresponds
220    * to the source equivalent of the proxy model index parent.
221    *
222    * \sa createIndex()
223    */
224   struct WT_API BaseItem {
225     /*! \brief The source model index.
226      *
227      * The source model index for this item.
228      */
229     WModelIndex sourceIndex_;
230 
231     /*! \brief Create a BaseItem.
232      */
BaseItemBaseItem233     BaseItem(const WModelIndex& sourceIndex) : sourceIndex_(sourceIndex) { }
234     virtual ~BaseItem();
235   };
236 
237   /*! \brief A map for items.
238    *
239    * \sa BaseItem
240    */
241 #ifndef WT_TARGET_JAVA
242   typedef std::map<WModelIndex, BaseItem *> ItemMap;
243 #else
244   typedef std::treemap<WModelIndex, BaseItem *> ItemMap;
245 #endif // WT_TARGET_JAVA
246 
247   /*! \brief Utility methods to shift items in an item map.
248    *
249    * You can use this method to adjust an item map after the source
250    * model has inserted or removed rows. When removing rows (count < 0),
251    * items may possibly be removed and deleted.
252    */
253   void startShiftModelIndexes(const WModelIndex& sourceParent, int start, int count,
254 			      ItemMap& items);
255   void endShiftModelIndexes(const WModelIndex& sourceParent, int start, int count,
256 			    ItemMap& items);
257 
258 private:
259   std::vector<BaseItem *> itemsToShift_;
260   std::shared_ptr<WAbstractItemModel> sourceModel_;
261 };
262 
263 }
264 
265 #endif // WABSTRACT_PROXY_MODEL_H_
266