Krita Source Code Documentation
Loading...
Searching...
No Matches
LocaleHandler.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2025 Wolthera van Hövell tot Westerflier <griffinvalley@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6#include <QDebug>
7
9#include <KLocalizedString>
10#include <KConfigGroup>
11#include <KSharedConfig>
12
13#include "LocaleHandler.h"
14
15const QString localeName (const KoWritingSystemUtils::Bcp47Locale &locale) {
16 if (!locale.isValid()) return i18nc("Empty locale", "Empty");
17
18 QString name;
19 const QLocale l = KoWritingSystemUtils::localeFromBcp47Locale(locale);
20 const QString lang = QLocale::languageToString(l.language());
21 const QString region = QLocale::countryToString(l.country());
22
23 if (!lang.isEmpty() && lang != "C") {
24 if (!locale.regionTag.isEmpty()) {
25 if (!locale.variantTags.isEmpty()) {
26 name = i18nc("language, region, variant", "%1, %2, variant: %3", lang, region, locale.variantTags.join("-"));
27 } else {
28 name = i18nc("language, variant", "%1, variant: %2", lang, region);
29 }
30 } else {
31 if (!locale.variantTags.isEmpty()) {
32 name = i18nc("language, variant", "%1, variant: %2", lang, locale.variantTags.join("-"));
33 } else {
34 name = lang;
35 }
36 }
37 } else {
38 name = locale.toString();
39 }
40
41 return name;
42}
43
45 Private(QObject *parent = nullptr) {
46 allLanguages = new AllLanguagesModel(parent);
48 filteredLanguagesModel->setSourceModel(allLanguages);
49 filteredLanguagesModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
50
51 favorites = new FavoriteLocaleModel(parent);
52 }
53
58};
59
61 : QObject(parent)
62 , d(new Private(parent))
63{
64
65}
66
71
73{
74 return d->locale.toString();
75}
76
77void LocaleHandler::setBcp47Tag(const QString &newBcp47Tag)
78{
79 if (d->locale.toString() == newBcp47Tag)
80 return;
81 d->locale = KoWritingSystemUtils::parseBcp47Locale(newBcp47Tag);
82
83
84 d->favorites->addCode(language());
85 emit bcp47TagChanged();
86 emit languageChanged();
87 emit scriptChanged();
88}
89
90QString LocaleHandler::script() const
91{
92 return d->locale.scriptTag;
93}
94
95void LocaleHandler::setScript(const QString &newScript)
96{
97 if (d->locale.scriptTag == newScript)
98 return;
99 d->locale.scriptTag = newScript;
100 emit scriptChanged();
101 emit bcp47TagChanged();
102}
103
105{
106 KoWritingSystemUtils::Bcp47Locale langOnly = d->locale;
107 langOnly.scriptTag.clear();
108 return langOnly.toString();
109}
110
111void LocaleHandler::setLanguage(const QString &newLanguage)
112{
113 KoWritingSystemUtils::Bcp47Locale langOnly = d->locale;
114 langOnly.scriptTag.clear();
115 if (langOnly.toString() == newLanguage)
116 return;
117
118 langOnly = KoWritingSystemUtils::parseBcp47Locale(newLanguage);
119 langOnly.scriptTag.clear();
120 if (!langOnly.isValid()) return;
121
122 d->favorites->addCode(langOnly.toString());
123
124 langOnly.scriptTag = d->locale.scriptTag;
125 d->locale = langOnly;
126
127 emit languageChanged();
128 emit bcp47TagChanged();
129}
130
131QVariantList LocaleHandler::scriptModel() const
132{
133 QVariantList model;
134 const QString code = "code";
135 const QString name = "name";
136
137 for (int i = 0; i< int(QLocale::LastScript); i++) {
138 const QLocale::Script script = QLocale::Script(i);
139 QVariantMap map;
141 map.insert(name, QLocale::scriptToString(script));
142 model.append(map);
143 }
144 return model;
145}
146
147QAbstractItemModel *LocaleHandler::languagesModel() const
148{
149 return d->filteredLanguagesModel;
150}
151
152QAbstractItemModel *LocaleHandler::favoritesModel() const
153{
154 return d->favorites;
155}
156
158{
159 return d->filteredLanguagesModel->filterRegularExpression().pattern();
160}
161
162void LocaleHandler::setSearchString(const QString &newSearchString)
163{
164 if (d->filteredLanguagesModel->filterRegularExpression().pattern() == newSearchString)
165 return;
166 d->filteredLanguagesModel->setFilterRegularExpression(newSearchString);
167 emit searchStringChanged();
168}
169
171{
172 return d->locale.isValid();
173}
174
175bool LocaleHandler::validBcp47Tag(const QString &tag) const
176{
178}
179
182 for (int i = 0; i < QLocale::LastLanguage; i++) {
183 const QLocale::Language lang = QLocale::Language(i);
184 const QString langName = QLocale(lang).bcp47Name();
185 if (!locales.contains(langName)) {
186 locales.append(langName);
187 }
188 Q_FOREACH(const QLocale::Country region, QLocale::countriesForLanguage(lang)) {
189 const QLocale locale(lang, region);
190 const QString bcp = locale.name().split("_").join("-");
191 if (!locales.contains(bcp)) {
192 locales.append(bcp);
193 }
194 }
195 }
196 }
197
199};
200
202 : QAbstractListModel(parent)
203 , d(new Private())
204{
205
206}
207
212
213int AllLanguagesModel::rowCount(const QModelIndex &parent) const
214{
215 Q_UNUSED(parent)
216 return d->locales.size();
217}
218
219QVariant AllLanguagesModel::data(const QModelIndex &index, int role) const
220{
221 if (index.isValid()) {
222
223 const QString code = d->locales.at(index.row());
224 if (role == Qt::DisplayRole) {
226 return localeName(bcp47);
227 } else if (role == Code) {
228 return code;
229 }
230 }
231 return QVariant();
232}
233
234QHash<int, QByteArray> AllLanguagesModel::roleNames() const
235{
236 QHash<int, QByteArray> roles = QAbstractItemModel::roleNames();
237 roles[Code] = "code";
238 return roles;
239}
240
243 config = KSharedConfig::openConfig()->group("TextProperties");
244 Q_FOREACH(const QString lang, config.readEntry<QStringList>(configKey, KLocalizedString::languages())) {
245 const QLocale locale(lang);
246 const QString code = locale.bcp47Name().split("_").join("-");
247 locales.append(code);
248 }
250 locales.insert(0, ""); // Add empty locale...
251 }
252
255 KConfigGroup config;
256
257 const QString configKey = "favoriteLocales";
258};
260 : QAbstractListModel(parent)
261 , d(new Private ())
262{
263}
264
269
270int FavoriteLocaleModel::rowCount(const QModelIndex &parent) const
271{
272 Q_UNUSED(parent)
273 return d->locales.size();
274}
275
276QVariant FavoriteLocaleModel::data(const QModelIndex &index, int role) const
277{
278 if (index.isValid()) {
279 const QString code = d->locales.at(index.row());
280 if (role == Qt::DisplayRole) {
282 return localeName(bcp47);
283 } else if (role == Code) {
284 return code;
285 } else if (role == Favorite) {
286 return d->favorites.contains(code);
287 }
288 }
289 return QVariant();
290}
291#include <QDebug>
292bool FavoriteLocaleModel::setData(const QModelIndex &index, const QVariant &value, int role)
293{
294 if (!index.isValid()) return false;
295
296 const QString code = d->locales.at(index.row());
297 if (role == Favorite) {
298
299 const bool fav = value.toBool();
300 bool updated = false;
301
302 if (fav) {
303 if (!d->favorites.contains(code)) {
304 d->favorites.append(code);
305 updated = true;
306 }
307 } else {
308 const int i = d->favorites.indexOf(code);
309 if (i > 0) {
310 d->favorites.removeAt(i);
311 updated = true;
312 }
313 }
314 if (updated) {
315 updateConfig();
316 emit dataChanged(index, index, {role});
317 return true;
318 }
319 }
320 return false;
321}
322
323void FavoriteLocaleModel::addCode(const QString &code)
324{
325 if (!d->locales.contains(code)) {
326 beginInsertRows(QModelIndex(), d->locales.size(), d->locales.size());
327 d->locales.append(code);
328 endInsertRows();
329 }
330}
331
332QHash<int, QByteArray> FavoriteLocaleModel::roleNames() const
333{
334 QHash<int, QByteArray> roles = QAbstractItemModel::roleNames();
335 roles[Code] = "code";
336 roles[Favorite] = "favorite";
337 return roles;
338}
339
341{
342 d->config.writeEntry<QStringList>(d->configKey, d->favorites);
343}
344
346 : QSortFilterProxyModel(parent)
347{
348
349}
350
351bool LanguagesFilterModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
352{
353 QModelIndex idx = sourceModel()->index(source_row, 0, source_parent);
354 const QString name = sourceModel()->data(idx).toString();
355 const QString code = sourceModel()->data(idx, AllLanguagesModel::Code).toString();
356
357 return (name.contains(filterRegularExpression()) || code.contains(filterRegularExpression()));
358}
359
360
float value(const T *src, size_t ch)
const QString localeName(const KoWritingSystemUtils::Bcp47Locale &locale)
int rowCount(const QModelIndex &parent) const override
QVariant data(const QModelIndex &index, int role) const override
AllLanguagesModel(QObject *parent=nullptr)
const QScopedPointer< Private > d
QHash< int, QByteArray > roleNames() const override
The FavoriteLocaleModel class This class keeps track of favorite locales from the config.
QVariant data(const QModelIndex &index, int role) const override
int rowCount(const QModelIndex &parent) const override
void addCode(const QString &code)
FavoriteLocaleModel(QObject *parent=nullptr)
QHash< int, QByteArray > roleNames() const override
bool setData(const QModelIndex &index, const QVariant &value, int role) override
const QScopedPointer< Private > d
static QString scriptTagForQLocaleScript(QLocale::Script script)
static Bcp47Locale parseBcp47Locale(const QString &locale)
static QLocale localeFromBcp47Locale(const Bcp47Locale &locale)
The LanguagesFilterModel class class that tests both the name and the code.
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override
LanguagesFilterModel(QObject *parent=nullptr)
QString searchString
void setLanguage(const QString &newLanguage)
void setSearchString(const QString &newSearchString)
Q_INVOKABLE QVariantList scriptModel() const
QAbstractItemModel * favoritesModel
QAbstractItemModel * languagesModel
LocaleHandler(QObject *parent=nullptr)
void languageChanged()
const QScopedPointer< Private > d
void setBcp47Tag(const QString &newBcp47Tag)
void bcp47TagChanged()
Q_INVOKABLE bool validBcp47Tag(const QString &tag) const
void setScript(const QString &newScript)
void scriptChanged()
void searchStringChanged()
The Bcp47Locale class This holds a parsed BCP47 locale. QLocale is primarily made for POSIX locale fo...
FavoriteLocaleModel * favorites
AllLanguagesModel * allLanguages
KoWritingSystemUtils::Bcp47Locale locale
Private(QObject *parent=nullptr)
LanguagesFilterModel * filteredLanguagesModel