8 #include "tagselectioncombobox.h"
13 #include <KCheckableProxyModel>
14 #include <QAbstractItemView>
16 #include <QItemSelectionModel>
21 #include <KLocalizedString>
30 template<
typename List> List tagsFromSelection(
const QItemSelection &selection,
int role)
33 for (
int i = 0; i < selection.
size(); ++i) {
34 const auto indexes = selection.
at(i).indexes();
35 std::transform(indexes.cbegin(), indexes.cend(), std::back_inserter(tags), [role](
const auto &idx) {
36 return idx.model()->data(idx, role).template value<typename List::value_type>();
44 const auto tags = tagsFromSelection<Tag::List>(selection, TagModel::TagRole);
47 std::transform(tags.cbegin(), tags.cend(), std::back_inserter(names), std::bind(&Tag::name, std::placeholders::_1));
53 class Akonadi::TagSelectionComboBoxPrivate
66 template<
typename Selection,
typename Comp>
void setSelection(
const Selection &entries, Comp &&cmp)
69 mPendingSelection = entries;
73 const auto forEachIndex = [
this, entries, cmp](
auto &&func) {
74 for (
int i = 0, cnt = tagModel->rowCount(); i < cnt; ++i) {
75 const auto index = tagModel->index(i, 0);
76 const auto tag = tagModel->data(index, TagModel::TagRole).value<
Tag>();
77 if (std::any_of(entries.cbegin(), entries.cend(), std::bind(cmp, tag, std::placeholders::_1))) {
78 if (func(index) == Break) {
87 forEachIndex([&selection](
const QModelIndex &index) {
94 q->setCurrentIndex(index.
row());
100 void toggleItem(
const QModelIndex &tagModelIndex)
const
110 void setCheckable(
bool checkable)
113 selectionModel = std::make_unique<QItemSelectionModel>(tagModel.get(), q);
114 checkableProxy = std::make_unique<KCheckableProxyModel>(q);
115 checkableProxy->setSourceModel(tagModel.get());
116 checkableProxy->setSelectionModel(selectionModel.get());
118 tagModel->setParent(
nullptr);
119 q->setModel(checkableProxy.get());
120 tagModel->setParent(q);
122 q->setEditable(
true);
123 q->lineEdit()->setReadOnly(
true);
124 q->lineEdit()->setPlaceholderText(
i18nc(
"@label Placeholder text in tag selection combobox",
"Select tags..."));
127 q->lineEdit()->installEventFilter(q);
128 q->view()->installEventFilter(q);
129 q->view()->viewport()->installEventFilter(q);
132 const auto selection = selectionModel->selection();
133 q->setEditText(getEditText(selection));
134 Q_EMIT q->selectionChanged(tagsFromSelection<Tag::List>(selection, TagModel::TagRole));
137 if (q->view()->isVisible()) {
138 const auto index = tagModel->index(i, 0);
145 tagModel->setParent(
nullptr);
146 q->setModel(tagModel.get());
147 tagModel->setParent(q);
150 q->lineEdit()->removeEventFilter(q);
153 q->view()->removeEventFilter(q);
154 q->view()->viewport()->removeEventFilter(q);
157 q->setEditable(
false);
159 selectionModel.reset();
160 checkableProxy.reset();
164 std::unique_ptr<QItemSelectionModel> selectionModel;
165 std::unique_ptr<TagModel> tagModel;
166 std::unique_ptr<KCheckableProxyModel> checkableProxy;
168 bool mCheckable =
false;
169 bool mAllowHide =
true;
170 bool mModelReady =
false;
172 std::variant<std::monostate, Tag::List, QStringList> mPendingSelection;
178 TagSelectionComboBox::TagSelectionComboBox(
QWidget *parent)
180 , d(new TagSelectionComboBoxPrivate(this))
182 auto monitor =
new Monitor(
this);
183 monitor->setObjectName(QStringLiteral(
"TagSelectionComboBoxMonitor"));
184 monitor->setTypeMonitored(Monitor::Tags);
186 d->tagModel = std::make_unique<TagModel>(monitor,
this);
187 connect(d->tagModel.get(), &TagModel::populated,
this, [
this]() {
188 d->mModelReady = true;
189 if (auto list = std::get_if<Tag::List>(&d->mPendingSelection)) {
191 }
else if (
auto slist = std::get_if<QStringList>(&d->mPendingSelection)) {
192 setSelection(*slist);
194 d->mPendingSelection = std::monostate{};
197 d->setCheckable(d->mCheckable);
200 TagSelectionComboBox::~TagSelectionComboBox() =
default;
202 void TagSelectionComboBox::setCheckable(
bool checkable)
204 if (d->mCheckable != checkable) {
205 d->mCheckable = checkable;
206 d->setCheckable(d->mCheckable);
210 bool TagSelectionComboBox::checkable()
const
212 return d->mCheckable;
215 void TagSelectionComboBox::setSelection(
const Tag::List &tags)
217 d->setSelection(tags, [](
const Tag &a,
const Tag &b) {
218 return a.name() == b.name();
222 void TagSelectionComboBox::setSelection(
const QStringList &tagNames)
224 d->setSelection(tagNames, [](
const Tag &a,
const QString &b) {
225 return a.name() == b;
229 Tag::List TagSelectionComboBox::selection()
const
231 if (!d->selectionModel) {
232 return {currentData(TagModel::TagRole).
value<
Tag>()};
234 return tagsFromSelection<Tag::List>(d->selectionModel->selection(), TagModel::TagRole);
237 QStringList TagSelectionComboBox::selectionNames()
const
239 if (!d->selectionModel) {
240 return {currentText()};
242 return tagsFromSelection<QStringList>(d->selectionModel->selection(), TagModel::NameRole);
245 void TagSelectionComboBox::hidePopup()
250 d->mAllowHide =
true;
253 void TagSelectionComboBox::keyPressEvent(
QKeyEvent *event)
255 switch (
event->key()) {
272 bool TagSelectionComboBox::eventFilter(
QObject *receiver,
QEvent *event)
274 switch (
event->type()) {
278 switch (
static_cast<QKeyEvent *
>(event)->key()) {
289 d->mAllowHide =
false;
290 if (receiver == lineEdit()) {