File indexing completed on 2024-05-19 05:37:54
0001 /* 0002 SPDX-FileCopyrightText: 2009 Aaron Seigo <aseigo@kde.org> 0003 0004 Moon Phase: 0005 SPDX-FileCopyrightText: 1998, 2000 Stephan Kulow <coolo@kde.org> 0006 SPDX-FileCopyrightText: 2009 Davide Bettio <davide.bettio@kdemail.net> 0007 0008 Solar position: 0009 SPDX-FileCopyrightText: 2009 Petri Damsten <damu@iki.fi> 0010 0011 SPDX-License-Identifier: LGPL-2.0-or-later 0012 */ 0013 0014 #include "timesource.h" 0015 0016 #include <QDateTime> 0017 0018 #include <KLazyLocalizedString> 0019 #include <KLocalizedString> 0020 0021 #include "solarsystem.h" 0022 0023 // timezone is defined in msvc 0024 #ifdef timezone 0025 #undef timezone 0026 #endif 0027 0028 TimeSource::TimeSource(const QString &name, QObject *parent) 0029 : Plasma5Support::DataContainer(parent) 0030 , m_offset(0) 0031 , m_latitude(0) 0032 , m_longitude(0) 0033 , m_sun(nullptr) 0034 , m_moon(nullptr) 0035 , m_moonPosition(false) 0036 , m_solarPosition(false) 0037 , m_local(false) 0038 { 0039 setObjectName(name); 0040 setTimeZone(parseName(name)); 0041 } 0042 0043 void TimeSource::setTimeZone(const QString &tz) 0044 { 0045 m_tzName = tz; 0046 m_local = m_tzName == kli18n("Local").untranslatedText(); 0047 if (m_local) { 0048 m_tzName = QString::fromUtf8(QTimeZone::systemTimeZoneId()); 0049 } 0050 0051 if (m_local) { 0052 m_tz = QTimeZone(QTimeZone::systemTimeZoneId()); 0053 } else { 0054 m_tz = QTimeZone(m_tzName.toUtf8()); 0055 if (!m_tz.isValid()) { 0056 m_tz = QTimeZone(QTimeZone::systemTimeZoneId()); 0057 } 0058 } 0059 0060 const QString trTimezone = i18n(m_tzName.toUtf8()); 0061 setData(kli18n("Timezone").untranslatedText(), trTimezone); 0062 0063 const QStringList tzParts = trTimezone.split('/', Qt::SkipEmptyParts); 0064 if (tzParts.count() == 1) { 0065 // no '/' so just set it as the city 0066 setData(kli18n("Timezone City").untranslatedText(), trTimezone); 0067 } else if (tzParts.count() == 2) { 0068 setData(kli18n("Timezone Continent").untranslatedText(), tzParts.value(0)); 0069 setData(kli18n("Timezone City").untranslatedText(), tzParts.value(1)); 0070 } else { // for zones like America/Argentina/Buenos_Aires 0071 setData(kli18n("Timezone Continent").untranslatedText(), tzParts.value(0)); 0072 setData(kli18n("Timezone Country").untranslatedText(), tzParts.value(1)); 0073 setData(kli18n("Timezone City").untranslatedText(), tzParts.value(2)); 0074 } 0075 0076 updateTime(); 0077 } 0078 0079 TimeSource::~TimeSource() 0080 { 0081 // First delete the moon, that does not delete the Sun, and then the Sun 0082 // If the Sun is deleted before the moon, the moon has a invalid pointer 0083 // to where the Sun was pointing. 0084 delete m_moon; 0085 delete m_sun; 0086 } 0087 0088 void TimeSource::updateTime() 0089 { 0090 QDateTime timeZoneDateTime = QDateTime::currentDateTime().toTimeZone(m_tz); 0091 0092 int offset = m_tz.offsetFromUtc(timeZoneDateTime); 0093 if (m_offset != offset) { 0094 m_offset = offset; 0095 } 0096 0097 setData(kli18n("Offset").untranslatedText(), m_offset); 0098 0099 QString abbreviation = m_tz.abbreviation(timeZoneDateTime); 0100 setData(kli18n("Timezone Abbreviation").untranslatedText(), abbreviation); 0101 0102 QDateTime dt; 0103 if (m_userDateTime) { 0104 dt = data()[QStringLiteral("DateTime")].toDateTime(); 0105 } else { 0106 dt = timeZoneDateTime; 0107 } 0108 0109 if (m_solarPosition || m_moonPosition) { 0110 const QDate prev = data()[QStringLiteral("DateTime")].toDate(); 0111 const bool updateDailies = prev != dt.date(); 0112 0113 if (m_solarPosition) { 0114 if (updateDailies) { 0115 addDailySolarPositionData(dt); 0116 } 0117 0118 addSolarPositionData(dt); 0119 } 0120 0121 if (m_moonPosition) { 0122 if (updateDailies) { 0123 addDailyMoonPositionData(dt); 0124 } 0125 0126 addMoonPositionData(dt); 0127 } 0128 } 0129 0130 if (!m_userDateTime) { 0131 setData(kli18n("DateTime").untranslatedText(), dt); 0132 0133 forceImmediateUpdate(); 0134 } 0135 } 0136 0137 QString TimeSource::parseName(const QString &name) 0138 { 0139 m_userDateTime = false; 0140 if (!name.contains('|')) { 0141 // the simple case where it's just a timezone request 0142 return name; 0143 } 0144 0145 // the various keys we recognize 0146 constexpr const auto latitude = kli18n("Latitude"); 0147 constexpr const auto longitude = kli18n("Longitude"); 0148 constexpr const auto solar = kli18n("Solar"); 0149 constexpr const auto moon = kli18n("Moon"); 0150 constexpr const auto datetime = kli18n("DateTime"); 0151 0152 // now parse out what we got handed in 0153 const QStringList list = name.split('|', Qt::SkipEmptyParts); 0154 0155 const int listSize = list.size(); 0156 for (int i = 1; i < listSize; ++i) { 0157 const QString arg = list[i]; 0158 const int n = arg.indexOf('='); 0159 0160 if (n != -1) { 0161 const QString key = arg.mid(0, n); 0162 const QString value = arg.mid(n + 1); 0163 0164 if (key == latitude.untranslatedText()) { 0165 m_latitude = value.toDouble(); 0166 } else if (key == longitude.untranslatedText()) { 0167 m_longitude = value.toDouble(); 0168 } else if (key == datetime.untranslatedText()) { 0169 QDateTime dt = QDateTime::fromString(value, Qt::ISODate); 0170 if (dt.isValid()) { 0171 setData(kli18n("DateTime").untranslatedText(), dt); 0172 m_userDateTime = true; 0173 } 0174 } 0175 } else if (arg == solar.untranslatedText()) { 0176 m_solarPosition = true; 0177 } else if (arg == moon.untranslatedText()) { 0178 m_moonPosition = true; 0179 } 0180 } 0181 0182 // timezone is first item ... 0183 return list.at(0); 0184 } 0185 0186 Sun *TimeSource::sun() 0187 { 0188 if (!m_sun) { 0189 m_sun = new Sun(); 0190 } 0191 m_sun->setPosition(m_latitude, m_longitude); 0192 return m_sun; 0193 } 0194 0195 Moon *TimeSource::moon() 0196 { 0197 if (!m_moon) { 0198 m_moon = new Moon(sun()); 0199 } 0200 m_moon->setPosition(m_latitude, m_longitude); 0201 return m_moon; 0202 } 0203 0204 void TimeSource::addMoonPositionData(const QDateTime &dt) 0205 { 0206 Moon *m = moon(); 0207 m->calcForDateTime(dt, m_offset); 0208 setData(QStringLiteral("Moon Azimuth"), m->azimuth()); 0209 setData(QStringLiteral("Moon Zenith"), 90 - m->altitude()); 0210 setData(QStringLiteral("Moon Corrected Elevation"), m->calcElevation()); 0211 setData(QStringLiteral("MoonPhaseAngle"), m->phase()); 0212 } 0213 0214 void TimeSource::addDailyMoonPositionData(const QDateTime &dt) 0215 { 0216 Moon *m = moon(); 0217 QList<QPair<QDateTime, QDateTime>> times = m->timesForAngles(QList<double>() << -0.833, dt, m_offset); 0218 setData(QStringLiteral("Moonrise"), times[0].first); 0219 setData(QStringLiteral("Moonset"), times[0].second); 0220 m->calcForDateTime(QDateTime(dt.date(), QTime(12, 0)), m_offset); 0221 setData(QStringLiteral("MoonPhase"), int(m->phase() / 360.0 * 29.0)); 0222 } 0223 0224 void TimeSource::addSolarPositionData(const QDateTime &dt) 0225 { 0226 Sun *s = sun(); 0227 s->calcForDateTime(dt, m_offset); 0228 setData(QStringLiteral("Azimuth"), s->azimuth()); 0229 setData(QStringLiteral("Zenith"), 90.0 - s->altitude()); 0230 setData(QStringLiteral("Corrected Elevation"), s->calcElevation()); 0231 } 0232 0233 void TimeSource::addDailySolarPositionData(const QDateTime &dt) 0234 { 0235 Sun *s = sun(); 0236 QList<QPair<QDateTime, QDateTime>> times = s->timesForAngles(QList<double>() << -0.833 << -6.0 << -12.0 << -18.0, dt, m_offset); 0237 0238 setData(QStringLiteral("Sunrise"), times[0].first); 0239 setData(QStringLiteral("Sunset"), times[0].second); 0240 setData(QStringLiteral("Civil Dawn"), times[1].first); 0241 setData(QStringLiteral("Civil Dusk"), times[1].second); 0242 setData(QStringLiteral("Nautical Dawn"), times[2].first); 0243 setData(QStringLiteral("Nautical Dusk"), times[2].second); 0244 setData(QStringLiteral("Astronomical Dawn"), times[3].first); 0245 setData(QStringLiteral("Astronomical Dusk"), times[3].second); 0246 }