summaryrefslogtreecommitdiffabout
Side-by-side diff
Diffstat (more/less context) (show whitespace changes)
-rw-r--r--bin/kdepim/WhatsNew.txt2
-rw-r--r--libkcal/icalformatimpl.cpp31
-rw-r--r--libkcal/incidencebase.cpp11
3 files changed, 27 insertions, 17 deletions
diff --git a/bin/kdepim/WhatsNew.txt b/bin/kdepim/WhatsNew.txt
index 06aa5f6..01d9e27 100644
--- a/bin/kdepim/WhatsNew.txt
+++ b/bin/kdepim/WhatsNew.txt
@@ -1,205 +1,207 @@
Info about the changes in new versions of KDE-Pim/Pi
********** VERSION 2.0.8 ************
Fixed a problem in dependency info in the ipk files for the Zaurus.
Added icon for the stealth new week view and made navigation more user friendly in monthview by adding a prev/next week button to the navigator bar.
Added a "go today" button to the datepicker.
Added "created" and "last modified" to event/todo viewer (and What'sThis viewer)
and made it configureable to show these values.
+Fixed a problem for events (from external iCal files) that do have a duration but no end date.
+
********** VERSION 2.0.7 ************
Added global application font settings
(for all KDE-Pim/Pi apps) to the general settings.
Fixed a problem in OM/Pi when trying to login to some IMAP servers
(like the IMAP server of Apple: mail.mac.com )
Added recurring todos to KO/Pi.
********** VERSION 2.0.6 ************
Some bugfixes in the pi-sync mode.
Added German translation for pi-sync mode.
KO/Pi:
Made the todolist using alternate background.
Other minor fixes in KO/Pi.
********** VERSION 2.0.5 ************
Bugfixes in KO/Pi.
********** VERSION 2.0.4 ************
KO/Pi:
Fixed problem loading translations for summary/location edit boxes in event/todo editor.
Added a general "select week number" to the toolbar.
Fixed some small problem of the new features introduced in version 2.0.3.
Made it possible to specify one specific category as category color,
if more than one categories are selected.
Fixed a bug in saving colors for categories with non-ascii characters.
(Like, e.g. German Umlauts).
Propably you have to set your colors again for those categories.
********** VERSION 2.0.3 ************
KO/Pi:
Added feature for changing alarm settings for many items at once:
Open list view (or search dialog), select the desired items and choose in
the popup menu: Set alarm for selected...
Added to the event/todo viewer the option to send an email to
all attendees or all selected (with RSVP) attendees.
Made the week-month mode changing in month view faster.
Made month view better useable with keyboard.
Now TAB key jumps to next cell with an event/todo.
Scroll in cell with coursor keys, scroll in time (next week) with
Shift/Control + coursorkeys.
Fixed bug that the todo view flat mode was reset after first view update.
If a todo is displayed closed in the todo view,
it is now displayed in overdue/due today color depending on the subtodos overdue/due today properties.
Added info about the numbers of years to the caption (title) information about a birthday event.
Made completion date in todo editor editable.
Added possibility to save/load templates for journals.
(Which is just a simple "save text to file" or "insert text from file".
********** VERSION 2.0.2 ************
KO/Pi:
Fixed the layout problem of the day label buttons
of the agenda view introduced in version 2.0.1.
Added WhatsThis support for the todo view and the list view.
Added a quite useful feature to the montview.
Just click on the week numbers on the left.
And in the top right corner of month view/agenda view
there is now a "week number quick selector".
(Click on the black triangle).
Made the quite difficult timezone change in KO/Pi easy.
OM/Pi:
Fixed too small icons on desktop.
Fixed non visible icons in mainwindow on Z with fastload enabled.
Added signature file setting to smtp account config.
And the signature can be edited and saved in the edit mail dialog.
That does mean:
Simply edit the signature for the selected smtp account in the
edit new mail dialog and press the "save signature" button there.
Then the signature is saved to the file specified in the smtp account settings.
If there is no file specified, it is saved automatically to the file
kdepim/apps/kopiemail/<accountname>.sig.
********** VERSION 2.0.1 ************
Oooops ... I forgot to test on the Zaurus 5500 ...
Fixed many problems of new (english) strings (and german translations)
introduced in the latest versions, where the text was not fitting on the
240x320 display of the Zaurus 5500.
KO/Pi:
Added a popup menu ( press pen and hold to get popup ) to the agenda view
with many useful items (add event/todo, show next week, two weeks, month, journal).
Added items to the todolist popup menu for:
Display all opened, all closed or all todos flat.
The "flat" view makes is possible to sort all todos after ,e.g., prio or date.
Made the reparenting of todos on the desktop possible via Drag&Drop.
Fixed several bugs in setting the completed datetime for todos.
Added info about completed datetime of todos to the todo viewer.
Now displaying a completed todo (with completed datetime set) in the agenda view
at the time of the completion. Such that now it is possible to see in the agenda view
when what todo was completed.
Fixed behaviour of automatic setting completion of todos with sub-todos/parent todos.
Now the behaviour is:
Setting a parent to complete sets all (sub)childs to complete.
Setting a parent to uncomplete does not change the childs.
Setting a child to uncomplete sets all parent to uncomplete.
Setting a child to complete does not change the parents.
Smart updating and double buffering of the daymatrix.
Showing holidays in the day matrix.
Many other small performance updates.
Made day labels in agenda clickable. By clicking a label, the day is displayed in single day mode.
Now the translation file usertranslation.txt is supposed to be in utf8 format.
If you want to translate a language from western europe, just change the germantranslation.txt file. Please read the updated Usertranslation HowTo in KO/Pi Help menu.
********** VERSION 2.0.0 ************
Stable release 2.0.0!
KO/Pi:
Fixed problem in edit dialog recreation at startup.
Made "toggle view*" menu items enabled context sensitive.
Changed agenda size menu to items 1-10.
Made it possible to change agenda size quickly by pressing mouse on timelabels in agenda view and move mouse up/down.
Usebility enhancements in the KO/Pi menus.
Birthday import now adds year to summary.
What's Next view shows age in years for birthday.
OM/Pi:
Added three info lines to display subject, from and to of selected mails.
KA/Pi:
Fixed jump bar behaviour on Zaurus.
Now KA/Pi search field supports searching for a range of starting characters.
E.g. to search for all contact beginning with b to n, type
b-n
in the search field.
********** VERSION 1.9.20 ************
KO/Pi:
Added for the "dislplay one day" agenda mode
info in the caption and in the day lables:
Now it is displayed, if the selected day is from "day before yesterday"
to "day after tomorrow".
Made it possible to delete a Todo, which has sub-todos.
Fixed two small problems in the todo view.
Added missing German translation for filter edit and print dialog.
Made search dialog closeable by cancel key.
Made it possible to select in the date picker the (ligt grey )
dates of the prev./next month with the mouse.
OM/Pi:
"Delete mail" icon in main window now deletes all selected mails.
Fixed the problem, that the state flag of imap mails was ignored.
Now mails with "FLAG_SEEN" on the imap server get no icon in the list view
to indecate that they are already seen.
Fixed the problem that the body of some mails was not displayed in the
mail viewer when fetching them from the imap server directly to read them.
Made it (configurable) possible to show the "To:" field in the list view.
Added to the mail viewer the option "View Source" to make it possible to see the raw mail data.
Added a "Download Mail" button to the mail viewer to quickly download the viewed mail to the
local storage folder (specified in account settings) of the account of the mail.
Removed some memory leaks in OM/Pi.
diff --git a/libkcal/icalformatimpl.cpp b/libkcal/icalformatimpl.cpp
index 2e38ae3..eae41aa 100644
--- a/libkcal/icalformatimpl.cpp
+++ b/libkcal/icalformatimpl.cpp
@@ -219,389 +219,389 @@ icalcomponent *ICalFormatImpl::writeFreeBusy(FreeBusy *freebusy,
icalcomponent_add_property(vfreebusy,icalproperty_new_uid(
freebusy->uid().utf8()));
}
//Loops through all the periods in the freebusy object
QValueList<Period> list = freebusy->busyPeriods();
QValueList<Period>::Iterator it;
icalperiodtype period;
for (it = list.begin(); it!= list.end(); ++it) {
period.start = writeICalDateTime((*it).start());
period.end = writeICalDateTime((*it).end());
icalcomponent_add_property(vfreebusy, icalproperty_new_freebusy(period) );
}
return vfreebusy;
}
icalcomponent *ICalFormatImpl::writeJournal(Journal *journal)
{
icalcomponent *vjournal = icalcomponent_new(ICAL_VJOURNAL_COMPONENT);
writeIncidence(vjournal,journal);
// start time
if (journal->dtStart().isValid()) {
icaltimetype start;
if (journal->doesFloat()) {
// kdDebug(5800) << "§§ Incidence " << event->summary() << " floats." << endl;
start = writeICalDate(journal->dtStart().date());
} else {
// kdDebug(5800) << "§§ incidence " << event->summary() << " has time." << endl;
start = writeICalDateTime(journal->dtStart());
}
icalcomponent_add_property(vjournal,icalproperty_new_dtstart(start));
}
return vjournal;
}
void ICalFormatImpl::writeIncidence(icalcomponent *parent,Incidence *incidence)
{
// pilot sync stuff
// TODO: move this application-specific code to kpilot
if (incidence->pilotId()) {
incidence->setNonKDECustomProperty("X-PILOTID", QString::number(incidence->pilotId()));
incidence->setNonKDECustomProperty("X-PILOTSTAT", QString::number(incidence->syncStatus()));
}
if ( !incidence->IDStr().isEmpty()) {
incidence->setNonKDECustomProperty("X-KOPIEXTID",incidence->IDStr() );
}
writeIncidenceBase(parent,incidence);
if (incidence->cancelled()) {
icalcomponent_add_property(parent,icalproperty_new_status(ICAL_STATUS_CANCELLED));
}
// creation date
icalcomponent_add_property(parent,icalproperty_new_created(
writeICalDateTime(incidence->created())));
// unique id
icalcomponent_add_property(parent,icalproperty_new_uid(
incidence->uid().utf8()));
// revision
icalcomponent_add_property(parent,icalproperty_new_sequence(
incidence->revision()));
// last modification date
icalcomponent_add_property(parent,icalproperty_new_lastmodified(
writeICalDateTime(incidence->lastModified())));
// description
if (!incidence->description().isEmpty()) {
icalcomponent_add_property(parent,icalproperty_new_description(
incidence->description().utf8()));
}
// summary
if (!incidence->summary().isEmpty()) {
icalcomponent_add_property(parent,icalproperty_new_summary(
incidence->summary().utf8()));
}
// location
if (!incidence->location().isEmpty()) {
icalcomponent_add_property(parent,icalproperty_new_location(
incidence->location().utf8()));
}
// TODO:
// status
// addPropValue(parent, VCStatusProp, incidence->getStatusStr().utf8());
// secrecy
enum icalproperty_class classInt;
switch (incidence->secrecy()) {
case Incidence::SecrecyPublic:
classInt = ICAL_CLASS_PUBLIC;
break;
case Incidence::SecrecyConfidential:
classInt = ICAL_CLASS_CONFIDENTIAL;
break;
case Incidence::SecrecyPrivate:
classInt =ICAL_CLASS_PRIVATE ;
default:
classInt =ICAL_CLASS_PRIVATE ;
break;
}
icalcomponent_add_property(parent,icalproperty_new_class(classInt));
// priority
icalcomponent_add_property(parent,icalproperty_new_priority(
incidence->priority()));
// categories
QStringList categories = incidence->categories();
QStringList::Iterator it;
for(it = categories.begin(); it != categories.end(); ++it ) {
icalcomponent_add_property(parent,icalproperty_new_categories((*it).utf8()));
}
// TODO: Ensure correct concatenation of categories properties.
/*
// categories
tmpStrList = incidence->getCategories();
tmpStr = "";
QString catStr;
for ( QStringList::Iterator it = tmpStrList.begin();
it != tmpStrList.end();
++it ) {
catStr = *it;
if (catStr[0] == ' ')
tmpStr += catStr.mid(1);
else
tmpStr += catStr;
// this must be a ';' character as the vCalendar specification requires!
// vcc.y has been hacked to translate the ';' to a ',' when the vcal is
// read in.
tmpStr += ";";
}
if (!tmpStr.isEmpty()) {
tmpStr.truncate(tmpStr.length()-1);
icalcomponent_add_property(parent,icalproperty_new_categories(
writeText(incidence->getCategories().join(";"))));
}
*/
// related event
if (incidence->relatedTo()) {
icalcomponent_add_property(parent,icalproperty_new_relatedto(
incidence->relatedTo()->uid().utf8()));
}
// recurrence rule stuff
Recurrence *recur = incidence->recurrence();
if (recur->doesRecur()) {
icalcomponent_add_property(parent,writeRecurrenceRule(recur));
}
// recurrence excpetion dates
DateList dateList = incidence->exDates();
DateList::ConstIterator exIt;
for(exIt = dateList.begin(); exIt != dateList.end(); ++exIt) {
icalcomponent_add_property(parent,icalproperty_new_exdate(
writeICalDate(*exIt)));
}
// attachments
QPtrList<Attachment> attachments = incidence->attachments();
for (Attachment *at = attachments.first(); at; at = attachments.next())
icalcomponent_add_property(parent,writeAttachment(at));
// alarms
QPtrList<Alarm> alarms = incidence->alarms();
Alarm* alarm;
for (alarm = alarms.first(); alarm; alarm = alarms.next()) {
if (alarm->enabled()) {
kdDebug(5800) << "Write alarm for " << incidence->summary() << endl;
icalcomponent_add_component(parent,writeAlarm(alarm));
}
}
if( incidence->hasRecurrenceID() ) {
icalcomponent_add_property(parent,
icalproperty_new_recurrenceid( writeICalDateTime( incidence->recurrenceID())));
}
// duration
// turned off as it always is set to PTS0 (and must not occur together with DTEND
-// if (incidence->hasDuration()) {
-// icaldurationtype duration;
-// duration = writeICalDuration(incidence->duration());
-// icalcomponent_add_property(parent,icalproperty_new_duration(duration));
-// }
+ if (incidence->hasDuration()) {
+ icaldurationtype duration;
+ duration = writeICalDuration(incidence->duration());
+ icalcomponent_add_property(parent,icalproperty_new_duration(duration));
+ }
}
void ICalFormatImpl::writeIncidenceBase(icalcomponent *parent,IncidenceBase *incidenceBase)
{
icalcomponent_add_property(parent,icalproperty_new_dtstamp(
writeICalDateTime(QDateTime::currentDateTime())));
// organizer stuff
icalcomponent_add_property(parent,icalproperty_new_organizer(
("MAILTO:" + incidenceBase->organizer()).utf8()));
// attendees
if (incidenceBase->attendeeCount() != 0) {
QPtrList<Attendee> al = incidenceBase->attendees();
QPtrListIterator<Attendee> ai(al);
for (; ai.current(); ++ai) {
icalcomponent_add_property(parent,writeAttendee(ai.current()));
}
}
// custom properties
writeCustomProperties(parent, incidenceBase);
}
void ICalFormatImpl::writeCustomProperties(icalcomponent *parent,CustomProperties *properties)
{
QMap<QCString, QString> custom = properties->customProperties();
for (QMap<QCString, QString>::Iterator c = custom.begin(); c != custom.end(); ++c) {
icalproperty *p = icalproperty_new_x(c.data().utf8());
icalproperty_set_x_name(p,c.key());
icalcomponent_add_property(parent,p);
}
}
icalproperty *ICalFormatImpl::writeAttendee(Attendee *attendee)
{
icalproperty *p = icalproperty_new_attendee("mailto:" + attendee->email().utf8());
if (!attendee->name().isEmpty()) {
icalproperty_add_parameter(p,icalparameter_new_cn(attendee->name().utf8()));
}
icalproperty_add_parameter(p,icalparameter_new_rsvp(
attendee->RSVP() ? ICAL_RSVP_TRUE : ICAL_RSVP_FALSE ));
icalparameter_partstat status = ICAL_PARTSTAT_NEEDSACTION;
switch (attendee->status()) {
default:
case Attendee::NeedsAction:
status = ICAL_PARTSTAT_NEEDSACTION;
break;
case Attendee::Accepted:
status = ICAL_PARTSTAT_ACCEPTED;
break;
case Attendee::Declined:
status = ICAL_PARTSTAT_DECLINED;
break;
case Attendee::Tentative:
status = ICAL_PARTSTAT_TENTATIVE;
break;
case Attendee::Delegated:
status = ICAL_PARTSTAT_DELEGATED;
break;
case Attendee::Completed:
status = ICAL_PARTSTAT_COMPLETED;
break;
case Attendee::InProcess:
status = ICAL_PARTSTAT_INPROCESS;
break;
}
icalproperty_add_parameter(p,icalparameter_new_partstat(status));
icalparameter_role role = ICAL_ROLE_REQPARTICIPANT;
switch (attendee->role()) {
case Attendee::Chair:
role = ICAL_ROLE_CHAIR;
break;
default:
case Attendee::ReqParticipant:
role = ICAL_ROLE_REQPARTICIPANT;
break;
case Attendee::OptParticipant:
role = ICAL_ROLE_OPTPARTICIPANT;
break;
case Attendee::NonParticipant:
role = ICAL_ROLE_NONPARTICIPANT;
break;
}
icalproperty_add_parameter(p,icalparameter_new_role(role));
if (!attendee->uid().isEmpty()) {
icalparameter* icalparameter_uid = icalparameter_new_x(attendee->uid().utf8());
icalparameter_set_xname(icalparameter_uid,"X-UID");
icalproperty_add_parameter(p,icalparameter_uid);
}
return p;
}
icalproperty *ICalFormatImpl::writeAttachment(Attachment *att)
{
#if 0
icalattachtype* attach = icalattachtype_new();
if (att->isURI())
icalattachtype_set_url(attach, att->uri().utf8().data());
else
icalattachtype_set_base64(attach, att->data(), 0);
#endif
icalattach *attach;
if (att->isURI())
attach = icalattach_new_from_url( att->uri().utf8().data());
else
attach = icalattach_new_from_data ( (unsigned char *)att->data(), 0, 0);
icalproperty *p = icalproperty_new_attach(attach);
if (!att->mimeType().isEmpty())
icalproperty_add_parameter(p,icalparameter_new_fmttype(att->mimeType().utf8().data()));
if (att->isBinary()) {
icalproperty_add_parameter(p,icalparameter_new_value(ICAL_VALUE_BINARY));
icalproperty_add_parameter(p,icalparameter_new_encoding(ICAL_ENCODING_BASE64));
}
return p;
}
icalproperty *ICalFormatImpl::writeRecurrenceRule(Recurrence *recur)
{
// kdDebug(5800) << "ICalFormatImpl::writeRecurrenceRule()" << endl;
icalrecurrencetype r;
icalrecurrencetype_clear(&r);
int index = 0;
int index2 = 0;
QPtrList<Recurrence::rMonthPos> tmpPositions;
QPtrList<int> tmpDays;
int *tmpDay;
Recurrence::rMonthPos *tmpPos;
bool datetime = false;
int day;
int i;
switch(recur->doesRecur()) {
case Recurrence::rMinutely:
r.freq = ICAL_MINUTELY_RECURRENCE;
datetime = true;
break;
case Recurrence::rHourly:
r.freq = ICAL_HOURLY_RECURRENCE;
datetime = true;
break;
case Recurrence::rDaily:
r.freq = ICAL_DAILY_RECURRENCE;
break;
case Recurrence::rWeekly:
r.freq = ICAL_WEEKLY_RECURRENCE;
r.week_start = static_cast<icalrecurrencetype_weekday>(recur->weekStart()%7 + 1);
for (i = 0; i < 7; i++) {
if (recur->days().testBit(i)) {
day = (i + 1)%7 + 1; // convert from Monday=0 to Sunday=1
r.by_day[index++] = icalrecurrencetype_day_day_of_week(day);
}
}
// r.by_day[index] = ICAL_RECURRENCE_ARRAY_MAX;
break;
case Recurrence::rMonthlyPos:
r.freq = ICAL_MONTHLY_RECURRENCE;
tmpPositions = recur->monthPositions();
for (tmpPos = tmpPositions.first();
tmpPos;
tmpPos = tmpPositions.next()) {
for (i = 0; i < 7; i++) {
if (tmpPos->rDays.testBit(i)) {
day = (i + 1)%7 + 1; // convert from Monday=0 to Sunday=1
day += tmpPos->rPos*8;
if (tmpPos->negative) day = -day;
r.by_day[index++] = day;
}
}
}
// r.by_day[index] = ICAL_RECURRENCE_ARRAY_MAX;
break;
case Recurrence::rMonthlyDay:
r.freq = ICAL_MONTHLY_RECURRENCE;
tmpDays = recur->monthDays();
for (tmpDay = tmpDays.first();
tmpDay;
tmpDay = tmpDays.next()) {
@@ -1580,395 +1580,396 @@ void ICalFormatImpl::readAlarm(icalcomponent *alarm,Incidence *incidence)
icalproperty_action action = icalproperty_get_action(p);
Alarm::Type type = Alarm::Display;
switch ( action ) {
case ICAL_ACTION_DISPLAY: type = Alarm::Display; break;
case ICAL_ACTION_AUDIO: type = Alarm::Audio; break;
case ICAL_ACTION_PROCEDURE: type = Alarm::Procedure; break;
case ICAL_ACTION_EMAIL: type = Alarm::Email; break;
default:
;
return;
}
ialarm->setType(type);
p = icalcomponent_get_first_property(alarm,ICAL_ANY_PROPERTY);
while (p) {
icalproperty_kind kind = icalproperty_isa(p);
switch (kind) {
case ICAL_TRIGGER_PROPERTY: {
icaltriggertype trigger = icalproperty_get_trigger(p);
if (icaltime_is_null_time(trigger.time)) {
if (icaldurationtype_is_null_duration(trigger.duration)) {
kdDebug(5800) << "ICalFormatImpl::readAlarm(): Trigger has no time and no duration." << endl;
} else {
Duration duration = icaldurationtype_as_int( trigger.duration );
icalparameter *param = icalproperty_get_first_parameter(p,ICAL_RELATED_PARAMETER);
if (param && icalparameter_get_related(param) == ICAL_RELATED_END)
ialarm->setEndOffset(duration);
else
ialarm->setStartOffset(duration);
}
} else {
ialarm->setTime(readICalDateTime(trigger.time));
}
break;
}
case ICAL_DURATION_PROPERTY: {
icaldurationtype duration = icalproperty_get_duration(p);
ialarm->setSnoozeTime(icaldurationtype_as_int(duration)/60);
break;
}
case ICAL_REPEAT_PROPERTY:
ialarm->setRepeatCount(icalproperty_get_repeat(p));
break;
// Only in DISPLAY and EMAIL and PROCEDURE alarms
case ICAL_DESCRIPTION_PROPERTY: {
QString description = QString::fromUtf8(icalproperty_get_description(p));
switch ( action ) {
case ICAL_ACTION_DISPLAY:
ialarm->setText( description );
break;
case ICAL_ACTION_PROCEDURE:
ialarm->setProgramArguments( description );
break;
case ICAL_ACTION_EMAIL:
ialarm->setMailText( description );
break;
default:
break;
}
break;
}
// Only in EMAIL alarm
case ICAL_SUMMARY_PROPERTY:
ialarm->setMailSubject(QString::fromUtf8(icalproperty_get_summary(p)));
break;
// Only in EMAIL alarm
case ICAL_ATTENDEE_PROPERTY: {
QString email = QString::fromUtf8(icalproperty_get_attendee(p));
QString name;
icalparameter *param = icalproperty_get_first_parameter(p,ICAL_CN_PARAMETER);
if (param) {
name = QString::fromUtf8(icalparameter_get_cn(param));
}
ialarm->addMailAddress(Person(name, email));
break;
}
// Only in AUDIO and EMAIL and PROCEDURE alarms
case ICAL_ATTACH_PROPERTY: {
icalattach *attach = icalproperty_get_attach(p);
QString url = QFile::decodeName(icalattach_get_url(attach));
switch ( action ) {
case ICAL_ACTION_AUDIO:
ialarm->setAudioFile( url );
break;
case ICAL_ACTION_PROCEDURE:
ialarm->setProgramFile( url );
break;
case ICAL_ACTION_EMAIL:
ialarm->addMailAttachment( url );
break;
default:
break;
}
break;
}
default:
break;
}
p = icalcomponent_get_next_property(alarm,ICAL_ANY_PROPERTY);
}
// custom properties
readCustomProperties(alarm, ialarm);
// TODO: check for consistency of alarm properties
}
icaltimetype ICalFormatImpl::writeICalDate(const QDate &date)
{
icaltimetype t;
t.year = date.year();
t.month = date.month();
t.day = date.day();
t.hour = 0;
t.minute = 0;
t.second = 0;
t.is_date = 1;
t.is_utc = 0;
t.zone = 0;
return t;
}
icaltimetype ICalFormatImpl::writeICalDateTime(const QDateTime &dt )
{
icaltimetype t;
t.is_date = 0;
t.zone = 0;
QDateTime datetime;
if ( mParent->utc() ) {
int offset = KGlobal::locale()->localTimeOffset( dt );
datetime = dt.addSecs ( -offset*60);
t.is_utc = 1;
}
else {
datetime = dt;
t.is_utc = 0;
}
t.year = datetime.date().year();
t.month = datetime.date().month();
t.day = datetime.date().day();
t.hour = datetime.time().hour();
t.minute = datetime.time().minute();
t.second = datetime.time().second();
//qDebug("*** time %s localtime %s ",dt .toString().latin1() ,datetime .toString().latin1() );
// if ( mParent->utc() ) {
// datetime = KGlobal::locale()->localTime( dt );
// qDebug("*** time %s localtime %s ",dt .toString().latin1() ,datetime .toString().latin1() );
// if (mParent->timeZoneId().isEmpty())
// t = icaltime_as_utc(t, 0);
// else
// t = icaltime_as_utc(t,mParent->timeZoneId().local8Bit());
// }
return t;
}
QDateTime ICalFormatImpl::readICalDateTime(icaltimetype t)
{
QDateTime dt (QDate(t.year,t.month,t.day),
QTime(t.hour,t.minute,t.second) );
if (t.is_utc) {
int offset = KGlobal::locale()->localTimeOffset( dt );
dt = dt.addSecs ( offset*60);
}
return dt;
}
QDate ICalFormatImpl::readICalDate(icaltimetype t)
{
return QDate(t.year,t.month,t.day);
}
icaldurationtype ICalFormatImpl::writeICalDuration(int seconds)
{
icaldurationtype d;
- d.weeks = seconds % gSecondsPerWeek;
- seconds -= d.weeks * gSecondsPerWeek;
- d.days = seconds % gSecondsPerDay;
- seconds -= d.days * gSecondsPerDay;
- d.hours = seconds % gSecondsPerHour;
- seconds -= d.hours * gSecondsPerHour;
- d.minutes = seconds % gSecondsPerMinute;
- seconds -= d.minutes * gSecondsPerMinute;
+ d.is_neg = (seconds<0)?1:0;
+ if (seconds<0) seconds = -seconds;
+
+ d.weeks = seconds / gSecondsPerWeek;
+ seconds %= gSecondsPerWeek;
+ d.days = seconds / gSecondsPerDay;
+ seconds %= gSecondsPerDay;
+ d.hours = seconds / gSecondsPerHour;
+ seconds %= gSecondsPerHour;
+ d.minutes = seconds / gSecondsPerMinute;
+ seconds %= gSecondsPerMinute;
d.seconds = seconds;
- d.is_neg = 0;
-
return d;
}
int ICalFormatImpl::readICalDuration(icaldurationtype d)
{
int result = 0;
result += d.weeks * gSecondsPerWeek;
result += d.days * gSecondsPerDay;
result += d.hours * gSecondsPerHour;
result += d.minutes * gSecondsPerMinute;
result += d.seconds;
if (d.is_neg) result *= -1;
return result;
}
icalcomponent *ICalFormatImpl::createCalendarComponent(Calendar *cal)
{
icalcomponent *calendar;
// Root component
calendar = icalcomponent_new(ICAL_VCALENDAR_COMPONENT);
icalproperty *p;
// Product Identifier
p = icalproperty_new_prodid(CalFormat::productId().utf8());
icalcomponent_add_property(calendar,p);
// TODO: Add time zone
// iCalendar version (2.0)
p = icalproperty_new_version(const_cast<char *>(_ICAL_VERSION));
icalcomponent_add_property(calendar,p);
// Custom properties
if( cal != 0 )
writeCustomProperties(calendar, cal);
return calendar;
}
// take a raw vcalendar (i.e. from a file on disk, clipboard, etc. etc.
// and break it down from its tree-like format into the dictionary format
// that is used internally in the ICalFormatImpl.
bool ICalFormatImpl::populate( Calendar *cal, icalcomponent *calendar)
{
// this function will populate the caldict dictionary and other event
// lists. It turns vevents into Events and then inserts them.
if (!calendar) return false;
// TODO: check for METHOD
#if 0
if ((curVO = isAPropertyOf(vcal, ICMethodProp)) != 0) {
char *methodType = 0;
methodType = fakeCString(vObjectUStringZValue(curVO));
if (mEnableDialogs)
KMessageBox::information(mTopWidget,
i18n("This calendar is an iTIP transaction of type \"%1\".")
.arg(methodType),
i18n("%1: iTIP Transaction").arg(CalFormat::application()));
delete methodType;
}
#endif
icalproperty *p;
p = icalcomponent_get_first_property(calendar,ICAL_PRODID_PROPERTY);
if (!p) {
// TODO: does no PRODID really matter?
// mParent->setException(new ErrorFormat(ErrorFormat::CalVersionUnknown));
// return false;
mLoadedProductId = "";
mCalendarVersion = 0;
} else {
mLoadedProductId = QString::fromUtf8(icalproperty_get_prodid(p));
mCalendarVersion = CalFormat::calendarVersion(mLoadedProductId);
delete mCompat;
mCompat = CompatFactory::createCompat( mLoadedProductId );
}
// TODO: check for unknown PRODID
#if 0
if (!mCalendarVersion
&& CalFormat::productId() != mLoadedProductId) {
// warn the user that we might have trouble reading non-known calendar.
if (mEnableDialogs)
KMessageBox::information(mTopWidget,
i18n("This vCalendar file was not created by KOrganizer "
"or any other product we support. Loading anyway..."),
i18n("%1: Unknown vCalendar Vendor").arg(CalFormat::application()));
}
#endif
p = icalcomponent_get_first_property(calendar,ICAL_VERSION_PROPERTY);
if (!p) {
mParent->setException(new ErrorFormat(ErrorFormat::CalVersionUnknown));
return false;
} else {
const char *version = icalproperty_get_version(p);
if (strcmp(version,"1.0") == 0) {
mParent->setException(new ErrorFormat(ErrorFormat::CalVersion1,
i18n("Expected iCalendar format")));
return false;
} else if (strcmp(version,"2.0") != 0) {
mParent->setException(new ErrorFormat(ErrorFormat::CalVersionUnknown));
return false;
}
}
// TODO: check for calendar format version
#if 0
// warn the user we might have trouble reading this unknown version.
if ((curVO = isAPropertyOf(vcal, VCVersionProp)) != 0) {
char *s = fakeCString(vObjectUStringZValue(curVO));
if (strcmp(_VCAL_VERSION, s) != 0)
if (mEnableDialogs)
KMessageBox::sorry(mTopWidget,
i18n("This vCalendar file has version %1.\n"
"We only support %2.")
.arg(s).arg(_VCAL_VERSION),
i18n("%1: Unknown vCalendar Version").arg(CalFormat::application()));
deleteStr(s);
}
#endif
// custom properties
readCustomProperties(calendar, cal);
// TODO: set time zone
#if 0
// set the time zone
if ((curVO = isAPropertyOf(vcal, VCTimeZoneProp)) != 0) {
char *s = fakeCString(vObjectUStringZValue(curVO));
cal->setTimeZone(s);
deleteStr(s);
}
#endif
// Store all events with a relatedTo property in a list for post-processing
mEventsRelate.clear();
mTodosRelate.clear();
// TODO: make sure that only actually added ecvens go to this lists.
icalcomponent *c;
// Iterate through all todos
c = icalcomponent_get_first_component(calendar,ICAL_VTODO_COMPONENT);
while (c) {
// kdDebug(5800) << "----Todo found" << endl;
Todo *todo = readTodo(c);
if (!cal->todo(todo->uid())) cal->addTodo(todo);
c = icalcomponent_get_next_component(calendar,ICAL_VTODO_COMPONENT);
}
// Iterate through all events
c = icalcomponent_get_first_component(calendar,ICAL_VEVENT_COMPONENT);
while (c) {
// kdDebug(5800) << "----Event found" << endl;
Event *event = readEvent(c);
if (!cal->event(event->uid())) cal->addEvent(event);
c = icalcomponent_get_next_component(calendar,ICAL_VEVENT_COMPONENT);
}
// Iterate through all journals
c = icalcomponent_get_first_component(calendar,ICAL_VJOURNAL_COMPONENT);
while (c) {
// kdDebug(5800) << "----Journal found" << endl;
Journal *journal = readJournal(c);
if (!cal->journal(journal->uid())) cal->addJournal(journal);
c = icalcomponent_get_next_component(calendar,ICAL_VJOURNAL_COMPONENT);
}
#if 0
initPropIterator(&i, vcal);
// go through all the vobjects in the vcal
while (moreIteration(&i)) {
curVO = nextVObject(&i);
/************************************************************************/
// now, check to see that the object is an event or todo.
if (strcmp(vObjectName(curVO), VCEventProp) == 0) {
diff --git a/libkcal/incidencebase.cpp b/libkcal/incidencebase.cpp
index 51f2e9d..1e99082 100644
--- a/libkcal/incidencebase.cpp
+++ b/libkcal/incidencebase.cpp
@@ -1,307 +1,314 @@
/*
This file is part of libkcal.
Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
*/
#include <kglobal.h>
#include <klocale.h>
#include <kdebug.h>
#include <kidmanager.h>
#include "calformat.h"
#include "syncdefines.h"
#include "incidencebase.h"
using namespace KCal;
IncidenceBase::IncidenceBase() :
mReadOnly(false), mFloats(true), mDuration(0), mHasDuration(false),
mPilotId(0), mSyncStatus(SYNCMOD)
{
setUid(CalFormat::createUniqueId());
mOrganizer = "";
mFloats = false;
mDuration = 0;
mHasDuration = false;
mPilotId = 0;
mExternalId = ":";
mTempSyncStat = SYNC_TEMPSTATE_INITIAL;
mSyncStatus = 0;
mAttendees.setAutoDelete( true );
}
IncidenceBase::IncidenceBase(const IncidenceBase &i) :
CustomProperties( i )
{
mReadOnly = i.mReadOnly;
mDtStart = i.mDtStart;
mDuration = i.mDuration;
mHasDuration = i.mHasDuration;
mOrganizer = i.mOrganizer;
mUid = i.mUid;
QPtrList<Attendee> attendees = i.attendees();
for( Attendee *a = attendees.first(); a; a = attendees.next() ) {
mAttendees.append( new Attendee( *a ) );
}
mFloats = i.mFloats;
mLastModified = i.mLastModified;
mPilotId = i.mPilotId;
mTempSyncStat = i.mTempSyncStat;
mSyncStatus = i.mSyncStatus;
mExternalId = i.mExternalId;
// The copied object is a new one, so it isn't observed by the observer
// of the original object.
mObservers.clear();
mAttendees.setAutoDelete( true );
}
IncidenceBase::~IncidenceBase()
{
}
bool KCal::operator==( const IncidenceBase& i1, const IncidenceBase& i2 )
{
// do not compare mSyncStatus and mExternalId
if( i1.attendees().count() != i2.attendees().count() ) {
return false; // no need to check further
}
if ( i1.attendees().count() > 0 ) {
Attendee * a1 = i1.attendees().first(), *a2 =i2.attendees().first() ;
while ( a1 ) {
if ( !( (*a1) == (*a2)) )
{
//qDebug("Attendee not equal ");
return false;
}
a1 = i1.attendees().next();
a2 = i2.attendees().next();
}
}
//if ( i1.dtStart() != i2.dtStart() )
// return false;
#if 0
qDebug("1 %d ",i1.doesFloat() == i2.doesFloat() );
qDebug("1 %d ",i1.duration() == i2.duration() );
qDebug("3 %d ",i1.hasDuration() == i2.hasDuration() );
qDebug("1 %d ",i1.pilotId() == i2.pilotId() );
qDebug("1 %d %d %d",i1.syncStatus() == i2.syncStatus() , i1.syncStatus(),i2.syncStatus() );
qDebug("6 %d ",i1.organizer() == i2.organizer() );
#endif
+ if ( i1.hasDuration() == i2.hasDuration() ) {
+ if ( i1.hasDuration() ) {
+ if ( i1.duration() != i2.duration() )
+ return false;
+ }
+ } else {
+ return false;
+ }
+
return ( i1.organizer() == i2.organizer() &&
// i1.uid() == i2.uid() &&
// Don't compare lastModified, otherwise the operator is not
// of much use. We are not comparing for identity, after all.
i1.doesFloat() == i2.doesFloat() &&
- i1.duration() == i2.duration() &&
- i1.hasDuration() == i2.hasDuration() &&
i1.pilotId() == i2.pilotId() );// && i1.syncStatus() == i2.syncStatus() );
// no need to compare mObserver
}
QDateTime IncidenceBase::getEvenTime( QDateTime dt )
{
QTime t = dt.time();
dt.setTime( QTime (t.hour (), t.minute (), t.second () ) );
return dt;
}
void IncidenceBase::setUid(const QString &uid)
{
mUid = uid;
updated();
}
QString IncidenceBase::uid() const
{
return mUid;
}
void IncidenceBase::setLastModified(const QDateTime &lm)
{
// DON'T! updated() because we call this from
// Calendar::updateEvent().
mLastModified = getEvenTime(lm);
//qDebug("IncidenceBase::setLastModified %s ",lm.toString().latin1());
}
QDateTime IncidenceBase::lastModified() const
{
return mLastModified;
}
void IncidenceBase::setOrganizer(const QString &o)
{
// we don't check for readonly here, because it is
// possible that by setting the organizer we are changing
// the event's readonly status...
mOrganizer = o;
if (mOrganizer.left(7).upper() == "MAILTO:")
mOrganizer = mOrganizer.remove(0,7);
updated();
}
QString IncidenceBase::organizer() const
{
return mOrganizer;
}
void IncidenceBase::setReadOnly( bool readOnly )
{
mReadOnly = readOnly;
}
void IncidenceBase::setDtStart(const QDateTime &dtStart)
{
// if (mReadOnly) return;
mDtStart = getEvenTime(dtStart);
updated();
}
QDateTime IncidenceBase::dtStart() const
{
return mDtStart;
}
QString IncidenceBase::dtStartTimeStr() const
{
return KGlobal::locale()->formatTime(dtStart().time());
}
QString IncidenceBase::dtStartDateStr(bool shortfmt) const
{
return KGlobal::locale()->formatDate(dtStart().date(),shortfmt);
}
QString IncidenceBase::dtStartStr(bool shortfmt) const
{
return KGlobal::locale()->formatDateTime(dtStart(), shortfmt);
}
bool IncidenceBase::doesFloat() const
{
return mFloats;
}
void IncidenceBase::setFloats(bool f)
{
if (mReadOnly) return;
mFloats = f;
updated();
}
bool IncidenceBase::addAttendee(Attendee *a, bool doupdate)
{
if (mReadOnly) return false;
if (a->name().left(7).upper() == "MAILTO:")
a->setName(a->name().remove(0,7));
QPtrListIterator<Attendee> qli(mAttendees);
qli.toFirst();
while (qli) {
if (*qli.current() == *a)
return false;
++qli;
}
mAttendees.append(a);
if (doupdate) updated();
return true;
}
#if 0
void IncidenceBase::removeAttendee(Attendee *a)
{
if (mReadOnly) return;
mAttendees.removeRef(a);
updated();
}
void IncidenceBase::removeAttendee(const char *n)
{
Attendee *a;
if (mReadOnly) return;
for (a = mAttendees.first(); a; a = mAttendees.next())
if (a->getName() == n) {
mAttendees.remove();
break;
}
}
#endif
void IncidenceBase::clearAttendees()
{
if (mReadOnly) return;
mAttendees.clear();
}
#if 0
Attendee *IncidenceBase::getAttendee(const char *n) const
{
QPtrListIterator<Attendee> qli(mAttendees);
qli.toFirst();
while (qli) {
if (qli.current()->getName() == n)
return qli.current();
++qli;
}
return 0L;
}
#endif
Attendee *IncidenceBase::attendeeByMail(const QString &email)
{
QPtrListIterator<Attendee> qli(mAttendees);
qli.toFirst();
while (qli) {
if (qli.current()->email().lower() == email.lower())
return qli.current();
++qli;
}
return 0L;
}
Attendee *IncidenceBase::attendeeByMails(const QStringList &emails, const QString& email)
{
QPtrListIterator<Attendee> qli(mAttendees);
QStringList mails = emails;
if (!email.isEmpty()) {
mails.append(email);
}
qli.toFirst();
while (qli) {
for ( QStringList::Iterator it = mails.begin(); it != mails.end(); ++it ) {
if (qli.current()->email().lower() == (*it).lower())
return qli.current();
}
++qli;
}