1 /*
2  * Copyright (C) 2008 Emweb bv, Herent, Belgium.
3  *
4  * See the LICENSE file for terms of use.
5  */
6 #include <cstring>
7 #include <utility>
8 
9 #include <boost/functional/hash.hpp>
10 
11 #include "Wt/WModelIndex.h"
12 #include "Wt/WAbstractItemModel.h"
13 #include "Wt/WLogger.h"
14 
15 namespace Wt {
16 
17 const int ItemDataRole::Display;
18 const int ItemDataRole::Decoration;
19 const int ItemDataRole::Edit;
20 const int ItemDataRole::StyleClass;
21 const int ItemDataRole::Checked;
22 const int ItemDataRole::ToolTip;
23 const int ItemDataRole::Link;
24 const int ItemDataRole::MimeType;
25 const int ItemDataRole::Level;
26 const int ItemDataRole::MarkerPenColor;
27 const int ItemDataRole::MarkerBrushColor;
28 const int ItemDataRole::MarkerScaleFactor;
29 const int ItemDataRole::MarkerType;
30 const int ItemDataRole::BarPenColor;
31 const int ItemDataRole::BarBrushColor;
32 const int ItemDataRole::User;
33 
34 LOGGER("WModelIndex");
35 
WModelIndex()36 WModelIndex::WModelIndex()
37   : model_(0),
38     row_(0),
39     column_(0),
40     internalId_(0)
41 { }
42 
data(ItemDataRole role)43 cpp17::any WModelIndex::data(ItemDataRole role) const
44 {
45   return model_ ? model_->data(*this, role) : cpp17::any();
46 }
47 
flags()48 WFlags<ItemFlag> WModelIndex::flags() const
49 {
50   return model_ ? model_->flags(*this) : WFlags<ItemFlag>();
51 }
52 
child(int row,int column)53 WModelIndex WModelIndex::child(int row, int column) const
54 {
55   return model_ ? model_->index(row, column, *this) : WModelIndex();
56 }
57 
parent()58 WModelIndex WModelIndex::parent() const
59 {
60   return model_ ? model_->parent(*this) : WModelIndex();
61 }
62 
ancestor(int depth)63 WModelIndex WModelIndex::ancestor(int depth) const
64 {
65   if (depth == 0)
66     return *this;
67   else
68     return parent().ancestor(depth - 1);
69 }
70 
depth()71 int WModelIndex::depth() const
72 {
73   if (isValid())
74     return parent().depth() + 1;
75   else
76     return 0;
77 }
78 
79 bool WModelIndex::operator== (const WModelIndex& other) const
80 {
81   return model_ == other.model_ &&
82     row_ == other.row_ &&
83     column_ == other.column_ &&
84     internalId_ == other.internalId_;
85 }
86 
87 bool WModelIndex::operator!= (const WModelIndex& other) const
88 {
89   return !(*this == other);
90 }
91 
92 bool WModelIndex::operator< (const WModelIndex& i2) const
93 {
94   const WModelIndex& i1 = *this;
95 
96   if (!i1.isValid())
97     return i2.isValid();
98   else if (!i2.isValid())
99     return false;
100   else if (i1 == i2)
101     return false;
102   else if (i1.model() != i2.model()) {
103     LOG_ERROR("comparing indexes from different models are you?");
104     return false;
105   }
106 
107   if (i1.isRawIndex() &&
108       i2.isRawIndex()) {
109     return i1.internalId() < i2.internalId();
110   } else if (i1.isRawIndex()) {
111     assert(!i2.isRawIndex());
112     return true;
113   } else if (i2.isRawIndex()) {
114     assert(!i1.isRawIndex());
115     return false;
116   }
117 
118   int i1Depth = i1.depth();
119   int i2Depth = i2.depth();
120   unsigned e = std::min(i1Depth, i2Depth);
121 
122   WModelIndex a1 = i1.ancestor(i1Depth - e);
123   WModelIndex a2 = i2.ancestor(i2Depth - e);
124 
125   if (a1 == a2)
126     return i1Depth < i2Depth;
127 
128   for (unsigned i = e; i > 0; --i) {
129     WModelIndex p1 = a1.parent();
130     WModelIndex p2 = a2.parent();
131 
132     if (p1 == p2) {
133       if (a1.row() < a2.row())
134 	return true;
135       else if (a1.row() > a2.row())
136 	return false;
137       else if (a1.column() < a2.column())
138 	return true;
139       else
140 	return false;
141     }
142 
143     a1 = p1;
144     a2 = p2;
145   }
146 
147   return false; // unreachable code
148 }
149 
operator()150 bool WModelIndex::UnorderedLess::operator() (const WModelIndex& i1,
151 					     const WModelIndex& i2) const
152 {
153   if (!i1.isValid())
154     return i2.isValid();
155   else if (!i2.isValid())
156     return false;
157   else if (i1 == i2)
158     return false;
159   else if (i1.model() != i2.model()) {
160     LOG_ERROR("comparing indexes from different models are you?");
161     return false;
162   } else if (i1.row() < i2.row())
163     return true;
164   else if (i1.row() > i2.row())
165     return false;
166   else if (i1.column() < i2.column())
167     return true;
168   else if (i1.column() > i2.column())
169     return false;
170   else
171     return i1.internalId_ < i2.internalId_;
172 }
173 
WModelIndex(int row,int column,const WAbstractItemModel * model,void * ptr)174 WModelIndex::WModelIndex(int row, int column, const WAbstractItemModel *model,
175 			 void *ptr)
176   : model_(model),
177     row_(row),
178     column_(column),
179     internalId_(reinterpret_cast< ::uint64_t >(ptr))
180 { }
181 
WModelIndex(int row,int column,const WAbstractItemModel * model,::uint64_t id)182 WModelIndex::WModelIndex(int row, int column, const WAbstractItemModel *model,
183 			 ::uint64_t id)
184   : model_(model),
185     row_(row),
186     column_(column),
187     internalId_(id)
188 { }
189 
hash_value(const Wt::WModelIndex & index)190 std::size_t hash_value(const Wt::WModelIndex& index) {
191   std::size_t seed = 0;
192 
193   boost::hash_combine(seed, index.row());
194   boost::hash_combine(seed, index.column());
195   boost::hash_combine(seed, index.internalId());
196 
197   return seed;
198 }
199 
encodeAsRawIndex()200 void WModelIndex::encodeAsRawIndex()
201 {
202   if (model_) {
203     if (isRawIndex()) {
204       LOG_ERROR("encodeAsRawIndex(): cannot encode a raw index to raw again");
205       return;
206     }
207 
208     internalId_ = reinterpret_cast< ::uint64_t >(model_->toRawIndex(*this));
209     row_ = column_ = -42;
210   }
211 }
212 
decodeFromRawIndex()213 WModelIndex WModelIndex::decodeFromRawIndex() const
214 {
215   if (model_) {
216     if (!isRawIndex()) {
217       LOG_ERROR("decodeFromRawIndex(): can only decode an encoded raw index");
218       return WModelIndex();
219     }
220 
221     return model_->fromRawIndex(internalPointer());
222   } else
223     return *this;
224 }
225 
isRawIndex()226 bool WModelIndex::isRawIndex() const
227 {
228   return row_ == -42 && column_ == -42;
229 }
230 
encodeAsRawIndexes(WModelIndexSet & indexes)231 void WModelIndex::encodeAsRawIndexes(WModelIndexSet& indexes)
232 {
233   WModelIndexSet newSet;
234 
235   for (WModelIndexSet::iterator i = indexes.begin(); i != indexes.end(); ++i) {
236     WModelIndex copy = *i;
237     copy.encodeAsRawIndex();
238     newSet.insert(copy);
239   }
240 
241   std::swap(newSet, indexes);
242 }
243 
encodeAsRawIndexes(std::unordered_set<WModelIndex> & indexes)244 void WModelIndex::encodeAsRawIndexes(std::unordered_set<WModelIndex>& indexes)
245 {
246   std::unordered_set<WModelIndex> newSet;
247 
248   for (auto i = indexes.begin(); i != indexes.end(); ++i) {
249     WModelIndex copy = *i;
250     copy.encodeAsRawIndex();
251     newSet.insert(copy);
252   }
253 
254   std::swap(newSet, indexes);
255 }
256 
257 WModelIndexSet
decodeFromRawIndexes(const WModelIndexSet & encodedIndexes)258 WModelIndex::decodeFromRawIndexes(const WModelIndexSet& encodedIndexes)
259 {
260   WModelIndexSet result;
261 
262   for (WModelIndexSet::const_iterator i = encodedIndexes.begin();
263        i != encodedIndexes.end(); ++i) {
264     WModelIndex n = i->decodeFromRawIndex();
265     if (n.isValid())
266       result.insert(n);
267   }
268 
269   return result;
270 }
271 
272 std::unordered_set<WModelIndex>
decodeFromRawIndexes(const std::unordered_set<WModelIndex> & encodedIndexes)273 WModelIndex::decodeFromRawIndexes(const std::unordered_set<WModelIndex>& encodedIndexes)
274 {
275   std::unordered_set<WModelIndex> result;
276 
277   for (auto i = encodedIndexes.begin();
278        i != encodedIndexes.end(); ++i) {
279     WModelIndex n = i->decodeFromRawIndex();
280     if (n.isValid())
281       result.insert(n);
282   }
283 
284   return result;
285 }
286 
isAncestor(const Wt::WModelIndex & i1,const Wt::WModelIndex & i2)287 bool WModelIndex::isAncestor(const Wt::WModelIndex& i1,
288 			     const Wt::WModelIndex& i2) {
289   if (!i1.isValid())
290     return false;
291 
292   for (Wt::WModelIndex p = i1.parent(); p.isValid(); p = p.parent()) {
293     if (p == i2)
294       return true;
295   }
296 
297   return !i2.isValid();
298 }
299 
300 }
301