/* SPDX-FileCopyrightText: 2005 S.R.Haque . SPDX-FileCopyrightText: 2009 David Faure SPDX-FileCopyrightText: 2011-2015 Sebastian Kügler SPDX-FileCopyrightText: 2015 David Edmundson SPDX-License-Identifier: GPL-2.0-or-later */ #include "timesettings.h" #include "timezonemodel.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "timedated_interface.h" #define FORMAT24H "HH:mm:ss" #define FORMAT12H "h:mm:ss ap" K_PLUGIN_CLASS_WITH_JSON(TimeSettings, "kcm_mobile_time.json") TimeSettings::TimeSettings(QObject *parent, const KPluginMetaData &metaData) : KQuickConfigModule(parent, metaData) , m_useNtp(true) { setButtons({}); qDebug() << "time settings init"; m_timeZonesModel = nullptr; setTimeZone(QTimeZone::systemTimeZone().id()); qmlRegisterAnonymousType("org.kde.timesettings", 1); qmlRegisterAnonymousType("org.kde.timesettings", 1); initSettings(); initTimeZones(); qDebug() << "TimeSettings module loaded."; } 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(); } } void TimeSettings::saveTime() { auto timedateIface = std::make_shared(QStringLiteral("org.freedesktop.timedate1"), QStringLiteral("/org/freedesktop/timedate1"), QDBusConnection::systemBus()); // 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); auto r = reply; QCoro::connect(std::move(reply), this, [=, this]() { if (r.isError()) { m_errorString = i18n("Unable to change NTP settings"); emit errorStringChanged(); qWarning() << "Failed to enable NTP" << r.error().name() << r.error().message(); } 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); auto r = reply; QCoro::connect(std::move(reply), this, [=, this]() { if (r.isError()) { m_errorString = i18n("Unable to set current time"); emit errorStringChanged(); qWarning() << "Failed to set current time" << r.error().name() << r.error().message(); } }); } saveTimeZone(m_timezone); }); } 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); auto r = reply; QCoro::connect(std::move(reply), this, [=, this]() { if (r.isError()) { m_errorString = i18n("Unable to set timezone"); emit errorStringChanged(); qWarning() << "Failed to set timezone" << r.error().name() << r.error().message(); } else { 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"