You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
246 lines
7.4 KiB
246 lines
7.4 KiB
/* |
|
SPDX-FileCopyrightText: 2009 Aaron Seigo <aseigo@kde.org> |
|
|
|
Moon Phase: |
|
SPDX-FileCopyrightText: 1998, 2000 Stephan Kulow <coolo@kde.org> |
|
SPDX-FileCopyrightText: 2009 Davide Bettio <davide.bettio@kdemail.net> |
|
|
|
Solar position: |
|
SPDX-FileCopyrightText: 2009 Petri Damsten <damu@iki.fi> |
|
|
|
SPDX-License-Identifier: LGPL-2.0-or-later |
|
*/ |
|
|
|
#include "timesource.h" |
|
|
|
#include <QDateTime> |
|
|
|
#include <KLazyLocalizedString> |
|
#include <KLocalizedString> |
|
|
|
#include "solarsystem.h" |
|
|
|
// timezone is defined in msvc |
|
#ifdef timezone |
|
#undef timezone |
|
#endif |
|
|
|
TimeSource::TimeSource(const QString &name, QObject *parent) |
|
: Plasma::DataContainer(parent) |
|
, m_offset(0) |
|
, m_latitude(0) |
|
, m_longitude(0) |
|
, m_sun(nullptr) |
|
, m_moon(nullptr) |
|
, m_moonPosition(false) |
|
, m_solarPosition(false) |
|
, m_local(false) |
|
{ |
|
setObjectName(name); |
|
setTimeZone(parseName(name)); |
|
} |
|
|
|
void TimeSource::setTimeZone(const QString &tz) |
|
{ |
|
m_tzName = tz; |
|
m_local = m_tzName == kli18n("Local").untranslatedText(); |
|
if (m_local) { |
|
m_tzName = QString::fromUtf8(QTimeZone::systemTimeZoneId()); |
|
} |
|
|
|
if (m_local) { |
|
m_tz = QTimeZone(QTimeZone::systemTimeZoneId()); |
|
} else { |
|
m_tz = QTimeZone(m_tzName.toUtf8()); |
|
if (!m_tz.isValid()) { |
|
m_tz = QTimeZone(QTimeZone::systemTimeZoneId()); |
|
} |
|
} |
|
|
|
const QString trTimezone = i18n(m_tzName.toUtf8()); |
|
setData(kli18n("Timezone").untranslatedText(), trTimezone); |
|
|
|
const QStringList tzParts = trTimezone.split('/', Qt::SkipEmptyParts); |
|
if (tzParts.count() == 1) { |
|
// no '/' so just set it as the city |
|
setData(kli18n("Timezone City").untranslatedText(), trTimezone); |
|
} else if (tzParts.count() == 2) { |
|
setData(kli18n("Timezone Continent").untranslatedText(), tzParts.value(0)); |
|
setData(kli18n("Timezone City").untranslatedText(), tzParts.value(1)); |
|
} else { // for zones like America/Argentina/Buenos_Aires |
|
setData(kli18n("Timezone Continent").untranslatedText(), tzParts.value(0)); |
|
setData(kli18n("Timezone Country").untranslatedText(), tzParts.value(1)); |
|
setData(kli18n("Timezone City").untranslatedText(), tzParts.value(2)); |
|
} |
|
|
|
updateTime(); |
|
} |
|
|
|
TimeSource::~TimeSource() |
|
{ |
|
// First delete the moon, that does not delete the Sun, and then the Sun |
|
// If the Sun is deleted before the moon, the moon has a invalid pointer |
|
// to where the Sun was pointing. |
|
delete m_moon; |
|
delete m_sun; |
|
} |
|
|
|
void TimeSource::updateTime() |
|
{ |
|
QDateTime timeZoneDateTime = QDateTime::currentDateTime().toTimeZone(m_tz); |
|
|
|
int offset = m_tz.offsetFromUtc(timeZoneDateTime); |
|
if (m_offset != offset) { |
|
m_offset = offset; |
|
} |
|
|
|
setData(kli18n("Offset").untranslatedText(), m_offset); |
|
|
|
QString abbreviation = m_tz.abbreviation(timeZoneDateTime); |
|
setData(kli18n("Timezone Abbreviation").untranslatedText(), abbreviation); |
|
|
|
QDateTime dt; |
|
if (m_userDateTime) { |
|
dt = data()[QStringLiteral("DateTime")].toDateTime(); |
|
} else { |
|
dt = timeZoneDateTime; |
|
} |
|
|
|
if (m_solarPosition || m_moonPosition) { |
|
const QDate prev = data()[QStringLiteral("DateTime")].toDate(); |
|
const bool updateDailies = prev != dt.date(); |
|
|
|
if (m_solarPosition) { |
|
if (updateDailies) { |
|
addDailySolarPositionData(dt); |
|
} |
|
|
|
addSolarPositionData(dt); |
|
} |
|
|
|
if (m_moonPosition) { |
|
if (updateDailies) { |
|
addDailyMoonPositionData(dt); |
|
} |
|
|
|
addMoonPositionData(dt); |
|
} |
|
} |
|
|
|
if (!m_userDateTime) { |
|
setData(kli18n("DateTime").untranslatedText(), dt); |
|
|
|
forceImmediateUpdate(); |
|
} |
|
} |
|
|
|
QString TimeSource::parseName(const QString &name) |
|
{ |
|
m_userDateTime = false; |
|
if (!name.contains('|')) { |
|
// the simple case where it's just a timezone request |
|
return name; |
|
} |
|
|
|
// the various keys we recognize |
|
constexpr const auto latitude = kli18n("Latitude"); |
|
constexpr const auto longitude = kli18n("Longitude"); |
|
constexpr const auto solar = kli18n("Solar"); |
|
constexpr const auto moon = kli18n("Moon"); |
|
constexpr const auto datetime = kli18n("DateTime"); |
|
|
|
// now parse out what we got handed in |
|
const QStringList list = name.split('|', Qt::SkipEmptyParts); |
|
|
|
const int listSize = list.size(); |
|
for (int i = 1; i < listSize; ++i) { |
|
const QString arg = list[i]; |
|
const int n = arg.indexOf('='); |
|
|
|
if (n != -1) { |
|
const QString key = arg.mid(0, n); |
|
const QString value = arg.mid(n + 1); |
|
|
|
if (key == latitude.untranslatedText()) { |
|
m_latitude = value.toDouble(); |
|
} else if (key == longitude.untranslatedText()) { |
|
m_longitude = value.toDouble(); |
|
} else if (key == datetime.untranslatedText()) { |
|
QDateTime dt = QDateTime::fromString(value, Qt::ISODate); |
|
if (dt.isValid()) { |
|
setData(kli18n("DateTime").untranslatedText(), dt); |
|
m_userDateTime = true; |
|
} |
|
} |
|
} else if (arg == solar.untranslatedText()) { |
|
m_solarPosition = true; |
|
} else if (arg == moon.untranslatedText()) { |
|
m_moonPosition = true; |
|
} |
|
} |
|
|
|
// timezone is first item ... |
|
return list.at(0); |
|
} |
|
|
|
Sun *TimeSource::sun() |
|
{ |
|
if (!m_sun) { |
|
m_sun = new Sun(); |
|
} |
|
m_sun->setPosition(m_latitude, m_longitude); |
|
return m_sun; |
|
} |
|
|
|
Moon *TimeSource::moon() |
|
{ |
|
if (!m_moon) { |
|
m_moon = new Moon(sun()); |
|
} |
|
m_moon->setPosition(m_latitude, m_longitude); |
|
return m_moon; |
|
} |
|
|
|
void TimeSource::addMoonPositionData(const QDateTime &dt) |
|
{ |
|
Moon *m = moon(); |
|
m->calcForDateTime(dt, m_offset); |
|
setData(QStringLiteral("Moon Azimuth"), m->azimuth()); |
|
setData(QStringLiteral("Moon Zenith"), 90 - m->altitude()); |
|
setData(QStringLiteral("Moon Corrected Elevation"), m->calcElevation()); |
|
setData(QStringLiteral("MoonPhaseAngle"), m->phase()); |
|
} |
|
|
|
void TimeSource::addDailyMoonPositionData(const QDateTime &dt) |
|
{ |
|
Moon *m = moon(); |
|
QList<QPair<QDateTime, QDateTime>> times = m->timesForAngles(QList<double>() << -0.833, dt, m_offset); |
|
setData(QStringLiteral("Moonrise"), times[0].first); |
|
setData(QStringLiteral("Moonset"), times[0].second); |
|
m->calcForDateTime(QDateTime(dt.date(), QTime(12, 0)), m_offset); |
|
setData(QStringLiteral("MoonPhase"), int(m->phase() / 360.0 * 29.0)); |
|
} |
|
|
|
void TimeSource::addSolarPositionData(const QDateTime &dt) |
|
{ |
|
Sun *s = sun(); |
|
s->calcForDateTime(dt, m_offset); |
|
setData(QStringLiteral("Azimuth"), s->azimuth()); |
|
setData(QStringLiteral("Zenith"), 90.0 - s->altitude()); |
|
setData(QStringLiteral("Corrected Elevation"), s->calcElevation()); |
|
} |
|
|
|
void TimeSource::addDailySolarPositionData(const QDateTime &dt) |
|
{ |
|
Sun *s = sun(); |
|
QList<QPair<QDateTime, QDateTime>> times = s->timesForAngles(QList<double>() << -0.833 << -6.0 << -12.0 << -18.0, dt, m_offset); |
|
|
|
setData(QStringLiteral("Sunrise"), times[0].first); |
|
setData(QStringLiteral("Sunset"), times[0].second); |
|
setData(QStringLiteral("Civil Dawn"), times[1].first); |
|
setData(QStringLiteral("Civil Dusk"), times[1].second); |
|
setData(QStringLiteral("Nautical Dawn"), times[2].first); |
|
setData(QStringLiteral("Nautical Dusk"), times[2].second); |
|
setData(QStringLiteral("Astronomical Dawn"), times[3].first); |
|
setData(QStringLiteral("Astronomical Dusk"), times[3].second); |
|
}
|
|
|