LeechCraft 0.6.70-16373-g319c272718
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 <QApplication>
17#include <QDesktopWidget>
18#include <QStringListModel>
19#include <QAction>
20#include <QtDebug>
21#include "ui_categoryselector.h"
22#include "util.h"
23
24namespace LC::Util
25{
26 class CategorySelector::SelectorTagsModel : public QStringListModel
27 {
28 CategorySelector& Selector_;
29 QSet<int> SelectedRows_;
30
31 QString Header_;
32 public:
34 : QStringListModel { &selector }
35 , Selector_ { selector }
36 {
37 }
38
39 QVariant headerData (int section, Qt::Orientation orientation, int role) const override
40 {
41 if (role != Qt::DisplayRole || orientation != Qt::Horizontal || section)
42 return {};
43
44 return Header_;
45 }
46
47 Qt::ItemFlags flags (const QModelIndex& index) const override
48 {
49 return (QStringListModel::flags (index) & ~Qt::ItemIsEditable) | Qt::ItemIsUserCheckable;
50 }
51
52 QVariant data (const QModelIndex& index, int role) const override
53 {
54 if (role == Qt::CheckStateRole)
55 return SelectedRows_.contains (index.row ()) ? Qt::Checked : Qt::Unchecked;
56
57 return QStringListModel::data (index, role);
58 }
59
60 bool setData (const QModelIndex& index, const QVariant& value, int role) override
61 {
62 if (role != Qt::CheckStateRole)
63 return false;
64
65 if (value.value<Qt::CheckState> () == Qt::Checked)
66 SelectedRows_ << index.row ();
67 else
68 SelectedRows_.remove (index.row ());
69 emit dataChanged (index, index, { Qt::CheckStateRole });
70 Selector_.NotifyTagsSelection ();
71 return true;
72 }
73
74 void SelectAll ()
75 {
76 const int size = stringList ().size ();
77 if (!size)
78 return;
79
80 SelectedRows_.reserve (size);
81 for (int i = 0; i < size; ++i)
82 SelectedRows_ << i;
83
84 emit dataChanged (index (0), index (size - 1), { Qt::CheckStateRole });
85
86 Selector_.NotifyTagsSelection ();
87 }
88
89 void SelectNone ()
90 {
91 const int size = stringList ().size ();
92 if (!size)
93 return;
94
95 SelectedRows_.clear ();
96 emit dataChanged (index (0), index (size - 1), { Qt::CheckStateRole });
97
98 Selector_.NotifyTagsSelection ();
99 }
100
101 void SetHeader (QString header)
102 {
103 if (header == Header_)
104 return;
105
106 Header_ = std::move (header);
107 emit headerDataChanged (Qt::Horizontal, 0, 0);
108 }
109 };
110
112 : QDialog (parent)
113 , Ui_ { new Ui::CategorySelector }
114 , Model_ { *new SelectorTagsModel { *this } }
115 , Separator_ { GetDefaultTagsSeparator () }
116 {
117 setWindowTitle (tr ("Tags selector"));
118 setWindowFlags (Qt::Dialog | Qt::WindowStaysOnTopHint);
119
120 Ui_->setupUi (this);
121 Ui_->Tree_->setModel (&Model_);
122
123 const auto& avail = QApplication::desktop ()->availableGeometry (this);
124 setMinimumHeight (avail.height () / 3 * 2);
125
126 const auto all = new QAction (tr ("Select all"), this);
127 all->setProperty ("ActionIcon", "edit-select-all");
128 connect (all,
129 &QAction::triggered,
130 this,
132
133 const auto none = new QAction (tr ("Select none"), this);
134 none->setProperty ("ActionIcon", "edit-select-none");
135 connect (none,
136 &QAction::triggered,
137 this,
139
140 Ui_->Tree_->addAction (all);
141 Ui_->Tree_->addAction (none);
142
143 Ui_->Tree_->setContextMenuPolicy (Qt::ActionsContextMenu);
144
146 }
147
148 void CategorySelector::SetCaption (const QString& caption)
149 {
150 Model_.SetHeader (caption);
151 }
152
153 void CategorySelector::SetPossibleSelections (QStringList tags, bool sort)
154 {
155 auto guard = DisableNotifications ();
156
157 if (sort)
158 tags.sort ();
159 Model_.setStringList (tags);
160 Model_.SelectNone ();
161 }
162
164 {
165 return Model_.stringList ();
166 }
167
169 {
170 const auto& allTags = Model_.stringList ();
171 const auto& selectedIdxes = GetSelectedIndexes ();
172 QStringList selected;
173 selected.reserve (selectedIdxes.size ());
174 for (const auto idx : selectedIdxes)
175 selected << allTags [idx];
176 return selected;
177 }
178
180 {
181 QList<int> result;
182
183 const auto& rowCount = Model_.stringList ().size ();
184 for (int i = 0; i < rowCount; ++i)
185 {
186 const auto state = Model_.index (i).data (Qt::CheckStateRole).value<Qt::CheckState> ();
187 if (state == Qt::Checked)
188 result << i;
189 }
190
191 return result;
192 }
193
194 void CategorySelector::SetSelections (const QStringList& tags)
195 {
196 auto guard = DisableNotifications (false);
197
198 const auto& allTags = Model_.stringList ();
199 const auto rowCount = allTags.size ();
200 for (int i = 0; i < rowCount; ++i)
201 {
202 const auto state = tags.contains (allTags [i]) ?
203 Qt::Checked :
204 Qt::Unchecked;
205 Model_.setData (Model_.index (i), state, Qt::CheckStateRole);
206 }
207 }
208
210 {
211 return Separator_;
212 }
213
214 void CategorySelector::SetSeparator (const QString& sep)
215 {
216 Separator_ = sep;
217 }
218
220 {
221 switch (mode)
222 {
224 Ui_->ButtonsBox_->setVisible (false);
225 break;
227 Ui_->ButtonsBox_->setStandardButtons (QDialogButtonBox::Close);
228 Ui_->ButtonsBox_->setVisible (true);
229 break;
231 Ui_->ButtonsBox_->setStandardButtons (QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
232 Ui_->ButtonsBox_->setVisible (true);
233 break;
234 }
235 }
236
237 void CategorySelector::moveEvent (QMoveEvent *e)
238 {
239 QWidget::moveEvent (e);
240 QPoint pos = e->pos ();
241 QRect avail = QApplication::desktop ()->availableGeometry (this);
242 int dx = 0, dy = 0;
243 if (pos.x () + width () > avail.width ())
244 dx = width () + pos.x () - avail.width ();
245 if (pos.y () + height () > avail.height () &&
246 height () < avail.height ())
247 dy = height () + pos.y () - avail.height ();
248
249 if (dx || dy)
250 move (pos - QPoint (dx, dy));
251 }
252
254 {
255 Model_.SelectAll ();
256 }
257
259 {
260 Model_.SelectNone ();
261 }
262
264 {
265 auto guard = DisableNotifications (false);
266 SetSelections (text.split (Separator_, Qt::SkipEmptyParts));
267 }
268
269 void CategorySelector::NotifyTagsSelection ()
270 {
271 if (NotificationsEnabled_)
273 }
274
275 DefaultScopeGuard CategorySelector::DisableNotifications (bool reemit)
276 {
277 auto prevValue = NotificationsEnabled_;
278 NotificationsEnabled_ = false;
279 return MakeScopeGuard ([this, prevValue, reemit]
280 {
281 NotificationsEnabled_ = prevValue;
282 if (reemit)
283 NotifyTagsSelection ();
284 });
285 }
286}
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