KTextAddons

emojisortfilterproxymodel.cpp
1/*
2 SPDX-FileCopyrightText: 2021-2025 Laurent Montel <montel@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6#include "emojisortfilterproxymodel.h"
7#include "emojimodel.h"
8#include "emoticonunicodeutils.h"
9using namespace Qt::Literals::StringLiterals;
10using namespace TextEmoticonsCore;
11
12class EmojiSortFilterProxyModel::EmojiProxyModelPrivate
13{
14public:
15 EmojiProxyModelPrivate(EmojiSortFilterProxyModel *qq)
16 : q(qq)
17 {
18 }
19 void clearSearch()
20 {
21 q->setSearchIdentifier(QString());
22 }
23
24 [[nodiscard]] QString emojiToneSuffix() const
25 {
26 switch (tone) {
27 case EmojiModelManager::EmojiTone::All:
28 case EmojiModelManager::EmojiTone::Original:
29 return {};
30 case EmojiModelManager::EmojiTone::Light:
31 return "_tone1"_L1;
32 case EmojiModelManager::EmojiTone::MediumLight:
33 return "_tone2"_L1;
34 case EmojiModelManager::EmojiTone::Medium:
35 return "_tone3"_L1;
36 case EmojiModelManager::EmojiTone::MediumDark:
37 return "_tone4"_L1;
38 case EmojiModelManager::EmojiTone::Dark:
39 return "_tone5"_L1;
40 }
41 return {};
42 }
43
44 bool filterTone(int source_row, const QModelIndex &source_parent) const
45 {
46 if (tone == EmojiModelManager::EmojiTone::Original) {
47 const QModelIndex sourceIndex = q->sourceModel()->index(source_row, 0, source_parent);
48 const QString identifier = sourceIndex.data(EmojiModel::Identifier).toString();
49 if (!identifier.contains("_tone"_L1)) {
50 return true;
51 }
52 return false;
53 }
54 const QString suffix = emojiToneSuffix();
55 if (suffix.isEmpty()) {
56 return true;
57 } else {
58 const QModelIndex sourceIndex = q->sourceModel()->index(source_row, 0, source_parent);
59 const QString identifier = sourceIndex.data(EmojiModel::Identifier).toString();
60 const bool diversityChildren = sourceIndex.data(EmojiModel::DiversityChildren).toBool();
61 if (diversityChildren) {
62 return false;
63 }
64 if (identifier.contains("_tone"_L1) && identifier.contains(suffix)) {
65 return true;
66 } else if (!identifier.contains("_tone"_L1)) {
67 return true;
68 }
69 return false;
70 }
71 }
72
73 QString category;
74 QStringList recentEmoticons;
75 QString searchIdentifier;
76 EmojiModelManager::EmojiTone tone = EmojiModelManager::EmojiTone::All;
77 EmojiSortFilterProxyModel *const q;
78};
79
80EmojiSortFilterProxyModel::EmojiSortFilterProxyModel(QObject *parent)
81 : QSortFilterProxyModel(parent)
82 , d(new EmojiSortFilterProxyModel::EmojiProxyModelPrivate(this))
83{
84 setFilterCaseSensitivity(Qt::CaseInsensitive);
85 setFilterRole(EmojiModel::Identifier);
86 sort(0);
87}
88
89EmojiSortFilterProxyModel::~EmojiSortFilterProxyModel() = default;
90
91bool EmojiSortFilterProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
92{
93 if (d->category.isEmpty()) {
94 return d->filterTone(source_row, source_parent) && QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
95 }
96 if (!d->searchIdentifier.isEmpty()) {
97 const QModelIndex sourceIndex = sourceModel()->index(source_row, 0, source_parent);
98 const QString identifier = sourceIndex.data(EmojiModel::Identifier).toString();
99 if (d->filterTone(source_row, source_parent) && identifier.contains(d->searchIdentifier)) {
100 return true;
101 }
102 return false;
103 }
104 if (d->category == TextEmoticonsCore::EmoticonUnicodeUtils::recentIdentifier()) {
105 const QModelIndex sourceIndex = sourceModel()->index(source_row, 0, source_parent);
106 const QString identifier = sourceIndex.data(EmojiModel::Identifier).toString();
107 if (d->recentEmoticons.contains(identifier)) {
108 return true;
109 }
110 } else {
111 const QModelIndex sourceIndex = sourceModel()->index(source_row, 0, source_parent);
112 const auto category = sourceIndex.data(EmojiModel::Category).toString();
113 if (d->filterTone(source_row, source_parent) && d->category == category) {
114 return true;
115 }
116 }
117 return false;
118}
119
120EmojiModelManager::EmojiTone EmojiSortFilterProxyModel::emojiTone() const
121{
122 return d->tone;
123}
124
125void EmojiSortFilterProxyModel::setEmojiTone(EmojiModelManager::EmojiTone tone)
126{
127 if (d->tone != tone) {
128 d->tone = tone;
130 Q_EMIT emojiToneChanged();
131 }
132}
133
134QString EmojiSortFilterProxyModel::searchIdentifier() const
135{
136 return d->searchIdentifier;
137}
138
139void EmojiSortFilterProxyModel::setSearchIdentifier(const QString &newSearchIdentifier)
140{
141 if (d->searchIdentifier != newSearchIdentifier) {
142 d->searchIdentifier = newSearchIdentifier;
144 }
145}
146
147QStringList EmojiSortFilterProxyModel::recentEmoticons() const
148{
149 return d->recentEmoticons;
150}
151
152void EmojiSortFilterProxyModel::setRecentEmoticons(const QStringList &newRecentEmoticons)
153{
154 if (d->recentEmoticons != newRecentEmoticons) {
155 d->recentEmoticons = newRecentEmoticons;
156 if (TextEmoticonsCore::EmoticonUnicodeUtils::recentIdentifier() == d->category) {
157 invalidate();
158 }
159 Q_EMIT recentEmoticonsChanged();
160 }
161}
162
163QString EmojiSortFilterProxyModel::category() const
164{
165 return d->category;
166}
167
168void EmojiSortFilterProxyModel::setCategory(const QString &newCategorie)
169{
170 if (d->category != newCategorie) {
171 d->category = newCategorie;
172 if (!d->searchIdentifier.isEmpty()) {
173 d->clearSearch();
174 } else {
176 }
177 if ((TextEmoticonsCore::EmoticonUnicodeUtils::recentIdentifier() == d->category)
178 || (TextEmoticonsCore::EmoticonUnicodeUtils::customIdentifier() == d->category)) {
179 // Make sure that we reorder recent/custom category
180 invalidate();
181 }
182 Q_EMIT categoryChanged();
183 }
184}
185
186bool EmojiSortFilterProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
187{
188 if (TextEmoticonsCore::EmoticonUnicodeUtils::recentIdentifier() == d->category) {
189 const QString leftIdentifier = sourceModel()->data(left, EmojiModel::Identifier).toString();
190 const QString rightIdentifier = sourceModel()->data(right, EmojiModel::Identifier).toString();
191 const int positionIdentifierLeft = d->recentEmoticons.indexOf(leftIdentifier);
192 const int positionIdentifierRight = d->recentEmoticons.indexOf(rightIdentifier);
193 // qDebug() << " leftIdentifier " << leftIdentifier << " rightIdentifier " << rightIdentifier << " positionIdentifierLeft " <<
194 // positionIdentifierLeft
195 // << " positionIdentifierRight " << positionIdentifierRight;
196 // qDebug() << "mRecentEmoticons " << mRecentEmoticons;
197 return positionIdentifierLeft < positionIdentifierRight;
198 } else {
199 const int leftOrder = sourceModel()->data(left, EmojiModel::Order).toInt();
200 const int rightOrder = sourceModel()->data(right, EmojiModel::Order).toInt();
201
202 return leftOrder < rightOrder;
203 }
204}
205
206QString EmojiSortFilterProxyModel::emojiToneSuffix() const
207{
208 return d->emojiToneSuffix();
209}
210
211#include "moc_emojisortfilterproxymodel.cpp"
QVariant data(int role) const const
Q_EMITQ_EMIT
virtual bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const const
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
CaseInsensitive
bool toBool() const const
QString toString() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2025 The KDE developers.
Generated on Fri Feb 21 2025 11:46:43 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.