26 #include <tqtextstream.h>
30 #include <tdelocale.h>
31 #include <tdemessagebox.h>
32 #include <kstandarddirs.h>
33 #include <kstaticdeleter.h>
34 #include <tdeconfig.h>
35 #include <tdeaboutdata.h>
36 #include <tdeio/netaccess.h>
37 #include <tdefileitem.h>
38 #include <tdetempfile.h>
39 #include <tdefiledialog.h>
40 #include <dcopclient.h>
44 #include <libical/ical.h>
47 #include <libkcal/vcaldrag.h>
48 #include <libkcal/vcalformat.h>
49 #include <libkcal/icalformat.h>
51 #include "calendarcompat.h"
56 #include "preferences.h"
57 #include "startdaytimer.h"
58 #include "alarmcalendar.moc"
62 TQString AlarmCalendar::icalProductId()
64 return TQString::fromLatin1(
"-//K Desktop Environment//NONSGML " KALARM_NAME
" %1//EN").arg(KAlarm::currentCalendarVersionString());
68 KAEvent::ACTIVE, KAEvent::EXPIRED, KAEvent::DISPLAYING, KAEvent::TEMPLATE
70 static const TQString calendarNames[AlarmCalendar::NCALS] = {
71 TQString::fromLatin1(
"calendar.ics"),
72 TQString::fromLatin1(
"expired.ics"),
73 TQString::fromLatin1(
"displaying.ics"),
74 TQString::fromLatin1(
"template.ics")
76 static KStaticDeleter<AlarmCalendar> calendarDeleter[AlarmCalendar::NCALS];
78 AlarmCalendar* AlarmCalendar::mCalendars[NCALS] = { 0, 0, 0, 0 };
91 bool AlarmCalendar::initialiseCalendars()
93 TDEConfig* config = kapp->config();
94 config->setGroup(TQString::fromLatin1(
"General"));
95 TQString activeKey = TQString::fromLatin1(
"Calendar");
96 TQString expiredKey = TQString::fromLatin1(
"ExpiredCalendar");
97 TQString templateKey = TQString::fromLatin1(
"TemplateCalendar");
98 TQString displayCal, activeCal, expiredCal, templateCal;
99 calendarDeleter[ACTIVE].setObject(mCalendars[ACTIVE], createCalendar(ACTIVE, config, activeCal, activeKey));
100 calendarDeleter[EXPIRED].setObject(mCalendars[EXPIRED], createCalendar(EXPIRED, config, expiredCal, expiredKey));
101 calendarDeleter[DISPLAY].setObject(mCalendars[DISPLAY], createCalendar(DISPLAY, config, displayCal));
102 calendarDeleter[TEMPLATE].setObject(mCalendars[TEMPLATE], createCalendar(TEMPLATE, config, templateCal, templateKey));
104 TQString errorKey1, errorKey2;
105 if (activeCal == displayCal)
106 errorKey1 = activeKey;
107 else if (expiredCal == displayCal)
108 errorKey1 = expiredKey;
109 else if (templateCal == displayCal)
110 errorKey1 = templateKey;
111 if (!errorKey1.isNull())
113 kdError(5950) <<
"AlarmCalendar::initialiseCalendars(): '" << errorKey1 <<
"' calendar name = display calendar name\n";
114 TQString file = config->readPathEntry(errorKey1);
115 KAlarmApp::displayFatalError(i18n(
"%1: file name not permitted: %2").arg(errorKey1).arg(file));
118 if (activeCal == expiredCal)
120 errorKey1 = activeKey;
121 errorKey2 = expiredKey;
123 else if (activeCal == templateCal)
125 errorKey1 = activeKey;
126 errorKey2 = templateKey;
128 else if (expiredCal == templateCal)
130 errorKey1 = expiredKey;
131 errorKey2 = templateKey;
133 if (!errorKey1.isNull())
135 kdError(5950) <<
"AlarmCalendar::initialiseCalendars(): calendar names clash: " << errorKey1 <<
", " << errorKey2 << endl;
136 KAlarmApp::displayFatalError(i18n(
"%1, %2: file names must be different").arg(errorKey1).arg(errorKey2));
139 if (!mCalendars[ACTIVE]->valid())
141 TQString path = mCalendars[ACTIVE]->path();
142 kdError(5950) <<
"AlarmCalendar::initialiseCalendars(): invalid name: " << path << endl;
143 KAlarmApp::displayFatalError(i18n(
"Invalid calendar file name: %1").arg(path));
153 AlarmCalendar* AlarmCalendar::createCalendar(CalID type, TDEConfig* config, TQString& writePath,
const TQString& configKey)
155 static TQRegExp vcsRegExp(TQString::fromLatin1(
"\\.vcs$"));
156 static TQString ical = TQString::fromLatin1(
".ics");
158 if (configKey.isNull())
160 writePath = locateLocal(
"appdata", calendarNames[type]);
165 TQString readPath = config->readPathEntry(configKey, locateLocal(
"appdata", calendarNames[type]));
166 writePath = readPath;
167 writePath.replace(vcsRegExp, ical);
168 return new AlarmCalendar(readPath, type, writePath, configKey);
175 void AlarmCalendar::terminateCalendars()
177 for (
int i = 0; i < NCALS; ++i)
179 calendarDeleter[i].destructObject();
192 if (!cal->mPurgeDays)
196 kdError(5950) <<
"AlarmCalendar::calendarOpen(" << calendarNames[id] <<
"): open error\n";
204 const KCal::Event* AlarmCalendar::getEvent(
const TQString& uniqueID)
206 if (uniqueID.isEmpty())
209 switch (KAEvent::uidStatus(uniqueID))
211 case KAEvent::ACTIVE: calID = ACTIVE;
break;
212 case KAEvent::TEMPLATE: calID = TEMPLATE;
break;
213 case KAEvent::EXPIRED: calID = EXPIRED;
break;
214 case KAEvent::DISPLAYING: calID = DISPLAY;
break;
221 return cal->event(uniqueID);
231 AlarmCalendar::AlarmCalendar(
const TQString& path, CalID type,
const TQString& icalPath,
232 const TQString& configKey)
234 mConfigKey(icalPath.isNull() ? TQString() : configKey),
235 mType(eventTypes[type]),
238 mPurgeDaysQueued(-1),
243 mICalUrl.setPath(icalPath.isNull() ? path : icalPath);
244 mVCal = (icalPath.isNull() || path != icalPath);
247 AlarmCalendar::~AlarmCalendar()
255 bool AlarmCalendar::open()
262 kdDebug(5950) <<
"AlarmCalendar::open(" << mUrl.prettyURL() <<
")\n";
269 if (!TDEIO::NetAccess::exists(mUrl,
true, MainWindow::mainMainWindow()))
296 bool AlarmCalendar::create()
298 if (mICalUrl.isLocalFile())
299 return saveCal(mICalUrl.path());
303 return saveCal(tmpFile.name());
314 int AlarmCalendar::load()
319 kdDebug(5950) <<
"AlarmCalendar::load(): " << mUrl.prettyURL() << endl;
321 if (!TDEIO::NetAccess::download(mUrl, tmpFile, MainWindow::mainMainWindow()))
323 kdError(5950) <<
"AlarmCalendar::load(): Load failure" << endl;
324 KMessageBox::error(0, i18n(
"Cannot open calendar:\n%1").arg(mUrl.prettyURL()));
327 kdDebug(5950) <<
"AlarmCalendar::load(): --- Downloaded to " << tmpFile << endl;
329 bool loaded = mCalendar->
load(tmpFile);
334 TDEIO::NetAccess::removeTempFile(tmpFile);
336 TDEIO::NetAccess::stat(mUrl, uds, MainWindow::mainMainWindow());
337 KFileItem fi(uds, mUrl);
340 kdError(5950) <<
"AlarmCalendar::load(): Error loading calendar file '" << tmpFile <<
"'" << endl;
341 KMessageBox::error(0, i18n(
"Error loading calendar:\n%1\n\nPlease fix or delete the file.").arg(mUrl.prettyURL()));
348 if (!mLocalFile.isEmpty())
349 TDEIO::NetAccess::removeTempFile(mLocalFile);
350 mLocalFile = tmpFile;
352 CalendarCompat::fix(*mCalendar, mLocalFile);
360 bool AlarmCalendar::reload()
364 kdDebug(5950) <<
"AlarmCalendar::reload(): " << mUrl.prettyURL() << endl;
366 bool result = open();
374 bool AlarmCalendar::saveCal(
const TQString& newFile)
376 if (!mCalendar || (!mOpen && newFile.isNull()))
379 kdDebug(5950) <<
"AlarmCalendar::saveCal(\"" << newFile <<
"\", " << mType <<
")\n";
380 TQString saveFilename = newFile.isNull() ? mLocalFile : newFile;
381 if (mVCal && newFile.isNull() && mUrl.isLocalFile())
382 saveFilename = mICalUrl.path();
385 kdError(5950) <<
"AlarmCalendar::saveCal(" << saveFilename <<
"): failed.\n";
386 KMessageBox::error(0, i18n(
"Failed to save calendar to\n'%1'").arg(mICalUrl.prettyURL()));
390 if (!mICalUrl.isLocalFile())
392 if (!TDEIO::NetAccess::upload(saveFilename, mICalUrl, MainWindow::mainMainWindow()))
394 kdError(5950) <<
"AlarmCalendar::saveCal(" << saveFilename <<
"): upload failed.\n";
395 KMessageBox::error(0, i18n(
"Cannot upload calendar to\n'%1'").arg(mICalUrl.prettyURL()));
404 if (!mConfigKey.isNull())
406 TDEConfig* config = kapp->config();
407 config->setGroup(TQString::fromLatin1(
"General"));
408 config->writePathEntry(mConfigKey, mICalUrl.path());
416 emit calendarSaved(
this);
423 void AlarmCalendar::close()
425 if (!mLocalFile.isEmpty())
427 TDEIO::NetAccess::removeTempFile(mLocalFile);
446 bool AlarmCalendar::importAlarms(TQWidget* parent)
448 KURL url = KFileDialog::getOpenURL(TQString::fromLatin1(
":importalarms"),
449 TQString::fromLatin1(
"*.vcs *.ics|%1").arg(i18n(
"Calendar Files")), parent);
452 kdError(5950) <<
"AlarmCalendar::importAlarms(): Empty URL" << endl;
457 kdDebug(5950) <<
"AlarmCalendar::importAlarms(): Invalid URL" << endl;
460 kdDebug(5950) <<
"AlarmCalendar::importAlarms(" << url.prettyURL() <<
")" << endl;
464 bool local = url.isLocalFile();
467 filename = url.path();
468 if (!TDEStandardDirs::exists(filename))
470 kdDebug(5950) <<
"AlarmCalendar::importAlarms(): File '" << url.prettyURL() <<
"' not found" << endl;
471 KMessageBox::error(parent, i18n(
"Could not load calendar '%1'.").arg(url.prettyURL()));
477 if (!TDEIO::NetAccess::download(url, filename, MainWindow::mainMainWindow()))
479 kdError(5950) <<
"AlarmCalendar::importAlarms(): Download failure" << endl;
480 KMessageBox::error(parent, i18n(
"Cannot download calendar:\n%1").arg(url.prettyURL()));
483 kdDebug(5950) <<
"--- Downloaded to " << filename << endl;
489 success = cal.load(filename);
492 kdDebug(5950) <<
"AlarmCalendar::importAlarms(): error loading calendar '" << filename <<
"'" << endl;
493 KMessageBox::error(parent, i18n(
"Could not load calendar '%1'.").arg(url.prettyURL()));
497 CalendarCompat::fix(cal, filename);
498 bool saveActive =
false;
499 bool saveExpired =
false;
500 bool saveTemplate =
false;
505 Event::List events = cal.rawEvents();
506 for (Event::List::ConstIterator it = events.begin(); it != events.end(); ++it)
508 const Event*
event = *it;
514 case KAEvent::ACTIVE:
518 case KAEvent::EXPIRED:
522 case KAEvent::TEMPLATE:
524 templat = templateCalendarOpen();
538 if (type == KAEvent::ACTIVE && !newev->
summary().isEmpty())
540 const Alarm::List& alarms = newev->
alarms();
541 for (Alarm::List::ConstIterator ait = alarms.begin(); ait != alarms.end(); ++ait)
544 if (alarm->
type() == Alarm::Display && alarm->
text().isEmpty())
550 newev->
setUid(KAEvent::uid(CalFormat::createUniqueId(), type));
551 if (!acal->mCalendar->
addEvent(newev))
564 TDEIO::NetAccess::removeTempFile(filename);
572 void AlarmCalendar::startUpdate()
581 bool AlarmCalendar::endUpdate()
583 if (mUpdateCount > 0)
596 bool AlarmCalendar::save()
612 void AlarmCalendar::convertToICal()
616 if (!mConfigKey.isNull())
618 TDEConfig* config = kapp->config();
619 config->setGroup(TQString::fromLatin1(
"General"));
620 config->writePathEntry(mConfigKey, mICalUrl.path());
633 void AlarmCalendar::setPurgeDays(
int days)
635 if (days != mPurgeDays)
637 int oldDays = mPurgeDays;
641 if (oldDays < 0 || (days >= 0 && days < oldDays))
647 else if (mPurgeDays > 0)
656 void AlarmCalendar::slotPurge()
666 void AlarmCalendar::purge(
int daysToKeep)
668 if (mPurgeDaysQueued < 0 || daysToKeep < mPurgeDaysQueued)
669 mPurgeDaysQueued = daysToKeep;
672 theApp()->processQueue();
683 void AlarmCalendar::purgeIfQueued()
685 if (mPurgeDaysQueued >= 0)
689 kdDebug(5950) <<
"AlarmCalendar::purgeIfQueued(" << mPurgeDaysQueued <<
")\n";
690 bool changed =
false;
691 TQDate cutoff = TQDate::currentDate().addDays(-mPurgeDaysQueued);
692 Event::List events = mCalendar->
rawEvents();
693 for (Event::List::ConstIterator it = events.begin(); it != events.end(); ++it)
695 Event* kcalEvent = *it;
696 if (!mPurgeDaysQueued || kcalEvent->
created().date() < cutoff)
707 mPurgeDaysQueued = -1;
717 void AlarmCalendar::startPurgeTimer()
730 Event* AlarmCalendar::addEvent(
KAEvent& event,
bool useEventID)
734 TQString
id =
event.id();
736 if (mType == KAEvent::ACTIVE)
741 event.setEventID(kcalEvent->
uid());
746 id = kcalEvent->
uid();
751 id = KAEvent::uid(
id, mType);
752 event.setEventID(
id);
755 event.updateKCalEvent(*kcalEvent,
false, (mType == KAEvent::EXPIRED),
true);
757 event.clearUpdated();
765 void AlarmCalendar::updateEvent(
const KAEvent& evnt)
769 Event* kcalEvent = event(evnt.id());
772 evnt.updateKCalEvent(*kcalEvent);
774 if (mType == KAEvent::ACTIVE)
775 Daemon::savingEvent(evnt.id());
779 if (mType == KAEvent::ACTIVE)
780 Daemon::eventHandled(evnt.id(),
false);
787 bool AlarmCalendar::deleteEvent(
const TQString& eventID,
bool saveit)
791 Event* kcalEvent = event(eventID);
795 if (mType == KAEvent::ACTIVE)
796 Daemon::savingEvent(eventID);
802 if (mType == KAEvent::ACTIVE)
803 Daemon::eventHandled(eventID,
false);
810 void AlarmCalendar::emitEmptyStatus()
812 emit emptyStatus(events().isEmpty());
818 KCal::Event* AlarmCalendar::event(
const TQString& uniqueID)
820 return mCalendar ? mCalendar->
event(uniqueID) : 0;
826 KCal::Event::List AlarmCalendar::events()
829 return KCal::Event::List();
830 KCal::Event::List list = mCalendar->
rawEvents();
831 KCal::Event::List::Iterator it = list.begin();
832 while (it != list.end())
835 if (event->alarms().isEmpty() || !
KAEvent(*event).valid())
836 it = list.remove(it);
846 Event::List AlarmCalendar::eventsWithAlarms(
const TQDateTime& from,
const TQDateTime& to)
848 kdDebug(5950) <<
"AlarmCalendar::eventsWithAlarms(" << from.toString() <<
" - " << to.toString() <<
")\n";
851 Event::List allEvents = events();
852 for (Event::List::ConstIterator it = allEvents.begin(); it != allEvents.end(); ++it)
857 bool endOffsetValid =
false;
858 const Alarm::List& alarms = e->
alarms();
859 for (Alarm::List::ConstIterator ait = alarms.begin(); ait != alarms.end(); ++ait)
881 endOffsetValid =
true;
886 TQDateTime pre = from.addSecs(-offset - 1);
887 if (e->
doesFloat() && pre.time() < Preferences::startOfDay())
888 pre = pre.addDays(-1);
892 dt = dt.addSecs(offset);
897 if (dt >= from && dt <= to)
899 kdDebug(5950) <<
"AlarmCalendar::events() '" << e->
summary()
900 <<
"': " << dt.toString() << endl;