mirror of
https://invent.kde.org/marcoa/shift-shell.git
synced 2026-04-26 14:23:09 +00:00
kcms: Move KCMs from plasma-settings
Having the KCMs that are mobile specific here makes more sense than in the settings application. Historically plasma-settings had a faster release cycle than Plasma, but the application is now moving to the Plasma release schedule and so it makes sense do this now.
This commit is contained in:
parent
c3882691bc
commit
e147f98aea
78 changed files with 9745 additions and 1 deletions
|
|
@ -67,8 +67,13 @@ find_package(KF6 ${KF6_MIN_VERSION} REQUIRED COMPONENTS
|
|||
Declarative
|
||||
Package
|
||||
)
|
||||
find_package(KF6KirigamiAddons 0.6 REQUIRED)
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
|
||||
pkg_check_modules(GOBJECT gobject-2.0 REQUIRED IMPORTED_TARGET)
|
||||
pkg_check_modules(GIO gio-2.0 REQUIRED IMPORTED_TARGET)
|
||||
|
||||
find_package(KF6KirigamiAddons 0.6 REQUIRED)
|
||||
find_package(LibKWorkspace CONFIG REQUIRED)
|
||||
|
||||
find_package(KWinDBusInterface)
|
||||
|
|
|
|||
|
|
@ -2,3 +2,8 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
add_subdirectory(mobileshell)
|
||||
add_subdirectory(cellularnetwork)
|
||||
add_subdirectory(info)
|
||||
add_subdirectory(powermanagement)
|
||||
add_subdirectory(time)
|
||||
add_subdirectory(virtualkeyboard)
|
||||
|
|
|
|||
26
kcms/cellularnetwork/CMakeLists.txt
Normal file
26
kcms/cellularnetwork/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
set (cellularnetworksettings_SRCS
|
||||
cellularnetworksettings.cpp
|
||||
modem.cpp
|
||||
modemdetails.cpp
|
||||
sim.cpp
|
||||
mobileproviders.cpp
|
||||
profilesettings.cpp
|
||||
)
|
||||
|
||||
add_library(kcm_cellular_network MODULE ${cellularnetworksettings_SRCS})
|
||||
|
||||
target_link_libraries(kcm_cellular_network
|
||||
Qt::DBus
|
||||
Qt::Gui
|
||||
Qt::Quick
|
||||
Qt::Qml
|
||||
Qt::Xml
|
||||
KF6::Plasma
|
||||
KF6::I18n
|
||||
KF6::NetworkManagerQt
|
||||
KF6::ModemManagerQt
|
||||
KF6::QuickAddons
|
||||
)
|
||||
|
||||
install(TARGETS kcm_cellular_network DESTINATION ${KDE_INSTALL_PLUGINDIR}/kcms)
|
||||
kpackage_install_package(package kcm_cellular_network kcms)
|
||||
2
kcms/cellularnetwork/Messages.sh
Normal file
2
kcms/cellularnetwork/Messages.sh
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
#!/usr/bin/env bash
|
||||
$XGETTEXT `find . -name \*.cpp -o -name \*.qml` -o $podir/kcm_cellular_network.pot
|
||||
157
kcms/cellularnetwork/cellularnetworksettings.cpp
Normal file
157
kcms/cellularnetwork/cellularnetworksettings.cpp
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2018 Martin Kacej <m.kacej@atlas.sk>
|
||||
SPDX-FileCopyrightText: 2020-2021 Devin Lin <espidev@gmail.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "cellularnetworksettings.h"
|
||||
|
||||
#include <KLocalizedString>
|
||||
#include <KPluginFactory>
|
||||
#include <KUser>
|
||||
|
||||
#include <QQmlEngine>
|
||||
|
||||
K_PLUGIN_CLASS_WITH_JSON(CellularNetworkSettings, "cellularnetworksettings.json")
|
||||
|
||||
CellularNetworkSettings *CellularNetworkSettings::staticInst = nullptr;
|
||||
|
||||
CellularNetworkSettings::CellularNetworkSettings(QObject *parent, const KPluginMetaData &metaData, const QVariantList &args)
|
||||
: KQuickAddons::ConfigModule(parent, metaData, args)
|
||||
, m_modemList{}
|
||||
, m_simList{}
|
||||
{
|
||||
CellularNetworkSettings::staticInst = this;
|
||||
|
||||
qmlRegisterType<ProfileSettings>("cellularnetworkkcm", 1, 0, "ProfileSettings");
|
||||
qmlRegisterType<Modem>("cellularnetworkkcm", 1, 0, "Modem");
|
||||
qmlRegisterType<ModemDetails>("cellularnetworkkcm", 1, 0, "ModemDetails");
|
||||
qmlRegisterType<AvailableNetwork>("cellularnetworkkcm", 1, 0, "AvailableNetwork");
|
||||
qmlRegisterType<Sim>("cellularnetworkkcm", 1, 0, "Sim");
|
||||
qmlRegisterType<InlineMessage>("cellularnetworkkcm", 1, 0, "InlineMessage");
|
||||
|
||||
// find modems
|
||||
updateModemList();
|
||||
|
||||
connect(ModemManager::notifier(), &ModemManager::Notifier::modemAdded, this, &CellularNetworkSettings::updateModemList);
|
||||
connect(ModemManager::notifier(), &ModemManager::Notifier::modemRemoved, this, &CellularNetworkSettings::updateModemList);
|
||||
}
|
||||
|
||||
CellularNetworkSettings *CellularNetworkSettings::instance()
|
||||
{
|
||||
return CellularNetworkSettings::staticInst;
|
||||
}
|
||||
|
||||
Modem *CellularNetworkSettings::selectedModem()
|
||||
{
|
||||
// TODO: we are currently assuming there is a single modem
|
||||
if (m_modemList.count() > 0) {
|
||||
return m_modemList[0];
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QList<Modem *> CellularNetworkSettings::modems()
|
||||
{
|
||||
return m_modemList;
|
||||
}
|
||||
|
||||
QList<Sim *> CellularNetworkSettings::sims()
|
||||
{
|
||||
return m_simList;
|
||||
}
|
||||
|
||||
bool CellularNetworkSettings::modemFound()
|
||||
{
|
||||
return !m_modemList.empty();
|
||||
}
|
||||
|
||||
void CellularNetworkSettings::updateModemList()
|
||||
{
|
||||
// find modems
|
||||
ModemManager::scanDevices();
|
||||
|
||||
qDebug() << QStringLiteral("Scanning for modems...");
|
||||
|
||||
// loop over every modem
|
||||
for (ModemManager::ModemDevice::Ptr device : ModemManager::modemDevices()) {
|
||||
ModemManager::Modem::Ptr modem = device->modemInterface();
|
||||
|
||||
qDebug() << QStringLiteral("Found modem:") << device->uni();
|
||||
|
||||
m_modemList.push_back(new Modem(this, device, modem));
|
||||
|
||||
// update sims list if modem's list changes
|
||||
connect(m_modemList[m_modemList.size() - 1], &Modem::simsChanged, this, [this]() -> void {
|
||||
fillSims();
|
||||
});
|
||||
}
|
||||
|
||||
if (m_modemList.empty()) {
|
||||
qDebug() << QStringLiteral("No modems found.");
|
||||
}
|
||||
|
||||
// fill sim list
|
||||
fillSims();
|
||||
|
||||
// update the currently selected modem
|
||||
Q_EMIT selectedModemChanged();
|
||||
}
|
||||
|
||||
void CellularNetworkSettings::fillSims()
|
||||
{
|
||||
for (auto p : m_simList) {
|
||||
delete p;
|
||||
}
|
||||
m_simList.clear();
|
||||
|
||||
qDebug() << QStringLiteral("Scanning SIMs list...");
|
||||
for (auto modem : m_modemList) {
|
||||
auto sims = modem->sims();
|
||||
for (auto sim : sims) {
|
||||
qDebug() << QStringLiteral("Found SIM") << sim->uni() << sim->imsi();
|
||||
m_simList.push_back(sim);
|
||||
}
|
||||
}
|
||||
|
||||
Q_EMIT simsChanged();
|
||||
}
|
||||
|
||||
QList<InlineMessage *> CellularNetworkSettings::messages()
|
||||
{
|
||||
return m_messages;
|
||||
}
|
||||
|
||||
void CellularNetworkSettings::addMessage(InlineMessage::Type type, QString msg)
|
||||
{
|
||||
m_messages.push_back(new InlineMessage{this, type, msg});
|
||||
Q_EMIT messagesChanged();
|
||||
}
|
||||
|
||||
void CellularNetworkSettings::removeMessage(int index)
|
||||
{
|
||||
if (index >= 0 && index < m_messages.size()) {
|
||||
m_messages.removeAt(index);
|
||||
Q_EMIT messagesChanged();
|
||||
}
|
||||
}
|
||||
|
||||
InlineMessage::InlineMessage(QObject *parent, Type type, QString message)
|
||||
: QObject{parent}
|
||||
, m_type{type}
|
||||
, m_message{message}
|
||||
{
|
||||
}
|
||||
|
||||
InlineMessage::Type InlineMessage::type()
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
|
||||
QString InlineMessage::message()
|
||||
{
|
||||
return m_message;
|
||||
}
|
||||
|
||||
#include "cellularnetworksettings.moc"
|
||||
101
kcms/cellularnetwork/cellularnetworksettings.h
Normal file
101
kcms/cellularnetwork/cellularnetworksettings.h
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2018 Martin Kacej <m.kacej@atlas.sk>
|
||||
SPDX-FileCopyrightText: 2020-2021 Devin Lin <espidev@gmail.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QSharedPointer>
|
||||
|
||||
#include <KQuickAddons/ConfigModule>
|
||||
|
||||
#include "mobileproviders.h"
|
||||
#include "modem.h"
|
||||
#include "modemdetails.h"
|
||||
#include "sim.h"
|
||||
|
||||
#include <NetworkManagerQt/CdmaSetting>
|
||||
#include <NetworkManagerQt/ConnectionSettings>
|
||||
#include <NetworkManagerQt/GsmSetting>
|
||||
#include <NetworkManagerQt/Manager>
|
||||
#include <NetworkManagerQt/ModemDevice>
|
||||
#include <NetworkManagerQt/Settings>
|
||||
|
||||
#include <ModemManagerQt/GenericTypes>
|
||||
#include <ModemManagerQt/Manager>
|
||||
#include <ModemManagerQt/ModemDevice>
|
||||
|
||||
class Sim;
|
||||
class Modem;
|
||||
class MobileProviders;
|
||||
|
||||
class InlineMessage : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int type READ type NOTIFY typeChanged)
|
||||
Q_PROPERTY(QString message READ message NOTIFY messageChanged)
|
||||
|
||||
public:
|
||||
enum Type {
|
||||
Information,
|
||||
Positive,
|
||||
Warning,
|
||||
Error,
|
||||
};
|
||||
|
||||
InlineMessage(QObject *parent = nullptr, Type type = Information, QString message = "");
|
||||
|
||||
Type type();
|
||||
QString message();
|
||||
|
||||
Q_SIGNALS:
|
||||
void typeChanged();
|
||||
void messageChanged();
|
||||
|
||||
private:
|
||||
Type m_type;
|
||||
QString m_message;
|
||||
};
|
||||
|
||||
class CellularNetworkSettings : public KQuickAddons::ConfigModule
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool modemFound READ modemFound NOTIFY modemFoundChanged)
|
||||
Q_PROPERTY(Modem *selectedModem READ selectedModem NOTIFY selectedModemChanged)
|
||||
Q_PROPERTY(QList<Sim *> sims READ sims NOTIFY simsChanged)
|
||||
Q_PROPERTY(QList<InlineMessage *> messages READ messages NOTIFY messagesChanged)
|
||||
|
||||
public:
|
||||
CellularNetworkSettings(QObject *parent, const KPluginMetaData &metaData, const QVariantList &args);
|
||||
|
||||
static CellularNetworkSettings *instance();
|
||||
|
||||
Modem *selectedModem();
|
||||
QList<Modem *> modems();
|
||||
QList<Sim *> sims();
|
||||
|
||||
bool modemFound();
|
||||
|
||||
QList<InlineMessage *> messages();
|
||||
void addMessage(InlineMessage::Type type, QString msg);
|
||||
Q_INVOKABLE void removeMessage(int index);
|
||||
|
||||
Q_SIGNALS:
|
||||
void modemFoundChanged();
|
||||
void selectedModemChanged();
|
||||
void simsChanged();
|
||||
void messagesChanged();
|
||||
|
||||
private:
|
||||
void updateModemList();
|
||||
void fillSims();
|
||||
|
||||
QList<Modem *> m_modemList;
|
||||
QList<Sim *> m_simList;
|
||||
|
||||
QList<InlineMessage *> m_messages;
|
||||
|
||||
static CellularNetworkSettings *staticInst;
|
||||
};
|
||||
114
kcms/cellularnetwork/cellularnetworksettings.json
Normal file
114
kcms/cellularnetwork/cellularnetworksettings.json
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
{
|
||||
"Categories": "Qt;KDE;X-KDE-settings-system;",
|
||||
"KPlugin": {
|
||||
"Description": "Management of cellular networks",
|
||||
"Description[az]": "Mobil şəbəkələr idarəetməsi",
|
||||
"Description[ca@valencia]": "Gestió de xarxes de telefonia mòbil",
|
||||
"Description[ca]": "Gestió de xarxes de telefonia mòbil",
|
||||
"Description[cs]": "Spravovat vaše mobilní sítě",
|
||||
"Description[de]": "Verwaltung von Mobilfunknetzen",
|
||||
"Description[en_GB]": "Management of cellular networks",
|
||||
"Description[es]": "Gestión de redes móviles",
|
||||
"Description[eu]": "Mugikor-sareen kudeaketa",
|
||||
"Description[fi]": "Matkapuhelinverkkojen hallinta",
|
||||
"Description[fr]": "Gestion de réseaux cellulaires",
|
||||
"Description[hu]": "Mobilhálózatok kezelése",
|
||||
"Description[ia]": "Gestion de retes cellular",
|
||||
"Description[id]": "Pengelolaan jaringan seluler",
|
||||
"Description[is]": "Umsjón farsímaneta",
|
||||
"Description[it]": "Gestione delle reti cellulari",
|
||||
"Description[ka]": "ფიჭური ქსელების მართვა",
|
||||
"Description[ko]": "모바일 네트워크 관리",
|
||||
"Description[lt]": "Korinių tinklų tvarkymas",
|
||||
"Description[nl]": "Beheer van cellulaire netwerken",
|
||||
"Description[nn]": "Handsaming av mobilnettverk",
|
||||
"Description[pa]": "ਸੈਲੂਲਰ ਨੈੱਟਵਰਕਾਂ ਦਾ ਇੰਤਜ਼ਾਮ ਕਰੋ",
|
||||
"Description[pl]": "Zarządzanie sieciami komórkowymi",
|
||||
"Description[pt]": "Gestão de redes móveis",
|
||||
"Description[pt_BR]": "Gerenciamento de redes celulares",
|
||||
"Description[ro]": "Gestiunea rețelelor celulare",
|
||||
"Description[ru]": "Управление сотовыми сетями",
|
||||
"Description[sl]": "Upravljanje mobilnih omrežij",
|
||||
"Description[sv]": "Hantering av mobilnät",
|
||||
"Description[tr]": "Hücresel ağların yönetimi",
|
||||
"Description[uk]": "Керування стільниковими мережами",
|
||||
"Description[vi]": "Quản lí các mạng di dộng",
|
||||
"Description[x-test]": "xxManagement of cellular networksxx",
|
||||
"Description[zh_CN]": "管理移动网络",
|
||||
"Description[zh_TW]": "行動網路管理",
|
||||
"FormFactors": [
|
||||
"handset",
|
||||
"tablet",
|
||||
"mediacenter"
|
||||
],
|
||||
"Icon": "smartphone",
|
||||
"Name": "Cellular Network",
|
||||
"Name[az]": "Mobil Şəbəkə",
|
||||
"Name[ca@valencia]": "Xarxa de telefonia mòbil",
|
||||
"Name[ca]": "Xarxa de telefonia mòbil",
|
||||
"Name[cs]": "Mobilní síť",
|
||||
"Name[de]": "Mobilfunknetz",
|
||||
"Name[en_GB]": "Cellular Network",
|
||||
"Name[es]": "Red móvil",
|
||||
"Name[eu]": "Mugikorrerako sareak",
|
||||
"Name[fi]": "Matkapuhelinverkko",
|
||||
"Name[fr]": "Réseau cellulaire",
|
||||
"Name[hu]": "Mobilhálózatok",
|
||||
"Name[ia]": "Rete Cellular",
|
||||
"Name[id]": "Jaringan Seluler",
|
||||
"Name[is]": "Farsímakerfi",
|
||||
"Name[it]": "Rete cellulare",
|
||||
"Name[ka]": "ფიჭური ქსელი",
|
||||
"Name[ko]": "모바일 네트워크",
|
||||
"Name[lt]": "Korinis tinklas",
|
||||
"Name[nl]": "Cellulair netwerk",
|
||||
"Name[nn]": "Mobilnettverk",
|
||||
"Name[pa]": "ਸੈਲੂਲਰ ਨੈੱਟਵਰਕ",
|
||||
"Name[pl]": "Sieci komórkowe",
|
||||
"Name[pt]": "Rede Móvel",
|
||||
"Name[pt_BR]": "Rede celular",
|
||||
"Name[ro]": "Rețea celulară",
|
||||
"Name[ru]": "Сотовая сеть",
|
||||
"Name[sk]": "Mobilná sieť",
|
||||
"Name[sl]": "Mobilno omrežje",
|
||||
"Name[sv]": "Mobilnät",
|
||||
"Name[tr]": "Hücresel Ağ",
|
||||
"Name[uk]": "Стільникова мережа",
|
||||
"Name[vi]": "Mạng di động",
|
||||
"Name[x-test]": "xxCellular Networkxx",
|
||||
"Name[zh_CN]": "移动网络",
|
||||
"Name[zh_TW]": "行動網路"
|
||||
},
|
||||
"X-KDE-Keywords": "mobile,data,network",
|
||||
"X-KDE-Keywords[az]": "mobile,data,network,verilənlər,şəbəkə,mobil",
|
||||
"X-KDE-Keywords[ca@valencia]": "mòbil,dades,xarxa",
|
||||
"X-KDE-Keywords[ca]": "mòbil,dades,xarxa",
|
||||
"X-KDE-Keywords[cs]": "mobilní,data,síť",
|
||||
"X-KDE-Keywords[de]": "mobil,daten,netzwerk,Mobiltelefon",
|
||||
"X-KDE-Keywords[en_GB]": "mobile,data,network",
|
||||
"X-KDE-Keywords[es]": "móvil,datos,red",
|
||||
"X-KDE-Keywords[eu]": "mugikorra,datuak,sarea",
|
||||
"X-KDE-Keywords[fi]": "mobiili,data,verkko",
|
||||
"X-KDE-Keywords[fr]": "mobile, donnée, réseau",
|
||||
"X-KDE-Keywords[hu]": "mobil,adat,hálózat",
|
||||
"X-KDE-Keywords[ia]": "mobile,data,network",
|
||||
"X-KDE-Keywords[it]": "mobile,dati,rete",
|
||||
"X-KDE-Keywords[ko]": "mobile,data,network,모바일,데이터,네트워크",
|
||||
"X-KDE-Keywords[lt]": "mobilusis,mobilieji,duomenys,tinklas",
|
||||
"X-KDE-Keywords[nl]": "mobiel,gegevens,netwerk",
|
||||
"X-KDE-Keywords[nn]": "mobil,mobilt,data,nettverk",
|
||||
"X-KDE-Keywords[pa]": "ਮੋਬਾਈਲ,ਡਾਟਾ,ਨੈੱਟਵਰਕ",
|
||||
"X-KDE-Keywords[pl]": "mobilne,komórkowe,przenośne,dane,sieć",
|
||||
"X-KDE-Keywords[pt]": "móvel,dados,rede",
|
||||
"X-KDE-Keywords[pt_BR]": "móvel,dados,rede",
|
||||
"X-KDE-Keywords[ru]": "mobile,data,network,мобильная сеть,данные,сеть",
|
||||
"X-KDE-Keywords[sk]": "mobilné,dáta,sieť",
|
||||
"X-KDE-Keywords[sl]": "mobilno,podatki,omrežje",
|
||||
"X-KDE-Keywords[sv]": "mobil,data,nätverk",
|
||||
"X-KDE-Keywords[uk]": "mobile,data,network,мобільний,дані,мережа",
|
||||
"X-KDE-Keywords[vi]": "mobile,data,network,di động,dữ liệu,mạng",
|
||||
"X-KDE-Keywords[x-test]": "xxmobilexx,xxdataxx,xxnetworkxx",
|
||||
"X-KDE-Keywords[zh_CN]": "mobile,data,network,移动,数据,网络,蜂窝,手机",
|
||||
"X-KDE-System-Settings-Parent-Category": "network",
|
||||
"X-KDE-Weight": 70
|
||||
}
|
||||
336
kcms/cellularnetwork/mobileproviders.cpp
Normal file
336
kcms/cellularnetwork/mobileproviders.cpp
Normal file
|
|
@ -0,0 +1,336 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2010-2012 Lamarque Souza <lamarque@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
*/
|
||||
|
||||
#include "mobileproviders.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
#include <QLocale>
|
||||
#include <QRegularExpression>
|
||||
#include <QTextStream>
|
||||
|
||||
const QString MobileProviders::ProvidersFile = QStringLiteral("/usr/share/mobile-broadband-provider-info/serviceproviders.xml");
|
||||
|
||||
// adapted from https://invent.kde.org/plasma/plasma-nm/-/blob/master/libs/editor/mobileproviders.cpp
|
||||
// we only use gsm, ignore cdma
|
||||
|
||||
bool localeAwareCompare(const QString &one, const QString &two)
|
||||
{
|
||||
return one.localeAwareCompare(two) < 0;
|
||||
}
|
||||
|
||||
MobileProviders::MobileProviders()
|
||||
{
|
||||
for (int c = 1; c <= QLocale::LastCountry; c++) {
|
||||
const auto country = static_cast<QLocale::Country>(c);
|
||||
QLocale locale(QLocale::AnyLanguage, country);
|
||||
if (locale.country() == country) {
|
||||
const QString localeName = locale.name();
|
||||
const auto idx = localeName.indexOf(QLatin1Char('_'));
|
||||
if (idx != -1) {
|
||||
const QString countryCode = localeName.mid(idx + 1);
|
||||
QString countryName = locale.nativeCountryName();
|
||||
if (countryName.isEmpty()) {
|
||||
countryName = QLocale::countryToString(country);
|
||||
}
|
||||
mCountries.insert(countryCode, countryName);
|
||||
}
|
||||
}
|
||||
}
|
||||
mError = Success;
|
||||
|
||||
QFile file2(ProvidersFile);
|
||||
|
||||
if (file2.open(QIODevice::ReadOnly)) {
|
||||
if (mDocProviders.setContent(&file2)) {
|
||||
docElement = mDocProviders.documentElement();
|
||||
|
||||
if (docElement.isNull()) {
|
||||
qWarning() << ProvidersFile << ": document is null";
|
||||
mError = ProvidersIsNull;
|
||||
} else {
|
||||
if (docElement.isNull() || docElement.tagName() != "serviceproviders") {
|
||||
qWarning() << ProvidersFile << ": wrong format";
|
||||
mError = ProvidersWrongFormat;
|
||||
} else {
|
||||
if (docElement.attribute("format") != "2.0") {
|
||||
qWarning() << ProvidersFile << ": mobile broadband provider database format '" << docElement.attribute("format") << "' not supported.";
|
||||
mError = ProvidersFormatNotSupported;
|
||||
} else {
|
||||
// qCDebug(PLASMA_NM) << "Everything is alright so far";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
file2.close();
|
||||
} else {
|
||||
qWarning() << "Error opening providers file" << ProvidersFile;
|
||||
mError = ProvidersMissing;
|
||||
}
|
||||
}
|
||||
|
||||
MobileProviders::~MobileProviders()
|
||||
{
|
||||
}
|
||||
|
||||
QStringList MobileProviders::getCountryList() const
|
||||
{
|
||||
QStringList temp = mCountries.values();
|
||||
std::sort(temp.begin(), temp.end(), localeAwareCompare);
|
||||
return temp;
|
||||
}
|
||||
|
||||
QString MobileProviders::countryFromLocale() const
|
||||
{
|
||||
const QString localeName = QLocale().name();
|
||||
const auto idx = localeName.indexOf(QLatin1Char('_'));
|
||||
if (idx != -1) {
|
||||
return localeName.mid(idx + 1);
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
QStringList MobileProviders::getApns(const QString &provider)
|
||||
{
|
||||
mApns.clear();
|
||||
mNetworkIds.clear();
|
||||
if (!mProvidersGsm.contains(provider)) {
|
||||
return QStringList();
|
||||
}
|
||||
|
||||
QDomNode n = mProvidersGsm[provider];
|
||||
|
||||
while (!n.isNull()) {
|
||||
QDomElement e = n.toElement(); // <gsm | cdma>
|
||||
|
||||
if (!e.isNull() && e.tagName().toLower() == "gsm") {
|
||||
QDomNode n2 = e.firstChild();
|
||||
while (!n2.isNull()) {
|
||||
QDomElement e2 = n2.toElement(); // <apn | network-id>
|
||||
|
||||
if (!e2.isNull() && e2.tagName().toLower() == "apn") {
|
||||
bool isInternet = true;
|
||||
QDomNode n3 = e2.firstChild();
|
||||
while (!n3.isNull()) {
|
||||
QDomElement e3 = n3.toElement(); // <usage>
|
||||
if (!e3.isNull() && e3.tagName().toLower() == "usage" && !e3.attribute("type").isNull()
|
||||
&& e3.attribute("type").toLower() != "internet") {
|
||||
// qCDebug(PLASMA_NM) << "apn" << e2.attribute("value") << "ignored because of usage" << e3.attribute("type");
|
||||
isInternet = false;
|
||||
break;
|
||||
}
|
||||
n3 = n3.nextSibling();
|
||||
}
|
||||
if (isInternet) {
|
||||
mApns.insert(e2.attribute("value"), e2.firstChild());
|
||||
}
|
||||
} else if (!e2.isNull() && e2.tagName().toLower() == "network-id") {
|
||||
mNetworkIds.append(e2.attribute("mcc") + '-' + e2.attribute("mnc"));
|
||||
}
|
||||
|
||||
n2 = n2.nextSibling();
|
||||
}
|
||||
}
|
||||
n = n.nextSibling();
|
||||
}
|
||||
|
||||
QStringList temp = mApns.keys();
|
||||
temp.sort();
|
||||
return temp;
|
||||
}
|
||||
|
||||
ProviderData MobileProviders::parseProvider(const QDomNode &providerNode)
|
||||
{
|
||||
ProviderData result;
|
||||
|
||||
QMap<QString, QString> localizedProviderNames;
|
||||
|
||||
QDomNode c = providerNode.firstChild(); // <name | gsm | cdma>
|
||||
bool hasGsm = false;
|
||||
|
||||
while (!c.isNull()) {
|
||||
QDomElement ce = c.toElement();
|
||||
|
||||
if (ce.tagName().toLower() == QLatin1String("gsm")) {
|
||||
QDomNode gsmNode = c.firstChild();
|
||||
|
||||
while (!gsmNode.isNull()) {
|
||||
QDomElement gsmElement = gsmNode.toElement();
|
||||
|
||||
if (gsmElement.tagName().toLower() == QLatin1String("network-id")) {
|
||||
result.mccmncs.append(gsmElement.attribute("mcc") + gsmElement.attribute("mnc"));
|
||||
}
|
||||
gsmNode = gsmNode.nextSibling();
|
||||
}
|
||||
|
||||
hasGsm = true;
|
||||
} else if (ce.tagName().toLower() == QLatin1String("name")) {
|
||||
QString lang = ce.attribute("xml:lang");
|
||||
if (lang.isEmpty()) {
|
||||
lang = "en"; // English is default
|
||||
} else {
|
||||
lang = lang.toLower();
|
||||
lang.remove(QRegularExpression(QStringLiteral("\\-.*$"))); // Remove everything after '-' in xml:lang attribute.
|
||||
}
|
||||
localizedProviderNames.insert(lang, ce.text());
|
||||
}
|
||||
|
||||
c = c.nextSibling();
|
||||
}
|
||||
|
||||
result.name = getNameByLocale(localizedProviderNames);
|
||||
|
||||
const QString name = result.name;
|
||||
if (hasGsm) {
|
||||
mProvidersGsm.insert(name, providerNode.firstChild());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QStringList MobileProviders::getProvidersFromMCCMNC(const QString &targetMccMnc)
|
||||
{
|
||||
QStringList result;
|
||||
|
||||
QDomNode n = docElement.firstChild();
|
||||
|
||||
while (!n.isNull()) {
|
||||
QDomElement e = n.toElement(); // <country ...>
|
||||
|
||||
if (!e.isNull()) {
|
||||
QDomNode n2 = e.firstChild();
|
||||
while (!n2.isNull()) {
|
||||
QDomElement e2 = n2.toElement(); // <provider ...>
|
||||
|
||||
if (!e2.isNull() && e2.tagName().toLower() == "provider") {
|
||||
ProviderData data = parseProvider(e2);
|
||||
|
||||
if (data.mccmncs.contains(targetMccMnc)) {
|
||||
result << data.name;
|
||||
}
|
||||
}
|
||||
n2 = n2.nextSibling();
|
||||
}
|
||||
}
|
||||
n = n.nextSibling();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QStringList MobileProviders::getNetworkIds(const QString &provider)
|
||||
{
|
||||
if (mNetworkIds.isEmpty()) {
|
||||
getApns(provider);
|
||||
}
|
||||
return mNetworkIds;
|
||||
}
|
||||
|
||||
QVariantMap MobileProviders::getApnInfo(const QString &apn)
|
||||
{
|
||||
QVariantMap temp;
|
||||
QDomNode n = mApns[apn];
|
||||
QStringList dnsList;
|
||||
QMap<QString, QString> localizedPlanNames;
|
||||
|
||||
while (!n.isNull()) {
|
||||
QDomElement e = n.toElement(); // <name|username|password|dns(*)>
|
||||
|
||||
if (!e.isNull()) {
|
||||
if (e.tagName().toLower() == "name") {
|
||||
QString lang = e.attribute("xml:lang");
|
||||
if (lang.isEmpty()) {
|
||||
lang = "en"; // English is default
|
||||
} else {
|
||||
lang = lang.toLower();
|
||||
lang.remove(QRegularExpression(QStringLiteral("\\-.*$"))); // Remove everything after '-' in xml:lang attribute.
|
||||
}
|
||||
localizedPlanNames.insert(lang, e.text());
|
||||
} else if (e.tagName().toLower() == "username") {
|
||||
temp.insert("username", e.text());
|
||||
} else if (e.tagName().toLower() == "password") {
|
||||
temp.insert("password", e.text());
|
||||
} else if (e.tagName().toLower() == "dns") {
|
||||
dnsList.append(e.text());
|
||||
} else if (e.tagName().toLower() == "usage") {
|
||||
temp.insert("usageType", e.attribute("type"));
|
||||
}
|
||||
}
|
||||
|
||||
n = n.nextSibling();
|
||||
}
|
||||
|
||||
QString name = getNameByLocale(localizedPlanNames);
|
||||
if (!name.isEmpty()) {
|
||||
temp.insert("name", QVariant::fromValue(name));
|
||||
}
|
||||
temp.insert("number", getGsmNumber());
|
||||
temp.insert("apn", apn);
|
||||
temp.insert("dnsList", dnsList);
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
QVariantMap MobileProviders::getCdmaInfo(const QString &provider)
|
||||
{
|
||||
if (!mProvidersCdma.contains(provider)) {
|
||||
return QVariantMap();
|
||||
}
|
||||
|
||||
QVariantMap temp;
|
||||
QDomNode n = mProvidersCdma[provider];
|
||||
QStringList sidList;
|
||||
|
||||
while (!n.isNull()) {
|
||||
QDomElement e = n.toElement(); // <gsm or cdma ...>
|
||||
|
||||
if (!e.isNull() && e.tagName().toLower() == "cdma") {
|
||||
QDomNode n2 = e.firstChild();
|
||||
while (!n2.isNull()) {
|
||||
QDomElement e2 = n2.toElement(); // <name | username | password | sid>
|
||||
|
||||
if (!e2.isNull()) {
|
||||
if (e2.tagName().toLower() == "username") {
|
||||
temp.insert("username", e2.text());
|
||||
} else if (e2.tagName().toLower() == "password") {
|
||||
temp.insert("password", e2.text());
|
||||
} else if (e2.tagName().toLower() == "sid") {
|
||||
sidList.append(e2.text());
|
||||
}
|
||||
}
|
||||
|
||||
n2 = n2.nextSibling();
|
||||
}
|
||||
}
|
||||
n = n.nextSibling();
|
||||
}
|
||||
|
||||
temp.insert("number", getCdmaNumber());
|
||||
temp.insert("sidList", sidList);
|
||||
return temp;
|
||||
}
|
||||
|
||||
QString MobileProviders::getNameByLocale(const QMap<QString, QString> &localizedNames) const
|
||||
{
|
||||
QString name;
|
||||
const QStringList locales = QLocale().uiLanguages();
|
||||
for (const QString &locale : locales) {
|
||||
QString language = locale.split(QLatin1Char('-')).at(0);
|
||||
|
||||
if (localizedNames.contains(language)) {
|
||||
return localizedNames[language];
|
||||
}
|
||||
}
|
||||
|
||||
name = localizedNames["en"];
|
||||
|
||||
// Use any language if no proper localized name were found.
|
||||
if (name.isEmpty() && !localizedNames.isEmpty()) {
|
||||
name = localizedNames.constBegin().value();
|
||||
}
|
||||
return name;
|
||||
}
|
||||
81
kcms/cellularnetwork/mobileproviders.h
Normal file
81
kcms/cellularnetwork/mobileproviders.h
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2010-2012 Lamarque Souza <lamarque@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
*/
|
||||
|
||||
#ifndef PLASMA_NM_MOBILE_PROVIDERS_H
|
||||
#define PLASMA_NM_MOBILE_PROVIDERS_H
|
||||
|
||||
#include <QDomDocument>
|
||||
#include <QHash>
|
||||
#include <QStringList>
|
||||
#include <QVariantMap>
|
||||
|
||||
#include <NetworkManagerQt/ConnectionSettings>
|
||||
|
||||
// adapted from https://invent.kde.org/plasma/plasma-nm/-/blob/master/libs/editor/mobileproviders.h
|
||||
// we only use gsm, ignore cdma
|
||||
|
||||
struct ProviderData {
|
||||
QStringList mccmncs;
|
||||
QString name;
|
||||
};
|
||||
|
||||
class Q_DECL_EXPORT MobileProviders
|
||||
{
|
||||
public:
|
||||
static const QString ProvidersFile;
|
||||
|
||||
enum ErrorCodes {
|
||||
Success,
|
||||
CountryCodesMissing,
|
||||
ProvidersMissing,
|
||||
ProvidersIsNull,
|
||||
ProvidersWrongFormat,
|
||||
ProvidersFormatNotSupported,
|
||||
};
|
||||
|
||||
MobileProviders();
|
||||
~MobileProviders();
|
||||
|
||||
QStringList getCountryList() const;
|
||||
QString countryFromLocale() const;
|
||||
QString getCountryName(const QString &key) const
|
||||
{
|
||||
return mCountries.value(key);
|
||||
}
|
||||
QStringList getApns(const QString &provider);
|
||||
QStringList getNetworkIds(const QString &provider);
|
||||
QVariantMap getApnInfo(const QString &apn);
|
||||
QVariantMap getCdmaInfo(const QString &provider);
|
||||
QStringList getProvidersFromMCCMNC(const QString &mccmnc);
|
||||
QString getGsmNumber() const
|
||||
{
|
||||
return QString("*99#");
|
||||
}
|
||||
QString getCdmaNumber() const
|
||||
{
|
||||
return QString("#777");
|
||||
}
|
||||
inline ErrorCodes getError()
|
||||
{
|
||||
return mError;
|
||||
}
|
||||
|
||||
private:
|
||||
ProviderData parseProvider(const QDomNode &providerNode);
|
||||
|
||||
QHash<QString, QString> mCountries;
|
||||
QHash<QString, QString> mMccMncToName;
|
||||
QMap<QString, QDomNode> mProvidersGsm;
|
||||
QMap<QString, QDomNode> mProvidersCdma;
|
||||
QMap<QString, QDomNode> mApns;
|
||||
QStringList mNetworkIds;
|
||||
QDomDocument mDocProviders;
|
||||
QDomElement docElement;
|
||||
ErrorCodes mError;
|
||||
QString getNameByLocale(const QMap<QString, QString> &names) const;
|
||||
};
|
||||
|
||||
#endif // PLASMA_NM_MOBILE_PROVIDERS_H
|
||||
527
kcms/cellularnetwork/modem.cpp
Normal file
527
kcms/cellularnetwork/modem.cpp
Normal file
|
|
@ -0,0 +1,527 @@
|
|||
// SPDX-FileCopyrightText: 2021-2022 Devin Lin <espidev@gmail.com>
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "modem.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include <KLocalizedString>
|
||||
#include <KUser>
|
||||
|
||||
Modem::Modem(QObject *parent)
|
||||
: QObject{parent}
|
||||
{
|
||||
}
|
||||
|
||||
Modem::Modem(QObject *parent, ModemManager::ModemDevice::Ptr mmModem, ModemManager::Modem::Ptr mmInterface)
|
||||
: QObject{parent}
|
||||
, m_mmModem{mmModem}
|
||||
, m_nmModem{nullptr}
|
||||
, m_mmInterface{mmInterface}
|
||||
{
|
||||
// TODO multi-sim support
|
||||
m_sims = {new Sim{this, this, m_mmModem->sim(), m_mmInterface, m_mm3gppDevice}};
|
||||
|
||||
connect(m_mmModem.data(), &ModemManager::ModemDevice::simAdded, this, &Modem::simsChanged);
|
||||
connect(m_mmModem.data(), &ModemManager::ModemDevice::simAdded, this, &Modem::hasSimChanged);
|
||||
connect(m_mmModem.data(), &ModemManager::ModemDevice::simRemoved, this, &Modem::simsChanged);
|
||||
connect(m_mmModem.data(), &ModemManager::ModemDevice::simRemoved, this, &Modem::hasSimChanged);
|
||||
|
||||
if (m_mmModem->sim()) {
|
||||
connect(m_mmModem->sim().get(), &ModemManager::Sim::simIdentifierChanged, this, &Modem::hasSimChanged);
|
||||
}
|
||||
|
||||
connect(NetworkManager::settingsNotifier(), &NetworkManager::SettingsNotifier::connectionAdded, this, &Modem::mobileDataEnabledChanged);
|
||||
connect(NetworkManager::settingsNotifier(), &NetworkManager::SettingsNotifier::connectionRemoved, this, &Modem::mobileDataEnabledChanged);
|
||||
connect(NetworkManager::notifier(), &NetworkManager::Notifier::activeConnectionAdded, this, &Modem::mobileDataEnabledChanged);
|
||||
connect(NetworkManager::notifier(), &NetworkManager::Notifier::activeConnectionRemoved, this, &Modem::mobileDataEnabledChanged);
|
||||
connect(NetworkManager::notifier(), &NetworkManager::Notifier::deviceAdded, this, &Modem::findNetworkManagerDevice);
|
||||
connect(NetworkManager::notifier(), &NetworkManager::Notifier::deviceRemoved, this, &Modem::findNetworkManagerDevice);
|
||||
|
||||
// this is guaranteed to be a GSM modem
|
||||
m_mm3gppDevice = m_mmModem->interface(ModemManager::ModemDevice::GsmInterface).objectCast<ModemManager::Modem3gpp>();
|
||||
|
||||
// if no sim is inserted, m_mm3gppDevice is nullptr
|
||||
if (m_mm3gppDevice) {
|
||||
m_mm3gppDevice->setTimeout(60000); // scanning networks likely takes longer than the default timeout
|
||||
}
|
||||
|
||||
// find networkmanager modem, if it exists
|
||||
findNetworkManagerDevice();
|
||||
|
||||
// we need to initialize it after m_mm3gppDevice has been set
|
||||
m_details = new ModemDetails(this, this);
|
||||
}
|
||||
|
||||
void Modem::findNetworkManagerDevice()
|
||||
{
|
||||
m_nmModem = nullptr;
|
||||
|
||||
// find networkmanager modem device
|
||||
for (NetworkManager::Device::Ptr nmDevice : NetworkManager::networkInterfaces()) {
|
||||
if (nmDevice->udi() == m_mmModem->uni()) {
|
||||
m_nmModem = nmDevice.objectCast<NetworkManager::ModemDevice>();
|
||||
}
|
||||
}
|
||||
|
||||
if (m_nmModem) {
|
||||
connect(m_nmModem.data(), &NetworkManager::Device::autoconnectChanged, this, &Modem::mobileDataEnabledChanged);
|
||||
connect(m_nmModem.data(), &NetworkManager::Device::stateChanged, this, &Modem::mobileDataEnabledChanged);
|
||||
connect(m_nmModem.data(), &NetworkManager::Device::availableConnectionAppeared, this, &Modem::mobileDataEnabledChanged);
|
||||
connect(m_nmModem.data(), &NetworkManager::Device::availableConnectionDisappeared, this, &Modem::mobileDataEnabledChanged);
|
||||
|
||||
connect(m_nmModem.data(), &NetworkManager::ModemDevice::availableConnectionChanged, this, [this]() -> void {
|
||||
refreshProfiles();
|
||||
});
|
||||
connect(m_nmModem.data(), &NetworkManager::ModemDevice::activeConnectionChanged, this, [this]() -> void {
|
||||
refreshProfiles();
|
||||
Q_EMIT activeConnectionUniChanged();
|
||||
});
|
||||
connect(m_nmModem.data(), &NetworkManager::ModemDevice::stateChanged, this, [this](auto newstate, auto oldstate, auto reason) -> void {
|
||||
qDebug() << QStringLiteral("Modem") << m_nmModem->uni() << QStringLiteral("changed state:") << nmDeviceStateStr(oldstate) << QStringLiteral("->")
|
||||
<< nmDeviceStateStr(newstate) << QStringLiteral("due to:") << reason;
|
||||
});
|
||||
|
||||
// add connection profiles
|
||||
refreshProfiles();
|
||||
}
|
||||
|
||||
Q_EMIT nmModemChanged();
|
||||
Q_EMIT mobileDataEnabledChanged();
|
||||
Q_EMIT mobileDataSupportedChanged();
|
||||
}
|
||||
|
||||
ModemDetails *Modem::modemDetails() const
|
||||
{
|
||||
return m_details;
|
||||
}
|
||||
|
||||
QString Modem::displayId() const
|
||||
{
|
||||
// in the form /org/freedesktop/ModemManager1/Modem/0
|
||||
QStringList uniSplit = uni().split("/");
|
||||
return uniSplit.count() == 0 ? QStringLiteral("(empty)") : QString(uniSplit[uniSplit.size() - 1]);
|
||||
}
|
||||
|
||||
QString Modem::uni() const
|
||||
{
|
||||
return m_mmInterface->uni();
|
||||
}
|
||||
|
||||
QString Modem::activeConnectionUni() const
|
||||
{
|
||||
if (m_nmModem && m_nmModem->activeConnection() && m_nmModem->activeConnection()->connection()) {
|
||||
return m_nmModem->activeConnection()->connection()->uuid();
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
void Modem::reset()
|
||||
{
|
||||
qDebug() << QStringLiteral("Resetting the modem...");
|
||||
QDBusPendingReply<void> reply = m_mmInterface->reset();
|
||||
reply.waitForFinished();
|
||||
if (reply.isError()) {
|
||||
qDebug() << QStringLiteral("Error resetting the modem:") << reply.error().message();
|
||||
CellularNetworkSettings::instance()->addMessage(InlineMessage::Error, i18n("Error resetting the modem: %1", reply.error().message()));
|
||||
}
|
||||
}
|
||||
|
||||
bool Modem::mobileDataSupported() const
|
||||
{
|
||||
return m_nmModem && hasSim();
|
||||
}
|
||||
|
||||
bool Modem::needsAPNAdded() const
|
||||
{
|
||||
return m_nmModem && mobileDataSupported() && m_nmModem->availableConnections().count() == 0;
|
||||
}
|
||||
|
||||
bool Modem::mobileDataEnabled() const
|
||||
{
|
||||
// no modem -> no mobile data -> report disabled
|
||||
if (!m_nmModem) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// mobile data already activated -> report enabled
|
||||
if (m_nmModem->state() == NetworkManager::Device::Activated) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// autoconnect disabled on the entire modem -> report disabled
|
||||
if (!m_nmModem->autoconnect()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// at least one connection set to autoconnect -> report enabled
|
||||
for (NetworkManager::Connection::Ptr con : m_nmModem->availableConnections()) {
|
||||
if (con->settings()->autoconnect()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// modem, but no connection, set to autoconnect -> report disabled
|
||||
return false;
|
||||
}
|
||||
|
||||
void Modem::setMobileDataEnabled(bool enabled)
|
||||
{
|
||||
if (!m_nmModem) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!enabled) {
|
||||
m_nmModem->setAutoconnect(false);
|
||||
// we need to also set all connections to not autoconnect (#182)
|
||||
for (NetworkManager::Connection::Ptr con : m_nmModem->availableConnections()) {
|
||||
con->settings()->setAutoconnect(false);
|
||||
con->update(con->settings()->toMap());
|
||||
}
|
||||
m_nmModem->disconnectInterface();
|
||||
} else {
|
||||
m_nmModem->setAutoconnect(true);
|
||||
// activate the connection that was last used
|
||||
QDateTime latestTimestamp;
|
||||
NetworkManager::Connection::Ptr latestCon;
|
||||
for (NetworkManager::Connection::Ptr con : m_nmModem->availableConnections()) {
|
||||
QDateTime timestamp = con->settings()->timestamp();
|
||||
// if con was not used yet, skip it, otherwise:
|
||||
// if we have no latestTimestamp yet, con is the latest
|
||||
// otherwise, compare the timestamps
|
||||
// in case of a tie, use the first connection that was found
|
||||
if (!timestamp.isNull() && (latestTimestamp.isNull() || timestamp > latestTimestamp)) {
|
||||
latestTimestamp = timestamp;
|
||||
latestCon = con;
|
||||
}
|
||||
}
|
||||
// if we found the last used connection
|
||||
if (!latestCon.isNull()) {
|
||||
// set it to autoconnect and connect it immediately
|
||||
latestCon->settings()->setAutoconnect(true);
|
||||
latestCon->update(latestCon->settings()->toMap());
|
||||
NetworkManager::activateConnection(latestCon->path(), m_nmModem->uni(), "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Modem::isRoaming() const
|
||||
{
|
||||
if (!m_nmModem) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_nmModem->activeConnection() && m_nmModem->activeConnection()->connection()) {
|
||||
auto connection = m_nmModem->activeConnection()->connection();
|
||||
NetworkManager::GsmSetting::Ptr gsmSetting = connection->settings()->setting(NetworkManager::Setting::Gsm).dynamicCast<NetworkManager::GsmSetting>();
|
||||
if (gsmSetting) {
|
||||
return !gsmSetting->homeOnly();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Modem::setIsRoaming(bool roaming)
|
||||
{
|
||||
if (!m_nmModem) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_nmModem->activeConnection() && m_nmModem->activeConnection()->connection()) {
|
||||
auto connection = m_nmModem->activeConnection()->connection();
|
||||
|
||||
NetworkManager::GsmSetting::Ptr gsmSetting = connection->settings()->setting(NetworkManager::Setting::Gsm).dynamicCast<NetworkManager::GsmSetting>();
|
||||
if (gsmSetting) {
|
||||
gsmSetting->setHomeOnly(!roaming); // set roaming setting
|
||||
|
||||
QDBusPendingReply reply = connection->update(connection->settings()->toMap());
|
||||
reply.waitForFinished();
|
||||
if (reply.isError()) {
|
||||
qWarning() << QStringLiteral("Error updating connection settings for") << connection->uuid() << QStringLiteral(":") << reply.error().message()
|
||||
<< QStringLiteral(".");
|
||||
CellularNetworkSettings::instance()->addMessage(
|
||||
InlineMessage::Error,
|
||||
i18n("Error updating connection settings for %1: %2.", connection->uuid(), reply.error().message()));
|
||||
} else {
|
||||
qDebug() << QStringLiteral("Successfully updated connection settings") << connection->uuid() << QStringLiteral(".");
|
||||
}
|
||||
}
|
||||
|
||||
// the connection uni has changed, refresh the profiles list
|
||||
refreshProfiles();
|
||||
Q_EMIT activeConnectionUniChanged();
|
||||
}
|
||||
}
|
||||
|
||||
bool Modem::hasSim() const
|
||||
{
|
||||
if (!m_mmModem) {
|
||||
return false;
|
||||
}
|
||||
return m_mmModem && m_mmModem->sim() && m_mmModem->sim()->uni() != QStringLiteral("/");
|
||||
}
|
||||
|
||||
QList<ProfileSettings *> &Modem::profileList()
|
||||
{
|
||||
return m_profileList;
|
||||
}
|
||||
|
||||
void Modem::refreshProfiles()
|
||||
{
|
||||
m_profileList.clear();
|
||||
|
||||
if (!m_nmModem) {
|
||||
Q_EMIT profileListChanged();
|
||||
qWarning() << "No NetworkManager modem found, cannot refresh profiles.";
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto connection : m_nmModem->availableConnections()) {
|
||||
for (auto setting : connection->settings()->settings()) {
|
||||
if (setting.dynamicCast<NetworkManager::GsmSetting>()) {
|
||||
m_profileList.append(new ProfileSettings(this, setting.dynamicCast<NetworkManager::GsmSetting>(), connection));
|
||||
}
|
||||
}
|
||||
}
|
||||
Q_EMIT profileListChanged();
|
||||
}
|
||||
|
||||
void Modem::activateProfile(const QString &connectionUni)
|
||||
{
|
||||
if (!m_nmModem) {
|
||||
qWarning() << "Cannot activate profile since there is no NetworkManager modem";
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << QStringLiteral("Activating profile on modem") << m_nmModem->uni() << QStringLiteral("for connection") << connectionUni << ".";
|
||||
|
||||
// cache roaming setting
|
||||
bool roaming = isRoaming();
|
||||
|
||||
NetworkManager::Connection::Ptr con;
|
||||
|
||||
// disable autoconnect for all other connections
|
||||
for (auto connection : m_nmModem->availableConnections()) {
|
||||
if (connection->uuid() == connectionUni) {
|
||||
connection->settings()->setAutoconnect(true);
|
||||
con = connection;
|
||||
} else {
|
||||
connection->settings()->setAutoconnect(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (!con) {
|
||||
qDebug() << QStringLiteral("Connection") << connectionUni << QStringLiteral("not found.");
|
||||
return;
|
||||
}
|
||||
|
||||
// activate connection manually
|
||||
// despite the documentation saying otherwise, activateConnection seems to need the DBus path, not uuid of the connection
|
||||
QDBusPendingReply<QDBusObjectPath> reply = NetworkManager::activateConnection(con->path(), m_nmModem->uni(), "");
|
||||
reply.waitForFinished();
|
||||
if (reply.isError()) {
|
||||
qWarning() << QStringLiteral("Error activating connection:") << reply.error().message();
|
||||
CellularNetworkSettings::instance()->addMessage(InlineMessage::Error, i18n("Error activating connection: %1", reply.error().message()));
|
||||
return;
|
||||
}
|
||||
|
||||
// set roaming settings separately (since it changes the uni)
|
||||
setIsRoaming(roaming);
|
||||
}
|
||||
|
||||
void Modem::addProfile(QString name, QString apn, QString username, QString password, QString networkType)
|
||||
{
|
||||
if (!m_nmModem) {
|
||||
qWarning() << "Cannot add profile since there is no NetworkManager modem";
|
||||
return;
|
||||
}
|
||||
|
||||
NetworkManager::ConnectionSettings::Ptr settings{new NetworkManager::ConnectionSettings(NetworkManager::ConnectionSettings::Gsm)};
|
||||
settings->setId(name);
|
||||
settings->setUuid(NetworkManager::ConnectionSettings::createNewUuid());
|
||||
settings->setAutoconnect(true);
|
||||
settings->addToPermissions(KUser().loginName(), QString());
|
||||
|
||||
NetworkManager::GsmSetting::Ptr gsmSetting = settings->setting(NetworkManager::Setting::Gsm).dynamicCast<NetworkManager::GsmSetting>();
|
||||
gsmSetting->setApn(apn);
|
||||
gsmSetting->setUsername(username);
|
||||
gsmSetting->setPassword(password);
|
||||
gsmSetting->setPasswordFlags(password.isEmpty() ? NetworkManager::Setting::NotRequired : NetworkManager::Setting::AgentOwned);
|
||||
gsmSetting->setNetworkType(ProfileSettings::networkTypeFlag(networkType));
|
||||
gsmSetting->setHomeOnly(!isRoaming());
|
||||
|
||||
gsmSetting->setInitialized(true);
|
||||
|
||||
QDBusPendingReply<QDBusObjectPath> reply = NetworkManager::addAndActivateConnection(settings->toMap(), m_nmModem->uni(), "");
|
||||
reply.waitForFinished();
|
||||
if (reply.isError()) {
|
||||
qWarning() << QStringLiteral("Error adding connection:") << reply.error().message();
|
||||
CellularNetworkSettings::instance()->addMessage(InlineMessage::Error, i18n("Error adding connection: %1", reply.error().message()));
|
||||
} else {
|
||||
qDebug() << QStringLiteral("Successfully added a new connection") << name << QStringLiteral("with APN") << apn << ".";
|
||||
}
|
||||
}
|
||||
|
||||
void Modem::removeProfile(const QString &connectionUni)
|
||||
{
|
||||
NetworkManager::Connection::Ptr con = NetworkManager::findConnectionByUuid(connectionUni);
|
||||
if (!con) {
|
||||
qWarning() << QStringLiteral("Could not find connection") << connectionUni << QStringLiteral("to update!");
|
||||
return;
|
||||
}
|
||||
|
||||
QDBusPendingReply reply = con->remove();
|
||||
reply.waitForFinished();
|
||||
if (reply.isError()) {
|
||||
qWarning() << QStringLiteral("Error removing connection") << reply.error().message();
|
||||
CellularNetworkSettings::instance()->addMessage(InlineMessage::Error, i18n("Error removing connection: %1", reply.error().message()));
|
||||
}
|
||||
}
|
||||
|
||||
void Modem::updateProfile(QString connectionUni, QString name, QString apn, QString username, QString password, QString networkType)
|
||||
{
|
||||
NetworkManager::Connection::Ptr con = NetworkManager::findConnectionByUuid(connectionUni);
|
||||
if (!con) {
|
||||
qWarning() << QStringLiteral("Could not find connection") << connectionUni << QStringLiteral("to update!");
|
||||
return;
|
||||
}
|
||||
|
||||
NetworkManager::ConnectionSettings::Ptr conSettings = con->settings();
|
||||
if (!conSettings) {
|
||||
qWarning() << QStringLiteral("Could not find connection settings for") << connectionUni << QStringLiteral("to update!");
|
||||
return;
|
||||
}
|
||||
|
||||
conSettings->setId(name);
|
||||
|
||||
NetworkManager::GsmSetting::Ptr gsmSetting = conSettings->setting(NetworkManager::Setting::Gsm).dynamicCast<NetworkManager::GsmSetting>();
|
||||
gsmSetting->setApn(apn);
|
||||
gsmSetting->setUsername(username);
|
||||
gsmSetting->setPassword(password);
|
||||
gsmSetting->setPasswordFlags(password == "" ? NetworkManager::Setting::NotRequired : NetworkManager::Setting::AgentOwned);
|
||||
gsmSetting->setNetworkType(ProfileSettings::networkTypeFlag(networkType));
|
||||
gsmSetting->setHomeOnly(!isRoaming());
|
||||
|
||||
gsmSetting->setInitialized(true);
|
||||
|
||||
QDBusPendingReply reply = con->update(conSettings->toMap());
|
||||
reply.waitForFinished();
|
||||
if (reply.isError()) {
|
||||
qWarning() << QStringLiteral("Error updating connection settings for") << connectionUni << QStringLiteral(":") << reply.error().message()
|
||||
<< QStringLiteral(".");
|
||||
CellularNetworkSettings::instance()->addMessage(InlineMessage::Error,
|
||||
i18n("Error updating connection settings for %1: %2.", connectionUni, reply.error().message()));
|
||||
} else {
|
||||
qDebug() << QStringLiteral("Successfully updated connection settings") << connectionUni << QStringLiteral(".");
|
||||
}
|
||||
}
|
||||
|
||||
void Modem::addDetectedProfileSettings()
|
||||
{
|
||||
if (!m_mmModem) {
|
||||
qWarning() << "ModemManager device missing, cannot detect profile settings";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!hasSim()) {
|
||||
qWarning() << "No SIM found, cannot detect profile settings";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_mm3gppDevice) {
|
||||
qWarning() << "3gpp object not found, cannot detect profile settings";
|
||||
return;
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
static MobileProviders mobileProviders{};
|
||||
|
||||
QString operatorCode = m_mm3gppDevice->operatorCode();
|
||||
qWarning() << QStringLiteral("Detecting profile settings. Using MCCMNC:") << operatorCode;
|
||||
|
||||
// lookup apns with mccmnc codes
|
||||
for (QString &provider : mobileProviders.getProvidersFromMCCMNC(operatorCode)) {
|
||||
qWarning() << QStringLiteral("Provider:") << provider;
|
||||
|
||||
for (auto apn : mobileProviders.getApns(provider)) {
|
||||
QVariantMap apnInfo = mobileProviders.getApnInfo(apn);
|
||||
qWarning() << QStringLiteral("Found gsm profile settings. Type:") << apnInfo[QStringLiteral("usageType")];
|
||||
|
||||
// only add mobile data apns (not mms)
|
||||
if (apnInfo[QStringLiteral("usageType")].toString() == QStringLiteral("internet")) {
|
||||
found = true;
|
||||
|
||||
QString name = provider;
|
||||
if (!apnInfo[QStringLiteral("name")].isNull()) {
|
||||
name += " - " + apnInfo[QStringLiteral("name")].toString();
|
||||
}
|
||||
|
||||
addProfile(name,
|
||||
apn,
|
||||
apnInfo[QStringLiteral("username")].toString(),
|
||||
apnInfo[QStringLiteral("password")].toString(),
|
||||
QStringLiteral("4G/3G/2G"));
|
||||
}
|
||||
|
||||
// TODO in the future for MMS settings, add else if here for == "mms"
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
qDebug() << QStringLiteral("No profiles were found.");
|
||||
Q_EMIT couldNotAutodetectSettings();
|
||||
}
|
||||
}
|
||||
|
||||
QList<Sim *> Modem::sims()
|
||||
{
|
||||
return m_sims;
|
||||
}
|
||||
|
||||
ModemManager::ModemDevice::Ptr Modem::mmModemDevice()
|
||||
{
|
||||
return m_mmModem;
|
||||
}
|
||||
|
||||
NetworkManager::ModemDevice::Ptr Modem::nmModemDevice()
|
||||
{
|
||||
return m_nmModem;
|
||||
}
|
||||
|
||||
ModemManager::Modem::Ptr Modem::mmModemInterface()
|
||||
{
|
||||
return m_mmInterface;
|
||||
}
|
||||
|
||||
QString Modem::nmDeviceStateStr(NetworkManager::Device::State state)
|
||||
{
|
||||
if (state == NetworkManager::Device::State::UnknownState)
|
||||
return i18n("Unknown");
|
||||
else if (state == NetworkManager::Device::State::Unmanaged)
|
||||
return i18n("Unmanaged");
|
||||
else if (state == NetworkManager::Device::State::Unavailable)
|
||||
return i18n("Unavailable");
|
||||
else if (state == NetworkManager::Device::State::Disconnected)
|
||||
return i18n("Disconnected");
|
||||
else if (state == NetworkManager::Device::State::Preparing)
|
||||
return i18n("Preparing");
|
||||
else if (state == NetworkManager::Device::State::ConfiguringHardware)
|
||||
return i18n("ConfiguringHardware");
|
||||
else if (state == NetworkManager::Device::State::NeedAuth)
|
||||
return i18n("NeedAuth");
|
||||
else if (state == NetworkManager::Device::State::ConfiguringIp)
|
||||
return i18n("ConfiguringIp");
|
||||
else if (state == NetworkManager::Device::State::CheckingIp)
|
||||
return i18n("CheckingIp");
|
||||
else if (state == NetworkManager::Device::State::WaitingForSecondaries)
|
||||
return i18n("WaitingForSecondaries");
|
||||
else if (state == NetworkManager::Device::State::Activated)
|
||||
return i18n("Activated");
|
||||
else if (state == NetworkManager::Device::State::Deactivating)
|
||||
return i18n("Deactivating");
|
||||
else if (state == NetworkManager::Device::State::Failed)
|
||||
return i18n("Failed");
|
||||
else
|
||||
return "";
|
||||
}
|
||||
117
kcms/cellularnetwork/modem.h
Normal file
117
kcms/cellularnetwork/modem.h
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
// SPDX-FileCopyrightText: 2021-2022 Devin Lin <espidev@gmail.com>
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cellularnetworksettings.h"
|
||||
#include "modemdetails.h"
|
||||
#include "profilesettings.h"
|
||||
#include "sim.h"
|
||||
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
|
||||
#include <NetworkManagerQt/CdmaSetting>
|
||||
#include <NetworkManagerQt/ConnectionSettings>
|
||||
#include <NetworkManagerQt/GsmSetting>
|
||||
#include <NetworkManagerQt/Manager>
|
||||
#include <NetworkManagerQt/ModemDevice>
|
||||
#include <NetworkManagerQt/Settings>
|
||||
|
||||
#include <ModemManagerQt/GenericTypes>
|
||||
#include <ModemManagerQt/Manager>
|
||||
#include <ModemManagerQt/Modem3Gpp>
|
||||
#include <ModemManagerQt/ModemDevice>
|
||||
|
||||
class ProfileSettings;
|
||||
class Sim;
|
||||
class AvailableNetwork;
|
||||
class ModemDetails;
|
||||
class MobileProviders;
|
||||
|
||||
// only supports GSM/UMTS/LTE
|
||||
class Modem : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(ModemDetails *details READ modemDetails NOTIFY modemDetailsChanged)
|
||||
Q_PROPERTY(QString uni READ uni NOTIFY uniChanged)
|
||||
Q_PROPERTY(QString displayId READ displayId NOTIFY displayIdChanged)
|
||||
|
||||
Q_PROPERTY(bool isRoaming READ isRoaming WRITE setIsRoaming NOTIFY isRoamingChanged)
|
||||
Q_PROPERTY(bool hasSim READ hasSim NOTIFY hasSimChanged)
|
||||
Q_PROPERTY(QList<ProfileSettings *> profiles READ profileList NOTIFY profileListChanged)
|
||||
Q_PROPERTY(QString activeConnectionUni READ activeConnectionUni NOTIFY activeConnectionUniChanged)
|
||||
|
||||
Q_PROPERTY(bool mobileDataEnabled READ mobileDataEnabled WRITE setMobileDataEnabled NOTIFY mobileDataEnabledChanged)
|
||||
Q_PROPERTY(bool mobileDataSupported READ mobileDataSupported NOTIFY mobileDataSupportedChanged)
|
||||
Q_PROPERTY(bool needsAPNAdded READ needsAPNAdded NOTIFY mobileDataEnabledChanged)
|
||||
|
||||
public:
|
||||
Modem(QObject *parent = nullptr);
|
||||
Modem(QObject *parent, ModemManager::ModemDevice::Ptr mmModem, ModemManager::Modem::Ptr m_mmInterface);
|
||||
|
||||
ModemDetails *modemDetails() const;
|
||||
QString displayId() const; // splits uni and obtains the number suffix
|
||||
QString uni() const;
|
||||
QString activeConnectionUni() const;
|
||||
|
||||
Q_INVOKABLE void reset();
|
||||
|
||||
bool mobileDataEnabled() const;
|
||||
void setMobileDataEnabled(bool enabled);
|
||||
bool mobileDataSupported() const;
|
||||
bool needsAPNAdded() const;
|
||||
|
||||
bool isRoaming() const;
|
||||
void setIsRoaming(bool roaming);
|
||||
bool hasSim() const;
|
||||
|
||||
// connection profiles
|
||||
QList<ProfileSettings *> &profileList();
|
||||
void refreshProfiles();
|
||||
Q_INVOKABLE void activateProfile(const QString &connectionUni);
|
||||
Q_INVOKABLE void addProfile(QString name, QString apn, QString username, QString password, QString networkType);
|
||||
Q_INVOKABLE void removeProfile(const QString &connectionUni);
|
||||
Q_INVOKABLE void updateProfile(QString connectionUni, QString name, QString apn, QString username, QString password, QString networkType);
|
||||
Q_INVOKABLE void addDetectedProfileSettings(); // detect modem connection settings (ex. apn) and add a new connection
|
||||
|
||||
QList<Sim *> sims();
|
||||
|
||||
ModemManager::ModemDevice::Ptr mmModemDevice();
|
||||
NetworkManager::ModemDevice::Ptr nmModemDevice();
|
||||
ModemManager::Modem::Ptr mmModemInterface();
|
||||
|
||||
Q_SIGNALS:
|
||||
void modemDetailsChanged();
|
||||
void uniChanged();
|
||||
void displayIdChanged();
|
||||
void activeConnectionUniChanged();
|
||||
|
||||
void nmModemChanged();
|
||||
|
||||
void mobileDataEnabledChanged();
|
||||
void mobileDataSupportedChanged();
|
||||
void isRoamingChanged();
|
||||
void simsChanged();
|
||||
void hasSimChanged();
|
||||
void profileListChanged();
|
||||
|
||||
void couldNotAutodetectSettings();
|
||||
|
||||
private:
|
||||
void findNetworkManagerDevice();
|
||||
|
||||
QString nmDeviceStateStr(NetworkManager::Device::State state);
|
||||
|
||||
ModemDetails *m_details;
|
||||
|
||||
ModemManager::ModemDevice::Ptr m_mmModem;
|
||||
NetworkManager::ModemDevice::Ptr m_nmModem; // may be a nullptr if the nm modem hasn't been found yet
|
||||
ModemManager::Modem::Ptr m_mmInterface = nullptr;
|
||||
ModemManager::Modem3gpp::Ptr m_mm3gppDevice = nullptr; // this may be a nullptr if no sim is inserted
|
||||
|
||||
QList<Sim *> m_sims;
|
||||
QList<ProfileSettings *> m_profileList;
|
||||
|
||||
friend class ModemDetails;
|
||||
};
|
||||
547
kcms/cellularnetwork/modemdetails.cpp
Normal file
547
kcms/cellularnetwork/modemdetails.cpp
Normal file
|
|
@ -0,0 +1,547 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2021 Devin Lin <espidev@gmail.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "modemdetails.h"
|
||||
|
||||
#include <KLocalizedString>
|
||||
|
||||
#include <QDBusPendingCallWatcher>
|
||||
|
||||
ModemDetails::ModemDetails(QObject *parent, Modem *modem)
|
||||
: QObject{parent}
|
||||
, m_modem{modem}
|
||||
, m_scanNetworkWatcher{nullptr}
|
||||
, m_isScanningNetworks{false}
|
||||
, m_cachedScannedNetworks{}
|
||||
{
|
||||
auto mmInterfacePointer = m_modem->m_mmInterface.data();
|
||||
connect(mmInterfacePointer, &ModemManager::Modem::accessTechnologiesChanged, this, [this]() -> void {
|
||||
Q_EMIT accessTechnologiesChanged();
|
||||
});
|
||||
connect(mmInterfacePointer, &ModemManager::Modem::deviceChanged, this, [this]() -> void {
|
||||
Q_EMIT deviceChanged();
|
||||
});
|
||||
connect(mmInterfacePointer, &ModemManager::Modem::deviceIdentifierChanged, this, [this]() -> void {
|
||||
Q_EMIT deviceIdentifierChanged();
|
||||
});
|
||||
connect(mmInterfacePointer, &ModemManager::Modem::driversChanged, this, [this]() -> void {
|
||||
Q_EMIT driversChanged();
|
||||
});
|
||||
connect(mmInterfacePointer, &ModemManager::Modem::equipmentIdentifierChanged, this, [this]() -> void {
|
||||
Q_EMIT equipmentIdentifierChanged();
|
||||
});
|
||||
connect(mmInterfacePointer, &ModemManager::Modem::manufacturerChanged, this, [this]() -> void {
|
||||
Q_EMIT manufacturerChanged();
|
||||
});
|
||||
connect(mmInterfacePointer, &ModemManager::Modem::modelChanged, this, [this]() -> void {
|
||||
Q_EMIT modelChanged();
|
||||
});
|
||||
connect(mmInterfacePointer, &ModemManager::Modem::ownNumbersChanged, this, [this]() -> void {
|
||||
Q_EMIT ownNumbersChanged();
|
||||
});
|
||||
connect(mmInterfacePointer, &ModemManager::Modem::pluginChanged, this, [this]() -> void {
|
||||
Q_EMIT pluginChanged();
|
||||
});
|
||||
connect(mmInterfacePointer, &ModemManager::Modem::powerStateChanged, this, [this]() -> void {
|
||||
Q_EMIT powerStateChanged();
|
||||
});
|
||||
connect(mmInterfacePointer, &ModemManager::Modem::revisionChanged, this, [this]() -> void {
|
||||
Q_EMIT revisionChanged();
|
||||
});
|
||||
connect(mmInterfacePointer, &ModemManager::Modem::signalQualityChanged, this, [this]() -> void {
|
||||
Q_EMIT signalQualityChanged();
|
||||
});
|
||||
connect(mmInterfacePointer, &ModemManager::Modem::simPathChanged, this, [this]() -> void {
|
||||
Q_EMIT simPathChanged();
|
||||
});
|
||||
connect(mmInterfacePointer, &ModemManager::Modem::stateChanged, this, [this]() -> void {
|
||||
Q_EMIT stateChanged();
|
||||
});
|
||||
connect(mmInterfacePointer, &ModemManager::Modem::stateFailedReasonChanged, this, [this]() -> void {
|
||||
Q_EMIT stateFailedReasonChanged();
|
||||
});
|
||||
|
||||
if (m_modem->m_mm3gppDevice) {
|
||||
connect(m_modem->m_mm3gppDevice.data(), &ModemManager::Modem3gpp::operatorCodeChanged, this, [this]() -> void {
|
||||
Q_EMIT operatorCodeChanged();
|
||||
});
|
||||
connect(m_modem->m_mm3gppDevice.data(), &ModemManager::Modem3gpp::operatorNameChanged, this, [this]() -> void {
|
||||
Q_EMIT operatorNameChanged();
|
||||
});
|
||||
connect(m_modem->m_mm3gppDevice.data(), &ModemManager::Modem3gpp::registrationStateChanged, this, [this]() -> void {
|
||||
Q_EMIT registrationStateChanged();
|
||||
Q_EMIT m_modem->isRoamingChanged();
|
||||
});
|
||||
} else {
|
||||
qWarning() << QStringLiteral("3gpp device not found!");
|
||||
}
|
||||
|
||||
// m_modem->m_nmModem may be nullptr, listen for updates
|
||||
connect(m_modem, &Modem::nmModemChanged, this, &ModemDetails::updateNMSignals);
|
||||
updateNMSignals();
|
||||
}
|
||||
|
||||
void ModemDetails::updateNMSignals()
|
||||
{
|
||||
if (m_modem->m_nmModem) {
|
||||
connect(m_modem->m_nmModem.data(), &NetworkManager::ModemDevice::firmwareVersionChanged, this, [this]() -> void {
|
||||
Q_EMIT firmwareVersionChanged();
|
||||
});
|
||||
connect(m_modem->m_nmModem.data(), &NetworkManager::ModemDevice::interfaceNameChanged, this, [this]() -> void {
|
||||
Q_EMIT interfaceNameChanged();
|
||||
});
|
||||
connect(m_modem->m_nmModem.data(), &NetworkManager::ModemDevice::meteredChanged, this, [this]() -> void {
|
||||
Q_EMIT meteredChanged();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
ModemDetails &ModemDetails::operator=(ModemDetails &&other)
|
||||
{
|
||||
swap(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void ModemDetails::swap(ModemDetails &other)
|
||||
{
|
||||
std::swap(m_modem, other.m_modem);
|
||||
std::swap(m_cachedScannedNetworks, other.m_cachedScannedNetworks);
|
||||
std::swap(m_isScanningNetworks, other.m_isScanningNetworks);
|
||||
std::swap(m_scanNetworkWatcher, other.m_scanNetworkWatcher);
|
||||
}
|
||||
|
||||
QStringList ModemDetails::accessTechnologies()
|
||||
{
|
||||
QStringList list;
|
||||
auto flags = m_modem->m_mmInterface->accessTechnologies();
|
||||
if (flags & MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN) {
|
||||
list.push_back(i18n("Unknown"));
|
||||
}
|
||||
if (flags & MM_MODEM_ACCESS_TECHNOLOGY_POTS) {
|
||||
list.push_back(i18n("POTS"));
|
||||
}
|
||||
if (flags & MM_MODEM_ACCESS_TECHNOLOGY_GSM) {
|
||||
list.push_back(i18n("GSM"));
|
||||
}
|
||||
if (flags & MM_MODEM_ACCESS_TECHNOLOGY_GSM_COMPACT) {
|
||||
list.push_back(i18n("GSM Compact"));
|
||||
}
|
||||
if (flags & MM_MODEM_ACCESS_TECHNOLOGY_GPRS) {
|
||||
list.push_back(i18n("GPRS"));
|
||||
}
|
||||
if (flags & MM_MODEM_ACCESS_TECHNOLOGY_EDGE) {
|
||||
list.push_back(i18n("EDGE"));
|
||||
}
|
||||
if (flags & MM_MODEM_ACCESS_TECHNOLOGY_UMTS) {
|
||||
list.push_back(i18n("UMTS"));
|
||||
}
|
||||
if (flags & MM_MODEM_ACCESS_TECHNOLOGY_HSDPA) {
|
||||
list.push_back(i18n("HSDPA"));
|
||||
}
|
||||
if (flags & MM_MODEM_ACCESS_TECHNOLOGY_HSUPA) {
|
||||
list.push_back(i18n("HSUPA"));
|
||||
}
|
||||
if (flags & MM_MODEM_ACCESS_TECHNOLOGY_HSPA) {
|
||||
list.push_back(i18n("HSPA"));
|
||||
}
|
||||
if (flags & MM_MODEM_ACCESS_TECHNOLOGY_HSPA_PLUS) {
|
||||
list.push_back(i18n("HSPA+"));
|
||||
}
|
||||
if (flags & MM_MODEM_ACCESS_TECHNOLOGY_1XRTT) {
|
||||
list.push_back(i18n("CDMA2000 1xRTT"));
|
||||
}
|
||||
if (flags & MM_MODEM_ACCESS_TECHNOLOGY_EVDO0) {
|
||||
list.push_back(i18n("CDMA2000 EVDO-0"));
|
||||
}
|
||||
if (flags & MM_MODEM_ACCESS_TECHNOLOGY_EVDOA) {
|
||||
list.push_back(i18n("CDMA2000 EVDO-A"));
|
||||
}
|
||||
if (flags & MM_MODEM_ACCESS_TECHNOLOGY_EVDOB) {
|
||||
list.push_back(i18n("CDMA2000 EVDO-B"));
|
||||
}
|
||||
if (flags & MM_MODEM_ACCESS_TECHNOLOGY_LTE) {
|
||||
list.push_back(i18n("LTE"));
|
||||
}
|
||||
if (flags & MM_MODEM_ACCESS_TECHNOLOGY_5GNR) {
|
||||
list.push_back(i18n("5GNR"));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
QString ModemDetails::device()
|
||||
{
|
||||
return m_modem->m_mmInterface->device();
|
||||
}
|
||||
|
||||
QString ModemDetails::deviceIdentifier()
|
||||
{
|
||||
return m_modem->m_mmInterface->deviceIdentifier();
|
||||
}
|
||||
|
||||
QStringList ModemDetails::drivers()
|
||||
{
|
||||
return m_modem->m_mmInterface->drivers();
|
||||
}
|
||||
|
||||
QString ModemDetails::equipmentIdentifier()
|
||||
{
|
||||
return m_modem->m_mmInterface->equipmentIdentifier();
|
||||
}
|
||||
|
||||
bool ModemDetails::isEnabled()
|
||||
{
|
||||
return m_modem->m_mmInterface->isEnabled();
|
||||
}
|
||||
|
||||
QString ModemDetails::manufacturer()
|
||||
{
|
||||
return m_modem->m_mmInterface->manufacturer();
|
||||
}
|
||||
|
||||
QString ModemDetails::model()
|
||||
{
|
||||
return m_modem->m_mmInterface->model();
|
||||
}
|
||||
|
||||
QStringList ModemDetails::ownNumbers()
|
||||
{
|
||||
return m_modem->m_mmInterface->ownNumbers();
|
||||
}
|
||||
|
||||
QString ModemDetails::plugin()
|
||||
{
|
||||
return m_modem->m_mmInterface->plugin();
|
||||
}
|
||||
|
||||
QString ModemDetails::powerState()
|
||||
{
|
||||
switch (m_modem->m_mmInterface->powerState()) {
|
||||
case MM_MODEM_POWER_STATE_UNKNOWN:
|
||||
return i18n("Unknown");
|
||||
case MM_MODEM_POWER_STATE_OFF:
|
||||
return i18n("Off");
|
||||
case MM_MODEM_POWER_STATE_LOW:
|
||||
return i18n("Low-power mode");
|
||||
case MM_MODEM_POWER_STATE_ON:
|
||||
return i18n("Full power mode");
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
QString ModemDetails::revision()
|
||||
{
|
||||
return m_modem->m_mmInterface->revision();
|
||||
}
|
||||
|
||||
uint ModemDetails::signalQuality()
|
||||
{
|
||||
return m_modem->m_mmInterface->signalQuality().signal;
|
||||
}
|
||||
|
||||
QString ModemDetails::simPath()
|
||||
{
|
||||
return m_modem->m_mmInterface->simPath();
|
||||
}
|
||||
|
||||
QString ModemDetails::state()
|
||||
{
|
||||
switch (m_modem->m_mmInterface->state()) {
|
||||
case MM_MODEM_STATE_FAILED:
|
||||
return i18n("Failed");
|
||||
case MM_MODEM_STATE_UNKNOWN:
|
||||
return i18n("Unknown");
|
||||
case MM_MODEM_STATE_INITIALIZING:
|
||||
return i18n("Initializing");
|
||||
case MM_MODEM_STATE_LOCKED:
|
||||
return i18n("Locked");
|
||||
case MM_MODEM_STATE_DISABLED:
|
||||
return i18n("Disabled");
|
||||
case MM_MODEM_STATE_DISABLING:
|
||||
return i18n("Disabling");
|
||||
case MM_MODEM_STATE_ENABLING:
|
||||
return i18n("Enabling");
|
||||
case MM_MODEM_STATE_ENABLED:
|
||||
return i18n("Enabled");
|
||||
case MM_MODEM_STATE_SEARCHING:
|
||||
return i18n("Searching for network provider");
|
||||
case MM_MODEM_STATE_REGISTERED:
|
||||
return i18n("Registered with network provider");
|
||||
case MM_MODEM_STATE_DISCONNECTING:
|
||||
return i18n("Disconnecting");
|
||||
case MM_MODEM_STATE_CONNECTING:
|
||||
return i18n("Connecting");
|
||||
case MM_MODEM_STATE_CONNECTED:
|
||||
return i18n("Connected");
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
QString ModemDetails::stateFailedReason()
|
||||
{
|
||||
switch (m_modem->m_mmInterface->stateFailedReason()) {
|
||||
case MM_MODEM_STATE_FAILED_REASON_NONE:
|
||||
return i18n("No error.");
|
||||
case MM_MODEM_STATE_FAILED_REASON_UNKNOWN:
|
||||
return i18n("Unknown error.");
|
||||
case MM_MODEM_STATE_FAILED_REASON_SIM_MISSING:
|
||||
return i18n("SIM is required but missing.");
|
||||
case MM_MODEM_STATE_FAILED_REASON_SIM_ERROR:
|
||||
return i18n("SIM is available but unusable.");
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
QString ModemDetails::operatorCode()
|
||||
{
|
||||
return m_modem->m_mm3gppDevice ? m_modem->m_mm3gppDevice->operatorCode() : QString{};
|
||||
}
|
||||
|
||||
QString ModemDetails::operatorName()
|
||||
{
|
||||
return m_modem->m_mm3gppDevice ? m_modem->m_mm3gppDevice->operatorName() : QString{};
|
||||
}
|
||||
|
||||
QString ModemDetails::registrationState()
|
||||
{
|
||||
if (!m_modem->m_mm3gppDevice) {
|
||||
return QString{};
|
||||
}
|
||||
|
||||
switch (m_modem->m_mm3gppDevice->registrationState()) {
|
||||
case MM_MODEM_3GPP_REGISTRATION_STATE_IDLE:
|
||||
return i18n("Not registered, not searching for new operator to register.");
|
||||
case MM_MODEM_3GPP_REGISTRATION_STATE_HOME:
|
||||
return i18n("Registered on home network.");
|
||||
case MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING:
|
||||
return i18n("Not registered, searching for new operator to register with.");
|
||||
case MM_MODEM_3GPP_REGISTRATION_STATE_DENIED:
|
||||
return i18n("Registration denied.");
|
||||
case MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN:
|
||||
return i18n("Unknown registration status.");
|
||||
case MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING:
|
||||
return i18n("Registered on a roaming network.");
|
||||
case MM_MODEM_3GPP_REGISTRATION_STATE_HOME_SMS_ONLY:
|
||||
return i18n("Registered for \"SMS only\", on home network.");
|
||||
case MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING_SMS_ONLY:
|
||||
return i18n("Registered for \"SMS only\", roaming network.");
|
||||
case MM_MODEM_3GPP_REGISTRATION_STATE_EMERGENCY_ONLY:
|
||||
return i18n("Emergency services only.");
|
||||
case MM_MODEM_3GPP_REGISTRATION_STATE_HOME_CSFB_NOT_PREFERRED:
|
||||
return i18n("Registered for \"CSFB not preferred\", home network.");
|
||||
case MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING_CSFB_NOT_PREFERRED:
|
||||
return i18n("Registered for \"CSFB not preferred\", roaming network.");
|
||||
case MM_MODEM_3GPP_REGISTRATION_STATE_ATTACHED_RLOS:
|
||||
return i18n("Attached for access to Restricted Local Operator Services.");
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(MMModem3gppNetworkAvailability)
|
||||
Q_DECLARE_METATYPE(MMModemAccessTechnology)
|
||||
|
||||
QList<AvailableNetwork *> ModemDetails::networks()
|
||||
{
|
||||
return m_cachedScannedNetworks;
|
||||
}
|
||||
|
||||
Q_INVOKABLE void ModemDetails::scanNetworks()
|
||||
{
|
||||
for (auto p : m_cachedScannedNetworks) {
|
||||
p->deleteLater();
|
||||
}
|
||||
m_cachedScannedNetworks.clear();
|
||||
|
||||
if (m_modem->m_mm3gppDevice) {
|
||||
qDebug() << QStringLiteral("Scanning for available networks...");
|
||||
|
||||
QDBusPendingReply<ModemManager::QVariantMapList> reply = m_modem->m_mm3gppDevice->scan();
|
||||
|
||||
m_isScanningNetworks = true;
|
||||
Q_EMIT isScanningNetworksChanged();
|
||||
m_scanNetworkWatcher = new QDBusPendingCallWatcher(reply, this);
|
||||
connect(m_scanNetworkWatcher, &QDBusPendingCallWatcher::finished, this, &ModemDetails::scanNetworksFinished);
|
||||
}
|
||||
|
||||
Q_EMIT networksChanged();
|
||||
}
|
||||
|
||||
void ModemDetails::scanNetworksFinished(QDBusPendingCallWatcher *call)
|
||||
{
|
||||
QDBusPendingReply<ModemManager::QVariantMapList> reply = *call;
|
||||
if (reply.isError()) {
|
||||
qDebug() << QStringLiteral("Scanning failed:") << reply.error().message();
|
||||
CellularNetworkSettings::instance()->addMessage(InlineMessage::Error, i18n("Scanning networks failed: %1", reply.error().message()));
|
||||
} else {
|
||||
ModemManager::QVariantMapList list = reply.value();
|
||||
|
||||
for (auto &var : list) {
|
||||
auto status = var[QStringLiteral("status")].value<MMModem3gppNetworkAvailability>();
|
||||
|
||||
if (status == MM_MODEM_3GPP_NETWORK_AVAILABILITY_CURRENT || status == MM_MODEM_3GPP_NETWORK_AVAILABILITY_AVAILABLE) {
|
||||
auto network = new AvailableNetwork{this,
|
||||
m_modem->m_mm3gppDevice,
|
||||
status == MM_MODEM_3GPP_NETWORK_AVAILABILITY_CURRENT,
|
||||
var[QStringLiteral("operator-long")].toString(),
|
||||
var[QStringLiteral("operator-short")].toString(),
|
||||
var[QStringLiteral("operator-code")].toString(),
|
||||
var[QStringLiteral("access-technology")].value<MMModemAccessTechnology>()};
|
||||
m_cachedScannedNetworks.push_back(network);
|
||||
}
|
||||
}
|
||||
}
|
||||
m_isScanningNetworks = false;
|
||||
Q_EMIT networksChanged();
|
||||
Q_EMIT isScanningNetworksChanged();
|
||||
|
||||
call->deleteLater();
|
||||
}
|
||||
|
||||
bool ModemDetails::isScanningNetworks()
|
||||
{
|
||||
return m_isScanningNetworks;
|
||||
}
|
||||
|
||||
QString ModemDetails::firmwareVersion()
|
||||
{
|
||||
if (!m_modem->m_nmModem) {
|
||||
return QString{};
|
||||
}
|
||||
return m_modem->m_nmModem->firmwareVersion();
|
||||
}
|
||||
|
||||
QString ModemDetails::interfaceName()
|
||||
{
|
||||
if (!m_modem->m_nmModem) {
|
||||
return QString{};
|
||||
}
|
||||
return m_modem->m_nmModem->interfaceName();
|
||||
}
|
||||
|
||||
QString ModemDetails::metered()
|
||||
{
|
||||
if (!m_modem->m_nmModem) {
|
||||
return QString{};
|
||||
}
|
||||
|
||||
switch (m_modem->m_nmModem->metered()) {
|
||||
case NetworkManager::Device::MeteredStatus::UnknownStatus:
|
||||
return i18n("Unknown");
|
||||
case NetworkManager::Device::MeteredStatus::Yes:
|
||||
return i18n("Yes");
|
||||
case NetworkManager::Device::MeteredStatus::No:
|
||||
return i18n("No");
|
||||
case NetworkManager::Device::MeteredStatus::GuessYes:
|
||||
return i18n("GuessYes");
|
||||
case NetworkManager::Device::MeteredStatus::GuessNo:
|
||||
return i18n("GuessNo");
|
||||
}
|
||||
return QString{};
|
||||
}
|
||||
|
||||
AvailableNetwork::AvailableNetwork(QObject *parent,
|
||||
ModemManager::Modem3gpp::Ptr mm3gppDevice,
|
||||
bool isCurrentlyUsed,
|
||||
QString operatorLong,
|
||||
QString operatorShort,
|
||||
QString operatorCode,
|
||||
MMModemAccessTechnology accessTechnology)
|
||||
: QObject{parent}
|
||||
, m_isCurrentlyUsed{isCurrentlyUsed}
|
||||
, m_operatorLong{operatorLong}
|
||||
, m_operatorShort{operatorShort}
|
||||
, m_operatorCode{operatorCode}
|
||||
, m_accessTechnology{}
|
||||
, m_mm3gppDevice{mm3gppDevice}
|
||||
{
|
||||
switch (accessTechnology) {
|
||||
case MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN:
|
||||
m_accessTechnology = i18n("Unknown");
|
||||
break;
|
||||
case MM_MODEM_ACCESS_TECHNOLOGY_POTS:
|
||||
m_accessTechnology = i18n("POTS");
|
||||
break;
|
||||
case MM_MODEM_ACCESS_TECHNOLOGY_GSM:
|
||||
m_accessTechnology = i18n("2G");
|
||||
break;
|
||||
case MM_MODEM_ACCESS_TECHNOLOGY_GSM_COMPACT:
|
||||
m_accessTechnology = i18n("2G");
|
||||
break;
|
||||
case MM_MODEM_ACCESS_TECHNOLOGY_GPRS:
|
||||
m_accessTechnology = i18n("2G");
|
||||
break;
|
||||
case MM_MODEM_ACCESS_TECHNOLOGY_EDGE:
|
||||
m_accessTechnology = i18n("2G");
|
||||
break;
|
||||
case MM_MODEM_ACCESS_TECHNOLOGY_UMTS:
|
||||
m_accessTechnology = i18n("3G");
|
||||
break;
|
||||
case MM_MODEM_ACCESS_TECHNOLOGY_HSDPA:
|
||||
m_accessTechnology = i18n("3G");
|
||||
break;
|
||||
case MM_MODEM_ACCESS_TECHNOLOGY_HSUPA:
|
||||
m_accessTechnology = i18n("3G");
|
||||
break;
|
||||
case MM_MODEM_ACCESS_TECHNOLOGY_HSPA:
|
||||
m_accessTechnology = i18n("3G");
|
||||
break;
|
||||
case MM_MODEM_ACCESS_TECHNOLOGY_HSPA_PLUS:
|
||||
m_accessTechnology = i18n("3G");
|
||||
break;
|
||||
case MM_MODEM_ACCESS_TECHNOLOGY_1XRTT:
|
||||
m_accessTechnology = i18n("3G");
|
||||
break;
|
||||
case MM_MODEM_ACCESS_TECHNOLOGY_EVDO0:
|
||||
m_accessTechnology = i18n("3G");
|
||||
break;
|
||||
case MM_MODEM_ACCESS_TECHNOLOGY_EVDOA:
|
||||
m_accessTechnology = i18n("3G");
|
||||
break;
|
||||
case MM_MODEM_ACCESS_TECHNOLOGY_EVDOB:
|
||||
m_accessTechnology = i18n("3G");
|
||||
break;
|
||||
case MM_MODEM_ACCESS_TECHNOLOGY_LTE:
|
||||
m_accessTechnology = i18n("4G");
|
||||
break;
|
||||
case MM_MODEM_ACCESS_TECHNOLOGY_5GNR:
|
||||
m_accessTechnology = i18n("5G");
|
||||
break;
|
||||
case MM_MODEM_ACCESS_TECHNOLOGY_ANY:
|
||||
m_accessTechnology = i18n("Any");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool AvailableNetwork::isCurrentlyUsed()
|
||||
{
|
||||
return m_isCurrentlyUsed;
|
||||
}
|
||||
|
||||
QString AvailableNetwork::operatorLong()
|
||||
{
|
||||
return m_operatorLong;
|
||||
}
|
||||
|
||||
QString AvailableNetwork::operatorShort()
|
||||
{
|
||||
return m_operatorShort;
|
||||
}
|
||||
|
||||
QString AvailableNetwork::operatorCode()
|
||||
{
|
||||
return m_operatorCode;
|
||||
}
|
||||
|
||||
QString AvailableNetwork::accessTechnology()
|
||||
{
|
||||
return m_accessTechnology;
|
||||
}
|
||||
|
||||
void AvailableNetwork::registerToNetwork()
|
||||
{
|
||||
if (!m_isCurrentlyUsed && m_mm3gppDevice) {
|
||||
m_mm3gppDevice->registerToNetwork(m_operatorCode);
|
||||
}
|
||||
}
|
||||
181
kcms/cellularnetwork/modemdetails.h
Normal file
181
kcms/cellularnetwork/modemdetails.h
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2021 Devin Lin <espidev@gmail.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "modem.h"
|
||||
#include "sim.h"
|
||||
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
|
||||
#include <NetworkManagerQt/CdmaSetting>
|
||||
#include <NetworkManagerQt/ConnectionSettings>
|
||||
#include <NetworkManagerQt/GsmSetting>
|
||||
#include <NetworkManagerQt/Manager>
|
||||
#include <NetworkManagerQt/ModemDevice>
|
||||
#include <NetworkManagerQt/Settings>
|
||||
|
||||
#include <ModemManagerQt/GenericTypes>
|
||||
#include <ModemManagerQt/Manager>
|
||||
#include <ModemManagerQt/Modem3Gpp>
|
||||
#include <ModemManagerQt/ModemDevice>
|
||||
|
||||
class Modem;
|
||||
class AvailableNetwork;
|
||||
|
||||
class ModemDetails : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
// modemmanager device
|
||||
Q_PROPERTY(QStringList accessTechnologies READ accessTechnologies NOTIFY accessTechnologiesChanged) // currently used tech
|
||||
Q_PROPERTY(QString device READ device NOTIFY deviceChanged)
|
||||
Q_PROPERTY(QString deviceIdentifier READ deviceIdentifier NOTIFY deviceIdentifierChanged)
|
||||
Q_PROPERTY(QStringList drivers READ drivers NOTIFY driversChanged)
|
||||
Q_PROPERTY(QString equipmentIdentifier READ equipmentIdentifier NOTIFY equipmentIdentifierChanged)
|
||||
// TODO add bands
|
||||
Q_PROPERTY(bool isEnabled READ isEnabled NOTIFY isEnabledChanged)
|
||||
Q_PROPERTY(QString manufacturer READ manufacturer NOTIFY manufacturerChanged)
|
||||
Q_PROPERTY(QString model READ model NOTIFY modelChanged)
|
||||
Q_PROPERTY(QStringList ownNumbers READ ownNumbers NOTIFY ownNumbersChanged)
|
||||
Q_PROPERTY(QString plugin READ plugin NOTIFY pluginChanged)
|
||||
Q_PROPERTY(QString powerState READ powerState NOTIFY powerStateChanged)
|
||||
Q_PROPERTY(QString revision READ revision NOTIFY revisionChanged)
|
||||
Q_PROPERTY(uint signalQuality READ signalQuality NOTIFY signalQualityChanged)
|
||||
Q_PROPERTY(QString simPath READ simPath NOTIFY simPathChanged)
|
||||
Q_PROPERTY(QString state READ state NOTIFY stateChanged)
|
||||
Q_PROPERTY(QString stateFailedReason READ stateFailedReason NOTIFY stateFailedReasonChanged)
|
||||
|
||||
// modemmanager 3gpp device
|
||||
Q_PROPERTY(QString operatorCode READ operatorCode NOTIFY operatorCodeChanged)
|
||||
Q_PROPERTY(QString operatorName READ operatorName NOTIFY operatorNameChanged)
|
||||
Q_PROPERTY(QString registrationState READ registrationState NOTIFY registrationStateChanged)
|
||||
Q_PROPERTY(QList<AvailableNetwork *> networks READ networks NOTIFY networksChanged)
|
||||
Q_PROPERTY(bool isScanningNetworks READ isScanningNetworks NOTIFY isScanningNetworksChanged)
|
||||
|
||||
// networkmanager device
|
||||
Q_PROPERTY(QString firmwareVersion READ firmwareVersion NOTIFY firmwareVersionChanged)
|
||||
Q_PROPERTY(QString interfaceName READ interfaceName NOTIFY interfaceNameChanged)
|
||||
Q_PROPERTY(QString metered READ metered NOTIFY meteredChanged)
|
||||
|
||||
public:
|
||||
ModemDetails(QObject *parent = nullptr, Modem *modem = nullptr);
|
||||
ModemDetails &operator=(ModemDetails &&other);
|
||||
void swap(ModemDetails &other);
|
||||
|
||||
QStringList accessTechnologies();
|
||||
QString device();
|
||||
QString deviceIdentifier();
|
||||
QStringList drivers();
|
||||
QString equipmentIdentifier();
|
||||
bool isEnabled();
|
||||
QString manufacturer();
|
||||
uint maxActiveBearers();
|
||||
uint maxBearers();
|
||||
QString model();
|
||||
QStringList ownNumbers();
|
||||
QString plugin();
|
||||
QString powerState();
|
||||
QString revision();
|
||||
uint signalQuality();
|
||||
QString simPath();
|
||||
QString state();
|
||||
QString stateFailedReason();
|
||||
|
||||
QString operatorCode();
|
||||
QString operatorName();
|
||||
QString registrationState();
|
||||
|
||||
Q_INVOKABLE void scanNetworks();
|
||||
QList<AvailableNetwork *> networks();
|
||||
bool isScanningNetworks();
|
||||
void scanNetworksFinished(QDBusPendingCallWatcher *call);
|
||||
|
||||
QString firmwareVersion();
|
||||
QString interfaceName();
|
||||
QString metered();
|
||||
|
||||
Q_SIGNALS:
|
||||
void accessTechnologiesChanged();
|
||||
void deviceChanged();
|
||||
void deviceIdentifierChanged();
|
||||
void driversChanged();
|
||||
void equipmentIdentifierChanged();
|
||||
void isEnabledChanged();
|
||||
void manufacturerChanged();
|
||||
void modelChanged();
|
||||
void ownNumbersChanged();
|
||||
void pluginChanged();
|
||||
void powerStateChanged();
|
||||
void revisionChanged();
|
||||
void signalQualityChanged();
|
||||
void simPathChanged();
|
||||
void stateChanged();
|
||||
void stateFailedReasonChanged();
|
||||
void supportedCapabilitiesChanged();
|
||||
|
||||
void operatorCodeChanged();
|
||||
void operatorNameChanged();
|
||||
void registrationStateChanged();
|
||||
void networksChanged();
|
||||
void isScanningNetworksChanged();
|
||||
|
||||
void firmwareVersionChanged();
|
||||
void interfaceNameChanged();
|
||||
void meteredChanged();
|
||||
|
||||
private:
|
||||
void updateNMSignals();
|
||||
|
||||
Modem *m_modem;
|
||||
|
||||
QDBusPendingCallWatcher *m_scanNetworkWatcher;
|
||||
bool m_isScanningNetworks;
|
||||
QList<AvailableNetwork *> m_cachedScannedNetworks;
|
||||
};
|
||||
|
||||
class AvailableNetwork : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool isCurrentlyUsed READ isCurrentlyUsed NOTIFY isCurrentlyUsedChanged)
|
||||
Q_PROPERTY(QString operatorLong READ operatorLong NOTIFY operatorLongChanged)
|
||||
Q_PROPERTY(QString operatorShort READ operatorShort NOTIFY operatorShortChanged)
|
||||
Q_PROPERTY(QString operatorCode READ operatorCode NOTIFY operatorCodeChanged)
|
||||
Q_PROPERTY(QString accessTechnology READ accessTechnology NOTIFY accessTechnologyChanged)
|
||||
|
||||
public:
|
||||
AvailableNetwork(QObject *parent = nullptr,
|
||||
ModemManager::Modem3gpp::Ptr mm3gppDevice = nullptr,
|
||||
bool isCurrentlyUsed = false,
|
||||
QString operatorLong = "",
|
||||
QString operatorShort = "",
|
||||
QString operatorCode = "",
|
||||
MMModemAccessTechnology accessTechnology = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN);
|
||||
|
||||
bool isCurrentlyUsed();
|
||||
QString operatorLong();
|
||||
QString operatorShort();
|
||||
QString operatorCode();
|
||||
QString accessTechnology();
|
||||
|
||||
Q_INVOKABLE void registerToNetwork();
|
||||
|
||||
Q_SIGNALS:
|
||||
void isCurrentlyUsedChanged();
|
||||
void operatorLongChanged();
|
||||
void operatorShortChanged();
|
||||
void operatorCodeChanged();
|
||||
void accessTechnologyChanged();
|
||||
|
||||
private:
|
||||
bool m_isCurrentlyUsed;
|
||||
QString m_operatorLong;
|
||||
QString m_operatorShort;
|
||||
QString m_operatorCode;
|
||||
QString m_accessTechnology;
|
||||
|
||||
ModemManager::Modem3gpp::Ptr m_mm3gppDevice; // this may be a nullptr if no sim is inserted
|
||||
};
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2021 Devin Lin <espidev@gmail.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Layouts 1.2
|
||||
import QtQuick.Controls 2.12 as Controls
|
||||
import org.kde.kirigami 2.12 as Kirigami
|
||||
import org.kde.kcm 1.2
|
||||
import cellularnetworkkcm 1.0
|
||||
|
||||
Kirigami.ScrollablePage {
|
||||
id: root
|
||||
title: i18n("Available Networks")
|
||||
|
||||
property Modem modem
|
||||
property Sim sim
|
||||
|
||||
ListView {
|
||||
id: listView
|
||||
header: ColumnLayout {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
spacing: 0
|
||||
|
||||
MessagesList {
|
||||
visible: count != 0
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: Kirigami.Units.largeSpacing
|
||||
model: kcm.messages
|
||||
}
|
||||
}
|
||||
|
||||
Kirigami.PlaceholderMessage {
|
||||
anchors.centerIn: parent
|
||||
visible: !modem.details.isScanningNetworks && listView.count == 0
|
||||
icon.name: "network-mobile-100"
|
||||
text: i18n("Current operator: %1", modem.details.operatorName ? modem.details.operatorName : i18n("none"))
|
||||
helpfulAction: Kirigami.Action {
|
||||
icon.name: "view-refresh"
|
||||
text: i18n("Scan For Networks")
|
||||
enabled: !modem.details.isScanningNetworks
|
||||
onTriggered: modem.details.scanNetworks()
|
||||
}
|
||||
}
|
||||
|
||||
Controls.BusyIndicator {
|
||||
anchors.centerIn: parent
|
||||
visible: modem.details.isScanningNetworks
|
||||
implicitWidth: Kirigami.Units.iconSizes.large
|
||||
implicitHeight: implicitWidth
|
||||
}
|
||||
|
||||
model: modem.details.networks
|
||||
|
||||
delegate: Kirigami.SwipeListItem {
|
||||
onClicked: {
|
||||
if (!modelData.isCurrentlyUsed) {
|
||||
modelData.registerToNetwork();
|
||||
modem.details.scanNetworks();
|
||||
}
|
||||
}
|
||||
|
||||
contentItem: RowLayout {
|
||||
Layout.fillWidth: true
|
||||
|
||||
ColumnLayout {
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
Kirigami.Heading {
|
||||
level: 3
|
||||
text: modelData.operatorLong + " | " + modelData.operatorShort + "(" + modelData.operatorCode + ")"
|
||||
}
|
||||
Controls.Label {
|
||||
text: modelData.accessTechnology
|
||||
}
|
||||
}
|
||||
Controls.RadioButton {
|
||||
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
||||
checked: modelData.isCurrentlyUsed
|
||||
onClicked: {
|
||||
if (!modelData.isCurrentlyUsed) {
|
||||
modelData.registerToNetwork();
|
||||
modem.details.scanNetworks();
|
||||
}
|
||||
checked = modelData.isCurrentlyUsed;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
// SPDX-FileCopyrightText: 2020-2022 Devin Lin <espidev@gmail.com>
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Layouts 1.2
|
||||
import QtQuick.Controls 2.12 as Controls
|
||||
|
||||
import org.kde.kirigami 2.19 as Kirigami
|
||||
|
||||
import cellularnetworkkcm 1.0
|
||||
|
||||
Kirigami.Dialog {
|
||||
id: dialog
|
||||
title: i18n("Edit APN")
|
||||
clip: true
|
||||
|
||||
property Modem modem
|
||||
property ProfileSettings profile
|
||||
|
||||
property int pageWidth
|
||||
|
||||
standardButtons: Controls.Dialog.Ok | Controls.Dialog.Cancel
|
||||
|
||||
onAccepted: {
|
||||
if (profile == null) { // create new profile
|
||||
modem.addProfile(profileName.text, profileApn.text, profileUsername.text, profilePassword.text, profileNetworkType.value);
|
||||
} else { // edit existing profile
|
||||
modem.updateProfile(profile.connectionUni, profileName.text, profileApn.text, profileUsername.text, profilePassword.text, profileNetworkType.value);
|
||||
}
|
||||
}
|
||||
preferredWidth: pageWidth - Kirigami.Units.gridUnit * 4
|
||||
padding: Kirigami.Units.gridUnit
|
||||
|
||||
ColumnLayout {
|
||||
Kirigami.FormLayout {
|
||||
Layout.fillWidth: true
|
||||
wideMode: false
|
||||
|
||||
Controls.TextField {
|
||||
id: profileName
|
||||
Kirigami.FormData.label: i18n("Name")
|
||||
text: profile != null ? profile.name : ""
|
||||
}
|
||||
Controls.TextField {
|
||||
id: profileApn
|
||||
Kirigami.FormData.label: i18n("APN")
|
||||
text: profile != null ? profile.apn : ""
|
||||
}
|
||||
Controls.TextField {
|
||||
id: profileUsername
|
||||
Kirigami.FormData.label: i18n("Username")
|
||||
text: profile != null ? profile.user : ""
|
||||
}
|
||||
Controls.TextField {
|
||||
id: profilePassword
|
||||
Kirigami.FormData.label: i18n("Password")
|
||||
text: profile != null ? profile.password : ""
|
||||
}
|
||||
Controls.ComboBox {
|
||||
id: profileNetworkType
|
||||
Kirigami.FormData.label: i18n("Network type")
|
||||
model: [i18n("4G/3G/2G"), i18n("3G/2G"), i18n("2G"), i18n("Only 4G"), i18n("Only 3G"), i18n("Only 2G"), i18n("Any")]
|
||||
Component.onCompleted: {
|
||||
if (profile != null) {
|
||||
currentIndex = indexOfValue(profile.networkType)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
51
kcms/cellularnetwork/package/contents/ui/MessagesList.qml
Normal file
51
kcms/cellularnetwork/package/contents/ui/MessagesList.qml
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2021 Devin Lin <espidev@gmail.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Layouts 1.2
|
||||
import QtQuick.Controls 2.12 as Controls
|
||||
|
||||
import org.kde.kirigami 2.12 as Kirigami
|
||||
|
||||
import cellularnetworkkcm 1.0
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
|
||||
property var model
|
||||
property alias count: repeater.count
|
||||
|
||||
spacing: 0
|
||||
visible: count > 0
|
||||
|
||||
Repeater {
|
||||
id: repeater
|
||||
model: root.model
|
||||
|
||||
delegate: Kirigami.InlineMessage {
|
||||
Layout.bottomMargin: Kirigami.Units.largeSpacing
|
||||
Layout.fillWidth: true
|
||||
visible: true
|
||||
text: modelData.message
|
||||
type: {
|
||||
switch (modelData.type) {
|
||||
case InlineMessage.Information: return Kirigami.MessageType.Information;
|
||||
case InlineMessage.Positive: return Kirigami.MessageType.Positive;
|
||||
case InlineMessage.Warning: return Kirigami.MessageType.Warning;
|
||||
case InlineMessage.Error: return Kirigami.MessageType.Error;
|
||||
}
|
||||
return Kirigami.MessageType.Error;
|
||||
}
|
||||
|
||||
actions: [
|
||||
Kirigami.Action {
|
||||
icon.name: "dialog-close"
|
||||
onTriggered: kcm.removeMessage(model.index)
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
309
kcms/cellularnetwork/package/contents/ui/ModemPage.qml
Normal file
309
kcms/cellularnetwork/package/contents/ui/ModemPage.qml
Normal file
|
|
@ -0,0 +1,309 @@
|
|||
// SPDX-FileCopyrightText: 2021-2022 Devin Lin <espidev@gmail.com>
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Layouts 1.2
|
||||
import QtQuick.Controls 2.12 as Controls
|
||||
|
||||
import org.kde.kirigami 2.19 as Kirigami
|
||||
import org.kde.kcm 1.2
|
||||
import org.kde.kirigamiaddons.labs.mobileform 0.1 as MobileForm
|
||||
|
||||
import cellularnetworkkcm 1.0
|
||||
|
||||
Kirigami.ScrollablePage {
|
||||
id: modemPage
|
||||
title: i18n("Modem %1", modem.displayId)
|
||||
|
||||
leftPadding: 0
|
||||
rightPadding: 0
|
||||
topPadding: Kirigami.Units.gridUnit
|
||||
bottomPadding: Kirigami.Units.gridUnit
|
||||
|
||||
property Modem modem
|
||||
property bool showExtra: false
|
||||
|
||||
ColumnLayout {
|
||||
MessagesList {
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: Kirigami.Units.smallSpacing
|
||||
visible: count != 0
|
||||
model: kcm.messages
|
||||
}
|
||||
|
||||
MobileForm.FormCard {
|
||||
Layout.fillWidth: true
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
spacing: 0
|
||||
|
||||
MobileForm.FormCardHeader {
|
||||
title: i18n("Modem Control")
|
||||
}
|
||||
|
||||
MobileForm.AbstractFormDelegate {
|
||||
id: modemRestartButton
|
||||
Layout.fillWidth: true
|
||||
contentItem: RowLayout {
|
||||
Controls.Label {
|
||||
Layout.fillWidth: true
|
||||
text: i18n("Modem Restart")
|
||||
}
|
||||
Controls.Button {
|
||||
text: i18n("Force Modem Restart")
|
||||
onClicked: modem.reset()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MobileForm.FormCard {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: Kirigami.Units.largeSpacing
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
spacing: 0
|
||||
|
||||
MobileForm.FormCardHeader {
|
||||
title: i18n("Modem Details")
|
||||
}
|
||||
|
||||
MobileForm.AbstractFormDelegate {
|
||||
id: accessTechnologiesText
|
||||
Layout.fillWidth: true
|
||||
|
||||
background: Item {}
|
||||
contentItem: ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
Controls.Label {
|
||||
Layout.fillWidth: true
|
||||
text: i18n("Access Technologies")
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
Repeater {
|
||||
model: modem.details.accessTechnologies
|
||||
Controls.Label {
|
||||
Layout.fillWidth: true
|
||||
text: modelData
|
||||
color: Kirigami.Theme.disabledTextColor
|
||||
font: Kirigami.Theme.smallFont
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator {}
|
||||
|
||||
MobileForm.FormTextDelegate {
|
||||
id: imeiText
|
||||
text: i18n("IMEI")
|
||||
description: modem.details.equipmentIdentifier
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator {}
|
||||
|
||||
MobileForm.FormTextDelegate {
|
||||
id: enabledText
|
||||
text: i18n("Enabled")
|
||||
description: modem.details.isEnabled
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator {}
|
||||
|
||||
MobileForm.FormTextDelegate {
|
||||
id: manufacturerText
|
||||
text: i18n("Manufacturer")
|
||||
description: modem.details.manufacturer
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator {}
|
||||
|
||||
MobileForm.FormTextDelegate {
|
||||
id: modelText
|
||||
text: i18n("Model")
|
||||
description: modem.details.model
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator {}
|
||||
|
||||
MobileForm.AbstractFormDelegate {
|
||||
id: ownedNumbersText
|
||||
Layout.fillWidth: true
|
||||
|
||||
background: Item {}
|
||||
contentItem: ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
Controls.Label {
|
||||
Layout.fillWidth: true
|
||||
text: i18n("Owned Numbers:")
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
Repeater {
|
||||
model: modem.details.ownNumbers
|
||||
Controls.Label {
|
||||
Layout.fillWidth: true
|
||||
text: modelData
|
||||
color: Kirigami.Theme.disabledTextColor
|
||||
font: Kirigami.Theme.smallFont
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator {}
|
||||
|
||||
MobileForm.FormTextDelegate {
|
||||
id: revisionText
|
||||
text: i18n("Revision")
|
||||
description: modem.details.revision
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator {}
|
||||
|
||||
MobileForm.FormTextDelegate {
|
||||
id: signalQualityText
|
||||
text: i18n("Signal Quality")
|
||||
description: modem.details.signalQuality
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator {}
|
||||
|
||||
MobileForm.FormTextDelegate {
|
||||
id: stateText
|
||||
text: i18n("State")
|
||||
description: modem.details.state
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator {}
|
||||
|
||||
MobileForm.FormTextDelegate {
|
||||
id: failureReasonText
|
||||
text: i18n("Failure Reason")
|
||||
description: modem.details.stateFailedReason
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator {}
|
||||
|
||||
MobileForm.FormTextDelegate {
|
||||
id: registrationStateText
|
||||
text: i18n("Registration State")
|
||||
description: modem.details.registrationState
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator {}
|
||||
|
||||
MobileForm.FormTextDelegate {
|
||||
id: roamingText
|
||||
text: i18n("Roaming")
|
||||
description: modem.isRoaming ? i18n("Yes") : i18n("No")
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator {}
|
||||
|
||||
MobileForm.FormTextDelegate {
|
||||
id: firmwareVersionText
|
||||
text: i18n("Firmware Version")
|
||||
description: modem.details.firmwareVersion
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator {}
|
||||
|
||||
MobileForm.FormTextDelegate {
|
||||
id: interfaceNameText
|
||||
text: i18n("Interface Name")
|
||||
description: modem.details.interfaceName
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator {}
|
||||
|
||||
MobileForm.FormTextDelegate {
|
||||
id: meteredText
|
||||
text: i18n("Metered")
|
||||
description: modem.details.metered
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator {}
|
||||
|
||||
MobileForm.FormTextDelegate {
|
||||
id: activeNMConnectionText
|
||||
text: i18n("Active NetworkManager Connection")
|
||||
description: modem.activeConnectionUni
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator {}
|
||||
|
||||
MobileForm.FormTextDelegate {
|
||||
id: deviceText
|
||||
text: i18n("Device")
|
||||
description: modem.details.device
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator {}
|
||||
|
||||
MobileForm.FormTextDelegate {
|
||||
id: deviceIdText
|
||||
text: i18n("Device ID")
|
||||
description: modem.details.deviceIdentifier
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator {}
|
||||
|
||||
MobileForm.AbstractFormDelegate {
|
||||
id: driversText
|
||||
Layout.fillWidth: true
|
||||
|
||||
background: Item {}
|
||||
contentItem: ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
Controls.Label {
|
||||
Layout.fillWidth: true
|
||||
text: i18n("Drivers:")
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
Repeater {
|
||||
model: modem.details.drivers
|
||||
Controls.Label {
|
||||
Layout.fillWidth: true
|
||||
text: modelData
|
||||
color: Kirigami.Theme.disabledTextColor
|
||||
font: Kirigami.Theme.smallFont
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator {}
|
||||
|
||||
MobileForm.FormTextDelegate {
|
||||
id: pluginText
|
||||
text: i18n("Plugin")
|
||||
description: modem.details.plugin
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator {}
|
||||
|
||||
MobileForm.FormTextDelegate {
|
||||
id: powerStateText
|
||||
text: i18n("Power State")
|
||||
description: modem.details.powerState
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator {}
|
||||
|
||||
MobileForm.FormTextDelegate {
|
||||
id: simPathText
|
||||
text: i18n("SIM Path")
|
||||
description: modem.details.simPath
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
103
kcms/cellularnetwork/package/contents/ui/PopupDialog.qml
Normal file
103
kcms/cellularnetwork/package/contents/ui/PopupDialog.qml
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2021 Devin Lin <espidev@gmail.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Layouts 1.2
|
||||
import QtQuick.Controls 2.15 as Controls
|
||||
import QtGraphicalEffects 1.12
|
||||
import org.kde.kirigami 2.12 as Kirigami
|
||||
|
||||
Controls.Dialog {
|
||||
id: dialog
|
||||
|
||||
anchors.centerIn: Controls.Overlay.overlay
|
||||
modal: true
|
||||
padding: Kirigami.Units.smallSpacing
|
||||
closePolicy: Controls.Popup.CloseOnEscape | Controls.Popup.CloseOnReleaseOutside
|
||||
|
||||
property int translateY: (1 - opacity) * Kirigami.Units.gridUnit * 2
|
||||
|
||||
NumberAnimation on opacity {
|
||||
from: 0; to: 1;
|
||||
duration: Kirigami.Units.veryShortDuration
|
||||
easing.type: Easing.InOutQuad
|
||||
running: true
|
||||
}
|
||||
|
||||
contentItem.transform: Translate { y: dialog.translateY }
|
||||
footer.transform: Translate { y: dialog.translateY }
|
||||
|
||||
header: Item {
|
||||
transform: Translate { y: dialog.translateY }
|
||||
implicitHeight: heading.implicitHeight + Kirigami.Units.largeSpacing * 2
|
||||
|
||||
Kirigami.Heading {
|
||||
id: heading
|
||||
level: 2
|
||||
text: dialog.title
|
||||
elide: Text.ElideRight
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.leftMargin: Kirigami.Units.largeSpacing
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
// use tooltip for long text that is elided
|
||||
Controls.ToolTip.visible: truncated && titleHoverHandler.hovered
|
||||
Controls.ToolTip.text: dialog.title
|
||||
HoverHandler {
|
||||
id: titleHoverHandler
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
background: Item {
|
||||
transform: Translate { y: dialog.translateY }
|
||||
|
||||
RectangularGlow {
|
||||
anchors.fill: rect
|
||||
anchors.topMargin: 1
|
||||
cornerRadius: rect.radius * 2
|
||||
glowRadius: 2
|
||||
spread: 0.2
|
||||
color: Qt.rgba(0, 0, 0, 0.3)
|
||||
}
|
||||
Rectangle {
|
||||
id: rect
|
||||
anchors.fill: parent
|
||||
Kirigami.Theme.inherit: false
|
||||
Kirigami.Theme.colorSet: Kirigami.Theme.Window
|
||||
color: Kirigami.Theme.backgroundColor
|
||||
radius: Kirigami.Units.smallSpacing
|
||||
|
||||
Kirigami.Separator {
|
||||
id: topSeparator
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: dialog.header.implicitHeight
|
||||
}
|
||||
|
||||
Kirigami.Separator {
|
||||
id: bottomSeparator
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: dialog.footer.implicitHeight
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Kirigami.Theme.inherit: false
|
||||
Kirigami.Theme.colorSet: Kirigami.Theme.View
|
||||
color: Kirigami.Theme.backgroundColor
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: topSeparator.bottom
|
||||
anchors.bottom: bottomSeparator.top
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
183
kcms/cellularnetwork/package/contents/ui/ProfileList.qml
Normal file
183
kcms/cellularnetwork/package/contents/ui/ProfileList.qml
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2020-2021 Devin Lin <espidev@gmail.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Layouts 1.2
|
||||
import QtQuick.Controls 2.12 as Controls
|
||||
import org.kde.kirigami 2.12 as Kirigami
|
||||
import cellularnetworkkcm 1.0
|
||||
|
||||
Kirigami.ScrollablePage {
|
||||
id: apnlist
|
||||
title: i18n("APNs")
|
||||
|
||||
property Modem modem
|
||||
|
||||
ListView {
|
||||
id: profileListView
|
||||
model: modem.profiles
|
||||
|
||||
Kirigami.PlaceholderMessage {
|
||||
anchors.centerIn: parent
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.margins: Kirigami.Units.largeSpacing
|
||||
visible: profileListView.count === 0
|
||||
text: i18n("No APNs configured")
|
||||
icon.name: "globe"
|
||||
|
||||
helpfulAction: Kirigami.Action {
|
||||
iconName: "list-add"
|
||||
text: i18n("Add Connection")
|
||||
onTriggered: {
|
||||
profileDialog.profile = null;
|
||||
profileDialog.open();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EditProfileDialog {
|
||||
id: profileDialog
|
||||
modem: apnlist.modem
|
||||
profile: null
|
||||
pageWidth: apnlist.width
|
||||
}
|
||||
|
||||
header: ColumnLayout {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
spacing: 0
|
||||
|
||||
MessagesList {
|
||||
id: messagesList
|
||||
visible: count != 0
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: Kirigami.Units.largeSpacing
|
||||
model: kcm.messages
|
||||
}
|
||||
|
||||
Kirigami.InlineMessage {
|
||||
id: cannotFindWarning
|
||||
Layout.margins: visible ? Kirigami.Units.largeSpacing : 0
|
||||
Layout.topMargin: visible && !messagesList.visible ? Kirigami.Units.largeSpacing : 0
|
||||
Layout.fillWidth: true
|
||||
|
||||
visible: false
|
||||
type: Kirigami.MessageType.Warning
|
||||
showCloseButton: true
|
||||
text: qsTr("Unable to autodetect connection settings for your carrier. Please find your carrier's APN settings by either contacting support or searching online.")
|
||||
|
||||
Connections {
|
||||
target: modem
|
||||
function onCouldNotAutodetectSettings() {
|
||||
cannotFindWarning.visible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Kirigami.SwipeListItem {
|
||||
Layout.fillWidth: true
|
||||
visible: profileListView.count !== 0
|
||||
onClicked: {
|
||||
profileDialog.profile = null;
|
||||
profileDialog.open();
|
||||
}
|
||||
|
||||
contentItem: Row {
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
Kirigami.Icon {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
source: "list-add"
|
||||
height: Kirigami.Units.gridUnit * 1.5
|
||||
width: height
|
||||
}
|
||||
Kirigami.Heading {
|
||||
level: 3
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
text: i18n("Add APN")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Kirigami.SwipeListItem {
|
||||
Layout.fillWidth: true
|
||||
onClicked: {
|
||||
modem.addDetectedProfileSettings();
|
||||
}
|
||||
|
||||
contentItem: Row {
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
Kirigami.Icon {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
source: "list-add"
|
||||
height: Kirigami.Units.gridUnit * 1.5
|
||||
width: height
|
||||
}
|
||||
Kirigami.Heading {
|
||||
level: 3
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
text: i18n("Autodetect APN")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delegate: Kirigami.SwipeListItem {
|
||||
onClicked: modem.activateProfile(modelData.connectionUni)
|
||||
|
||||
actions: [
|
||||
Kirigami.Action {
|
||||
iconName: "entry-edit"
|
||||
text: i18n("Edit")
|
||||
onTriggered: {
|
||||
profileDialog.profile = modelData;
|
||||
profileDialog.open();
|
||||
}
|
||||
},
|
||||
Kirigami.Action {
|
||||
iconName: "delete"
|
||||
text: i18n("Delete")
|
||||
onTriggered: modem.removeProfile(modelData.connectionUni)
|
||||
}
|
||||
]
|
||||
|
||||
contentItem: RowLayout {
|
||||
Layout.fillWidth: true
|
||||
|
||||
Controls.RadioButton {
|
||||
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
|
||||
checked: modem.activeConnectionUni == modelData.connectionUni
|
||||
onClicked: {
|
||||
if (!checked) {
|
||||
modem.activateProfile(modelData.connectionUni);
|
||||
}
|
||||
|
||||
// reapply binding
|
||||
checked = Qt.binding(() => { return modem.activeConnectionUni == modelData.connectionUni });
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
Layout.fillWidth: true
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
|
||||
Kirigami.Heading {
|
||||
Layout.fillWidth: true
|
||||
level: 3
|
||||
text: modelData.name
|
||||
}
|
||||
Controls.Label {
|
||||
Layout.fillWidth: true
|
||||
text: modelData.apn
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
249
kcms/cellularnetwork/package/contents/ui/SimLockPage.qml
Normal file
249
kcms/cellularnetwork/package/contents/ui/SimLockPage.qml
Normal file
|
|
@ -0,0 +1,249 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2021 Devin Lin <espidev@gmail.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Layouts 1.2
|
||||
import QtQuick.Controls 2.12 as Controls
|
||||
|
||||
import org.kde.kirigami 2.19 as Kirigami
|
||||
import org.kde.kcm 1.2
|
||||
import org.kde.kirigamiaddons.labs.mobileform 0.1 as MobileForm
|
||||
|
||||
import cellularnetworkkcm 1.0
|
||||
|
||||
Kirigami.ScrollablePage {
|
||||
id: root
|
||||
title: i18n("SIM Lock")
|
||||
|
||||
leftPadding: 0
|
||||
rightPadding: 0
|
||||
topPadding: Kirigami.Units.gridUnit
|
||||
bottomPadding: Kirigami.Units.gridUnit
|
||||
|
||||
property Sim sim
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 0
|
||||
width: root.width
|
||||
|
||||
MessagesList {
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: Kirigami.Units.largeSpacing
|
||||
model: kcm.messages
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: unlockSimPlaceholder
|
||||
visible: sim.locked
|
||||
Layout.fillWidth: true
|
||||
|
||||
// HACK: prevent infinite binding loop?
|
||||
Component.onCompleted: unlockSimPlaceholder.Layout.preferredHeight = root.height
|
||||
|
||||
Kirigami.PlaceholderMessage {
|
||||
Layout.margins: Kirigami.Units.gridUnit * 2
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
text: i18n("SIM is locked")
|
||||
explanation: i18n("In order to use this SIM, you must first unlock it.")
|
||||
icon.name: "lock"
|
||||
helpfulAction: Kirigami.Action {
|
||||
icon.name: "unlock"
|
||||
text: "Unlock SIM"
|
||||
onTriggered: unlockPinDialog.open() // TODO replace custom unlock pin dialog with just opening the system unlock PIN dialog
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: notLockedSimPlaceholder
|
||||
visible: !sim.pinEnabled && !unlockSimPlaceholder.visible
|
||||
Layout.fillWidth: true
|
||||
|
||||
// HACK: prevent infinite binding loop?
|
||||
Component.onCompleted: notLockedSimPlaceholder.Layout.preferredHeight = root.height
|
||||
|
||||
Kirigami.PlaceholderMessage {
|
||||
Layout.margins: Kirigami.Units.gridUnit * 2
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
text: i18n("SIM is not locked")
|
||||
explanation: i18n("You can lock your SIM to require a set PIN code for phone calls and mobile data.")
|
||||
icon.name: "unlock"
|
||||
helpfulAction: Kirigami.Action {
|
||||
icon.name: "lock"
|
||||
text: i18n("Lock SIM")
|
||||
onTriggered: createPinDialog.open()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MobileForm.FormCard {
|
||||
visible: !notLockedSimPlaceholder.visible && !unlockSimPlaceholder.visible
|
||||
Layout.fillWidth: true
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
spacing: 0
|
||||
MobileForm.FormButtonDelegate {
|
||||
id: disableSimLockButton
|
||||
text: i18n("Disable SIM Lock")
|
||||
description: i18n("Disable the SIM lock feature and remove the passcode on the SIM.")
|
||||
onClicked: removePinDialog.open();
|
||||
}
|
||||
|
||||
Kirigami.Separator {
|
||||
Layout.leftMargin: Kirigami.Units.largeSpacing
|
||||
Layout.rightMargin: Kirigami.Units.largeSpacing
|
||||
Layout.fillWidth: true
|
||||
opacity: (!disableSimLockButton.controlHovered && !changePinButton.controlHovered) ? 0.5 : 0
|
||||
}
|
||||
|
||||
MobileForm.FormButtonDelegate {
|
||||
id: changePinButton
|
||||
text: i18n("Change PIN")
|
||||
description: i18n("Change the passcode set on the SIM.")
|
||||
onClicked: changePinDialog.open()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// dialogs
|
||||
|
||||
RegExpValidator {
|
||||
id: pinValidator
|
||||
regExp: /[0-9]+/
|
||||
}
|
||||
|
||||
Kirigami.Dialog {
|
||||
id: unlockPinDialog
|
||||
title: i18n("Unlock SIM")
|
||||
standardButtons: Controls.Dialog.Ok | Controls.Dialog.Cancel
|
||||
padding: Kirigami.Units.largeSpacing
|
||||
|
||||
onAccepted: sim.sendPin(unlockPinCurPin.text)
|
||||
|
||||
ColumnLayout {
|
||||
Controls.Label {
|
||||
text: i18n("Attempts left: %1", sim.unlockRetriesLeft)
|
||||
}
|
||||
Kirigami.PasswordField {
|
||||
id: unlockPinCurPin
|
||||
placeholderText: i18n("Enter PIN")
|
||||
validator: pinValidator
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Kirigami.Dialog {
|
||||
id: changePinDialog
|
||||
title: i18n("Change SIM PIN")
|
||||
standardButtons: isValid ? Controls.Dialog.Ok | Controls.Dialog.Cancel : Controls.Dialog.Cancel
|
||||
padding: Kirigami.Units.largeSpacing
|
||||
|
||||
property bool isValid: changePinNewPin.text == changePinConfirmPin.text &&
|
||||
changePinNewPin.text.length >= 4 && changePinNewPin.text.length <= 8 // SIM PINs are between 4-8 digits
|
||||
|
||||
onAccepted: {
|
||||
if (isValid) {
|
||||
sim.changePin(changePinCurPin.text, changePinNewPin.text);
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
Kirigami.InlineMessage {
|
||||
id: changePinMatch
|
||||
Layout.fillWidth: true
|
||||
visible: changePinNewPin.text != changePinConfirmPin.text
|
||||
text: i18n("PINs don't match!")
|
||||
type: Kirigami.MessageType.Error
|
||||
}
|
||||
Kirigami.InlineMessage {
|
||||
Layout.fillWidth: true
|
||||
visible: !changePinMatch.visible && changePinNewPin.text.length != 0 && (changePinNewPin.text.length < 4 || changePinNewPin.text.length > 8)
|
||||
text: i18n("PINs must be between 4 and 8 digits!")
|
||||
type: Kirigami.MessageType.Error
|
||||
}
|
||||
Kirigami.PasswordField {
|
||||
id: changePinCurPin
|
||||
placeholderText: i18n("Current PIN")
|
||||
validator: pinValidator
|
||||
}
|
||||
Kirigami.PasswordField {
|
||||
id: changePinNewPin
|
||||
placeholderText: i18n("New PIN")
|
||||
validator: pinValidator
|
||||
}
|
||||
Kirigami.PasswordField {
|
||||
id: changePinConfirmPin
|
||||
placeholderText: i18n("Confirm PIN")
|
||||
validator: pinValidator
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Kirigami.Dialog {
|
||||
id: removePinDialog
|
||||
title: i18n("Remove SIM PIN")
|
||||
standardButtons: Controls.Dialog.Ok | Controls.Dialog.Cancel
|
||||
padding: Kirigami.Units.largeSpacing
|
||||
|
||||
onAccepted: sim.togglePinEnabled(removePinCurPin.text);
|
||||
|
||||
ColumnLayout {
|
||||
Kirigami.PasswordField {
|
||||
id: removePinCurPin
|
||||
placeholderText: i18n("Current PIN")
|
||||
validator: pinValidator
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Kirigami.Dialog {
|
||||
id: createPinDialog
|
||||
title: i18n("Add SIM PIN")
|
||||
standardButtons: isValid ? Controls.Dialog.Ok | Controls.Dialog.Cancel : Controls.Dialog.Cancel
|
||||
padding: Kirigami.Units.largeSpacing
|
||||
|
||||
property bool isValid: createPinNewPin.text == createPinConfirmPin.text &&
|
||||
createPinNewPin.text.length >= 4 && createPinNewPin.text.length <= 8 // SIM PINs are between 4-8 digits
|
||||
|
||||
onAccepted: {
|
||||
if (isValid) {
|
||||
sim.togglePinEnabled(createPinNewPin.text);
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
Kirigami.InlineMessage {
|
||||
id: createPinMatch
|
||||
Layout.fillWidth: true
|
||||
visible: createPinNewPin.text != createPinConfirmPin.text
|
||||
text: i18n("PINs don't match!")
|
||||
type: Kirigami.MessageType.Error
|
||||
}
|
||||
Kirigami.InlineMessage {
|
||||
Layout.fillWidth: true
|
||||
visible: !createPinMatch.visible && createPinNewPin.text.length != 0 && (createPinNewPin.text.length < 4 || createPinNewPin.text.length > 8)
|
||||
text: i18n("PINs must be between 4 and 8 digits!")
|
||||
type: Kirigami.MessageType.Error
|
||||
}
|
||||
Kirigami.PasswordField {
|
||||
id: createPinNewPin
|
||||
placeholderText: i18n("New PIN")
|
||||
validator: pinValidator
|
||||
}
|
||||
Kirigami.PasswordField {
|
||||
id: createPinConfirmPin
|
||||
placeholderText: i18n("Confirm PIN")
|
||||
validator: pinValidator
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
230
kcms/cellularnetwork/package/contents/ui/SimPage.qml
Normal file
230
kcms/cellularnetwork/package/contents/ui/SimPage.qml
Normal file
|
|
@ -0,0 +1,230 @@
|
|||
// SPDX-FileCopyrightText: 2022 Devin Lin <espidev@gmail.com>
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Layouts 1.2
|
||||
import QtQuick.Controls 2.12 as Controls
|
||||
|
||||
import org.kde.kirigami 2.12 as Kirigami
|
||||
import org.kde.plasma.networkmanagement 0.2 as PlasmaNM
|
||||
import org.kde.kcm 1.2
|
||||
import org.kde.kirigamiaddons.labs.mobileform 0.1 as MobileForm
|
||||
|
||||
import cellularnetworkkcm 1.0
|
||||
|
||||
Kirigami.ScrollablePage {
|
||||
id: simPage
|
||||
title: i18n("SIM") + " " + displayId
|
||||
|
||||
property Sim sim: null
|
||||
|
||||
property string displayId: sim ? sim.displayId : ""
|
||||
property bool simEnabled: sim ? sim.enabled : false
|
||||
property bool isRoaming: sim ? (sim.modem ? sim.modem.isRoaming : false) : false
|
||||
|
||||
property bool simLocked: sim ? sim.locked : false
|
||||
property string simImsi: sim ? sim.imsi : ""
|
||||
property string simEid: sim ? sim.eid : ""
|
||||
property string operatorCode: sim ? (sim.modem ? sim.modem.details.operatorCode : "") : ""
|
||||
property string operatorName: sim ? (sim.modem ? sim.modem.details.operatorName : "") : ""
|
||||
property string simOperatorIdentifier: sim ? sim.operatorIdentifier : ""
|
||||
property string simOperatorName: sim ? sim.operatorName : ""
|
||||
property string simIdentifier: sim ? sim.simIdentifier : ""
|
||||
property var simEmergencyNumbers: sim ? sim.emergencyNumbers : []
|
||||
|
||||
leftPadding: 0
|
||||
rightPadding: 0
|
||||
topPadding: Kirigami.Units.gridUnit
|
||||
bottomPadding: Kirigami.Units.gridUnit
|
||||
|
||||
PlasmaNM.EnabledConnections {
|
||||
id: enabledConnections
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 0
|
||||
width: simPage.width
|
||||
|
||||
Kirigami.InlineMessage {
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: Kirigami.Units.largeSpacing
|
||||
Layout.bottomMargin: visible && !messagesList.visible ? Kirigami.Units.largeSpacing : 0
|
||||
visible: !simEnabled
|
||||
type: Kirigami.MessageType.Error
|
||||
text: qsTr("This SIM slot is empty, a SIM card needs to be inserted in order for it to be used.")
|
||||
}
|
||||
|
||||
MessagesList {
|
||||
id: messagesList
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: Kirigami.Units.largeSpacing
|
||||
model: kcm.messages
|
||||
}
|
||||
|
||||
MobileForm.FormCard {
|
||||
Layout.fillWidth: true
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
spacing: 0
|
||||
|
||||
MobileForm.FormSwitchDelegate {
|
||||
id: dataRoamingCheckBox
|
||||
text: i18n("Data Roaming")
|
||||
description: i18n("Allow your device to use networks other than your carrier.")
|
||||
enabled: simEnabled
|
||||
checked: isRoaming
|
||||
onCheckedChanged: sim.modem.isRoaming = checked
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator { above: dataRoamingCheckBox; below: apnButton }
|
||||
|
||||
MobileForm.FormButtonDelegate {
|
||||
id: apnButton
|
||||
icon.name: "globe"
|
||||
text: i18n("Modify APNs")
|
||||
description: i18n("Configure access point names for your carrier.")
|
||||
enabled: simEnabled && enabledConnections.wwanEnabled
|
||||
onClicked: kcm.push("ProfileList.qml", { "modem": sim.modem });
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator { above: apnButton; below: networksButton }
|
||||
|
||||
MobileForm.FormButtonDelegate {
|
||||
id: networksButton
|
||||
icon.name: "network-mobile-available"
|
||||
text: i18n("Networks")
|
||||
description: i18n("Select a network operator.")
|
||||
enabled: simEnabled
|
||||
onClicked: kcm.push("AvailableNetworks.qml", { "modem": sim.modem, "sim": sim });
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator { above: networksButton; below: simLockButton }
|
||||
|
||||
MobileForm.FormButtonDelegate {
|
||||
id: simLockButton
|
||||
icon.name: "unlock"
|
||||
text: i18n("SIM Lock")
|
||||
description: i18n("Modify SIM lock settings.")
|
||||
enabled: simEnabled
|
||||
onClicked: kcm.push("SimLockPage.qml", { "sim": sim });
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator { above: simLockButton; below: modemDetailsButton }
|
||||
|
||||
MobileForm.FormButtonDelegate {
|
||||
id: modemDetailsButton
|
||||
icon.name: "network-modem"
|
||||
text: i18n("Modem Details")
|
||||
description: i18n("View the details of the modem this SIM is connected to.")
|
||||
onClicked: kcm.push("ModemPage.qml", { "modem": sim.modem })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MobileForm.FormCard {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: Kirigami.Units.largeSpacing
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
spacing: 0
|
||||
|
||||
MobileForm.FormCardHeader {
|
||||
title: i18n("SIM Details")
|
||||
}
|
||||
|
||||
MobileForm.FormTextDelegate {
|
||||
id: lockedText
|
||||
text: i18n("Locked")
|
||||
description: simLocked ? i18n("Yes") : i18n("No")
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator {}
|
||||
|
||||
MobileForm.FormTextDelegate {
|
||||
id: imsiText
|
||||
text: i18n("IMSI")
|
||||
description: simImsi
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator {}
|
||||
|
||||
MobileForm.FormTextDelegate {
|
||||
id: eidText
|
||||
text: i18n("EID")
|
||||
description: simEid
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator {}
|
||||
|
||||
MobileForm.FormTextDelegate {
|
||||
id: opCodeModemText
|
||||
text: i18n("Operator Code (modem)")
|
||||
description: operatorCode
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator {}
|
||||
|
||||
MobileForm.FormTextDelegate {
|
||||
id: opNameModemText
|
||||
text: i18n("Operator Name (modem)")
|
||||
description: operatorName
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator {}
|
||||
|
||||
MobileForm.FormTextDelegate {
|
||||
id: opCodeSimText
|
||||
text: i18n("Operator Code (provided by SIM)")
|
||||
description: simOperatorIdentifier
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator {}
|
||||
|
||||
MobileForm.FormTextDelegate {
|
||||
id: opNameSimText
|
||||
text: i18n("Operator Name (provided by SIM)")
|
||||
description: simOperatorName
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator {}
|
||||
|
||||
MobileForm.FormTextDelegate {
|
||||
id: simIdText
|
||||
text: i18n("SIM ID")
|
||||
description: simIdentifier
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator {}
|
||||
|
||||
MobileForm.AbstractFormDelegate {
|
||||
id: emergencyNumbersText
|
||||
Layout.fillWidth: true
|
||||
|
||||
background: Item {}
|
||||
contentItem: ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
|
||||
Controls.Label {
|
||||
Layout.fillWidth: true
|
||||
text: i18n("Emergency Numbers")
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: simEmergencyNumbers
|
||||
|
||||
Controls.Label {
|
||||
Layout.fillWidth: true
|
||||
text: modelData
|
||||
color: Kirigami.Theme.disabledTextColor
|
||||
font: Kirigami.Theme.smallFont
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
167
kcms/cellularnetwork/package/contents/ui/main.qml
Normal file
167
kcms/cellularnetwork/package/contents/ui/main.qml
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
// SPDX-FileCopyrightText: 2018 Martin Kacej <m.kacej@atlas.sk>
|
||||
// SPDX-FileCopyrightText: 2020 Dimitris Kardarakos <dimkard@posteo.net>
|
||||
// SPDX-FileCopyrightText: 2021-2022 Devin Lin <espidev@gmail.com>
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Layouts 1.2
|
||||
import QtQuick.Controls 2.12 as Controls
|
||||
|
||||
import org.kde.plasma.networkmanagement 0.2 as PlasmaNM
|
||||
import org.kde.kirigami 2.19 as Kirigami
|
||||
import org.kde.kcm 1.3 as KCM
|
||||
import org.kde.kirigamiaddons.labs.mobileform 0.1 as MobileForm
|
||||
|
||||
import cellularnetworkkcm 1.0
|
||||
|
||||
KCM.SimpleKCM {
|
||||
id: root
|
||||
objectName: "mobileDataMain"
|
||||
|
||||
leftPadding: 0
|
||||
rightPadding: 0
|
||||
topPadding: Kirigami.Units.gridUnit
|
||||
bottomPadding: Kirigami.Units.gridUnit
|
||||
|
||||
Kirigami.PlaceholderMessage {
|
||||
id: noModem
|
||||
anchors.centerIn: parent
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.margins: Kirigami.Units.largeSpacing
|
||||
|
||||
visible: !enabledConnections.wwanHwEnabled || !availableDevices.modemDeviceAvailable || !kcm.modemFound
|
||||
icon.name: "auth-sim-missing"
|
||||
text: i18n("Modem not available")
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 0
|
||||
width: root.width
|
||||
visible: !noModem.visible
|
||||
|
||||
PlasmaNM.Handler {
|
||||
id: nmHandler
|
||||
}
|
||||
|
||||
PlasmaNM.AvailableDevices {
|
||||
id: availableDevices
|
||||
}
|
||||
|
||||
PlasmaNM.EnabledConnections {
|
||||
id: enabledConnections
|
||||
}
|
||||
|
||||
SimPage {
|
||||
id: simPage
|
||||
visible: false
|
||||
}
|
||||
|
||||
MessagesList {
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: Kirigami.Units.largeSpacing
|
||||
model: kcm.messages
|
||||
}
|
||||
|
||||
MobileForm.FormCard {
|
||||
Layout.fillWidth: true
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
spacing: 0
|
||||
|
||||
MobileForm.FormSwitchDelegate {
|
||||
id: mobileDataSwitch
|
||||
text: i18n("Mobile data")
|
||||
description: {
|
||||
if (!kcm.modemFound) {
|
||||
return "";
|
||||
} else if (!kcm.selectedModem.hasSim) {
|
||||
return i18n("No SIM is inserted.")
|
||||
} if (!kcm.selectedModem.mobileDataSupported) {
|
||||
return i18n("Mobile data is not available with this modem.")
|
||||
} else if (kcm.selectedModem.needsAPNAdded) {
|
||||
return i18n("An APN needs to be configured to have mobile data.");
|
||||
} else {
|
||||
return i18n("Whether mobile data is enabled.");
|
||||
}
|
||||
}
|
||||
|
||||
property bool manuallySet: false
|
||||
property bool shouldBeChecked: kcm.selectedModem && kcm.selectedModem.mobileDataEnabled
|
||||
onShouldBeCheckedChanged: {
|
||||
checked = shouldBeChecked;
|
||||
}
|
||||
|
||||
enabled: kcm.selectedModem.mobileDataSupported && !kcm.selectedModem.needsAPNAdded
|
||||
checked: shouldBeChecked
|
||||
|
||||
onCheckedChanged: {
|
||||
// prevent binding loops
|
||||
if (manuallySet) {
|
||||
manuallySet = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (kcm.selectedModem.mobileDataEnabled != checked) {
|
||||
manuallySet = true;
|
||||
kcm.selectedModem.mobileDataEnabled = checked;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator { above: mobileDataSwitch; below: dataUsageButton }
|
||||
|
||||
MobileForm.FormButtonDelegate {
|
||||
id: dataUsageButton
|
||||
text: i18n("Data Usage")
|
||||
description: i18n("View data usage.")
|
||||
icon.name: "office-chart-bar"
|
||||
|
||||
enabled: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MobileForm.FormCard {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: Kirigami.Units.largeSpacing
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
spacing: 0
|
||||
|
||||
MobileForm.FormCardHeader {
|
||||
title: kcm.sims.count == 1 ? i18n("SIM") : i18n("SIMs")
|
||||
}
|
||||
|
||||
Repeater {
|
||||
id: repeater
|
||||
model: kcm.sims
|
||||
|
||||
delegate: ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
|
||||
Kirigami.Separator {
|
||||
visible: model.index !== 0
|
||||
Layout.leftMargin: Kirigami.Units.largeSpacing
|
||||
Layout.rightMargin: Kirigami.Units.largeSpacing
|
||||
Layout.fillWidth: true
|
||||
opacity: (!(model.index && repeater.itemAt(model.index - 1).controlHovered) && !simDelegate.controlHovered) ? 0.5 : 0
|
||||
}
|
||||
|
||||
MobileForm.FormButtonDelegate {
|
||||
id: simDelegate
|
||||
text: i18n("SIM %1", modelData.displayId)
|
||||
description: i18n("View SIM %1 details.", modelData.displayId)
|
||||
icon.name: "auth-sim-symbolic"
|
||||
onClicked: {
|
||||
simPage.sim = modelData;
|
||||
simPage.visible = true;
|
||||
kcm.push(simPage);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
141
kcms/cellularnetwork/profilesettings.cpp
Normal file
141
kcms/cellularnetwork/profilesettings.cpp
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
// SPDX-FileCopyrightText: 2022 Devin Lin <espidev@gmail.com>
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "profilesettings.h"
|
||||
|
||||
#include <KLocalizedString>
|
||||
|
||||
ProfileSettings::ProfileSettings(QObject *parent,
|
||||
QString name,
|
||||
QString apn,
|
||||
QString user,
|
||||
QString password,
|
||||
NetworkManager::GsmSetting::NetworkType networkType,
|
||||
QString connectionUni)
|
||||
: QObject{parent}
|
||||
, m_name(name)
|
||||
, m_apn(apn)
|
||||
, m_user(user)
|
||||
, m_password(password)
|
||||
, m_networkType(networkTypeStr(networkType))
|
||||
, m_connectionUni(connectionUni)
|
||||
{
|
||||
setParent(parent);
|
||||
}
|
||||
|
||||
ProfileSettings::ProfileSettings(QObject *parent, NetworkManager::Setting::Ptr setting, NetworkManager::Connection::Ptr connection)
|
||||
: QObject{parent}
|
||||
, m_connectionUni(connection->uuid())
|
||||
{
|
||||
setParent(parent);
|
||||
|
||||
NetworkManager::GsmSetting::Ptr gsmSetting = setting.staticCast<NetworkManager::GsmSetting>();
|
||||
|
||||
m_name = connection->name();
|
||||
m_apn = gsmSetting->apn();
|
||||
m_user = gsmSetting->username();
|
||||
m_password = gsmSetting->password();
|
||||
m_networkType = networkTypeStr(gsmSetting->networkType());
|
||||
}
|
||||
|
||||
QString ProfileSettings::name()
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
QString ProfileSettings::apn()
|
||||
{
|
||||
return m_apn;
|
||||
}
|
||||
|
||||
void ProfileSettings::setApn(QString apn)
|
||||
{
|
||||
if (apn != m_apn) {
|
||||
m_apn = apn;
|
||||
Q_EMIT apnChanged();
|
||||
}
|
||||
}
|
||||
|
||||
QString ProfileSettings::user()
|
||||
{
|
||||
return m_user;
|
||||
}
|
||||
|
||||
void ProfileSettings::setUser(QString user)
|
||||
{
|
||||
if (user != m_user) {
|
||||
m_user = user;
|
||||
Q_EMIT userChanged();
|
||||
}
|
||||
}
|
||||
|
||||
QString ProfileSettings::password()
|
||||
{
|
||||
return m_password;
|
||||
}
|
||||
|
||||
void ProfileSettings::setPassword(QString password)
|
||||
{
|
||||
if (password != m_password) {
|
||||
m_password = password;
|
||||
Q_EMIT passwordChanged();
|
||||
}
|
||||
}
|
||||
|
||||
QString ProfileSettings::networkType()
|
||||
{
|
||||
return m_networkType;
|
||||
}
|
||||
|
||||
void ProfileSettings::setNetworkType(QString networkType)
|
||||
{
|
||||
if (networkType != m_networkType) {
|
||||
m_networkType = networkType;
|
||||
Q_EMIT networkTypeChanged();
|
||||
}
|
||||
}
|
||||
|
||||
QString ProfileSettings::connectionUni()
|
||||
{
|
||||
return m_connectionUni;
|
||||
}
|
||||
|
||||
QString ProfileSettings::networkTypeStr(NetworkManager::GsmSetting::NetworkType networkType)
|
||||
{
|
||||
if (networkType == NetworkManager::GsmSetting::NetworkType::Any) {
|
||||
return QStringLiteral("Any");
|
||||
} else if (networkType == NetworkManager::GsmSetting::NetworkType::GprsEdgeOnly) {
|
||||
return QStringLiteral("Only 2G");
|
||||
} else if (networkType == NetworkManager::GsmSetting::NetworkType::Only3G) {
|
||||
return QStringLiteral("Only 3G");
|
||||
} else if (networkType == NetworkManager::GsmSetting::NetworkType::Only4GLte) {
|
||||
return QStringLiteral("Only 4G");
|
||||
} else if (networkType == NetworkManager::GsmSetting::NetworkType::Prefer2G) {
|
||||
return QStringLiteral("2G");
|
||||
} else if (networkType == NetworkManager::GsmSetting::NetworkType::Prefer3G) {
|
||||
return QStringLiteral("3G/2G");
|
||||
} else if (networkType == NetworkManager::GsmSetting::NetworkType::Prefer4GLte) {
|
||||
return QStringLiteral("4G/3G/2G");
|
||||
}
|
||||
return QStringLiteral("Any");
|
||||
}
|
||||
|
||||
NetworkManager::GsmSetting::NetworkType ProfileSettings::networkTypeFlag(const QString &networkType)
|
||||
{
|
||||
if (networkType == QStringLiteral("Any")) {
|
||||
return NetworkManager::GsmSetting::NetworkType::Any;
|
||||
} else if (networkType == QStringLiteral("Only 2G")) {
|
||||
return NetworkManager::GsmSetting::NetworkType::GprsEdgeOnly;
|
||||
} else if (networkType == QStringLiteral("Only 3G")) {
|
||||
return NetworkManager::GsmSetting::NetworkType::Only3G;
|
||||
} else if (networkType == QStringLiteral("Only 4G")) {
|
||||
return NetworkManager::GsmSetting::NetworkType::Only4GLte;
|
||||
} else if (networkType == QStringLiteral("2G")) {
|
||||
return NetworkManager::GsmSetting::NetworkType::Prefer2G;
|
||||
} else if (networkType == QStringLiteral("3G/2G")) {
|
||||
return NetworkManager::GsmSetting::NetworkType::Prefer3G;
|
||||
} else if (networkType == QStringLiteral("4G/3G/2G")) {
|
||||
return NetworkManager::GsmSetting::NetworkType::Prefer4GLte;
|
||||
}
|
||||
return NetworkManager::GsmSetting::NetworkType::Any;
|
||||
}
|
||||
79
kcms/cellularnetwork/profilesettings.h
Normal file
79
kcms/cellularnetwork/profilesettings.h
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
// SPDX-FileCopyrightText: 2021-2022 Devin Lin <espidev@gmail.com>
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cellularnetworksettings.h"
|
||||
#include "modemdetails.h"
|
||||
#include "sim.h"
|
||||
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
|
||||
#include <NetworkManagerQt/CdmaSetting>
|
||||
#include <NetworkManagerQt/ConnectionSettings>
|
||||
#include <NetworkManagerQt/GsmSetting>
|
||||
#include <NetworkManagerQt/Manager>
|
||||
#include <NetworkManagerQt/ModemDevice>
|
||||
#include <NetworkManagerQt/Settings>
|
||||
|
||||
#include <ModemManagerQt/GenericTypes>
|
||||
#include <ModemManagerQt/Manager>
|
||||
#include <ModemManagerQt/Modem3Gpp>
|
||||
#include <ModemManagerQt/ModemDevice>
|
||||
|
||||
class ProfileSettings : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString name READ name NOTIFY nameChanged)
|
||||
Q_PROPERTY(QString apn READ apn WRITE setApn NOTIFY apnChanged)
|
||||
Q_PROPERTY(QString user READ user WRITE setUser NOTIFY userChanged)
|
||||
Q_PROPERTY(QString password READ password WRITE setPassword NOTIFY passwordChanged)
|
||||
Q_PROPERTY(QString networkType READ networkType WRITE setNetworkType NOTIFY networkTypeChanged)
|
||||
Q_PROPERTY(QString connectionUni READ connectionUni NOTIFY connectionUniChanged)
|
||||
|
||||
public:
|
||||
ProfileSettings(QObject *parent = nullptr)
|
||||
: QObject{parent}
|
||||
{
|
||||
}
|
||||
ProfileSettings(QObject *parent,
|
||||
QString name,
|
||||
QString apn,
|
||||
QString user,
|
||||
QString password,
|
||||
NetworkManager::GsmSetting::NetworkType networkType,
|
||||
QString connectionUni);
|
||||
ProfileSettings(QObject *parent, NetworkManager::Setting::Ptr settings, NetworkManager::Connection::Ptr connection);
|
||||
|
||||
QString name();
|
||||
QString apn();
|
||||
void setApn(QString apn);
|
||||
QString user();
|
||||
void setUser(QString user);
|
||||
QString password();
|
||||
void setPassword(QString password);
|
||||
QString networkType();
|
||||
void setNetworkType(QString ipType);
|
||||
QString connectionUni();
|
||||
|
||||
// utilities
|
||||
static QString networkTypeStr(NetworkManager::GsmSetting::NetworkType networkType);
|
||||
static NetworkManager::GsmSetting::NetworkType networkTypeFlag(const QString &networkType);
|
||||
|
||||
Q_SIGNALS:
|
||||
void nameChanged();
|
||||
void apnChanged();
|
||||
void userChanged();
|
||||
void passwordChanged();
|
||||
void networkTypeChanged();
|
||||
void connectionUniChanged();
|
||||
|
||||
private:
|
||||
QString m_name;
|
||||
QString m_apn;
|
||||
QString m_user;
|
||||
QString m_password;
|
||||
QString m_networkType;
|
||||
QString m_connectionUni;
|
||||
};
|
||||
194
kcms/cellularnetwork/sim.cpp
Normal file
194
kcms/cellularnetwork/sim.cpp
Normal file
|
|
@ -0,0 +1,194 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2021 Devin Lin <espidev@gmail.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "sim.h"
|
||||
|
||||
#include <KLocalizedString>
|
||||
|
||||
Sim::Sim(QObject *parent, Modem *modem, ModemManager::Sim::Ptr mmSim, ModemManager::Modem::Ptr mmModem, ModemManager::Modem3gpp::Ptr mmModem3gpp)
|
||||
: QObject{parent}
|
||||
, m_modem{modem}
|
||||
, m_mmSim{mmSim}
|
||||
, m_mmModem{mmModem}
|
||||
, m_mmModem3gpp{mmModem3gpp}
|
||||
{
|
||||
connect(m_mmSim.data(), &ModemManager::Sim::imsiChanged, this, [this]() -> void {
|
||||
Q_EMIT imsiChanged();
|
||||
});
|
||||
connect(m_mmSim.data(), &ModemManager::Sim::operatorIdentifierChanged, this, [this]() -> void {
|
||||
Q_EMIT operatorIdentifierChanged();
|
||||
});
|
||||
connect(m_mmSim.data(), &ModemManager::Sim::operatorNameChanged, this, [this]() -> void {
|
||||
Q_EMIT operatorNameChanged();
|
||||
});
|
||||
connect(m_mmSim.data(), &ModemManager::Sim::simIdentifierChanged, this, [this]() -> void {
|
||||
Q_EMIT simIdentifierChanged();
|
||||
});
|
||||
|
||||
connect(m_mmModem.data(), &ModemManager::Modem::unlockRequiredChanged, this, [this]() -> void {
|
||||
Q_EMIT lockedChanged();
|
||||
Q_EMIT lockedReasonChanged();
|
||||
});
|
||||
|
||||
if (m_mmModem3gpp) {
|
||||
connect(m_mmModem3gpp.data(), &ModemManager::Modem3gpp::enabledFacilityLocksChanged, this, [this]() -> void {
|
||||
Q_EMIT pinEnabledChanged();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
bool Sim::enabled()
|
||||
{
|
||||
return uni() != QStringLiteral("/");
|
||||
}
|
||||
|
||||
bool Sim::pinEnabled()
|
||||
{
|
||||
return m_mmModem3gpp && (m_mmModem3gpp->enabledFacilityLocks() & MM_MODEM_3GPP_FACILITY_SIM);
|
||||
}
|
||||
|
||||
int Sim::unlockRetriesLeft()
|
||||
{
|
||||
return m_mmModem->unlockRetries()[MM_MODEM_LOCK_SIM_PIN];
|
||||
}
|
||||
|
||||
bool Sim::locked()
|
||||
{
|
||||
return m_mmModem->unlockRequired() == MM_MODEM_LOCK_SIM_PIN;
|
||||
}
|
||||
|
||||
QString Sim::lockedReason()
|
||||
{
|
||||
switch (m_mmModem->unlockRequired()) {
|
||||
case MM_MODEM_LOCK_UNKNOWN:
|
||||
return i18n("Lock reason unknown.");
|
||||
case MM_MODEM_LOCK_NONE:
|
||||
return i18n("Modem is unlocked.");
|
||||
case MM_MODEM_LOCK_SIM_PIN:
|
||||
return i18n("SIM requires the PIN code.");
|
||||
case MM_MODEM_LOCK_SIM_PIN2:
|
||||
return i18n("SIM requires the PIN2 code.");
|
||||
case MM_MODEM_LOCK_SIM_PUK:
|
||||
return i18n("SIM requires the PUK code.");
|
||||
case MM_MODEM_LOCK_SIM_PUK2:
|
||||
return i18n("SIM requires the PUK2 code.");
|
||||
case MM_MODEM_LOCK_PH_SP_PIN:
|
||||
return i18n("Modem requires the service provider PIN code.");
|
||||
case MM_MODEM_LOCK_PH_SP_PUK:
|
||||
return i18n("Modem requires the service provider PUK code.");
|
||||
case MM_MODEM_LOCK_PH_NET_PIN:
|
||||
return i18n("Modem requires the network PIN code.");
|
||||
case MM_MODEM_LOCK_PH_NET_PUK:
|
||||
return i18n("Modem requires the network PUK code.");
|
||||
case MM_MODEM_LOCK_PH_SIM_PIN:
|
||||
return i18n("Modem requires the PIN code.");
|
||||
case MM_MODEM_LOCK_PH_CORP_PIN:
|
||||
return i18n("Modem requires the corporate PIN code.");
|
||||
case MM_MODEM_LOCK_PH_CORP_PUK:
|
||||
return i18n("Modem requires the corporate PUK code.");
|
||||
case MM_MODEM_LOCK_PH_FSIM_PIN:
|
||||
return i18n("Modem requires the PH-FSIM PIN code.");
|
||||
case MM_MODEM_LOCK_PH_FSIM_PUK:
|
||||
return i18n("Modem requires the PH-FSIM PUK code.");
|
||||
case MM_MODEM_LOCK_PH_NETSUB_PIN:
|
||||
return i18n("Modem requires the network subset PIN code.");
|
||||
case MM_MODEM_LOCK_PH_NETSUB_PUK:
|
||||
return i18n("Modem requires the network subset PUK code.");
|
||||
}
|
||||
return QString{};
|
||||
}
|
||||
|
||||
QString Sim::imsi()
|
||||
{
|
||||
return m_mmSim->imsi();
|
||||
}
|
||||
|
||||
QString Sim::eid()
|
||||
{
|
||||
return ""; // TODO add in mm-qt
|
||||
}
|
||||
|
||||
QString Sim::operatorIdentifier()
|
||||
{
|
||||
return m_mmSim->operatorIdentifier();
|
||||
}
|
||||
|
||||
QString Sim::operatorName()
|
||||
{
|
||||
return m_mmSim->operatorName();
|
||||
}
|
||||
|
||||
QString Sim::simIdentifier()
|
||||
{
|
||||
return m_mmSim->simIdentifier();
|
||||
}
|
||||
|
||||
QStringList Sim::emergencyNumbers()
|
||||
{
|
||||
return {}; // TODO add in mm-qt
|
||||
}
|
||||
|
||||
QString Sim::uni()
|
||||
{
|
||||
return m_mmSim->uni();
|
||||
}
|
||||
|
||||
QString Sim::displayId()
|
||||
{
|
||||
// in the form /org/freedesktop/ModemManager1/Sim/0
|
||||
QStringList uniSplit = uni().split(QStringLiteral("/"));
|
||||
return (uniSplit.count() == 0 || uni() == "/") ? i18n("(empty)") : QString(uniSplit[uniSplit.size() - 1]);
|
||||
}
|
||||
|
||||
Modem *Sim::modem()
|
||||
{
|
||||
return m_modem;
|
||||
}
|
||||
|
||||
void Sim::togglePinEnabled(const QString &pin)
|
||||
{
|
||||
bool isPinEnabled = pinEnabled();
|
||||
QDBusPendingReply reply = m_mmSim->enablePin(pin, !isPinEnabled);
|
||||
reply.waitForFinished();
|
||||
if (reply.isError()) {
|
||||
qWarning() << QStringLiteral("Error toggling SIM lock to") << isPinEnabled << QStringLiteral(":") << reply.error().message();
|
||||
CellularNetworkSettings::instance()->addMessage(InlineMessage::Error, i18n("Error toggling SIM lock: %1", reply.error().message()));
|
||||
}
|
||||
}
|
||||
|
||||
void Sim::changePin(const QString &oldPin, const QString &newPin)
|
||||
{
|
||||
QDBusPendingReply reply = m_mmSim->changePin(oldPin, newPin);
|
||||
reply.waitForFinished();
|
||||
if (reply.isError()) {
|
||||
qWarning() << QStringLiteral("Error changing the PIN:") << reply.error().message();
|
||||
CellularNetworkSettings::instance()->addMessage(InlineMessage::Error, i18n("Error changing the PIN: %1", reply.error().message()));
|
||||
}
|
||||
}
|
||||
|
||||
void Sim::sendPin(const QString &pin)
|
||||
{
|
||||
if (m_mmModem->unlockRequired() != MM_MODEM_LOCK_NONE) {
|
||||
QDBusPendingReply reply = m_mmSim->sendPin(pin);
|
||||
reply.waitForFinished();
|
||||
if (reply.isError()) {
|
||||
qWarning() << QStringLiteral("Error sending the PIN:") << reply.error().message();
|
||||
CellularNetworkSettings::instance()->addMessage(InlineMessage::Error, i18n("Error sending the PIN: %1", reply.error().message()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Sim::sendPuk(const QString &pin, const QString &puk)
|
||||
{
|
||||
if (m_mmModem->unlockRequired() != MM_MODEM_LOCK_NONE) {
|
||||
QDBusPendingReply reply = m_mmSim->sendPuk(pin, puk);
|
||||
reply.waitForFinished();
|
||||
if (reply.isError()) {
|
||||
qWarning() << QStringLiteral("Error sending the PUK:") << reply.error().message();
|
||||
CellularNetworkSettings::instance()->addMessage(InlineMessage::Error, i18n("Error sending the PUK: %1", reply.error().message()));
|
||||
}
|
||||
}
|
||||
}
|
||||
94
kcms/cellularnetwork/sim.h
Normal file
94
kcms/cellularnetwork/sim.h
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2021 Devin Lin <espidev@gmail.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "modem.h"
|
||||
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
|
||||
#include <NetworkManagerQt/CdmaSetting>
|
||||
#include <NetworkManagerQt/ConnectionSettings>
|
||||
#include <NetworkManagerQt/GsmSetting>
|
||||
#include <NetworkManagerQt/Manager>
|
||||
#include <NetworkManagerQt/ModemDevice>
|
||||
#include <NetworkManagerQt/Settings>
|
||||
|
||||
#include <ModemManagerQt/GenericTypes>
|
||||
#include <ModemManagerQt/Manager>
|
||||
#include <ModemManagerQt/Modem3Gpp>
|
||||
#include <ModemManagerQt/ModemDevice>
|
||||
|
||||
class Modem;
|
||||
|
||||
class Sim : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool enabled READ enabled NOTIFY enabledChanged)
|
||||
Q_PROPERTY(bool pinEnabled READ pinEnabled NOTIFY pinEnabledChanged) // if there is a PIN set on the SIM
|
||||
Q_PROPERTY(int unlockRetriesLeft READ unlockRetriesLeft NOTIFY unlockRetriesLeftChanged)
|
||||
Q_PROPERTY(bool locked READ locked NOTIFY lockedChanged) // if the SIM is currently locked (requires entering PIN)
|
||||
Q_PROPERTY(QString lockedReason READ lockedReason NOTIFY lockedReasonChanged)
|
||||
Q_PROPERTY(QString imsi READ imsi NOTIFY imsiChanged)
|
||||
Q_PROPERTY(QString eid READ eid NOTIFY eidChanged) // TODO (not in mm-qt)
|
||||
Q_PROPERTY(QString operatorIdentifier READ operatorIdentifier NOTIFY operatorIdentifierChanged)
|
||||
Q_PROPERTY(QString operatorName READ operatorName NOTIFY operatorNameChanged)
|
||||
Q_PROPERTY(QString simIdentifier READ simIdentifier NOTIFY simIdentifierChanged)
|
||||
Q_PROPERTY(QStringList emergencyNumbers READ emergencyNumbers NOTIFY emergencyNumbersChanged)
|
||||
Q_PROPERTY(QString uni READ uni NOTIFY uniChanged)
|
||||
Q_PROPERTY(QString displayId READ displayId NOTIFY displayIdChanged)
|
||||
Q_PROPERTY(Modem *modem READ modem NOTIFY modemChanged)
|
||||
|
||||
public:
|
||||
Sim(QObject *parent = nullptr,
|
||||
Modem *modem = nullptr,
|
||||
ModemManager::Sim::Ptr mmSim = ModemManager::Sim::Ptr{nullptr},
|
||||
ModemManager::Modem::Ptr mmModem = ModemManager::Modem::Ptr{nullptr},
|
||||
ModemManager::Modem3gpp::Ptr mmModem3gpp = ModemManager::Modem3gpp::Ptr{nullptr});
|
||||
|
||||
bool enabled();
|
||||
bool pinEnabled();
|
||||
int unlockRetriesLeft();
|
||||
bool locked();
|
||||
QString lockedReason();
|
||||
QString imsi();
|
||||
QString eid(); // TODO add in mm-qt
|
||||
QString operatorIdentifier();
|
||||
QString operatorName();
|
||||
QString simIdentifier();
|
||||
QStringList emergencyNumbers(); // TODO add in mm-qt
|
||||
QString uni();
|
||||
QString displayId();
|
||||
Modem *modem();
|
||||
|
||||
Q_INVOKABLE void togglePinEnabled(const QString &pin);
|
||||
Q_INVOKABLE void changePin(const QString &oldPin, const QString &newPin);
|
||||
Q_INVOKABLE void sendPin(const QString &pin);
|
||||
Q_INVOKABLE void sendPuk(const QString &pin, const QString &puk);
|
||||
|
||||
Q_SIGNALS:
|
||||
void enabledChanged();
|
||||
void pinEnabledChanged();
|
||||
void unlockRetriesLeftChanged();
|
||||
void lockedChanged();
|
||||
void lockedReasonChanged();
|
||||
void imsiChanged();
|
||||
void eidChanged();
|
||||
void operatorIdentifierChanged();
|
||||
void operatorNameChanged();
|
||||
void simIdentifierChanged();
|
||||
void emergencyNumbersChanged();
|
||||
void uniChanged();
|
||||
void displayIdChanged();
|
||||
void modemChanged();
|
||||
|
||||
private:
|
||||
Modem *m_modem;
|
||||
ModemManager::Sim::Ptr m_mmSim;
|
||||
ModemManager::Modem::Ptr m_mmModem;
|
||||
ModemManager::Modem3gpp::Ptr m_mmModem3gpp; // this may be a nullptr if no sim is inserted
|
||||
};
|
||||
22
kcms/info/CMakeLists.txt
Normal file
22
kcms/info/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
set(info_SRCS # Specify source files for the library
|
||||
info.cpp
|
||||
distroinfo.cpp
|
||||
softwareinfo.cpp
|
||||
hardwareinfo.cpp
|
||||
)
|
||||
|
||||
add_library(kcm_mobile_info MODULE ${info_SRCS})
|
||||
|
||||
target_link_libraries(kcm_mobile_info
|
||||
Qt::Core
|
||||
KF6::CoreAddons
|
||||
KF6::I18n
|
||||
KF6::QuickAddons
|
||||
KF6::ConfigCore
|
||||
KF6::Solid
|
||||
)
|
||||
|
||||
install(TARGETS kcm_mobile_info DESTINATION ${KDE_INSTALL_PLUGINDIR}/kcms) # Install the library to the kcm location
|
||||
|
||||
kpackage_install_package(package kcm_mobile_info kcms) # Finally install our QML kpackage.
|
||||
|
||||
1
kcms/info/Messages.sh
Normal file
1
kcms/info/Messages.sh
Normal file
|
|
@ -0,0 +1 @@
|
|||
$XGETTEXT $(find . -name \*.cpp -o -name \*.h -o -name \*.qml) -o $podir/kcm_mobile_info.pot
|
||||
12
kcms/info/distroinfo.cpp
Normal file
12
kcms/info/distroinfo.cpp
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2019 Jonah Brüchert <jbb@kaidan.im>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
*/
|
||||
|
||||
#include "distroinfo.h"
|
||||
|
||||
DistroInfo::DistroInfo(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
}
|
||||
69
kcms/info/distroinfo.h
Normal file
69
kcms/info/distroinfo.h
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2019 Jonah Brüchert <jbb@kaidan.im>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
*/
|
||||
|
||||
#include <KOSRelease>
|
||||
#include <QObject>
|
||||
|
||||
// clang-format off
|
||||
|
||||
#define PROPERTY(type, name) \
|
||||
type name() const { return m_osrelease.name(); }\
|
||||
|
||||
// clang-format off
|
||||
|
||||
#ifndef DISTROINFO_H
|
||||
#define DISTROINFO_H
|
||||
|
||||
class DistroInfo : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QString name READ name CONSTANT)
|
||||
Q_PROPERTY(QString version READ version CONSTANT)
|
||||
Q_PROPERTY(QString id READ id CONSTANT)
|
||||
Q_PROPERTY(QStringList idLike READ idLike CONSTANT)
|
||||
Q_PROPERTY(QString versionCodename READ versionCodename CONSTANT)
|
||||
Q_PROPERTY(QString versionId READ versionId CONSTANT)
|
||||
Q_PROPERTY(QString prettyName READ prettyName CONSTANT)
|
||||
Q_PROPERTY(QString ansiColor READ ansiColor CONSTANT)
|
||||
Q_PROPERTY(QString cpeName READ cpeName CONSTANT)
|
||||
Q_PROPERTY(QString homeUrl READ homeUrl CONSTANT)
|
||||
Q_PROPERTY(QString documentationUrl READ documentationUrl CONSTANT)
|
||||
Q_PROPERTY(QString supportUrl READ supportUrl CONSTANT)
|
||||
Q_PROPERTY(QString bugReportUrl READ bugReportUrl CONSTANT)
|
||||
Q_PROPERTY(QString privacyPolicyUrl READ privacyPolicyUrl CONSTANT)
|
||||
Q_PROPERTY(QString buildId READ buildId CONSTANT)
|
||||
Q_PROPERTY(QString variant READ variant CONSTANT)
|
||||
Q_PROPERTY(QString variantId READ variantId CONSTANT)
|
||||
Q_PROPERTY(QString logo READ logo CONSTANT)
|
||||
|
||||
public:
|
||||
DistroInfo(QObject *parent = nullptr);
|
||||
|
||||
PROPERTY(QString, name)
|
||||
PROPERTY(QString, version)
|
||||
PROPERTY(QString, id)
|
||||
PROPERTY(QStringList, idLike)
|
||||
PROPERTY(QString, versionCodename)
|
||||
PROPERTY(QString, versionId)
|
||||
PROPERTY(QString, prettyName)
|
||||
PROPERTY(QString, ansiColor)
|
||||
PROPERTY(QString, cpeName)
|
||||
PROPERTY(QString, homeUrl)
|
||||
PROPERTY(QString, documentationUrl)
|
||||
PROPERTY(QString, supportUrl)
|
||||
PROPERTY(QString, bugReportUrl)
|
||||
PROPERTY(QString, privacyPolicyUrl)
|
||||
PROPERTY(QString, buildId)
|
||||
PROPERTY(QString, variant)
|
||||
PROPERTY(QString, variantId)
|
||||
PROPERTY(QString, logo)
|
||||
|
||||
private:
|
||||
KOSRelease m_osrelease;
|
||||
};
|
||||
|
||||
#endif // DISTROINFO_H
|
||||
89
kcms/info/hardwareinfo.cpp
Normal file
89
kcms/info/hardwareinfo.cpp
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2019 Jonah Brüchert <jbb@kaidan.im>
|
||||
SPDX-FileCopyrightText: 2012-2019 Harald Sitter <sitter@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
*/
|
||||
|
||||
#include "hardwareinfo.h"
|
||||
|
||||
#include <KCoreAddons>
|
||||
#include <KFormat>
|
||||
|
||||
#include <solid/device.h>
|
||||
#include <solid/processor.h>
|
||||
|
||||
#include <KLocalizedString>
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
#include <sys/sysinfo.h>
|
||||
#elif defined(Q_OS_FREEBSD)
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
HardwareInfo::HardwareInfo(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
int HardwareInfo::processorCount() const
|
||||
{
|
||||
return Solid::Device::listFromType(Solid::DeviceInterface::Processor).count();
|
||||
}
|
||||
|
||||
QString HardwareInfo::processors() const
|
||||
{
|
||||
const auto list = Solid::Device::listFromType(Solid::DeviceInterface::Processor);
|
||||
|
||||
// Format processor string
|
||||
// Group by processor name
|
||||
QMap<QString, int> processorMap;
|
||||
for (const auto &device : list) {
|
||||
const QString name = device.product();
|
||||
auto it = processorMap.find(name);
|
||||
if (it == processorMap.end()) {
|
||||
processorMap.insert(name, 1);
|
||||
} else {
|
||||
++it.value();
|
||||
}
|
||||
}
|
||||
// Create a formatted list of grouped processors
|
||||
QStringList names;
|
||||
names.reserve(processorMap.count());
|
||||
for (auto it = processorMap.constBegin(); it != processorMap.constEnd(); ++it) {
|
||||
const int count = it.value();
|
||||
QString name = it.key();
|
||||
name.replace(QStringLiteral("(TM)"), QChar(8482));
|
||||
name.replace(QStringLiteral("(R)"), QChar(174));
|
||||
name = name.simplified();
|
||||
names.append(QStringLiteral("%1 × %2").arg(count).arg(name));
|
||||
}
|
||||
|
||||
const QString processorLabel = names.join(QLatin1String(", "));
|
||||
|
||||
return processorLabel;
|
||||
}
|
||||
|
||||
QString HardwareInfo::memory() const
|
||||
{
|
||||
qlonglong totalRam = -1;
|
||||
#ifdef Q_OS_LINUX
|
||||
struct sysinfo info {
|
||||
};
|
||||
if (sysinfo(&info) == 0)
|
||||
// manpage "sizes are given as multiples of mem_unit bytes"
|
||||
totalRam = qlonglong(info.totalram) * info.mem_unit;
|
||||
#elif defined(Q_OS_FREEBSD)
|
||||
/* Stuff for sysctl */
|
||||
size_t len;
|
||||
|
||||
unsigned long memory;
|
||||
len = sizeof(memory);
|
||||
sysctlbyname("hw.physmem", &memory, &len, NULL, 0);
|
||||
|
||||
totalRam = memory;
|
||||
#endif
|
||||
|
||||
return KFormat().formatByteSize(totalRam);
|
||||
}
|
||||
28
kcms/info/hardwareinfo.h
Normal file
28
kcms/info/hardwareinfo.h
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2019 Jonah Brüchert <jbb@kaidan.im>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
*/
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#ifndef HARDWAREINFO_H
|
||||
#define HARDWAREINFO_H
|
||||
|
||||
class HardwareInfo : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QString processors READ processors CONSTANT)
|
||||
Q_PROPERTY(int processorCount READ processorCount CONSTANT)
|
||||
Q_PROPERTY(QString memory READ memory CONSTANT)
|
||||
|
||||
public:
|
||||
HardwareInfo(QObject *parent = nullptr);
|
||||
|
||||
QString processors() const;
|
||||
int processorCount() const;
|
||||
QString memory() const;
|
||||
};
|
||||
|
||||
#endif // HARDWAREINFO_H
|
||||
65
kcms/info/info.cpp
Normal file
65
kcms/info/info.cpp
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2019 Jonah Brüchert <jbb@kaidan.im>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
*/
|
||||
|
||||
#include "info.h"
|
||||
|
||||
#include <KLocalizedString>
|
||||
#include <KPluginFactory>
|
||||
#include <QClipboard>
|
||||
#include <QGuiApplication>
|
||||
|
||||
K_PLUGIN_CLASS_WITH_JSON(Info, "info.json")
|
||||
|
||||
Info::Info(QObject *parent, const KPluginMetaData &metaData, const QVariantList &args)
|
||||
: KQuickAddons::ConfigModule(parent, metaData, args)
|
||||
, m_distroInfo(new DistroInfo(this))
|
||||
, m_softwareInfo(new SoftwareInfo(this))
|
||||
, m_hardwareInfo(new HardwareInfo(this))
|
||||
{
|
||||
setButtons(Apply | Default);
|
||||
|
||||
qDebug() << "Info module loaded.";
|
||||
}
|
||||
|
||||
void Info::copyInfoToClipboard() const
|
||||
{
|
||||
const QString clipboardText = QStringLiteral(
|
||||
"Operating System: %1\n"
|
||||
"KDE Plasma Version: %2\n"
|
||||
"KDE Frameworks Version: %3\n"
|
||||
"Qt Version: %4\n"
|
||||
"Kernel Version: %5\n"
|
||||
"OS-Type: %6\n"
|
||||
"Processor: %7\n"
|
||||
"Memory: %8\n")
|
||||
.arg(distroInfo()->name(),
|
||||
softwareInfo()->plasmaVersion(),
|
||||
softwareInfo()->frameworksVersion(),
|
||||
softwareInfo()->qtVersion(),
|
||||
softwareInfo()->kernelRelease(),
|
||||
softwareInfo()->osType(),
|
||||
hardwareInfo()->processors(),
|
||||
hardwareInfo()->memory());
|
||||
|
||||
QGuiApplication::clipboard()->setText(clipboardText);
|
||||
}
|
||||
|
||||
DistroInfo *Info::distroInfo() const
|
||||
{
|
||||
return m_distroInfo;
|
||||
}
|
||||
|
||||
SoftwareInfo *Info::softwareInfo() const
|
||||
{
|
||||
return m_softwareInfo;
|
||||
}
|
||||
|
||||
HardwareInfo *Info::hardwareInfo() const
|
||||
{
|
||||
return m_hardwareInfo;
|
||||
}
|
||||
|
||||
#include "info.moc"
|
||||
42
kcms/info/info.h
Normal file
42
kcms/info/info.h
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2019 Jonah Brüchert <jbb@kaidan.im>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
*/
|
||||
|
||||
#include "distroinfo.h"
|
||||
#include "hardwareinfo.h"
|
||||
#include "softwareinfo.h"
|
||||
#include <KQuickAddons/ConfigModule>
|
||||
|
||||
#ifndef INFO_H
|
||||
#define INFO_H
|
||||
|
||||
class Info : public KQuickAddons::ConfigModule
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(DistroInfo *distroInfo READ distroInfo NOTIFY distroInfoChanged)
|
||||
Q_PROPERTY(SoftwareInfo *softwareInfo READ softwareInfo NOTIFY softwareInfoChanged)
|
||||
Q_PROPERTY(HardwareInfo *hardwareInfo READ hardwareInfo NOTIFY hardwareInfoChanged)
|
||||
DistroInfo *distroInfo() const;
|
||||
SoftwareInfo *softwareInfo() const;
|
||||
HardwareInfo *hardwareInfo() const;
|
||||
|
||||
public:
|
||||
Info(QObject *parent, const KPluginMetaData &metaData, const QVariantList &args);
|
||||
|
||||
Q_INVOKABLE void copyInfoToClipboard() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void distroInfoChanged();
|
||||
void softwareInfoChanged();
|
||||
void hardwareInfoChanged();
|
||||
|
||||
private:
|
||||
DistroInfo *m_distroInfo;
|
||||
SoftwareInfo *m_softwareInfo;
|
||||
HardwareInfo *m_hardwareInfo;
|
||||
};
|
||||
|
||||
#endif // INFO_H
|
||||
123
kcms/info/info.json
Normal file
123
kcms/info/info.json
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
{
|
||||
"Categories": "Qt;KDE;X-KDE-settings-system;",
|
||||
"KPlugin": {
|
||||
"Description": "Software Versions",
|
||||
"Description[az]": "Proqram təminatı versiyası",
|
||||
"Description[ca@valencia]": "Versions de programari",
|
||||
"Description[ca]": "Versions de programari",
|
||||
"Description[cs]": "Verze softwaru",
|
||||
"Description[de]": "Software-Versionen",
|
||||
"Description[en_GB]": "Software Versions",
|
||||
"Description[es]": "Versiones de software",
|
||||
"Description[eu]": "Softwarearen bertsioak",
|
||||
"Description[fi]": "Ohjelmaversiot",
|
||||
"Description[fr]": "Versions des logiciels",
|
||||
"Description[hu]": "Szoftververziók",
|
||||
"Description[ia]": "Versiones de software",
|
||||
"Description[id]": "Versi Perangkat Lunak",
|
||||
"Description[is]": "Útgáfur hugbúnaðar",
|
||||
"Description[it]": "Versioni software",
|
||||
"Description[ka]": "პროგრამების ვერსიები",
|
||||
"Description[ko]": "소프트웨어 버전",
|
||||
"Description[lt]": "Programinės įrangos versijos",
|
||||
"Description[nl]": "Softwareversies",
|
||||
"Description[nn]": "Programversjonar",
|
||||
"Description[pa]": "ਸਾਫਟਵੇਅਰ ਵਰਜ਼ਨ",
|
||||
"Description[pl]": "Wersje oprogramowania",
|
||||
"Description[pt]": "Versões do 'Software'",
|
||||
"Description[pt_BR]": "Versões do software",
|
||||
"Description[ro]": "Versiuni de programe",
|
||||
"Description[ru]": "Версии приложений",
|
||||
"Description[sl]": "Verzije programja",
|
||||
"Description[sv]": "Programvaruversioner",
|
||||
"Description[tr]": "Yazılım Sürümleri",
|
||||
"Description[uk]": "Версії програмного забезпечення",
|
||||
"Description[vi]": "Các phiên bản phần mềm",
|
||||
"Description[x-test]": "xxSoftware Versionsxx",
|
||||
"Description[zh_CN]": "软件版本",
|
||||
"Description[zh_TW]": "軟體版本",
|
||||
"FormFactors": [
|
||||
"handset",
|
||||
"tablet",
|
||||
"mediacenter"
|
||||
],
|
||||
"Icon": "dialog-information",
|
||||
"Name": "Information",
|
||||
"Name[az]": "Məlumat",
|
||||
"Name[ca@valencia]": "Informació",
|
||||
"Name[ca]": "Informació",
|
||||
"Name[cs]": "Informace",
|
||||
"Name[da]": "Information",
|
||||
"Name[de]": "Informationen",
|
||||
"Name[en_GB]": "Information",
|
||||
"Name[es]": "Información",
|
||||
"Name[et]": "Teave",
|
||||
"Name[eu]": "Informazioa",
|
||||
"Name[fi]": "Tiedot",
|
||||
"Name[fr]": "Informations",
|
||||
"Name[gl]": "Información",
|
||||
"Name[hu]": "Információk",
|
||||
"Name[ia]": "Information",
|
||||
"Name[id]": "Informasi",
|
||||
"Name[is]": "Upplýsingar",
|
||||
"Name[it]": "Informazioni",
|
||||
"Name[ka]": "ინფორმაცია",
|
||||
"Name[ko]": "정보",
|
||||
"Name[lt]": "Informacija",
|
||||
"Name[nl]": "Informatie",
|
||||
"Name[nn]": "Informasjon",
|
||||
"Name[pa]": "ਜਾਣਕਾਰੀ",
|
||||
"Name[pl]": "Informacje",
|
||||
"Name[pt]": "Informação",
|
||||
"Name[pt_BR]": "Informações",
|
||||
"Name[ro]": "Informații",
|
||||
"Name[ru]": "Сведения",
|
||||
"Name[sk]": "Informácie",
|
||||
"Name[sl]": "Informacije",
|
||||
"Name[sv]": "Information",
|
||||
"Name[ta]": "விவரங்கள்",
|
||||
"Name[tr]": "Bilgi",
|
||||
"Name[uk]": "Інформація",
|
||||
"Name[vi]": "Thông tin",
|
||||
"Name[x-test]": "xxInformationxx",
|
||||
"Name[zh_CN]": "信息",
|
||||
"Name[zh_TW]": "資訊"
|
||||
},
|
||||
"X-KDE-Keywords": "info, distro, system",
|
||||
"X-KDE-Keywords[ast]": "info, información, systema",
|
||||
"X-KDE-Keywords[az]": "info, distro, system,məlumat,distribütor,sistem",
|
||||
"X-KDE-Keywords[ca@valencia]": "informació, distribució, sistema",
|
||||
"X-KDE-Keywords[ca]": "informació, distribució, sistema",
|
||||
"X-KDE-Keywords[cs]": "informace, distribuce, systém",
|
||||
"X-KDE-Keywords[da]": "info, distribution, system",
|
||||
"X-KDE-Keywords[de]": "information,distribution,system",
|
||||
"X-KDE-Keywords[en_GB]": "info, distro, system",
|
||||
"X-KDE-Keywords[es]": "información, distro, sistema",
|
||||
"X-KDE-Keywords[et]": "teave, info, süsteem",
|
||||
"X-KDE-Keywords[eu]": "informazioa, banaketa, sistema",
|
||||
"X-KDE-Keywords[fi]": "tietoa, jakelu, järjestelmä",
|
||||
"X-KDE-Keywords[fr]": "info, distrib, système",
|
||||
"X-KDE-Keywords[gl]": "info, información, distro, distribución, sistema",
|
||||
"X-KDE-Keywords[hu]": "információ, disztró, rendszer",
|
||||
"X-KDE-Keywords[ia]": "info, distro, system",
|
||||
"X-KDE-Keywords[it]": "informazioni, distribuzione, sistema",
|
||||
"X-KDE-Keywords[ko]": "info, distro, system, 정보, 배포판, 시스템",
|
||||
"X-KDE-Keywords[lt]": "informacija, platinamasis paketas, platinimas, distribucija, sistema, distributyvas",
|
||||
"X-KDE-Keywords[nl]": "informatie, distributie, systeem",
|
||||
"X-KDE-Keywords[nn]": "info, distro, distribusjon, system",
|
||||
"X-KDE-Keywords[pa]": "ਜਾਣਕਾਰੀ, ਡਿਸਟਰੋ, ਸਿਸਟਮ",
|
||||
"X-KDE-Keywords[pl]": "info, distro, system",
|
||||
"X-KDE-Keywords[pt]": "informação, distribuição, sistema",
|
||||
"X-KDE-Keywords[pt_BR]": "informação, info, distro, distribuição, sistema",
|
||||
"X-KDE-Keywords[ro]": "informații, info, distribuție, sistem",
|
||||
"X-KDE-Keywords[ru]": "info,distro,system,информация,дистрибутив,сведения,система",
|
||||
"X-KDE-Keywords[sk]": "info, distro, systém",
|
||||
"X-KDE-Keywords[sl]": "info, distro, system,sistem",
|
||||
"X-KDE-Keywords[sv]": "information, distribution, system",
|
||||
"X-KDE-Keywords[tr]": "bilgi, dağıtım, sistem",
|
||||
"X-KDE-Keywords[uk]": "info, distro, system, інфо, відомості, дистрибутив, система",
|
||||
"X-KDE-Keywords[vi]": "info,distro,system,thông tin,bản phân phối,hệ thống",
|
||||
"X-KDE-Keywords[x-test]": "xxinfoxx,xx distroxx,xx systemxx",
|
||||
"X-KDE-Keywords[zh_CN]": "info, distro, system, 信息, 发行版, 系统",
|
||||
"X-KDE-Keywords[zh_TW]": "info, distro, system, 資訊, 發行版, 系統, 信息"
|
||||
}
|
||||
148
kcms/info/package/contents/ui/main.qml
Normal file
148
kcms/info/package/contents/ui/main.qml
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2019 Jonah Brüchert <jbb@kaidan.im>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
*/
|
||||
|
||||
import QtQuick.Layouts 1.2
|
||||
import QtQuick 2.7
|
||||
import QtQuick.Controls 2.2 as Controls
|
||||
|
||||
import org.kde.kcm 1.2 as KCM
|
||||
import org.kde.kirigami 2.10 as Kirigami
|
||||
import org.kde.kirigamiaddons.labs.mobileform 0.1 as MobileForm
|
||||
|
||||
KCM.SimpleKCM {
|
||||
title: i18n("System Information")
|
||||
|
||||
leftPadding: 0
|
||||
rightPadding: 0
|
||||
Kirigami.Theme.colorSet: Kirigami.Theme.Window
|
||||
|
||||
ColumnLayout {
|
||||
width: parent.width
|
||||
spacing: 0
|
||||
|
||||
Kirigami.Icon {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.topMargin: Kirigami.Units.gridUnit
|
||||
Layout.bottomMargin: Kirigami.Units.gridUnit
|
||||
implicitWidth: Kirigami.Units.iconSizes.huge
|
||||
implicitHeight: width
|
||||
source: kcm.distroInfo.logo ? kcm.distroInfo.logo : "kde"
|
||||
}
|
||||
|
||||
MobileForm.FormCard {
|
||||
Layout.fillWidth: true
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
spacing: 0
|
||||
|
||||
MobileForm.FormTextDelegate {
|
||||
text: i18n("Operating System")
|
||||
description: kcm.distroInfo.name
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator {}
|
||||
|
||||
MobileForm.FormButtonDelegate {
|
||||
text: i18n("Webpage")
|
||||
description: kcm.distroInfo.homeUrl
|
||||
onClicked: {
|
||||
Qt.openUrlExternally(kcm.distroInfo.homeUrl)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MobileForm.FormCard {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: Kirigami.Units.largeSpacing
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
spacing: 0
|
||||
|
||||
MobileForm.FormCardHeader {
|
||||
title: "Software"
|
||||
}
|
||||
|
||||
MobileForm.FormTextDelegate {
|
||||
text: i18n("KDE Plasma Version")
|
||||
description: kcm.softwareInfo.plasmaVersion
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator {}
|
||||
|
||||
MobileForm.FormTextDelegate {
|
||||
text: i18n("KDE Frameworks Version")
|
||||
description: kcm.softwareInfo.frameworksVersion
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator {}
|
||||
|
||||
MobileForm.FormTextDelegate {
|
||||
text: i18n("Qt Version")
|
||||
description: kcm.softwareInfo.qtVersion
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator {}
|
||||
|
||||
MobileForm.FormTextDelegate {
|
||||
text: i18n("Kernel Version")
|
||||
description: kcm.softwareInfo.kernelRelease
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator {}
|
||||
|
||||
MobileForm.FormTextDelegate {
|
||||
text: i18n("OS Type")
|
||||
description: i18nc("@label %1 is the CPU bit width (e.g. 32 or 64)", "%1-bit", kcm.softwareInfo.osType)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MobileForm.FormCard {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: Kirigami.Units.largeSpacing
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
spacing: 0
|
||||
|
||||
MobileForm.FormCardHeader {
|
||||
title: "Hardware"
|
||||
}
|
||||
|
||||
MobileForm.FormTextDelegate {
|
||||
text: i18np("Processor", "Processors", kcm.hardwareInfo.processorCount);
|
||||
description: kcm.hardwareInfo.processors
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator {}
|
||||
|
||||
MobileForm.FormTextDelegate {
|
||||
text: i18n("Memory")
|
||||
description: {
|
||||
if (kcm.hardwareInfo.memory !== "0 B") {
|
||||
return i18nc("@label %1 is the formatted amount of system memory (e.g. 7,7 GiB)",
|
||||
"%1 of RAM", kcm.hardwareInfo.memory)
|
||||
} else {
|
||||
return i18nc("Unknown amount of RAM", "Unknown")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
footer: RowLayout {
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Controls.Button {
|
||||
text: i18n("Copy to clipboard")
|
||||
icon.name: "edit-copy"
|
||||
onClicked: kcm.copyInfoToClipboard()
|
||||
}
|
||||
}
|
||||
}
|
||||
63
kcms/info/softwareinfo.cpp
Normal file
63
kcms/info/softwareinfo.cpp
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2019 Jonah Brüchert <jbb@kaidan.im>
|
||||
SPDX-FileCopyrightText: 2012-2019 Harald Sitter <sitter@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
*/
|
||||
|
||||
#include "softwareinfo.h"
|
||||
#include <sys/utsname.h>
|
||||
|
||||
#include <KConfigGroup>
|
||||
#include <KCoreAddons>
|
||||
#include <KDesktopFile>
|
||||
#include <KLocalizedString>
|
||||
#include <QDebug>
|
||||
#include <QStandardPaths>
|
||||
|
||||
SoftwareInfo::SoftwareInfo(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
QString SoftwareInfo::kernelRelease() const
|
||||
{
|
||||
struct utsname utsName {
|
||||
};
|
||||
uname(&utsName);
|
||||
|
||||
return QString::fromLatin1(utsName.release);
|
||||
}
|
||||
|
||||
QString SoftwareInfo::frameworksVersion() const
|
||||
{
|
||||
return KCoreAddons::versionString();
|
||||
}
|
||||
|
||||
QString SoftwareInfo::qtVersion() const
|
||||
{
|
||||
return QString::fromLatin1(qVersion());
|
||||
}
|
||||
|
||||
QString SoftwareInfo::plasmaVersion() const
|
||||
{
|
||||
const QStringList &filePaths = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("wayland-sessions/plasma.desktop"));
|
||||
|
||||
if (filePaths.length() < 1) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
// Despite the fact that there can be multiple desktop files we simply take
|
||||
// the first one as users usually don't have xsessions/ in their $HOME
|
||||
// data location, so the first match should (usually) be the only one and
|
||||
// reflect the plasma session run.
|
||||
KDesktopFile desktopFile(filePaths.first());
|
||||
return desktopFile.desktopGroup().readEntry("X-KDE-PluginInfo-Version", QString());
|
||||
}
|
||||
|
||||
QString SoftwareInfo::osType() const
|
||||
{
|
||||
const int bits = QT_POINTER_SIZE == 8 ? 64 : 32;
|
||||
|
||||
return QString::number(bits);
|
||||
}
|
||||
31
kcms/info/softwareinfo.h
Normal file
31
kcms/info/softwareinfo.h
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2019 Jonah Brüchert <jbb@kaidan.im>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
*/
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#ifndef SOFTWAREINFO_H
|
||||
#define SOFTWAREINFO_H
|
||||
|
||||
class SoftwareInfo : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QString kernelRelease READ kernelRelease CONSTANT)
|
||||
Q_PROPERTY(QString frameworksVersion READ frameworksVersion CONSTANT)
|
||||
Q_PROPERTY(QString qtVersion READ qtVersion CONSTANT)
|
||||
Q_PROPERTY(QString plasmaVersion READ plasmaVersion CONSTANT)
|
||||
Q_PROPERTY(QString osType READ osType CONSTANT)
|
||||
|
||||
public:
|
||||
SoftwareInfo(QObject *parent = nullptr);
|
||||
QString kernelRelease() const;
|
||||
QString frameworksVersion() const;
|
||||
QString qtVersion() const;
|
||||
QString plasmaVersion() const;
|
||||
QString osType() const;
|
||||
};
|
||||
|
||||
#endif // SOFTWAREINFO_H
|
||||
24
kcms/powermanagement/CMakeLists.txt
Normal file
24
kcms/powermanagement/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# SPDX-FileCopyrightText: 2020 Tomaz Canabrava <tcanabrava@kde.org>
|
||||
|
||||
add_definitions(-DTRANSLATION_DOMAIN=\"kcm_mobile_power\")
|
||||
|
||||
add_library(kcm_mobile_power MODULE
|
||||
mobilepower.cpp
|
||||
batterymodel.cpp
|
||||
statisticsprovider.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(kcm_mobile_power
|
||||
Qt::DBus
|
||||
Qt::Core
|
||||
KF6::CoreAddons
|
||||
KF6::I18n
|
||||
KF6::QuickAddons
|
||||
KF6::ConfigCore
|
||||
KF6::Solid
|
||||
)
|
||||
|
||||
install(TARGETS kcm_mobile_power DESTINATION ${KDE_INSTALL_PLUGINDIR}/kcms)
|
||||
|
||||
kpackage_install_package(package kcm_mobile_power kcms)
|
||||
1
kcms/powermanagement/Messages.sh
Normal file
1
kcms/powermanagement/Messages.sh
Normal file
|
|
@ -0,0 +1 @@
|
|||
$XGETTEXT $(find . -name \*.cpp -o -name \*.h -o -name \*.qml) -o $podir/kcm_mobile_powermanagement.pot
|
||||
92
kcms/powermanagement/batterymodel.cpp
Normal file
92
kcms/powermanagement/batterymodel.cpp
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2015 Kai Uwe Broulik <kde@privat.broulik.de>
|
||||
* SPD
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "batterymodel.h"
|
||||
|
||||
#include <Solid/DeviceNotifier>
|
||||
|
||||
#include <QQmlEngine>
|
||||
#include <QtQml>
|
||||
|
||||
BatteryModel::BatteryModel(QObject *parent)
|
||||
: QAbstractListModel(parent)
|
||||
{
|
||||
qmlRegisterUncreatableType<Solid::Battery>("org.kde.kinfocenter.energy.private", 1, 0, "Battery", QStringLiteral("Use Solid::Battery"));
|
||||
|
||||
m_batteries = Solid::Device::listFromType(Solid::DeviceInterface::Battery);
|
||||
|
||||
connect(Solid::DeviceNotifier::instance(), &Solid::DeviceNotifier::deviceAdded, this, [this](const QString &udi) {
|
||||
auto it = std::find_if(m_batteries.constBegin(), m_batteries.constEnd(), [&udi](const Solid::Device &dev) {
|
||||
return dev.udi() == udi;
|
||||
});
|
||||
if (it != m_batteries.constEnd()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const Solid::Device device(udi);
|
||||
if (device.isValid() && device.is<Solid::Battery>()) {
|
||||
beginInsertRows(QModelIndex(), m_batteries.count(), m_batteries.count());
|
||||
m_batteries.append(device);
|
||||
endInsertRows();
|
||||
|
||||
Q_EMIT countChanged();
|
||||
}
|
||||
});
|
||||
connect(Solid::DeviceNotifier::instance(), &Solid::DeviceNotifier::deviceRemoved, this, [this](const QString &udi) {
|
||||
auto it = std::find_if(m_batteries.constBegin(), m_batteries.constEnd(), [&udi](const Solid::Device &dev) {
|
||||
return dev.udi() == udi;
|
||||
});
|
||||
if (it == m_batteries.constEnd()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int index = std::distance(m_batteries.constBegin(), it);
|
||||
|
||||
beginRemoveRows(QModelIndex(), index, index);
|
||||
m_batteries.removeAt(index);
|
||||
endRemoveRows();
|
||||
|
||||
Q_EMIT countChanged();
|
||||
});
|
||||
}
|
||||
|
||||
QVariant BatteryModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (index.row() < 0 || index.row() >= m_batteries.count()) {
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
if (role == BatteryRole) {
|
||||
// .as returns a pointer to a casted DeviceInterface. This pointer must
|
||||
// not, under any circumstances, be deleted outside Solid!
|
||||
// https://bugs.kde.org/show_bug.cgi?id=413003
|
||||
const auto battery = m_batteries.value(index.row()).as<Solid::Battery>();
|
||||
QQmlEngine::setObjectOwnership(battery, QQmlEngine::CppOwnership);
|
||||
return QVariant::fromValue(battery);
|
||||
} else if (role == ProductRole) {
|
||||
const Solid::Device device = m_batteries.value(index.row());
|
||||
return device.product();
|
||||
} else if (role == VendorRole) {
|
||||
const Solid::Device device = m_batteries.value(index.row());
|
||||
return device.vendor();
|
||||
} else if (role == UdiRole) {
|
||||
return m_batteries.at(index.row()).udi();
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
int BatteryModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(parent);
|
||||
return m_batteries.count();
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> BatteryModel::roleNames() const
|
||||
{
|
||||
return {{BatteryRole, "battery"}, {VendorRole, "vendor"}, {ProductRole, "product"}, {UdiRole, "udi"}};
|
||||
}
|
||||
42
kcms/powermanagement/batterymodel.h
Normal file
42
kcms/powermanagement/batterymodel.h
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2015 Kai Uwe Broulik <kde@privat.broulik.de>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QList>
|
||||
|
||||
#include <Solid/Battery>
|
||||
#include <Solid/Device>
|
||||
|
||||
class BatteryModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(int count READ rowCount NOTIFY countChanged)
|
||||
|
||||
public:
|
||||
explicit BatteryModel(QObject *parent);
|
||||
~BatteryModel() override = default;
|
||||
|
||||
enum Roles {
|
||||
BatteryRole = Qt::UserRole,
|
||||
UdiRole,
|
||||
VendorRole,
|
||||
ProductRole,
|
||||
};
|
||||
Q_ENUM(Roles)
|
||||
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
signals:
|
||||
void countChanged();
|
||||
|
||||
private:
|
||||
QList<Solid::Device> m_batteries;
|
||||
};
|
||||
285
kcms/powermanagement/mobilepower.cpp
Normal file
285
kcms/powermanagement/mobilepower.cpp
Normal file
|
|
@ -0,0 +1,285 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
// SPDX-FileCopyrightText: 2020 Tomaz Canabrava <tcanabrava@kde.org>
|
||||
|
||||
#include "mobilepower.h"
|
||||
#include "statisticsprovider.h"
|
||||
|
||||
#include <KConfigGroup>
|
||||
#include <KLocalizedString>
|
||||
#include <KPluginFactory>
|
||||
#include <KSharedConfig>
|
||||
|
||||
#include <Solid/Battery>
|
||||
|
||||
K_PLUGIN_CLASS_WITH_JSON(MobilePower, "powermanagement.json")
|
||||
|
||||
enum {
|
||||
THIRTY_SECONDS,
|
||||
ONE_MINUTE,
|
||||
TWO_MINUTES,
|
||||
FIVE_MINUTES,
|
||||
TEN_MINUTES,
|
||||
FIFTEEN_MINUTES,
|
||||
NEVER,
|
||||
};
|
||||
|
||||
const QStringList timeValues = {
|
||||
i18n("30 sec"),
|
||||
i18n("1 min"),
|
||||
i18n("2 min"),
|
||||
i18n("5 min"),
|
||||
i18n("10 min"),
|
||||
i18n("15 min"),
|
||||
i18n("Never"),
|
||||
};
|
||||
|
||||
// Maps the indices of the timeValues indexes
|
||||
// to minutes.
|
||||
const QMap<int, qreal> idxToMinutes = {
|
||||
{THIRTY_SECONDS, 0.5},
|
||||
{ONE_MINUTE, 1},
|
||||
{TWO_MINUTES, 2},
|
||||
{FIVE_MINUTES, 5},
|
||||
{TEN_MINUTES, 10},
|
||||
{FIFTEEN_MINUTES, 15},
|
||||
{NEVER, 0},
|
||||
};
|
||||
|
||||
MobilePower::MobilePower(QObject *parent, const KPluginMetaData &metaData, const QVariantList &args)
|
||||
: KQuickAddons::ConfigModule(parent, metaData, args)
|
||||
, m_batteries{new BatteryModel(this)}
|
||||
, m_profilesConfig{KSharedConfig::openConfig("powermanagementprofilesrc", KConfig::SimpleConfig | KConfig::CascadeConfig)}
|
||||
{
|
||||
qmlRegisterUncreatableType<BatteryModel>("org.kde.kcm.power.mobile.private", 1, 0, "BatteryModel", QStringLiteral("Use BatteryModel"));
|
||||
qmlRegisterUncreatableType<Solid::Battery>("org.kde.kcm.power.mobile.private", 1, 0, "Battery", "");
|
||||
qmlRegisterType<StatisticsProvider>("org.kde.kcm.power.mobile.private", 1, 0, "HistoryModel");
|
||||
|
||||
setButtons(KQuickAddons::ConfigModule::NoAdditionalButton);
|
||||
load();
|
||||
}
|
||||
|
||||
MobilePower::~MobilePower() = default;
|
||||
|
||||
// contents of powermanagementprofilesrc
|
||||
//
|
||||
// [Battery][SuspendSession] // our LockScreen
|
||||
// idleTime=600000
|
||||
// suspendThenHibernate = enabled / disabled.
|
||||
// suspendType=1
|
||||
// type 1 = sleep
|
||||
// type 8 = shutdown
|
||||
// type 32 = lock screen
|
||||
//
|
||||
// [Battery][DimDisplay] // our "Sleep Screen"
|
||||
// idleTime=300000
|
||||
// Aparently KDE removes this group when it's false.
|
||||
//
|
||||
|
||||
void MobilePower::load()
|
||||
{
|
||||
// we assume that the [AC], [Battery], and [LowBattery] groups have the same value
|
||||
// (which is done by this kcm)
|
||||
|
||||
KConfigGroup batteryGroup = m_profilesConfig->group("Battery");
|
||||
|
||||
if (batteryGroup.hasGroup("DimDisplay")) {
|
||||
qDebug() << "[Battery][DimDisplay] group is listed";
|
||||
KConfigGroup dimSettings = batteryGroup.group("DimDisplay");
|
||||
|
||||
// powerdevil/dimdisplayconfig.cpp - here we load time / 60 / 1000
|
||||
// We should really, really, stop doing that.
|
||||
m_dimScreenTime = (dimSettings.readEntry("idleTime").toDouble() / 60) / 1000;
|
||||
} else {
|
||||
qDebug() << "[Battery][DimDisplay] Group is not listed";
|
||||
m_dimScreenTime = 0;
|
||||
}
|
||||
|
||||
if (batteryGroup.hasGroup("DPMSControl")) {
|
||||
qDebug() << "[Battery][DPMSControl] group is listed";
|
||||
KConfigGroup dpmsSettings = batteryGroup.group("DPMSControl");
|
||||
m_screenOffTime = dpmsSettings.readEntry("idleTime").toDouble() / 60 / 1000;
|
||||
} else {
|
||||
qDebug() << "[Battery][DPMSControl] is not listed";
|
||||
m_screenOffTime = 0;
|
||||
}
|
||||
|
||||
if (batteryGroup.hasGroup("SuspendSession")) {
|
||||
qDebug() << "[Battery][SuspendSession] group is listed";
|
||||
KConfigGroup suspendSessionGroup = batteryGroup.group("SuspendSession");
|
||||
m_suspendSessionTime = suspendSessionGroup.readEntry("idleTime").toDouble() / 60 / 1000;
|
||||
} else {
|
||||
qDebug() << "[Battery][SuspendSession] is not listed";
|
||||
m_suspendSessionTime = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void MobilePower::save()
|
||||
{
|
||||
// we set all profiles at the same time, since our UI is quite a simple global toggle
|
||||
KConfigGroup acGroup = m_profilesConfig->group("AC");
|
||||
KConfigGroup batteryGroup = m_profilesConfig->group("Battery");
|
||||
KConfigGroup lowBatteryGroup = m_profilesConfig->group("LowBattery");
|
||||
|
||||
if (m_dimScreenTime == 0) {
|
||||
qDebug() << "Deleting the group DimDisplay";
|
||||
|
||||
acGroup.deleteGroup("DimDisplay", KConfigGroup::Notify);
|
||||
batteryGroup.deleteGroup("DimDisplay", KConfigGroup::Notify);
|
||||
lowBatteryGroup.deleteGroup("DimDisplay", KConfigGroup::Notify);
|
||||
} else {
|
||||
// powerdevil/dimdisplayconfig.cpp - here we store time * 60 * 1000
|
||||
// We should really, really, stop doing that.
|
||||
acGroup.group("DimDisplay").writeEntry("idleTime", m_dimScreenTime * 60 * 1000, KConfigGroup::Notify);
|
||||
batteryGroup.group("DimDisplay").writeEntry("idleTime", m_dimScreenTime * 60 * 1000, KConfigGroup::Notify);
|
||||
lowBatteryGroup.group("DimDisplay").writeEntry("idleTime", m_dimScreenTime * 60 * 1000, KConfigGroup::Notify);
|
||||
}
|
||||
|
||||
if (m_screenOffTime == 0) {
|
||||
qDebug() << "Deleting the group DPMSControl";
|
||||
|
||||
acGroup.deleteGroup("DPMSControl", KConfigGroup::Notify);
|
||||
batteryGroup.deleteGroup("DPMSControl", KConfigGroup::Notify);
|
||||
lowBatteryGroup.deleteGroup("DPMSControl", KConfigGroup::Notify);
|
||||
} else {
|
||||
acGroup.group("DPMSControl").writeEntry("idleTime", m_screenOffTime * 60 * 1000, KConfigGroup::Notify);
|
||||
batteryGroup.group("DPMSControl").writeEntry("idleTime", m_screenOffTime * 60 * 1000, KConfigGroup::Notify);
|
||||
lowBatteryGroup.group("DPMSControl").writeEntry("idleTime", m_screenOffTime * 60 * 1000, KConfigGroup::Notify);
|
||||
}
|
||||
|
||||
// ensure the system is locked when the screen is turned off
|
||||
acGroup.group("DPMSControl").writeEntry("lockBeforeTurnOff", 1, KConfigGroup::Notify);
|
||||
batteryGroup.group("DPMSControl").writeEntry("lockBeforeTurnOff", 1, KConfigGroup::Notify);
|
||||
lowBatteryGroup.group("DPMSControl").writeEntry("lockBeforeTurnOff", 1, KConfigGroup::Notify);
|
||||
|
||||
if (m_suspendSessionTime == 0) {
|
||||
qDebug() << "Deleting the group SuspendDisplay";
|
||||
|
||||
acGroup.deleteGroup("SuspendSession", KConfigGroup::Notify);
|
||||
batteryGroup.deleteGroup("SuspendSession", KConfigGroup::Notify);
|
||||
lowBatteryGroup.deleteGroup("SuspendSession", KConfigGroup::Notify);
|
||||
} else {
|
||||
acGroup.group("SuspendSession").writeEntry("idleTime", m_suspendSessionTime * 60 * 1000, KConfigGroup::Notify);
|
||||
acGroup.group("SuspendSession").writeEntry("suspendType", 1, KConfigGroup::Notify);
|
||||
|
||||
batteryGroup.group("SuspendSession").writeEntry("idleTime", m_suspendSessionTime * 60 * 1000, KConfigGroup::Notify);
|
||||
batteryGroup.group("SuspendSession").writeEntry("suspendType", 1, KConfigGroup::Notify);
|
||||
|
||||
lowBatteryGroup.group("SuspendSession").writeEntry("idleTime", m_suspendSessionTime * 60 * 1000, KConfigGroup::Notify);
|
||||
lowBatteryGroup.group("SuspendSession").writeEntry("suspendType", 1, KConfigGroup::Notify);
|
||||
}
|
||||
|
||||
m_profilesConfig->sync();
|
||||
// Do not mess with Suspend Type
|
||||
// suspendSessionGroup.writeEntry("suspendType", 32); // always lock screen.
|
||||
}
|
||||
|
||||
QStringList MobilePower::timeOptions() const
|
||||
{
|
||||
return timeValues;
|
||||
}
|
||||
|
||||
void MobilePower::setDimScreenIdx(int idx)
|
||||
{
|
||||
qreal value = idxToMinutes.value(idx);
|
||||
qDebug() << "Got the value" << value;
|
||||
|
||||
if (m_dimScreenTime == value) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (value == 0) {
|
||||
qDebug() << "Setting to never dim";
|
||||
} else {
|
||||
qDebug() << "Setting to dim in " << value << "Minutes";
|
||||
}
|
||||
|
||||
m_dimScreenTime = value;
|
||||
Q_EMIT dimScreenIdxChanged();
|
||||
save();
|
||||
}
|
||||
|
||||
void MobilePower::setScreenOffIdx(int idx)
|
||||
{
|
||||
qreal value = idxToMinutes.value(idx);
|
||||
qDebug() << "Got the value" << value;
|
||||
|
||||
if (m_screenOffTime == value) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (value == 0) {
|
||||
qDebug() << "Setting to never screen off";
|
||||
} else {
|
||||
qDebug() << "Setting to screen off in " << value << "Minutes";
|
||||
}
|
||||
m_screenOffTime = value;
|
||||
|
||||
Q_EMIT screenOffIdxChanged();
|
||||
save();
|
||||
}
|
||||
|
||||
void MobilePower::setSuspendSessionIdx(int idx)
|
||||
{
|
||||
qreal value = idxToMinutes.value(idx);
|
||||
qDebug() << "Got the value" << value;
|
||||
|
||||
if (m_suspendSessionTime == value) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (value == 0) {
|
||||
qDebug() << "Setting to never suspend";
|
||||
} else {
|
||||
qDebug() << "Setting to suspend in " << value << "Minutes";
|
||||
}
|
||||
|
||||
m_suspendSessionTime = value;
|
||||
Q_EMIT suspendSessionIdxChanged();
|
||||
save();
|
||||
}
|
||||
|
||||
int MobilePower::suspendSessionIdx()
|
||||
{
|
||||
if (m_suspendSessionTime == 0) {
|
||||
return NEVER;
|
||||
} else if (qFuzzyIsNull(m_suspendSessionTime)) {
|
||||
return NEVER;
|
||||
} else if (qFuzzyCompare(m_suspendSessionTime, 0.5)) {
|
||||
return THIRTY_SECONDS;
|
||||
}
|
||||
|
||||
return idxToMinutes.key(std::round(m_suspendSessionTime));
|
||||
}
|
||||
|
||||
int MobilePower::dimScreenIdx()
|
||||
{
|
||||
if (m_dimScreenTime == 0) {
|
||||
return NEVER;
|
||||
} else if (qFuzzyIsNull(m_dimScreenTime)) {
|
||||
return NEVER;
|
||||
} else if (qFuzzyCompare(m_dimScreenTime, 0.5)) {
|
||||
return THIRTY_SECONDS;
|
||||
}
|
||||
|
||||
return idxToMinutes.key(std::round(m_dimScreenTime));
|
||||
}
|
||||
|
||||
int MobilePower::screenOffIdx()
|
||||
{
|
||||
if (m_screenOffTime == 0) {
|
||||
return NEVER;
|
||||
} else if (qFuzzyIsNull(m_screenOffTime)) {
|
||||
return NEVER;
|
||||
} else if (qFuzzyCompare(m_screenOffTime, 0.5)) {
|
||||
return THIRTY_SECONDS;
|
||||
}
|
||||
|
||||
return idxToMinutes.key(std::round(m_screenOffTime));
|
||||
}
|
||||
|
||||
BatteryModel *MobilePower::batteries()
|
||||
{
|
||||
return m_batteries;
|
||||
}
|
||||
|
||||
#include "mobilepower.moc"
|
||||
51
kcms/powermanagement/mobilepower.h
Normal file
51
kcms/powermanagement/mobilepower.h
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
// SPDX-FileCopyrightText: 2020 Tomaz Canabrava <tcanabrava@kde.org>
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "batterymodel.h"
|
||||
|
||||
#include <KQuickAddons/ConfigModule>
|
||||
#include <KSharedConfig>
|
||||
#include <memory>
|
||||
|
||||
class MobilePower : public KQuickAddons::ConfigModule
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(BatteryModel *batteries READ batteries CONSTANT)
|
||||
Q_PROPERTY(int dimScreenIdx READ dimScreenIdx WRITE setDimScreenIdx NOTIFY dimScreenIdxChanged)
|
||||
Q_PROPERTY(int screenOffIdx READ screenOffIdx WRITE setScreenOffIdx NOTIFY screenOffIdxChanged)
|
||||
Q_PROPERTY(int suspendSessionIdx READ suspendSessionIdx WRITE setSuspendSessionIdx NOTIFY suspendSessionIdxChanged)
|
||||
|
||||
public:
|
||||
MobilePower(QObject *parent, const KPluginMetaData &metaData, const QVariantList &args);
|
||||
~MobilePower();
|
||||
|
||||
Q_INVOKABLE QStringList timeOptions() const;
|
||||
|
||||
void setDimScreenIdx(int idx);
|
||||
void setScreenOffIdx(int idx);
|
||||
void setSuspendSessionIdx(int idx);
|
||||
int dimScreenIdx();
|
||||
int screenOffIdx();
|
||||
int suspendSessionIdx();
|
||||
|
||||
BatteryModel *batteries();
|
||||
|
||||
Q_SIGNAL void dimScreenIdxChanged();
|
||||
Q_SIGNAL void screenOffIdxChanged();
|
||||
Q_SIGNAL void suspendSessionIdxChanged();
|
||||
|
||||
QString stringForValue(int value);
|
||||
|
||||
void load() override;
|
||||
void save() override;
|
||||
|
||||
private:
|
||||
BatteryModel *m_batteries;
|
||||
KSharedConfig::Ptr m_profilesConfig;
|
||||
|
||||
qreal m_suspendSessionTime;
|
||||
qreal m_dimScreenTime;
|
||||
qreal m_screenOffTime;
|
||||
};
|
||||
185
kcms/powermanagement/package/contents/ui/BatteryPage.qml
Normal file
185
kcms/powermanagement/package/contents/ui/BatteryPage.qml
Normal file
|
|
@ -0,0 +1,185 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2022 Devin Lin <devin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
import QtQuick 2.2
|
||||
import QtQuick.Controls 2.10 as QQC2
|
||||
import QtQuick.Layouts 1.11
|
||||
|
||||
import org.kde.kirigami 2.10 as Kirigami
|
||||
import org.kde.plasma.components 2.0 as PlasmaComponents
|
||||
import org.kde.plasma.core 2.0 as PlasmaCore
|
||||
import org.kde.kcm 1.2
|
||||
import org.kde.kirigamiaddons.labs.mobileform 0.1 as MobileForm
|
||||
import org.kde.kcm.power.mobile.private 1.0
|
||||
|
||||
Kirigami.ScrollablePage {
|
||||
id: root
|
||||
|
||||
property QtObject battery
|
||||
property string vendor
|
||||
property string product
|
||||
property string currentUdi
|
||||
|
||||
title: i18n("Battery Information")
|
||||
|
||||
leftPadding: 0
|
||||
rightPadding: 0
|
||||
topPadding: Kirigami.Units.gridUnit
|
||||
bottomPadding: Kirigami.Units.gridUnit
|
||||
|
||||
HistoryModel {
|
||||
id: history
|
||||
duration: 86400 // last 24 hours
|
||||
device: currentUdi
|
||||
type: HistoryModel.ChargeType
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
width: parent.width
|
||||
spacing: 0
|
||||
|
||||
MobileForm.FormCard {
|
||||
Layout.fillWidth: true
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
spacing: 0
|
||||
|
||||
MobileForm.FormCardHeader {
|
||||
title: i18n("Usage Graph")
|
||||
}
|
||||
|
||||
MobileForm.AbstractFormDelegate {
|
||||
Layout.fillWidth: true
|
||||
background: Item {}
|
||||
clip: true
|
||||
|
||||
contentItem: Flickable {
|
||||
implicitWidth: 500
|
||||
implicitHeight: 200
|
||||
contentWidth: 500
|
||||
contentHeight: 200
|
||||
|
||||
Graph {
|
||||
id: graph
|
||||
width: 500
|
||||
height: 200
|
||||
implicitWidth: 500
|
||||
implicitHeight: 200
|
||||
data: history.points
|
||||
|
||||
// Set grid lines distances which directly correspondent to the xTicksAt variables
|
||||
readonly property var xDivisionWidths: [1000 * 60 * 10, 1000 * 60 * 60 * 12, 1000 * 60 * 60, 1000 * 60 * 30, 1000 * 60 * 60 * 2, 1000 * 60 * 10]
|
||||
xTicksAt: graph.xTicksAtFullSecondHour
|
||||
xDivisionWidth: xDivisionWidths[xTicksAt]
|
||||
|
||||
xMin: history.firstDataPointTime
|
||||
xMax: history.lastDataPointTime
|
||||
xDuration: history.duration
|
||||
|
||||
yUnits: i18nc("literal percent sign","%")
|
||||
yMax: 100
|
||||
yStep: 20
|
||||
visible: history.count > 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MobileForm.FormCard {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: Kirigami.Units.largeSpacing
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
spacing: 0
|
||||
|
||||
MobileForm.FormCardHeader {
|
||||
title: i18n("Information")
|
||||
}
|
||||
|
||||
MobileForm.FormTextDelegate {
|
||||
id: isRechargeableDelegate
|
||||
text: i18n("Is Rechargeable")
|
||||
description: battery.rechargeable ? i18n("Yes") : i18n("No")
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator {}
|
||||
|
||||
MobileForm.FormTextDelegate {
|
||||
id: chargeStateDelegate
|
||||
text: i18n("Charge State")
|
||||
description: {
|
||||
switch (battery.chargeState) {
|
||||
case Battery.NoCharge: return i18n("Not charging")
|
||||
case Battery.Charging: return i18n("Charging")
|
||||
case Battery.Discharging: return i18n("Discharging")
|
||||
case Battery.FullyCharged: return i18n("Fully charged")
|
||||
default: return i18n("Unknown")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator {}
|
||||
|
||||
MobileForm.FormTextDelegate {
|
||||
id: currentChargeDelegate
|
||||
text: i18n("Current Charge")
|
||||
description: i18nc("%1 is value, %2 is unit", "%1 %2", Number(battery.chargePercent).toLocaleString(Qt.locale(), "f", 0), i18n("%"))
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator {}
|
||||
|
||||
MobileForm.FormTextDelegate {
|
||||
id: healthDelegate
|
||||
text: i18n("Health")
|
||||
description: i18nc("%1 is value, %2 is unit", "%1 %2", Number(battery.capacity).toLocaleString(Qt.locale(), "f", 0), i18n("%"))
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator {}
|
||||
|
||||
MobileForm.FormTextDelegate {
|
||||
id: vendorDelegate
|
||||
text: i18n("Vendor")
|
||||
description: root.vendor
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator {}
|
||||
|
||||
MobileForm.FormTextDelegate {
|
||||
id: modelDelegate
|
||||
text: i18n("Model")
|
||||
description: root.product
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator {}
|
||||
|
||||
MobileForm.FormTextDelegate {
|
||||
id: serialDelegate
|
||||
text: i18n("Serial Number")
|
||||
description: battery.serial
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator {}
|
||||
|
||||
MobileForm.FormTextDelegate {
|
||||
id: technologyDelegate
|
||||
text: i18n("Technology")
|
||||
description: {
|
||||
switch (battery.technology) {
|
||||
case Battery.LithiumIon: return i18n("Lithium ion")
|
||||
case Battery.LithiumPolymer: return i18n("Lithium polymer")
|
||||
case Battery.LithiumIronPhosphate: return i18n("Lithium iron phosphate")
|
||||
case Battery.LeadAcid: return i18n("Lead acid")
|
||||
case Battery.NickelCadmium: return i18n("Nickel cadmium")
|
||||
case Battery.NickelMetalHydride: return i18n("Nickel metal hydride")
|
||||
default: return i18n("Unknown technology")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
243
kcms/powermanagement/package/contents/ui/Graph.qml
Normal file
243
kcms/powermanagement/package/contents/ui/Graph.qml
Normal file
|
|
@ -0,0 +1,243 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2015 David Edmundson <david@davidedmundson.co.uk>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*
|
||||
*/
|
||||
|
||||
import QtQuick 2.3
|
||||
|
||||
/**
|
||||
* We need to draw a graph, all other libs are not suitable as we are basically
|
||||
* a connected scatter plot with non linear X spacing.
|
||||
* Currently this is not available in kdeclarative nor kqtquickcharts
|
||||
*
|
||||
* We only paint once, so canvas is fast enough for our purposes.
|
||||
* It is designed to look identical to those in ksysguard.
|
||||
*/
|
||||
|
||||
Canvas
|
||||
{
|
||||
id: canvas
|
||||
antialiasing: true
|
||||
|
||||
readonly property real xTicksAtDontCare: 0
|
||||
readonly property real xTicksAtTwelveOClock: 1
|
||||
readonly property real xTicksAtFullHour: 2
|
||||
readonly property real xTicksAtHalfHour: 3
|
||||
readonly property real xTicksAtFullSecondHour: 4
|
||||
readonly property real xTicksAtTenMinutes: 5
|
||||
readonly property real xTicksAtFullTwoHours: 6
|
||||
|
||||
property int xPadding: 45
|
||||
property int yPadding: 40
|
||||
|
||||
property var data //expect an array of QPointF
|
||||
|
||||
property real yMax: 100
|
||||
property real xMax: 100
|
||||
property real yMin: 0
|
||||
property real xMin: 0
|
||||
property real yStep: 20
|
||||
|
||||
property string yUnits: ""
|
||||
property string xUnits: ""
|
||||
|
||||
property real xDuration: 3600
|
||||
property real xDivisions: 6
|
||||
property real xDivisionWidth: 600000
|
||||
property real xTicksAt: xTicksAtDontCare
|
||||
|
||||
//internal
|
||||
|
||||
property real plotWidth: width - xPadding * 1.5
|
||||
property real plotHeight: height - yPadding * 2
|
||||
|
||||
onDataChanged: {
|
||||
canvas.requestPaint();
|
||||
}
|
||||
|
||||
//take a QPointF
|
||||
function scalePoint(plot, currentUnixTime) {
|
||||
var scaledX = (plot.x - (currentUnixTime / 1000 - xDuration)) / xDuration * plotWidth;
|
||||
var scaledY = (plot.y - yMin) * plotHeight / (yMax - yMin);
|
||||
|
||||
return Qt.point(xPadding + scaledX,
|
||||
height - yPadding - scaledY);
|
||||
}
|
||||
|
||||
SystemPalette {
|
||||
id: palette;
|
||||
colorGroup: SystemPalette.Active
|
||||
}
|
||||
|
||||
|
||||
onPaint: {
|
||||
var c = canvas.getContext('2d');
|
||||
|
||||
c.clearRect(0,0, width, height)
|
||||
|
||||
//draw the background
|
||||
c.fillStyle = palette.base
|
||||
c.fillRect(xPadding, yPadding, plotWidth, plotHeight);
|
||||
|
||||
//reset for fonts and stuff
|
||||
c.fillStyle = palette.text
|
||||
|
||||
//Draw the lines
|
||||
|
||||
c.lineWidth = 1;
|
||||
c.lineJoin = 'round';
|
||||
c.lineCap = 'round';
|
||||
c.strokeStyle = 'rgba(255, 0, 0, 1)';
|
||||
var gradient = c.createLinearGradient(0,0,0,height);
|
||||
gradient.addColorStop(0, 'rgba(255, 0, 0, 0.2)');
|
||||
gradient.addColorStop(1, 'rgba(255, 0, 0, 0.05)');
|
||||
c.fillStyle = gradient;
|
||||
|
||||
// For scaling
|
||||
var currentUnixTime = Date.now()
|
||||
var xMinUnixTime = currentUnixTime - xDuration * 1000
|
||||
|
||||
// Draw the line graph
|
||||
c.beginPath();
|
||||
|
||||
var index = 0
|
||||
|
||||
while ((index < data.length - 1) && (data[index].x < (xMinUnixTime / 1000))) {
|
||||
index++
|
||||
}
|
||||
|
||||
var firstPoint = scalePoint(data[index], currentUnixTime)
|
||||
c.moveTo(firstPoint.x, firstPoint.y)
|
||||
|
||||
var point
|
||||
for (var i = index + 1; i < data.length; i++) {
|
||||
if (data[i].x > (xMinUnixTime / 1000)) {
|
||||
point = scalePoint(data[i], currentUnixTime)
|
||||
c.lineTo(point.x, point.y)
|
||||
}
|
||||
}
|
||||
|
||||
c.stroke();
|
||||
c.strokeStyle = 'rgba(0, 0, 0, 0)';
|
||||
c.lineTo(point.x, height - yPadding);
|
||||
c.lineTo(firstPoint.x, height - yPadding);
|
||||
c.fill();
|
||||
|
||||
c.closePath()
|
||||
|
||||
// Draw the frame on top
|
||||
|
||||
//draw an outline
|
||||
c.strokeStyle = 'rgba(0,50,0,0.02)';
|
||||
c.lineWidth = 1;
|
||||
c.rect(xPadding - 1, yPadding - 1, plotWidth + 2, plotHeight + 2);
|
||||
|
||||
// Draw the Y value texts
|
||||
c.fillStyle = palette.text;
|
||||
c.textAlign = "right"
|
||||
c.textBaseline = "middle";
|
||||
for(var i = 0; i <= yMax; i += yStep) {
|
||||
var y = scalePoint(Qt.point(0,i)).y;
|
||||
|
||||
c.fillText(i + canvas.yUnits, xPadding - 10, y);
|
||||
|
||||
//grid line
|
||||
c.moveTo(xPadding, y)
|
||||
c.lineTo(plotWidth + xPadding, y)
|
||||
}
|
||||
c.stroke()
|
||||
|
||||
// Draw the X value texts
|
||||
c.textAlign = "center"
|
||||
c.lineWidth = 1
|
||||
c.strokeStyle = 'rgba(0, 0, 0, 0.15)'
|
||||
|
||||
var xDivisions = xDuration / xDivisionWidth * 1000
|
||||
var xGridDistance = plotWidth / xDivisions
|
||||
var xTickPos
|
||||
var xTickDateTime
|
||||
var xTickDateStr
|
||||
var xTickTimeStr
|
||||
|
||||
var currentDateTime = new Date()
|
||||
var lastDateStr = currentDateTime.toLocaleDateString(Qt.locale(), Locale.ShortFormat)
|
||||
|
||||
var hours = currentDateTime.getHours()
|
||||
var minutes = currentDateTime.getMinutes()
|
||||
var seconds = currentDateTime.getSeconds()
|
||||
|
||||
var diff
|
||||
|
||||
switch (xTicksAt) {
|
||||
case xTicksAtTwelveOClock:
|
||||
diff = ((hours - 12) * 60 * 60 + minutes * 60 + seconds)
|
||||
break
|
||||
case xTicksAtFullHour:
|
||||
diff = (minutes * 60 + seconds)
|
||||
break
|
||||
case xTicksAtFullSecondHour:
|
||||
diff = (minutes * 60 + seconds)
|
||||
break
|
||||
case xTicksAtHalfHour:
|
||||
diff = ((minutes - 30) * 60 + seconds)
|
||||
break
|
||||
case xTicksAtTenMinutes:
|
||||
diff = ((minutes % 10) * 60 + seconds)
|
||||
break
|
||||
default:
|
||||
diff = 0
|
||||
}
|
||||
|
||||
var xGridOffset = plotWidth * (diff / xDuration)
|
||||
var dateChanged = false
|
||||
|
||||
var dashedLines = 50
|
||||
var dashedLineLength = plotHeight / dashedLines
|
||||
var dashedLineDutyCycle
|
||||
|
||||
for (var i = xDivisions; i >= -1; i--) {
|
||||
xTickPos = i * xGridDistance + xPadding - xGridOffset
|
||||
|
||||
if ((xTickPos > xPadding) && (xTickPos < plotWidth + xPadding))
|
||||
{
|
||||
xTickDateTime = new Date(currentUnixTime - (xDivisions - i) * xDivisionWidth - diff * 1000)
|
||||
xTickDateStr = xTickDateTime.toLocaleDateString(Qt.locale(), Locale.ShortFormat)
|
||||
xTickTimeStr = xTickDateTime.toLocaleTimeString(Qt.locale(), Locale.ShortFormat)
|
||||
|
||||
if (lastDateStr != xTickDateStr) {
|
||||
dateChanged = true
|
||||
}
|
||||
|
||||
if ((i % 2 == 0) || (xDivisions < 10))
|
||||
{
|
||||
// Display the time
|
||||
c.fillText(xTickTimeStr, xTickPos, canvas.height - yPadding / 2)
|
||||
|
||||
// If the date has changed and is not the current day in a <= 24h graph, display it
|
||||
// Always display the date for 48h and 1 week graphs
|
||||
if (dateChanged || (xDuration > (60*60*48))) {
|
||||
c.fillText(xTickDateStr, xTickPos, canvas.height - yPadding / 4)
|
||||
dateChanged = false
|
||||
}
|
||||
|
||||
// Tick markers
|
||||
c.moveTo(xTickPos, canvas.height - yPadding)
|
||||
c.lineTo(xTickPos, canvas.height - (yPadding * 4) / 5)
|
||||
|
||||
dashedLineDutyCycle = 0.5
|
||||
} else {
|
||||
dashedLineDutyCycle = 0.1
|
||||
}
|
||||
|
||||
for (var j = 0; j < dashedLines; j++) {
|
||||
c.moveTo(xTickPos, yPadding + j * dashedLineLength)
|
||||
c.lineTo(xTickPos, yPadding + j * dashedLineLength + dashedLineDutyCycle * dashedLineLength)
|
||||
}
|
||||
lastDateStr = xTickDateStr
|
||||
}
|
||||
}
|
||||
c.stroke()
|
||||
}
|
||||
}
|
||||
165
kcms/powermanagement/package/contents/ui/main.qml
Normal file
165
kcms/powermanagement/package/contents/ui/main.qml
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2011 Sebastian Kügler <sebas@kde.org>
|
||||
SPDX-FileCopyrightText: 2012 Marco Martin <mart@kde.org>
|
||||
SPDX-FileCopyrightText: 2015 Kai Uwe Broulik <kde@privat.broulik.de>
|
||||
SPDX-FileCopyrightText: 2022 Devin Lin <devin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
import QtQuick 2.2
|
||||
import QtQuick.Controls 2.10 as QQC2
|
||||
import QtQuick.Layouts 1.11
|
||||
|
||||
import org.kde.kirigami 2.10 as Kirigami
|
||||
import org.kde.plasma.components 2.0 as PlasmaComponents
|
||||
import org.kde.plasma.core 2.0 as PlasmaCore
|
||||
import org.kde.kcm 1.2
|
||||
import org.kde.kirigamiaddons.labs.mobileform 0.1 as MobileForm
|
||||
import org.kde.kcm.power.mobile.private 1.0
|
||||
|
||||
SimpleKCM {
|
||||
id: powermanagementModule
|
||||
|
||||
leftPadding: 0
|
||||
rightPadding: 0
|
||||
topPadding: Kirigami.Units.gridUnit
|
||||
bottomPadding: Kirigami.Units.gridUnit
|
||||
|
||||
ColumnLayout {
|
||||
width: parent.width
|
||||
spacing: 0
|
||||
|
||||
MobileForm.FormCard {
|
||||
Layout.fillWidth: true
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
spacing: 0
|
||||
|
||||
MobileForm.FormCardHeader {
|
||||
title: i18n("Devices")
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: kcm.batteries
|
||||
|
||||
delegate: MobileForm.AbstractFormDelegate {
|
||||
Layout.fillWidth: true
|
||||
|
||||
onClicked: kcm.push("BatteryPage.qml", { "battery": model.battery, "vendor": model.vendor, "product": model.product, "currentUdi": model.udi })
|
||||
|
||||
contentItem: RowLayout {
|
||||
spacing: Kirigami.Units.gridUnit
|
||||
|
||||
Kirigami.Icon {
|
||||
implicitWidth: Kirigami.Units.iconSizes.smallMedium
|
||||
implicitHeight: Kirigami.Units.iconSizes.smallMedium
|
||||
Layout.rightMargin: Kirigami.Units.largeSpacing
|
||||
source: {
|
||||
switch (model.battery.type) {
|
||||
case 3: return model.battery.chargeState === 1 ? "battery-full-charging" : "battery-full"
|
||||
case 2: return "battery-ups"
|
||||
case 9: return "monitor"
|
||||
case 4: return "input-mouse"
|
||||
case 5: return "input-keyboard"
|
||||
case 1: return "phone"
|
||||
case 7: return "smartphone"
|
||||
default: return "paint-unknown"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
|
||||
QQC2.Label {
|
||||
Layout.fillWidth: true
|
||||
elide: Text.ElideRight
|
||||
wrapMode: Text.Wrap
|
||||
maximumLineCount: 2
|
||||
color: Kirigami.Theme.textColor
|
||||
text: {
|
||||
let batteryType;
|
||||
switch (model.battery.type) {
|
||||
case 3: batteryType = i18n("Internal battery"); break;
|
||||
case 2: batteryType = i18n("UPS battery"); break;
|
||||
case 9: batteryType = i18n("Monitor battery"); break;
|
||||
case 4: batteryType = i18n("Mouse battery"); break;
|
||||
case 5: batteryType = i18n("Keyboard battery"); break;
|
||||
case 1: batteryType = i18n("PDA battery"); break;
|
||||
case 7: batteryType = i18n("Phone battery"); break;
|
||||
default: batteryType = i18n("Unknown battery"); break;
|
||||
}
|
||||
|
||||
const chargePercent = i18nc("%1 is value, %2 is unit", "%1%2", Number(battery.chargePercent).toLocaleString(Qt.locale(), "f", 0), i18n("%"));
|
||||
|
||||
return (model.battery.chargeState === Battery.Charging) ? i18nc("%1 is battery type, %2 is charge percent", "%1 %2 (Charging)", batteryType, chargePercent) : i18nc("%1 is battery type, %2 is charge percent", "%1 %2", batteryType, chargePercent);
|
||||
}
|
||||
}
|
||||
|
||||
QQC2.ProgressBar {
|
||||
Layout.fillWidth: true
|
||||
from: 0
|
||||
to: 100
|
||||
value: model.battery.chargePercent
|
||||
}
|
||||
}
|
||||
|
||||
Kirigami.Icon {
|
||||
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
||||
source: "arrow-right"
|
||||
implicitWidth: Math.round(Kirigami.Units.iconSizes.small * 0.75)
|
||||
implicitHeight: Math.round(Kirigami.Units.iconSizes.small * 0.75)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MobileForm.FormCard {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: Kirigami.Units.largeSpacing
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
spacing: 0
|
||||
|
||||
MobileForm.FormCardHeader {
|
||||
title: i18n("Screen")
|
||||
}
|
||||
|
||||
MobileForm.FormComboBoxDelegate {
|
||||
id: dimScreenCombo
|
||||
text: i18nc("Part of a sentence like 'Dim screen after 5 minutes'", "Dim screen after")
|
||||
model: kcm.timeOptions()
|
||||
currentIndex: kcm.dimScreenIdx
|
||||
Component.onCompleted: dialog.parent = powermanagementModule
|
||||
onCurrentIndexChanged: kcm.dimScreenIdx = currentIndex
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator { above: dimScreenCombo; below: screenOffCombo }
|
||||
|
||||
MobileForm.FormComboBoxDelegate {
|
||||
id: screenOffCombo
|
||||
text: i18nc("Part of a sentence like 'Turn off screen after 5 minutes'", "Turn off screen after")
|
||||
model: kcm.timeOptions()
|
||||
currentIndex: kcm.screenOffIdx
|
||||
Component.onCompleted: dialog.parent = powermanagementModule
|
||||
onCurrentIndexChanged: kcm.screenOffIdx = currentIndex
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator { above: screenOffCombo; below: suspendCombo }
|
||||
|
||||
MobileForm.FormComboBoxDelegate {
|
||||
id: suspendCombo
|
||||
text: i18nc("Part of a sentence like 'Suspend device after 5 minutes'", "Suspend device after")
|
||||
model: kcm.timeOptions()
|
||||
currentIndex: kcm.suspendSessionIdx
|
||||
Component.onCompleted: dialog.parent = powermanagementModule
|
||||
onCurrentIndexChanged: kcm.suspendSessionIdx = currentIndex
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
111
kcms/powermanagement/powermanagement.json
Normal file
111
kcms/powermanagement/powermanagement.json
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
{
|
||||
"Categories": "Qt;KDE;X-KDE-settings-system;",
|
||||
"KPlugin": {
|
||||
"Description": "Configure power management settings",
|
||||
"Description[az]": "Enerji sərfiyyatı ayarlarını tənzimlə",
|
||||
"Description[ca@valencia]": "Configureu els paràmetres de gestió de l'energia",
|
||||
"Description[ca]": "Configuració dels paràmetres de gestió d'energia",
|
||||
"Description[cs]": "Konfigurace nastavení správy napájení",
|
||||
"Description[en_GB]": "Configure power management settings",
|
||||
"Description[es]": "Configurar las preferencias de la gestión de energía",
|
||||
"Description[eu]": "Konfiguratu energia-kudeaketa ezarpenak",
|
||||
"Description[fi]": "Aseta virranhallinta",
|
||||
"Description[fr]": "Configurer les paramètres de gestion de l'énergie ",
|
||||
"Description[ia]": "Configura preferentias de gestion de energia",
|
||||
"Description[is]": "Grunnstilla orkunotkun",
|
||||
"Description[it]": "Configura le impostazioni di gestione energetica",
|
||||
"Description[ka]": "ენერგიის მართვის პარამეტრების კონფიგურაცია",
|
||||
"Description[ko]": "전력 관리 설정",
|
||||
"Description[lt]": "Konfigūruoti energijos valdymo nuostatas",
|
||||
"Description[nl]": "Energie-instellingen configureren",
|
||||
"Description[nn]": "Set opp straumstyring",
|
||||
"Description[pa]": "ਪਾਵਰ ਇੰਤਜ਼ਾਮ ਸੈਟਿੰਗਾਂ ਦੀ ਸੰਰਚਨਾ",
|
||||
"Description[pl]": "Ustawienia zarządzania energią",
|
||||
"Description[pt]": "Configurar as definições de gestão de energia",
|
||||
"Description[pt_BR]": "Configurar as opções do gerenciamento de energia",
|
||||
"Description[ru]": "Настройка параметров энергопотребления",
|
||||
"Description[sl]": "Konfiguriraj nastavitve upravljanja energijo",
|
||||
"Description[sv]": "Anpassa inställningar av strömhantering",
|
||||
"Description[tr]": "Güç yönetimi ayarlarını yapılandır",
|
||||
"Description[uk]": "Налаштовування керування живленням",
|
||||
"Description[vi]": "Cấu hình thiết lập quản lí nguồn điện",
|
||||
"Description[x-test]": "xxConfigure power management settingsxx",
|
||||
"Description[zh_CN]": "配置电源管理设置。",
|
||||
"FormFactors": [
|
||||
"handset",
|
||||
"tablet",
|
||||
"mediacenter"
|
||||
],
|
||||
"Icon": "preferences-system-power-management",
|
||||
"Name": "Energy",
|
||||
"Name[az]": "Enerji sərfiyyatı",
|
||||
"Name[ca@valencia]": "Energia",
|
||||
"Name[ca]": "Energia",
|
||||
"Name[cs]": "Energie",
|
||||
"Name[en_GB]": "Energy",
|
||||
"Name[es]": "Energía",
|
||||
"Name[eu]": "Energia",
|
||||
"Name[fi]": "Virta",
|
||||
"Name[fr]": "Énergie",
|
||||
"Name[ia]": "Energia",
|
||||
"Name[is]": "Orka",
|
||||
"Name[it]": "Energia",
|
||||
"Name[ka]": "ენერგია",
|
||||
"Name[ko]": "에너지",
|
||||
"Name[lt]": "Energija",
|
||||
"Name[nl]": "Energie",
|
||||
"Name[nn]": "Energibruk",
|
||||
"Name[pa]": "ਊਰਜਾ",
|
||||
"Name[pl]": "Energia",
|
||||
"Name[pt]": "Energia",
|
||||
"Name[pt_BR]": "Energia",
|
||||
"Name[ru]": "Энергопотребление",
|
||||
"Name[sl]": "Energija",
|
||||
"Name[sv]": "Energi",
|
||||
"Name[tr]": "Enerji",
|
||||
"Name[uk]": "Живлення",
|
||||
"Name[vi]": "Năng lượng",
|
||||
"Name[x-test]": "xxEnergyxx",
|
||||
"Name[zh_CN]": "电量"
|
||||
},
|
||||
"X-KDE-Keywords": "video, monitor, graphics, timeout, sleep, lock, screenlocker, screensaver",
|
||||
"X-KDE-Keywords[ast]": "videu,monitor,gráficos,dormir,dormición,bloquiar,bloquéu,curiapantalles,bloquiador de pantalla",
|
||||
"X-KDE-Keywords[az]": "video, monitor, graphics, timeout, sleep, lock, screenlocker, screensaver,qrafiklər,boşdayanma,yuxu,kilid,ekran kilidləyici,ekran qoruyucu",
|
||||
"X-KDE-Keywords[ca@valencia]": "vídeo, monitor, gràfics, temps d'espera, adorm, bloqueja, bloqueig de la pantalla, estalvi de pantalla",
|
||||
"X-KDE-Keywords[ca]": "vídeo, monitor, gràfics, temps d'espera, adorm, bloqueja, bloqueig de la pantalla, estalvi de pantalla",
|
||||
"X-KDE-Keywords[cs]": "video, monitor, grafika, časový limit, spánek, zámek, zamčení obrazovky, spořič obrazovky",
|
||||
"X-KDE-Keywords[da]": "video, skærm, grafik, tidsudløb, slumre, lås, skærmlåsning, pauseskærm",
|
||||
"X-KDE-Keywords[de]": "Video,Monitor,Grafik,Zeitüberschreitung,Standby,Sperren, Bildschirmsperre,Bildschirmschoner",
|
||||
"X-KDE-Keywords[el]": "βίντεο, οθόνη, γραφικά, χρονικό όριο, ύπνωση, κλείδωμα, κλείδωμα οθόνης, προστασία οθόνης",
|
||||
"X-KDE-Keywords[en_GB]": "video, monitor, graphics, timeout, sleep, lock, screenlocker, screensaver",
|
||||
"X-KDE-Keywords[es]": "vídeo, monitor, gráficos, tiempo de espera, dormir, bloquear, bloqueo de pantalla, salvapantallas",
|
||||
"X-KDE-Keywords[et]": "video, monitor, graafika, aegumine, uni, lukustus, ekraanisäästja",
|
||||
"X-KDE-Keywords[eu]": "bideoa, monitorea, grafikoak, denbora-muga, egin lo, giltzatu, pantaila-giltzatzailea, pantaila-babeslea",
|
||||
"X-KDE-Keywords[fi]": "video, näyttö, grafiikka, aikakatkaisu, keskeytystila, lukitus, näyttölukko, näytönsäästäjä",
|
||||
"X-KDE-Keywords[fr]": "vidéo, écran, graphique, mise en veille, sommeil, verrouillage, verrouillage d'écran, écran de veille",
|
||||
"X-KDE-Keywords[gl]": "vídeo, monitor, gráficos, tempo límite, hibernar, bloquear, bloqueador de pantalla, salvapantallas",
|
||||
"X-KDE-Keywords[hu]": "videó, monitor, grafika, időkorlát, alvás, zárolás, képernyőzár, képernyővédő",
|
||||
"X-KDE-Keywords[ia]": "video, monitor, graphics, timeout, sleep, lock, screenlocker, screensaver",
|
||||
"X-KDE-Keywords[it]": "video, monitor, grafica, tempo massimo, attendi, blocca, bloccaschermo, salvaschermo",
|
||||
"X-KDE-Keywords[ko]": "video, monitor, graphics, timeout, sleep, lock, screenlocker, screensaver, 비디오, 모니터, 그래픽, 시간 제한, 절전, 대기, 잠금, 화면 보호기, 화면 잠금",
|
||||
"X-KDE-Keywords[lt]": "vaizdas, monitorius, vaizduoklis, grafika, laiko limitas, miegas, miegoti, užraktas, uzraktas, užrakinti, uzrakinti, ekrano užraktas, ekrano uzraktas, ekrano užsklanda, ekrano uzsklanda",
|
||||
"X-KDE-Keywords[nl]": "video, monitor, grafisch, tijdslimiet, onderbreken, vergrendelen, schermvergrendelaar, schermbeveiliging",
|
||||
"X-KDE-Keywords[nn]": "video, skjerm, grafikk, tidsavbrot, timeout, sove, lås, låsing, skjermlåsar, pauseskjerm, skjermsparar",
|
||||
"X-KDE-Keywords[pa]": "ਵੀਡੀਓ, ਮਾਨੀਟਰ, ਗਰਾਫਿਕਸ, ਟਾਈਮ ਆਉਟ, ਸਲੀਪ, ਲਾਕ, ਸਕਰੀਨ-ਲਾਕਰ, ਸਕਰੀਨ-ਸੇਵਰ",
|
||||
"X-KDE-Keywords[pl]": "video, monitor, grafika, timeout, uśpij, zablokuj, blokada ekranu, wygaszacz ekranu",
|
||||
"X-KDE-Keywords[pt]": "vídeo, monitor, gráfica, tempo-limite, suspender, bloquear, bloqueio de ecrã, protector de ecrã",
|
||||
"X-KDE-Keywords[pt_BR]": "vídeo, monitor, gráfico, tempo limite, suspender, bloquear, bloqueio de tela, protetor de tela",
|
||||
"X-KDE-Keywords[ro]": "video, monitor, grafică, expirare, somn, adormire, blocare, blocare ecran, protecție ecran",
|
||||
"X-KDE-Keywords[ru]": "video, monitor, graphics, timeout, sleep, lock, screenlocker, screensaver, видео, монитор, экран, графика, блокировка",
|
||||
"X-KDE-Keywords[sk]": "video, obrazovka, grafika, prestávka, spánok, zámok, zámok obrazovky, šetrič obrazovky",
|
||||
"X-KDE-Keywords[sl]": "video, zaslon, grafika, časovna omejitev, spanje, zaklep, zaklep zaslona, ohranjevalnik zaslona",
|
||||
"X-KDE-Keywords[sv]": "video, bildskärm, grafik, tidsgräns, viloläge, låsning, skärmlåsning, skärmsläckare",
|
||||
"X-KDE-Keywords[tr]": "video, monitör, grafikler, zaman aşımı, uyku, kilit, ekran kilitleyici, ekran koruyucu",
|
||||
"X-KDE-Keywords[uk]": "video, monitor, graphics, timeout, sleep, lock, screenlocker, screensaver, відео, монітор, графіка, час очікування, присипляння, блокування, збереження, екран",
|
||||
"X-KDE-Keywords[vi]": "video,monitor,graphics,timeout,sleep,lock,screenlocker,screensaver,phim,màn hình,đồ hoạ,tắt màn hình,ngủ,khoá,khoá màn hình,bảo vệ màn hình",
|
||||
"X-KDE-Keywords[x-test]": "xxvideoxx,xx monitorxx,xx graphicsxx,xx timeoutxx,xx sleepxx,xx lockxx,xx screenlockerxx,xx screensaverxx",
|
||||
"X-KDE-Keywords[zh_CN]": "video, monitor, graphics, timeout, sleep, lock, screenlocker, screensaver, 视频, 显示器, 监视器, 图形, 图像, 超时, 睡眠, 锁屏, 屏幕保护, 屏幕锁定, 屏保, 锁定",
|
||||
"X-KDE-Keywords[zh_TW]": "video, monitor, graphics, timeout, sleep, lock, screenlocker, screensaver, 影片, 顯示器, 圖形, 顯示卡, 逾時, 休眠, 鎖定, 螢幕鎖定, 螢幕保護程式",
|
||||
"X-KDE-System-Settings-Parent-Category": "display",
|
||||
"X-KDE-Weight": 70
|
||||
}
|
||||
188
kcms/powermanagement/statisticsprovider.cpp
Normal file
188
kcms/powermanagement/statisticsprovider.cpp
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2015 David Edmundson <david@davidedmundson.co.uk>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*
|
||||
*/
|
||||
|
||||
#include "statisticsprovider.h"
|
||||
|
||||
#include <QDBusArgument>
|
||||
#include <QDBusConnection>
|
||||
#include <QDBusInterface>
|
||||
#include <QDBusMessage>
|
||||
#include <QDBusMetaType> // qDBusRegisterMetaType
|
||||
#include <QDBusPendingReply>
|
||||
#include <QDebug>
|
||||
|
||||
const QDBusArgument &operator<<(QDBusArgument &argument, const HistoryReply &data)
|
||||
{
|
||||
argument.beginStructure();
|
||||
argument << data.time << data.value << data.charging;
|
||||
argument.endStructure();
|
||||
return argument;
|
||||
}
|
||||
|
||||
const QDBusArgument &operator>>(const QDBusArgument &arg, HistoryReply &attrs)
|
||||
{
|
||||
arg.beginStructure();
|
||||
arg >> attrs.time >> attrs.value >> attrs.charging;
|
||||
arg.endStructure();
|
||||
return arg;
|
||||
}
|
||||
|
||||
StatisticsProvider::StatisticsProvider(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
m_type = StatisticsProvider::ChargeType;
|
||||
m_duration = 120;
|
||||
|
||||
qDBusRegisterMetaType<HistoryReply>();
|
||||
qDBusRegisterMetaType<QList<HistoryReply>>();
|
||||
}
|
||||
|
||||
void StatisticsProvider::setDevice(const QString &device)
|
||||
{
|
||||
if (device == m_device) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_device = device;
|
||||
Q_EMIT deviceChanged();
|
||||
|
||||
load();
|
||||
}
|
||||
|
||||
void StatisticsProvider::setDuration(uint duration)
|
||||
{
|
||||
if (duration == m_duration) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_duration = duration;
|
||||
Q_EMIT durationChanged();
|
||||
|
||||
load();
|
||||
}
|
||||
|
||||
void StatisticsProvider::setType(StatisticsProvider::HistoryType type)
|
||||
{
|
||||
if (m_type == type) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_type = type;
|
||||
Q_EMIT typeChanged();
|
||||
|
||||
load();
|
||||
}
|
||||
|
||||
void StatisticsProvider::classBegin()
|
||||
{
|
||||
}
|
||||
|
||||
void StatisticsProvider::componentComplete()
|
||||
{
|
||||
m_isComplete = true;
|
||||
load();
|
||||
}
|
||||
|
||||
QVariantList StatisticsProvider::asPoints() const
|
||||
{
|
||||
QVariantList points;
|
||||
points.reserve(m_values.count());
|
||||
foreach (const HistoryReply &h, m_values) {
|
||||
points.append(QPointF(h.time, h.value));
|
||||
}
|
||||
|
||||
if (!points.isEmpty()) {
|
||||
points.takeLast();
|
||||
}
|
||||
|
||||
return points;
|
||||
}
|
||||
|
||||
int StatisticsProvider::count() const
|
||||
{
|
||||
return m_values.count();
|
||||
}
|
||||
|
||||
int StatisticsProvider::firstDataPointTime() const
|
||||
{
|
||||
if (m_values.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return m_values.first().time;
|
||||
}
|
||||
|
||||
int StatisticsProvider::lastDataPointTime() const
|
||||
{
|
||||
if (m_values.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return m_values.last().time;
|
||||
}
|
||||
|
||||
int StatisticsProvider::largestValue() const
|
||||
{
|
||||
if (m_values.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int max = 0; // TODO std::max or something?
|
||||
for (auto it = m_values.constBegin(), end = m_values.constEnd(); it != end; ++it) {
|
||||
if ((*it).value > max) {
|
||||
max = (*it).value;
|
||||
}
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
void StatisticsProvider::refresh()
|
||||
{
|
||||
load();
|
||||
}
|
||||
|
||||
void StatisticsProvider::load()
|
||||
{
|
||||
if (!m_isComplete || m_device.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto msg = QDBusMessage::createMethodCall(QStringLiteral("org.freedesktop.UPower"),
|
||||
m_device,
|
||||
QStringLiteral("org.freedesktop.UPower.Device"),
|
||||
QStringLiteral("GetHistory"));
|
||||
if (m_type == RateType) {
|
||||
msg << QLatin1String("rate");
|
||||
} else { // m_type must = ChargeType
|
||||
msg << QLatin1String("charge");
|
||||
}
|
||||
|
||||
uint resolution = 100;
|
||||
msg << m_duration << resolution;
|
||||
|
||||
QDBusPendingReply<QList<HistoryReply>> reply = QDBusConnection::systemBus().asyncCall(msg);
|
||||
|
||||
auto *watcher = new QDBusPendingCallWatcher(reply, this);
|
||||
QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this, [this](QDBusPendingCallWatcher *watcher) {
|
||||
QDBusPendingReply<QList<HistoryReply>> reply = *watcher;
|
||||
watcher->deleteLater();
|
||||
m_values.clear();
|
||||
|
||||
if (reply.isError()) {
|
||||
qWarning() << "Failed to get device history from UPower" << reply.error().message();
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (const HistoryReply &r, reply.value()) {
|
||||
if (r.value > 0) { // we get back some values which contain no value, possibly to indicate if charging changes, ignore them
|
||||
m_values.prepend(r);
|
||||
}
|
||||
}
|
||||
|
||||
Q_EMIT dataChanged();
|
||||
});
|
||||
}
|
||||
89
kcms/powermanagement/statisticsprovider.h
Normal file
89
kcms/powermanagement/statisticsprovider.h
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2015 David Edmundson <david@davidedmundson.co.uk>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef STATISTICSPROVIDER_H
|
||||
#define STATISTICSPROVIDER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QPointF>
|
||||
#include <QQmlParserStatus>
|
||||
|
||||
struct HistoryReply {
|
||||
public:
|
||||
uint time = 0;
|
||||
double value = 0.0;
|
||||
uint charging = 0;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(HistoryReply)
|
||||
|
||||
class StatisticsProvider : public QObject, public QQmlParserStatus
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(QQmlParserStatus)
|
||||
|
||||
Q_PROPERTY(QString device MEMBER m_device WRITE setDevice NOTIFY deviceChanged)
|
||||
Q_PROPERTY(uint duration MEMBER m_duration WRITE setDuration NOTIFY durationChanged)
|
||||
Q_PROPERTY(HistoryType type MEMBER m_type WRITE setType NOTIFY typeChanged)
|
||||
|
||||
Q_PROPERTY(QVariantList points READ asPoints NOTIFY dataChanged)
|
||||
Q_PROPERTY(int count READ count NOTIFY dataChanged)
|
||||
Q_PROPERTY(int firstDataPointTime READ firstDataPointTime NOTIFY dataChanged)
|
||||
Q_PROPERTY(int lastDataPointTime READ lastDataPointTime NOTIFY dataChanged)
|
||||
Q_PROPERTY(int largestValue READ largestValue NOTIFY dataChanged)
|
||||
|
||||
public:
|
||||
enum HistoryType {
|
||||
RateType,
|
||||
ChargeType,
|
||||
};
|
||||
Q_ENUM(HistoryType)
|
||||
|
||||
enum HistoryRoles {
|
||||
TimeRole = Qt::UserRole + 1,
|
||||
ValueRole,
|
||||
ChargingRole,
|
||||
};
|
||||
|
||||
explicit StatisticsProvider(QObject *parent = nullptr);
|
||||
|
||||
void setDevice(const QString &device);
|
||||
void setDuration(uint duration);
|
||||
void setType(HistoryType type);
|
||||
|
||||
void load();
|
||||
|
||||
void classBegin() override;
|
||||
void componentComplete() override;
|
||||
|
||||
QVariantList asPoints() const;
|
||||
int count() const;
|
||||
|
||||
int firstDataPointTime() const;
|
||||
int lastDataPointTime() const;
|
||||
int largestValue() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void deviceChanged();
|
||||
void typeChanged();
|
||||
void durationChanged();
|
||||
|
||||
void dataChanged();
|
||||
|
||||
public Q_SLOTS:
|
||||
void refresh();
|
||||
|
||||
private:
|
||||
QString m_device;
|
||||
HistoryType m_type;
|
||||
uint m_duration; // in seconds
|
||||
|
||||
QList<HistoryReply> m_values;
|
||||
bool m_isComplete = false;
|
||||
};
|
||||
|
||||
#endif // STATISTICSPROVIDER_H
|
||||
23
kcms/time/CMakeLists.txt
Normal file
23
kcms/time/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
set(timesettings_SRCS
|
||||
timesettings.cpp
|
||||
timezonemodel.cpp
|
||||
timezonesi18n.cpp
|
||||
)
|
||||
|
||||
qt_add_dbus_interface(timesettings_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/timedated1.xml timedated_interface)
|
||||
|
||||
add_library(kcm_mobile_time MODULE ${timesettings_SRCS})
|
||||
|
||||
target_link_libraries(kcm_mobile_time
|
||||
Qt::Quick
|
||||
Qt::Qml
|
||||
Qt::DBus
|
||||
KF6::QuickAddons
|
||||
KF6::ConfigCore
|
||||
KF6::I18n
|
||||
)
|
||||
|
||||
# Time and Date
|
||||
|
||||
install(TARGETS kcm_mobile_time DESTINATION ${KDE_INSTALL_QTPLUGINDIR}/kcms)
|
||||
kpackage_install_package(package kcm_mobile_time kcms)
|
||||
1
kcms/time/Messages.sh
Normal file
1
kcms/time/Messages.sh
Normal file
|
|
@ -0,0 +1 @@
|
|||
$XGETTEXT $(find . -name \*.cpp -o -name \*.h -o -name \*.qml) -o $podir/kcm_mobile_time.pot
|
||||
128
kcms/time/clockconfig_actions.actions
Normal file
128
kcms/time/clockconfig_actions.actions
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
[Domain]
|
||||
Name=Date and Time Control Module
|
||||
Name[az]=Tarix və Vaxta Nəzarət Modulu
|
||||
Name[ca]=Mòdul de control de la data i hora
|
||||
Name[ca@valencia]=Mòdul de control de la data i hora
|
||||
Name[cs]=Ovládací modul data a času
|
||||
Name[da]=Dato og klokkeslæt-kontrolmodul
|
||||
Name[de]=Kontrollmodul für Datum und Zeit
|
||||
Name[el]=Άρθρωμα ελέγχου ημερομηνίας και ώρας
|
||||
Name[en_GB]=Date and Time Control Module
|
||||
Name[es]=Módulo de control de fecha y hora
|
||||
Name[et]=Kuupäeva ja kellaaja juhtimismoodul
|
||||
Name[eu]=Data eta ordua aginte modulua
|
||||
Name[fi]=Aika-asetukset
|
||||
Name[fr]=Module de contrôle de date et d'heure
|
||||
Name[gl]=Módulo de control da data e hora
|
||||
Name[hu]=Dátum és idő beállítómodul
|
||||
Name[ia]=Modulo de controlo de data e tempore
|
||||
Name[id]=Modul Kontrol Waktu dan Tanggal
|
||||
Name[is]=Stjórneining fyrir dagsetningu og tíma
|
||||
Name[it]=Modulo di controllo Data e ora
|
||||
Name[ka]=თარიღისა და დროის კონტროლის მოდული
|
||||
Name[ko]=날짜와 시간 제어 모듈
|
||||
Name[lt]=Datos ir laiko valdymo modulis
|
||||
Name[nl]=Controlemodule van datum en tijd
|
||||
Name[nn]=Kontrollmodul for dato og klokkeslett
|
||||
Name[pa]=ਮਿਤੀ ਅਤੇ ਟਾਈਮ ਕੰਟਰੋਲ ਮੋਡੀਊਲ
|
||||
Name[pl]=Moduł sterowania datą i czasem
|
||||
Name[pt]=Módulo de Controlo da Data e Hora
|
||||
Name[pt_BR]=Módulo de controle da data e hora
|
||||
Name[ro]=Modul de control pentru dată și oră
|
||||
Name[ru]=Модуль настройки даты и времени
|
||||
Name[sk]=Modul pre nastavenie dátumu a času
|
||||
Name[sl]=Nadzorni modul za datum in čas
|
||||
Name[sv]=Inställningsmodul för datum och tid
|
||||
Name[ta]=தேதி மற்றும் நேரத்தை கட்டுப்படுத்தும் கூறு
|
||||
Name[tr]=Tarih ve Zaman Denetim Modülü
|
||||
Name[uk]=Модуль керування датою і часом
|
||||
Name[vi]=Khối điều khiển ngày giờ
|
||||
Name[x-test]=xxDate and Time Control Modulexx
|
||||
Name[zh_CN]=日期和时间控制模块
|
||||
Name[zh_TW]=日期與時間控制模組
|
||||
Icon=preferences-system-time
|
||||
|
||||
[org.kde.active.clockconfig.save]
|
||||
Name=Save the date/time settings
|
||||
Name[az]=Tarix/Vaxt ayarlarını saxlamaq
|
||||
Name[ca]=Desa la configuració de la data i hora
|
||||
Name[ca@valencia]=Guarda la configuració de la data i hora
|
||||
Name[cs]=Uložit nastavení data a času
|
||||
Name[da]=Gem dato-/klokkeslætsindstillingerne
|
||||
Name[de]=Einstellungen für Datum und Zeit speichern
|
||||
Name[el]=Αποθήκευση των ρυθμίσεων ημερομηνίας/ώρας
|
||||
Name[en_GB]=Save the date/time settings
|
||||
Name[es]=Guardar las preferencias de fecha y hora
|
||||
Name[et]=Kuupäeva/kellaaja seadistuste salvestamine
|
||||
Name[eu]=Gorde data/ordu ezarpenak
|
||||
Name[fi]=Tallenna päiväyksen ja ajan asetukset
|
||||
Name[fr]=Enregistrement des paramètres de date / d'heure
|
||||
Name[gl]=Garda a configuración da data e hora
|
||||
Name[hu]=A dátum- és időbeállítások mentése
|
||||
Name[ia]=Salveguarda le preferentias de data/ tempore
|
||||
Name[id]=Simpan pengaturan waktu/tanggal
|
||||
Name[is]=Vista stillingar dagsetningar og tíma
|
||||
Name[it]=Salva le impostazioni di data e ora
|
||||
Name[ka]=თარიღის/დროის პარამეტრების შენახვა
|
||||
Name[ko]=날짜와 시간 설정 저장
|
||||
Name[lt]=Įrašyti datos/laiko nuostatas
|
||||
Name[nl]=Datum- en tijdinstellingen opslaan
|
||||
Name[nn]=Lagra innstillingane for dato og klokkeslett
|
||||
Name[pa]=ਮਿਤੀ/ਸਮਾਂ ਸੈਟਿੰਗਾਂ ਸੰਭਾਲੋ
|
||||
Name[pl]=Zapisz ustawienia daty/czasu
|
||||
Name[pt]=Mudar a configuração da data/hora
|
||||
Name[pt_BR]=Salvar as configurações de data e hora
|
||||
Name[ro]=Salvează configurările datei și orei
|
||||
Name[ru]=Сохранить параметры даты и времени
|
||||
Name[sk]=Uložiť nastavenia dátumu a času
|
||||
Name[sl]=Shranjevanje nastavitev datuma in časa
|
||||
Name[sv]=Spara inställningar av datum och tid
|
||||
Name[ta]=தேதி மற்றும் நேர அமைப்புகளை சேமியுங்கள்
|
||||
Name[tr]=Tarih/zaman ayarlarını kaydet
|
||||
Name[uk]=Зберегти параметри дати/часу
|
||||
Name[vi]=Lưu thiết lập ngày/giờ
|
||||
Name[x-test]=xxSave the date/time settingsxx
|
||||
Name[zh_CN]=保存日期/时间设置
|
||||
Name[zh_TW]=儲存日期與時間設定
|
||||
Description=System policies prevent you from saving the date/time settings.
|
||||
Description[az]=Təhlükəsizlik qaydaları sizə tarix və vaxtı idarə etməyə mane olur.
|
||||
Description[ca]=Les polítiques del sistema impedeixen que deseu la configuració de la data i hora.
|
||||
Description[ca@valencia]=Les polítiques del sistema impedixen que guardeu la configuració de la data i hora.
|
||||
Description[cs]=Nastavení systému vám znemožňuje uložit datum/čas.
|
||||
Description[da]=Systempolitikker forhindrer dig i at gemme dato-/klokkeslætsindstillinger.
|
||||
Description[de]=Die Einstellungen für Datum und Zeit können aufgrund einer Systemrichtlinie nicht gespeichert werden.
|
||||
Description[el]=Οι πολιτικές του συστήματος σάς εμποδίζουν να αποθηκεύσετε τις ρυθμίσεις ημερομηνίας/ώρας.
|
||||
Description[en_GB]=System policies prevent you from saving the date/time settings.
|
||||
Description[es]=La política del sistema le impide que pueda guardar las preferencias de fecha y hora.
|
||||
Description[et]=Süsteemi reeglid takistavad sul kuupäeva/kellaaja seadistusi salvestamast.
|
||||
Description[eu]=Sistemako gidalerroek data/ordu ezarpenak gordetzea eragozten dizute.
|
||||
Description[fi]=Järjestelmäkäytäntö estää sinua tallentamasta aika-asetuksia.
|
||||
Description[fr]=Les stratégies système vous empêchent d'enregistrer les paramètres de date / d'heure.
|
||||
Description[gl]=As políticas do sistema non permiten que garde a configuración da data e hora.
|
||||
Description[hu]=A rendszer házirendjei nem engedik Önnek a dátum- és időbeállítások mentését.
|
||||
Description[ia]=Le politicas de systema preveni te ex salveguardar le preferentias de tempore/data.
|
||||
Description[id]=Kebijakan sistem menghalangi anda untuk menyimpan pengaturan waktu/tanggal.
|
||||
Description[is]=Öryggisreglur kerfisins koma í veg fyrir að þú getir vistað stillingar fyrir tíma/dagsetningu.
|
||||
Description[it]=Le politiche di sistema ti impediscono di salvare le impostazioni di data e ora.
|
||||
Description[ka]=სისტემის წესები გიკრძალავთ დროის/თარიღის პარამეტრების შენახვას.
|
||||
Description[ko]=시스템 정책 때문에 날짜와 시간 설정을 저장할 수 없습니다.
|
||||
Description[lt]=Sistemos politika neleidžia jums įrašyti datos/laiko nustatymų.
|
||||
Description[nl]=Systeembeleid voorkwam dat u de datum- en tijdinstellingen kon opslaan.
|
||||
Description[nn]=Systemreglane hindrar deg i å lagra innstillingane for dato og klokkeslett.
|
||||
Description[pa]=ਸਿਸਟਮ ਪਾਲਸੀ ਤੁਹਾਨੂੰ ਮਿਤੀ/ਸਮਾਂ ਸੈਟਿੰਗ ਬਦਲਣ ਤੋਂ ਤੁਹਾਨੂੰ ਰੋਕਦੀ ਹੈ।
|
||||
Description[pl]=Polityka systemu nie pozwala ci na zapisanie ustawień daty/czasu.
|
||||
Description[pt]=As políticas do sistema proíbem a modificação da configuração de data/hora.
|
||||
Description[pt_BR]=As políticas do sistema não permitem a modificação das configurações de data e hora.
|
||||
Description[ro]=Politicile sistemului vă interzic salvarea configurărilor de dată și oră.
|
||||
Description[ru]=Правила безопасности запрещают вам управлять системной датой и временем.
|
||||
Description[sk]=Systémové politiky vám zabránili uložiť nastavenie dátumu a času.
|
||||
Description[sl]=Sistemski pravilniki vam onemogočajo, da bi shranili nastavitve datuma in časa.
|
||||
Description[sv]=Systemets policy förhindrar att du sparar inställningar av datum och tid.
|
||||
Description[ta]=தேதி மற்றும் நேர அமைப்புகளை நீங்கள் சேமிப்பதை கணினியின் கொள்கைகள் தடுக்கின்றன.
|
||||
Description[tr]=Sistem politikaları, tarih/saat ayarlarını kaydetmenizi engeller.
|
||||
Description[uk]=Відповідно до загальносистемних правил, ви не можете зберігати параметри дати/часу.
|
||||
Description[vi]=Các chính sách của hệ thống không cho phép bạn lưu thiết lập ngày/giờ.
|
||||
Description[x-test]=xxSystem policies prevent you from saving the date/time settings.xx
|
||||
Description[zh_CN]=系统安全策略不允许您保存日期/时间设置。
|
||||
Description[zh_TW]=系統政策拒絕讓您儲存日期與時間設定。
|
||||
Policy=yes
|
||||
9
kcms/time/config.h.cmake
Normal file
9
kcms/time/config.h.cmake
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2011 Marco Martin <mart@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
/* KDE's configuration directory */
|
||||
#define KDE_CONFDIR "${CONFIG_INSTALL_DIR}"
|
||||
|
||||
160
kcms/time/package/contents/ui/DatePicker.qml
Normal file
160
kcms/time/package/contents/ui/DatePicker.qml
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2011 Marco Martin <mart@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
import QtQuick 2.1
|
||||
import org.kde.kirigami 2.5 as Kirigami
|
||||
//import "private"
|
||||
|
||||
//FIXME: shouldn't be a FrameSvgItem
|
||||
Item {
|
||||
id: root
|
||||
clip: true
|
||||
|
||||
//////// API
|
||||
property int day
|
||||
property int month
|
||||
property int year
|
||||
|
||||
property bool userConfiguring: false
|
||||
|
||||
property string isoDate: year + "-" + clockRow.twoDigitString(month) + "-" + clockRow.twoDigitString(day)
|
||||
|
||||
property int fontSize: 14
|
||||
property int _margin: Kirigami.Units.gridUnit
|
||||
|
||||
opacity: enabled ? 1.0 : 0.5
|
||||
|
||||
Rectangle {
|
||||
color: "transparent"
|
||||
border.width: 1
|
||||
border.color: Kirigami.Theme.textColor
|
||||
anchors.fill: parent
|
||||
opacity: 0.3
|
||||
}
|
||||
|
||||
/////// Implementation
|
||||
Connections {
|
||||
target: root
|
||||
onDayChanged: clockRow.day = root.day
|
||||
onMonthChanged: clockRow.month = root.month
|
||||
onYearChanged: clockRow.year = root.year
|
||||
}
|
||||
|
||||
|
||||
//imagePath: "widgets/picker"
|
||||
width: clockRow.width + root._margin * 2
|
||||
height: clockRow.height + root._margin * 2
|
||||
|
||||
|
||||
Timer {
|
||||
id: userConfiguringTimer
|
||||
repeat: false
|
||||
interval: 1500
|
||||
running: false
|
||||
onTriggered: {
|
||||
root.day = clockRow.day
|
||||
root.month = clockRow.month
|
||||
root.year = clockRow.year
|
||||
userConfiguring = false
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
id: clockRow
|
||||
spacing: 3
|
||||
x: root._margin
|
||||
y: root._margin
|
||||
|
||||
property int day
|
||||
property int month
|
||||
property int year
|
||||
|
||||
function twoDigitString(number)
|
||||
{
|
||||
return number < 10 ? "0"+number : number
|
||||
}
|
||||
|
||||
Digit {
|
||||
id: dayDigit
|
||||
model: {
|
||||
var dd = new Date(year, month, 0);
|
||||
return dd.getDate()
|
||||
}
|
||||
currentIndex: ((day - 1) < model) ? day-1 : 1
|
||||
onSelectedIndexChanged: {
|
||||
if (selectedIndex > -1) {
|
||||
day = selectedIndex+1
|
||||
}
|
||||
}
|
||||
delegate: Text {
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
width: dayDigit.width
|
||||
property int ownIndex: index
|
||||
text: index+1
|
||||
color: Kirigami.Theme.textColor
|
||||
font.pointSize: root.fontSize
|
||||
opacity: PathView.itemOpacity
|
||||
}
|
||||
}
|
||||
Kirigami.Separator {
|
||||
anchors {
|
||||
top: parent.top
|
||||
bottom: parent.bottom
|
||||
}
|
||||
}
|
||||
Digit {
|
||||
id: monthDigit
|
||||
model: 12
|
||||
currentIndex: month -1
|
||||
onSelectedIndexChanged: {
|
||||
if (selectedIndex > -1) {
|
||||
month = selectedIndex + 1
|
||||
}
|
||||
}
|
||||
delegate: Text {
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
width: monthDigit.width
|
||||
property int ownIndex: index
|
||||
property variant months: Array(i18n("Jan"), i18n("Feb"), i18n("Mar"), i18n("Apr"), i18n("May"), i18n("Jun"), i18n("Jul"), i18n("Aug"), i18n("Sep"), i18n("Oct"), i18n("Nov"), i18n("Dec"))
|
||||
text: months[index]
|
||||
font.pointSize: root.fontSize
|
||||
color: Kirigami.Theme.textColor
|
||||
opacity: PathView.itemOpacity
|
||||
}
|
||||
width: monthPlaceHolder.width
|
||||
Text {
|
||||
id: monthPlaceHolder
|
||||
visible: false
|
||||
font.pointSize: root.fontSize
|
||||
text: "0000"
|
||||
}
|
||||
}
|
||||
Kirigami.Separator {
|
||||
anchors {
|
||||
top: parent.top
|
||||
bottom: parent.bottom
|
||||
}
|
||||
}
|
||||
Digit {
|
||||
id: yearDigit
|
||||
//FIXME: yes, this is a tad lame ;)
|
||||
model: 3000
|
||||
currentIndex: year
|
||||
onSelectedIndexChanged: {
|
||||
if (selectedIndex > -1) {
|
||||
year = selectedIndex
|
||||
}
|
||||
}
|
||||
width: yearPlaceHolder.width*1.3
|
||||
Text {
|
||||
id: yearPlaceHolder
|
||||
visible: false
|
||||
font.pointSize: root.fontSize
|
||||
text: "0000"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
75
kcms/time/package/contents/ui/Digit.qml
Normal file
75
kcms/time/package/contents/ui/Digit.qml
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2011 Marco Martin <mart@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
import QtQuick 2.7
|
||||
import org.kde.kirigami 2.4 as Kirigami
|
||||
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property alias model: spinnerView.model
|
||||
property alias currentIndex: spinnerView.currentIndex
|
||||
property alias delegate: spinnerView.delegate
|
||||
property alias moving: spinnerView.moving
|
||||
property int selectedIndex: -1
|
||||
property int fontSize: 14
|
||||
|
||||
width: placeHolder.width*1.3
|
||||
height: placeHolder.height*3
|
||||
|
||||
Text {
|
||||
id: placeHolder
|
||||
visible: false
|
||||
font.pointSize: root.fontSize
|
||||
text: "00"
|
||||
}
|
||||
|
||||
PathView {
|
||||
id: spinnerView
|
||||
anchors.fill: parent
|
||||
model: 60
|
||||
clip: true
|
||||
pathItemCount: 5
|
||||
dragMargin: 800
|
||||
preferredHighlightBegin: 0.5
|
||||
preferredHighlightEnd: 0.5
|
||||
delegate: Text {
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
width: spinnerView.width
|
||||
property int ownIndex: index
|
||||
text: index < 10 ? "0"+index : index
|
||||
color: Kirigami.Theme.textColor
|
||||
font.pointSize: root.fontSize
|
||||
opacity: PathView.itemOpacity
|
||||
}
|
||||
|
||||
onMovingChanged: {
|
||||
userConfiguring = true
|
||||
if (!moving) {
|
||||
userConfiguringTimer.restart()
|
||||
selectedIndex = childAt(width/2, height/2).ownIndex
|
||||
}
|
||||
}
|
||||
|
||||
path: Path {
|
||||
startX: spinnerView.width/2
|
||||
startY: spinnerView.height + 1.5*placeHolder.height
|
||||
PathAttribute { name: "itemOpacity"; value: 0 }
|
||||
PathLine {
|
||||
x: spinnerView.width/2
|
||||
y: spinnerView.height/2
|
||||
}
|
||||
PathAttribute { name: "itemOpacity"; value: 1 }
|
||||
PathLine {
|
||||
x: spinnerView.width/2
|
||||
y: -1.5*placeHolder.height
|
||||
}
|
||||
PathAttribute { name: "itemOpacity"; value: 0 }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
216
kcms/time/package/contents/ui/TimePicker.qml
Normal file
216
kcms/time/package/contents/ui/TimePicker.qml
Normal file
|
|
@ -0,0 +1,216 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2011 Marco Martin <mart@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
import QtQuick 2.1
|
||||
|
||||
import org.kde.kirigami 2.4 as Kirigami
|
||||
|
||||
|
||||
//FIXME: shouldn't be a FrameSvgItem
|
||||
Item {
|
||||
id: root
|
||||
clip: true
|
||||
|
||||
//////// API
|
||||
property alias hours: clockRow.hours
|
||||
property alias minutes: clockRow.minutes
|
||||
property alias seconds: clockRow.seconds
|
||||
|
||||
property bool userConfiguring: false
|
||||
property bool twentyFour: true
|
||||
|
||||
property int fontSize: 14
|
||||
property int _margin: Kirigami.Units.gridUnit
|
||||
|
||||
property string timeString: clockRow.twoDigitString(hours) + ":" + clockRow.twoDigitString(minutes) + ":" + clockRow.twoDigitString(seconds)
|
||||
|
||||
opacity: enabled ? 1.0 : 0.5
|
||||
|
||||
Connections {
|
||||
target: root
|
||||
// onHoursChanged: print("H : " + root.hours)
|
||||
// onMinutesChanged: print("M : " + root.minutes)
|
||||
// onSecondsChanged: print("S : " + root.seconds)
|
||||
}
|
||||
|
||||
Behavior on width {
|
||||
SequentialAnimation {
|
||||
PauseAnimation {
|
||||
duration: 250
|
||||
}
|
||||
NumberAnimation {
|
||||
//duration: PlasmaCore.Units.longDuration
|
||||
duration: 250
|
||||
easing.type: Easing.InOutQuad
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// KLocale.Locale {
|
||||
// id: locale
|
||||
// }
|
||||
|
||||
//imagePath: "widgets/picker"
|
||||
width: clockRow.width + root._margin
|
||||
height: clockRow.height + root._margin * 2
|
||||
|
||||
Timer {
|
||||
id: userConfiguringTimer
|
||||
repeat: false
|
||||
interval: 1500
|
||||
running: false
|
||||
onTriggered: {
|
||||
root.hours = clockRow.hours
|
||||
root.minutes = clockRow.minutes
|
||||
root.seconds = clockRow.seconds
|
||||
userConfiguring = false
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
color: "transparent"
|
||||
opacity: 0.3
|
||||
border.color: Kirigami.Theme.textColor
|
||||
border.width: 1
|
||||
anchors.fill: parent
|
||||
}
|
||||
|
||||
Row {
|
||||
id: clockRow
|
||||
spacing: Kirigami.Units.gridUnit
|
||||
x: root._margin
|
||||
y: root._margin
|
||||
|
||||
property int hours
|
||||
property int minutes
|
||||
property int seconds
|
||||
|
||||
function twoDigitString(number)
|
||||
{
|
||||
return number < 10 ? "0"+number : number
|
||||
}
|
||||
|
||||
Digit {
|
||||
id: hoursDigit
|
||||
model: root.twentyFour ? 24 : 12
|
||||
currentIndex: root.twentyFour || hours < 12 ? hours : hours - 12
|
||||
delegate: Text {
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
width: hoursDigit.width
|
||||
property int ownIndex: index
|
||||
text: (!root.twentyFour && index == 0) ? "12" : clockRow.twoDigitString(index)
|
||||
font.pointSize: root.fontSize
|
||||
color: Kirigami.Theme.textColor
|
||||
opacity: PathView.itemOpacity
|
||||
}
|
||||
onSelectedIndexChanged: {
|
||||
print("Bah");
|
||||
if (selectedIndex > -1) {
|
||||
if (root.twentyFour ||
|
||||
meridiaeDigit.isAm) {
|
||||
hours = selectedIndex
|
||||
} else {
|
||||
hours = selectedIndex + 12
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Kirigami.Separator {
|
||||
anchors {
|
||||
top: parent.top
|
||||
bottom: parent.bottom
|
||||
}
|
||||
}
|
||||
Digit {
|
||||
id: minutesDigit
|
||||
model: 60
|
||||
currentIndex: minutes
|
||||
onSelectedIndexChanged: {
|
||||
if (selectedIndex > -1) {
|
||||
minutes = selectedIndex
|
||||
}
|
||||
}
|
||||
}
|
||||
Kirigami.Separator {
|
||||
anchors {
|
||||
top: parent.top
|
||||
bottom: parent.bottom
|
||||
}
|
||||
}
|
||||
Digit {
|
||||
id: secondsDigit
|
||||
model: 60
|
||||
currentIndex: seconds
|
||||
onSelectedIndexChanged: {
|
||||
if (selectedIndex > -1) {
|
||||
seconds = selectedIndex
|
||||
}
|
||||
}
|
||||
}
|
||||
Kirigami.Separator {
|
||||
opacity: meridiaeDigit.opacity == 0 ? 0 : 1
|
||||
|
||||
anchors {
|
||||
top: parent.top
|
||||
bottom: parent.bottom
|
||||
}
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: 250
|
||||
easing.type: Easing.InOutQuad
|
||||
}
|
||||
}
|
||||
}
|
||||
Digit {
|
||||
id: meridiaeDigit
|
||||
visible: opacity != 0
|
||||
opacity: root.twentyFour ? 0 : 1
|
||||
property bool isAm: (selectedIndex > -1) ? (selectedIndex < 1) : (currentIndex < 1)
|
||||
model: ListModel {
|
||||
ListElement {
|
||||
meridiae: "AM"
|
||||
}
|
||||
ListElement {
|
||||
meridiae: "PM"
|
||||
}
|
||||
}
|
||||
delegate: Text {
|
||||
width: meridiaeDigit.width
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
property int ownIndex: index
|
||||
text: meridiae
|
||||
color: Kirigami.Theme.textColor
|
||||
font.pointSize: root.fontSize
|
||||
//opacity: PathView.itemOpacity
|
||||
}
|
||||
currentIndex: hours > 12 ? 1 : 0
|
||||
onSelectedIndexChanged: {
|
||||
if (selectedIndex > -1) {
|
||||
//AM
|
||||
if (selectedIndex == 0) {
|
||||
hours -= 12
|
||||
//PM
|
||||
} else {
|
||||
hours += 12
|
||||
}
|
||||
}
|
||||
}
|
||||
width: meridiaePlaceHolder.width + root._margin
|
||||
Text {
|
||||
id: meridiaePlaceHolder
|
||||
visible: false
|
||||
font.pointSize: root.fontSize
|
||||
text: "00"
|
||||
}
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: 250
|
||||
easing.type: Easing.InOutQuad
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
257
kcms/time/package/contents/ui/main.qml
Normal file
257
kcms/time/package/contents/ui/main.qml
Normal file
|
|
@ -0,0 +1,257 @@
|
|||
// -*- coding: iso-8859-1 -*-
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2011 Sebastian Kügler <sebas@kde.org>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
import QtQuick 2.7
|
||||
import QtQuick.Layouts 1.3
|
||||
import QtQuick.Controls 2.3 as Controls
|
||||
|
||||
import org.kde.kirigami 2.10 as Kirigami
|
||||
import org.kde.kcm 1.2
|
||||
import org.kde.timesettings 1.0
|
||||
import org.kde.kirigamiaddons.labs.mobileform 0.1 as MobileForm
|
||||
|
||||
SimpleKCM {
|
||||
id: timeModule
|
||||
|
||||
leftPadding: 0
|
||||
rightPadding: 0
|
||||
topPadding: Kirigami.Units.gridUnit
|
||||
bottomPadding: Kirigami.Units.gridUnit
|
||||
|
||||
Component {
|
||||
id: listDelegateComponent
|
||||
|
||||
Kirigami.BasicListItem {
|
||||
text: {
|
||||
if (model) {
|
||||
if (model.region) {
|
||||
return "%1 / %2".arg(model.region).arg(model.city)
|
||||
} else {
|
||||
return model.city
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
onClicked: {
|
||||
timeZonePickerSheet.close()
|
||||
kcm.saveTimeZone(model.timeZoneId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 0
|
||||
width: parent.width
|
||||
|
||||
MobileForm.FormCard {
|
||||
Layout.fillWidth: true
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
spacing: 0
|
||||
|
||||
MobileForm.FormCardHeader {
|
||||
title: i18n("Display")
|
||||
}
|
||||
|
||||
MobileForm.FormSwitchDelegate {
|
||||
id: hourFormatSwitch
|
||||
text: i18n("24-Hour Format")
|
||||
description: i18n("Whether to use a 24-hour format for clocks.")
|
||||
checked: kcm.twentyFour
|
||||
onCheckedChanged: {
|
||||
kcm.twentyFour = checked
|
||||
}
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator { above: hourFormatSwitch; below: timeZoneSelect }
|
||||
|
||||
MobileForm.FormButtonDelegate {
|
||||
id: timeZoneSelect
|
||||
text: i18n("Timezone")
|
||||
description: kcm.timeZone
|
||||
onClicked: timeZonePickerSheet.open()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MobileForm.FormCard {
|
||||
Layout.topMargin: Kirigami.Units.largeSpacing
|
||||
Layout.fillWidth: true
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
spacing: 0
|
||||
|
||||
MobileForm.FormCardHeader {
|
||||
title: i18n("Time and Date")
|
||||
}
|
||||
|
||||
MobileForm.FormSwitchDelegate {
|
||||
id: ntpCheckBox
|
||||
text: i18n("Automatic Time Synchronization")
|
||||
description: i18n("Whether to set the time automatically.")
|
||||
checked: kcm.useNtp
|
||||
onCheckedChanged: {
|
||||
kcm.useNtp = checked
|
||||
if (!checked) {
|
||||
kcm.ntpServer = ""
|
||||
kcm.saveTime()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator { above: ntpCheckBox; below: timeSelect }
|
||||
|
||||
MobileForm.FormButtonDelegate {
|
||||
id: timeSelect
|
||||
enabled: !ntpCheckBox.checked
|
||||
icon.name: "clock"
|
||||
text: i18n("Current Time")
|
||||
description: Qt.formatTime(kcm.currentTime, Locale.LongFormat)
|
||||
onClicked: timePickerSheet.open()
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator { above: timeSelect; below: dateSelect }
|
||||
|
||||
MobileForm.FormButtonDelegate {
|
||||
id: dateSelect
|
||||
enabled: !ntpCheckBox.checked
|
||||
icon.name: "view-calendar"
|
||||
text: i18n("Date")
|
||||
description: Qt.formatDate(kcm.currentDate, Locale.LongFormat)
|
||||
onClicked: datePickerSheet.open()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Kirigami.OverlaySheet {
|
||||
id: timeZonePickerSheet
|
||||
header: ColumnLayout {
|
||||
Kirigami.Heading {
|
||||
text: i18nc("@title:window", "Pick Timezone")
|
||||
}
|
||||
Kirigami.SearchField {
|
||||
Layout.fillWidth: true
|
||||
width: parent.width
|
||||
onTextChanged: {
|
||||
kcm.timeZonesModel.filterString = text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
footer: RowLayout {
|
||||
Controls.Button {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
|
||||
text: i18nc("@action:button", "Close")
|
||||
|
||||
onClicked: timeZonePickerSheet.close()
|
||||
}
|
||||
}
|
||||
ListView {
|
||||
clip: true
|
||||
anchors.fill: parent
|
||||
implicitWidth: 18 * Kirigami.Units.gridUnit
|
||||
model: kcm.timeZonesModel
|
||||
delegate: Kirigami.DelegateRecycler {
|
||||
width: parent.width
|
||||
|
||||
sourceComponent: listDelegateComponent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Kirigami.OverlaySheet {
|
||||
id: timePickerSheet
|
||||
header: Kirigami.Heading { text: i18n("Pick Time") }
|
||||
TimePicker {
|
||||
id: timePicker
|
||||
enabled: !ntpCheckBox.checked
|
||||
twentyFour: twentyFourSwitch.checked
|
||||
|
||||
implicitWidth: width > Kirigami.Units.gridUnit * 15 ? width : Kirigami.Units.gridUnit * 15
|
||||
|
||||
Component.onCompleted: {
|
||||
var date = new Date(kcm.currentTime);
|
||||
timePicker.hours = date.getHours();
|
||||
timePicker.minutes = date.getMinutes();
|
||||
timePicker.seconds = date.getSeconds();
|
||||
}
|
||||
Connections {
|
||||
target: kcm
|
||||
onCurrentTimeChanged: {
|
||||
if (timePicker.userConfiguring) {
|
||||
return;
|
||||
}
|
||||
|
||||
var date = new Date(kcm.currentTime);
|
||||
timePicker.hours = date.getHours();
|
||||
timePicker.minutes = date.getMinutes();
|
||||
timePicker.seconds = date.getSeconds();
|
||||
}
|
||||
}
|
||||
onUserConfiguringChanged: {
|
||||
kcm.currentTime = timeString
|
||||
kcm.saveTime()
|
||||
}
|
||||
}
|
||||
footer: RowLayout {
|
||||
Controls.Button {
|
||||
Layout.alignment: Qt.AlignRight
|
||||
|
||||
text: i18nc("@action:button", "Close")
|
||||
|
||||
onClicked: timePickerSheet.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Kirigami.OverlaySheet {
|
||||
id: datePickerSheet
|
||||
header: Kirigami.Heading { text: i18n("Pick Date") }
|
||||
DatePicker {
|
||||
id: datePicker
|
||||
enabled: !ntpCheckBox.checked
|
||||
|
||||
implicitWidth: width > Kirigami.Units.gridUnit * 15 ? width : Kirigami.Units.gridUnit * 15
|
||||
|
||||
Component.onCompleted: {
|
||||
var date = new Date(kcm.currentDate)
|
||||
datePicker.day = date.getDate()
|
||||
datePicker.month = date.getMonth()+1
|
||||
datePicker.year = date.getFullYear()
|
||||
}
|
||||
Connections {
|
||||
target: kcm
|
||||
onCurrentDateChanged: {
|
||||
if (datePicker.userConfiguring) {
|
||||
return
|
||||
}
|
||||
|
||||
var date = new Date(kcm.currentDate)
|
||||
|
||||
datePicker.day = date.getDate()
|
||||
datePicker.month = date.getMonth()+1
|
||||
datePicker.year = date.getFullYear()
|
||||
}
|
||||
}
|
||||
onUserConfiguringChanged: {
|
||||
kcm.currentDate = isoDate
|
||||
kcm.saveTime()
|
||||
}
|
||||
}
|
||||
footer: RowLayout {
|
||||
Controls.Button {
|
||||
Layout.alignment: Qt.AlignRight
|
||||
|
||||
text: i18nc("@action:button", "Close")
|
||||
|
||||
onClicked: datePickerSheet.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
43
kcms/time/timedated1.xml
Normal file
43
kcms/time/timedated1.xml
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
<node>
|
||||
<interface name="org.freedesktop.timedate1">
|
||||
<property name="Timezone" type="s" access="read">
|
||||
</property>
|
||||
<property name="LocalRTC" type="b" access="read">
|
||||
</property>
|
||||
<property name="CanNTP" type="b" access="read">
|
||||
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
|
||||
</property>
|
||||
<property name="NTP" type="b" access="read">
|
||||
</property>
|
||||
<property name="NTPSynchronized" type="b" access="read">
|
||||
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
|
||||
</property>
|
||||
<property name="TimeUSec" type="t" access="read">
|
||||
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
|
||||
</property>
|
||||
<property name="RTCTimeUSec" type="t" access="read">
|
||||
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
|
||||
</property>
|
||||
<method name="SetTime">
|
||||
<arg type="x" direction="in"/>
|
||||
<arg type="b" direction="in"/>
|
||||
<arg type="b" direction="in"/>
|
||||
</method>
|
||||
<method name="SetTimezone">
|
||||
<arg type="s" direction="in"/>
|
||||
<arg type="b" direction="in"/>
|
||||
</method>
|
||||
<method name="SetLocalRTC">
|
||||
<arg type="b" direction="in"/>
|
||||
<arg type="b" direction="in"/>
|
||||
<arg type="b" direction="in"/>
|
||||
</method>
|
||||
<method name="SetNTP">
|
||||
<arg type="b" direction="in"/>
|
||||
<arg type="b" direction="in"/>
|
||||
</method>
|
||||
</interface>
|
||||
</node>
|
||||
|
||||
278
kcms/time/timesettings.cpp
Normal file
278
kcms/time/timesettings.cpp
Normal file
|
|
@ -0,0 +1,278 @@
|
|||
/*
|
||||
|
||||
SPDX-FileCopyrightText: 2005 S.R.Haque <srhaque@iee.org>.
|
||||
SPDX-FileCopyrightText: 2009 David Faure <faure@kde.org>
|
||||
SPDX-FileCopyrightText: 2011-2015 Sebastian Kügler <sebas@kde.org>
|
||||
SPDX-FileCopyrightText: 2015 David Edmundson <davidedmundson@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "timesettings.h"
|
||||
#include "timezonemodel.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QtCore/QDate>
|
||||
|
||||
#include <QDBusConnection>
|
||||
#include <QDBusMessage>
|
||||
#include <QStandardItemModel>
|
||||
#include <QTimer>
|
||||
#include <QVariant>
|
||||
|
||||
#include <KConfigGroup>
|
||||
#include <KLocalizedString>
|
||||
#include <KPluginFactory>
|
||||
#include <KSharedConfig>
|
||||
#include <utility>
|
||||
|
||||
#include "timedated_interface.h"
|
||||
|
||||
#define FORMAT24H "HH:mm:ss"
|
||||
#define FORMAT12H "h:mm:ss ap"
|
||||
|
||||
K_PLUGIN_FACTORY_WITH_JSON(TimeSettingsFactory, "timesettings.json", registerPlugin<TimeSettings>();)
|
||||
|
||||
TimeSettings::TimeSettings(QObject *parent, const KPluginMetaData &metaData, const QVariantList &args)
|
||||
: KQuickAddons::ConfigModule(parent, metaData, args)
|
||||
, m_useNtp(true)
|
||||
{
|
||||
qDebug() << "time settings init";
|
||||
m_timeZonesModel = nullptr;
|
||||
setTimeZone(QTimeZone::systemTimeZone().id());
|
||||
|
||||
setButtons(Apply | Default);
|
||||
|
||||
qmlRegisterAnonymousType<TimeZoneModel>("org.kde.timesettings", 1);
|
||||
qmlRegisterAnonymousType<TimeZoneFilterProxy>("org.kde.timesettings", 1);
|
||||
|
||||
initSettings();
|
||||
initTimeZones();
|
||||
qDebug() << "TimeSettings module loaded.";
|
||||
}
|
||||
|
||||
TimeSettings::~TimeSettings()
|
||||
{
|
||||
}
|
||||
|
||||
void TimeSettings::initTimeZones()
|
||||
{
|
||||
auto *filterModel = new TimeZoneFilterProxy(this);
|
||||
filterModel->setSourceModel(new TimeZoneModel(filterModel));
|
||||
setTimeZonesModel(filterModel);
|
||||
}
|
||||
|
||||
void TimeSettings::initSettings()
|
||||
{
|
||||
m_localeConfig = KSharedConfig::openConfig(QStringLiteral("kdeglobals"), KConfig::SimpleConfig);
|
||||
m_localeSettings = KConfigGroup(m_localeConfig, "Locale");
|
||||
|
||||
setTimeFormat(m_localeSettings.readEntry("TimeFormat", QStringLiteral(FORMAT24H))); // FIXME?!
|
||||
|
||||
OrgFreedesktopTimedate1Interface timeDatedIface(QStringLiteral("org.freedesktop.timedate1"),
|
||||
QStringLiteral("/org/freedesktop/timedate1"),
|
||||
QDBusConnection::systemBus());
|
||||
// the server list is not relevant for timesyncd, it fetches it from the network
|
||||
m_useNtp = timeDatedIface.nTP();
|
||||
}
|
||||
|
||||
void TimeSettings::timeout()
|
||||
{
|
||||
setCurrentTime(QTime::currentTime());
|
||||
setCurrentDate(QDate::currentDate());
|
||||
notify();
|
||||
}
|
||||
|
||||
QString TimeSettings::currentTimeText()
|
||||
{
|
||||
return m_currentTimeText;
|
||||
}
|
||||
|
||||
QTime TimeSettings::currentTime() const
|
||||
{
|
||||
return m_currentTime;
|
||||
}
|
||||
|
||||
void TimeSettings::setCurrentTime(const QTime ¤tTime)
|
||||
{
|
||||
if (m_currentTime != currentTime) {
|
||||
m_currentTime = currentTime;
|
||||
m_currentTimeText = QLocale().toString(QTime::currentTime(), m_timeFormat);
|
||||
emit currentTimeChanged();
|
||||
}
|
||||
}
|
||||
|
||||
QDate TimeSettings::currentDate() const
|
||||
{
|
||||
return m_currentDate;
|
||||
}
|
||||
|
||||
void TimeSettings::setCurrentDate(const QDate ¤tDate)
|
||||
{
|
||||
if (m_currentDate != currentDate) {
|
||||
m_currentDate = currentDate;
|
||||
emit currentDateChanged();
|
||||
}
|
||||
}
|
||||
|
||||
bool TimeSettings::useNtp() const
|
||||
{
|
||||
return m_useNtp;
|
||||
}
|
||||
|
||||
void TimeSettings::setUseNtp(bool ntp)
|
||||
{
|
||||
if (m_useNtp != ntp) {
|
||||
m_useNtp = ntp;
|
||||
saveTime();
|
||||
emit useNtpChanged();
|
||||
}
|
||||
}
|
||||
|
||||
bool TimeSettings::saveTime()
|
||||
{
|
||||
OrgFreedesktopTimedate1Interface timedateIface(QStringLiteral("org.freedesktop.timedate1"),
|
||||
QStringLiteral("/org/freedesktop/timedate1"),
|
||||
QDBusConnection::systemBus());
|
||||
|
||||
bool rc = true;
|
||||
// final arg in each method is "user-interaction" i.e whether it's OK for polkit to ask for auth
|
||||
|
||||
// we cannot send requests up front then block for all replies as we need NTP to be disabled before we can make a call to SetTime
|
||||
// timedated processes these in parallel and will return an error otherwise
|
||||
|
||||
auto reply = timedateIface.SetNTP(m_useNtp, true);
|
||||
reply.waitForFinished();
|
||||
if (reply.isError()) {
|
||||
m_errorString = i18n("Unable to change NTP settings");
|
||||
emit errorStringChanged();
|
||||
qWarning() << "Failed to enable NTP" << reply.error().name() << reply.error().message();
|
||||
rc = false;
|
||||
}
|
||||
|
||||
if (!useNtp()) {
|
||||
QDateTime userTime;
|
||||
userTime.setTime(currentTime());
|
||||
userTime.setDate(currentDate());
|
||||
qDebug() << "Setting userTime: " << userTime;
|
||||
qint64 timeDiff = userTime.toMSecsSinceEpoch() - QDateTime::currentMSecsSinceEpoch();
|
||||
//*1000 for milliseconds -> microseconds
|
||||
auto reply = timedateIface.SetTime(timeDiff * 1000, true, true);
|
||||
reply.waitForFinished();
|
||||
if (reply.isError()) {
|
||||
m_errorString = i18n("Unable to set current time");
|
||||
emit errorStringChanged();
|
||||
qWarning() << "Failed to set current time" << reply.error().name() << reply.error().message();
|
||||
rc = false;
|
||||
}
|
||||
}
|
||||
saveTimeZone(m_timezone);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void TimeSettings::saveTimeZone(const QString &newtimezone)
|
||||
{
|
||||
qDebug() << "Saving timezone to config: " << newtimezone;
|
||||
OrgFreedesktopTimedate1Interface timedateIface(QStringLiteral("org.freedesktop.timedate1"),
|
||||
QStringLiteral("/org/freedesktop/timedate1"),
|
||||
QDBusConnection::systemBus());
|
||||
|
||||
if (!newtimezone.isEmpty()) {
|
||||
qDebug() << "Setting timezone: " << newtimezone;
|
||||
auto reply = timedateIface.SetTimezone(newtimezone, true);
|
||||
reply.waitForFinished();
|
||||
if (reply.isError()) {
|
||||
m_errorString = i18n("Unable to set timezone");
|
||||
emit errorStringChanged();
|
||||
qWarning() << "Failed to set timezone" << reply.error().name() << reply.error().message();
|
||||
}
|
||||
}
|
||||
|
||||
setTimeZone(newtimezone);
|
||||
emit timeZoneChanged();
|
||||
notify();
|
||||
}
|
||||
|
||||
QString TimeSettings::timeFormat()
|
||||
{
|
||||
return m_timeFormat;
|
||||
}
|
||||
|
||||
void TimeSettings::setTimeFormat(const QString &timeFormat)
|
||||
{
|
||||
if (m_timeFormat != timeFormat) {
|
||||
m_timeFormat = timeFormat;
|
||||
|
||||
m_localeSettings.writeEntry("TimeFormat", timeFormat, KConfigGroup::Notify);
|
||||
m_localeConfig->sync();
|
||||
|
||||
QDBusMessage msg =
|
||||
QDBusMessage::createSignal(QStringLiteral("/org/kde/kcmshell_clock"), QStringLiteral("org.kde.kcmshell_clock"), QStringLiteral("clockUpdated"));
|
||||
QDBusConnection::sessionBus().send(msg);
|
||||
|
||||
qDebug() << "time format is now: " << QLocale().toString(QTime::currentTime(), m_timeFormat);
|
||||
emit timeFormatChanged();
|
||||
timeout();
|
||||
}
|
||||
}
|
||||
|
||||
QString TimeSettings::timeZone()
|
||||
{
|
||||
return m_timezone;
|
||||
}
|
||||
|
||||
void TimeSettings::setTimeZone(const QString &timezone)
|
||||
{
|
||||
if (m_timezone != timezone) {
|
||||
m_timezone = timezone;
|
||||
qDebug() << "timezone changed to: " << timezone;
|
||||
emit timeZoneChanged();
|
||||
timeout();
|
||||
}
|
||||
}
|
||||
|
||||
TimeZoneFilterProxy *TimeSettings::timeZonesModel()
|
||||
{
|
||||
return m_timeZonesModel;
|
||||
}
|
||||
|
||||
void TimeSettings::setTimeZonesModel(TimeZoneFilterProxy *timezones)
|
||||
{
|
||||
m_timeZonesModel = timezones;
|
||||
emit timeZonesModelChanged();
|
||||
}
|
||||
|
||||
bool TimeSettings::twentyFour()
|
||||
{
|
||||
return timeFormat() == QStringLiteral(FORMAT24H);
|
||||
}
|
||||
|
||||
void TimeSettings::setTwentyFour(bool t)
|
||||
{
|
||||
if (twentyFour() != t) {
|
||||
if (t) {
|
||||
setTimeFormat(FORMAT24H);
|
||||
} else {
|
||||
setTimeFormat(FORMAT12H);
|
||||
}
|
||||
qDebug() << "T24 toggled: " << t << m_timeFormat;
|
||||
emit twentyFourChanged();
|
||||
emit currentTimeChanged();
|
||||
timeout();
|
||||
}
|
||||
}
|
||||
|
||||
QString TimeSettings::errorString()
|
||||
{
|
||||
return m_errorString;
|
||||
}
|
||||
|
||||
void TimeSettings::notify()
|
||||
{
|
||||
const QDBusMessage msg =
|
||||
QDBusMessage::createSignal(QStringLiteral("/org/kde/kcmshell_clock"), QStringLiteral("org.kde.kcmshell_clock"), QStringLiteral("clockUpdated"));
|
||||
QDBusConnection::sessionBus().send(msg);
|
||||
}
|
||||
|
||||
#include "timesettings.moc"
|
||||
120
kcms/time/timesettings.h
Normal file
120
kcms/time/timesettings.h
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
|
||||
SPDX-FileCopyrightText: 2011-2015 Sebastian Kügler <sebas@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef TIMESETTINGS_H
|
||||
#define TIMESETTINGS_H
|
||||
|
||||
#include <QDate>
|
||||
#include <QIcon>
|
||||
#include <QObject>
|
||||
#include <QStringListModel>
|
||||
#include <QTime>
|
||||
#include <QVariant>
|
||||
|
||||
#include <KConfigGroup>
|
||||
#include <KSharedConfig>
|
||||
|
||||
#include <KQuickAddons/ConfigModule>
|
||||
|
||||
#include "timezonemodel.h"
|
||||
|
||||
// #include "settingsmodule.h"
|
||||
|
||||
class TimeSettingsPrivate;
|
||||
|
||||
/**
|
||||
* @class TimeSettings A class to manage time and date related settings. This class serves two functions:
|
||||
* - Provide a plugin implementation
|
||||
* - Provide a settings module
|
||||
* This is done from one class in order to simplify the code. You can export any QObject-based
|
||||
* class through qmlRegisterType(), however.
|
||||
*/
|
||||
class TimeSettings : public KQuickAddons::ConfigModule
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QString timeFormat READ timeFormat WRITE setTimeFormat NOTIFY timeFormatChanged)
|
||||
Q_PROPERTY(bool twentyFour READ twentyFour WRITE setTwentyFour NOTIFY twentyFourChanged)
|
||||
Q_PROPERTY(QString timeZone READ timeZone WRITE setTimeZone NOTIFY timeZoneChanged)
|
||||
Q_PROPERTY(TimeZoneFilterProxy *timeZonesModel READ timeZonesModel WRITE setTimeZonesModel NOTIFY timeZonesModelChanged)
|
||||
Q_PROPERTY(QTime currentTime READ currentTime WRITE setCurrentTime NOTIFY currentTimeChanged)
|
||||
Q_PROPERTY(QDate currentDate READ currentDate WRITE setCurrentDate NOTIFY currentDateChanged)
|
||||
Q_PROPERTY(bool useNtp READ useNtp WRITE setUseNtp NOTIFY useNtpChanged)
|
||||
Q_PROPERTY(QString currentTimeText READ currentTimeText NOTIFY currentTimeTextChanged)
|
||||
Q_PROPERTY(QString errorString READ errorString NOTIFY errorStringChanged)
|
||||
|
||||
public:
|
||||
/**
|
||||
* @name Settings Module Constructor
|
||||
*
|
||||
* @arg parent The parent object
|
||||
* @arg list Arguments, currently unused
|
||||
*/
|
||||
TimeSettings(QObject *parent, const KPluginMetaData &metaData, const QVariantList &args);
|
||||
~TimeSettings() override;
|
||||
|
||||
QString currentTimeText();
|
||||
QTime currentTime() const;
|
||||
void setCurrentTime(const QTime &time);
|
||||
|
||||
QDate currentDate() const;
|
||||
void setCurrentDate(const QDate &date);
|
||||
|
||||
bool useNtp() const;
|
||||
void setUseNtp(bool ntp);
|
||||
|
||||
QString timeFormat();
|
||||
QString timeZone();
|
||||
TimeZoneFilterProxy *timeZonesModel();
|
||||
bool twentyFour();
|
||||
|
||||
QString errorString();
|
||||
|
||||
public Q_SLOTS:
|
||||
void setTimeZone(const QString &timezone);
|
||||
void setTimeZonesModel(TimeZoneFilterProxy *timezones);
|
||||
void setTimeFormat(const QString &timeFormat);
|
||||
void setTwentyFour(bool t);
|
||||
void timeout();
|
||||
bool saveTime();
|
||||
void notify();
|
||||
Q_INVOKABLE void saveTimeZone(const QString &newtimezone);
|
||||
|
||||
Q_SIGNALS:
|
||||
void currentTimeTextChanged();
|
||||
void currentTimeChanged();
|
||||
void currentDateChanged();
|
||||
void twentyFourChanged();
|
||||
void timeFormatChanged();
|
||||
void timeZoneChanged();
|
||||
void timeZonesChanged();
|
||||
void timeZonesModelChanged();
|
||||
void useNtpChanged();
|
||||
void errorStringChanged();
|
||||
|
||||
protected:
|
||||
QString findNtpUtility();
|
||||
|
||||
private:
|
||||
QString m_timeFormat;
|
||||
QString m_timezone;
|
||||
TimeZoneFilterProxy *m_timeZonesModel;
|
||||
QString m_timeZoneFilter;
|
||||
QString m_currentTimeText;
|
||||
QTime m_currentTime;
|
||||
QDate m_currentDate;
|
||||
bool m_useNtp;
|
||||
QString m_errorString;
|
||||
|
||||
void initSettings();
|
||||
void initTimeZones();
|
||||
|
||||
KSharedConfig::Ptr m_localeConfig;
|
||||
KConfigGroup m_localeSettings;
|
||||
};
|
||||
|
||||
#endif // TIMESETTINGS_H
|
||||
128
kcms/time/timesettings.json
Normal file
128
kcms/time/timesettings.json
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
{
|
||||
"Categories": "Qt;KDE;X-KDE-settings-system;",
|
||||
"KPlugin": {
|
||||
"Description": "Timezone, Date Display",
|
||||
"Description[az]": "Saat Qurşağı, Tarix göstərişi",
|
||||
"Description[ca@valencia]": "Zona horària, Mostra la data",
|
||||
"Description[ca]": "Zona horària, Mostra la data",
|
||||
"Description[cs]": "Zobrazení data a časového pásma",
|
||||
"Description[de]": "Zeitzone, Datumsanzeige",
|
||||
"Description[en_GB]": "Timezone, Date Display",
|
||||
"Description[es]": "Zona horaria, visor de la fecha",
|
||||
"Description[eu]": "Ordu-eremua, data azaltzea",
|
||||
"Description[fi]": "Aikavyöhyke, Päivämääränäyttö",
|
||||
"Description[fr]": "Fuseau horaire, affichage de la date",
|
||||
"Description[hu]": "Időzóna, dátummegjelenítés",
|
||||
"Description[ia]": "Fuso horari, Monstrator de Data",
|
||||
"Description[id]": "Zona Waktu, Tampilan Tanggal",
|
||||
"Description[is]": "Tímabelti, birting dagsetninga",
|
||||
"Description[it]": "Fuso orario, visualizzazione della data",
|
||||
"Description[ka]": "დროის სარტყელი, თარიღის ჩვენება",
|
||||
"Description[ko]": "시간대, 날짜 표시",
|
||||
"Description[lt]": "Laiko juosta, datos atvaizdavimas",
|
||||
"Description[nl]": "Tijdzone, datumweergave",
|
||||
"Description[nn]": "Tidssone, datovising",
|
||||
"Description[pa]": "ਸਮਾਂ-ਖੇਤਰ, ਤਾਰੀਖ ਦਿਖਾਓ",
|
||||
"Description[pl]": "Strefa czasowa, wyświetlanie daty",
|
||||
"Description[pt]": "Fuso-Horário, Visualização das Datas",
|
||||
"Description[pt_BR]": "Fuso horário, exibição de datas",
|
||||
"Description[ro]": "Fus orar, afișare dată",
|
||||
"Description[ru]": "Часовой пояс, формат вывода даты",
|
||||
"Description[sl]": "Časovni pas, prikaz datuma",
|
||||
"Description[sv]": "Tidszon, datumvisning",
|
||||
"Description[tr]": "Zaman Dilimi, Tarih Gösterimi",
|
||||
"Description[uk]": "Часовий пояс, показ дати",
|
||||
"Description[vi]": "Hiển thị múi giờ, ngày",
|
||||
"Description[x-test]": "xxTimezone, Date Displayxx",
|
||||
"Description[zh_CN]": "时区、日期显示",
|
||||
"Description[zh_TW]": "時區、日期顯示",
|
||||
"FormFactors": [
|
||||
"handset",
|
||||
"tablet",
|
||||
"mediacenter"
|
||||
],
|
||||
"Icon": "preferences-system-time",
|
||||
"Name": "Time and Date",
|
||||
"Name[az]": "Vaxt və Tarixi ayarlamaq",
|
||||
"Name[ca@valencia]": "Hora i data",
|
||||
"Name[ca]": "Hora i data",
|
||||
"Name[cs]": "Datum a čas",
|
||||
"Name[da]": "Klokkeslæt og dato",
|
||||
"Name[de]": "Zeit und Datum",
|
||||
"Name[el]": "Ώρα και ημερομηνία",
|
||||
"Name[en_GB]": "Time and Date",
|
||||
"Name[es]": "Fecha y hora",
|
||||
"Name[et]": "Kellaaeg ja kuupäev",
|
||||
"Name[eu]": "Ordua eta data",
|
||||
"Name[fi]": "Aika ja päivämäärä",
|
||||
"Name[fr]": "Heure et Date",
|
||||
"Name[gl]": "Hora e data",
|
||||
"Name[hu]": "Dátum és idő",
|
||||
"Name[ia]": "Hora e data",
|
||||
"Name[id]": "Waktu dan Tanggal",
|
||||
"Name[is]": "Dagsetning og tími",
|
||||
"Name[it]": "Ora e data",
|
||||
"Name[ka]": "თარიღი და დრო",
|
||||
"Name[ko]": "날짜와 시간",
|
||||
"Name[lt]": "Laikas ir data",
|
||||
"Name[nl]": "Datum en tijd",
|
||||
"Name[nn]": "Dato og klokkeslett",
|
||||
"Name[pa]": "ਸਮਾਂ ਅਤੇ ਮਿਤੀ",
|
||||
"Name[pl]": "Czas i data",
|
||||
"Name[pt]": "Hora e Data",
|
||||
"Name[pt_BR]": "Data e hora",
|
||||
"Name[ro]": "Oră și dată",
|
||||
"Name[ru]": "Дата и время",
|
||||
"Name[sk]": "Čas a dátum",
|
||||
"Name[sl]": "Čas in datum",
|
||||
"Name[sv]": "Tid och datum",
|
||||
"Name[ta]": "நேரமும் தேதியும்",
|
||||
"Name[tr]": "Zaman ve Tarih",
|
||||
"Name[uk]": "Час і дата",
|
||||
"Name[vi]": "Ngày và giờ",
|
||||
"Name[x-test]": "xxTime and Datexx",
|
||||
"Name[zh_CN]": "时间和日期",
|
||||
"Name[zh_TW]": "日期與時間"
|
||||
},
|
||||
"X-KDE-Keywords": "theme, look, feel",
|
||||
"X-KDE-Keywords[ast]": "estilu, aspeutu",
|
||||
"X-KDE-Keywords[az]": "theme, look, feel,mövzu,xarici görünüş,hissetmə",
|
||||
"X-KDE-Keywords[ca@valencia]": "tema, aspecte, comportament",
|
||||
"X-KDE-Keywords[ca]": "tema, aspecte, comportament",
|
||||
"X-KDE-Keywords[cs]": "motiv,vzhled,chování",
|
||||
"X-KDE-Keywords[da]": "tema, udseende, fremtoning",
|
||||
"X-KDE-Keywords[de]": "Design,Erscheinungsbild",
|
||||
"X-KDE-Keywords[el]": "θέμα, όψη, αίσθηση",
|
||||
"X-KDE-Keywords[en_GB]": "theme, look, feel",
|
||||
"X-KDE-Keywords[es]": "tema, aspecto, visual",
|
||||
"X-KDE-Keywords[et]": "teema, välimus",
|
||||
"X-KDE-Keywords[eu]": "gaia,itxura,izaera",
|
||||
"X-KDE-Keywords[fi]": "teema, ulkoasu, tuntuma",
|
||||
"X-KDE-Keywords[fr]": "thème, apparence, comportement, graphique",
|
||||
"X-KDE-Keywords[gl]": "tema, aparencia, estilo, comportamento",
|
||||
"X-KDE-Keywords[hu]": "téma, kinézet, megjelenés",
|
||||
"X-KDE-Keywords[ia]": "thema, semblantia, apparentia",
|
||||
"X-KDE-Keywords[it]": "tema, aspetto",
|
||||
"X-KDE-Keywords[ko]": "theme, look, feel, 테마, 모습과 느낌, 외형, 외관",
|
||||
"X-KDE-Keywords[lt]": "apipavidalinimas, išvaizda, isvaizda, turinys",
|
||||
"X-KDE-Keywords[nl]": "thema, uiterlijk, gedrag",
|
||||
"X-KDE-Keywords[nn]": "tema, utsjånad, åtferd",
|
||||
"X-KDE-Keywords[pa]": "ਥੀਮ, ਦਿੱਖ, ਰਵੱਈਆ",
|
||||
"X-KDE-Keywords[pl]": "wystrój, wygląd, odczucia, wrażenia",
|
||||
"X-KDE-Keywords[pt]": "tema, aparência, comportamento",
|
||||
"X-KDE-Keywords[pt_BR]": "tema, visual, aparência",
|
||||
"X-KDE-Keywords[ro]": "tematică, temă, aspect, comportament",
|
||||
"X-KDE-Keywords[ru]": "theme,look,feel,тема,оформление,внешний вид,стиль",
|
||||
"X-KDE-Keywords[sk]": "téma, vzhľad, nastavenie",
|
||||
"X-KDE-Keywords[sl]": "tema, videz, občutek",
|
||||
"X-KDE-Keywords[sv]": "tema, utseende, känsla",
|
||||
"X-KDE-Keywords[ta]": "theme, look, feel, தோற்றம், தோற்றத்திட்டம், பார்வை, காட்சி, உணர்வு",
|
||||
"X-KDE-Keywords[tr]": "tema, bak, hisset",
|
||||
"X-KDE-Keywords[uk]": "theme,look,feel,тема,вигляд,поведінка",
|
||||
"X-KDE-Keywords[vi]": "theme,look,feel,chủ đề,nhìn,cảm",
|
||||
"X-KDE-Keywords[x-test]": "xxthemexx,xx lookxx,xx feelxx",
|
||||
"X-KDE-Keywords[zh_CN]": "theme, look, feel, 主题, 外观, 视觉效果, 显示效果",
|
||||
"X-KDE-Keywords[zh_TW]": "theme, look, feel, 主題, 外觀, 感覺",
|
||||
"X-KDE-System-Settings-Parent-Category": "regionalsettings",
|
||||
"X-KDE-Weight": 70
|
||||
}
|
||||
23
kcms/time/timezonedata.h
Normal file
23
kcms/time/timezonedata.h
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2014 Kai Uwe Broulik <kde@privat.broulik.de>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef TIMEZONEDATA_H
|
||||
#define TIMEZONEDATA_H
|
||||
|
||||
#include <QString>
|
||||
|
||||
class TimeZoneData
|
||||
{
|
||||
public:
|
||||
QString id;
|
||||
QString region;
|
||||
QString city;
|
||||
QString comment;
|
||||
bool checked;
|
||||
int offsetFromUtc;
|
||||
};
|
||||
|
||||
#endif // TIMEZONEDATA_H
|
||||
217
kcms/time/timezonemodel.cpp
Normal file
217
kcms/time/timezonemodel.cpp
Normal file
|
|
@ -0,0 +1,217 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2014 Kai Uwe Broulik <kde@privat.broulik.de>
|
||||
SPDX-FileCopyrightText: 2014 Martin Klapetek <mklapetek@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "timezonemodel.h"
|
||||
#include "timezonesi18n.h"
|
||||
|
||||
#include <KLocalizedString>
|
||||
#include <QStringMatcher>
|
||||
#include <QTimeZone>
|
||||
|
||||
TimeZoneFilterProxy::TimeZoneFilterProxy(QObject *parent)
|
||||
: QSortFilterProxyModel(parent)
|
||||
{
|
||||
m_stringMatcher.setCaseSensitivity(Qt::CaseInsensitive);
|
||||
}
|
||||
|
||||
bool TimeZoneFilterProxy::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
|
||||
{
|
||||
if (!sourceModel() || m_filterString.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const QString city = sourceModel()->index(source_row, 0, source_parent).data(TimeZoneModel::CityRole).toString();
|
||||
const QString region = sourceModel()->index(source_row, 0, source_parent).data(TimeZoneModel::RegionRole).toString();
|
||||
const QString comment = sourceModel()->index(source_row, 0, source_parent).data(TimeZoneModel::CommentRole).toString();
|
||||
|
||||
if (m_stringMatcher.indexIn(city) != -1 || m_stringMatcher.indexIn(region) != -1 || m_stringMatcher.indexIn(comment) != -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void TimeZoneFilterProxy::setFilterString(const QString &filterString)
|
||||
{
|
||||
m_filterString = filterString;
|
||||
m_stringMatcher.setPattern(filterString);
|
||||
emit filterStringChanged();
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
TimeZoneModel::TimeZoneModel(QObject *parent)
|
||||
: QAbstractListModel(parent)
|
||||
, m_timezonesI18n(new TimezonesI18n(this))
|
||||
{
|
||||
update();
|
||||
}
|
||||
|
||||
TimeZoneModel::~TimeZoneModel()
|
||||
{
|
||||
}
|
||||
|
||||
int TimeZoneModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(parent);
|
||||
return m_data.count();
|
||||
}
|
||||
|
||||
QVariant TimeZoneModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (index.isValid()) {
|
||||
TimeZoneData currentData = m_data.at(index.row());
|
||||
|
||||
switch (role) {
|
||||
case TimeZoneIdRole:
|
||||
return currentData.id;
|
||||
case RegionRole:
|
||||
return currentData.region;
|
||||
case CityRole:
|
||||
return currentData.city;
|
||||
case CommentRole:
|
||||
return currentData.comment;
|
||||
case CheckedRole:
|
||||
return currentData.checked;
|
||||
}
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
bool TimeZoneModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
||||
{
|
||||
if (!index.isValid() || value.isNull()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (role == CheckedRole) {
|
||||
m_data[index.row()].checked = value.toBool();
|
||||
emit dataChanged(index, index);
|
||||
|
||||
if (m_data[index.row()].checked) {
|
||||
m_selectedTimeZones.append(m_data[index.row()].id);
|
||||
m_offsetData.insert(m_data[index.row()].id, m_data[index.row()].offsetFromUtc);
|
||||
} else {
|
||||
m_selectedTimeZones.removeAll(m_data[index.row()].id);
|
||||
m_offsetData.remove(m_data[index.row()].id);
|
||||
}
|
||||
|
||||
sortTimeZones();
|
||||
|
||||
emit selectedTimeZonesChanged();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void TimeZoneModel::update()
|
||||
{
|
||||
beginResetModel();
|
||||
m_data.clear();
|
||||
|
||||
QTimeZone localZone = QTimeZone(QTimeZone::systemTimeZoneId());
|
||||
const QStringList data = QString::fromUtf8(localZone.id()).split(QLatin1Char('/'));
|
||||
|
||||
TimeZoneData local;
|
||||
local.id = QStringLiteral("Local");
|
||||
local.region = i18nc("This means \"Local Timezone\"", "Local");
|
||||
local.city = m_timezonesI18n->i18nCity(data.last());
|
||||
local.comment = i18n("Your system time zone");
|
||||
local.checked = false;
|
||||
|
||||
m_data.append(local);
|
||||
|
||||
QStringList cities;
|
||||
QHash<QString, QTimeZone> zonesByCity;
|
||||
|
||||
const QList<QByteArray> systemTimeZones = QTimeZone::availableTimeZoneIds();
|
||||
|
||||
for (auto it = systemTimeZones.constBegin(); it != systemTimeZones.constEnd(); ++it) {
|
||||
const QTimeZone zone(*it);
|
||||
const QStringList splitted = QString::fromUtf8(zone.id()).split(QStringLiteral("/"));
|
||||
|
||||
// CITY | COUNTRY | CONTINENT
|
||||
const QString key = QStringLiteral("%1|%2|%3").arg(splitted.last(), QLocale::countryToString(zone.country()), splitted.first());
|
||||
|
||||
cities.append(key);
|
||||
zonesByCity.insert(key, zone);
|
||||
}
|
||||
cities.sort(Qt::CaseInsensitive);
|
||||
|
||||
Q_FOREACH (const QString &key, cities) {
|
||||
const QTimeZone timeZone = zonesByCity.value(key);
|
||||
QString comment = timeZone.comment();
|
||||
|
||||
// FIXME - this was in the old code but makes no sense
|
||||
// if (!comment.isEmpty()) {
|
||||
// comment = i18n(comment.toUtf8());
|
||||
// }
|
||||
|
||||
const QStringList cityCountryContinent = key.split(QLatin1Char('|'));
|
||||
|
||||
TimeZoneData newData;
|
||||
newData.id = QString::fromUtf8(timeZone.id());
|
||||
newData.region = timeZone.country() == QLocale::AnyCountry
|
||||
? QString()
|
||||
: m_timezonesI18n->i18nContinents(cityCountryContinent.at(2)) + QLatin1Char('/') + m_timezonesI18n->i18nCountry(timeZone.country());
|
||||
newData.city = m_timezonesI18n->i18nCity(cityCountryContinent.at(0));
|
||||
newData.comment = comment;
|
||||
newData.checked = false;
|
||||
newData.offsetFromUtc = timeZone.offsetFromUtc(QDateTime::currentDateTimeUtc());
|
||||
m_data.append(newData);
|
||||
}
|
||||
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void TimeZoneModel::setSelectedTimeZones(const QStringList &selectedTimeZones)
|
||||
{
|
||||
m_selectedTimeZones = selectedTimeZones;
|
||||
for (int i = 0; i < m_data.size(); i++) {
|
||||
if (m_selectedTimeZones.contains(m_data.at(i).id)) {
|
||||
m_data[i].checked = true;
|
||||
m_offsetData.insert(m_data[i].id, m_data[i].offsetFromUtc);
|
||||
|
||||
QModelIndex index = createIndex(i, 0);
|
||||
emit dataChanged(index, index);
|
||||
}
|
||||
}
|
||||
|
||||
sortTimeZones();
|
||||
}
|
||||
|
||||
void TimeZoneModel::selectLocalTimeZone()
|
||||
{
|
||||
m_data[0].checked = true;
|
||||
|
||||
QModelIndex index = createIndex(0, 0);
|
||||
emit dataChanged(index, index);
|
||||
|
||||
m_selectedTimeZones << m_data[0].id;
|
||||
emit selectedTimeZonesChanged();
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> TimeZoneModel::roleNames() const
|
||||
{
|
||||
return QHash<int, QByteArray>({
|
||||
{TimeZoneIdRole, "timeZoneId"},
|
||||
{RegionRole, "region"},
|
||||
{CityRole, "city"},
|
||||
{CommentRole, "comment"},
|
||||
{CheckedRole, "checked"},
|
||||
});
|
||||
}
|
||||
|
||||
void TimeZoneModel::sortTimeZones()
|
||||
{
|
||||
std::sort(m_selectedTimeZones.begin(), m_selectedTimeZones.end(), [this](const QString &a, const QString &b) {
|
||||
return m_offsetData.value(a) < m_offsetData.value(b);
|
||||
});
|
||||
}
|
||||
80
kcms/time/timezonemodel.h
Normal file
80
kcms/time/timezonemodel.h
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2014 Kai Uwe Broulik <kde@privat.broulik.de>
|
||||
SPDX-FileCopyrightText: 2014 Martin Klapetek <mklapetek@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef TIMEZONEMODEL_H
|
||||
#define TIMEZONEMODEL_H
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
#include "timezonedata.h"
|
||||
|
||||
class TimezonesI18n;
|
||||
|
||||
class TimeZoneFilterProxy : public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString filterString WRITE setFilterString MEMBER m_filterString NOTIFY filterStringChanged)
|
||||
|
||||
public:
|
||||
explicit TimeZoneFilterProxy(QObject *parent = nullptr);
|
||||
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
|
||||
|
||||
void setFilterString(const QString &filterString);
|
||||
|
||||
Q_SIGNALS:
|
||||
void filterStringChanged();
|
||||
|
||||
private:
|
||||
QString m_filterString;
|
||||
QStringMatcher m_stringMatcher;
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
|
||||
class TimeZoneModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QStringList selectedTimeZones WRITE setSelectedTimeZones MEMBER m_selectedTimeZones NOTIFY selectedTimeZonesChanged)
|
||||
|
||||
public:
|
||||
explicit TimeZoneModel(QObject *parent = nullptr);
|
||||
~TimeZoneModel() override;
|
||||
|
||||
enum Roles {
|
||||
TimeZoneIdRole = Qt::UserRole + 1,
|
||||
RegionRole,
|
||||
CityRole,
|
||||
CommentRole,
|
||||
CheckedRole,
|
||||
};
|
||||
|
||||
int rowCount(const QModelIndex &parent) const override;
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
|
||||
|
||||
void update();
|
||||
void setSelectedTimeZones(const QStringList &selectedTimeZones);
|
||||
|
||||
Q_INVOKABLE void selectLocalTimeZone();
|
||||
|
||||
Q_SIGNALS:
|
||||
void selectedTimeZonesChanged();
|
||||
|
||||
protected:
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
private:
|
||||
void sortTimeZones();
|
||||
|
||||
QList<TimeZoneData> m_data;
|
||||
QHash<QString, int> m_offsetData; // used for sorting
|
||||
QStringList m_selectedTimeZones;
|
||||
TimezonesI18n *m_timezonesI18n;
|
||||
};
|
||||
|
||||
#endif // TIMEZONEMODEL_H
|
||||
787
kcms/time/timezonesi18n.cpp
Normal file
787
kcms/time/timezonesi18n.cpp
Normal file
|
|
@ -0,0 +1,787 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2014 Martin Klapetek <mklapetek@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
*/
|
||||
|
||||
#include "timezonesi18n.h"
|
||||
|
||||
#include <KLocalizedString>
|
||||
|
||||
TimezonesI18n::TimezonesI18n(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_isInitialized(false)
|
||||
{
|
||||
}
|
||||
|
||||
QString TimezonesI18n::i18nCity(const QString &city)
|
||||
{
|
||||
if (!m_isInitialized) {
|
||||
init();
|
||||
}
|
||||
return m_i18nCities.value(city);
|
||||
}
|
||||
|
||||
QString TimezonesI18n::i18nContinents(const QString &continent)
|
||||
{
|
||||
if (!m_isInitialized) {
|
||||
init();
|
||||
}
|
||||
return m_i18nContinents.value(continent);
|
||||
}
|
||||
|
||||
QString TimezonesI18n::i18nCountry(QLocale::Country country)
|
||||
{
|
||||
if (!m_isInitialized) {
|
||||
init();
|
||||
}
|
||||
return m_i18nCountries.value(country);
|
||||
}
|
||||
|
||||
void TimezonesI18n::init()
|
||||
{
|
||||
m_i18nCities =
|
||||
QHash<QString, QString>({{QStringLiteral("Abidjan"), i18nc("This is a city associated with particular time zone", "Abidjan")},
|
||||
{QStringLiteral("Accra"), i18nc("This is a city associated with particular time zone", "Accra")},
|
||||
{QStringLiteral("Adak"), i18nc("This is a city associated with particular time zone", "Adak")},
|
||||
{QStringLiteral("Addis_Ababa"), i18nc("This is a city associated with particular time zone", "Addis Ababa")},
|
||||
{QStringLiteral("Adelaide"), i18nc("This is a city associated with particular time zone", "Adelaide")},
|
||||
{QStringLiteral("Aden"), i18nc("This is a city associated with particular time zone", "Aden")},
|
||||
{QStringLiteral("Algiers"), i18nc("This is a city associated with particular time zone", "Algiers")},
|
||||
{QStringLiteral("Almaty"), i18nc("This is a city associated with particular time zone", "Almaty")},
|
||||
{QStringLiteral("Amman"), i18nc("This is a city associated with particular time zone", "Amman")},
|
||||
{QStringLiteral("Amsterdam"), i18nc("This is a city associated with particular time zone", "Amsterdam")},
|
||||
{QStringLiteral("Anadyr"), i18nc("This is a city associated with particular time zone", "Anadyr")},
|
||||
{QStringLiteral("Anchorage"), i18nc("This is a city associated with particular time zone", "Anchorage")},
|
||||
{QStringLiteral("Andorra"), i18nc("This is a city associated with particular time zone", "Andorra")},
|
||||
{QStringLiteral("Anguilla"), i18nc("This is a city associated with particular time zone", "Anguilla")},
|
||||
{QStringLiteral("Antananarivo"), i18nc("This is a city associated with particular time zone", "Antananarivo")},
|
||||
{QStringLiteral("Antigua"), i18nc("This is a city associated with particular time zone", "Antigua")},
|
||||
{QStringLiteral("Apia"), i18nc("This is a city associated with particular time zone", "Apia")},
|
||||
{QStringLiteral("Aqtau"), i18nc("This is a city associated with particular time zone", "Aqtau")},
|
||||
{QStringLiteral("Aqtobe"), i18nc("This is a city associated with particular time zone", "Aqtobe")},
|
||||
{QStringLiteral("Araguaina"), i18nc("This is a city associated with particular time zone", "Araguaina")},
|
||||
{QStringLiteral("Aruba"), i18nc("This is a city associated with particular time zone", "Aruba")},
|
||||
{QStringLiteral("Ashgabat"), i18nc("This is a city associated with particular time zone", "Ashgabat")},
|
||||
{QStringLiteral("Asmara"), i18nc("This is a city associated with particular time zone", "Asmara")},
|
||||
{QStringLiteral("Astrakhan"), i18nc("This is a city associated with particular time zone", "Astrakhan")},
|
||||
{QStringLiteral("Asuncion"), i18nc("This is a city associated with particular time zone", "Asuncion")},
|
||||
{QStringLiteral("Athens"), i18nc("This is a city associated with particular time zone", "Athens")},
|
||||
{QStringLiteral("Atikokan"), i18nc("This is a city associated with particular time zone", "Atikokan")},
|
||||
{QStringLiteral("Atyrau"), i18nc("This is a city associated with particular time zone", "Atyrau")},
|
||||
{QStringLiteral("Auckland"), i18nc("This is a city associated with particular time zone", "Auckland")},
|
||||
{QStringLiteral("Azores"), i18nc("This is a city associated with particular time zone", "Azores")},
|
||||
{QStringLiteral("Baghdad"), i18nc("This is a city associated with particular time zone", "Baghdad")},
|
||||
{QStringLiteral("Bahia_Banderas"), i18nc("This is a city associated with particular time zone", "Bahia Banderas")},
|
||||
{QStringLiteral("Bahia"), i18nc("This is a city associated with particular time zone", "Bahia")},
|
||||
{QStringLiteral("Bahrain"), i18nc("This is a city associated with particular time zone", "Bahrain")},
|
||||
{QStringLiteral("Baku"), i18nc("This is a city associated with particular time zone", "Baku")},
|
||||
{QStringLiteral("Bamako"), i18nc("This is a city associated with particular time zone", "Bamako")},
|
||||
{QStringLiteral("Bangkok"), i18nc("This is a city associated with particular time zone", "Bangkok")},
|
||||
{QStringLiteral("Bangui"), i18nc("This is a city associated with particular time zone", "Bangui")},
|
||||
{QStringLiteral("Banjul"), i18nc("This is a city associated with particular time zone", "Banjul")},
|
||||
{QStringLiteral("Barbados"), i18nc("This is a city associated with particular time zone", "Barbados")},
|
||||
{QStringLiteral("Barnaul"), i18nc("This is a city associated with particular time zone", "Barnaul")},
|
||||
{QStringLiteral("Beirut"), i18nc("This is a city associated with particular time zone", "Beirut")},
|
||||
{QStringLiteral("Belem"), i18nc("This is a city associated with particular time zone", "Belem")},
|
||||
{QStringLiteral("Belgrade"), i18nc("This is a city associated with particular time zone", "Belgrade")},
|
||||
{QStringLiteral("Belize"), i18nc("This is a city associated with particular time zone", "Belize")},
|
||||
{QStringLiteral("Berlin"), i18nc("This is a city associated with particular time zone", "Berlin")},
|
||||
{QStringLiteral("Bermuda"), i18nc("This is a city associated with particular time zone", "Bermuda")},
|
||||
{QStringLiteral("Beulah"), i18nc("This is a city associated with particular time zone", "Beulah")},
|
||||
{QStringLiteral("Bishkek"), i18nc("This is a city associated with particular time zone", "Bishkek")},
|
||||
{QStringLiteral("Bissau"), i18nc("This is a city associated with particular time zone", "Bissau")},
|
||||
{QStringLiteral("Blanc-Sablon"), i18nc("This is a city associated with particular time zone", "Blanc-Sablon")},
|
||||
{QStringLiteral("Blantyre"), i18nc("This is a city associated with particular time zone", "Blantyre")},
|
||||
{QStringLiteral("Boa_Vista"), i18nc("This is a city associated with particular time zone", "Boa Vista")},
|
||||
{QStringLiteral("Bogota"), i18nc("This is a city associated with particular time zone", "Bogota")},
|
||||
{QStringLiteral("Boise"), i18nc("This is a city associated with particular time zone", "Boise")},
|
||||
{QStringLiteral("Bougainville"), i18nc("This is a city associated with particular time zone", "Bougainville")},
|
||||
{QStringLiteral("Bratislava"), i18nc("This is a city associated with particular time zone", "Bratislava")},
|
||||
{QStringLiteral("Brazzaville"), i18nc("This is a city associated with particular time zone", "Brazzaville")},
|
||||
{QStringLiteral("Brisbane"), i18nc("This is a city associated with particular time zone", "Brisbane")},
|
||||
{QStringLiteral("Broken_Hill"), i18nc("This is a city associated with particular time zone", "Broken Hill")},
|
||||
{QStringLiteral("Brunei"), i18nc("This is a city associated with particular time zone", "Brunei")},
|
||||
{QStringLiteral("Brussels"), i18nc("This is a city associated with particular time zone", "Brussels")},
|
||||
{QStringLiteral("Bucharest"), i18nc("This is a city associated with particular time zone", "Bucharest")},
|
||||
{QStringLiteral("Budapest"), i18nc("This is a city associated with particular time zone", "Budapest")},
|
||||
{QStringLiteral("Buenos_Aires"), i18nc("This is a city associated with particular time zone", "Buenos Aires")},
|
||||
{QStringLiteral("Bujumbura"), i18nc("This is a city associated with particular time zone", "Bujumbura")},
|
||||
{QStringLiteral("Busingen"), i18nc("This is a city associated with particular time zone", "Busingen")},
|
||||
{QStringLiteral("Cairo"), i18nc("This is a city associated with particular time zone", "Cairo")},
|
||||
{QStringLiteral("Cambridge_Bay"), i18nc("This is a city associated with particular time zone", "Cambridge Bay")},
|
||||
{QStringLiteral("Campo_Grande"), i18nc("This is a city associated with particular time zone", "Campo Grande")},
|
||||
{QStringLiteral("Canary"), i18nc("This is a city associated with particular time zone", "Canary")},
|
||||
{QStringLiteral("Cancun"), i18nc("This is a city associated with particular time zone", "Cancun")},
|
||||
{QStringLiteral("Cape_Verde"), i18nc("This is a city associated with particular time zone", "Cape Verde")},
|
||||
{QStringLiteral("Caracas"), i18nc("This is a city associated with particular time zone", "Caracas")},
|
||||
{QStringLiteral("Casablanca"), i18nc("This is a city associated with particular time zone", "Casablanca")},
|
||||
{QStringLiteral("Casey"), i18nc("This is a city associated with particular time zone", "Casey")},
|
||||
{QStringLiteral("Catamarca"), i18nc("This is a city associated with particular time zone", "Catamarca")},
|
||||
{QStringLiteral("Cayenne"), i18nc("This is a city associated with particular time zone", "Cayenne")},
|
||||
{QStringLiteral("Cayman"), i18nc("This is a city associated with particular time zone", "Cayman")},
|
||||
{QStringLiteral("Center"), i18nc("This is a city associated with particular time zone", "Center")},
|
||||
{QStringLiteral("Ceuta"), i18nc("This is a city associated with particular time zone", "Ceuta")},
|
||||
{QStringLiteral("Chagos"), i18nc("This is a city associated with particular time zone", "Chagos")},
|
||||
{QStringLiteral("Chatham"), i18nc("This is a city associated with particular time zone", "Chatham")},
|
||||
{QStringLiteral("Chicago"), i18nc("This is a city associated with particular time zone", "Chicago")},
|
||||
{QStringLiteral("Chihuahua"), i18nc("This is a city associated with particular time zone", "Chihuahua")},
|
||||
{QStringLiteral("Chisinau"), i18nc("This is a city associated with particular time zone", "Chisinau")},
|
||||
{QStringLiteral("Chita"), i18nc("This is a city associated with particular time zone", "Chita")},
|
||||
{QStringLiteral("Choibalsan"), i18nc("This is a city associated with particular time zone", "Choibalsan")},
|
||||
{QStringLiteral("Chongqing"), i18nc("This is a city associated with particular time zone", "Chongqing")},
|
||||
{QStringLiteral("Christmas"), i18nc("This is a city associated with particular time zone", "Christmas")},
|
||||
{QStringLiteral("Chuuk"), i18nc("This is a city associated with particular time zone", "Chuuk")},
|
||||
{QStringLiteral("Cocos"), i18nc("This is a city associated with particular time zone", "Cocos")},
|
||||
{QStringLiteral("Colombo"), i18nc("This is a city associated with particular time zone", "Colombo")},
|
||||
{QStringLiteral("Comoro"), i18nc("This is a city associated with particular time zone", "Comoro")},
|
||||
{QStringLiteral("Conakry"), i18nc("This is a city associated with particular time zone", "Conakry")},
|
||||
{QStringLiteral("Copenhagen"), i18nc("This is a city associated with particular time zone", "Copenhagen")},
|
||||
{QStringLiteral("Cordoba"), i18nc("This is a city associated with particular time zone", "Cordoba")},
|
||||
{QStringLiteral("Costa_Rica"), i18nc("This is a city associated with particular time zone", "Costa Rica")},
|
||||
{QStringLiteral("Creston"), i18nc("This is a city associated with particular time zone", "Creston")},
|
||||
{QStringLiteral("Cuiaba"), i18nc("This is a city associated with particular time zone", "Cuiaba")},
|
||||
{QStringLiteral("Curacao"), i18nc("This is a city associated with particular time zone", "Curacao")},
|
||||
{QStringLiteral("Currie"), i18nc("This is a city associated with particular time zone", "Currie")},
|
||||
{QStringLiteral("Dakar"), i18nc("This is a city associated with particular time zone", "Dakar")},
|
||||
{QStringLiteral("Damascus"), i18nc("This is a city associated with particular time zone", "Damascus")},
|
||||
{QStringLiteral("Danmarkshavn"), i18nc("This is a city associated with particular time zone", "Danmarkshavn")},
|
||||
{QStringLiteral("Dar_es_Salaam"), i18nc("This is a city associated with particular time zone", "Dar es Salaam")},
|
||||
{QStringLiteral("Darwin"), i18nc("This is a city associated with particular time zone", "Darwin")},
|
||||
{QStringLiteral("Davis"), i18nc("This is a city associated with particular time zone", "Davis")},
|
||||
{QStringLiteral("Dawson_Creek"), i18nc("This is a city associated with particular time zone", "Dawson Creek")},
|
||||
{QStringLiteral("Dawson"), i18nc("This is a city associated with particular time zone", "Dawson")},
|
||||
{QStringLiteral("Denver"), i18nc("This is a city associated with particular time zone", "Denver")},
|
||||
{QStringLiteral("Detroit"), i18nc("This is a city associated with particular time zone", "Detroit")},
|
||||
{QStringLiteral("Dhaka"), i18nc("This is a city associated with particular time zone", "Dhaka")},
|
||||
{QStringLiteral("Dili"), i18nc("This is a city associated with particular time zone", "Dili")},
|
||||
{QStringLiteral("Djibouti"), i18nc("This is a city associated with particular time zone", "Djibouti")},
|
||||
{QStringLiteral("Dominica"), i18nc("This is a city associated with particular time zone", "Dominica")},
|
||||
{QStringLiteral("Douala"), i18nc("This is a city associated with particular time zone", "Douala")},
|
||||
{QStringLiteral("Dubai"), i18nc("This is a city associated with particular time zone", "Dubai")},
|
||||
{QStringLiteral("Dublin"), i18nc("This is a city associated with particular time zone", "Dublin")},
|
||||
{QStringLiteral("DumontDUrville"), i18nc("This is a city associated with particular time zone", "Dumont d’Urville")},
|
||||
{QStringLiteral("Dushanbe"), i18nc("This is a city associated with particular time zone", "Dushanbe")},
|
||||
{QStringLiteral("Easter"), i18nc("This is a city associated with particular time zone", "Easter")},
|
||||
{QStringLiteral("Edmonton"), i18nc("This is a city associated with particular time zone", "Edmonton")},
|
||||
{QStringLiteral("Efate"), i18nc("This is a city associated with particular time zone", "Efate")},
|
||||
{QStringLiteral("Eirunepe"), i18nc("This is a city associated with particular time zone", "Eirunepe")},
|
||||
{QStringLiteral("El_Aaiun"), i18nc("This is a city associated with particular time zone", "El Aaiun")},
|
||||
{QStringLiteral("El_Salvador"), i18nc("This is a city associated with particular time zone", "El Salvador")},
|
||||
{QStringLiteral("Enderbury"), i18nc("This is a city associated with particular time zone", "Enderbury")},
|
||||
{QStringLiteral("Eucla"), i18nc("This is a city associated with particular time zone", "Eucla")},
|
||||
{QStringLiteral("Fakaofo"), i18nc("This is a city associated with particular time zone", "Fakaofo")},
|
||||
{QStringLiteral("Famagusta"), i18nc("This is a city associated with particular time zone", "Famagusta")},
|
||||
{QStringLiteral("Faroe"), i18nc("This is a city associated with particular time zone", "Faroe")},
|
||||
{QStringLiteral("Fiji"), i18nc("This is a city associated with particular time zone", "Fiji")},
|
||||
{QStringLiteral("Fort_Nelson"), i18nc("This is a city associated with particular time zone", "Fort Nelson")},
|
||||
{QStringLiteral("Fortaleza"), i18nc("This is a city associated with particular time zone", "Fortaleza")},
|
||||
{QStringLiteral("Freetown"), i18nc("This is a city associated with particular time zone", "Freetown")},
|
||||
{QStringLiteral("Funafuti"), i18nc("This is a city associated with particular time zone", "Funafuti")},
|
||||
{QStringLiteral("Gaborone"), i18nc("This is a city associated with particular time zone", "Gaborone")},
|
||||
{QStringLiteral("Galapagos"), i18nc("This is a city associated with particular time zone", "Galapagos")},
|
||||
{QStringLiteral("Gambier"), i18nc("This is a city associated with particular time zone", "Gambier")},
|
||||
{QStringLiteral("Gaza"), i18nc("This is a city associated with particular time zone", "Gaza")},
|
||||
{QStringLiteral("Gibraltar"), i18nc("This is a city associated with particular time zone", "Gibraltar")},
|
||||
{QStringLiteral("Glace_Bay"), i18nc("This is a city associated with particular time zone", "Glace Bay")},
|
||||
{QStringLiteral("Godthab"), i18nc("This is a city associated with particular time zone", "Godthab")},
|
||||
{QStringLiteral("Goose_Bay"), i18nc("This is a city associated with particular time zone", "Goose Bay")},
|
||||
{QStringLiteral("Grand_Turk"), i18nc("This is a city associated with particular time zone", "Grand Turk")},
|
||||
{QStringLiteral("Grenada"), i18nc("This is a city associated with particular time zone", "Grenada")},
|
||||
{QStringLiteral("Guadalcanal"), i18nc("This is a city associated with particular time zone", "Guadalcanal")},
|
||||
{QStringLiteral("Guadeloupe"), i18nc("This is a city associated with particular time zone", "Guadeloupe")},
|
||||
{QStringLiteral("Guam"), i18nc("This is a city associated with particular time zone", "Guam")},
|
||||
{QStringLiteral("Guatemala"), i18nc("This is a city associated with particular time zone", "Guatemala")},
|
||||
{QStringLiteral("Guayaquil"), i18nc("This is a city associated with particular time zone", "Guayaquil")},
|
||||
{QStringLiteral("Guernsey"), i18nc("This is a city associated with particular time zone", "Guernsey")},
|
||||
{QStringLiteral("Guyana"), i18nc("This is a city associated with particular time zone", "Guyana")},
|
||||
{QStringLiteral("Halifax"), i18nc("This is a city associated with particular time zone", "Halifax")},
|
||||
{QStringLiteral("Harare"), i18nc("This is a city associated with particular time zone", "Harare")},
|
||||
{QStringLiteral("Harbin"), i18nc("This is a city associated with particular time zone", "Harbin")},
|
||||
{QStringLiteral("Havana"), i18nc("This is a city associated with particular time zone", "Havana")},
|
||||
{QStringLiteral("Hebron"), i18nc("This is a city associated with particular time zone", "Hebron")},
|
||||
{QStringLiteral("Helsinki"), i18nc("This is a city associated with particular time zone", "Helsinki")},
|
||||
{QStringLiteral("Hermosillo"), i18nc("This is a city associated with particular time zone", "Hermosillo")},
|
||||
{QStringLiteral("Ho_Chi_Minh"), i18nc("This is a city associated with particular time zone", "Ho Chi Minh")},
|
||||
{QStringLiteral("Hobart"), i18nc("This is a city associated with particular time zone", "Hobart")},
|
||||
{QStringLiteral("Hong_Kong"), i18nc("This is a city associated with particular time zone", "Hong Kong")},
|
||||
{QStringLiteral("Honolulu"), i18nc("This is a city associated with particular time zone", "Honolulu")},
|
||||
{QStringLiteral("Hovd"), i18nc("This is a city associated with particular time zone", "Hovd")},
|
||||
{QStringLiteral("Indianapolis"), i18nc("This is a city associated with particular time zone", "Indianapolis")},
|
||||
{QStringLiteral("Inuvik"), i18nc("This is a city associated with particular time zone", "Inuvik")},
|
||||
{QStringLiteral("Iqaluit"), i18nc("This is a city associated with particular time zone", "Iqaluit")},
|
||||
{QStringLiteral("Irkutsk"), i18nc("This is a city associated with particular time zone", "Irkutsk")},
|
||||
{QStringLiteral("Isle_of_Man"), i18nc("This is a city associated with particular time zone", "Isle of Man")},
|
||||
{QStringLiteral("Istanbul"), i18nc("This is a city associated with particular time zone", "Istanbul")},
|
||||
{QStringLiteral("Jakarta"), i18nc("This is a city associated with particular time zone", "Jakarta")},
|
||||
{QStringLiteral("Jamaica"), i18nc("This is a city associated with particular time zone", "Jamaica")},
|
||||
{QStringLiteral("Jayapura"), i18nc("This is a city associated with particular time zone", "Jayapura")},
|
||||
{QStringLiteral("Jersey"), i18nc("This is a city associated with particular time zone", "Jersey")},
|
||||
{QStringLiteral("Jerusalem"), i18nc("This is a city associated with particular time zone", "Jerusalem")},
|
||||
{QStringLiteral("Johannesburg"), i18nc("This is a city associated with particular time zone", "Johannesburg")},
|
||||
{QStringLiteral("Johnston"), i18nc("This is a city associated with particular time zone", "Johnston")},
|
||||
{QStringLiteral("Juba"), i18nc("This is a city associated with particular time zone", "Juba")},
|
||||
{QStringLiteral("Jujuy"), i18nc("This is a city associated with particular time zone", "Jujuy")},
|
||||
{QStringLiteral("Juneau"), i18nc("This is a city associated with particular time zone", "Juneau")},
|
||||
{QStringLiteral("Kabul"), i18nc("This is a city associated with particular time zone", "Kabul")},
|
||||
{QStringLiteral("Kaliningrad"), i18nc("This is a city associated with particular time zone", "Kaliningrad")},
|
||||
{QStringLiteral("Kamchatka"), i18nc("This is a city associated with particular time zone", "Kamchatka")},
|
||||
{QStringLiteral("Kampala"), i18nc("This is a city associated with particular time zone", "Kampala")},
|
||||
{QStringLiteral("Karachi"), i18nc("This is a city associated with particular time zone", "Karachi")},
|
||||
{QStringLiteral("Kashgar"), i18nc("This is a city associated with particular time zone", "Kashgar")},
|
||||
{QStringLiteral("Kathmandu"), i18nc("This is a city associated with particular time zone", "Kathmandu")},
|
||||
{QStringLiteral("Kerguelen"), i18nc("This is a city associated with particular time zone", "Kerguelen")},
|
||||
{QStringLiteral("Khandyga"), i18nc("This is a city associated with particular time zone", "Khandyga")},
|
||||
{QStringLiteral("Khartoum"), i18nc("This is a city associated with particular time zone", "Khartoum")},
|
||||
{QStringLiteral("Kiev"), i18nc("This is a city associated with particular time zone", "Kyiv")},
|
||||
{QStringLiteral("Kigali"), i18nc("This is a city associated with particular time zone", "Kigali")},
|
||||
{QStringLiteral("Kinshasa"), i18nc("This is a city associated with particular time zone", "Kinshasa")},
|
||||
{QStringLiteral("Kiritimati"), i18nc("This is a city associated with particular time zone", "Kiritimati")},
|
||||
{QStringLiteral("Kirov"), i18nc("This is a city associated with particular time zone", "Kirov")},
|
||||
{QStringLiteral("Knox"), i18nc("This is a city associated with particular time zone", "Knox")},
|
||||
{QStringLiteral("Kolkata"), i18nc("This is a city associated with particular time zone", "Kolkata")},
|
||||
{QStringLiteral("Kosrae"), i18nc("This is a city associated with particular time zone", "Kosrae")},
|
||||
{QStringLiteral("Kralendijk"), i18nc("This is a city associated with particular time zone", "Kralendijk")},
|
||||
{QStringLiteral("Krasnoyarsk"), i18nc("This is a city associated with particular time zone", "Krasnoyarsk")},
|
||||
{QStringLiteral("Kuala_Lumpur"), i18nc("This is a city associated with particular time zone", "Kuala Lumpur")},
|
||||
{QStringLiteral("Kuching"), i18nc("This is a city associated with particular time zone", "Kuching")},
|
||||
{QStringLiteral("Kuwait"), i18nc("This is a city associated with particular time zone", "Kuwait")},
|
||||
{QStringLiteral("Kwajalein"), i18nc("This is a city associated with particular time zone", "Kwajalein")},
|
||||
{QStringLiteral("La_Paz"), i18nc("This is a city associated with particular time zone", "La Paz")},
|
||||
{QStringLiteral("La_Rioja"), i18nc("This is a city associated with particular time zone", "La Rioja")},
|
||||
{QStringLiteral("Lagos"), i18nc("This is a city associated with particular time zone", "Lagos")},
|
||||
{QStringLiteral("Libreville"), i18nc("This is a city associated with particular time zone", "Libreville")},
|
||||
{QStringLiteral("Lima"), i18nc("This is a city associated with particular time zone", "Lima")},
|
||||
{QStringLiteral("Lindeman"), i18nc("This is a city associated with particular time zone", "Lindeman")},
|
||||
{QStringLiteral("Lisbon"), i18nc("This is a city associated with particular time zone", "Lisbon")},
|
||||
{QStringLiteral("Ljubljana"), i18nc("This is a city associated with particular time zone", "Ljubljana")},
|
||||
{QStringLiteral("Lome"), i18nc("This is a city associated with particular time zone", "Lome")},
|
||||
{QStringLiteral("London"), i18nc("This is a city associated with particular time zone", "London")},
|
||||
{QStringLiteral("Longyearbyen"), i18nc("This is a city associated with particular time zone", "Longyearbyen")},
|
||||
{QStringLiteral("Lord_Howe"), i18nc("This is a city associated with particular time zone", "Lord Howe")},
|
||||
{QStringLiteral("Los_Angeles"), i18nc("This is a city associated with particular time zone", "Los Angeles")},
|
||||
{QStringLiteral("Louisville"), i18nc("This is a city associated with particular time zone", "Louisville")},
|
||||
{QStringLiteral("Lower_Princes"), i18nc("This is a city associated with particular time zone", "Lower Princes")},
|
||||
{QStringLiteral("Luanda"), i18nc("This is a city associated with particular time zone", "Luanda")},
|
||||
{QStringLiteral("Lubumbashi"), i18nc("This is a city associated with particular time zone", "Lubumbashi")},
|
||||
{QStringLiteral("Lusaka"), i18nc("This is a city associated with particular time zone", "Lusaka")},
|
||||
{QStringLiteral("Luxembourg"), i18nc("This is a city associated with particular time zone", "Luxembourg")},
|
||||
{QStringLiteral("Macau"), i18nc("This is a city associated with particular time zone", "Macau")},
|
||||
{QStringLiteral("Maceio"), i18nc("This is a city associated with particular time zone", "Maceio")},
|
||||
{QStringLiteral("Macquarie"), i18nc("This is a city associated with particular time zone", "Macquarie")},
|
||||
{QStringLiteral("Madeira"), i18nc("This is a city associated with particular time zone", "Madeira")},
|
||||
{QStringLiteral("Madrid"), i18nc("This is a city associated with particular time zone", "Madrid")},
|
||||
{QStringLiteral("Magadan"), i18nc("This is a city associated with particular time zone", "Magadan")},
|
||||
{QStringLiteral("Mahe"), i18nc("This is a city associated with particular time zone", "Mahe")},
|
||||
{QStringLiteral("Majuro"), i18nc("This is a city associated with particular time zone", "Majuro")},
|
||||
{QStringLiteral("Makassar"), i18nc("This is a city associated with particular time zone", "Makassar")},
|
||||
{QStringLiteral("Malabo"), i18nc("This is a city associated with particular time zone", "Malabo")},
|
||||
{QStringLiteral("Maldives"), i18nc("This is a city associated with particular time zone", "Maldives")},
|
||||
{QStringLiteral("Malta"), i18nc("This is a city associated with particular time zone", "Malta")},
|
||||
{QStringLiteral("Managua"), i18nc("This is a city associated with particular time zone", "Managua")},
|
||||
{QStringLiteral("Manaus"), i18nc("This is a city associated with particular time zone", "Manaus")},
|
||||
{QStringLiteral("Manila"), i18nc("This is a city associated with particular time zone", "Manila")},
|
||||
{QStringLiteral("Maputo"), i18nc("This is a city associated with particular time zone", "Maputo")},
|
||||
{QStringLiteral("Marengo"), i18nc("This is a city associated with particular time zone", "Marengo")},
|
||||
{QStringLiteral("Mariehamn"), i18nc("This is a city associated with particular time zone", "Mariehamn")},
|
||||
{QStringLiteral("Marigot"), i18nc("This is a city associated with particular time zone", "Marigot")},
|
||||
{QStringLiteral("Marquesas"), i18nc("This is a city associated with particular time zone", "Marquesas")},
|
||||
{QStringLiteral("Martinique"), i18nc("This is a city associated with particular time zone", "Martinique")},
|
||||
{QStringLiteral("Maseru"), i18nc("This is a city associated with particular time zone", "Maseru")},
|
||||
{QStringLiteral("Matamoros"), i18nc("This is a city associated with particular time zone", "Matamoros")},
|
||||
{QStringLiteral("Mauritius"), i18nc("This is a city associated with particular time zone", "Mauritius")},
|
||||
{QStringLiteral("Mawson"), i18nc("This is a city associated with particular time zone", "Mawson")},
|
||||
{QStringLiteral("Mayotte"), i18nc("This is a city associated with particular time zone", "Mayotte")},
|
||||
{QStringLiteral("Mazatlan"), i18nc("This is a city associated with particular time zone", "Mazatlan")},
|
||||
{QStringLiteral("Mbabane"), i18nc("This is a city associated with particular time zone", "Mbabane")},
|
||||
{QStringLiteral("McMurdo"), i18nc("This is a city associated with particular time zone", "McMurdo")},
|
||||
{QStringLiteral("Melbourne"), i18nc("This is a city associated with particular time zone", "Melbourne")},
|
||||
{QStringLiteral("Mendoza"), i18nc("This is a city associated with particular time zone", "Mendoza")},
|
||||
{QStringLiteral("Menominee"), i18nc("This is a city associated with particular time zone", "Menominee")},
|
||||
{QStringLiteral("Merida"), i18nc("This is a city associated with particular time zone", "Merida")},
|
||||
{QStringLiteral("Metlakatla"), i18nc("This is a city associated with particular time zone", "Metlakatla")},
|
||||
{QStringLiteral("Mexico_City"), i18nc("This is a city associated with particular time zone", "Mexico City")},
|
||||
{QStringLiteral("Midway"), i18nc("This is a city associated with particular time zone", "Midway")},
|
||||
{QStringLiteral("Minsk"), i18nc("This is a city associated with particular time zone", "Minsk")},
|
||||
{QStringLiteral("Miquelon"), i18nc("This is a city associated with particular time zone", "Miquelon")},
|
||||
{QStringLiteral("Mogadishu"), i18nc("This is a city associated with particular time zone", "Mogadishu")},
|
||||
{QStringLiteral("Monaco"), i18nc("This is a city associated with particular time zone", "Monaco")},
|
||||
{QStringLiteral("Moncton"), i18nc("This is a city associated with particular time zone", "Moncton")},
|
||||
{QStringLiteral("Monrovia"), i18nc("This is a city associated with particular time zone", "Monrovia")},
|
||||
{QStringLiteral("Monterrey"), i18nc("This is a city associated with particular time zone", "Monterrey")},
|
||||
{QStringLiteral("Montevideo"), i18nc("This is a city associated with particular time zone", "Montevideo")},
|
||||
{QStringLiteral("Monticello"), i18nc("This is a city associated with particular time zone", "Monticello")},
|
||||
{QStringLiteral("Montserrat"), i18nc("This is a city associated with particular time zone", "Montserrat")},
|
||||
{QStringLiteral("Moscow"), i18nc("This is a city associated with particular time zone", "Moscow")},
|
||||
{QStringLiteral("Muscat"), i18nc("This is a city associated with particular time zone", "Muscat")},
|
||||
{QStringLiteral("Nairobi"), i18nc("This is a city associated with particular time zone", "Nairobi")},
|
||||
{QStringLiteral("Nassau"), i18nc("This is a city associated with particular time zone", "Nassau")},
|
||||
{QStringLiteral("Nauru"), i18nc("This is a city associated with particular time zone", "Nauru")},
|
||||
{QStringLiteral("Ndjamena"), i18nc("This is a city associated with particular time zone", "Ndjamena")},
|
||||
{QStringLiteral("New_Salem"), i18nc("This is a city associated with particular time zone", "New Salem")},
|
||||
{QStringLiteral("New_York"), i18nc("This is a city associated with particular time zone", "New York")},
|
||||
{QStringLiteral("Niamey"), i18nc("This is a city associated with particular time zone", "Niamey")},
|
||||
{QStringLiteral("Nicosia"), i18nc("This is a city associated with particular time zone", "Nicosia")},
|
||||
{QStringLiteral("Nipigon"), i18nc("This is a city associated with particular time zone", "Nipigon")},
|
||||
{QStringLiteral("Niue"), i18nc("This is a city associated with particular time zone", "Niue")},
|
||||
{QStringLiteral("Nome"), i18nc("This is a city associated with particular time zone", "Nome")},
|
||||
{QStringLiteral("Norfolk"), i18nc("This is a city associated with particular time zone", "Norfolk")},
|
||||
{QStringLiteral("Noronha"), i18nc("This is a city associated with particular time zone", "Noronha")},
|
||||
{QStringLiteral("Nouakchott"), i18nc("This is a city associated with particular time zone", "Nouakchott")},
|
||||
{QStringLiteral("Noumea"), i18nc("This is a city associated with particular time zone", "Noumea")},
|
||||
{QStringLiteral("Novokuznetsk"), i18nc("This is a city associated with particular time zone", "Novokuznetsk")},
|
||||
{QStringLiteral("Novosibirsk"), i18nc("This is a city associated with particular time zone", "Novosibirsk")},
|
||||
{QStringLiteral("Nuuk"), i18nc("This is a city associated with particular time zone", "Nuuk")},
|
||||
{QStringLiteral("Ojinaga"), i18nc("This is a city associated with particular time zone", "Ojinaga")},
|
||||
{QStringLiteral("Omsk"), i18nc("This is a city associated with particular time zone", "Omsk")},
|
||||
{QStringLiteral("Oral"), i18nc("This is a city associated with particular time zone", "Oral")},
|
||||
{QStringLiteral("Oslo"), i18nc("This is a city associated with particular time zone", "Oslo")},
|
||||
{QStringLiteral("Ouagadougou"), i18nc("This is a city associated with particular time zone", "Ouagadougou")},
|
||||
{QStringLiteral("Pago_Pago"), i18nc("This is a city associated with particular time zone", "Pago Pago")},
|
||||
{QStringLiteral("Palau"), i18nc("This is a city associated with particular time zone", "Palau")},
|
||||
{QStringLiteral("Palmer"), i18nc("This is a city associated with particular time zone", "Palmer")},
|
||||
{QStringLiteral("Panama"), i18nc("This is a city associated with particular time zone", "Panama")},
|
||||
{QStringLiteral("Pangnirtung"), i18nc("This is a city associated with particular time zone", "Pangnirtung")},
|
||||
{QStringLiteral("Paramaribo"), i18nc("This is a city associated with particular time zone", "Paramaribo")},
|
||||
{QStringLiteral("Paris"), i18nc("This is a city associated with particular time zone", "Paris")},
|
||||
{QStringLiteral("Perth"), i18nc("This is a city associated with particular time zone", "Perth")},
|
||||
{QStringLiteral("Petersburg"), i18nc("This is a city associated with particular time zone", "Petersburg")},
|
||||
{QStringLiteral("Phnom_Penh"), i18nc("This is a city associated with particular time zone", "Phnom Penh")},
|
||||
{QStringLiteral("Phoenix"), i18nc("This is a city associated with particular time zone", "Phoenix")},
|
||||
{QStringLiteral("Pitcairn"), i18nc("This is a city associated with particular time zone", "Pitcairn")},
|
||||
{QStringLiteral("Podgorica"), i18nc("This is a city associated with particular time zone", "Podgorica")},
|
||||
{QStringLiteral("Pohnpei"), i18nc("This is a city associated with particular time zone", "Pohnpei")},
|
||||
{QStringLiteral("Pontianak"), i18nc("This is a city associated with particular time zone", "Pontianak")},
|
||||
{QStringLiteral("Port-au-Prince"), i18nc("This is a city associated with particular time zone", "Port-au-Prince")},
|
||||
{QStringLiteral("Port_Moresby"), i18nc("This is a city associated with particular time zone", "Port Moresby")},
|
||||
{QStringLiteral("Port_of_Spain"), i18nc("This is a city associated with particular time zone", "Port of Spain")},
|
||||
{QStringLiteral("Porto-Novo"), i18nc("This is a city associated with particular time zone", "Porto-Novo")},
|
||||
{QStringLiteral("Porto_Velho"), i18nc("This is a city associated with particular time zone", "Porto Velho")},
|
||||
{QStringLiteral("Prague"), i18nc("This is a city associated with particular time zone", "Prague")},
|
||||
{QStringLiteral("Puerto_Rico"), i18nc("This is a city associated with particular time zone", "Puerto Rico")},
|
||||
{QStringLiteral("Punta_Arenas"), i18nc("This is a city associated with particular time zone", "Punta Arenas")},
|
||||
{QStringLiteral("Pyongyang"), i18nc("This is a city associated with particular time zone", "Pyongyang")},
|
||||
{QStringLiteral("Qatar"), i18nc("This is a city associated with particular time zone", "Qatar")},
|
||||
{QStringLiteral("Qostanay"), i18nc("This is a city associated with particular time zone", "Qostanay")},
|
||||
{QStringLiteral("Qyzylorda"), i18nc("This is a city associated with particular time zone", "Qyzylorda")},
|
||||
{QStringLiteral("Rainy_River"), i18nc("This is a city associated with particular time zone", "Rainy River")},
|
||||
{QStringLiteral("Rangoon"), i18nc("This is a city associated with particular time zone", "Rangoon")},
|
||||
{QStringLiteral("Rankin_Inlet"), i18nc("This is a city associated with particular time zone", "Rankin Inlet")},
|
||||
{QStringLiteral("Rarotonga"), i18nc("This is a city associated with particular time zone", "Rarotonga")},
|
||||
{QStringLiteral("Recife"), i18nc("This is a city associated with particular time zone", "Recife")},
|
||||
{QStringLiteral("Regina"), i18nc("This is a city associated with particular time zone", "Regina")},
|
||||
{QStringLiteral("Resolute"), i18nc("This is a city associated with particular time zone", "Resolute")},
|
||||
{QStringLiteral("Reunion"), i18nc("This is a city associated with particular time zone", "Reunion")},
|
||||
{QStringLiteral("Reykjavik"), i18nc("This is a city associated with particular time zone", "Reykjavik")},
|
||||
{QStringLiteral("Riga"), i18nc("This is a city associated with particular time zone", "Riga")},
|
||||
{QStringLiteral("Rio_Branco"), i18nc("This is a city associated with particular time zone", "Rio Branco")},
|
||||
{QStringLiteral("Rio_Gallegos"), i18nc("This is a city associated with particular time zone", "Rio Gallegos")},
|
||||
{QStringLiteral("Riyadh"), i18nc("This is a city associated with particular time zone", "Riyadh")},
|
||||
{QStringLiteral("Rome"), i18nc("This is a city associated with particular time zone", "Rome")},
|
||||
{QStringLiteral("Rothera"), i18nc("This is a city associated with particular time zone", "Rothera")},
|
||||
{QStringLiteral("Saipan"), i18nc("This is a city associated with particular time zone", "Saipan")},
|
||||
{QStringLiteral("Sakhalin"), i18nc("This is a city associated with particular time zone", "Sakhalin")},
|
||||
{QStringLiteral("Salta"), i18nc("This is a city associated with particular time zone", "Salta")},
|
||||
{QStringLiteral("Samara"), i18nc("This is a city associated with particular time zone", "Samara")},
|
||||
{QStringLiteral("Samarkand"), i18nc("This is a city associated with particular time zone", "Samarkand")},
|
||||
{QStringLiteral("San_Juan"), i18nc("This is a city associated with particular time zone", "San Juan")},
|
||||
{QStringLiteral("San_Luis"), i18nc("This is a city associated with particular time zone", "San Luis")},
|
||||
{QStringLiteral("San_Marino"), i18nc("This is a city associated with particular time zone", "San Marino")},
|
||||
{QStringLiteral("Santa_Isabel"), i18nc("This is a city associated with particular time zone", "Santa Isabel")},
|
||||
{QStringLiteral("Santarem"), i18nc("This is a city associated with particular time zone", "Santarem")},
|
||||
{QStringLiteral("Santiago"), i18nc("This is a city associated with particular time zone", "Santiago")},
|
||||
{QStringLiteral("Santo_Domingo"), i18nc("This is a city associated with particular time zone", "Santo Domingo")},
|
||||
{QStringLiteral("Sao_Paulo"), i18nc("This is a city associated with particular time zone", "Sao Paulo")},
|
||||
{QStringLiteral("Sao_Tome"), i18nc("This is a city associated with particular time zone", "Sao Tome")},
|
||||
{QStringLiteral("Sarajevo"), i18nc("This is a city associated with particular time zone", "Sarajevo")},
|
||||
{QStringLiteral("Saratov"), i18nc("This is a city associated with particular time zone", "Saratov")},
|
||||
{QStringLiteral("Scoresbysund"), i18nc("This is a city associated with particular time zone", "Scoresbysund")},
|
||||
{QStringLiteral("Seoul"), i18nc("This is a city associated with particular time zone", "Seoul")},
|
||||
{QStringLiteral("Shanghai"), i18nc("This is a city associated with particular time zone", "Shanghai")},
|
||||
{QStringLiteral("Simferopol"), i18nc("This is a city associated with particular time zone", "Simferopol")},
|
||||
{QStringLiteral("Singapore"), i18nc("This is a city associated with particular time zone", "Singapore")},
|
||||
{QStringLiteral("Sitka"), i18nc("This is a city associated with particular time zone", "Sitka")},
|
||||
{QStringLiteral("Skopje"), i18nc("This is a city associated with particular time zone", "Skopje")},
|
||||
{QStringLiteral("Sofia"), i18nc("This is a city associated with particular time zone", "Sofia")},
|
||||
{QStringLiteral("South_Georgia"), i18nc("This is a city associated with particular time zone", "South Georgia")},
|
||||
{QStringLiteral("Srednekolymsk"), i18nc("This is a city associated with particular time zone", "Srednekolymsk")},
|
||||
{QStringLiteral("St_Barthelemy"), i18nc("This is a city associated with particular time zone", "St Barthelemy")},
|
||||
{QStringLiteral("St_Helena"), i18nc("This is a city associated with particular time zone", "St Helena")},
|
||||
{QStringLiteral("St_Johns"), i18nc("This is a city associated with particular time zone", "St Johns")},
|
||||
{QStringLiteral("St_Kitts"), i18nc("This is a city associated with particular time zone", "St Kitts")},
|
||||
{QStringLiteral("St_Lucia"), i18nc("This is a city associated with particular time zone", "St Lucia")},
|
||||
{QStringLiteral("St_Thomas"), i18nc("This is a city associated with particular time zone", "St Thomas")},
|
||||
{QStringLiteral("St_Vincent"), i18nc("This is a city associated with particular time zone", "St Vincent")},
|
||||
{QStringLiteral("Stanley"), i18nc("This is a city associated with particular time zone", "Stanley")},
|
||||
{QStringLiteral("Stockholm"), i18nc("This is a city associated with particular time zone", "Stockholm")},
|
||||
{QStringLiteral("Swift_Current"), i18nc("This is a city associated with particular time zone", "Swift Current")},
|
||||
{QStringLiteral("Sydney"), i18nc("This is a city associated with particular time zone", "Sydney")},
|
||||
{QStringLiteral("Syowa"), i18nc("This is a city associated with particular time zone", "Syowa")},
|
||||
{QStringLiteral("Tahiti"), i18nc("This is a city associated with particular time zone", "Tahiti")},
|
||||
{QStringLiteral("Taipei"), i18nc("This is a city associated with particular time zone", "Taipei")},
|
||||
{QStringLiteral("Tallinn"), i18nc("This is a city associated with particular time zone", "Tallinn")},
|
||||
{QStringLiteral("Tarawa"), i18nc("This is a city associated with particular time zone", "Tarawa")},
|
||||
{QStringLiteral("Tashkent"), i18nc("This is a city associated with particular time zone", "Tashkent")},
|
||||
{QStringLiteral("Tbilisi"), i18nc("This is a city associated with particular time zone", "Tbilisi")},
|
||||
{QStringLiteral("Tegucigalpa"), i18nc("This is a city associated with particular time zone", "Tegucigalpa")},
|
||||
{QStringLiteral("Tehran"), i18nc("This is a city associated with particular time zone", "Tehran")},
|
||||
{QStringLiteral("Tell_City"), i18nc("This is a city associated with particular time zone", "Tell City")},
|
||||
{QStringLiteral("Thimphu"), i18nc("This is a city associated with particular time zone", "Thimphu")},
|
||||
{QStringLiteral("Thule"), i18nc("This is a city associated with particular time zone", "Thule")},
|
||||
{QStringLiteral("Thunder_Bay"), i18nc("This is a city associated with particular time zone", "Thunder Bay")},
|
||||
{QStringLiteral("Tijuana"), i18nc("This is a city associated with particular time zone", "Tijuana")},
|
||||
{QStringLiteral("Tirane"), i18nc("This is a city associated with particular time zone", "Tirane")},
|
||||
{QStringLiteral("Tokyo"), i18nc("This is a city associated with particular time zone", "Tokyo")},
|
||||
{QStringLiteral("Tomsk"), i18nc("This is a city associated with particular time zone", "Tomsk")},
|
||||
{QStringLiteral("Tongatapu"), i18nc("This is a city associated with particular time zone", "Tongatapu")},
|
||||
{QStringLiteral("Toronto"), i18nc("This is a city associated with particular time zone", "Toronto")},
|
||||
{QStringLiteral("Tortola"), i18nc("This is a city associated with particular time zone", "Tortola")},
|
||||
{QStringLiteral("Tripoli"), i18nc("This is a city associated with particular time zone", "Tripoli")},
|
||||
{QStringLiteral("Troll"), i18nc("This is a city associated with particular time zone", "Troll")},
|
||||
{QStringLiteral("Tucuman"), i18nc("This is a city associated with particular time zone", "Tucuman")},
|
||||
{QStringLiteral("Tunis"), i18nc("This is a city associated with particular time zone", "Tunis")},
|
||||
{QStringLiteral("Ulaanbaatar"), i18nc("This is a city associated with particular time zone", "Ulaanbaatar")},
|
||||
{QStringLiteral("Ulyanovsk"), i18nc("This is a city associated with particular time zone", "Ulyanovsk")},
|
||||
{QStringLiteral("Urumqi"), i18nc("This is a city associated with particular time zone", "Urumqi")},
|
||||
{QStringLiteral("Ushuaia"), i18nc("This is a city associated with particular time zone", "Ushuaia")},
|
||||
{QStringLiteral("Ust-Nera"), i18nc("This is a city associated with particular time zone", "Ust-Nera")},
|
||||
{QStringLiteral("UTC+00:00"), i18nc("This is a generic time zone name, localize as needed", "UTC+00:00")},
|
||||
{QStringLiteral("UTC+01:00"), i18nc("This is a generic time zone name, localize as needed", "UTC+01:00")},
|
||||
{QStringLiteral("UTC+02:00"), i18nc("This is a generic time zone name, localize as needed", "UTC+02:00")},
|
||||
{QStringLiteral("UTC+03:00"), i18nc("This is a generic time zone name, localize as needed", "UTC+03:00")},
|
||||
{QStringLiteral("UTC+03:30"), i18nc("This is a generic time zone name, localize as needed", "UTC+03:30")},
|
||||
{QStringLiteral("UTC+04:00"), i18nc("This is a generic time zone name, localize as needed", "UTC+04:00")},
|
||||
{QStringLiteral("UTC+04:30"), i18nc("This is a generic time zone name, localize as needed", "UTC+04:30")},
|
||||
{QStringLiteral("UTC+05:00"), i18nc("This is a generic time zone name, localize as needed", "UTC+05:00")},
|
||||
{QStringLiteral("UTC+05:30"), i18nc("This is a generic time zone name, localize as needed", "UTC+05:30")},
|
||||
{QStringLiteral("UTC+05:45"), i18nc("This is a generic time zone name, localize as needed", "UTC+05:45")},
|
||||
{QStringLiteral("UTC+06:00"), i18nc("This is a generic time zone name, localize as needed", "UTC+06:00")},
|
||||
{QStringLiteral("UTC+06:30"), i18nc("This is a generic time zone name, localize as needed", "UTC+06:30")},
|
||||
{QStringLiteral("UTC+07:00"), i18nc("This is a generic time zone name, localize as needed", "UTC+07:00")},
|
||||
{QStringLiteral("UTC+08:00"), i18nc("This is a generic time zone name, localize as needed", "UTC+08:00")},
|
||||
{QStringLiteral("UTC+09:00"), i18nc("This is a generic time zone name, localize as needed", "UTC+09:00")},
|
||||
{QStringLiteral("UTC+09:30"), i18nc("This is a generic time zone name, localize as needed", "UTC+09:30")},
|
||||
{QStringLiteral("UTC+10:00"), i18nc("This is a generic time zone name, localize as needed", "UTC+10:00")},
|
||||
{QStringLiteral("UTC+11:00"), i18nc("This is a generic time zone name, localize as needed", "UTC+11:00")},
|
||||
{QStringLiteral("UTC+12:00"), i18nc("This is a generic time zone name, localize as needed", "UTC+12:00")},
|
||||
{QStringLiteral("UTC+13:00"), i18nc("This is a generic time zone name, localize as needed", "UTC+13:00")},
|
||||
{QStringLiteral("UTC+14:00"), i18nc("This is a generic time zone name, localize as needed", "UTC+14:00")},
|
||||
{QStringLiteral("UTC-00:00"), i18nc("This is a generic time zone name, localize as needed", "UTC-00:00")},
|
||||
{QStringLiteral("UTC-01:00"), i18nc("This is a generic time zone name, localize as needed", "UTC-01:00")},
|
||||
{QStringLiteral("UTC-02:00"), i18nc("This is a generic time zone name, localize as needed", "UTC-02:00")},
|
||||
{QStringLiteral("UTC-03:00"), i18nc("This is a generic time zone name, localize as needed", "UTC-03:00")},
|
||||
{QStringLiteral("UTC-03:30"), i18nc("This is a generic time zone name, localize as needed", "UTC-03:30")},
|
||||
{QStringLiteral("UTC-04:00"), i18nc("This is a generic time zone name, localize as needed", "UTC-04:00")},
|
||||
{QStringLiteral("UTC-04:30"), i18nc("This is a generic time zone name, localize as needed", "UTC-04:30")},
|
||||
{QStringLiteral("UTC-05:00"), i18nc("This is a generic time zone name, localize as needed", "UTC-05:00")},
|
||||
{QStringLiteral("UTC-06:00"), i18nc("This is a generic time zone name, localize as needed", "UTC-06:00")},
|
||||
{QStringLiteral("UTC-07:00"), i18nc("This is a generic time zone name, localize as needed", "UTC-07:00")},
|
||||
{QStringLiteral("UTC-08:00"), i18nc("This is a generic time zone name, localize as needed", "UTC-08:00")},
|
||||
{QStringLiteral("UTC-09:00"), i18nc("This is a generic time zone name, localize as needed", "UTC-09:00")},
|
||||
{QStringLiteral("UTC-10:00"), i18nc("This is a generic time zone name, localize as needed", "UTC-10:00")},
|
||||
{QStringLiteral("UTC-11:00"), i18nc("This is a generic time zone name, localize as needed", "UTC-11:00")},
|
||||
{QStringLiteral("UTC-12:00"), i18nc("This is a generic time zone name, localize as needed", "UTC-12:00")},
|
||||
{QStringLiteral("UTC-13:00"), i18nc("This is a generic time zone name, localize as needed", "UTC-13:00")},
|
||||
{QStringLiteral("UTC-14:00"), i18nc("This is a generic time zone name, localize as needed", "UTC-14:00")},
|
||||
{QStringLiteral("UTC"), i18nc("This is a generic time zone name, localize as needed", "UTC")},
|
||||
{QStringLiteral("Uzhgorod"), i18nc("This is a city associated with particular time zone", "Uzhhorod")},
|
||||
{QStringLiteral("Vaduz"), i18nc("This is a city associated with particular time zone", "Vaduz")},
|
||||
{QStringLiteral("Vancouver"), i18nc("This is a city associated with particular time zone", "Vancouver")},
|
||||
{QStringLiteral("Vatican"), i18nc("This is a city associated with particular time zone", "Vatican")},
|
||||
{QStringLiteral("Vevay"), i18nc("This is a city associated with particular time zone", "Vevay")},
|
||||
{QStringLiteral("Vienna"), i18nc("This is a city associated with particular time zone", "Vienna")},
|
||||
{QStringLiteral("Vientiane"), i18nc("This is a city associated with particular time zone", "Vientiane")},
|
||||
{QStringLiteral("Vilnius"), i18nc("This is a city associated with particular time zone", "Vilnius")},
|
||||
{QStringLiteral("Vincennes"), i18nc("This is a city associated with particular time zone", "Vincennes")},
|
||||
{QStringLiteral("Vladivostok"), i18nc("This is a city associated with particular time zone", "Vladivostok")},
|
||||
{QStringLiteral("Volgograd"), i18nc("This is a city associated with particular time zone", "Volgograd")},
|
||||
{QStringLiteral("Vostok"), i18nc("This is a city associated with particular time zone", "Vostok")},
|
||||
{QStringLiteral("Wake"), i18nc("This is a city associated with particular time zone", "Wake")},
|
||||
{QStringLiteral("Wallis"), i18nc("This is a city associated with particular time zone", "Wallis")},
|
||||
{QStringLiteral("Warsaw"), i18nc("This is a city associated with particular time zone", "Warsaw")},
|
||||
{QStringLiteral("Whitehorse"), i18nc("This is a city associated with particular time zone", "Whitehorse")},
|
||||
{QStringLiteral("Winamac"), i18nc("This is a city associated with particular time zone", "Winamac")},
|
||||
{QStringLiteral("Windhoek"), i18nc("This is a city associated with particular time zone", "Windhoek")},
|
||||
{QStringLiteral("Winnipeg"), i18nc("This is a city associated with particular time zone", "Winnipeg")},
|
||||
{QStringLiteral("Yakutat"), i18nc("This is a city associated with particular time zone", "Yakutat")},
|
||||
{QStringLiteral("Yakutsk"), i18nc("This is a city associated with particular time zone", "Yakutsk")},
|
||||
{QStringLiteral("Yangon"), i18nc("This is a city associated with particular time zone", "Yangon")},
|
||||
{QStringLiteral("Yekaterinburg"), i18nc("This is a city associated with particular time zone", "Yekaterinburg")},
|
||||
{QStringLiteral("Yellowknife"), i18nc("This is a city associated with particular time zone", "Yellowknife")},
|
||||
{QStringLiteral("Yerevan"), i18nc("This is a city associated with particular time zone", "Yerevan")},
|
||||
{QStringLiteral("Zagreb"), i18nc("This is a city associated with particular time zone", "Zagreb")},
|
||||
{QStringLiteral("Zaporozhye"), i18nc("This is a city associated with particular time zone", "Zaporizhzhia")},
|
||||
{QStringLiteral("Zurich"), i18nc("This is a city associated with particular time zone", "Zurich")}});
|
||||
|
||||
#define ENTRY_ISO_3166(qlocale_enum, string) {QLocale::qlocale_enum, i18nd("iso_3166", string)}
|
||||
/* Make sure the country names match their versions in iso-codes,
|
||||
* ISO 3166. */
|
||||
m_i18nCountries = QHash<QLocale::Country, QString>({
|
||||
ENTRY_ISO_3166(IvoryCoast, "Côte d'Ivoire"),
|
||||
ENTRY_ISO_3166(Ghana, "Ghana"),
|
||||
ENTRY_ISO_3166(Ethiopia, "Ethiopia"),
|
||||
ENTRY_ISO_3166(Algeria, "Algeria"),
|
||||
ENTRY_ISO_3166(Eritrea, "Eritrea"),
|
||||
ENTRY_ISO_3166(Mali, "Mali"),
|
||||
ENTRY_ISO_3166(CentralAfricanRepublic, "Central African Republic"),
|
||||
ENTRY_ISO_3166(Gambia, "Gambia"),
|
||||
ENTRY_ISO_3166(GuineaBissau, "Guinea-Bissau"),
|
||||
ENTRY_ISO_3166(Malawi, "Malawi"),
|
||||
ENTRY_ISO_3166(CongoBrazzaville, "Congo"),
|
||||
ENTRY_ISO_3166(Burundi, "Burundi"),
|
||||
ENTRY_ISO_3166(Egypt, "Egypt"),
|
||||
ENTRY_ISO_3166(Morocco, "Morocco"),
|
||||
ENTRY_ISO_3166(Spain, "Spain"),
|
||||
ENTRY_ISO_3166(Guinea, "Guinea"),
|
||||
ENTRY_ISO_3166(Senegal, "Senegal"),
|
||||
ENTRY_ISO_3166(Tanzania, "Tanzania"),
|
||||
ENTRY_ISO_3166(Djibouti, "Djibouti"),
|
||||
ENTRY_ISO_3166(Cameroon, "Cameroon"),
|
||||
ENTRY_ISO_3166(WesternSahara, "Western Sahara"),
|
||||
ENTRY_ISO_3166(SierraLeone, "Sierra Leone"),
|
||||
ENTRY_ISO_3166(Botswana, "Botswana"),
|
||||
ENTRY_ISO_3166(BouvetIsland, "Bouvet Island"),
|
||||
ENTRY_ISO_3166(Zimbabwe, "Zimbabwe"),
|
||||
ENTRY_ISO_3166(SouthAfrica, "South Africa"),
|
||||
ENTRY_ISO_3166(SouthSudan, "South Sudan"),
|
||||
ENTRY_ISO_3166(Uganda, "Uganda"),
|
||||
ENTRY_ISO_3166(Sudan, "Sudan"),
|
||||
ENTRY_ISO_3166(Rwanda, "Rwanda"),
|
||||
ENTRY_ISO_3166(CongoKinshasa, "Congo, The Democratic Republic of the"),
|
||||
ENTRY_ISO_3166(Nigeria, "Nigeria"),
|
||||
ENTRY_ISO_3166(Gabon, "Gabon"),
|
||||
ENTRY_ISO_3166(Togo, "Togo"),
|
||||
ENTRY_ISO_3166(Angola, "Angola"),
|
||||
ENTRY_ISO_3166(Zambia, "Zambia"),
|
||||
ENTRY_ISO_3166(EquatorialGuinea, "Equatorial Guinea"),
|
||||
ENTRY_ISO_3166(Mozambique, "Mozambique"),
|
||||
ENTRY_ISO_3166(Lesotho, "Lesotho"),
|
||||
ENTRY_ISO_3166(Swaziland, "Swaziland"),
|
||||
ENTRY_ISO_3166(Somalia, "Somalia"),
|
||||
ENTRY_ISO_3166(Liberia, "Liberia"),
|
||||
ENTRY_ISO_3166(Kenya, "Kenya"),
|
||||
ENTRY_ISO_3166(Chad, "Chad"),
|
||||
ENTRY_ISO_3166(Niger, "Niger"),
|
||||
ENTRY_ISO_3166(Mauritania, "Mauritania"),
|
||||
ENTRY_ISO_3166(BurkinaFaso, "Burkina Faso"),
|
||||
ENTRY_ISO_3166(Benin, "Benin"),
|
||||
ENTRY_ISO_3166(SaoTomeAndPrincipe, "Sao Tome and Principe"),
|
||||
ENTRY_ISO_3166(Libya, "Libya"),
|
||||
ENTRY_ISO_3166(Tunisia, "Tunisia"),
|
||||
ENTRY_ISO_3166(Namibia, "Namibia"),
|
||||
ENTRY_ISO_3166(UnitedStates, "United States"),
|
||||
ENTRY_ISO_3166(Anguilla, "Anguilla"),
|
||||
ENTRY_ISO_3166(AntiguaAndBarbuda, "Antigua and Barbuda"),
|
||||
ENTRY_ISO_3166(Brazil, "Brazil"),
|
||||
ENTRY_ISO_3166(Argentina, "Argentina"),
|
||||
ENTRY_ISO_3166(Aruba, "Aruba"),
|
||||
ENTRY_ISO_3166(Paraguay, "Paraguay"),
|
||||
ENTRY_ISO_3166(Canada, "Canada"),
|
||||
ENTRY_ISO_3166(Mexico, "Mexico"),
|
||||
ENTRY_ISO_3166(Barbados, "Barbados"),
|
||||
ENTRY_ISO_3166(Belize, "Belize"),
|
||||
ENTRY_ISO_3166(Colombia, "Colombia"),
|
||||
ENTRY_ISO_3166(Venezuela, "Venezuela"),
|
||||
ENTRY_ISO_3166(FrenchGuiana, "French Guiana"),
|
||||
ENTRY_ISO_3166(CaymanIslands, "Cayman Islands"),
|
||||
ENTRY_ISO_3166(CostaRica, "Costa Rica"),
|
||||
ENTRY_ISO_3166(CuraSao, "Curaçao"),
|
||||
ENTRY_ISO_3166(Greenland, "Greenland"),
|
||||
ENTRY_ISO_3166(Dominica, "Dominica"),
|
||||
ENTRY_ISO_3166(ElSalvador, "El Salvador"),
|
||||
ENTRY_ISO_3166(TurksAndCaicosIslands, "Turks and Caicos Islands"),
|
||||
ENTRY_ISO_3166(Grenada, "Grenada"),
|
||||
ENTRY_ISO_3166(Guadeloupe, "Guadeloupe"),
|
||||
ENTRY_ISO_3166(Guatemala, "Guatemala"),
|
||||
ENTRY_ISO_3166(Ecuador, "Ecuador"),
|
||||
ENTRY_ISO_3166(Guyana, "Guyana"),
|
||||
ENTRY_ISO_3166(Cuba, "Cuba"),
|
||||
ENTRY_ISO_3166(Jamaica, "Jamaica"),
|
||||
ENTRY_ISO_3166(Bonaire, "Bonaire, Sint Eustatius and Saba"),
|
||||
ENTRY_ISO_3166(Bolivia, "Bolivia"),
|
||||
ENTRY_ISO_3166(Peru, "Peru"),
|
||||
ENTRY_ISO_3166(SintMaarten, "Sint Maarten (Dutch part)"),
|
||||
ENTRY_ISO_3166(Nicaragua, "Nicaragua"),
|
||||
ENTRY_ISO_3166(SaintMartin, "Saint Martin (French part)"),
|
||||
ENTRY_ISO_3166(Martinique, "Martinique"),
|
||||
ENTRY_ISO_3166(SaintPierreAndMiquelon, "Saint Pierre and Miquelon"),
|
||||
ENTRY_ISO_3166(Uruguay, "Uruguay"),
|
||||
ENTRY_ISO_3166(Montserrat, "Montserrat"),
|
||||
ENTRY_ISO_3166(Bahamas, "Bahamas"),
|
||||
ENTRY_ISO_3166(Panama, "Panama"),
|
||||
ENTRY_ISO_3166(Suriname, "Suriname"),
|
||||
ENTRY_ISO_3166(Haiti, "Haiti"),
|
||||
ENTRY_ISO_3166(HeardAndMcDonaldIslands, "Heard Island and McDonald Islands"),
|
||||
ENTRY_ISO_3166(TrinidadAndTobago, "Trinidad and Tobago"),
|
||||
ENTRY_ISO_3166(PuertoRico, "Puerto Rico"),
|
||||
ENTRY_ISO_3166(Chile, "Chile"),
|
||||
ENTRY_ISO_3166(DominicanRepublic, "Dominican Republic"),
|
||||
ENTRY_ISO_3166(SaintBarthelemy, "Saint Barthélemy"),
|
||||
ENTRY_ISO_3166(SaintKittsAndNevis, "Saint Kitts and Nevis"),
|
||||
ENTRY_ISO_3166(SaintLucia, "Saint Lucia"),
|
||||
ENTRY_ISO_3166(UnitedStatesVirginIslands, "Virgin Islands, U.S."),
|
||||
ENTRY_ISO_3166(SaintVincentAndTheGrenadines, "Saint Vincent and the Grenadines"),
|
||||
ENTRY_ISO_3166(Honduras, "Honduras"),
|
||||
ENTRY_ISO_3166(BritishVirginIslands, "Virgin Islands, British"),
|
||||
ENTRY_ISO_3166(Antarctica, "Antarctica"),
|
||||
ENTRY_ISO_3166(Australia, "Australia"),
|
||||
ENTRY_ISO_3166(SvalbardAndJanMayenIslands, "Svalbard and Jan Mayen"),
|
||||
ENTRY_ISO_3166(Yemen, "Yemen"),
|
||||
ENTRY_ISO_3166(Kazakhstan, "Kazakhstan"),
|
||||
ENTRY_ISO_3166(Jordan, "Jordan"),
|
||||
ENTRY_ISO_3166(Russia, "Russian Federation"),
|
||||
ENTRY_ISO_3166(Turkmenistan, "Turkmenistan"),
|
||||
ENTRY_ISO_3166(Iraq, "Iraq"),
|
||||
ENTRY_ISO_3166(Bahrain, "Bahrain"),
|
||||
ENTRY_ISO_3166(Azerbaijan, "Azerbaijan"),
|
||||
ENTRY_ISO_3166(Thailand, "Thailand"),
|
||||
ENTRY_ISO_3166(Lebanon, "Lebanon"),
|
||||
ENTRY_ISO_3166(Kyrgyzstan, "Kyrgyzstan"),
|
||||
ENTRY_ISO_3166(Brunei, "Brunei Darussalam"),
|
||||
ENTRY_ISO_3166(Mongolia, "Mongolia"),
|
||||
ENTRY_ISO_3166(China, "China"),
|
||||
ENTRY_ISO_3166(SriLanka, "Sri Lanka"),
|
||||
ENTRY_ISO_3166(Syria, "Syrian Arab Republic"),
|
||||
ENTRY_ISO_3166(Bangladesh, "Bangladesh"),
|
||||
ENTRY_ISO_3166(EastTimor, "Timor-Leste"),
|
||||
ENTRY_ISO_3166(UnitedArabEmirates, "United Arab Emirates"),
|
||||
ENTRY_ISO_3166(Tajikistan, "Tajikistan"),
|
||||
ENTRY_ISO_3166(PalestinianTerritories, "Palestine, State of"),
|
||||
ENTRY_ISO_3166(Vietnam, "Vietnam"),
|
||||
ENTRY_ISO_3166(HongKong, "Hong Kong"),
|
||||
ENTRY_ISO_3166(Indonesia, "Indonesia"),
|
||||
ENTRY_ISO_3166(Israel, "Israel"),
|
||||
ENTRY_ISO_3166(Afghanistan, "Afghanistan"),
|
||||
ENTRY_ISO_3166(Pakistan, "Pakistan"),
|
||||
ENTRY_ISO_3166(Nepal, "Nepal"),
|
||||
ENTRY_ISO_3166(India, "India"),
|
||||
ENTRY_ISO_3166(Malaysia, "Malaysia"),
|
||||
ENTRY_ISO_3166(Kuwait, "Kuwait"),
|
||||
ENTRY_ISO_3166(Macau, "Macao"),
|
||||
ENTRY_ISO_3166(Philippines, "Philippines"),
|
||||
ENTRY_ISO_3166(Oman, "Oman"),
|
||||
ENTRY_ISO_3166(Cyprus, "Cyprus"),
|
||||
ENTRY_ISO_3166(Cambodia, "Cambodia"),
|
||||
ENTRY_ISO_3166(NorthKorea, "Korea, Democratic People's Republic of"),
|
||||
ENTRY_ISO_3166(Qatar, "Qatar"),
|
||||
ENTRY_ISO_3166(Myanmar, "Myanmar"),
|
||||
ENTRY_ISO_3166(SaudiArabia, "Saudi Arabia"),
|
||||
ENTRY_ISO_3166(Uzbekistan, "Uzbekistan"),
|
||||
ENTRY_ISO_3166(SouthKorea, "Korea, Republic of"),
|
||||
ENTRY_ISO_3166(Singapore, "Singapore"),
|
||||
ENTRY_ISO_3166(Taiwan, "Taiwan"),
|
||||
ENTRY_ISO_3166(Georgia, "Georgia"),
|
||||
ENTRY_ISO_3166(Iran, "Iran, Islamic Republic of"),
|
||||
ENTRY_ISO_3166(Bhutan, "Bhutan"),
|
||||
ENTRY_ISO_3166(Japan, "Japan"),
|
||||
ENTRY_ISO_3166(Laos, "Lao People's Democratic Republic"),
|
||||
ENTRY_ISO_3166(Armenia, "Armenia"),
|
||||
ENTRY_ISO_3166(Portugal, "Portugal"),
|
||||
ENTRY_ISO_3166(Bermuda, "Bermuda"),
|
||||
ENTRY_ISO_3166(CapeVerde, "Cabo Verde"),
|
||||
ENTRY_ISO_3166(FaroeIslands, "Faroe Islands"),
|
||||
ENTRY_ISO_3166(Iceland, "Iceland"),
|
||||
ENTRY_ISO_3166(SouthGeorgiaAndTheSouthSandwichIslands, "South Georgia and the South Sandwich Islands"),
|
||||
ENTRY_ISO_3166(SaintHelena, "Saint Helena, Ascension and Tristan da Cunha"),
|
||||
ENTRY_ISO_3166(FalklandIslands, "Falkland Islands (Malvinas)"),
|
||||
ENTRY_ISO_3166(Netherlands, "Netherlands"),
|
||||
ENTRY_ISO_3166(Andorra, "Andorra"),
|
||||
ENTRY_ISO_3166(Greece, "Greece"),
|
||||
ENTRY_ISO_3166(Serbia, "Serbia"),
|
||||
ENTRY_ISO_3166(Germany, "Germany"),
|
||||
ENTRY_ISO_3166(Slovakia, "Slovakia"),
|
||||
ENTRY_ISO_3166(Belgium, "Belgium"),
|
||||
ENTRY_ISO_3166(Romania, "Romania"),
|
||||
ENTRY_ISO_3166(Hungary, "Hungary"),
|
||||
ENTRY_ISO_3166(Moldova, "Moldova"),
|
||||
ENTRY_ISO_3166(Denmark, "Denmark"),
|
||||
ENTRY_ISO_3166(Ireland, "Ireland"),
|
||||
ENTRY_ISO_3166(Gibraltar, "Gibraltar"),
|
||||
ENTRY_ISO_3166(Guernsey, "Guernsey"),
|
||||
ENTRY_ISO_3166(Finland, "Finland"),
|
||||
ENTRY_ISO_3166(IsleOfMan, "Isle of Man"),
|
||||
ENTRY_ISO_3166(Turkey, "Turkey"),
|
||||
ENTRY_ISO_3166(Jersey, "Jersey"),
|
||||
ENTRY_ISO_3166(Ukraine, "Ukraine"),
|
||||
ENTRY_ISO_3166(Slovenia, "Slovenia"),
|
||||
ENTRY_ISO_3166(UnitedKingdom, "United Kingdom"),
|
||||
ENTRY_ISO_3166(Luxembourg, "Luxembourg"),
|
||||
ENTRY_ISO_3166(Malta, "Malta"),
|
||||
ENTRY_ISO_3166(AlandIslands, "Åland Islands"),
|
||||
ENTRY_ISO_3166(Belarus, "Belarus"),
|
||||
ENTRY_ISO_3166(Monaco, "Monaco"),
|
||||
ENTRY_ISO_3166(Norway, "Norway"),
|
||||
ENTRY_ISO_3166(France, "France"),
|
||||
ENTRY_ISO_3166(Montenegro, "Montenegro"),
|
||||
ENTRY_ISO_3166(CzechRepublic, "Czechia"),
|
||||
ENTRY_ISO_3166(Latvia, "Latvia"),
|
||||
ENTRY_ISO_3166(Italy, "Italy"),
|
||||
ENTRY_ISO_3166(SanMarino, "San Marino"),
|
||||
ENTRY_ISO_3166(BosniaAndHerzegowina, "Bosnia and Herzegovina"),
|
||||
ENTRY_ISO_3166(Macedonia, "Macedonia, Republic of"),
|
||||
ENTRY_ISO_3166(Bulgaria, "Bulgaria"),
|
||||
ENTRY_ISO_3166(Sweden, "Sweden"),
|
||||
ENTRY_ISO_3166(Estonia, "Estonia"),
|
||||
ENTRY_ISO_3166(Albania, "Albania"),
|
||||
ENTRY_ISO_3166(Liechtenstein, "Liechtenstein"),
|
||||
ENTRY_ISO_3166(VaticanCityState, "Holy See (Vatican City State)"),
|
||||
ENTRY_ISO_3166(Austria, "Austria"),
|
||||
ENTRY_ISO_3166(Lithuania, "Lithuania"),
|
||||
ENTRY_ISO_3166(Poland, "Poland"),
|
||||
ENTRY_ISO_3166(Croatia, "Croatia"),
|
||||
ENTRY_ISO_3166(Switzerland, "Switzerland"),
|
||||
ENTRY_ISO_3166(Madagascar, "Madagascar"),
|
||||
ENTRY_ISO_3166(BritishIndianOceanTerritory, "British Indian Ocean Territory"),
|
||||
ENTRY_ISO_3166(ChristmasIsland, "Christmas Island"),
|
||||
ENTRY_ISO_3166(CocosIslands, "Cocos (Keeling) Islands"),
|
||||
ENTRY_ISO_3166(Comoros, "Comoros"),
|
||||
ENTRY_ISO_3166(FrenchSouthernTerritories, "French Southern Territories"),
|
||||
ENTRY_ISO_3166(Seychelles, "Seychelles"),
|
||||
ENTRY_ISO_3166(Maldives, "Maldives"),
|
||||
ENTRY_ISO_3166(Mauritius, "Mauritius"),
|
||||
ENTRY_ISO_3166(Mayotte, "Mayotte"),
|
||||
ENTRY_ISO_3166(Reunion, "Réunion"),
|
||||
ENTRY_ISO_3166(Samoa, "Samoa"),
|
||||
ENTRY_ISO_3166(NewZealand, "New Zealand"),
|
||||
ENTRY_ISO_3166(Micronesia, "Micronesia, Federated States of"),
|
||||
ENTRY_ISO_3166(Vanuatu, "Vanuatu"),
|
||||
ENTRY_ISO_3166(Kiribati, "Kiribati"),
|
||||
ENTRY_ISO_3166(TokelauCountry, "Tokelau"),
|
||||
ENTRY_ISO_3166(Fiji, "Fiji"),
|
||||
ENTRY_ISO_3166(TuvaluCountry, "Tuvalu"),
|
||||
ENTRY_ISO_3166(FrenchPolynesia, "French Polynesia"),
|
||||
ENTRY_ISO_3166(SolomonIslands, "Solomon Islands"),
|
||||
ENTRY_ISO_3166(Guam, "Guam"),
|
||||
ENTRY_ISO_3166(UnitedStatesMinorOutlyingIslands, "United States Minor Outlying Islands"),
|
||||
ENTRY_ISO_3166(MarshallIslands, "Marshall Islands"),
|
||||
ENTRY_ISO_3166(NauruCountry, "Nauru"),
|
||||
ENTRY_ISO_3166(Niue, "Niue"),
|
||||
ENTRY_ISO_3166(NorfolkIsland, "Norfolk Island"),
|
||||
ENTRY_ISO_3166(NewCaledonia, "New Caledonia"),
|
||||
ENTRY_ISO_3166(AmericanSamoa, "American Samoa"),
|
||||
ENTRY_ISO_3166(Palau, "Palau"),
|
||||
ENTRY_ISO_3166(Pitcairn, "Pitcairn"),
|
||||
ENTRY_ISO_3166(PapuaNewGuinea, "Papua New Guinea"),
|
||||
ENTRY_ISO_3166(CookIslands, "Cook Islands"),
|
||||
ENTRY_ISO_3166(NorthernMarianaIslands, "Northern Mariana Islands"),
|
||||
ENTRY_ISO_3166(Tonga, "Tonga"),
|
||||
ENTRY_ISO_3166(WallisAndFutunaIslands, "Wallis and Futuna")
|
||||
// {QLocale::Default, i18nc("This is a country name associated with a particular time zone in a zone selection dialog",
|
||||
// "Default")} },
|
||||
});
|
||||
#undef ENTRY_ISO_3166
|
||||
|
||||
m_i18nContinents =
|
||||
QHash<QString, QString>({{QStringLiteral("Africa"), i18nc("This is a continent/area associated with a particular timezone", "Africa")},
|
||||
{QStringLiteral("America"), i18nc("This is a continent/area associated with a particular timezone", "America")},
|
||||
{QStringLiteral("Antarctica"), i18nc("This is a continent/area associated with a particular timezone", "Antarctica")},
|
||||
{QStringLiteral("Asia"), i18nc("This is a continent/area associated with a particular timezone", "Asia")},
|
||||
{QStringLiteral("Atlantic"), i18nc("This is a continent/area associated with a particular timezone", "Atlantic")},
|
||||
{QStringLiteral("Australia"), i18nc("This is a continent/area associated with a particular timezone", "Australia")},
|
||||
{QStringLiteral("Europe"), i18nc("This is a continent/area associated with a particular timezone", "Europe")},
|
||||
{QStringLiteral("Indian"), i18nc("This is a continent/area associated with a particular timezone", "Indian")},
|
||||
{QStringLiteral("Pacific"), i18nc("This is a continent/area associated with a particular timezone", "Pacific")}});
|
||||
|
||||
m_isInitialized = true;
|
||||
}
|
||||
34
kcms/time/timezonesi18n.h
Normal file
34
kcms/time/timezonesi18n.h
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2014 Martin Klapetek <mklapetek@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
*/
|
||||
|
||||
#ifndef TIMEZONESI18N_H
|
||||
#define TIMEZONESI18N_H
|
||||
|
||||
#include <QHash>
|
||||
#include <QLocale>
|
||||
#include <QObject>
|
||||
|
||||
class TimezonesI18n : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit TimezonesI18n(QObject *parent = nullptr);
|
||||
Q_INVOKABLE QString i18nCity(const QString &city);
|
||||
Q_INVOKABLE QString i18nContinents(const QString &continent);
|
||||
Q_INVOKABLE QString i18nCountry(QLocale::Country country);
|
||||
|
||||
private:
|
||||
void init();
|
||||
|
||||
QHash<QString, QString> m_i18nCities;
|
||||
QHash<QString, QString> m_i18nContinents;
|
||||
QHash<QLocale::Country, QString> m_i18nCountries;
|
||||
bool m_isInitialized;
|
||||
};
|
||||
|
||||
#endif // TIMEZONESI18N_H
|
||||
27
kcms/virtualkeyboard/CMakeLists.txt
Normal file
27
kcms/virtualkeyboard/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
set(MALIIT_KEYBOARD_LANGUAGES_DIR "${CMAKE_INSTALL_FULL_LIBDIR}/maliit/keyboard2/languages" CACHE PATH "Directory containing maliit-keyboard data")
|
||||
|
||||
add_definitions(-DQT_NO_KEYWORDS)
|
||||
|
||||
set(onscreenkeyboard_SRCS
|
||||
languagemodel.cpp
|
||||
gsettingsitem.cpp
|
||||
virtualkeyboard.cpp
|
||||
)
|
||||
|
||||
add_library(kcm_mobile_onscreenkeyboard MODULE ${onscreenkeyboard_SRCS})
|
||||
|
||||
target_compile_definitions(kcm_mobile_onscreenkeyboard PRIVATE "MALIIT_KEYBOARD_LANGUAGES_DIR=\"${MALIIT_KEYBOARD_LANGUAGES_DIR}\"")
|
||||
|
||||
target_link_libraries(kcm_mobile_onscreenkeyboard
|
||||
Qt::Core
|
||||
KF6::CoreAddons
|
||||
KF6::I18n
|
||||
KF6::QuickAddons
|
||||
KF6::ConfigCore
|
||||
PkgConfig::GIO
|
||||
PkgConfig::GOBJECT
|
||||
)
|
||||
|
||||
install(TARGETS kcm_mobile_onscreenkeyboard DESTINATION ${KDE_INSTALL_PLUGINDIR}/kcms)
|
||||
|
||||
kpackage_install_package(package kcm_mobile_virtualkeyboard kcms)
|
||||
1
kcms/virtualkeyboard/Messages.sh
Normal file
1
kcms/virtualkeyboard/Messages.sh
Normal file
|
|
@ -0,0 +1 @@
|
|||
$XGETTEXT $(find . -name \*.cpp -o -name \*.h -o -name \*.qml) -o $podir/kcm_mobile_virtualkeyboard.pot
|
||||
131
kcms/virtualkeyboard/gsettingsitem.cpp
Normal file
131
kcms/virtualkeyboard/gsettingsitem.cpp
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2018 Nicolas Fella <nicolas.fella@gmx.de>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only
|
||||
|
||||
*/
|
||||
|
||||
#include <QDebug>
|
||||
#include <QString>
|
||||
|
||||
#include "gsettingsitem.h"
|
||||
|
||||
QVariant GSettingsItem::value(const QString &key) const
|
||||
{
|
||||
if (!m_settings) {
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
GVariant *gvalue = g_settings_get_value(m_settings, key.toLatin1().data());
|
||||
|
||||
QVariant toReturn;
|
||||
|
||||
switch (g_variant_classify(gvalue)) {
|
||||
case G_VARIANT_CLASS_BOOLEAN:
|
||||
toReturn = QVariant(static_cast<bool>(g_variant_get_boolean(gvalue)));
|
||||
break;
|
||||
case G_VARIANT_CLASS_STRING:
|
||||
toReturn = QVariant(QString::fromUtf8(g_variant_get_string(gvalue, nullptr)));
|
||||
break;
|
||||
case G_VARIANT_CLASS_ARRAY:
|
||||
if (g_variant_is_of_type(gvalue, G_VARIANT_TYPE_STRING_ARRAY)) {
|
||||
GVariantIter iter;
|
||||
QStringList list;
|
||||
const gchar *str;
|
||||
g_variant_iter_init(&iter, gvalue);
|
||||
while (g_variant_iter_next(&iter, "&s", &str)) {
|
||||
list.append(str);
|
||||
}
|
||||
return QVariant(list);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
qWarning() << "Unhandled variant type in value()";
|
||||
}
|
||||
|
||||
g_variant_unref(gvalue);
|
||||
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
void GSettingsItem::set(const QString &key, const QVariant &val)
|
||||
{
|
||||
if (!m_settings) {
|
||||
return;
|
||||
}
|
||||
|
||||
// It might be hard to detect the right GVariant type from
|
||||
// complex QVariant types such as string lists or more detailed
|
||||
// types such as integers (GVariant has different sizes),
|
||||
// therefore we get the current value for the key and convert
|
||||
// to QVariant using the GVariant type
|
||||
GVariant *oldValue = g_settings_get_value(m_settings, key.toLatin1().data());
|
||||
GVariant *newValue = nullptr;
|
||||
|
||||
switch (g_variant_type_peek_string(g_variant_get_type(oldValue))[0]) {
|
||||
case G_VARIANT_CLASS_BOOLEAN:
|
||||
newValue = g_variant_new_boolean(val.toBool());
|
||||
break;
|
||||
case G_VARIANT_CLASS_STRING:
|
||||
newValue = g_variant_new_string(val.toString().toUtf8().constData());
|
||||
break;
|
||||
case G_VARIANT_CLASS_ARRAY:
|
||||
if (g_variant_is_of_type(oldValue, G_VARIANT_TYPE_STRING_ARRAY)) {
|
||||
const QStringList list = val.toStringList();
|
||||
GVariantBuilder builder;
|
||||
g_variant_builder_init(&builder, G_VARIANT_TYPE_STRING_ARRAY);
|
||||
for (const QString &string : list) {
|
||||
g_variant_builder_add(&builder, "s", string.toUtf8().constData());
|
||||
}
|
||||
|
||||
newValue = g_variant_builder_end(&builder);
|
||||
break;
|
||||
}
|
||||
qWarning() << "Unhandled variant array type in set()";
|
||||
break;
|
||||
default:
|
||||
qWarning() << "Unhandled variant type in set()";
|
||||
}
|
||||
|
||||
if (newValue) {
|
||||
g_settings_set_value(m_settings, key.toLatin1().data(), newValue);
|
||||
}
|
||||
|
||||
g_variant_unref(oldValue);
|
||||
}
|
||||
|
||||
bool GSettingsItem::isValid() const
|
||||
{
|
||||
return m_settings;
|
||||
}
|
||||
|
||||
GSettingsItem::GSettingsItem(const QString &key, QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
const char schemaId[] = "org.maliit.keyboard.maliit";
|
||||
|
||||
// g_settings_new_with_path asserts if the schema doesn't exist, check this manually to avoid an abort.
|
||||
auto *defaultSource = g_settings_schema_source_get_default();
|
||||
if (!defaultSource) {
|
||||
qWarning() << "No GSettings schemas are installed on the system";
|
||||
return;
|
||||
}
|
||||
|
||||
auto *schema = g_settings_schema_source_lookup(defaultSource, schemaId, true /*recursive*/);
|
||||
if (!schema) {
|
||||
qWarning() << "Settings schema" << schemaId << "is not installed";
|
||||
return;
|
||||
}
|
||||
|
||||
m_settings = g_settings_new_with_path(schemaId, key.toLatin1().data());
|
||||
g_settings_schema_unref(schema);
|
||||
|
||||
g_signal_connect(m_settings, "changed", G_CALLBACK(GSettingsItem::settingChanged), this);
|
||||
}
|
||||
|
||||
GSettingsItem::~GSettingsItem()
|
||||
{
|
||||
g_settings_sync();
|
||||
if (m_settings)
|
||||
g_object_unref(m_settings);
|
||||
}
|
||||
46
kcms/virtualkeyboard/gsettingsitem.h
Normal file
46
kcms/virtualkeyboard/gsettingsitem.h
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2018 Nicolas Fella <nicolas.fella@gmx.de>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only
|
||||
|
||||
*/
|
||||
|
||||
#ifndef GSETTINGSITEM_H
|
||||
#define GSETTINGSITEM_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QStringList>
|
||||
#include <QVariant>
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
class GSettingsItem : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit GSettingsItem(const QString &key, QObject *parent = nullptr);
|
||||
virtual ~GSettingsItem() override;
|
||||
|
||||
QVariant value(const QString &key) const;
|
||||
void set(const QString &key, const QVariant &val);
|
||||
|
||||
bool isValid() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void subtreeChanged();
|
||||
|
||||
private:
|
||||
GSettings *m_settings = nullptr;
|
||||
|
||||
static void settingChanged(GSettings *settings, const gchar *key, gpointer data)
|
||||
{
|
||||
Q_UNUSED(settings)
|
||||
Q_UNUSED(key)
|
||||
|
||||
GSettingsItem *self = static_cast<GSettingsItem *>(data);
|
||||
Q_EMIT self->subtreeChanged();
|
||||
}
|
||||
};
|
||||
|
||||
#endif // GCONFITEM_H
|
||||
104
kcms/virtualkeyboard/languagemodel.cpp
Normal file
104
kcms/virtualkeyboard/languagemodel.cpp
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2020 Bhushan Shah <bshah@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
*/
|
||||
|
||||
#include <QDebug>
|
||||
#include <QDirIterator>
|
||||
#include <QPluginLoader>
|
||||
|
||||
#include "gsettingsitem.h"
|
||||
#include "languagemodel.h"
|
||||
|
||||
LanguageModel::LanguageModel(QObject *parent, GSettingsItem *settings)
|
||||
: QAbstractListModel(parent)
|
||||
, m_gsettings(settings)
|
||||
{
|
||||
beginResetModel();
|
||||
loadPlugins();
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void LanguageModel::loadPlugins()
|
||||
{
|
||||
const QStringList enabledLangs = m_gsettings->value("enabled-languages").toStringList();
|
||||
|
||||
QStringList langPaths;
|
||||
QDirIterator it(QStringLiteral(MALIIT_KEYBOARD_LANGUAGES_DIR), {"*plugin.so"}, QDir::NoFilter, QDirIterator::Subdirectories);
|
||||
while (it.hasNext()) {
|
||||
langPaths << it.next();
|
||||
}
|
||||
m_languages.clear();
|
||||
for (const auto &langPath : qAsConst(langPaths)) {
|
||||
QPluginLoader langPlugin(langPath);
|
||||
const auto &metadata = langPlugin.metaData().value("MetaData").toObject();
|
||||
Data lang;
|
||||
lang.langName = metadata.value("Language").toString();
|
||||
lang.langCode = metadata.value("LanguageId").toString();
|
||||
lang.enabled = enabledLangs.contains(lang.langCode);
|
||||
m_languages.append(lang);
|
||||
}
|
||||
}
|
||||
|
||||
QVariant LanguageModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid()) {
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
if (index.row() >= m_languages.size()) {
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
const Data data = m_languages.at(index.row());
|
||||
switch (role) {
|
||||
case EnabledRole:
|
||||
return data.enabled;
|
||||
case NameRole:
|
||||
return data.langName;
|
||||
case LanguageIdRole:
|
||||
return data.langCode;
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
bool LanguageModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
||||
{
|
||||
if (!index.isValid()) {
|
||||
return QAbstractListModel::setData(index, value, role);
|
||||
}
|
||||
|
||||
if (role == EnabledRole) {
|
||||
Data &data = m_languages[index.row()];
|
||||
if (data.enabled != value.toBool()) {
|
||||
data.enabled = value.toBool();
|
||||
}
|
||||
Q_EMIT dataChanged(this->index(index.row(), 0), this->index(index.row(), 0));
|
||||
}
|
||||
|
||||
QStringList enabledLangs;
|
||||
for (const auto &data : qAsConst(m_languages)) {
|
||||
if (data.enabled) {
|
||||
enabledLangs << data.langCode;
|
||||
}
|
||||
}
|
||||
m_gsettings->set("enabled-languages", enabledLangs);
|
||||
return QAbstractListModel::setData(index, value, role);
|
||||
}
|
||||
|
||||
int LanguageModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(parent)
|
||||
return m_languages.size();
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> LanguageModel::roleNames() const
|
||||
{
|
||||
return {
|
||||
{NameRole, "name"},
|
||||
{EnabledRole, "enabled"},
|
||||
{LanguageIdRole, "langId"},
|
||||
};
|
||||
}
|
||||
43
kcms/virtualkeyboard/languagemodel.h
Normal file
43
kcms/virtualkeyboard/languagemodel.h
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2020 Bhushan Shah <bshah@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
*/
|
||||
|
||||
#ifndef LANGUAGEMODEL_H
|
||||
#define LANGUAGEMODEL_H
|
||||
|
||||
#include "gsettingsitem.h"
|
||||
#include <QAbstractListModel>
|
||||
|
||||
struct Data {
|
||||
QString langCode;
|
||||
QString langName;
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
class LanguageModel : public QAbstractListModel
|
||||
{
|
||||
enum ModelRoles {
|
||||
NameRole = Qt::DisplayRole,
|
||||
EnabledRole = Qt::UserRole + 1,
|
||||
LanguageIdRole,
|
||||
};
|
||||
|
||||
Q_OBJECT
|
||||
public:
|
||||
LanguageModel(QObject *parent, GSettingsItem *gsettingsItem);
|
||||
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
|
||||
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
private:
|
||||
QVector<Data> m_languages;
|
||||
void loadPlugins();
|
||||
GSettingsItem *m_gsettings;
|
||||
};
|
||||
|
||||
#endif
|
||||
153
kcms/virtualkeyboard/metadata.json
Normal file
153
kcms/virtualkeyboard/metadata.json
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
{
|
||||
"KPlugin": {
|
||||
"Authors": [
|
||||
{
|
||||
"Name": "Bhushan Shah",
|
||||
"Name[az]": "Bhushan Shah",
|
||||
"Name[ca@valencia]": "Bhushan Shah",
|
||||
"Name[ca]": "Bhushan Shah",
|
||||
"Name[cs]": "Bhushan Shah",
|
||||
"Name[de]": "Bhushan Shah",
|
||||
"Name[en_GB]": "Bhushan Shah",
|
||||
"Name[es]": "Bhushan Shah",
|
||||
"Name[eu]": "Bhushan Shah",
|
||||
"Name[fi]": "Bhushan Shah",
|
||||
"Name[fr]": "Bhushan Shah",
|
||||
"Name[hu]": "Bhushan Shah",
|
||||
"Name[ia]": "Bhushan Shah",
|
||||
"Name[id]": "Bhushan Shah",
|
||||
"Name[is]": "Bhushan Shah",
|
||||
"Name[it]": "Bhushan Shah",
|
||||
"Name[ka]": "Bhushan Shah",
|
||||
"Name[ko]": "Bhushan Shah",
|
||||
"Name[lt]": "Bhushan Shah",
|
||||
"Name[nl]": "Bhushan Shah",
|
||||
"Name[nn]": "Bhushan Shah",
|
||||
"Name[pa]": "ਭੂਸ਼ਨ ਸ਼ਾਹ",
|
||||
"Name[pl]": "Bhushan Shah",
|
||||
"Name[pt]": "Bhushan Shah",
|
||||
"Name[pt_BR]": "Bhushan Shah",
|
||||
"Name[ro]": "Bhushan Shah",
|
||||
"Name[ru]": "Bhushan Shah",
|
||||
"Name[sl]": "Bhushan Shah",
|
||||
"Name[sv]": "Bhushan Shah",
|
||||
"Name[tr]": "Buşan Şah",
|
||||
"Name[uk]": "Bhushan Shah",
|
||||
"Name[vi]": "Bhushan Shah",
|
||||
"Name[x-test]": "xxBhushan Shahxx",
|
||||
"Name[zh_CN]": "Bhushan Shah",
|
||||
"Name[zh_TW]": "Bhushan Shah"
|
||||
}
|
||||
],
|
||||
"Description": "On-Screen Keyboard configuration",
|
||||
"Description[az]": "Ekran klaviaturası tənzimləməsi",
|
||||
"Description[ca@valencia]": "Configureu el teclat en pantalla",
|
||||
"Description[ca]": "Configuració del teclat en pantalla",
|
||||
"Description[cs]": "Nastavení klávesnice na obrazovce",
|
||||
"Description[de]": "Einrichtung der Bildschirmtastatur",
|
||||
"Description[en_GB]": "On-Screen Keyboard configuration",
|
||||
"Description[es]": "Configuración del teclado en pantalla",
|
||||
"Description[eu]": "Pantailako teklatua konfiguratzea",
|
||||
"Description[fi]": "Näyttönäppäimistön asetukset",
|
||||
"Description[fr]": "Configuration du clavier virtuel",
|
||||
"Description[hu]": "Képernyő-billentyűzet beállítása",
|
||||
"Description[ia]": "Configuration de Claviero sur le schermo",
|
||||
"Description[id]": "Konfigurasi On-Screen Keyboard",
|
||||
"Description[is]": "Grunnstillingar skjályklaborðs",
|
||||
"Description[it]": "Configurazione della tastiera su schermo",
|
||||
"Description[ka]": "კლავიატურის კრანზე მორგება",
|
||||
"Description[ko]": "가상 키보드 설정",
|
||||
"Description[lt]": "Ekraninės klaviatūros konfigūracija",
|
||||
"Description[nl]": "Configuratie van toetsenbord op het scherm",
|
||||
"Description[nn]": "Oppsett av skjermtastatur",
|
||||
"Description[pa]": "ਆਨ-ਸਕਰੀਨ ਕੀਬੋਰਡ ਦੀ ਸੰਰਚਨਾ",
|
||||
"Description[pl]": "Ustawienia klawiatury ekranowej",
|
||||
"Description[pt]": "Configuração do Teclado Virtual",
|
||||
"Description[pt_BR]": "Configuração do teclado virtual",
|
||||
"Description[ro]": "Configurarea tastaturii pe ecran",
|
||||
"Description[ru]": "Настройка экранной клавиатуры",
|
||||
"Description[sl]": "Nastavitev tipkovnice na zaslonu",
|
||||
"Description[sv]": "Inställning av skärmtangentbord",
|
||||
"Description[tr]": "Ekran Klavyesi yapılandırması",
|
||||
"Description[uk]": "Налаштування екранної клавіатури",
|
||||
"Description[vi]": "Cấu hình bàn phím trên màn hình",
|
||||
"Description[x-test]": "xxOn-Screen Keyboard configurationxx",
|
||||
"Description[zh_CN]": "屏幕键盘配置",
|
||||
"Description[zh_TW]": "螢幕上的虛擬鍵盤設定",
|
||||
"FormFactors": [
|
||||
"handset",
|
||||
"tablet"
|
||||
],
|
||||
"Icon": "input-keyboard",
|
||||
"License": "GPL",
|
||||
"Name": "On-Screen Keyboard",
|
||||
"Name[az]": "Ekran klaviaturası",
|
||||
"Name[ca@valencia]": "Teclat en pantalla",
|
||||
"Name[ca]": "Teclat en pantalla",
|
||||
"Name[cs]": "Klávesnice na obrazovce",
|
||||
"Name[de]": "Bildschirmtastatur",
|
||||
"Name[en_GB]": "On-Screen Keyboard",
|
||||
"Name[es]": "Teclado en pantalla",
|
||||
"Name[eu]": "Pantailako teklatua",
|
||||
"Name[fi]": "Näyttönäppäimistö",
|
||||
"Name[fr]": "Clavier virtuel",
|
||||
"Name[hu]": "Képernyő-billentyűzet",
|
||||
"Name[ia]": "Claviero sur schermo",
|
||||
"Name[id]": "On-Screen Keyboard",
|
||||
"Name[is]": "Skjályklaborð",
|
||||
"Name[it]": "Tastiera su schermo",
|
||||
"Name[ka]": "ეკრანის კლავიატურა",
|
||||
"Name[ko]": "가상 키보드",
|
||||
"Name[lt]": "Ekraninė klaviatūra",
|
||||
"Name[nl]": "Toetsenbord op scherm",
|
||||
"Name[nn]": "Skjermtastatur",
|
||||
"Name[pa]": "ਆਨ-ਸਕਰੀਨ ਕੀਬੋਰਡ",
|
||||
"Name[pl]": "Klawiatura ekranowa",
|
||||
"Name[pt]": "Teclado no Ecrã",
|
||||
"Name[pt_BR]": "Teclado virtual",
|
||||
"Name[ro]": "Tastatură pe ecran",
|
||||
"Name[ru]": "Экранная клавиатура",
|
||||
"Name[sl]": "Tipkovnica na zaslonu",
|
||||
"Name[sv]": "Tangentbord på skärmen",
|
||||
"Name[tr]": "Ekran Klavyesi",
|
||||
"Name[uk]": "Екранна клавіатура",
|
||||
"Name[vi]": "Bàn phím trên màn hình",
|
||||
"Name[x-test]": "xxOn-Screen Keyboardxx",
|
||||
"Name[zh_CN]": "屏幕键盘",
|
||||
"Name[zh_TW]": "螢幕上的虛擬鍵盤",
|
||||
"Version": "1.0",
|
||||
"Website": "https://plasma-mobile.org"
|
||||
},
|
||||
"X-KDE-Keywords": "onscreen,osk,virtualkeyboard,keyboard",
|
||||
"X-KDE-Keywords[az]": "virtualkeyboard,keyboard,virtual klaviatura",
|
||||
"X-KDE-Keywords[ca@valencia]": "teclat virtual,teclat",
|
||||
"X-KDE-Keywords[ca]": "teclat virtual,teclat",
|
||||
"X-KDE-Keywords[cs]": "virtuální klávesnice, klávesnice",
|
||||
"X-KDE-Keywords[de]": "Virtuelle Tastatur,Tastatur",
|
||||
"X-KDE-Keywords[en_GB]": "virtualkeyboard,keyboard",
|
||||
"X-KDE-Keywords[es]": "tecladovirtual,teclado",
|
||||
"X-KDE-Keywords[eu]": "alegiazko teklatua,teklatua",
|
||||
"X-KDE-Keywords[fi]": "näyttönäppäimistö,virtuaalinäppäimistö,näppäimistö",
|
||||
"X-KDE-Keywords[fr]": "clavier virtuel, clavier",
|
||||
"X-KDE-Keywords[hu]": "virtuális billentyűzet,billentyűzet",
|
||||
"X-KDE-Keywords[ia]": "virtualkeyboard,keyboard",
|
||||
"X-KDE-Keywords[it]": "tastieravirtuale,tastiera",
|
||||
"X-KDE-Keywords[ko]": "virtualkeyboard,keyboard,키보드,가상 키보드",
|
||||
"X-KDE-Keywords[lt]": "virtualiklaviatūra,virtualiklaviatura,virtuali klaviatūra,virtuali klaviatura,klaviatūra,klaviatura",
|
||||
"X-KDE-Keywords[nl]": "virtueeltoetsenbord,toetsenbord",
|
||||
"X-KDE-Keywords[nn]": "virtuelt tastatur,tastatur",
|
||||
"X-KDE-Keywords[pa]": "ਫ਼ਰਜ਼ੀ ਕੀਬੋਰਡ,ਵਰਚੁਅਲ ਕੀਬੋਰਡ,ਖਾਕਾ,ਕੀਬੋਰਡ",
|
||||
"X-KDE-Keywords[pl]": "klawiatura ekranowa,klawiatura",
|
||||
"X-KDE-Keywords[pt]": "teclado virtual,teclado",
|
||||
"X-KDE-Keywords[pt_BR]": "teclado virtual,teclado",
|
||||
"X-KDE-Keywords[ro]": "tastatură virtuală,tastatură",
|
||||
"X-KDE-Keywords[ru]": "virtualkeyboard,keyboard,клавиатура,виртуальная клавиатура",
|
||||
"X-KDE-Keywords[sk]": "virtuálna klávesnica, klávesnica",
|
||||
"X-KDE-Keywords[sl]": "navidezna tipkovnica,tipkovnica",
|
||||
"X-KDE-Keywords[sv]": "virtuellt tangentbord,tangentbord",
|
||||
"X-KDE-Keywords[ta]": "virtualkeyboard, keyboard, மெய்நிகர் விசைப்பலகை, விசைப்பலகை, திரையில் விசைப்பலகை, திரை விசைப்பலகை, திரைவிசைப்பலகை",
|
||||
"X-KDE-Keywords[uk]": "virtualkeyboard,keyboard,екранна,віртуальна,клавіатура,клавіші",
|
||||
"X-KDE-Keywords[vi]": "virtualkeyboard,keyboard,bàn phím ảo,bàn phím",
|
||||
"X-KDE-Keywords[x-test]": "xxvirtualkeyboardxx,xxkeyboardxx",
|
||||
"X-KDE-Keywords[zh_CN]": "virtualkeyboard,keyboard,虚拟键盘,键盘"
|
||||
}
|
||||
52
kcms/virtualkeyboard/package/contents/ui/languages.qml
Normal file
52
kcms/virtualkeyboard/package/contents/ui/languages.qml
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2020 Bhushan Shah <bshah@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
import QtQuick 2.7
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtQuick.Controls 2.11 as QQC2
|
||||
|
||||
import org.kde.kirigami 2.10 as Kirigami
|
||||
import org.kde.kcm 1.3 as KCM
|
||||
import org.kde.kitemmodels 1.0 as KItemModel
|
||||
|
||||
import org.kde.kcm.virtualkeyboard 1.0
|
||||
|
||||
KCM.ScrollViewKCM {
|
||||
id: root
|
||||
|
||||
title: i18n("Languages")
|
||||
|
||||
view: ListView {
|
||||
id: languageList
|
||||
|
||||
clip: true
|
||||
|
||||
model: KItemModel.KSortFilterProxyModel {
|
||||
sourceModel: kcm.languageModel
|
||||
sortRole: "name"
|
||||
sortOrder: Qt.Ascending
|
||||
}
|
||||
|
||||
delegate: Kirigami.AbstractListItem {
|
||||
QQC2.CheckBox {
|
||||
text: model.name
|
||||
checked: model.enabled
|
||||
onCheckedChanged: {
|
||||
model.enabled = checked
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
footer: RowLayout {
|
||||
QQC2.Button {
|
||||
text: i18n("Apply")
|
||||
icon.name: "dialog-ok"
|
||||
onClicked: kcm.pop()
|
||||
Layout.alignment: Qt.AlignRight
|
||||
}
|
||||
}
|
||||
}
|
||||
150
kcms/virtualkeyboard/package/contents/ui/main.qml
Normal file
150
kcms/virtualkeyboard/package/contents/ui/main.qml
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2020 Bhushan Shah <bshah@kde.org>
|
||||
SPDX-FileCopyrightText: 2021 Devin Lin <devin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
import QtQuick 2.7
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtQuick.Controls 2.11 as QQC2
|
||||
|
||||
import org.kde.kirigami 2.19 as Kirigami
|
||||
import org.kde.kcm 1.3 as KCM
|
||||
import org.kde.kitemmodels 1.0 as KItemModel
|
||||
import org.kde.kirigamiaddons.labs.mobileform 0.1 as MobileForm
|
||||
|
||||
KCM.SimpleKCM {
|
||||
id: root
|
||||
|
||||
title: i18n("On-Screen Keyboard")
|
||||
|
||||
leftPadding: 0
|
||||
rightPadding: 0
|
||||
topPadding: Kirigami.Units.gridUnit
|
||||
bottomPadding: Kirigami.Units.gridUnit
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 0
|
||||
width: parent.width
|
||||
|
||||
MobileForm.FormCard {
|
||||
Layout.fillWidth: true
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
spacing: 0
|
||||
|
||||
MobileForm.AbstractFormDelegate {
|
||||
Layout.fillWidth: true
|
||||
background: Item {}
|
||||
contentItem: RowLayout {
|
||||
QQC2.TextField {
|
||||
Layout.fillWidth: true
|
||||
placeholderText: i18n("Type anything here…")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MobileForm.FormCard {
|
||||
Layout.topMargin: Kirigami.Units.largeSpacing
|
||||
Layout.fillWidth: true
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
spacing: 0
|
||||
|
||||
MobileForm.FormCardHeader {
|
||||
title: "Feedback"
|
||||
}
|
||||
|
||||
MobileForm.FormSwitchDelegate {
|
||||
id: firstFeedbackCheckBox
|
||||
text: i18n("Sound")
|
||||
description: i18n("Whether to emit a sound on keypress.")
|
||||
checked: kcm.soundFeedback
|
||||
onCheckedChanged: kcm.soundFeedback = checked;
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator { above: firstFeedbackCheckBox; below: secondFeedbackCheckBox }
|
||||
|
||||
MobileForm.FormSwitchDelegate {
|
||||
id: secondFeedbackCheckBox
|
||||
text: i18n("Vibration")
|
||||
description: i18n("Whether to vibrate on keypress.")
|
||||
checked: kcm.vibrateFeedback
|
||||
onCheckedChanged: kcm.vibrateFeedback = checked;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MobileForm.FormCard {
|
||||
Layout.topMargin: Kirigami.Units.largeSpacing
|
||||
Layout.fillWidth: true
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
spacing: 0
|
||||
|
||||
MobileForm.FormCardHeader {
|
||||
title: "Text Correction"
|
||||
}
|
||||
|
||||
MobileForm.FormCheckDelegate {
|
||||
id: firstTextCorrectionCheckBox
|
||||
text: i18n("Check spelling of entered text")
|
||||
checked: kcm.spellCheck
|
||||
onCheckedChanged: kcm.spellCheck = checked;
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator { above: firstTextCorrectionCheckBox; below: capitalizeCheck }
|
||||
|
||||
MobileForm.FormCheckDelegate {
|
||||
id: capitalizeCheck
|
||||
text: i18n("Capitalize the first letter of each sentence")
|
||||
checked: kcm.autoCapitalize
|
||||
onCheckedChanged: kcm.autoCapitalize = checked;
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator { above: capitalizeCheck; below: wordCompletionCheck }
|
||||
|
||||
MobileForm.FormCheckDelegate {
|
||||
id: wordCompletionCheck
|
||||
text: i18n("Complete current word with first suggestion when hitting space")
|
||||
checked: kcm.autoCompleteOnSpace
|
||||
onCheckedChanged: kcm.autoCompleteOnSpace = checked;
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator { above: wordCompletionCheck; below: wordSuggestionCheck }
|
||||
|
||||
MobileForm.FormCheckDelegate {
|
||||
id: wordSuggestionCheck
|
||||
text: i18n("Suggest potential words in word ribbon")
|
||||
checked: kcm.showSuggestions
|
||||
onCheckedChanged: {
|
||||
kcm.showSuggestions = checked;
|
||||
}
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator { above: wordSuggestionCheck; below: fullStopCheck }
|
||||
|
||||
MobileForm.FormCheckDelegate {
|
||||
id: fullStopCheck
|
||||
text: i18n("Insert a full-stop when space is pressed twice")
|
||||
checked: kcm.fullStopOnDoubleSpace
|
||||
onCheckedChanged: {
|
||||
kcm.fullStopOnDoubleSpace = checked;
|
||||
}
|
||||
}
|
||||
|
||||
MobileForm.FormDelegateSeparator { above: fullStopCheck; below: languageButton }
|
||||
|
||||
MobileForm.FormButtonDelegate {
|
||||
id: languageButton
|
||||
text: i18n("Configure Languages")
|
||||
icon.name: "set-language"
|
||||
onClicked: kcm.push("languages.qml")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
57
kcms/virtualkeyboard/virtualkeyboard.cpp
Normal file
57
kcms/virtualkeyboard/virtualkeyboard.cpp
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2020 Bhushan Shah <bshah@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
*/
|
||||
|
||||
#include "virtualkeyboard.h"
|
||||
#include <KLocalizedString>
|
||||
#include <KPluginFactory>
|
||||
|
||||
#include <QDir>
|
||||
|
||||
#include "languagemodel.h"
|
||||
|
||||
// clang-format off
|
||||
|
||||
#define SETTER(setter, member, gsetting, signal) \
|
||||
void VirtualKeyboard::setter(bool enabled) \
|
||||
{ \
|
||||
if (member != enabled) {\
|
||||
member = enabled; \
|
||||
m_gsettings->set(gsetting, enabled); \
|
||||
Q_EMIT signal();\
|
||||
}\
|
||||
}
|
||||
|
||||
// clang-format on
|
||||
|
||||
K_PLUGIN_CLASS_WITH_JSON(VirtualKeyboard, "metadata.json")
|
||||
|
||||
VirtualKeyboard::VirtualKeyboard(QObject *parent, const KPluginMetaData &metaData, const QVariantList &args)
|
||||
: KQuickAddons::ConfigModule(parent, metaData, args)
|
||||
, m_gsettings(new GSettingsItem("/org/maliit/keyboard/maliit/", parent))
|
||||
, m_langModel(new LanguageModel(this, m_gsettings))
|
||||
{
|
||||
qmlRegisterAnonymousType<LanguageModel>("org.kde.kcm.virtualkeyboard", 1);
|
||||
|
||||
m_autoCapitalize = m_gsettings->value("auto-capitalization").toBool();
|
||||
m_autoCompleteOnSpace = m_gsettings->value("auto-completion").toBool();
|
||||
m_showSuggestions = m_gsettings->value("predictive-text").toBool();
|
||||
m_fullStopOnDoubleSpace = m_gsettings->value("double-space-full-stop").toBool();
|
||||
m_spellCheck = m_gsettings->value("spell-checking").toBool();
|
||||
|
||||
m_soundFeedback = m_gsettings->value("key-press-feedback").toBool();
|
||||
m_vibrateFeedback = m_gsettings->value("key-press-haptic-feedback").toBool();
|
||||
}
|
||||
|
||||
SETTER(setAutoCapitalize, m_autoCapitalize, "auto-capitalization", autoCapitalizeChanged)
|
||||
SETTER(setAutoCompleteOnSpace, m_autoCompleteOnSpace, "auto-completion", autoCompleteOnSpaceChanged);
|
||||
SETTER(setShowSuggestions, m_showSuggestions, "predictive-text", showSuggestionsChanged)
|
||||
SETTER(setFullStopOnDoubleSpace, m_fullStopOnDoubleSpace, "double-space-full-stop", fullStopOnDoubleSpaceChanged)
|
||||
SETTER(setSpellCheck, m_spellCheck, "spell-checking", spellCheckChanged)
|
||||
|
||||
SETTER(setSoundFeedback, m_soundFeedback, "key-press-feedback", soundFeedbackChanged)
|
||||
SETTER(setVibrateFeedback, m_vibrateFeedback, "key-press-haptic-feedback", vibrateFeedbackChanged)
|
||||
|
||||
#include "virtualkeyboard.moc"
|
||||
67
kcms/virtualkeyboard/virtualkeyboard.h
Normal file
67
kcms/virtualkeyboard/virtualkeyboard.h
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2020 Bhushan Shah <bshah@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
*/
|
||||
|
||||
#include "languagemodel.h"
|
||||
#include <KQuickAddons/ConfigModule>
|
||||
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
|
||||
#ifndef VIRTUALKEYBOARD_H
|
||||
#define VIRTUALKEYBOARD_H
|
||||
|
||||
class VirtualKeyboard : public KQuickAddons::ConfigModule
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(LanguageModel *languageModel MEMBER m_langModel CONSTANT)
|
||||
|
||||
Q_PROPERTY(bool spellCheck MEMBER m_spellCheck WRITE setSpellCheck NOTIFY spellCheckChanged)
|
||||
Q_PROPERTY(bool autoCapitalize MEMBER m_autoCapitalize WRITE setAutoCapitalize NOTIFY autoCapitalizeChanged)
|
||||
Q_PROPERTY(bool autoCompleteOnSpace MEMBER m_autoCompleteOnSpace WRITE setAutoCompleteOnSpace NOTIFY autoCompleteOnSpaceChanged)
|
||||
Q_PROPERTY(bool showSuggestions MEMBER m_showSuggestions WRITE setShowSuggestions NOTIFY showSuggestionsChanged)
|
||||
Q_PROPERTY(bool fullStopOnDoubleSpace MEMBER m_fullStopOnDoubleSpace WRITE setFullStopOnDoubleSpace NOTIFY fullStopOnDoubleSpaceChanged)
|
||||
|
||||
Q_PROPERTY(bool soundFeedback MEMBER m_soundFeedback WRITE setSoundFeedback NOTIFY soundFeedbackChanged)
|
||||
Q_PROPERTY(bool vibrateFeedback MEMBER m_vibrateFeedback WRITE setVibrateFeedback NOTIFY vibrateFeedbackChanged)
|
||||
|
||||
public:
|
||||
VirtualKeyboard(QObject *parent, const KPluginMetaData &metaData, const QVariantList &args);
|
||||
|
||||
void setSpellCheck(bool enabled);
|
||||
void setAutoCapitalize(bool enabled);
|
||||
void setAutoCompleteOnSpace(bool enabled);
|
||||
void setShowSuggestions(bool enabled);
|
||||
void setFullStopOnDoubleSpace(bool enabled);
|
||||
|
||||
void setSoundFeedback(bool enabled);
|
||||
void setVibrateFeedback(bool enabled);
|
||||
|
||||
Q_SIGNALS:
|
||||
void spellCheckChanged();
|
||||
void autoCapitalizeChanged();
|
||||
void autoCompleteOnSpaceChanged();
|
||||
void showSuggestionsChanged();
|
||||
void fullStopOnDoubleSpaceChanged();
|
||||
void soundFeedbackChanged();
|
||||
void vibrateFeedbackChanged();
|
||||
|
||||
private:
|
||||
GSettingsItem *m_gsettings;
|
||||
LanguageModel *m_langModel;
|
||||
|
||||
// spell check
|
||||
bool m_spellCheck;
|
||||
bool m_autoCapitalize;
|
||||
bool m_autoCompleteOnSpace;
|
||||
bool m_showSuggestions;
|
||||
bool m_fullStopOnDoubleSpace;
|
||||
|
||||
// feedback
|
||||
bool m_soundFeedback;
|
||||
bool m_vibrateFeedback;
|
||||
};
|
||||
|
||||
#endif
|
||||
Loading…
Reference in a new issue