File indexing completed on 2024-05-05 05:36:41

0001 /*
0002 
0003     SPDX-FileCopyrightText: 2005 S.R.Haque <srhaque@iee.org>.
0004     SPDX-FileCopyrightText: 2009 David Faure <faure@kde.org>
0005     SPDX-FileCopyrightText: 2011-2015 Sebastian Kügler <sebas@kde.org>
0006     SPDX-FileCopyrightText: 2015 David Edmundson <davidedmundson@kde.org>
0007 
0008     SPDX-License-Identifier: GPL-2.0-or-later
0009 */
0010 
0011 #include "timesettings.h"
0012 #include "timezonemodel.h"
0013 
0014 #include <QDebug>
0015 #include <QtCore/QDate>
0016 
0017 #include <QDBusConnection>
0018 #include <QDBusMessage>
0019 #include <QStandardItemModel>
0020 #include <QTimer>
0021 #include <QVariant>
0022 
0023 #include <KConfigGroup>
0024 #include <KLocalizedString>
0025 #include <KPluginFactory>
0026 #include <KSharedConfig>
0027 #include <utility>
0028 
0029 #include <QCoroDBus>
0030 #include <QCoroTask>
0031 
0032 #include "timedated_interface.h"
0033 
0034 #define FORMAT24H "HH:mm:ss"
0035 #define FORMAT12H "h:mm:ss ap"
0036 
0037 K_PLUGIN_CLASS_WITH_JSON(TimeSettings, "kcm_mobile_time.json")
0038 
0039 TimeSettings::TimeSettings(QObject *parent, const KPluginMetaData &metaData)
0040     : KQuickConfigModule(parent, metaData)
0041     , m_useNtp(true)
0042 {
0043     setButtons({});
0044 
0045     qDebug() << "time settings init";
0046     m_timeZonesModel = nullptr;
0047     setTimeZone(QTimeZone::systemTimeZone().id());
0048 
0049     qmlRegisterAnonymousType<TimeZoneModel>("org.kde.timesettings", 1);
0050     qmlRegisterAnonymousType<TimeZoneFilterProxy>("org.kde.timesettings", 1);
0051 
0052     initSettings();
0053     initTimeZones();
0054     qDebug() << "TimeSettings module loaded.";
0055 }
0056 
0057 void TimeSettings::initTimeZones()
0058 {
0059     auto *filterModel = new TimeZoneFilterProxy(this);
0060     filterModel->setSourceModel(new TimeZoneModel(filterModel));
0061     setTimeZonesModel(filterModel);
0062 }
0063 
0064 void TimeSettings::initSettings()
0065 {
0066     m_localeConfig = KSharedConfig::openConfig(QStringLiteral("kdeglobals"), KConfig::SimpleConfig);
0067     m_localeSettings = KConfigGroup(m_localeConfig, "Locale");
0068 
0069     setTimeFormat(m_localeSettings.readEntry("TimeFormat", QStringLiteral(FORMAT24H))); // FIXME?!
0070 
0071     OrgFreedesktopTimedate1Interface timeDatedIface(QStringLiteral("org.freedesktop.timedate1"),
0072                                                     QStringLiteral("/org/freedesktop/timedate1"),
0073                                                     QDBusConnection::systemBus());
0074     // the server list is not relevant for timesyncd, it fetches it from the network
0075     m_useNtp = timeDatedIface.nTP();
0076 }
0077 
0078 void TimeSettings::timeout()
0079 {
0080     setCurrentTime(QTime::currentTime());
0081     setCurrentDate(QDate::currentDate());
0082     notify();
0083 }
0084 
0085 QString TimeSettings::currentTimeText()
0086 {
0087     return m_currentTimeText;
0088 }
0089 
0090 QTime TimeSettings::currentTime() const
0091 {
0092     return m_currentTime;
0093 }
0094 
0095 void TimeSettings::setCurrentTime(const QTime &currentTime)
0096 {
0097     if (m_currentTime != currentTime) {
0098         m_currentTime = currentTime;
0099         m_currentTimeText = QLocale().toString(QTime::currentTime(), m_timeFormat);
0100         emit currentTimeChanged();
0101     }
0102 }
0103 
0104 QDate TimeSettings::currentDate() const
0105 {
0106     return m_currentDate;
0107 }
0108 
0109 void TimeSettings::setCurrentDate(const QDate &currentDate)
0110 {
0111     if (m_currentDate != currentDate) {
0112         m_currentDate = currentDate;
0113         emit currentDateChanged();
0114     }
0115 }
0116 
0117 bool TimeSettings::useNtp() const
0118 {
0119     return m_useNtp;
0120 }
0121 
0122 void TimeSettings::setUseNtp(bool ntp)
0123 {
0124     if (m_useNtp != ntp) {
0125         m_useNtp = ntp;
0126         saveTime();
0127         emit useNtpChanged();
0128     }
0129 }
0130 
0131 void TimeSettings::saveTime()
0132 {
0133     auto timedateIface = std::make_shared<OrgFreedesktopTimedate1Interface>(QStringLiteral("org.freedesktop.timedate1"),
0134                                                                             QStringLiteral("/org/freedesktop/timedate1"),
0135                                                                             QDBusConnection::systemBus());
0136 
0137     // final arg in each method is "user-interaction" i.e whether it's OK for polkit to ask for auth
0138 
0139     // 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
0140     // timedated processes these in parallel and will return an error otherwise
0141 
0142     auto reply = timedateIface->SetNTP(m_useNtp, true);
0143     auto r = reply;
0144     QCoro::connect(std::move(reply), this, [=, this]() {
0145         if (r.isError()) {
0146             m_errorString = i18n("Unable to change NTP settings");
0147             emit errorStringChanged();
0148             qWarning() << "Failed to enable NTP" << r.error().name() << r.error().message();
0149         }
0150 
0151         if (!useNtp()) {
0152             QDateTime userTime;
0153             userTime.setTime(currentTime());
0154             userTime.setDate(currentDate());
0155             qDebug() << "Setting userTime: " << userTime;
0156             qint64 timeDiff = userTime.toMSecsSinceEpoch() - QDateTime::currentMSecsSinceEpoch();
0157 
0158             //*1000 for milliseconds -> microseconds
0159             auto reply = timedateIface->SetTime(timeDiff * 1000, true, true);
0160             auto r = reply;
0161             QCoro::connect(std::move(reply), this, [=, this]() {
0162                 if (r.isError()) {
0163                     m_errorString = i18n("Unable to set current time");
0164                     emit errorStringChanged();
0165                     qWarning() << "Failed to set current time" << r.error().name() << r.error().message();
0166                 }
0167             });
0168         }
0169         saveTimeZone(m_timezone);
0170     });
0171 }
0172 
0173 void TimeSettings::saveTimeZone(const QString &newtimezone)
0174 {
0175     qDebug() << "Saving timezone to config: " << newtimezone;
0176     OrgFreedesktopTimedate1Interface timedateIface(QStringLiteral("org.freedesktop.timedate1"),
0177                                                    QStringLiteral("/org/freedesktop/timedate1"),
0178                                                    QDBusConnection::systemBus());
0179 
0180     if (!newtimezone.isEmpty()) {
0181         qDebug() << "Setting timezone: " << newtimezone;
0182         auto reply = timedateIface.SetTimezone(newtimezone, true);
0183         auto r = reply;
0184         QCoro::connect(std::move(reply), this, [=, this]() {
0185             if (r.isError()) {
0186                 m_errorString = i18n("Unable to set timezone");
0187                 emit errorStringChanged();
0188                 qWarning() << "Failed to set timezone" << r.error().name() << r.error().message();
0189             } else {
0190                 setTimeZone(newtimezone);
0191                 emit timeZoneChanged();
0192                 notify();
0193             }
0194         });
0195     }
0196 }
0197 
0198 QString TimeSettings::timeFormat()
0199 {
0200     return m_timeFormat;
0201 }
0202 
0203 void TimeSettings::setTimeFormat(const QString &timeFormat)
0204 {
0205     if (m_timeFormat != timeFormat) {
0206         m_timeFormat = timeFormat;
0207 
0208         m_localeSettings.writeEntry("TimeFormat", timeFormat, KConfigGroup::Notify);
0209         m_localeConfig->sync();
0210 
0211         QDBusMessage msg =
0212             QDBusMessage::createSignal(QStringLiteral("/org/kde/kcmshell_clock"), QStringLiteral("org.kde.kcmshell_clock"), QStringLiteral("clockUpdated"));
0213         QDBusConnection::sessionBus().send(msg);
0214 
0215         qDebug() << "time format is now: " << QLocale().toString(QTime::currentTime(), m_timeFormat);
0216         emit timeFormatChanged();
0217         timeout();
0218     }
0219 }
0220 
0221 QString TimeSettings::timeZone()
0222 {
0223     return m_timezone;
0224 }
0225 
0226 void TimeSettings::setTimeZone(const QString &timezone)
0227 {
0228     if (m_timezone != timezone) {
0229         m_timezone = timezone;
0230         qDebug() << "timezone changed to: " << timezone;
0231         emit timeZoneChanged();
0232         timeout();
0233     }
0234 }
0235 
0236 TimeZoneFilterProxy *TimeSettings::timeZonesModel()
0237 {
0238     return m_timeZonesModel;
0239 }
0240 
0241 void TimeSettings::setTimeZonesModel(TimeZoneFilterProxy *timezones)
0242 {
0243     m_timeZonesModel = timezones;
0244     emit timeZonesModelChanged();
0245 }
0246 
0247 bool TimeSettings::twentyFour()
0248 {
0249     return timeFormat() == QStringLiteral(FORMAT24H);
0250 }
0251 
0252 void TimeSettings::setTwentyFour(bool t)
0253 {
0254     if (twentyFour() != t) {
0255         if (t) {
0256             setTimeFormat(FORMAT24H);
0257         } else {
0258             setTimeFormat(FORMAT12H);
0259         }
0260         qDebug() << "T24 toggled: " << t << m_timeFormat;
0261         emit twentyFourChanged();
0262         emit currentTimeChanged();
0263         timeout();
0264     }
0265 }
0266 
0267 QString TimeSettings::errorString()
0268 {
0269     return m_errorString;
0270 }
0271 
0272 void TimeSettings::notify()
0273 {
0274     const QDBusMessage msg =
0275         QDBusMessage::createSignal(QStringLiteral("/org/kde/kcmshell_clock"), QStringLiteral("org.kde.kcmshell_clock"), QStringLiteral("clockUpdated"));
0276     QDBusConnection::sessionBus().send(msg);
0277 }
0278 
0279 #include "timesettings.moc"