LeechCraft 0.6.70-19424-g027e980fd1
Modular cross-platform feature rich live environment.
Loading...
Searching...
No Matches
categoryselector.cpp
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#include "categoryselector.h"
10#include <QAction>
11#include <QSet>
12#include <QSortFilterProxyModel>
13#include <QTreeView>
14#include <QVBoxLayout>
15
16namespace LC::Util
17{
18 class CategorySelector::CheckableModel final : public QSortFilterProxyModel
19 {
20 CategorySelector& Selector_;
21 QSet<QString> Selected_;
22 QString Caption_;
23 public:
24 explicit CheckableModel (CategorySelector& selector)
25 : QSortFilterProxyModel { &selector }
26 , Selector_ { selector }
27 {
28 setSortCaseSensitivity (Qt::CaseInsensitive);
29 sort (0);
30 }
31
32 QVariant headerData (int section, Qt::Orientation orientation, int role) const override
33 {
34 if (role != Qt::DisplayRole || orientation != Qt::Horizontal || section)
35 return {};
36
37 return Caption_;
38 }
39
40 Qt::ItemFlags flags (const QModelIndex& index) const override
41 {
42 const auto flags = QSortFilterProxyModel::flags (index);
43 if (!index.isValid () || index.column ())
44 return flags;
45
46 return (flags & ~Qt::ItemIsEditable) | Qt::ItemIsUserCheckable;
47 }
48
49 QVariant data (const QModelIndex& index, int role) const override
50 {
51 if (role != Qt::CheckStateRole)
52 return QSortFilterProxyModel::data (index, role);
53
54 if (!index.isValid () || index.column ())
55 return {};
56
57 return Selected_.contains (Name (index)) ? Qt::Checked : Qt::Unchecked;
58 }
59
60 bool setData (const QModelIndex& index, const QVariant& value, int role) override
61 {
62 if (role != Qt::CheckStateRole || !index.isValid () || index.column ())
63 return false;
64
65 const auto& name = Name (index);
66 if (value.value<Qt::CheckState> () == Qt::Checked)
67 Selected_ << name;
68 else
69 Selected_.remove (name);
70 emit dataChanged (index, index, { Qt::CheckStateRole });
71
72 emit Selector_.selectionEdited (Selector_.GetSelections ());
73 return true;
74 }
75
76 QStringList Selections () const
77 {
78 QStringList result;
79 for (int row = 0; row < rowCount (); ++row)
80 if (const auto& name = Name (index (row, 0)); Selected_.contains (name))
81 result << name;
82 return result;
83 }
84
85 QModelIndexList SelectedIndexes () const
86 {
87 QModelIndexList result;
88 for (int row = 0; row < rowCount (); ++row)
89 if (const auto& idx = index (row, 0); Selected_.contains (Name (idx)))
90 result << mapToSource (idx);
91 return result;
92 }
93
94 void SetSelected (const QStringList& names)
95 {
96 Selected_ = { names.begin (), names.end () };
97 NotifyAll ();
98 }
99
100 void SelectAll ()
101 {
102 Selected_.clear ();
103 for (int row = 0; row < rowCount (); ++row)
104 Selected_ << Name (index (row, 0));
105 NotifyAll ();
106 }
107
109 {
110 Selected_.clear ();
111 NotifyAll ();
112 }
113
114 void SetCaption (const QString& caption)
115 {
116 if (caption == Caption_)
117 return;
118
119 Caption_ = caption;
120 emit headerDataChanged (Qt::Horizontal, 0, 0);
121 }
122 private:
123 QString Name (const QModelIndex& index) const
124 {
125 return index.siblingAtColumn (0).data ().toString ();
126 }
127
128 void NotifyAll ()
129 {
130 if (const auto rows = rowCount ())
131 emit dataChanged (index (0, 0), index (rows - 1, 0), { Qt::CheckStateRole });
132 }
133 };
134
136 : QWidget { parent }
137 , Model_ { *new CheckableModel { *this } }
138 , View_ { *new QTreeView { this } }
139 {
140 View_.setModel (&Model_);
141 View_.setUniformRowHeights (true);
142 View_.setRootIsDecorated (false);
143 View_.setHeaderHidden (true);
144 View_.setContextMenuPolicy (Qt::ActionsContextMenu);
145
146 const auto all = new QAction { tr ("Select all"), this };
147 all->setProperty ("ActionIcon", "edit-select-all");
148 connect (all,
149 &QAction::triggered,
150 this,
151 [this]
152 {
153 Model_.SelectAll ();
155 });
156
157 const auto none = new QAction { tr ("Select none"), this };
158 none->setProperty ("ActionIcon", "edit-select-none");
159 connect (none,
160 &QAction::triggered,
161 this,
162 [this]
163 {
164 Model_.SelectNone ();
165 emit selectionEdited ({});
166 });
167
168 View_.addActions ({ all, none });
169
170 const auto layout = new QVBoxLayout { this };
171 layout->setContentsMargins (0, 0, 0, 0);
172 layout->addWidget (&View_);
173 }
174
175 void CategorySelector::SetModel (QAbstractItemModel& model)
176 {
177 Model_.setSourceModel (&model);
178 }
179
180 void CategorySelector::SetCaption (const QString& caption)
181 {
182 Model_.SetCaption (caption);
183 View_.setHeaderHidden (caption.isEmpty ());
184 }
185
187 {
188 return Model_.Selections ();
189 }
190
192 {
193 return Model_.SelectedIndexes ();
194 }
195
196 void CategorySelector::SetSelections (const QStringList& names)
197 {
198 Model_.SetSelected (names);
199 }
200
202 {
203 Model_.SelectAll ();
204 }
205
207 {
208 Model_.SelectNone ();
209 }
210}
bool setData(const QModelIndex &index, const QVariant &value, int role) override
Qt::ItemFlags flags(const QModelIndex &index) const override
void SetSelected(const QStringList &names)
QVariant headerData(int section, Qt::Orientation orientation, int role) const override
QVariant data(const QModelIndex &index, int role) const override
void selectionEdited(const QStringList &selected)
Emitted after the user has changed the selection, with GetSelections().
QStringList GetSelections() const
Returns the selected names present in the model.
void SetModel(QAbstractItemModel &model)
Lists the names of model, which is not owned.
CategorySelector(QWidget *parent=nullptr)
void SelectNone()
Clears the selection.
void SetCaption(const QString &caption)
Sets the header above the list; there is none by default.
void SetSelections(const QStringList &names)
Replaces the selection.
void SelectAll()
Selects exactly the names in the model.
QModelIndexList GetSelectedIndexes() const
Returns the model's indexes of the selected names.