File indexing completed on 2024-12-01 07:40:33
0001 // SPDX-FileCopyrightText: 2017 Konstantinos Sideris <siderisk@auth.gr> 0002 // SPDX-License-Identifier: GPL-3.0-or-later 0003 0004 #include <QVariant> 0005 0006 #include "emojimodel.h" 0007 #include "emojitones.h" 0008 #include <QDebug> 0009 0010 #include <algorithm> 0011 0012 #include "customemojimodel.h" 0013 #include <KLocalizedString> 0014 0015 EmojiModel::EmojiModel(QObject *parent) 0016 : QAbstractListModel(parent) 0017 , m_config(KSharedConfig::openStateConfig()) 0018 , m_configGroup(KConfigGroup(m_config, QStringLiteral("Editor"))) 0019 { 0020 if (_emojis.isEmpty()) { 0021 #include "emojis.h" 0022 } 0023 } 0024 0025 int EmojiModel::rowCount(const QModelIndex &parent) const 0026 { 0027 Q_UNUSED(parent); 0028 int total = 0; 0029 for (const auto &category : _emojis) { 0030 total += category.count(); 0031 } 0032 return total; 0033 } 0034 0035 QVariant EmojiModel::data(const QModelIndex &index, int role) const 0036 { 0037 auto row = index.row(); 0038 for (const auto &category : _emojis) { 0039 if (row >= category.count()) { 0040 row -= category.count(); 0041 continue; 0042 } 0043 auto emoji = category[row].value<Emoji>(); 0044 switch (role) { 0045 case ShortNameRole: 0046 return QStringLiteral(":%1:").arg(emoji.shortName); 0047 case UnicodeRole: 0048 case ReplacedTextRole: 0049 return emoji.unicode; 0050 case InvalidRole: 0051 return QStringLiteral("invalid"); 0052 case DisplayRole: 0053 return QStringLiteral("%2 :%1:").arg(emoji.shortName, emoji.unicode); 0054 case DescriptionRole: 0055 return emoji.description; 0056 } 0057 } 0058 return {}; 0059 } 0060 0061 QHash<int, QByteArray> EmojiModel::roleNames() const 0062 { 0063 return {{ShortNameRole, "shortName"}, {UnicodeRole, "unicode"}}; 0064 } 0065 0066 QStringList EmojiModel::lastUsedEmojis() const 0067 { 0068 return m_configGroup.readEntry(QStringLiteral("lastUsedEmojis"), QStringList()); 0069 } 0070 0071 QVariantList EmojiModel::filterModel(const QString &filter, bool limit) 0072 { 0073 auto emojis = CustomEmojiModel::instance().filterModel(filter); 0074 emojis += filterModelNoCustom(filter, limit); 0075 return emojis; 0076 } 0077 0078 QVariantList EmojiModel::filterModelNoCustom(const QString &filter, bool limit) 0079 { 0080 QVariantList result; 0081 0082 for (const auto &e : _emojis.values()) { 0083 for (const auto &variant : e) { 0084 const auto &emoji = qvariant_cast<Emoji>(variant); 0085 if (emoji.shortName.contains(filter, Qt::CaseInsensitive)) { 0086 result.append(variant); 0087 if (result.length() > 10 && limit) { 0088 return result; 0089 } 0090 } 0091 } 0092 } 0093 return result; 0094 } 0095 0096 void EmojiModel::emojiUsed(const QVariant &modelData) 0097 { 0098 auto list = lastUsedEmojis(); 0099 const auto emoji = modelData.value<Emoji>(); 0100 0101 auto it = list.begin(); 0102 while (it != list.end()) { 0103 if (*it == emoji.shortName) { 0104 it = list.erase(it); 0105 } else { 0106 it++; 0107 } 0108 } 0109 0110 list.push_front(emoji.shortName); 0111 0112 m_configGroup.writeEntry(QStringLiteral("lastUsedEmojis"), list); 0113 0114 Q_EMIT historyChanged(); 0115 } 0116 0117 QVariantList EmojiModel::emojis(Category category) const 0118 { 0119 if (category == History) { 0120 return emojiHistory(); 0121 } 0122 if (category == HistoryNoCustom) { 0123 QVariantList list; 0124 for (const auto &e : emojiHistory()) { 0125 auto emoji = qvariant_cast<Emoji>(e); 0126 if (!emoji.isCustom) { 0127 list.append(e); 0128 } 0129 } 0130 return list; 0131 } 0132 if (category == Custom) { 0133 return CustomEmojiModel::instance().filterModel({}); 0134 } 0135 return _emojis[category]; 0136 } 0137 0138 QVariantList EmojiModel::tones(const QString &baseEmoji) const 0139 { 0140 if (baseEmoji.endsWith(QStringLiteral("tone"))) { 0141 return EmojiTones::_tones.values(baseEmoji.split(QStringLiteral(":"))[0]); 0142 } 0143 return EmojiTones::_tones.values(baseEmoji); 0144 } 0145 0146 QHash<EmojiModel::Category, QVariantList> EmojiModel::_emojis; 0147 0148 QVariantList EmojiModel::categories() const 0149 { 0150 return QVariantList{ 0151 {QVariantMap{ 0152 {QStringLiteral("category"), EmojiModel::HistoryNoCustom}, 0153 {QStringLiteral("name"), i18nc("Previously used emojis", "History")}, 0154 {QStringLiteral("emoji"), QStringLiteral("⌛️")}, 0155 }}, 0156 {QVariantMap{ 0157 {QStringLiteral("category"), EmojiModel::Smileys}, 0158 {QStringLiteral("name"), i18nc("'Smileys' is a category of emoji", "Smileys")}, 0159 {QStringLiteral("emoji"), QStringLiteral("😏")}, 0160 }}, 0161 {QVariantMap{ 0162 {QStringLiteral("category"), EmojiModel::People}, 0163 {QStringLiteral("name"), i18nc("'People' is a category of emoji", "People")}, 0164 {QStringLiteral("emoji"), QStringLiteral("🙋♂️")}, 0165 }}, 0166 {QVariantMap{ 0167 {QStringLiteral("category"), EmojiModel::Nature}, 0168 {QStringLiteral("name"), i18nc("'Nature' is a category of emoji", "Nature")}, 0169 {QStringLiteral("emoji"), QStringLiteral("🌲")}, 0170 }}, 0171 {QVariantMap{ 0172 {QStringLiteral("category"), EmojiModel::Food}, 0173 {QStringLiteral("name"), i18nc("'Food' is a category of emoji", "Food")}, 0174 {QStringLiteral("emoji"), QStringLiteral("🍛")}, 0175 }}, 0176 {QVariantMap{ 0177 {QStringLiteral("category"), EmojiModel::Activities}, 0178 {QStringLiteral("name"), i18nc("'Activities' is a category of emoji", "Activities")}, 0179 {QStringLiteral("emoji"), QStringLiteral("🚁")}, 0180 }}, 0181 {QVariantMap{ 0182 {QStringLiteral("category"), EmojiModel::Travel}, 0183 {QStringLiteral("name"), i18nc("'Travel' is a category of emoji", "Travel")}, 0184 {QStringLiteral("emoji"), QStringLiteral("🚅")}, 0185 }}, 0186 {QVariantMap{ 0187 {QStringLiteral("category"), EmojiModel::Objects}, 0188 {QStringLiteral("name"), i18nc("'Objects' is a category of emoji", "Objects")}, 0189 {QStringLiteral("emoji"), QStringLiteral("💡")}, 0190 }}, 0191 {QVariantMap{ 0192 {QStringLiteral("category"), EmojiModel::Symbols}, 0193 {QStringLiteral("name"), i18nc("'Symbols' is a category of emoji", "Symbols")}, 0194 {QStringLiteral("emoji"), QStringLiteral("🔣")}, 0195 }}, 0196 {QVariantMap{ 0197 {QStringLiteral("category"), EmojiModel::Flags}, 0198 {QStringLiteral("name"), i18nc("'Flags' is a category of emoji", "Flags")}, 0199 {QStringLiteral("emoji"), QStringLiteral("🏁")}, 0200 }}, 0201 }; 0202 } 0203 0204 QVariantList EmojiModel::categoriesWithCustom() const 0205 { 0206 auto cats = categories(); 0207 cats.removeAt(0); 0208 cats.insert(0, 0209 QVariantMap{ 0210 {QStringLiteral("category"), EmojiModel::History}, 0211 {QStringLiteral("name"), i18nc("Previously used emojis", "History")}, 0212 {QStringLiteral("emoji"), QStringLiteral("⌛️")}, 0213 }); 0214 cats.insert(1, 0215 QVariantMap{ 0216 {QStringLiteral("category"), EmojiModel::Custom}, 0217 {QStringLiteral("name"), i18nc("'Custom' is a category of emoji", "Custom")}, 0218 {QStringLiteral("emoji"), QStringLiteral("🖼️")}, 0219 }); 0220 ; 0221 return cats; 0222 } 0223 0224 QVariantList EmojiModel::emojiHistory() const 0225 { 0226 QVariantList list; 0227 for (const auto &historicEmoji : lastUsedEmojis()) { 0228 for (const auto &emojiCategory : _emojis) { 0229 for (const auto &emoji : emojiCategory) { 0230 if (qvariant_cast<Emoji>(emoji).shortName == historicEmoji) { 0231 list.append(emoji); 0232 } 0233 } 0234 } 0235 } 0236 return list; 0237 } 0238 0239 #include "moc_emojimodel.cpp"