File indexing completed on 2024-11-24 04:42:28

0001 /*
0002  *  calendarfunctions.cpp  -  miscellaneous calendar access functions
0003  *  Program:  kalarm
0004  *  SPDX-FileCopyrightText: 2020 David Jarvie <djarvie@kde.org>
0005  *
0006  *  SPDX-License-Identifier: GPL-2.0-or-later
0007  */
0008 
0009 #include "calendarfunctions.h"
0010 
0011 #include "preferences.h"
0012 #include "lib/messagebox.h"
0013 #include "kalarm_debug.h"
0014 
0015 #include <KCalendarCore/CalFormat>
0016 #include <KCalendarCore/Event>
0017 #include <KCalendarCore/MemoryCalendar>
0018 using namespace KCalendarCore;
0019 
0020 #include <KLocalizedString>
0021 #include <KJobWidgets>
0022 #include <KIO/StoredTransferJob>
0023 
0024 #include <QTemporaryFile>
0025 
0026 
0027 namespace KAlarm
0028 {
0029 
0030 /******************************************************************************
0031 * Import alarms from a calendar file. The alarms are converted to the current
0032 * KAlarm format and are given new unique event IDs.
0033 * Parameters: parent:    parent widget for error message boxes
0034 *             alarmList: imported alarms are appended to this list
0035 */
0036 bool importCalendarFile(const QUrl& url, CalEvent::Types alarmTypes, bool newId, QWidget* parent, QHash<CalEvent::Type, QList<KAEvent>>& alarmList)
0037 {
0038     if (!url.isValid())
0039     {
0040         qCDebug(KALARM_LOG) << "KAlarm::importCalendarFile: Invalid URL";
0041         return false;
0042     }
0043 
0044     // If the URL is remote, download it into a temporary local file.
0045     QString filename;
0046     bool local = url.isLocalFile();
0047     if (local)
0048     {
0049         filename = url.toLocalFile();
0050         if (!QFile::exists(filename))
0051         {
0052             qCDebug(KALARM_LOG) << "KAlarm::importCalendarFile:" << url.toDisplayString() << "not found";
0053             KAMessageBox::error(parent, xi18nc("@info", "Could not load calendar <filename>%1</filename>.", url.toDisplayString()));
0054             return false;
0055         }
0056     }
0057     else
0058     {
0059         auto getJob = KIO::storedGet(url);
0060         KJobWidgets::setWindow(getJob, parent);
0061         if (!getJob->exec())
0062         {
0063             qCCritical(KALARM_LOG) << "KAlarm::importCalendarFile: Download failure";
0064             KAMessageBox::error(parent, xi18nc("@info", "Cannot download calendar: <filename>%1</filename>", url.toDisplayString()));
0065             return false;
0066         }
0067         QTemporaryFile tmpFile;
0068         tmpFile.setAutoRemove(false);
0069         tmpFile.write(getJob->data());
0070         tmpFile.seek(0);
0071         filename = tmpFile.fileName();
0072         qCDebug(KALARM_LOG) << "KAlarm::importCalendarFile: --- Downloaded to" << filename;
0073     }
0074 
0075     // Read the calendar and add its alarms to the current calendars
0076     MemoryCalendar::Ptr cal(new MemoryCalendar(Preferences::timeSpecAsZone()));
0077     FileStorage::Ptr calStorage(new FileStorage(cal, filename));
0078     bool success = calStorage->load();
0079     if (!local)
0080         QFile::remove(filename);
0081     if (!success)
0082     {
0083         qCDebug(KALARM_LOG) << "KAlarm::importCalendarFile: Error loading calendar '" << filename <<"'";
0084         KAMessageBox::error(parent, xi18nc("@info", "Could not load calendar <filename>%1</filename>.", url.toDisplayString()));
0085         return false;
0086     }
0087 
0088     QString versionString;
0089     const bool currentFormat = (KACalendar::updateVersion(calStorage, versionString) != KACalendar::IncompatibleFormat);
0090     const Event::List events = cal->rawEvents();
0091     for (const Event::Ptr& event : events)
0092     {
0093         if (event->alarms().isEmpty()  ||  !KAEvent(event).isValid())
0094             continue;    // ignore events without alarms, or usable alarms
0095         CalEvent::Type type = CalEvent::status(event);
0096         if (type == CalEvent::TEMPLATE)
0097         {
0098             // If we know the event was not created by KAlarm, don't treat it as a template
0099             if (!currentFormat)
0100                 type = CalEvent::ACTIVE;
0101         }
0102         if (!(type & alarmTypes))
0103             continue;
0104 
0105         Event::Ptr newev(new Event(*event));
0106 
0107         // If there is a display alarm without display text, use the event
0108         // summary text instead.
0109         if (type == CalEvent::ACTIVE  &&  !newev->summary().isEmpty())
0110         {
0111             const Alarm::List& alarms = newev->alarms();
0112             for (Alarm::Ptr alarm : alarms)
0113             {
0114                 if (alarm->type() == Alarm::Display  &&  alarm->text().isEmpty())
0115                     alarm->setText(newev->summary());
0116             }
0117             newev->setSummary(QString());   // KAlarm only uses summary for template names
0118         }
0119 
0120         // Give the event a new ID, or ensure that it is in the correct format.
0121         const QString id = newId ? CalFormat::createUniqueId() : newev->uid();
0122         newev->setUid(CalEvent::uid(id, type));
0123 
0124         alarmList[type] += KAEvent(newev);
0125     }
0126     return true;
0127 }
0128 
0129 }
0130 
0131 // vim: et sw=4: