File indexing completed on 2024-04-28 16:44:42
0001 /* 0002 SPDX-FileCopyrightText: 2022 Fushan Wen <qydwhotmail@gmail.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "config-ICU.h" 0008 0009 #include "alternatecalendarplugin.h" 0010 0011 #include <QCache> 0012 0013 #include <KConfigGroup> 0014 #include <KConfigWatcher> 0015 #include <KSharedConfig> 0016 0017 #include "provider/qtcalendar.h" 0018 #if HAVE_ICU 0019 #include "provider/chinesecalendar.h" 0020 #include "provider/hebrewcalendar.h" 0021 #include "provider/indiancalendar.h" 0022 #endif 0023 0024 using SubLabel = CalendarEvents::CalendarEventsPlugin::SubLabel; 0025 0026 class AlternateCalendarPluginPrivate 0027 { 0028 public: 0029 explicit AlternateCalendarPluginPrivate(AlternateCalendarPlugin *parent); 0030 ~AlternateCalendarPluginPrivate(); 0031 0032 void init(); 0033 void loadEventsForDateRange(const QDate &startDate, const QDate &endDate); 0034 0035 private: 0036 std::unique_ptr<AbstractCalendarProvider> m_calendarProvider; 0037 0038 // Cache lookup data 0039 QCache<QDate, SubLabel> m_subLabelsCache; 0040 0041 // For updating config 0042 KConfigGroup m_generalConfigGroup; 0043 KConfigWatcher::Ptr m_configWatcher; 0044 0045 CalendarSystem::System m_calendarSystem; 0046 int m_dateOffset; // For the (tabular) Islamic Civil calendar 0047 0048 AlternateCalendarPlugin *q; 0049 }; 0050 0051 AlternateCalendarPluginPrivate::AlternateCalendarPluginPrivate(AlternateCalendarPlugin *parent) 0052 : q(parent) 0053 { 0054 m_subLabelsCache.setMaxCost(42 * 3 /*previous, current, next*/); 0055 0056 auto config = KSharedConfig::openConfig(QStringLiteral("plasma_calendar_alternatecalendar")); 0057 m_generalConfigGroup = config->group("General"); 0058 m_configWatcher = KConfigWatcher::create(config); 0059 QObject::connect(m_configWatcher.get(), &KConfigWatcher::configChanged, q, &AlternateCalendarPlugin::updateSettings); 0060 init(); 0061 } 0062 0063 AlternateCalendarPluginPrivate::~AlternateCalendarPluginPrivate() 0064 { 0065 } 0066 0067 void AlternateCalendarPluginPrivate::init() 0068 { 0069 m_dateOffset = m_generalConfigGroup.readEntry("dateOffset", 0); 0070 0071 // Find the matched calendar system 0072 const QString system = m_generalConfigGroup.readEntry("calendarSystem", "Julian"); 0073 const auto systemIt = s_calendarMap.find(system); 0074 0075 if (systemIt == s_calendarMap.end()) { 0076 // Invalid config, fall back to Gregorian 0077 m_calendarSystem = CalendarSystem::Gregorian; 0078 } else { 0079 m_calendarSystem = systemIt->second.system; 0080 } 0081 0082 // Load/Reload the calendar provider 0083 switch (m_calendarSystem) { 0084 #if HAVE_ICU 0085 case CalendarSystem::Chinese: 0086 m_calendarProvider.reset(new ChineseCalendarProvider(q, m_calendarSystem)); 0087 break; 0088 case CalendarSystem::Indian: 0089 m_calendarProvider.reset(new IndianCalendarProvider(q, m_calendarSystem)); 0090 break; 0091 case CalendarSystem::Hebrew: 0092 m_calendarProvider.reset(new HebrewCalendarProvider(q, m_calendarSystem)); 0093 break; 0094 #endif 0095 #ifndef QT_BOOTSTRAPPED 0096 case CalendarSystem::Julian: 0097 case CalendarSystem::Milankovic: 0098 #endif 0099 #if QT_CONFIG(jalalicalendar) 0100 case CalendarSystem::Jalali: 0101 #endif 0102 #if QT_CONFIG(islamiccivilcalendar) 0103 case CalendarSystem::IslamicCivil: 0104 #endif 0105 m_calendarProvider.reset(new QtCalendarProvider(q, m_calendarSystem)); 0106 break; 0107 default: 0108 m_calendarProvider.reset(new AbstractCalendarProvider(q, m_calendarSystem)); 0109 } 0110 0111 // Clear the old cache when config is reloaded 0112 m_subLabelsCache.clear(); 0113 } 0114 0115 void AlternateCalendarPluginPrivate::loadEventsForDateRange(const QDate &startDate, const QDate &endDate) 0116 { 0117 if (!endDate.isValid() || m_calendarSystem == CalendarSystem::Gregorian) { 0118 return; 0119 } 0120 0121 QHash<QDate, QDate> alternateDatesData; 0122 QHash<QDate, CalendarEvents::CalendarEventsPlugin::SubLabel> subLabelsData; 0123 0124 for (QDate date = startDate; date <= endDate && date.isValid(); date = date.addDays(1)) { 0125 const QDate offsetDate = date.addDays(m_dateOffset); 0126 const QCalendar::YearMonthDay alt = m_calendarProvider->fromGregorian(offsetDate); 0127 0128 if (alt.day != date.day() || alt.month != date.month() || alt.year != date.year()) { 0129 alternateDatesData.insert(date, QDate(alt.year, alt.month, alt.day)); 0130 } 0131 0132 if (m_subLabelsCache.contains(date)) { 0133 subLabelsData.insert(date, *m_subLabelsCache.object(date)); 0134 } else { 0135 const auto it = subLabelsData.insert(date, m_calendarProvider->subLabels(offsetDate)); 0136 m_subLabelsCache.insert(date, new SubLabel(*it)); 0137 } 0138 } 0139 0140 if (alternateDatesData.size() > 0) { 0141 Q_EMIT q->alternateDateReady(alternateDatesData); 0142 } 0143 Q_EMIT q->subLabelReady(subLabelsData); 0144 } 0145 0146 AlternateCalendarPlugin::AlternateCalendarPlugin(QObject *parent) 0147 : CalendarEvents::CalendarEventsPlugin(parent) 0148 , d(std::make_unique<AlternateCalendarPluginPrivate>(this)) 0149 { 0150 } 0151 0152 AlternateCalendarPlugin::~AlternateCalendarPlugin() 0153 { 0154 } 0155 0156 void AlternateCalendarPlugin::loadEventsForDateRange(const QDate &startDate, const QDate &endDate) 0157 { 0158 m_lastStartDate = startDate; 0159 m_lastEndDate = endDate; 0160 0161 d->loadEventsForDateRange(startDate, endDate); 0162 } 0163 0164 void AlternateCalendarPlugin::updateSettings() 0165 { 0166 d->init(); 0167 loadEventsForDateRange(m_lastStartDate, m_lastEndDate); 0168 }