LeechCraft 0.6.70-18450-gabe19ee3b0
Modular cross-platform feature rich live environment.
Loading...
Searching...
No Matches
itemsmodel.h
Go to the documentation of this file.
1/**********************************************************************
2 * LeechCraft - modular cross-platform feature rich internet client.
3 * Copyright (C) 2006-2014 Georg Rudoy
4 *
5 * Distributed under the Boost Software License, Version 1.0.
6 * (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt)
7 **********************************************************************/
8
9#pragma once
10
11#include <util/sll/ctstring.h>
12#include <util/sll/typegetter.h>
14
15namespace LC::Util
16{
17 template<typename T, int RoleV>
18 struct RoleOf
19 {
20 constexpr static auto Role = RoleV;
21
22 using Type = T;
23
24 T Value_ {};
25
26 RoleOf () = default;
27
28 RoleOf (const RoleOf& other) = default;
29 RoleOf (RoleOf&& other) = default;
30
31 RoleOf& operator= (const RoleOf& other) = default;
32 RoleOf& operator= (RoleOf&& other) = default;
33
34 template<typename U = T>
35 RoleOf (U&& value)
36 : Value_ (std::forward<U> (value))
37 {
38 }
39
40 template<typename U = T>
41 RoleOf& operator= (U&& value)
42 {
43 Value_ = std::forward<U> (value);
44 return *this;
45 }
46
47 template<typename U = T>
48 requires requires (T t, U u) { t == u; }
49 bool operator== (const U& value) const
50 {
51 return Value_ == value;
52 }
53
55 {
56 return Value_;
57 }
58
59 const T& operator* () const
60 {
61 return Value_;
62 }
63
65 {
66 return &Value_;
67 }
68
69 const T* operator-> () const
70 {
71 return &Value_;
72 }
73
74 operator T () const
75 requires (!std::is_same_v<T, QVariant>)
76 {
77 return Value_;
78 }
79
80 operator QVariant () const
81 {
82 return Value_;
83 }
84 };
85
86 namespace detail
87 {
88 constexpr auto GetFieldsCount (auto&& val)
89 {
90 auto&& [...elems] = val;
91 return std::integral_constant<size_t, sizeof... (elems)> {};
92 }
93
94 template<size_t I>
95 constexpr auto GetFieldAt (auto&& val)
96 {
97 auto&& [...elems] = val;
98 return elems... [I];
99 }
100
101 template<typename T, size_t I>
102 using FieldType_t = decltype (GetFieldAt<I> (std::declval<T> ()));
103
104 template<typename T>
105 constexpr size_t FieldsCount_v = decltype (GetFieldsCount (std::declval<T> ()))::value;
106
107 template<typename T>
108 using FieldGetter_t = QVariant (*) (const T&);
109
110 template<typename T, size_t Ix>
111 std::pair<int, FieldGetter_t<T>> Role2GetterPair ()
112 {
113 if constexpr (requires { FieldType_t<T, Ix>::Role; })
114 return
115 {
117 +[] (const T& t) { return QVariant::fromValue (*GetFieldAt<Ix> (t)); }
118 };
119 else
120 return { -1, nullptr };
121 }
122
123 template<typename T>
124 QHash<int, FieldGetter_t<T>> MkGetters ()
125 {
126 return []<size_t... Ixs> (std::index_sequence<Ixs...>)
127 {
128 return QHash<int, FieldGetter_t<T>> { Role2GetterPair<T, Ixs> ()... };
129 } (std::make_index_sequence<FieldsCount_v<T>> {});
130 }
131 }
132
133 template<auto F>
134 constexpr auto FromField = +[] (const ArgType_t<decltype (F), 0>& t) { return QVariant::fromValue (t.*F); };
135
136 template<typename T>
138 {
139 public:
141 private:
142 const QHash<int, FieldGetter_t> Role2Getter_;
143 public:
144 explicit RoledItemsModel (QObject *parent = nullptr)
145 : FlatItemsModelTypedBase<T> { QStringList { {} }, parent }
146 , Role2Getter_ { detail::MkGetters<T> () }
147 {
148 }
149
150 explicit RoledItemsModel (const QHash<int, FieldGetter_t>& getters, QObject *parent = nullptr)
151 : FlatItemsModelTypedBase<T> { QStringList { {} }, parent }
152 , Role2Getter_ { getters }
153 {
154 }
155
156 template<auto F, typename V>
157 void SetField (int idx, V&& value)
158 {
159 if (this->Items_ [idx].*F == value)
160 return;
161
162 this->Items_ [idx].*F = std::forward<V> (value);
163 emit this->dataChanged (this->index (idx, 0), this->index (idx, 0),
164 { std::decay_t<decltype (T {}.*F)>::Role });
165 }
166
167 template<auto... Fs, typename... Vs>
168 void SetFields (int idx, Vs&&... values)
169 {
170 QList<int> changedRoles;
171 changedRoles.reserve (sizeof... (values));
172 (([&, this]
173 {
174 if (this->Items_ [idx].*Fs != std::forward<Vs> (values))
175 {
176 this->Items_ [idx].*Fs = std::forward<Vs> (values);
177 changedRoles << std::decay_t<decltype (T {}.*Fs)>::Role;
178 }
179 } ()), ...);
180
181 if (!changedRoles.isEmpty ())
182 emit this->dataChanged (this->index (idx, 0), this->index (idx, 0), changedRoles);
183 }
184 protected:
185 QVariant GetData (int row, int, int role) const override
186 {
187 if (const auto getter = Role2Getter_.value (role))
188 return getter (this->Items_.at (row));
189 return {};
190 }
191 };
192
193
194 template<CtString RoleArg, auto GetterArg>
196 {
197 static constexpr auto Getter = GetterArg;
198 static constexpr auto Role = RoleArg;
199 };
200
201 template<CtString RoleArg, auto GetterArg>
203
204 template<typename T>
206 {
207 public:
209 using FieldsList_t = QVector<QPair<QByteArray, FieldGetter_t>>;
210 private:
211 const QVector<FieldGetter_t> Fields_;
212 const QHash<int, QByteArray> Roles_;
213 public:
214 template<typename... Fields>
215 explicit NamedItemsModel (QObject *parent, Fields...) noexcept
216 : FlatItemsModelTypedBase<T> { QStringList { {} }, parent }
217 , Fields_ { +[] (const T& t) -> QVariant { return t.*Fields::Getter; }... }
218 , Roles_ { MakeRoles ({ ToByteArray<Fields::Role> ()... }) }
219 {
220 }
221
222 QHash<int, QByteArray> roleNames () const override
223 {
224 return Roles_;
225 }
226 protected:
227 QVariant GetData (int row, int, int role) const override
228 {
229 if (const auto getter = Fields_.value (role - this->DataRole - 1))
230 return getter (this->Items_.at (row));
231 return {};
232 }
233 private:
234 QHash<int, QByteArray> MakeRoles (QVector<QByteArray> fields) const
235 {
237 result.reserve (result.size () + fields.size ());
238 for (int i = 0; i < fields.size (); ++i)
239 result [this->DataRole + i + 1] = std::move (fields [i]);
240 return result;
241 }
242 };
243
244 template<auto Getter>
245 struct Field
246 {
247 QString Name_;
248 };
249
250 namespace detail
251 {
252 template<Qt::ItemDataRole Role>
253 using RoleTag = std::integral_constant<Qt::ItemDataRole, Role>;
254
256 {
257 explicit Extension (auto&&...) {}
258
259 static Qt::ItemFlags GetFlags (auto&&...) { return {}; }
260 static bool SetData (auto&&...) { return false; }
261 static void GetDataForRole () {}
262 };
263
264 template<typename P>
266 {
267 struct Param
268 {
270 };
271
273
274 template<typename... Params>
275 requires (std::is_same_v<Param, Params> || ...)
276 explicit ParameterizedExtension (const std::tuple<Params...>& args)
277 : Param_ { std::get<Param> (args).Param_ }
278 {
279 }
280 };
281 }
282
283 template<auto IconField>
285 {
286 using Extension::Extension;
287
288 static QVariant GetDataForRole (detail::RoleTag<Qt::DecorationRole>, const auto& item, int column)
289 {
290 if (column)
291 return {};
292 return item.*IconField;
293 }
294 };
295
297 {
298 using ParameterizedExtension::ParameterizedExtension;
299
300 Qt::ItemFlags GetFlags (int column) const
301 {
302 return Param_.contains (column) ? Qt::ItemIsEditable : Qt::ItemFlags {};
303 }
304 };
305
306 template<auto CheckField>
308 {
309 using Extension::Extension;
310
311 static Qt::ItemFlags GetFlags (int column)
312 {
313 return column ? Qt::ItemFlags {} : Qt::ItemIsUserCheckable;
314 }
315
316 static QVariant GetDataForRole (detail::RoleTag<Qt::CheckStateRole>, const auto& item, int, int column)
317 {
318 if (column)
319 return QVariant {};
320
321 if constexpr (std::is_same_v<std::decay_t<decltype (item.*CheckField)>, Qt::CheckState>)
322 return item.*CheckField;
323 else if constexpr (std::is_same_v<std::decay_t<decltype (item.*CheckField)>, bool>)
324 return item.*CheckField ? Qt::Checked : Qt::Unchecked;
325 else
326 static_assert (false, "expected Qt::CheckState or bool field");
327 }
328
329 template<typename Item>
330 static bool SetData (Item& item, int, int column, const QVariant& value, int role)
331 {
332 if (role != Qt::CheckStateRole || column)
333 return false;
334
335 const auto state = value.value<Qt::CheckState> ();
336 if constexpr (std::is_same_v<std::decay_t<decltype (item.*CheckField)>, Qt::CheckState>)
337 item.*CheckField = state;
338 else if constexpr (std::is_same_v<std::decay_t<decltype (item.*CheckField)>, bool>)
339 item.*CheckField = state == Qt::Checked;
340 else
341 static_assert (false, "expected Qt::CheckState or bool field");
342 return true;
343 }
344 };
345
346 struct NoField {};
347 inline constexpr auto NoField_v = NoField {};
348
349 template<>
351 {
352 QHash<int, Qt::CheckState> RowsStates_;
353
354 using ParameterizedExtension::ParameterizedExtension;
355
356 static Qt::ItemFlags GetFlags (int column)
357 {
358 return column ? Qt::ItemFlags {} : Qt::ItemIsUserCheckable;
359 }
360
361 bool IsChecked (int row) const
362 {
363 return RowsStates_.value (row, Param_) == Qt::Checked;
364 }
365
366 QVariant GetDataForRole (detail::RoleTag<Qt::CheckStateRole>, const auto&, int row, int column)
367 {
368 return column ? QVariant {} : RowsStates_.value (row, Param_);
369 }
370
371 template<typename Item>
372 bool SetData (Item&, int row, int column, const QVariant& value, int role)
373 {
374 if (role != Qt::CheckStateRole || column)
375 return false;
376
377 RowsStates_ [row] = value.value<Qt::CheckState> ();
378 return true;
379 }
380 };
381
382 template<typename T, typename... Extensions>
384 , public Extensions...
385 {
386 using FieldGetter_t = QVariant (*) (const T&);
387 const QVector<FieldGetter_t> Fields_;
388
389 using FieldSetter_t = void (*) (T&, const QVariant&);
390 const QVector<FieldSetter_t> Setters_;
391 public:
392 template<auto... Getter>
393 explicit ItemsModel (const Field<Getter>&... fields)
394 : ItemsModel { std::tuple {}, fields... }
395 {
396 }
397
398 template<auto... Member, typename... ExtParams>
399 explicit ItemsModel (const std::tuple<ExtParams...>& extParams, const Field<Member>&... fields)
400 : FlatItemsModelTypedBase<T> { { fields.Name_... } }
401 , Extensions { extParams }...
402 , Fields_ { +[] (const T& t) -> QVariant { return t.*Member; }... }
403 , Setters_ { +[] (T& t, const QVariant& v) { t.*Member = v.value<std::decay_t<decltype (t.*Member)>> (); }... }
404 {
405 }
406
407 Qt::ItemFlags flags (const QModelIndex& index) const override
408 {
410 flags |= (Extensions::GetFlags (index.column ()) | ...);
411 return flags;
412 }
413
414 bool setData (const QModelIndex& index, const QVariant& value, int role) override
415 {
416 auto& item = this->Items_ [index.row ()];
417 if ((Extensions::SetData (item, index.row (), index.column (), value, role) ||...))
418 {
419 emit this->dataChanged (index, index);
420 return true;
421 }
422
423 if (role != Qt::EditRole)
424 return false;
425
426 Setters_ [index.column ()] (item, value);
427 emit this->dataChanged (index, index);
428 return true;
429 }
430 protected:
431 QVariant GetData (int row, int column, int role) const override
432 {
433 const auto& item = this->Items_ [row];
434
435 switch (role)
436 {
437 case Qt::DisplayRole:
438 case Qt::EditRole:
439 if (const auto getter = Fields_.value (column))
440 return getter (item);
441 return {};
442 case Qt::CheckStateRole:
443 return this->GetDataForRole (detail::RoleTag<Qt::CheckStateRole> {}, item, row, column);
444 case Qt::DecorationRole:
445 return this->GetDataForRole (detail::RoleTag<Qt::DecorationRole> {}, item, row, column);
446 default:
447 return {};
448 }
449 }
450
451 using Extensions::GetDataForRole...;
452
453 static QVariant GetDataForRole (auto&&...)
454 {
455 return {};
456 }
457 };
458}
QModelIndex index(int row, int col, const QModelIndex &parent={}) const override
QModelIndex parent(const QModelIndex &) const override
static constexpr auto DataRole
Qt::ItemFlags flags(const QModelIndex &index) const override
Definition itemsmodel.h:407
ItemsModel(const std::tuple< ExtParams... > &extParams, const Field< Member > &... fields)
Definition itemsmodel.h:399
ItemsModel(const Field< Getter > &... fields)
Definition itemsmodel.h:393
QVariant GetData(int row, int column, int role) const override
Definition itemsmodel.h:431
static QVariant GetDataForRole(auto &&...)
Definition itemsmodel.h:453
bool setData(const QModelIndex &index, const QVariant &value, int role) override
Definition itemsmodel.h:414
QHash< int, QByteArray > roleNames() const override
Definition itemsmodel.h:222
QVector< QPair< QByteArray, FieldGetter_t > > FieldsList_t
Definition itemsmodel.h:209
detail::FieldGetter_t< T > FieldGetter_t
Definition itemsmodel.h:208
NamedItemsModel(QObject *parent, Fields...) noexcept
Definition itemsmodel.h:215
QVariant GetData(int row, int, int role) const override
Definition itemsmodel.h:227
RoledItemsModel(QObject *parent=nullptr)
Definition itemsmodel.h:144
QVariant GetData(int row, int, int role) const override
Definition itemsmodel.h:185
void SetField(int idx, V &&value)
Definition itemsmodel.h:157
detail::FieldGetter_t< T > FieldGetter_t
Definition itemsmodel.h:140
RoledItemsModel(const QHash< int, FieldGetter_t > &getters, QObject *parent=nullptr)
Definition itemsmodel.h:150
void SetFields(int idx, Vs &&... values)
Definition itemsmodel.h:168
std::integral_constant< Qt::ItemDataRole, Role > RoleTag
Definition itemsmodel.h:253
constexpr size_t FieldsCount_v
Definition itemsmodel.h:105
std::pair< int, FieldGetter_t< T > > Role2GetterPair()
Definition itemsmodel.h:111
decltype(GetFieldAt< I >(std::declval< T >())) FieldType_t
Definition itemsmodel.h:102
QHash< int, FieldGetter_t< T > > MkGetters()
Definition itemsmodel.h:124
QVariant(*)(const T &) FieldGetter_t
Definition itemsmodel.h:108
constexpr auto GetFieldAt(auto &&val)
Definition itemsmodel.h:95
constexpr auto GetFieldsCount(auto &&val)
Definition itemsmodel.h:88
QByteArray ToByteArray() noexcept
Definition ctstring.h:146
NamedMemberField< RoleArg, GetterArg > NamedMemberField_v
Definition itemsmodel.h:202
std::tuple_element_t< Idx+1, detail::CallTypeGetter_t< F > > ArgType_t
Definition typegetter.h:49
constexpr auto FromField
Definition itemsmodel.h:134
constexpr auto NoField_v
Definition itemsmodel.h:347
QVariant GetDataForRole(detail::RoleTag< Qt::CheckStateRole >, const auto &, int row, int column)
Definition itemsmodel.h:366
bool SetData(Item &, int row, int column, const QVariant &value, int role)
Definition itemsmodel.h:372
QHash< int, Qt::CheckState > RowsStates_
Definition itemsmodel.h:352
static Qt::ItemFlags GetFlags(int column)
Definition itemsmodel.h:356
static Qt::ItemFlags GetFlags(int column)
Definition itemsmodel.h:311
static bool SetData(Item &item, int, int column, const QVariant &value, int role)
Definition itemsmodel.h:330
static QVariant GetDataForRole(detail::RoleTag< Qt::CheckStateRole >, const auto &item, int, int column)
Definition itemsmodel.h:316
static QVariant GetDataForRole(detail::RoleTag< Qt::DecorationRole >, const auto &item, int column)
Definition itemsmodel.h:288
Qt::ItemFlags GetFlags(int column) const
Definition itemsmodel.h:300
static constexpr auto Role
Definition itemsmodel.h:198
static constexpr auto Getter
Definition itemsmodel.h:197
bool operator==(const U &value) const
Definition itemsmodel.h:49
RoleOf()=default
static constexpr auto Role
Definition itemsmodel.h:20
RoleOf(RoleOf &&other)=default
RoleOf & operator=(const RoleOf &other)=default
RoleOf(const RoleOf &other)=default
RoleOf(U &&value)
Definition itemsmodel.h:35
static bool SetData(auto &&...)
Definition itemsmodel.h:260
static Qt::ItemFlags GetFlags(auto &&...)
Definition itemsmodel.h:259
ParameterizedExtension(const std::tuple< Params... > &args)
Definition itemsmodel.h:276