You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
368 lines
11 KiB
368 lines
11 KiB
/* |
|
languagelistmodel.h |
|
SPDX-FileCopyrightText: 2021 Han Young <hanyoung@protonmail.com> |
|
SPDX-FileCopyrightText: 2019 Kevin Ottens <kevin.ottens@enioka.com> |
|
SPDX-License-Identifier: GPL-2.0-or-later |
|
*/ |
|
|
|
#include "languagelistmodel.h" |
|
#include "exampleutility.h" |
|
#include "kcm_regionandlang_debug.h" |
|
#include "kcmregionandlang.h" |
|
#include "regionandlangsettings.h" |
|
|
|
using namespace KCM_RegionAndLang; |
|
|
|
LanguageListModel::LanguageListModel(QObject *parent) |
|
: QAbstractListModel(parent) |
|
, m_selectedLanguageModel(new SelectedLanguageModel(this)) |
|
{ |
|
connect(this, &LanguageListModel::isPreviewExampleChanged, this, &LanguageListModel::exampleChanged); |
|
connect(m_selectedLanguageModel, &SelectedLanguageModel::exampleChanged, this, &LanguageListModel::exampleChanged); |
|
m_availableLanguages = KLocalizedString::availableDomainTranslations("plasmashell").values(); |
|
m_availableLanguages.sort(); |
|
m_availableLanguages.push_front(QStringLiteral("C")); |
|
} |
|
|
|
int LanguageListModel::rowCount(const QModelIndex &parent) const |
|
{ |
|
Q_UNUSED(parent) |
|
return m_availableLanguages.size(); |
|
} |
|
|
|
QVariant LanguageListModel::data(const QModelIndex &index, int role) const |
|
{ |
|
const auto row = index.row(); |
|
if (row < 0 || row >= m_availableLanguages.size()) { |
|
return {}; |
|
} |
|
switch (role) { |
|
case NativeName: |
|
return languageCodeToName(m_availableLanguages.at(row)); |
|
case LanguageCode: |
|
return m_availableLanguages.at(row); |
|
case Flag: { |
|
QString flagCode; |
|
const QStringList split = QLocale(m_availableLanguages.at(row)).name().split(QLatin1Char('_')); |
|
if (split.size() > 1) { |
|
flagCode = split[1].toLower(); |
|
} |
|
return QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kf5/locale/countries/%1/flag.png").arg(flagCode)); |
|
} |
|
} |
|
Q_UNREACHABLE(); |
|
return {}; |
|
} |
|
|
|
QHash<int, QByteArray> LanguageListModel::roleNames() const |
|
{ |
|
return {{NativeName, QByteArrayLiteral("nativeName")}, {LanguageCode, QByteArrayLiteral("languageCode")}, {Flag, QByteArrayLiteral("flag")}}; |
|
} |
|
|
|
QString LanguageListModel::languageCodeToName(const QString &languageCode) |
|
{ |
|
const QLocale locale(languageCode); |
|
const QString languageName = locale.nativeLanguageName(); |
|
|
|
if (languageName.isEmpty()) { |
|
return languageCode; |
|
} |
|
|
|
if (languageCode.contains(QLatin1Char('@'))) { |
|
return i18nc("%1 is language name, %2 is language code name", "%1 (%2)", languageName, languageCode); |
|
} |
|
|
|
// KDE languageCode got translated by QLocale to a locale code we also have on |
|
// the list. Currently this only happens with pt that gets translated to pt_BR. |
|
if (languageCode == QStringLiteral("pt_BR")) { |
|
return i18nc("%1 is português in system locale name, Brazil is to distinguish European português and Brazilian português", "%1 (Brazil)", languageName); |
|
} |
|
|
|
return languageName; |
|
} |
|
|
|
int LanguageListModel::currentIndex() const |
|
{ |
|
return m_index; |
|
} |
|
|
|
void LanguageListModel::setCurrentIndex(int index) |
|
{ |
|
if (index == m_index || index < 0 || index >= m_availableLanguages.size()) { |
|
return; |
|
} |
|
|
|
m_index = index; |
|
Q_EMIT exampleChanged(); |
|
} |
|
|
|
QString LanguageListModel::exampleHelper(const std::function<QString(const QLocale &)> &func) const |
|
{ |
|
if (!m_settings) { |
|
return {}; |
|
} |
|
|
|
QString result = func(QLocale(m_settings->langWithFallback())); |
|
if (m_isPreviewExample) { |
|
if (m_index < 0) { |
|
result = func(QLocale(m_settings->langWithFallback())); |
|
} else { |
|
result = func(QLocale(m_availableLanguages[m_index])); |
|
} |
|
} |
|
return result; |
|
} |
|
|
|
QString LanguageListModel::numberExample() const |
|
{ |
|
return exampleHelper(Utility::numericExample); |
|
} |
|
|
|
QString LanguageListModel::currencyExample() const |
|
{ |
|
return exampleHelper(Utility::monetaryExample); |
|
} |
|
|
|
QString LanguageListModel::timeExample() const |
|
{ |
|
return exampleHelper(Utility::timeExample); |
|
} |
|
|
|
QString LanguageListModel::metric() const |
|
{ |
|
return exampleHelper(Utility::measurementExample); |
|
} |
|
|
|
void LanguageListModel::setRegionAndLangSettings(QObject *settings) |
|
{ |
|
if (auto *regionandlangsettings = dynamic_cast<RegionAndLangSettings *>(settings)) { |
|
m_settings = regionandlangsettings; |
|
m_selectedLanguageModel->setRegionAndLangSettings(regionandlangsettings); |
|
Q_EMIT exampleChanged(); |
|
} |
|
} |
|
|
|
bool LanguageListModel::isPreviewExample() const |
|
{ |
|
return m_isPreviewExample; |
|
} |
|
|
|
void LanguageListModel::setIsPreviewExample(bool preview) |
|
{ |
|
m_isPreviewExample = preview; |
|
} |
|
|
|
void SelectedLanguageModel::setRegionAndLangSettings(RegionAndLangSettings *settings) |
|
{ |
|
m_settings = settings; |
|
|
|
beginResetModel(); |
|
if (m_settings->language().isEmpty() && m_settings->isDefaultSetting(SettingType::Lang)) { |
|
// no language but have lang |
|
m_selectedLanguages = {m_settings->lang()}; |
|
m_selectedLanguages.first().remove(QStringLiteral(".UTF-8")); |
|
} else if (!m_settings->language().isEmpty()) { |
|
// have language, ignore lang |
|
m_selectedLanguages = m_settings->language().split(QLatin1Char(':')); |
|
} else { |
|
// have nothing, figure out from env |
|
QString lang = envLang(); |
|
QString language = envLanguage(); |
|
if (!language.isEmpty()) { |
|
QStringList langlist = language.split(QLatin1Char(':')); |
|
for (QString &lang : langlist) { |
|
lang = lang.split(QLatin1Char('.'))[0]; |
|
} |
|
m_selectedLanguages = langlist; |
|
} else if (!lang.isEmpty()) { |
|
lang.remove(QStringLiteral(".UTF-8")); |
|
m_selectedLanguages = {lang}; |
|
} |
|
m_hasImplicitLang = true; |
|
Q_EMIT hasImplicitLangChanged(); |
|
} |
|
endResetModel(); |
|
|
|
// check for invalid lang |
|
if (const QString lang = KCMRegionAndLang::toGlibcLocale(m_selectedLanguages.front()); lang.isEmpty()) { |
|
m_unsupportedLanguage = m_selectedLanguages.front(); |
|
Q_EMIT unsupportedLanguageChanged(); |
|
} else if (!m_unsupportedLanguage.isEmpty()) { |
|
m_unsupportedLanguage.clear(); |
|
Q_EMIT unsupportedLanguageChanged(); |
|
} |
|
} |
|
|
|
SelectedLanguageModel *LanguageListModel::selectedLanguageModel() const |
|
{ |
|
return m_selectedLanguageModel; |
|
} |
|
|
|
int SelectedLanguageModel::rowCount(const QModelIndex &parent) const |
|
{ |
|
Q_UNUSED(parent) |
|
return m_selectedLanguages.size(); |
|
} |
|
|
|
QVariant SelectedLanguageModel::data(const QModelIndex &index, int role) const |
|
{ |
|
Q_UNUSED(role) |
|
const auto row = index.row(); |
|
if (row < 0 || row > m_selectedLanguages.size()) { |
|
return {}; |
|
} |
|
// "add Language" Item |
|
if (row == m_selectedLanguages.size()) { |
|
return {}; |
|
} |
|
|
|
return LanguageListModel::languageCodeToName(m_selectedLanguages.at(row)); |
|
} |
|
|
|
bool SelectedLanguageModel::shouldWarnMultipleLang() const |
|
{ |
|
if (m_selectedLanguages.size() >= 2) { |
|
if (m_selectedLanguages.front() == QStringLiteral("en_US")) { |
|
return true; |
|
} |
|
} |
|
return false; |
|
} |
|
|
|
void SelectedLanguageModel::move(int from, int to) |
|
{ |
|
if (from == to || from < 0 || from >= m_selectedLanguages.size() || to < 0 || to >= m_selectedLanguages.size()) { |
|
return; |
|
} |
|
|
|
if (m_hasImplicitLang) { |
|
m_hasImplicitLang = false; |
|
Q_EMIT hasImplicitLangChanged(); |
|
} |
|
|
|
beginResetModel(); |
|
m_selectedLanguages.move(from, to); |
|
endResetModel(); |
|
saveLanguages(); |
|
Q_EMIT shouldWarnMultipleLangChanged(); |
|
Q_EMIT exampleChanged(); |
|
} |
|
|
|
void SelectedLanguageModel::remove(int index) |
|
{ |
|
if (index < 0 || index >= m_selectedLanguages.size()) { |
|
return; |
|
} |
|
beginRemoveRows(QModelIndex(), index, index); |
|
m_selectedLanguages.removeAt(index); |
|
endRemoveRows(); |
|
saveLanguages(); |
|
Q_EMIT shouldWarnMultipleLangChanged(); |
|
Q_EMIT exampleChanged(); |
|
} |
|
|
|
void SelectedLanguageModel::addLanguage(const QString &lang) |
|
{ |
|
if (lang.isEmpty() || m_selectedLanguages.indexOf(lang) != -1) { |
|
return; |
|
} |
|
|
|
// fix Kirigami.SwipeListItem doesn't connect to Actions' visible property. |
|
// Reset model enforce a refresh of delegate |
|
beginResetModel(); |
|
if (m_hasImplicitLang) { |
|
m_hasImplicitLang = false; |
|
Q_EMIT hasImplicitLangChanged(); |
|
} |
|
m_selectedLanguages.push_back(lang); |
|
endResetModel(); |
|
saveLanguages(); |
|
Q_EMIT shouldWarnMultipleLangChanged(); |
|
Q_EMIT exampleChanged(); |
|
} |
|
|
|
void SelectedLanguageModel::replaceLanguage(int index, const QString &lang) |
|
{ |
|
if (index < 0 || index >= m_selectedLanguages.size() || lang.isEmpty()) { |
|
return; |
|
} |
|
|
|
int existLangIndex = m_selectedLanguages.indexOf(lang); |
|
// return if no change, but allow change implicit lang to explicit |
|
if (existLangIndex == index && !m_hasImplicitLang) { |
|
return; |
|
} |
|
|
|
beginResetModel(); |
|
m_selectedLanguages[index] = lang; |
|
if (!m_hasImplicitLang) { |
|
// delete duplicate lang |
|
if (existLangIndex != -1) { |
|
m_selectedLanguages.removeAt(existLangIndex); |
|
} |
|
} else { |
|
m_hasImplicitLang = false; |
|
Q_EMIT hasImplicitLangChanged(); |
|
} |
|
endResetModel(); |
|
saveLanguages(); |
|
Q_EMIT shouldWarnMultipleLangChanged(); |
|
Q_EMIT exampleChanged(); |
|
} |
|
|
|
void SelectedLanguageModel::saveLanguages() |
|
{ |
|
// implicit lang means no change |
|
if (!m_settings || m_hasImplicitLang) { |
|
return; |
|
} |
|
if (m_selectedLanguages.empty()) { |
|
m_settings->setLang(m_settings->defaultLangValue()); |
|
m_settings->config()->group(QStringLiteral("Formats")).deleteEntry("lang"); |
|
m_settings->config()->group(QStringLiteral("Translations")).deleteEntry("language"); |
|
} else { |
|
QString lang = KCMRegionAndLang::toGlibcLocale(m_selectedLanguages.front()); |
|
if (lang.isEmpty()) { |
|
m_unsupportedLanguage = m_selectedLanguages.front(); |
|
Q_EMIT unsupportedLanguageChanged(); |
|
} else { |
|
if (!m_unsupportedLanguage.isEmpty()) { |
|
m_unsupportedLanguage.clear(); |
|
Q_EMIT unsupportedLanguageChanged(); |
|
} |
|
// don't set LANG in non glibc systems, because in non glibc systems KCMRegionAndLang::toGlibcLocale return the language itself |
|
if (KCMRegionAndLang::isGlibc()) { |
|
m_settings->setLang(lang); |
|
} |
|
} |
|
QString languages; |
|
for (auto i = m_selectedLanguages.cbegin(); i != m_selectedLanguages.cend(); i++) { |
|
languages.push_back(*i); |
|
// no ':' at end |
|
if (i + 1 != m_selectedLanguages.cend()) { |
|
languages.push_back(QLatin1Char(':')); |
|
} |
|
} |
|
m_settings->setLanguage(languages); |
|
} |
|
} |
|
|
|
bool SelectedLanguageModel::hasImplicitLang() const |
|
{ |
|
return m_hasImplicitLang; |
|
} |
|
|
|
const QString &SelectedLanguageModel::unsupportedLanguage() const |
|
{ |
|
return m_unsupportedLanguage; |
|
} |
|
|
|
QString SelectedLanguageModel::envLang() const |
|
{ |
|
return qEnvironmentVariable("LANG"); |
|
} |
|
|
|
QString SelectedLanguageModel::envLanguage() const |
|
{ |
|
return qEnvironmentVariable("LANGUAGE"); |
|
}
|
|
|