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