File indexing completed on 2024-10-06 12:16:52
0001 /* 0002 SPDX-FileCopyrightText: 1999-2003 Hans Petter Bieker <bieker@kde.org> 0003 SPDX-FileCopyrightText: 2007 David Jarvie <djarvie@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "klanguagebutton.h" 0009 0010 #include <QDir> 0011 #include <QFile> 0012 #include <QHBoxLayout> 0013 #include <QLocale> 0014 #include <QMenu> 0015 #include <QPushButton> 0016 0017 #include <KConfig> 0018 #include <KConfigGroup> 0019 0020 static void checkInsertPos(QMenu *popup, const QString &str, int &index) 0021 { 0022 if (index != -1) { 0023 return; 0024 } 0025 0026 int a = 0; 0027 const QList<QAction *> actions = popup->actions(); 0028 int b = actions.count(); 0029 0030 while (a < b) { 0031 int w = (a + b) / 2; 0032 QAction *ac = actions[w]; 0033 int j = str.localeAwareCompare(ac->text()); 0034 if (j > 0) { 0035 a = w + 1; 0036 } else { 0037 b = w; 0038 } 0039 } 0040 0041 index = a; // it doesn't really matter ... a == b here. 0042 0043 Q_ASSERT(a == b); 0044 } 0045 0046 class KLanguageButtonPrivate 0047 { 0048 public: 0049 explicit KLanguageButtonPrivate(KLanguageButton *parent); 0050 ~KLanguageButtonPrivate() 0051 { 0052 delete button; 0053 delete popup; 0054 } 0055 void setCurrentItem(QAction *); 0056 void clear(); 0057 QAction *findAction(const QString &data) const; 0058 0059 QPushButton *button = nullptr; 0060 QStringList ids; 0061 QMenu *popup = nullptr; 0062 QString current; 0063 QString locale; 0064 bool staticText : 1; 0065 bool showCodes : 1; 0066 }; 0067 0068 KLanguageButton::KLanguageButton(QWidget *parent) 0069 : QWidget(parent) 0070 , d(new KLanguageButtonPrivate(this)) 0071 { 0072 } 0073 0074 KLanguageButton::KLanguageButton(const QString &text, QWidget *parent) 0075 : QWidget(parent) 0076 , d(new KLanguageButtonPrivate(this)) 0077 { 0078 setText(text); 0079 } 0080 0081 KLanguageButtonPrivate::KLanguageButtonPrivate(KLanguageButton *parent) 0082 : button(new QPushButton(parent)) 0083 , popup(new QMenu(parent)) 0084 , locale(QLocale::system().name()) 0085 , staticText(false) 0086 , showCodes(false) 0087 { 0088 QHBoxLayout *layout = new QHBoxLayout(parent); 0089 layout->setContentsMargins(0, 0, 0, 0); 0090 layout->addWidget(button); 0091 0092 parent->setFocusProxy(button); 0093 parent->setFocusPolicy(button->focusPolicy()); 0094 0095 button->setMenu(popup); 0096 0097 QObject::connect(popup, &QMenu::triggered, parent, &KLanguageButton::slotTriggered); 0098 QObject::connect(popup, &QMenu::hovered, parent, &KLanguageButton::slotHovered); 0099 } 0100 0101 KLanguageButton::~KLanguageButton() = default; 0102 0103 void KLanguageButton::setText(const QString &text) 0104 { 0105 d->staticText = true; 0106 d->button->setText(text); 0107 } 0108 0109 void KLanguageButton::setLocale(const QString &locale) 0110 { 0111 d->locale = locale; 0112 } 0113 0114 void KLanguageButton::showLanguageCodes(bool show) 0115 { 0116 d->showCodes = show; 0117 } 0118 0119 static QString nameFromEntryFile(const QString &entryFile) 0120 { 0121 const KConfig entry(entryFile, KConfig::SimpleConfig); 0122 const KConfigGroup group(&entry, "KCM Locale"); 0123 return group.readEntry("Name", QString()); 0124 } 0125 0126 void KLanguageButton::insertLanguage(const QString &languageCode, const QString &name, int index) 0127 { 0128 QString text; 0129 bool showCodes = d->showCodes; 0130 if (name.isEmpty()) { 0131 const QString entryFile = 0132 QStandardPaths::locate(QStandardPaths::GenericDataLocation, QLatin1String("locale/") + languageCode + QLatin1String("/kf5_entry.desktop")); 0133 if (QFile::exists(entryFile)) { 0134 text = nameFromEntryFile(entryFile); 0135 } 0136 0137 if (text.isEmpty()) { 0138 text = languageCode; 0139 QLocale locale(languageCode); 0140 if (locale != QLocale::c()) { 0141 text = locale.nativeLanguageName(); 0142 // For some languages the native name might be empty. 0143 // In this case use the non native language name as fallback. 0144 // See: QTBUG-51323 0145 text = text.isEmpty() ? QLocale::languageToString(locale.language()) : text; 0146 } else { 0147 showCodes = false; 0148 } 0149 } 0150 } else { 0151 text = name; 0152 } 0153 if (showCodes) { 0154 text += QLatin1String(" (") + languageCode + QLatin1Char(')'); 0155 } 0156 0157 checkInsertPos(d->popup, text, index); 0158 QAction *a = new QAction(QIcon(), text, this); 0159 a->setData(languageCode); 0160 if (index >= 0 && index < d->popup->actions().count() - 1) { 0161 d->popup->insertAction(d->popup->actions()[index], a); 0162 } else { 0163 d->popup->addAction(a); 0164 } 0165 d->ids.append(languageCode); 0166 } 0167 0168 void KLanguageButton::insertSeparator(int index) 0169 { 0170 if (index >= 0 && index < d->popup->actions().count() - 1) { 0171 d->popup->insertSeparator(d->popup->actions()[index]); 0172 } else { 0173 d->popup->addSeparator(); 0174 } 0175 } 0176 0177 void KLanguageButton::loadAllLanguages() 0178 { 0179 const QStringList localeDirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("locale"), QStandardPaths::LocateDirectory); 0180 for (const QString &localeDir : localeDirs) { 0181 const QStringList entries = QDir(localeDir).entryList(QDir::Dirs, QDir::Name); 0182 for (const QString &d : entries) { 0183 const QString entryFile = localeDir + QLatin1Char('/') + d + QStringLiteral("/kf5_entry.desktop"); 0184 if (QFile::exists(entryFile)) { 0185 insertLanguage(d); 0186 } 0187 } 0188 } 0189 0190 d->ids.removeDuplicates(); 0191 setCurrentItem(d->locale); 0192 } 0193 0194 void KLanguageButton::slotTriggered(QAction *a) 0195 { 0196 // qCDebug(KCONFIG_WIDGETS_LOG) << "slotTriggered" << index; 0197 if (!a) { 0198 return; 0199 } 0200 0201 d->setCurrentItem(a); 0202 0203 // Forward event from popup menu as if it was emitted from this widget: 0204 Q_EMIT activated(d->current); 0205 } 0206 0207 void KLanguageButton::slotHovered(QAction *a) 0208 { 0209 // qCDebug(KCONFIG_WIDGETS_LOG) << "slotHovered" << index; 0210 0211 Q_EMIT highlighted(a->data().toString()); 0212 } 0213 0214 int KLanguageButton::count() const 0215 { 0216 return d->ids.count(); 0217 } 0218 0219 void KLanguageButton::clear() 0220 { 0221 d->clear(); 0222 } 0223 0224 void KLanguageButtonPrivate::clear() 0225 { 0226 ids.clear(); 0227 popup->clear(); 0228 0229 if (!staticText) { 0230 button->setText(QString()); 0231 } 0232 } 0233 0234 bool KLanguageButton::contains(const QString &languageCode) const 0235 { 0236 return d->ids.contains(languageCode); 0237 } 0238 0239 QString KLanguageButton::current() const 0240 { 0241 return d->current.isEmpty() ? QStringLiteral("en") : d->current; 0242 } 0243 0244 QAction *KLanguageButtonPrivate::findAction(const QString &data) const 0245 { 0246 const auto listActions = popup->actions(); 0247 for (QAction *a : listActions) { 0248 if (!a->data().toString().compare(data)) { 0249 return a; 0250 } 0251 } 0252 return nullptr; 0253 } 0254 0255 void KLanguageButton::setCurrentItem(const QString &languageCode) 0256 { 0257 if (d->ids.isEmpty()) { 0258 return; 0259 } 0260 QAction *a; 0261 if (d->ids.indexOf(languageCode) < 0) { 0262 a = d->findAction(d->ids[0]); 0263 } else { 0264 a = d->findAction(languageCode); 0265 } 0266 if (a) { 0267 d->setCurrentItem(a); 0268 } 0269 } 0270 0271 void KLanguageButtonPrivate::setCurrentItem(QAction *a) 0272 { 0273 if (!a->data().isValid()) { 0274 return; 0275 } 0276 current = a->data().toString(); 0277 0278 if (!staticText) { 0279 button->setText(a->text()); 0280 } 0281 } 0282 0283 #include "moc_klanguagebutton.cpp"