LeechCraft 0.6.70-17609-g3dde4097dd
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 <algorithm>
11#include <QStringList>
12#include <QCheckBox>
13#include <QVariant>
14#include <QVBoxLayout>
15#include <QMoveEvent>
16#include <QStringListModel>
17#include <QAction>
18#include <QtDebug>
19#include "ui_categoryselector.h"
20#include "util.h"
21
22namespace LC::Util
23{
24 class CategorySelector::SelectorTagsModel : public QStringListModel
25 {
26 CategorySelector& Selector_;
27 QSet<int> SelectedRows_;
28
29 QString Header_;
30 public:
32 : QStringListModel { &selector }
33 , Selector_ { selector }
34 {
35 }
36
37 QVariant headerData (int section, Qt::Orientation orientation, int role) const override
38 {
39 if (role != Qt::DisplayRole || orientation != Qt::Horizontal || section)
40 return {};
41
42 return Header_;
43 }
44
45 Qt::ItemFlags flags (const QModelIndex& index) const override
46 {
47 return (QStringListModel::flags (index) & ~Qt::ItemIsEditable) | Qt::ItemIsUserCheckable;
48 }
49
50 QVariant data (const QModelIndex& index, int role) const override
51 {
52 if (role == Qt::CheckStateRole)
53 return SelectedRows_.contains (index.row ()) ? Qt::Checked : Qt::Unchecked;
54
55 return QStringListModel::data (index, role);
56 }
57
58 bool setData (const QModelIndex& index, const QVariant& value, int role) override
59 {
60 if (role != Qt::CheckStateRole)
61 return false;
62
63 if (value.value<Qt::CheckState> () == Qt::Checked)
64 SelectedRows_ << index.row ();
65 else
66 SelectedRows_.remove (index.row ());
67 emit dataChanged (index, index, { Qt::CheckStateRole });
68 Selector_.NotifyTagsSelection ();
69 return true;
70 }
71
72 void SelectAll ()
73 {
74 const int size = stringList ().size ();
75 if (!size)
76 return;
77
78 SelectedRows_.reserve (size);
79 for (int i = 0; i < size; ++i)
80 SelectedRows_ << i;
81
82 emit dataChanged (index (0), index (size - 1), { Qt::CheckStateRole });
83
84 Selector_.NotifyTagsSelection ();
85 }
86
87 void SelectNone ()
88 {
89 const int size = stringList ().size ();
90 if (!size)
91 return;
92
93 SelectedRows_.clear ();
94 emit dataChanged (index (0), index (size - 1), { Qt::CheckStateRole });
95
96 Selector_.NotifyTagsSelection ();
97 }
98
99 void SetHeader (QString header)
100 {
101 if (header == Header_)
102 return;
103
104 Header_ = std::move (header);
105 emit headerDataChanged (Qt::Horizontal, 0, 0);
106 }
107 };
108
110 : QDialog (parent)
111 , Ui_ { new Ui::CategorySelector }
112 , Model_ { *new SelectorTagsModel { *this } }
113 , Separator_ { GetDefaultTagsSeparator () }
114 {
115 setWindowTitle (tr ("Tags selector"));
116 setWindowFlags (Qt::Dialog | Qt::WindowStaysOnTopHint);
117
118 Ui_->setupUi (this);
119 Ui_->Tree_->setModel (&Model_);
120
121 const auto& avail = screen ()->availableGeometry ();
122 setMinimumHeight (avail.height () / 3 * 2);
123
124 const auto all = new QAction (tr ("Select all"), this);
125 all->setProperty ("ActionIcon", "edit-select-all");
126 connect (all,
127 &QAction::triggered,
128 this,
130
131 const auto none = new QAction (tr ("Select none"), this);
132 none->setProperty ("ActionIcon", "edit-select-none");
133 connect (none,
134 &QAction::triggered,
135 this,
137
138 Ui_->Tree_->addAction (all);
139 Ui_->Tree_->addAction (none);
140
141 Ui_->Tree_->setContextMenuPolicy (Qt::ActionsContextMenu);
142
144 }
145
146 void CategorySelector::SetCaption (const QString& caption)
147 {
148 Model_.SetHeader (caption);
149 }
150
151 void CategorySelector::SetPossibleSelections (QStringList tags, bool sort)
152 {
153 auto guard = DisableNotifications ();
154
155 if (sort)
156 tags.sort ();
157 Model_.setStringList (tags);
158 Model_.SelectNone ();
159 }
160
162 {
163 return Model_.stringList ();
164 }
165
167 {
168 const auto& allTags = Model_.stringList ();
169 const auto& selectedIdxes = GetSelectedIndexes ();
170 QStringList selected;
171 selected.reserve (selectedIdxes.size ());
172 for (const auto idx : selectedIdxes)
173 selected << allTags [idx];
174 return selected;
175 }
176
178 {
179 QList<int> result;
180
181 const auto& rowCount = Model_.stringList ().size ();
182 for (int i = 0; i < rowCount; ++i)
183 {
184 const auto state = Model_.index (i).data (Qt::CheckStateRole).value<Qt::CheckState> ();
185 if (state == Qt::Checked)
186 result << i;
187 }
188
189 return result;
190 }
191
192 void CategorySelector::SetSelections (const QStringList& tags)
193 {
194 auto guard = DisableNotifications (false);
195
196 const auto& allTags = Model_.stringList ();
197 const auto rowCount = allTags.size ();
198 for (int i = 0; i < rowCount; ++i)
199 {
200 const auto state = tags.contains (allTags [i]) ?
201 Qt::Checked :
202 Qt::Unchecked;
203 Model_.setData (Model_.index (i), state, Qt::CheckStateRole);
204 }
205 }
206
208 {
209 return Separator_;
210 }
211
212 void CategorySelector::SetSeparator (const QString& sep)
213 {
214 Separator_ = sep;
215 }
216
218 {
219 switch (mode)
220 {
222 Ui_->ButtonsBox_->setVisible (false);
223 break;
225 Ui_->ButtonsBox_->setStandardButtons (QDialogButtonBox::Close);
226 Ui_->ButtonsBox_->setVisible (true);
227 break;
229 Ui_->ButtonsBox_->setStandardButtons (QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
230 Ui_->ButtonsBox_->setVisible (true);
231 break;
232 }
233 }
234
235 void CategorySelector::moveEvent (QMoveEvent *e)
236 {
237 QWidget::moveEvent (e);
238 QPoint pos = e->pos ();
239 QRect avail = screen ()->availableGeometry ();
240 int dx = 0, dy = 0;
241 if (pos.x () + width () > avail.width ())
242 dx = width () + pos.x () - avail.width ();
243 if (pos.y () + height () > avail.height () &&
244 height () < avail.height ())
245 dy = height () + pos.y () - avail.height ();
246
247 if (dx || dy)
248 move (pos - QPoint (dx, dy));
249 }
250
252 {
253 Model_.SelectAll ();
254 }
255
257 {
258 Model_.SelectNone ();
259 }
260
262 {
263 auto guard = DisableNotifications (false);
264 SetSelections (text.split (Separator_, Qt::SkipEmptyParts));
265 }
266
267 void CategorySelector::NotifyTagsSelection ()
268 {
269 if (NotificationsEnabled_)
271 }
272
273 DefaultScopeGuard CategorySelector::DisableNotifications (bool reemit)
274 {
275 auto prevValue = NotificationsEnabled_;
276 NotificationsEnabled_ = false;
277 return MakeScopeGuard ([this, prevValue, reemit]
278 {
279 NotificationsEnabled_ = prevValue;
280 if (reemit)
281 NotifyTagsSelection ();
282 });
283 }
284}
bool setData(const QModelIndex &index, const QVariant &value, int role) override
QVariant data(const QModelIndex &index, int role) const override
QVariant headerData(int section, Qt::Orientation orientation, int role) const override
Qt::ItemFlags flags(const QModelIndex &index) const override
void SetSelections(const QStringList &subset)
Selects some of the items.
void SetButtonsMode(ButtonsMode)
Sets the buttons mode.
QList< int > GetSelectedIndexes() const
Gets the indexes of the selected items.
QStringList GetSelections() const
Gets selected items.
CategorySelector(QWidget *parent=nullptr)
Constructor.
QStringList GetPossibleSelections() const
QString GetSeparator() const
Returns the separator for the tags.
void moveEvent(QMoveEvent *) override
Checks whether after the move event the selector won't be beoynd the screen. if it would,...
void SelectNone()
Deselects all variants.
void SetCaption(const QString &caption)
Sets the caption of this selector.
void SetSeparator(const QString &)
Sets the separator for the tags.
virtual void SetPossibleSelections(QStringList selections, bool sort=true)
Sets possible selections.
void SetSelectionsFromString(const QString &newText)
Notifies CategorySelector about logical selection changes.
void SelectAll()
Selects all variants.
void tagsSelectionChanged(const QStringList &newSelections)
Indicates that selections have changed.
detail::ScopeGuard< F > MakeScopeGuard(const F &f)
Returns an object performing passed function on scope exit.
Definition util.h:155
QString GetDefaultTagsSeparator()
Definition util.cpp:14
detail::ScopeGuard< detail::DefaultScopeGuardDeleter > DefaultScopeGuard
Definition util.h:132