LeechCraft 0.6.70-19214-g121e5318a7
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 (std::invoke (F, t)); };
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 auto& item = this->ItemAt (idx);
160 if (item.*F == value)
161 return;
162
163 item.*F = std::forward<V> (value);
164 emit this->dataChanged (this->index (idx, 0), this->index (idx, 0),
165 { std::decay_t<decltype (T {}.*F)>::Role });
166 }
167
168 template<auto... Fs, typename... Vs>
169 void SetFields (int idx, Vs&&... values)
170 {
171 auto& item = this->ItemAt (idx);
172 QList<int> changedRoles;
173 changedRoles.reserve (sizeof... (values));
174 (([&]
175 {
176 if (item.*Fs != std::forward<Vs> (values))
177 {
178 item.*Fs = std::forward<Vs> (values);
179 changedRoles << std::decay_t<decltype (T {}.*Fs)>::Role;
180 }
181 } ()), ...);
182
183 if (!changedRoles.isEmpty ())
184 emit this->dataChanged (this->index (idx, 0), this->index (idx, 0), changedRoles);
185 }
186 protected:
187 QVariant GetData (int row, int, int role) const override
188 {
189 if (const auto getter = Role2Getter_.value (role))
190 return getter (this->ItemAt (row));
191 return {};
192 }
193 };
194
195
196 template<CtString RoleArg, auto GetterArg>
198 {
199 static constexpr auto Getter = GetterArg;
200 static constexpr auto Role = RoleArg;
201 };
202
203 template<CtString RoleArg, auto GetterArg>
205
206 template<typename T>
208 {
209 public:
211 using FieldsList_t = QVector<QPair<QByteArray, FieldGetter_t>>;
212 private:
213 const QVector<FieldGetter_t> Fields_;
214 const QHash<int, QByteArray> Roles_;
215 public:
216 template<typename... Fields>
217 explicit NamedItemsModel (QObject *parent, Fields...) noexcept
218 : FlatItemsModelTypedBase<T> { QStringList { {} }, parent }
219 , Fields_ { +[] (const T& t) -> QVariant { return t.*Fields::Getter; }... }
220 , Roles_ { MakeRoles ({ ToByteArray<Fields::Role> ()... }) }
221 {
222 }
223
224 QHash<int, QByteArray> roleNames () const override
225 {
226 return Roles_;
227 }
228 protected:
229 QVariant GetData (int row, int, int role) const override
230 {
231 if (const auto getter = Fields_.value (role - this->DataRole - 1))
232 return getter (this->ItemAt (row));
233 return {};
234 }
235 private:
236 QHash<int, QByteArray> MakeRoles (QVector<QByteArray> fields) const
237 {
239 result.reserve (result.size () + fields.size ());
240 for (int i = 0; i < fields.size (); ++i)
241 result [this->DataRole + i + 1] = std::move (fields [i]);
242 return result;
243 }
244 };
245
246 template<auto Getter>
247 struct Field
248 {
249 QString Name_;
250 };
251
252 namespace detail
253 {
254 template<Qt::ItemDataRole Role>
255 using RoleTag = std::integral_constant<Qt::ItemDataRole, Role>;
256
258 {
259 explicit Extension (auto&&...) {}
260
261 static Qt::ItemFlags GetFlags (auto&&...) { return {}; }
262 static bool SetData (auto&&...) { return false; }
263 static void GetDataForRole () {}
264 };
265
266 template<typename P>
268 {
269 struct Param
270 {
272 };
273
275
276 template<typename... Params>
277 requires (std::is_same_v<Param, Params> || ...)
278 explicit ParameterizedExtension (const std::tuple<Params...>& args)
279 : Param_ { std::get<Param> (args).Param_ }
280 {
281 }
282 };
283 }
284
285 template<auto IconField>
287 {
288 using Extension::Extension;
289
290 static QVariant GetDataForRole (detail::RoleTag<Qt::DecorationRole>, const auto& item, int column)
291 {
292 if (column)
293 return {};
294 return item.*IconField;
295 }
296 };
297
299 {
300 using ParameterizedExtension::ParameterizedExtension;
301
302 Qt::ItemFlags GetFlags (int column) const
303 {
304 return Param_.contains (column) ? Qt::ItemIsEditable : Qt::ItemFlags {};
305 }
306 };
307
308 template<auto CheckField>
310 {
311 using Extension::Extension;
312
313 static Qt::ItemFlags GetFlags (int column)
314 {
315 return column ? Qt::ItemFlags {} : Qt::ItemIsUserCheckable;
316 }
317
318 static QVariant GetDataForRole (detail::RoleTag<Qt::CheckStateRole>, const auto& item, int, int column)
319 {
320 if (column)
321 return QVariant {};
322
323 if constexpr (std::is_same_v<std::decay_t<decltype (item.*CheckField)>, Qt::CheckState>)
324 return item.*CheckField;
325 else if constexpr (std::is_same_v<std::decay_t<decltype (item.*CheckField)>, bool>)
326 return item.*CheckField ? Qt::Checked : Qt::Unchecked;
327 else
328 static_assert (false, "expected Qt::CheckState or bool field");
329 }
330
331 template<typename Item>
332 static bool SetData (Item& item, int, int column, const QVariant& value, int role)
333 {
334 if (role != Qt::CheckStateRole || column)
335 return false;
336
337 const auto state = value.value<Qt::CheckState> ();
338 if constexpr (std::is_same_v<std::decay_t<decltype (item.*CheckField)>, Qt::CheckState>)
339 item.*CheckField = state;
340 else if constexpr (std::is_same_v<std::decay_t<decltype (item.*CheckField)>, bool>)
341 item.*CheckField = state == Qt::Checked;
342 else
343 static_assert (false, "expected Qt::CheckState or bool field");
344 return true;
345 }
346 };
347
348 struct NoField {};
349 inline constexpr auto NoField_v = NoField {};
350
351 template<>
353 {
354 QHash<int, Qt::CheckState> RowsStates_;
355
356 using ParameterizedExtension::ParameterizedExtension;
357
358 static Qt::ItemFlags GetFlags (int column)
359 {
360 return column ? Qt::ItemFlags {} : Qt::ItemIsUserCheckable;
361 }
362
363 bool IsChecked (int row) const
364 {
365 return RowsStates_.value (row, Param_) == Qt::Checked;
366 }
367
368 QVariant GetDataForRole (detail::RoleTag<Qt::CheckStateRole>, const auto&, int row, int column)
369 {
370 return column ? QVariant {} : RowsStates_.value (row, Param_);
371 }
372
373 template<typename Item>
374 bool SetData (Item&, int row, int column, const QVariant& value, int role)
375 {
376 if (role != Qt::CheckStateRole || column)
377 return false;
378
379 RowsStates_ [row] = value.value<Qt::CheckState> ();
380 return true;
381 }
382 };
383
384 template<typename T, typename... Extensions>
386 , public Extensions...
387 {
388 using FieldGetter_t = QVariant (*) (const T&);
389 const QVector<FieldGetter_t> Fields_;
390
391 using FieldSetter_t = void (*) (T&, const QVariant&);
392 const QVector<FieldSetter_t> Setters_;
393 public:
394 template<auto... Getter>
395 explicit ItemsModel (const Field<Getter>&... fields)
396 : ItemsModel { std::tuple {}, fields... }
397 {
398 }
399
400 template<auto... Member, typename... ExtParams>
401 explicit ItemsModel (const std::tuple<ExtParams...>& extParams, const Field<Member>&... fields)
402 : FlatItemsModelTypedBase<T> { { fields.Name_... } }
403 , Extensions { extParams }...
404 , Fields_ { +[] (const T& t) -> QVariant { return t.*Member; }... }
405 , Setters_ { +[] (T& t, const QVariant& v) { t.*Member = v.value<std::decay_t<decltype (t.*Member)>> (); }... }
406 {
407 }
408
409 Qt::ItemFlags flags (const QModelIndex& index) const override
410 {
412 if (index.isValid ())
413 flags |= (Extensions::GetFlags (index.column ()) | ...);
414 return flags;
415 }
416
417 bool setData (const QModelIndex& index, const QVariant& value, int role) override
418 {
419 if (!index.isValid ())
420 return false;
421
422 auto& item = this->ItemAt (index.row ());
423 if ((Extensions::SetData (item, index.row (), index.column (), value, role) ||...))
424 {
425 emit this->dataChanged (index, index);
426 return true;
427 }
428
429 if (role != Qt::EditRole)
430 return false;
431
432 Setters_ [index.column ()] (item, value);
433 emit this->dataChanged (index, index);
434 return true;
435 }
436 protected:
437 QVariant GetData (int row, int column, int role) const override
438 {
439 const auto& item = this->ItemAt (row);
440
441 switch (role)
442 {
443 case Qt::DisplayRole:
444 case Qt::EditRole:
445 if (const auto getter = Fields_.value (column))
446 return getter (item);
447 return {};
448 case Qt::CheckStateRole:
449 return this->GetDataForRole (detail::RoleTag<Qt::CheckStateRole> {}, item, row, column);
450 case Qt::DecorationRole:
451 return this->GetDataForRole (detail::RoleTag<Qt::DecorationRole> {}, item, row, column);
452 default:
453 return {};
454 }
455 }
456
457 using Extensions::GetDataForRole...;
458
459 static QVariant GetDataForRole (auto&&...)
460 {
461 return {};
462 }
463 };
464}
QModelIndex index(int row, int col, const QModelIndex &parent={}) const override
QModelIndex parent(const QModelIndex &) const override
static constexpr auto DataRole
auto & ItemAt(this auto &&self, int row, const std::source_location &loc=std::source_location::current())
FlatItemsModelTypedBase(QStringList headers, QObject *parent=nullptr)
Qt::ItemFlags flags(const QModelIndex &index) const override
Definition itemsmodel.h:409
ItemsModel(const std::tuple< ExtParams... > &extParams, const Field< Member > &... fields)
Definition itemsmodel.h:401
ItemsModel(const Field< Getter > &... fields)
Definition itemsmodel.h:395
QVariant GetData(int row, int column, int role) const override
Definition itemsmodel.h:437
static QVariant GetDataForRole(auto &&...)
Definition itemsmodel.h:459
bool setData(const QModelIndex &index, const QVariant &value, int role) override
Definition itemsmodel.h:417
QHash< int, QByteArray > roleNames() const override
Definition itemsmodel.h:224
QVector< QPair< QByteArray, FieldGetter_t > > FieldsList_t
Definition itemsmodel.h:211
detail::FieldGetter_t< T > FieldGetter_t
Definition itemsmodel.h:210
NamedItemsModel(QObject *parent, Fields...) noexcept
Definition itemsmodel.h:217
QVariant GetData(int row, int, int role) const override
Definition itemsmodel.h:229
RoledItemsModel(QObject *parent=nullptr)
Definition itemsmodel.h:144
QVariant GetData(int row, int, int role) const override
Definition itemsmodel.h:187
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:169
std::integral_constant< Qt::ItemDataRole, Role > RoleTag
Definition itemsmodel.h:255
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:151
NamedMemberField< RoleArg, GetterArg > NamedMemberField_v
Definition itemsmodel.h:204
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:349
QVariant GetDataForRole(detail::RoleTag< Qt::CheckStateRole >, const auto &, int row, int column)
Definition itemsmodel.h:368
bool SetData(Item &, int row, int column, const QVariant &value, int role)
Definition itemsmodel.h:374
QHash< int, Qt::CheckState > RowsStates_
Definition itemsmodel.h:354
static Qt::ItemFlags GetFlags(int column)
Definition itemsmodel.h:358
static Qt::ItemFlags GetFlags(int column)
Definition itemsmodel.h:313
static bool SetData(Item &item, int, int column, const QVariant &value, int role)
Definition itemsmodel.h:332
static QVariant GetDataForRole(detail::RoleTag< Qt::CheckStateRole >, const auto &item, int, int column)
Definition itemsmodel.h:318
static QVariant GetDataForRole(detail::RoleTag< Qt::DecorationRole >, const auto &item, int column)
Definition itemsmodel.h:290
Qt::ItemFlags GetFlags(int column) const
Definition itemsmodel.h:302
static constexpr auto Role
Definition itemsmodel.h:200
static constexpr auto Getter
Definition itemsmodel.h:199
RoleOf()=default
static constexpr auto Role
Definition itemsmodel.h:20
RoleOf(RoleOf &&other)=default
RoleOf & operator=(const RoleOf &other)=default
bool operator==(const U &value) const
Definition itemsmodel.h:49
RoleOf(const RoleOf &other)=default
RoleOf(U &&value)
Definition itemsmodel.h:35
static bool SetData(auto &&...)
Definition itemsmodel.h:262
static Qt::ItemFlags GetFlags(auto &&...)
Definition itemsmodel.h:261
ParameterizedExtension(const std::tuple< Params... > &args)
Definition itemsmodel.h:278