summaryrefslogtreecommitdiffabout
path: root/libkcal
authorzautrix <zautrix>2005-07-27 22:26:08 (UTC)
committer zautrix <zautrix>2005-07-27 22:26:08 (UTC)
commit0e38cffd7ba745f237c659e1c48080fcb25b126c (patch) (side-by-side diff)
tree6069600e18bae5300c6ce427735457dbfed93141 /libkcal
parent136f9082862e7a56abb3a201e96f5e7386c4f1b9 (diff)
downloadkdepimpi-0e38cffd7ba745f237c659e1c48080fcb25b126c.zip
kdepimpi-0e38cffd7ba745f237c659e1c48080fcb25b126c.tar.gz
kdepimpi-0e38cffd7ba745f237c659e1c48080fcb25b126c.tar.bz2
rec changes
Diffstat (limited to 'libkcal') (more/less context) (show whitespace changes)
-rw-r--r--libkcal/event.cpp1
-rw-r--r--libkcal/icalformatimpl.cpp10
-rw-r--r--libkcal/incidence.cpp53
-rw-r--r--libkcal/incidence.h5
-rw-r--r--libkcal/kincidenceformatter.cpp4
-rw-r--r--libkcal/vcalformat.cpp4
-rw-r--r--libkcal/vcalformat.h2
7 files changed, 55 insertions, 24 deletions
diff --git a/libkcal/event.cpp b/libkcal/event.cpp
index ad66639..0766fd9 100644
--- a/libkcal/event.cpp
+++ b/libkcal/event.cpp
@@ -1,415 +1,416 @@
/*
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 "event.h"
using namespace KCal;
Event::Event() :
mHasEndDate( false ), mTransparency( Opaque )
{
}
Event::Event(const Event &e) : Incidence(e)
{
mDtEnd = e.mDtEnd;
mHasEndDate = e.mHasEndDate;
mTransparency = e.mTransparency;
}
Event::~Event()
{
}
Incidence *Event::clone()
{
return new Event(*this);
}
bool KCal::operator==( const Event& e1, const Event& e2 )
{
return operator==( (const Incidence&)e1, (const Incidence&)e2 ) &&
e1.dtEnd() == e2.dtEnd() &&
e1.hasEndDate() == e2.hasEndDate() &&
e1.transparency() == e2.transparency();
}
bool Event::contains ( Event* from )
{
if ( !from->summary().isEmpty() )
if ( !summary().startsWith( from->summary() ))
return false;
if ( from->dtStart().isValid() )
if (dtStart() != from->dtStart() )
return false;
if ( from->dtEnd().isValid() )
if ( dtEnd() != from->dtEnd() )
return false;
if ( !from->location().isEmpty() )
if ( !location().startsWith( from->location() ) )
return false;
if ( !from->description().isEmpty() )
if ( !description().startsWith( from->description() ))
return false;
if ( from->alarms().count() ) {
Alarm *a = from->alarms().first();
if ( a->enabled() ){
if ( !alarms().count() )
return false;
Alarm *b = alarms().first();
if( ! b->enabled() )
return false;
if ( ! (a->offset() == b->offset() ))
return false;
}
}
QStringList cat = categories();
QStringList catFrom = from->categories();
QString nCat;
unsigned int iii;
for ( iii = 0; iii < catFrom.count();++iii ) {
nCat = catFrom[iii];
if ( !nCat.isEmpty() )
if ( !cat.contains( nCat )) {
return false;
}
}
if ( from->doesRecur() )
if ( from->doesRecur() != doesRecur() && ! (from->doesRecur()== Recurrence::rYearlyMonth && doesRecur()== Recurrence::rYearlyDay) )
return false;
return true;
}
void Event::setDtEnd(const QDateTime &dtEnd)
{
if (mReadOnly) return;
mDtEnd = getEvenTime( dtEnd );
setHasEndDate(true);
setHasDuration(false);
updated();
}
QDateTime Event::dtEnd() const
{
if (hasEndDate()) return mDtEnd;
if (hasDuration()) return dtStart().addSecs(duration());
return dtStart();
}
QString Event::dtEndTimeStr() const
{
return KGlobal::locale()->formatTime(mDtEnd.time());
}
QString Event::dtEndDateStr(bool shortfmt) const
{
return KGlobal::locale()->formatDate(mDtEnd.date(),shortfmt);
}
QString Event::dtEndStr(bool shortfmt) const
{
return KGlobal::locale()->formatDateTime(mDtEnd, shortfmt);
}
void Event::setHasEndDate(bool b)
{
mHasEndDate = b;
}
bool Event::hasEndDate() const
{
return mHasEndDate;
}
bool Event::isMultiDay() const
{
bool multi = !(dtStart().date() == dtEnd().date());
return multi;
}
void Event::setTransparency(Event::Transparency transparency)
{
if (mReadOnly) return;
mTransparency = transparency;
updated();
}
Event::Transparency Event::transparency() const
{
return mTransparency;
}
void Event::setDuration(int seconds)
{
setHasEndDate(false);
Incidence::setDuration(seconds);
}
bool Event::matchTime(QDateTime*startDT, QDateTime* endDT)
{
+ if ( cancelled() ) return false;
if ( ! doesRecur() ) {
if ( doesFloat() ) {
if ( mDtEnd.addDays( 1 ) < *startDT)
return false;
if ( endDT && mDtStart > * endDT)
return false;
} else {
if ( mDtEnd < *startDT )
return false;
if ( endDT && mDtStart > * endDT)
return false;
}
} else {
if ( endDT && mDtStart > * endDT)
return false;
}
return true;
}
bool Event::isOverlapping ( Event* testEvent, QDateTime* overlapDT, QDateTime* startDT )
{
if ( testEvent == this )
return false;
if ( ! doesRecur() && !testEvent->doesRecur() ) {
QDateTime te;
if ( testEvent->doesFloat() )
te = testEvent->mDtEnd.addDays( 1 );
else
te = testEvent->mDtEnd;
QDateTime e;
if ( doesFloat() )
e = mDtEnd.addDays( 1 );
else
e = mDtEnd;
if ( mDtStart < te && testEvent->mDtStart < e ) {
if ( mDtStart < testEvent->mDtStart )
*overlapDT = testEvent->mDtStart;
else
*overlapDT = mDtStart;
if ( startDT )
return (*overlapDT >= *startDT );
return true;
}
return false;
}
if ( !doesFloat() && !testEvent->doesFloat() && !isMultiDay() && !testEvent->isMultiDay() ) {
if ( mDtStart.time() >= testEvent->mDtEnd.time() || testEvent->mDtStart.time() >= mDtEnd.time() ) {
// no need to test. times mismatch
//fprintf(stderr,"timi ");
return false;
}
}
Event *nonRecur = 0;
Event *recurEvent = 0;
if ( ! doesRecur() ) {
nonRecur = this;
recurEvent = testEvent;
}
else if ( !testEvent->doesRecur() ) {
nonRecur = testEvent;
recurEvent = this;
}
if ( nonRecur ) {
QDateTime enr;
if ( nonRecur->doesFloat() )
enr = nonRecur->mDtEnd.addDays( 1 );
else
enr = nonRecur->mDtEnd;
if ( enr < recurEvent->mDtStart )
return false;
if ( startDT && enr < *startDT )
return false;
int recDuration = recurEvent->mDtStart.secsTo( recurEvent->mDtEnd );
if ( recurEvent->doesFloat() )
recDuration += 86400;
bool ok = false;
QDateTime recStart;
if ( startDT ) {
recStart = recurEvent->recurrence()->getPreviousDateTime( startDT->addSecs( 61 ), &ok );
}
if ( recStart.isValid() ) {
//qDebug("%s start at %s ", startDT-> toString().latin1(), recStart.toString().latin1());
recStart = recStart.addSecs( -300);
}
else
recStart = recurEvent->mDtStart.addSecs( -300);
ok = true;
while ( ok ) {
recStart = recurEvent->getNextOccurence( recStart.addSecs( 60 ), &ok );
if ( ok ) {
if ( recStart > enr )
return false;
QDateTime recEnd = recStart.addSecs( recDuration );
if ( nonRecur->mDtStart < recEnd && recStart < nonRecur->mDtEnd ) {
if ( nonRecur->mDtStart < recStart )
*overlapDT = recStart;
else
*overlapDT = nonRecur->mDtStart;
if ( startDT ) {
if ( *overlapDT >= *startDT )
return true;
} else
return true;
}
}
}
return false;
}
if ( !doesFloat() && !testEvent->doesFloat() && !isMultiDay() && !testEvent->isMultiDay() ) {
if ( recurrence()->doesRecur() == Recurrence::rWeekly && testEvent->recurrence()->doesRecur() == Recurrence::rWeekly ) {
bool found = false;
uint i;
for ( i=0; i< recurrence()->days().size();++i ) {
found = found || (recurrence()->days().testBit( i ) && testEvent->recurrence()->days().testBit( i ) );
}
if ( ! found ) {
//qDebug("recurring days mismatch %s -- %s", summary().latin1(),testEvent->summary().latin1());
return false;
}
}
}
bool ok = true;
QDateTime incidenceStart;// = mDtStart;
QDateTime testincidenceStart;// = testEvent->mDtStart;
if ( startDT ) {
incidenceStart = recurrence()->getPreviousDateTime( startDT->addSecs( 61 ), &ok );
testincidenceStart = testEvent->recurrence()->getPreviousDateTime( startDT->addSecs( 61 ), &ok );
}
if ( !testincidenceStart.isValid() )
testincidenceStart = testEvent->mDtStart;
if ( !incidenceStart.isValid() )
incidenceStart = mDtStart;
int duration = mDtStart.secsTo( mDtEnd );
if ( doesFloat() )
duration += 86400;
int testduration = testEvent->mDtStart.secsTo( testEvent->mDtEnd );
if ( testEvent->doesFloat() )
testduration += 86400;
bool computeThis = false;
if ( incidenceStart < testincidenceStart )
computeThis = true;
if ( computeThis )
incidenceStart = incidenceStart.addSecs( -300 );
else
testincidenceStart = testincidenceStart.addSecs( -300 );
int count = 0;
ok = true;
int countbreak = 2000;
QDateTime stopSearch;
bool testStop = false;
if ( startDT ) {
stopSearch = startDT->addDays( 365*3 );
testStop = true;
}
while ( ok ) {
++count;
if ( count > countbreak ) break;
if ( computeThis ) {
if ( testStop )
if ( testincidenceStart > stopSearch )
break;
incidenceStart = getNextOccurence( incidenceStart.addSecs( 60 ), &ok );
}
else {
if ( testStop )
if ( incidenceStart > stopSearch )
break;
testincidenceStart = testEvent->getNextOccurence( testincidenceStart.addSecs( 60 ), &ok );
}
if ( ok ) {
if ( incidenceStart < testincidenceStart.addSecs( testduration ) && testincidenceStart < incidenceStart.addSecs( duration ) ) {
if ( incidenceStart < testincidenceStart )
*overlapDT = testincidenceStart;
else
*overlapDT = incidenceStart;
if ( startDT ) {
if ( *overlapDT >= *startDT )
return true;
} else
return true;
}
computeThis = ( incidenceStart < testincidenceStart );
}
}
//qDebug("%d rec counter stopped at %d - %s %s", ok ,count, summary().latin1(),testEvent->summary().latin1() );
return false;
}
QDateTime Event::getNextAlarmDateTime( bool * ok, int * offset, QDateTime start_dt ) const
{
*ok = false;
if ( !alarmEnabled() )
return QDateTime ();
bool yes;
QDateTime incidenceStart = getNextOccurence( start_dt, &yes );
if ( ! yes || cancelled() ) {
*ok = false;
return QDateTime ();
}
bool enabled = false;
Alarm* alarm;
int off = 0;
QDateTime alarmStart = QDateTime::currentDateTime().addDays( 3650 );;
// if ( QDateTime::currentDateTime() > incidenceStart ){
// *ok = false;
// return incidenceStart;
// }
for (QPtrListIterator<Alarm> it(mAlarms); (alarm = it.current()) != 0; ++it) {
if (alarm->enabled()) {
if ( alarm->hasTime () ) {
if ( alarm->time() < alarmStart ) {
alarmStart = alarm->time();
enabled = true;
off = alarmStart.secsTo( incidenceStart );
}
} else {
int secs = alarm->startOffset().asSeconds();
if ( incidenceStart.addSecs( secs ) < alarmStart ) {
alarmStart = incidenceStart.addSecs( secs );
enabled = true;
off = -secs;
}
}
}
}
if ( enabled ) {
if ( alarmStart > start_dt ) {
*ok = true;
* offset = off;
return alarmStart;
}
}
*ok = false;
return QDateTime ();
}
diff --git a/libkcal/icalformatimpl.cpp b/libkcal/icalformatimpl.cpp
index 4794bc9..f349681 100644
--- a/libkcal/icalformatimpl.cpp
+++ b/libkcal/icalformatimpl.cpp
@@ -1,2065 +1,2063 @@
/*
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 <qdatetime.h>
#include <qstring.h>
#include <qptrlist.h>
#include <qfile.h>
#include <kdebug.h>
#include <klocale.h>
#include <kglobal.h>
extern "C" {
#include <ical.h>
#include <icalss.h>
#include <icalparser.h>
#include <icalrestriction.h>
}
#include "calendar.h"
#include "journal.h"
#include "icalformat.h"
#include "icalformatimpl.h"
#include "compat.h"
#define _ICAL_VERSION "2.0"
using namespace KCal;
const int gSecondsPerMinute = 60;
const int gSecondsPerHour = gSecondsPerMinute * 60;
const int gSecondsPerDay = gSecondsPerHour * 24;
const int gSecondsPerWeek = gSecondsPerDay * 7;
ICalFormatImpl::ICalFormatImpl( ICalFormat *parent ) :
mParent( parent ), mCalendarVersion( 0 )
{
mCompat = new Compat;
}
ICalFormatImpl::~ICalFormatImpl()
{
delete mCompat;
}
class ToStringVisitor : public Incidence::Visitor
{
public:
ToStringVisitor( ICalFormatImpl *impl ) : mImpl( impl ), mComponent( 0 ) {}
bool visit( Event *e ) { mComponent = mImpl->writeEvent( e ); return true; }
bool visit( Todo *e ) { mComponent = mImpl->writeTodo( e ); return true; }
bool visit( Journal *e ) { mComponent = mImpl->writeJournal( e ); return true; }
icalcomponent *component() { return mComponent; }
private:
ICalFormatImpl *mImpl;
icalcomponent *mComponent;
};
icalcomponent *ICalFormatImpl::writeIncidence(Incidence *incidence)
{
ToStringVisitor v( this );
incidence->accept(v);
return v.component();
}
icalcomponent *ICalFormatImpl::writeTodo(Todo *todo)
{
QString tmpStr;
QStringList tmpStrList;
icalcomponent *vtodo = icalcomponent_new(ICAL_VTODO_COMPONENT);
writeIncidence(vtodo,todo);
// due date
if (todo->hasDueDate()) {
icaltimetype due;
if (todo->doesFloat()) {
due = writeICalDate(todo->dtDue().date());
} else {
due = writeICalDateTime(todo->dtDue());
}
icalcomponent_add_property(vtodo,icalproperty_new_due(due));
}
// start time
if (todo->hasStartDate()) {
icaltimetype start;
if (todo->doesFloat()) {
// kdDebug(5800) << "§§ Incidence " << todo->summary() << " floats." << endl;
start = writeICalDate(todo->dtStart().date());
} else {
// kdDebug(5800) << "§§ incidence " << todo->summary() << " has time." << endl;
start = writeICalDateTime(todo->dtStart());
}
icalcomponent_add_property(vtodo,icalproperty_new_dtstart(start));
}
// completion date
if (todo->isCompleted()) {
if (!todo->hasCompletedDate()) {
// If todo was created by KOrganizer <2.2 it has no correct completion
// date. Set it to now.
todo->setCompleted(QDateTime::currentDateTime());
}
icaltimetype completed = writeICalDateTime(todo->completed());
icalcomponent_add_property(vtodo,icalproperty_new_completed(completed));
}
icalcomponent_add_property(vtodo,
icalproperty_new_percentcomplete(todo->percentComplete()));
return vtodo;
}
icalcomponent *ICalFormatImpl::writeEvent(Event *event)
{
kdDebug(5800) << "Write Event '" << event->summary() << "' (" << event->uid()
<< ")" << endl;
QString tmpStr;
QStringList tmpStrList;
icalcomponent *vevent = icalcomponent_new(ICAL_VEVENT_COMPONENT);
writeIncidence(vevent,event);
// start time
icaltimetype start;
if (event->doesFloat()) {
// kdDebug(5800) << "§§ Incidence " << event->summary() << " floats." << endl;
start = writeICalDate(event->dtStart().date());
} else {
// kdDebug(5800) << "§§ incidence " << event->summary() << " has time." << endl;
start = writeICalDateTime(event->dtStart());
}
icalcomponent_add_property(vevent,icalproperty_new_dtstart(start));
if (event->hasEndDate()) {
// end time
icaltimetype end;
if (event->doesFloat()) {
// kdDebug(5800) << "§§ Event " << event->summary() << " floats." << endl;
// +1 day because end date is non-inclusive.
end = writeICalDate( event->dtEnd().date().addDays( 1 ) );
} else {
// kdDebug(5800) << "§§ Event " << event->summary() << " has time." << endl;
end = writeICalDateTime(event->dtEnd());
}
icalcomponent_add_property(vevent,icalproperty_new_dtend(end));
}
// TODO: attachments, resources
#if 0
// attachments
tmpStrList = anEvent->attachments();
for ( QStringList::Iterator it = tmpStrList.begin();
it != tmpStrList.end();
++it )
addPropValue(vevent, VCAttachProp, (*it).utf8());
// resources
tmpStrList = anEvent->resources();
tmpStr = tmpStrList.join(";");
if (!tmpStr.isEmpty())
addPropValue(vevent, VCResourcesProp, tmpStr.utf8());
#endif
// Transparency
switch( event->transparency() ) {
case Event::Transparent:
icalcomponent_add_property(vevent, icalproperty_new_transp(ICAL_TRANSP_TRANSPARENT));
break;
case Event::Opaque:
icalcomponent_add_property(vevent, icalproperty_new_transp(ICAL_TRANSP_OPAQUE));
break;
}
return vevent;
}
icalcomponent *ICalFormatImpl::writeFreeBusy(FreeBusy *freebusy,
Scheduler::Method method)
{
icalcomponent *vfreebusy = icalcomponent_new(ICAL_VFREEBUSY_COMPONENT);
writeIncidenceBase(vfreebusy,freebusy);
icalcomponent_add_property(vfreebusy, icalproperty_new_dtstart(
writeICalDateTime(freebusy->dtStart())));
icalcomponent_add_property(vfreebusy, icalproperty_new_dtend(
writeICalDateTime(freebusy->dtEnd())));
if (method == Scheduler::Request) {
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->relatedToUid().isEmpty()) {
icalcomponent_add_property(parent,icalproperty_new_relatedto(
incidence->relatedToUid().utf8()));
}
// recurrence rule stuff
- Recurrence *recur = incidence->recurrence();
- if (recur->doesRecur()) {
-
- icalcomponent_add_property(parent,writeRecurrenceRule(recur));
- }
-
+ if (incidence->doesRecur()) {
+ icalcomponent_add_property(parent,writeRecurrenceRule(incidence->recurrence()));
// 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));
}
}
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()) {
r.by_month_day[index++] = icalrecurrencetype_day_position(*tmpDay*8);//*tmpDay);
}
// r.by_day[index] = ICAL_RECURRENCE_ARRAY_MAX;
break;
case Recurrence::rYearlyMonth:
case Recurrence::rYearlyPos:
r.freq = ICAL_YEARLY_RECURRENCE;
tmpDays = recur->yearNums();
for (tmpDay = tmpDays.first();
tmpDay;
tmpDay = tmpDays.next()) {
r.by_month[index++] = *tmpDay;
}
// r.by_set_pos[index] = ICAL_RECURRENCE_ARRAY_MAX;
if (recur->doesRecur() == Recurrence::rYearlyPos) {
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[index2++] = day;
}
}
}
// r.by_day[index2] = ICAL_RECURRENCE_ARRAY_MAX;
}
break;
case Recurrence::rYearlyDay:
r.freq = ICAL_YEARLY_RECURRENCE;
tmpDays = recur->yearNums();
for (tmpDay = tmpDays.first();
tmpDay;
tmpDay = tmpDays.next()) {
r.by_year_day[index++] = *tmpDay;
}
// r.by_year_day[index] = ICAL_RECURRENCE_ARRAY_MAX;
break;
default:
r.freq = ICAL_NO_RECURRENCE;
kdDebug(5800) << "ICalFormatImpl::writeRecurrence(): no recurrence" << endl;
break;
}
r.interval = recur->frequency();
if (recur->duration() > 0) {
r.count = recur->duration();
} else if (recur->duration() == -1) {
r.count = 0;
} else {
if (datetime)
r.until = writeICalDateTime(recur->endDateTime());
else
r.until = writeICalDate(recur->endDate());
}
// Debug output
#if 0
const char *str = icalrecurrencetype_as_string(&r);
if (str) {
kdDebug(5800) << " String: " << str << endl;
} else {
kdDebug(5800) << " No String" << endl;
}
#endif
return icalproperty_new_rrule(r);
}
icalcomponent *ICalFormatImpl::writeAlarm(Alarm *alarm)
{
icalcomponent *a = icalcomponent_new(ICAL_VALARM_COMPONENT);
icalproperty_action action;
icalattach *attach = 0;
switch (alarm->type()) {
case Alarm::Procedure:
action = ICAL_ACTION_PROCEDURE;
attach = icalattach_new_from_url( QFile::encodeName(alarm->programFile()).data() );
icalcomponent_add_property(a,icalproperty_new_attach(attach));
if (!alarm->programArguments().isEmpty()) {
icalcomponent_add_property(a,icalproperty_new_description(alarm->programArguments().utf8()));
}
icalattach_unref( attach );
break;
case Alarm::Audio:
action = ICAL_ACTION_AUDIO;
if (!alarm->audioFile().isEmpty()) {
attach = icalattach_new_from_url(QFile::encodeName( alarm->audioFile() ).data());
icalcomponent_add_property(a,icalproperty_new_attach(attach));
icalattach_unref( attach );
}
break;
case Alarm::Email: {
action = ICAL_ACTION_EMAIL;
QValueList<Person> addresses = alarm->mailAddresses();
for (QValueList<Person>::Iterator ad = addresses.begin(); ad != addresses.end(); ++ad) {
icalproperty *p = icalproperty_new_attendee("MAILTO:" + (*ad).email().utf8());
if (!(*ad).name().isEmpty()) {
icalproperty_add_parameter(p,icalparameter_new_cn((*ad).name().utf8()));
}
icalcomponent_add_property(a,p);
}
icalcomponent_add_property(a,icalproperty_new_summary(alarm->mailSubject().utf8()));
icalcomponent_add_property(a,icalproperty_new_description(alarm->text().utf8()));
QStringList attachments = alarm->mailAttachments();
if (attachments.count() > 0) {
for (QStringList::Iterator at = attachments.begin(); at != attachments.end(); ++at) {
attach = icalattach_new_from_url(QFile::encodeName( *at ).data());
icalcomponent_add_property(a,icalproperty_new_attach(attach));
icalattach_unref( attach );
}
}
break;
}
case Alarm::Display:
action = ICAL_ACTION_DISPLAY;
icalcomponent_add_property(a,icalproperty_new_description(alarm->text().utf8()));
break;
case Alarm::Invalid:
default:
kdDebug(5800) << "Unknown type of alarm" << endl;
action = ICAL_ACTION_NONE;
break;
}
icalcomponent_add_property(a,icalproperty_new_action(action));
// Trigger time
icaltriggertype trigger;
if ( alarm->hasTime() ) {
trigger.time = writeICalDateTime(alarm->time());
trigger.duration = icaldurationtype_null_duration();
} else {
trigger.time = icaltime_null_time();
Duration offset;
if ( alarm->hasStartOffset() )
offset = alarm->startOffset();
else
offset = alarm->endOffset();
trigger.duration = icaldurationtype_from_int( offset.asSeconds() );
}
icalproperty *p = icalproperty_new_trigger(trigger);
if ( alarm->hasEndOffset() )
icalproperty_add_parameter(p,icalparameter_new_related(ICAL_RELATED_END));
icalcomponent_add_property(a,p);
// Repeat count and duration
if (alarm->repeatCount()) {
icalcomponent_add_property(a,icalproperty_new_repeat(alarm->repeatCount()));
icalcomponent_add_property(a,icalproperty_new_duration(
icaldurationtype_from_int(alarm->snoozeTime()*60)));
}
// Custom properties
QMap<QCString, QString> custom = alarm->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(a,p);
}
return a;
}
Todo *ICalFormatImpl::readTodo(icalcomponent *vtodo)
{
Todo *todo = new Todo;
readIncidence(vtodo,todo);
icalproperty *p = icalcomponent_get_first_property(vtodo,ICAL_ANY_PROPERTY);
// int intvalue;
icaltimetype icaltime;
QStringList categories;
while (p) {
icalproperty_kind kind = icalproperty_isa(p);
switch (kind) {
case ICAL_DUE_PROPERTY: // due date
icaltime = icalproperty_get_due(p);
if (icaltime.is_date) {
todo->setDtDue(QDateTime(readICalDate(icaltime),QTime(0,0,0)));
todo->setFloats(true);
} else {
todo->setDtDue(readICalDateTime(icaltime));
todo->setFloats(false);
}
todo->setHasDueDate(true);
break;
case ICAL_COMPLETED_PROPERTY: // completion date
icaltime = icalproperty_get_completed(p);
todo->setCompleted(readICalDateTime(icaltime));
break;
case ICAL_PERCENTCOMPLETE_PROPERTY: // Percent completed
todo->setPercentComplete(icalproperty_get_percentcomplete(p));
break;
case ICAL_RELATEDTO_PROPERTY: // related todo (parent)
todo->setRelatedToUid(QString::fromUtf8(icalproperty_get_relatedto(p)));
mTodosRelate.append(todo);
break;
case ICAL_DTSTART_PROPERTY:
// Flag that todo has start date. Value is read in by readIncidence().
todo->setHasStartDate(true);
break;
default:
// kdDebug(5800) << "ICALFormat::readTodo(): Unknown property: " << kind
// << endl;
break;
}
p = icalcomponent_get_next_property(vtodo,ICAL_ANY_PROPERTY);
}
return todo;
}
Event *ICalFormatImpl::readEvent(icalcomponent *vevent)
{
Event *event = new Event;
event->setFloats(false);
readIncidence(vevent,event);
icalproperty *p = icalcomponent_get_first_property(vevent,ICAL_ANY_PROPERTY);
// int intvalue;
icaltimetype icaltime;
QStringList categories;
QString transparency;
while (p) {
icalproperty_kind kind = icalproperty_isa(p);
switch (kind) {
case ICAL_DTEND_PROPERTY: // start date and time
icaltime = icalproperty_get_dtend(p);
if (icaltime.is_date) {
event->setFloats( true );
// End date is non-inclusive
QDate endDate = readICalDate( icaltime ).addDays( -1 );
mCompat->fixFloatingEnd( endDate );
if ( endDate < event->dtStart().date() ) {
endDate = event->dtStart().date();
}
event->setDtEnd( QDateTime( endDate, QTime( 0, 0, 0 ) ) );
} else {
event->setDtEnd(readICalDateTime(icaltime));
}
break;
// TODO:
// at this point, there should be at least a start or end time.
// fix up for events that take up no time but have a time associated
#if 0
if (!(vo = isAPropertyOf(vevent, VCDTstartProp)))
anEvent->setDtStart(anEvent->dtEnd());
if (!(vo = isAPropertyOf(vevent, VCDTendProp)))
anEvent->setDtEnd(anEvent->dtStart());
#endif
// TODO: exdates
#if 0
// recurrence exceptions
if ((vo = isAPropertyOf(vevent, VCExDateProp)) != 0) {
anEvent->setExDates(s = fakeCString(vObjectUStringZValue(vo)));
deleteStr(s);
}
#endif
#if 0
// secrecy
if ((vo = isAPropertyOf(vevent, VCClassProp)) != 0) {
anEvent->setSecrecy(s = fakeCString(vObjectUStringZValue(vo)));
deleteStr(s);
}
else
anEvent->setSecrecy("PUBLIC");
// attachments
tmpStrList.clear();
initPropIterator(&voi, vevent);
while (moreIteration(&voi)) {
vo = nextVObject(&voi);
if (strcmp(vObjectName(vo), VCAttachProp) == 0) {
tmpStrList.append(s = fakeCString(vObjectUStringZValue(vo)));
deleteStr(s);
}
}
anEvent->setAttachments(tmpStrList);
// resources
if ((vo = isAPropertyOf(vevent, VCResourcesProp)) != 0) {
QString resources = (s = fakeCString(vObjectUStringZValue(vo)));
deleteStr(s);
tmpStrList.clear();
index1 = 0;
index2 = 0;
QString resource;
while ((index2 = resources.find(';', index1)) != -1) {
resource = resources.mid(index1, (index2 - index1));
tmpStrList.append(resource);
index1 = index2;
}
anEvent->setResources(tmpStrList);
}
#endif
case ICAL_RELATEDTO_PROPERTY: // releated event (parent)
event->setRelatedToUid(QString::fromUtf8(icalproperty_get_relatedto(p)));
mEventsRelate.append(event);
break;
case ICAL_TRANSP_PROPERTY: // Transparency
if(icalproperty_get_transp(p) == ICAL_TRANSP_TRANSPARENT )
event->setTransparency( Event::Transparent );
else
event->setTransparency( Event::Opaque );
break;
default:
// kdDebug(5800) << "ICALFormat::readEvent(): Unknown property: " << kind
// << endl;
break;
}
p = icalcomponent_get_next_property(vevent,ICAL_ANY_PROPERTY);
}
QString msade = event->nonKDECustomProperty("X-MICROSOFT-CDO-ALLDAYEVENT");
if (!msade.isNull()) {
bool floats = (msade == QString::fromLatin1("TRUE"));
kdDebug(5800) << "ICALFormat::readEvent(): all day event: " << floats << endl;
event->setFloats(floats);
if (floats) {
QDateTime endDate = event->dtEnd();
event->setDtEnd(endDate.addDays(-1));
}
}
// some stupid vCal exporters ignore the standard and use Description
// instead of Summary for the default field. Correct for this.
if (event->summary().isEmpty() &&
!(event->description().isEmpty())) {
QString tmpStr = event->description().simplifyWhiteSpace();
event->setDescription("");
event->setSummary(tmpStr);
}
return event;
}
FreeBusy *ICalFormatImpl::readFreeBusy(icalcomponent *vfreebusy)
{
FreeBusy *freebusy = new FreeBusy;
readIncidenceBase(vfreebusy,freebusy);
icalproperty *p = icalcomponent_get_first_property(vfreebusy,ICAL_ANY_PROPERTY);
icaltimetype icaltime;
icalperiodtype icalperiod;
QDateTime period_start, period_end;
while (p) {
icalproperty_kind kind = icalproperty_isa(p);
switch (kind) {
case ICAL_DTSTART_PROPERTY: // start date and time
icaltime = icalproperty_get_dtstart(p);
freebusy->setDtStart(readICalDateTime(icaltime));
break;
case ICAL_DTEND_PROPERTY: // start End Date and Time
icaltime = icalproperty_get_dtend(p);
freebusy->setDtEnd(readICalDateTime(icaltime));
break;
case ICAL_FREEBUSY_PROPERTY: //Any FreeBusy Times
icalperiod = icalproperty_get_freebusy(p);
period_start = readICalDateTime(icalperiod.start);
period_end = readICalDateTime(icalperiod.end);
freebusy->addPeriod(period_start, period_end);
break;
default:
kdDebug(5800) << "ICALFormat::readIncidence(): Unknown property: " << kind
<< endl;
break;
}
p = icalcomponent_get_next_property(vfreebusy,ICAL_ANY_PROPERTY);
}
return freebusy;
}
Journal *ICalFormatImpl::readJournal(icalcomponent *vjournal)
{
Journal *journal = new Journal;
readIncidence(vjournal,journal);
if ( !journal->dtStart().isValid() && journal->created().isValid() ) {
journal->setDtStart( journal->created() );
}
return journal;
}
Attendee *ICalFormatImpl::readAttendee(icalproperty *attendee)
{
icalparameter *p = 0;
QString email = QString::fromUtf8(icalproperty_get_attendee(attendee));
QString name;
QString uid = QString::null;
p = icalproperty_get_first_parameter(attendee,ICAL_CN_PARAMETER);
if (p) {
name = QString::fromUtf8(icalparameter_get_cn(p));
} else {
}
bool rsvp=false;
p = icalproperty_get_first_parameter(attendee,ICAL_RSVP_PARAMETER);
if (p) {
icalparameter_rsvp rsvpParameter = icalparameter_get_rsvp(p);
if (rsvpParameter == ICAL_RSVP_TRUE) rsvp = true;
}
Attendee::PartStat status = Attendee::NeedsAction;
p = icalproperty_get_first_parameter(attendee,ICAL_PARTSTAT_PARAMETER);
if (p) {
icalparameter_partstat partStatParameter = icalparameter_get_partstat(p);
switch(partStatParameter) {
default:
case ICAL_PARTSTAT_NEEDSACTION:
status = Attendee::NeedsAction;
break;
case ICAL_PARTSTAT_ACCEPTED:
status = Attendee::Accepted;
break;
case ICAL_PARTSTAT_DECLINED:
status = Attendee::Declined;
break;
case ICAL_PARTSTAT_TENTATIVE:
status = Attendee::Tentative;
break;
case ICAL_PARTSTAT_DELEGATED:
status = Attendee::Delegated;
break;
case ICAL_PARTSTAT_COMPLETED:
status = Attendee::Completed;
break;
case ICAL_PARTSTAT_INPROCESS:
status = Attendee::InProcess;
break;
}
}
Attendee::Role role = Attendee::ReqParticipant;
p = icalproperty_get_first_parameter(attendee,ICAL_ROLE_PARAMETER);
if (p) {
icalparameter_role roleParameter = icalparameter_get_role(p);
switch(roleParameter) {
case ICAL_ROLE_CHAIR:
role = Attendee::Chair;
break;
default:
case ICAL_ROLE_REQPARTICIPANT:
role = Attendee::ReqParticipant;
break;
case ICAL_ROLE_OPTPARTICIPANT:
role = Attendee::OptParticipant;
break;
case ICAL_ROLE_NONPARTICIPANT:
role = Attendee::NonParticipant;
break;
}
}
p = icalproperty_get_first_parameter(attendee,ICAL_X_PARAMETER);
uid = icalparameter_get_xvalue(p);
// This should be added, but there seems to be a libical bug here.
/*while (p) {
// if (icalparameter_get_xname(p) == "X-UID") {
uid = icalparameter_get_xvalue(p);
p = icalproperty_get_next_parameter(attendee,ICAL_X_PARAMETER);
} */
return new Attendee( name, email, rsvp, status, role, uid );
}
Attachment *ICalFormatImpl::readAttachment(icalproperty *attach)
{
icalattach *a = icalproperty_get_attach(attach);
icalparameter_value v = ICAL_VALUE_NONE;
icalparameter_encoding e = ICAL_ENCODING_NONE;
Attachment *attachment = 0;
/*
icalparameter *vp = icalproperty_get_first_parameter(attach, ICAL_VALUE_PARAMETER);
if (vp)
v = icalparameter_get_value(vp);
icalparameter *ep = icalproperty_get_first_parameter(attach, ICAL_ENCODING_PARAMETER);
if (ep)
e = icalparameter_get_encoding(ep);
*/
int isurl = icalattach_get_is_url (a);
if (isurl == 0)
attachment = new Attachment((const char*)icalattach_get_data(a));
else {
attachment = new Attachment(QString(icalattach_get_url(a)));
}
icalparameter *p = icalproperty_get_first_parameter(attach, ICAL_FMTTYPE_PARAMETER);
if (p)
attachment->setMimeType(QString(icalparameter_get_fmttype(p)));
return attachment;
}
#include <qtextcodec.h>
void ICalFormatImpl::readIncidence(icalcomponent *parent,Incidence *incidence)
{
readIncidenceBase(parent,incidence);
icalproperty *p = icalcomponent_get_first_property(parent,ICAL_ANY_PROPERTY);
bool readrec = false;
const char *text;
int intvalue;
icaltimetype icaltime;
icaldurationtype icalduration;
struct icalrecurrencetype rectype;
QStringList categories;
while (p) {
icalproperty_kind kind = icalproperty_isa(p);
switch (kind) {
case ICAL_CREATED_PROPERTY:
icaltime = icalproperty_get_created(p);
incidence->setCreated(readICalDateTime(icaltime));
break;
case ICAL_SEQUENCE_PROPERTY: // sequence
intvalue = icalproperty_get_sequence(p);
incidence->setRevision(intvalue);
break;
case ICAL_LASTMODIFIED_PROPERTY: // last modification date
icaltime = icalproperty_get_lastmodified(p);
incidence->setLastModified(readICalDateTime(icaltime));
break;
case ICAL_DTSTART_PROPERTY: // start date and time
icaltime = icalproperty_get_dtstart(p);
if (icaltime.is_date) {
incidence->setDtStart(QDateTime(readICalDate(icaltime),QTime(0,0,0)));
incidence->setFloats(true);
} else {
incidence->setDtStart(readICalDateTime(icaltime));
}
break;
case ICAL_DURATION_PROPERTY: // start date and time
icalduration = icalproperty_get_duration(p);
incidence->setDuration(readICalDuration(icalduration));
break;
case ICAL_DESCRIPTION_PROPERTY: // description
text = icalproperty_get_description(p);
incidence->setDescription(QString::fromUtf8(text));
break;
case ICAL_SUMMARY_PROPERTY: // summary
{
text = icalproperty_get_summary(p);
incidence->setSummary(QString::fromUtf8(text));
}
break;
case ICAL_STATUS_PROPERTY: // summary
{
if ( ICAL_STATUS_CANCELLED == icalproperty_get_status(p) )
incidence->setCancelled( true );
}
break;
case ICAL_LOCATION_PROPERTY: // location
text = icalproperty_get_location(p);
incidence->setLocation(QString::fromUtf8(text));
break;
case ICAL_RECURRENCEID_PROPERTY:
icaltime = icalproperty_get_recurrenceid(p);
incidence->setRecurrenceID( readICalDateTime(icaltime) );
//qDebug(" RecurrenceID %s",incidence->recurrenceID().toString().latin1() );
break;
#if 0
// status
if ((vo = isAPropertyOf(vincidence, VCStatusProp)) != 0) {
incidence->setStatus(s = fakeCString(vObjectUStringZValue(vo)));
deleteStr(s);
}
else
incidence->setStatus("NEEDS ACTION");
#endif
case ICAL_PRIORITY_PROPERTY: // priority
intvalue = icalproperty_get_priority(p);
incidence->setPriority(intvalue);
break;
case ICAL_CATEGORIES_PROPERTY: // categories
text = icalproperty_get_categories(p);
categories.append(QString::fromUtf8(text));
break;
//*******************************************
case ICAL_RRULE_PROPERTY:
// we do need (maybe )start datetime of incidence for recurrence
// such that we can read recurrence only after we read incidence completely
readrec = true;
rectype = icalproperty_get_rrule(p);
break;
case ICAL_EXDATE_PROPERTY:
icaltime = icalproperty_get_exdate(p);
incidence->addExDate(readICalDate(icaltime));
break;
case ICAL_CLASS_PROPERTY: {
int inttext = icalproperty_get_class(p);
if (inttext == ICAL_CLASS_PUBLIC ) {
incidence->setSecrecy(Incidence::SecrecyPublic);
} else if (inttext == ICAL_CLASS_CONFIDENTIAL ) {
incidence->setSecrecy(Incidence::SecrecyConfidential);
} else {
incidence->setSecrecy(Incidence::SecrecyPrivate);
}
}
break;
case ICAL_ATTACH_PROPERTY: // attachments
incidence->addAttachment(readAttachment(p));
break;
default:
// kdDebug(5800) << "ICALFormat::readIncidence(): Unknown property: " << kind
// << endl;
break;
}
p = icalcomponent_get_next_property(parent,ICAL_ANY_PROPERTY);
}
if ( readrec ) {
readRecurrenceRule(rectype,incidence);
}
// kpilot stuff
// TODO: move this application-specific code to kpilot
QString kp = incidence->nonKDECustomProperty("X-PILOTID");
if (!kp.isNull()) {
incidence->setPilotId(kp.toInt());
}
kp = incidence->nonKDECustomProperty("X-PILOTSTAT");
if (!kp.isNull()) {
incidence->setSyncStatus(kp.toInt());
}
kp = incidence->nonKDECustomProperty("X-KOPIEXTID");
if (!kp.isNull()) {
incidence->setIDStr(kp);
}
// Cancel backwards compatibility mode for subsequent changes by the application
+ if ( readrec )
incidence->recurrence()->setCompatVersion();
// add categories
incidence->setCategories(categories);
// iterate through all alarms
for (icalcomponent *alarm = icalcomponent_get_first_component(parent,ICAL_VALARM_COMPONENT);
alarm;
alarm = icalcomponent_get_next_component(parent,ICAL_VALARM_COMPONENT)) {
readAlarm(alarm,incidence);
}
}
void ICalFormatImpl::readIncidenceBase(icalcomponent *parent,IncidenceBase *incidenceBase)
{
icalproperty *p = icalcomponent_get_first_property(parent,ICAL_ANY_PROPERTY);
while (p) {
icalproperty_kind kind = icalproperty_isa(p);
switch (kind) {
case ICAL_UID_PROPERTY: // unique id
incidenceBase->setUid(QString::fromUtf8(icalproperty_get_uid(p)));
break;
case ICAL_ORGANIZER_PROPERTY: // organizer
incidenceBase->setOrganizer(QString::fromUtf8(icalproperty_get_organizer(p)));
break;
case ICAL_ATTENDEE_PROPERTY: // attendee
incidenceBase->addAttendee(readAttendee(p));
break;
default:
break;
}
p = icalcomponent_get_next_property(parent,ICAL_ANY_PROPERTY);
}
// custom properties
readCustomProperties(parent, incidenceBase);
}
void ICalFormatImpl::readCustomProperties(icalcomponent *parent,CustomProperties *properties)
{
QMap<QCString, QString> customProperties;
icalproperty *p = icalcomponent_get_first_property(parent,ICAL_X_PROPERTY);
while (p) {
QString value = QString::fromUtf8(icalproperty_get_x(p));
customProperties[icalproperty_get_x_name(p)] = value;
//qDebug("ICalFormatImpl::readCustomProperties %s %s",value.latin1(), icalproperty_get_x_name(p) );
p = icalcomponent_get_next_property(parent,ICAL_X_PROPERTY);
}
properties->setCustomProperties(customProperties);
}
void ICalFormatImpl::readRecurrenceRule(struct icalrecurrencetype rrule,Incidence *incidence)
{
// kdDebug(5800) << "Read recurrence for " << incidence->summary() << endl;
Recurrence *recur = incidence->recurrence();
recur->setCompatVersion(mCalendarVersion);
recur->unsetRecurs();
struct icalrecurrencetype r = rrule;
dumpIcalRecurrence(r);
readRecurrence( r, recur, incidence);
}
void ICalFormatImpl::readRecurrence( const struct icalrecurrencetype &r, Recurrence* recur, Incidence *incidence)
{
int wkst;
int index = 0;
short day = 0;
QBitArray qba(7);
int frequ = r.freq;
int interv = r.interval;
// preprocessing for odd recurrence definitions
if ( r.freq == ICAL_MONTHLY_RECURRENCE ) {
if ( r.by_month[0] != ICAL_RECURRENCE_ARRAY_MAX) {
interv = 12;
}
}
if ( r.freq == ICAL_YEARLY_RECURRENCE ) {
if ( r.by_month[0] != ICAL_RECURRENCE_ARRAY_MAX && r.by_day[0] != ICAL_RECURRENCE_ARRAY_MAX ) {
frequ = ICAL_MONTHLY_RECURRENCE;
interv = 12* r.interval;
}
}
switch (frequ) {
case ICAL_MINUTELY_RECURRENCE:
if (!icaltime_is_null_time(r.until)) {
recur->setMinutely(interv,readICalDateTime(r.until));
} else {
if (r.count == 0)
recur->setMinutely(interv,-1);
else
recur->setMinutely(interv,r.count);
}
break;
case ICAL_HOURLY_RECURRENCE:
if (!icaltime_is_null_time(r.until)) {
recur->setHourly(interv,readICalDateTime(r.until));
} else {
if (r.count == 0)
recur->setHourly(interv,-1);
else
recur->setHourly(interv,r.count);
}
break;
case ICAL_DAILY_RECURRENCE:
if (!icaltime_is_null_time(r.until)) {
recur->setDaily(interv,readICalDate(r.until));
} else {
if (r.count == 0)
recur->setDaily(interv,-1);
else
recur->setDaily(interv,r.count);
}
break;
case ICAL_WEEKLY_RECURRENCE:
// kdDebug(5800) << "WEEKLY_RECURRENCE" << endl;
wkst = (r.week_start + 5)%7 + 1;
if (!icaltime_is_null_time(r.until)) {
recur->setWeekly(interv,qba,readICalDate(r.until),wkst);
} else {
if (r.count == 0)
recur->setWeekly(interv,qba,-1,wkst);
else
recur->setWeekly(interv,qba,r.count,wkst);
}
if ( r.by_day[0] == ICAL_RECURRENCE_ARRAY_MAX) {
int wday = incidence->dtStart().date().dayOfWeek ()-1;
//qDebug("weekly error found ");
qba.setBit(wday);
} else {
while((day = r.by_day[index++]) != ICAL_RECURRENCE_ARRAY_MAX) {
// kdDebug(5800) << " " << day << endl;
qba.setBit((day+5)%7); // convert from Sunday=1 to Monday=0
}
}
break;
case ICAL_MONTHLY_RECURRENCE:
if (r.by_day[0] != ICAL_RECURRENCE_ARRAY_MAX) {
if (!icaltime_is_null_time(r.until)) {
recur->setMonthly(Recurrence::rMonthlyPos,interv,
readICalDate(r.until));
} else {
if (r.count == 0)
recur->setMonthly(Recurrence::rMonthlyPos,interv,-1);
else
recur->setMonthly(Recurrence::rMonthlyPos,interv,r.count);
}
bool useSetPos = false;
short pos = 0;
while((day = r.by_day[index++]) != ICAL_RECURRENCE_ARRAY_MAX) {
// kdDebug(5800) << "----a " << index << ": " << day << endl;
pos = icalrecurrencetype_day_position(day);
if (pos) {
day = icalrecurrencetype_day_day_of_week(day);
QBitArray ba(7); // don't wipe qba
ba.setBit((day+5)%7); // convert from Sunday=1 to Monday=0
recur->addMonthlyPos(pos,ba);
} else {
qba.setBit((day+5)%7); // convert from Sunday=1 to Monday=0
useSetPos = true;
}
}
if (useSetPos) {
if (r.by_set_pos[0] != ICAL_RECURRENCE_ARRAY_MAX) {
recur->addMonthlyPos(r.by_set_pos[0],qba);
}
}
} else if (r.by_month_day[0] != ICAL_RECURRENCE_ARRAY_MAX) {
if (!icaltime_is_null_time(r.until)) {
recur->setMonthly(Recurrence::rMonthlyDay,interv,
readICalDate(r.until));
} else {
if (r.count == 0)
recur->setMonthly(Recurrence::rMonthlyDay,interv,-1);
else
recur->setMonthly(Recurrence::rMonthlyDay,interv,r.count);
}
while((day = r.by_month_day[index++]) != ICAL_RECURRENCE_ARRAY_MAX) {
// kdDebug(5800) << "----b " << day << endl;
recur->addMonthlyDay(day);
}
}
break;
case ICAL_YEARLY_RECURRENCE:
if (r.by_year_day[0] != ICAL_RECURRENCE_ARRAY_MAX) {
//qDebug(" YEARLY DAY OF YEAR");
if (!icaltime_is_null_time(r.until)) {
recur->setYearly(Recurrence::rYearlyDay,interv,
readICalDate(r.until));
} else {
if (r.count == 0)
recur->setYearly(Recurrence::rYearlyDay,interv,-1);
else
recur->setYearly(Recurrence::rYearlyDay,interv,r.count);
}
while((day = r.by_year_day[index++]) != ICAL_RECURRENCE_ARRAY_MAX) {
recur->addYearlyNum(day);
}
} else if ( true /*r.by_month[0] != ICAL_RECURRENCE_ARRAY_MAX*/) {
if (r.by_day[0] != ICAL_RECURRENCE_ARRAY_MAX) {
qDebug("YEARLY POS NOT SUPPORTED BY GUI");
if (!icaltime_is_null_time(r.until)) {
recur->setYearly(Recurrence::rYearlyPos,interv,
readICalDate(r.until));
} else {
if (r.count == 0)
recur->setYearly(Recurrence::rYearlyPos,interv,-1);
else
recur->setYearly(Recurrence::rYearlyPos,interv,r.count);
}
bool useSetPos = false;
short pos = 0;
while((day = r.by_day[index++]) != ICAL_RECURRENCE_ARRAY_MAX) {
// kdDebug(5800) << "----a " << index << ": " << day << endl;
pos = icalrecurrencetype_day_position(day);
if (pos) {
day = icalrecurrencetype_day_day_of_week(day);
QBitArray ba(7); // don't wipe qba
ba.setBit((day+5)%7); // convert from Sunday=1 to Monday=0
recur->addYearlyMonthPos(pos,ba);
} else {
qba.setBit((day+5)%7); // convert from Sunday=1 to Monday=0
useSetPos = true;
}
}
if (useSetPos) {
if (r.by_set_pos[0] != ICAL_RECURRENCE_ARRAY_MAX) {
recur->addYearlyMonthPos(r.by_set_pos[0],qba);
}
}
} else {
//qDebug("YEARLY MONTH ");
if (!icaltime_is_null_time(r.until)) {
recur->setYearly(Recurrence::rYearlyMonth,interv,
readICalDate(r.until));
} else {
if (r.count == 0)
recur->setYearly(Recurrence::rYearlyMonth,interv,-1);
else
recur->setYearly(Recurrence::rYearlyMonth,interv,r.count);
}
if ( r.by_month[0] != ICAL_RECURRENCE_ARRAY_MAX ) {
index = 0;
while((day = r.by_month[index++]) != ICAL_RECURRENCE_ARRAY_MAX) {
recur->addYearlyNum(day);
}
} else {
recur->addYearlyNum(incidence->dtStart().date().month());
}
}
}
break;
default:
;
break;
}
}
void ICalFormatImpl::readAlarm(icalcomponent *alarm,Incidence *incidence)
{
//kdDebug(5800) << "Read alarm for " << incidence->summary() << endl;
Alarm* ialarm = incidence->newAlarm();
ialarm->setRepeatCount(0);
ialarm->setEnabled(true);
// Determine the alarm's action type
icalproperty *p = icalcomponent_get_first_property(alarm,ICAL_ACTION_PROPERTY);
if ( !p ) {
return;
}
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.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;
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) {
if ((curVOProp = isAPropertyOf(curVO, KPilotStatusProp)) != 0) {
char *s;
s = fakeCString(vObjectUStringZValue(curVOProp));
// check to see if event was deleted by the kpilot conduit
if (atoi(s) == Event::SYNCDEL) {
deleteStr(s);
goto SKIP;
}
deleteStr(s);
}
// this code checks to see if we are trying to read in an event
// that we already find to be in the calendar. If we find this
// to be the case, we skip the event.
if ((curVOProp = isAPropertyOf(curVO, VCUniqueStringProp)) != 0) {
char *s = fakeCString(vObjectUStringZValue(curVOProp));
QString tmpStr(s);
deleteStr(s);
if (cal->event(tmpStr)) {
goto SKIP;
}
if (cal->todo(tmpStr)) {
goto SKIP;
}
}
if ((!(curVOProp = isAPropertyOf(curVO, VCDTstartProp))) &&
(!(curVOProp = isAPropertyOf(curVO, VCDTendProp)))) {
kdDebug(5800) << "found a VEvent with no DTSTART and no DTEND! Skipping..." << endl;
goto SKIP;
}
anEvent = VEventToEvent(curVO);
// we now use addEvent instead of insertEvent so that the
// signal/slot get connected.
if (anEvent)
cal->addEvent(anEvent);
else {
// some sort of error must have occurred while in translation.
goto SKIP;
}
} else if (strcmp(vObjectName(curVO), VCTodoProp) == 0) {
anEvent = VTodoToEvent(curVO);
cal->addTodo(anEvent);
} else if ((strcmp(vObjectName(curVO), VCVersionProp) == 0) ||
(strcmp(vObjectName(curVO), VCProdIdProp) == 0) ||
(strcmp(vObjectName(curVO), VCTimeZoneProp) == 0)) {
// do nothing, we know these properties and we want to skip them.
// we have either already processed them or are ignoring them.
;
} else {
;
}
SKIP:
;
} // while
#endif
// Post-Process list of events with relations, put Event objects in relation
Event *ev;
for ( ev=mEventsRelate.first(); ev != 0; ev=mEventsRelate.next() ) {
Incidence * inc = cal->event(ev->relatedToUid());
if ( inc )
ev->setRelatedTo( inc );
}
Todo *todo;
for ( todo=mTodosRelate.first(); todo != 0; todo=mTodosRelate.next() ) {
Incidence * inc = cal->todo(todo->relatedToUid());
if ( inc )
todo->setRelatedTo( inc );
}
return true;
}
QString ICalFormatImpl::extractErrorProperty(icalcomponent *c)
{
// kdDebug(5800) << "ICalFormatImpl:extractErrorProperty: "
// << icalcomponent_as_ical_string(c) << endl;
QString errorMessage;
diff --git a/libkcal/incidence.cpp b/libkcal/incidence.cpp
index e4bcc5e..4643a3a 100644
--- a/libkcal/incidence.cpp
+++ b/libkcal/incidence.cpp
@@ -1,780 +1,811 @@
/*
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 "calformat.h"
#include "incidence.h"
#include "todo.h"
using namespace KCal;
Incidence::Incidence() :
IncidenceBase(),
mRelatedTo(0), mSecrecy(SecrecyPublic), mPriority(3)
{
- mRecurrence = new Recurrence(this);
+ mRecurrence = 0;//new Recurrence(this);
mCancelled = false;
recreate();
mHasStartDate = true;
mAlarms.setAutoDelete(true);
mAttachments.setAutoDelete(true);
mHasRecurrenceID = false;
mHoliday = false;
mBirthday = false;
mAnniversary = false;
}
Incidence::Incidence( const Incidence &i ) : IncidenceBase( i )
{
// TODO: reenable attributes currently commented out.
mRevision = i.mRevision;
mCreated = i.mCreated;
mDescription = i.mDescription;
mSummary = i.mSummary;
mCategories = i.mCategories;
// Incidence *mRelatedTo; Incidence *mRelatedTo;
mRelatedTo = 0;
mRelatedToUid = i.mRelatedToUid;
// QPtrList<Incidence> mRelations; QPtrList<Incidence> mRelations;
mExDates = i.mExDates;
mAttachments = i.mAttachments;
mResources = i.mResources;
mSecrecy = i.mSecrecy;
mPriority = i.mPriority;
mLocation = i.mLocation;
mCancelled = i.mCancelled;
mHasStartDate = i.mHasStartDate;
QPtrListIterator<Alarm> it( i.mAlarms );
const Alarm *a;
while( (a = it.current()) ) {
Alarm *b = new Alarm( *a );
b->setParent( this );
mAlarms.append( b );
++it;
}
mAlarms.setAutoDelete(true);
mHasRecurrenceID = i.mHasRecurrenceID;
mRecurrenceID = i.mRecurrenceID;
+ if ( i.mRecurrence )
mRecurrence = new Recurrence( *(i.mRecurrence), this );
+ else
+ mRecurrence = 0;
mHoliday = i.mHoliday ;
mBirthday = i.mBirthday;
mAnniversary = i.mAnniversary;
}
Incidence::~Incidence()
{
Incidence *ev;
QPtrList<Incidence> Relations = relations();
for (ev=Relations.first();ev;ev=Relations.next()) {
if (ev->relatedTo() == this) ev->setRelatedTo(0);
}
if (relatedTo()) relatedTo()->removeRelation(this);
+ if ( mRecurrence )
delete mRecurrence;
}
bool Incidence::isHoliday() const
{
return mHoliday;
}
bool Incidence::isBirthday() const
{
return mBirthday ;
}
bool Incidence::isAnniversary() const
{
return mAnniversary ;
}
bool Incidence::hasRecurrenceID() const
{
return mHasRecurrenceID;
}
void Incidence::setHasRecurrenceID( bool b )
{
mHasRecurrenceID = b;
}
void Incidence::setRecurrenceID(QDateTime d)
{
mRecurrenceID = d;
mHasRecurrenceID = true;
updated();
}
QDateTime Incidence::recurrenceID () const
{
return mRecurrenceID;
}
bool Incidence::cancelled() const
{
return mCancelled;
}
void Incidence::setCancelled( bool b )
{
mCancelled = b;
updated();
}
bool Incidence::hasStartDate() const
{
return mHasStartDate;
}
void Incidence::setHasStartDate(bool f)
{
if (mReadOnly) return;
mHasStartDate = f;
updated();
}
// A string comparison that considers that null and empty are the same
static bool stringCompare( const QString& s1, const QString& s2 )
{
if ( s1.isEmpty() && s2.isEmpty() )
return true;
return s1 == s2;
}
bool KCal::operator==( const Incidence& i1, const Incidence& i2 )
{
if( i1.alarms().count() != i2.alarms().count() ) {
return false; // no need to check further
}
if ( i1.alarms().count() > 0 ) {
if ( !( *(i1.alarms().first()) == *(i2.alarms().first())) )
{
qDebug("alarm not equal ");
return false;
}
}
#if 0
QPtrListIterator<Alarm> a1( i1.alarms() );
QPtrListIterator<Alarm> a2( i2.alarms() );
for( ; a1.current() && a2.current(); ++a1, ++a2 ) {
if( *a1.current() == *a2.current() ) {
continue;
}
else {
return false;
}
}
#endif
if ( i1.hasRecurrenceID() == i2.hasRecurrenceID() ) {
if ( i1.hasRecurrenceID() ) {
if ( i1.recurrenceID() != i2.recurrenceID() )
return false;
}
} else {
return false;
}
if ( ! operator==( (const IncidenceBase&)i1, (const IncidenceBase&)i2 ) )
return false;
if ( i1.hasStartDate() == i2.hasStartDate() ) {
if ( i1.hasStartDate() ) {
if ( i1.dtStart() != i2.dtStart() )
return false;
}
} else {
return false;
}
- if (!( *i1.recurrence() == *i2.recurrence()) ) {
- qDebug("recurrence is NOT equal ");
+ if ( i1.mRecurrence != 0 && i2.mRecurrence != 0 ) {
+ if (!( *i1.mRecurrence == *i2.mRecurrence) ) {
+ //qDebug("recurrence is NOT equal ");
+ return false;
+ }
+ } else {
+ // one ( or both ) recurrence is 0
+ if ( i1.mRecurrence == 0 ) {
+ if ( i2.mRecurrence != 0 && i2.mRecurrence->doesRecur() != Recurrence::rNone )
+ return false;
+ } else {
+ // i1.mRecurrence != 0
+ // i2.mRecurrence == 0
+ if ( i1.mRecurrence->doesRecur() != Recurrence::rNone )
return false;
}
+ }
+
return
// i1.created() == i2.created() &&
stringCompare( i1.description(), i2.description() ) &&
stringCompare( i1.summary(), i2.summary() ) &&
i1.categories() == i2.categories() &&
// no need to compare mRelatedTo
stringCompare( i1.relatedToUid(), i2.relatedToUid() ) &&
// i1.relations() == i2.relations() &&
i1.exDates() == i2.exDates() &&
i1.attachments() == i2.attachments() &&
i1.resources() == i2.resources() &&
i1.secrecy() == i2.secrecy() &&
i1.priority() == i2.priority() &&
i1.cancelled() == i2.cancelled() &&
stringCompare( i1.location(), i2.location() );
}
Incidence* Incidence::recreateCloneException( QDate d )
{
Incidence* newInc = clone();
newInc->recreate();
if ( doesRecur() ) {
addExDate( d );
newInc->recurrence()->unsetRecurs();
if ( typeID() == eventID ) {
int len = dtStart().secsTo( ((Event*)this)->dtEnd());
QTime tim = dtStart().time();
newInc->setDtStart( QDateTime(d, tim) );
((Event*)newInc)->setDtEnd( newInc->dtStart().addSecs( len ) );
} else {
int len = dtStart().secsTo( ((Todo*)this)->dtDue());
QTime tim = ((Todo*)this)->dtDue().time();
((Todo*)newInc)->setDtDue( QDateTime(d, tim) );
((Todo*)newInc)->setDtStart( ((Todo*)newInc)->dtDue().addSecs( -len ) );
((Todo*)this)->setRecurDates();
}
newInc->setExDates( DateList () );
}
return newInc;
}
void Incidence::recreate()
{
setCreated(QDateTime::currentDateTime());
setUid(CalFormat::createUniqueId());
setRevision(0);
setIDStr( ":" );
setLastModified(QDateTime::currentDateTime());
}
void Incidence::cloneRelations( Incidence * newInc )
{
// newInc is already a clone of this incidence
Incidence * inc;
Incidence * cloneInc;
QPtrList<Incidence> Relations = relations();
for (inc=Relations.first();inc;inc=Relations.next()) {
cloneInc = inc->clone();
cloneInc->recreate();
cloneInc->setRelatedTo( newInc );
inc->cloneRelations( cloneInc );
}
}
void Incidence::setReadOnly( bool readOnly )
{
IncidenceBase::setReadOnly( readOnly );
- recurrence()->setRecurReadOnly( readOnly);
+ if ( mRecurrence )
+ mRecurrence->setRecurReadOnly( readOnly);
}
void Incidence::setLastModifiedSubInvalid()
{
mLastModifiedSub = QDateTime();
if ( mRelatedTo )
mRelatedTo->setLastModifiedSubInvalid();
}
QDateTime Incidence::lastModifiedSub()
{
if ( !mRelations.count() )
return lastModified();
if ( mLastModifiedSub.isValid() )
return mLastModifiedSub;
mLastModifiedSub = lastModified();
Incidence * inc;
QPtrList<Incidence> Relations = relations();
for (inc=Relations.first();inc;inc=Relations.next()) {
if ( inc->lastModifiedSub() > mLastModifiedSub )
mLastModifiedSub = inc->lastModifiedSub();
}
return mLastModifiedSub;
}
void Incidence::setCreated(QDateTime created)
{
if (mReadOnly) return;
mCreated = getEvenTime(created);
}
QDateTime Incidence::created() const
{
return mCreated;
}
void Incidence::setRevision(int rev)
{
if (mReadOnly) return;
mRevision = rev;
updated();
}
int Incidence::revision() const
{
return mRevision;
}
void Incidence::setDtStart(const QDateTime &dtStart)
{
QDateTime dt = getEvenTime(dtStart);
- recurrence()->setRecurStart( dt);
+
+ if ( mRecurrence )
+ mRecurrence->setRecurStart( dt);
IncidenceBase::setDtStart( dt );
}
void Incidence::setDescription(const QString &description)
{
if (mReadOnly) return;
mDescription = description;
updated();
}
QString Incidence::description() const
{
return mDescription;
}
void Incidence::setSummary(const QString &summary)
{
if (mReadOnly) return;
mSummary = summary;
updated();
}
QString Incidence::summary() const
{
return mSummary;
}
void Incidence::checkCategories()
{
mHoliday = mCategories.contains("Holiday") || mCategories.contains(i18n("Holiday"));
mBirthday = mCategories.contains("Birthday") || mCategories.contains(i18n("Birthday"));
mAnniversary = mCategories.contains("Anniversary") || mCategories.contains(i18n("Anniversary"));
}
void Incidence::addCategories(const QStringList &categories, bool addToRelations ) //addToRelations = false
{
if (mReadOnly) return;
int i;
for( i = 0; i < categories.count(); ++i ) {
if ( !mCategories.contains (categories[i]))
mCategories.append( categories[i] );
}
checkCategories();
updated();
if ( addToRelations ) {
Incidence * inc;
QPtrList<Incidence> Relations = relations();
for (inc=Relations.first();inc;inc=Relations.next()) {
inc->addCategories( categories, true );
}
}
}
void Incidence::setCategories(const QStringList &categories, bool setForRelations ) //setForRelations = false
{
if (mReadOnly) return;
mCategories = categories;
checkCategories();
updated();
if ( setForRelations ) {
Incidence * inc;
QPtrList<Incidence> Relations = relations();
for (inc=Relations.first();inc;inc=Relations.next()) {
inc->setCategories( categories, true );
}
}
}
// TODO: remove setCategories(QString) function
void Incidence::setCategories(const QString &catStr)
{
if (mReadOnly) return;
mCategories.clear();
if (catStr.isEmpty()) return;
mCategories = QStringList::split(",",catStr);
QStringList::Iterator it;
for(it = mCategories.begin();it != mCategories.end(); ++it) {
*it = (*it).stripWhiteSpace();
}
checkCategories();
updated();
}
// using this makes filtering 3 times faster
QStringList* Incidence::categoriesP()
{
return &mCategories;
}
QStringList Incidence::categories() const
{
return mCategories;
}
QString Incidence::categoriesStr()
{
return mCategories.join(",");
}
QString Incidence::categoriesStrWithSpace()
{
return mCategories.join(", ");
}
void Incidence::setRelatedToUid(const QString &relatedToUid)
{
if (mReadOnly) return;
mRelatedToUid = relatedToUid;
}
QString Incidence::relatedToUid() const
{
return mRelatedToUid;
}
void Incidence::setRelatedTo(Incidence *relatedTo)
{
//qDebug("Incidence::setRelatedTo %d ", relatedTo);
//qDebug("setRelatedTo(Incidence *relatedTo) %s %s", summary().latin1(), relatedTo->summary().latin1() );
if (mReadOnly || mRelatedTo == relatedTo) return;
if(mRelatedTo) {
// updated();
mRelatedTo->removeRelation(this);
}
mRelatedTo = relatedTo;
if (mRelatedTo) {
mRelatedTo->addRelation(this);
mRelatedToUid = mRelatedTo->uid();
} else {
mRelatedToUid = "";
}
}
Incidence *Incidence::relatedTo() const
{
return mRelatedTo;
}
QPtrList<Incidence> Incidence::relations() const
{
return mRelations;
}
void Incidence::addRelationsToList(QPtrList<Incidence> *rel)
{
Incidence* inc;
QPtrList<Incidence> Relations = relations();
for (inc=Relations.first();inc;inc=Relations.next()) {
inc->addRelationsToList( rel );
}
if ( rel->findRef( this ) == -1 )
rel->append( this );
}
void Incidence::addRelation(Incidence *event)
{
setLastModifiedSubInvalid();
if( mRelations.findRef( event ) == -1 ) {
mRelations.append(event);
//updated();
}
}
void Incidence::removeRelation(Incidence *event)
{
setLastModifiedSubInvalid();
mRelations.removeRef(event);
// if (event->getRelatedTo() == this) event->setRelatedTo(0);
}
bool Incidence::recursOn(const QDate &qd) const
{
- if (recurrence()->recursOnPure(qd) && !isException(qd)) return true;
+ if (mRecurrence && mRecurrence->recursOnPure(qd) && !isException(qd)) return true;
else return false;
}
void Incidence::setExDates(const DateList &exDates)
{
if (mReadOnly) return;
mExDates = exDates;
-
recurrence()->setRecurExDatesCount(mExDates.count());
updated();
}
void Incidence::addExDate(const QDate &date)
{
if (mReadOnly) return;
mExDates.append(date);
recurrence()->setRecurExDatesCount(mExDates.count());
updated();
}
DateList Incidence::exDates() const
{
return mExDates;
}
bool Incidence::isException(const QDate &date) const
{
DateList::ConstIterator it;
for( it = mExDates.begin(); it != mExDates.end(); ++it ) {
if ( (*it) == date ) {
return true;
}
}
return false;
}
void Incidence::addAttachment(Attachment *attachment)
{
if (mReadOnly || !attachment) return;
mAttachments.append(attachment);
updated();
}
void Incidence::deleteAttachment(Attachment *attachment)
{
mAttachments.removeRef(attachment);
}
void Incidence::deleteAttachments(const QString& mime)
{
Attachment *at = mAttachments.first();
while (at) {
if (at->mimeType() == mime)
mAttachments.remove();
else
at = mAttachments.next();
}
}
QPtrList<Attachment> Incidence::attachments() const
{
return mAttachments;
}
QPtrList<Attachment> Incidence::attachments(const QString& mime) const
{
QPtrList<Attachment> attachments;
QPtrListIterator<Attachment> it( mAttachments );
Attachment *at;
while ( (at = it.current()) ) {
if (at->mimeType() == mime)
attachments.append(at);
++it;
}
return attachments;
}
void Incidence::setResources(const QStringList &resources)
{
if (mReadOnly) return;
mResources = resources;
updated();
}
QStringList Incidence::resources() const
{
return mResources;
}
void Incidence::setPriority(int priority)
{
if (mReadOnly) return;
mPriority = priority;
updated();
}
int Incidence::priority() const
{
return mPriority;
}
void Incidence::setSecrecy(int sec)
{
if (mReadOnly) return;
mSecrecy = sec;
updated();
}
int Incidence::secrecy() const
{
return mSecrecy;
}
QString Incidence::secrecyStr() const
{
return secrecyName(mSecrecy);
}
QString Incidence::secrecyName(int secrecy)
{
switch (secrecy) {
case SecrecyPublic:
return i18n("Public");
break;
case SecrecyPrivate:
return i18n("Private");
break;
case SecrecyConfidential:
return i18n("Confidential");
break;
default:
return i18n("Undefined");
break;
}
}
QStringList Incidence::secrecyList()
{
QStringList list;
list << secrecyName(SecrecyPublic);
list << secrecyName(SecrecyPrivate);
list << secrecyName(SecrecyConfidential);
return list;
}
QPtrList<Alarm> Incidence::alarms() const
{
return mAlarms;
}
Alarm* Incidence::newAlarm()
{
Alarm* alarm = new Alarm(this);
mAlarms.append(alarm);
// updated();
return alarm;
}
void Incidence::addAlarm(Alarm *alarm)
{
mAlarms.append(alarm);
updated();
}
void Incidence::removeAlarm(Alarm *alarm)
{
mAlarms.removeRef(alarm);
updated();
}
void Incidence::clearAlarms()
{
mAlarms.clear();
updated();
}
bool Incidence::isAlarmEnabled() const
{
Alarm* alarm;
for (QPtrListIterator<Alarm> it(mAlarms); (alarm = it.current()) != 0; ++it) {
if (alarm->enabled())
return true;
}
return false;
}
-
-Recurrence *Incidence::recurrence() const
+#include <stdlib.h>
+Recurrence *Incidence::recurrence()
{
+ if ( ! mRecurrence ) {
+ mRecurrence = new Recurrence(this);
+ qDebug("creating new recurence ");
+ //abort();
+ }
return mRecurrence;
}
void Incidence::setRecurrence( Recurrence * r)
{
+ if ( mRecurrence )
delete mRecurrence;
mRecurrence = r;
}
void Incidence::setLocation(const QString &location)
{
if (mReadOnly) return;
mLocation = location;
updated();
}
QString Incidence::location() const
{
return mLocation;
}
+QString Incidence::recurrenceText() const
+{
+ if ( mRecurrence ) return mRecurrence->recurrenceText();
+ return i18n("No");
+}
ushort Incidence::doesRecur() const
{
if ( mRecurrence ) return mRecurrence->doesRecur();
else return Recurrence::rNone;
}
QDateTime Incidence::getNextOccurence( const QDateTime& dt, bool* ok ) const
{
QDateTime incidenceStart = dt;
*ok = false;
if ( doesRecur() ) {
bool last;
- recurrence()->getPreviousDateTime( incidenceStart , &last );
+ mRecurrence->getPreviousDateTime( incidenceStart , &last );
int count = 0;
if ( !last ) {
while ( !last ) {
++count;
- incidenceStart = recurrence()->getNextDateTime( incidenceStart, &last );
+ incidenceStart = mRecurrence->getNextDateTime( incidenceStart, &last );
if ( recursOn( incidenceStart.date() ) ) {
last = true; // exit while llop
} else {
if ( last ) { // no alarm on last recurrence
return QDateTime ();
}
int year = incidenceStart.date().year();
// workaround for bug in recurrence
if ( count == 100 || year < 1000 || year > 5000 ) {
return QDateTime ();
}
incidenceStart = incidenceStart.addSecs( 1 );
}
}
} else {
return QDateTime ();
}
} else {
if ( hasStartDate () ) {
incidenceStart = dtStart();
}
if ( typeID() == todoID ) {
if ( ((Todo*)this)->hasDueDate() )
incidenceStart = ((Todo*)this)->dtDue();
}
}
if ( incidenceStart > dt )
*ok = true;
return incidenceStart;
}
QDateTime Incidence::dtStart() const
{
if ( doesRecur() ) {
if ( typeID() == todoID ) {
((Todo*)this)->checkSetCompletedFalse();
}
}
return mDtStart;
}
diff --git a/libkcal/incidence.h b/libkcal/incidence.h
index d4af9f0..8519f01 100644
--- a/libkcal/incidence.h
+++ b/libkcal/incidence.h
@@ -1,321 +1,322 @@
/*
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.
*/
#ifndef INCIDENCE_H
#define INCIDENCE_H
//
// Incidence - base class of calendaring components
//
#include <qdatetime.h>
#include <qstringlist.h>
#include <qvaluelist.h>
#include "recurrence.h"
#include "alarm.h"
#include "attachment.h"
#include "listbase.h"
#include "incidencebase.h"
namespace KCal {
class Event;
class Todo;
class Journal;
/**
This class provides the base class common to all calendar components.
*/
class Incidence : public IncidenceBase
{
public:
/**
This class provides the interface for a visitor of calendar components. It
serves as base class for concrete visitors, which implement certain actions on
calendar components. It allows to add functions, which operate on the concrete
types of calendar components, without changing the calendar component classes.
*/
class Visitor
{
public:
/** Destruct Incidence::Visitor */
virtual ~Visitor() {}
/**
Reimplement this function in your concrete subclass of IncidenceVisitor to perform actions
on an Event object.
*/
virtual bool visit(Event *) { return false; }
/**
Reimplement this function in your concrete subclass of IncidenceVisitor to perform actions
on an Todo object.
*/
virtual bool visit(Todo *) { return false; }
/**
Reimplement this function in your concrete subclass of IncidenceVisitor to perform actions
on an Journal object.
*/
virtual bool visit(Journal *) { return false; }
protected:
/** Constructor is protected to prevent direct creation of visitor base class. */
Visitor() {}
};
/**
This class implements a visitor for adding an Incidence to a resource
supporting addEvent(), addTodo() and addJournal() calls.
*/
template<class T>
class AddVisitor : public Visitor
{
public:
AddVisitor( T *r ) : mResource( r ) {}
bool visit( Event *e ) { return mResource->addEvent( e ); }
bool visit( Todo *t ) { return mResource->addTodo( t ); }
bool visit( Journal *j ) { return mResource->addJournal( j ); }
private:
T *mResource;
};
/** enumeration for describing an event's secrecy. */
enum { SecrecyPublic = 0, SecrecyPrivate = 1, SecrecyConfidential = 2 };
typedef ListBase<Incidence> List;
Incidence();
Incidence(const Incidence &);
~Incidence();
/**
Accept IncidenceVisitor. A class taking part in the visitor mechanism has to
provide this implementation:
<pre>
bool accept(Visitor &v) { return v.visit(this); }
</pre>
*/
virtual bool accept(Visitor &) { return false; }
virtual Incidence *clone() = 0;
virtual void cloneRelations( Incidence * );
void addRelationsToList(QPtrList<Incidence> *rel);
virtual QDateTime getNextAlarmDateTime( bool * ok, int * offset, QDateTime start_dt ) const = 0;
void setReadOnly( bool );
/**
Recreate event. The event is made a new unique event, but already stored
event information is preserved. Sets uniquie id, creation date, last
modification date and revision number.
*/
void recreate();
Incidence* recreateCloneException(QDate);
/** set creation date */
void setCreated(QDateTime);
/** return time and date of creation. */
QDateTime created() const;
/** set the number of revisions this event has seen */
void setRevision(int rev);
/** return the number of revisions this event has seen */
int revision() const;
/** Set starting date/time. */
virtual void setDtStart(const QDateTime &dtStart);
/** Return the incidence's ending date/time as a QDateTime. */
virtual QDateTime dtEnd() const { return QDateTime(); }
/** sets the event's lengthy description. */
void setDescription(const QString &description);
/** returns a reference to the event's description. */
QString description() const;
/** sets the event's short summary. */
void setSummary(const QString &summary);
/** returns a reference to the event's summary. */
QString summary() const;
/** set event's applicable categories */
void setCategories(const QStringList &categories, bool setForRelations = false);
void addCategories(const QStringList &categories, bool addToRelations = false);
/** set event's categories based on a comma delimited string */
void setCategories(const QString &catStr);
/** return categories in a list */
QStringList categories() const;
QStringList* categoriesP();
/** return categories as a comma separated string */
QString categoriesStr();
QString categoriesStrWithSpace();
/** point at some other event to which the event relates. This function should
* only be used when constructing a calendar before the related Event
* exists. */
void setRelatedToUid(const QString &);
/** what event does this one relate to? This function should
* only be used when constructing a calendar before the related Event
* exists. */
QString relatedToUid() const;
/** point at some other event to which the event relates */
void setRelatedTo(Incidence *relatedTo);
/** what event does this one relate to? */
Incidence *relatedTo() const;
/** All events that are related to this event */
QPtrList<Incidence> relations() const;
/** Add an event which is related to this event */
void addRelation(Incidence *);
/** Remove event that is related to this event */
void removeRelation(Incidence *);
/** returns the list of dates which are exceptions to the recurrence rule */
DateList exDates() const;
/** sets the list of dates which are exceptions to the recurrence rule */
void setExDates(const DateList &_exDates);
void setExDates(const char *dates);
/** Add a date to the list of exceptions of the recurrence rule. */
void addExDate(const QDate &date);
/** returns true if there is an exception for this date in the recurrence
rule set, or false otherwise. */
bool isException(const QDate &qd) const;
/** add attachment to this event */
void addAttachment(Attachment *attachment);
/** remove and delete a specific attachment */
void deleteAttachment(Attachment *attachment);
/** remove and delete all attachments with this mime type */
void deleteAttachments(const QString& mime);
/** return list of all associated attachments */
QPtrList<Attachment> attachments() const;
/** find a list of attachments with this mime type */
QPtrList<Attachment> attachments(const QString& mime) const;
/** sets the event's status the value specified. See the enumeration
* above for possible values. */
void setSecrecy(int);
/** return the event's secrecy. */
int secrecy() const;
/** return the event's secrecy in string format. */
QString secrecyStr() const;
/** return list of all availbale secrecy classes */
static QStringList secrecyList();
/** return human-readable name of secrecy class */
static QString secrecyName(int);
/** returns TRUE if the date specified is one on which the event will
* recur. */
bool recursOn(const QDate &qd) const;
// VEVENT and VTODO, but not VJOURNAL (move to EventBase class?):
/** set resources used, such as Office, Car, etc. */
void setResources(const QStringList &resources);
/** return list of current resources */
QStringList resources() const;
/** set the event's priority, 0 is undefined, 1 highest (decreasing order) */
void setPriority(int priority);
/** get the event's priority */
int priority() const;
/** All alarms that are associated with this incidence */
QPtrList<Alarm> alarms() const;
/** Create a new alarm which is associated with this incidence */
Alarm* newAlarm();
/** Add an alarm which is associated with this incidence */
void addAlarm(Alarm*);
/** Remove an alarm that is associated with this incidence */
void removeAlarm(Alarm*);
/** Remove all alarms that are associated with this incidence */
void clearAlarms();
/** return whether any alarm associated with this incidence is enabled */
bool isAlarmEnabled() const;
/**
Return the recurrence rule associated with this incidence. If there is
none, returns an appropriate (non-0) object.
*/
- Recurrence *recurrence() const;
+ Recurrence *recurrence();
void setRecurrence(Recurrence * r);
/**
Forward to Recurrence::doesRecur().
*/
ushort doesRecur() const;
/** set the event's/todo's location. Do _not_ use it with journal */
void setLocation(const QString &location);
/** return the event's/todo's location. Do _not_ use it with journal */
QString location() const;
/** returns TRUE or FALSE depending on whether the todo has a start date */
bool hasStartDate() const;
/** sets the event's hasStartDate value. */
void setHasStartDate(bool f);
QDateTime getNextOccurence( const QDateTime& dt, bool* yes ) const;
bool cancelled() const;
void setCancelled( bool b );
bool hasRecurrenceID() const;
void setHasRecurrenceID( bool b );
void setRecurrenceID(QDateTime);
QDateTime recurrenceID () const;
QDateTime dtStart() const;
bool isHoliday() const;
bool isBirthday() const;
bool isAnniversary() const;
QDateTime lastModifiedSub();
+ QString recurrenceText() const;
void setLastModifiedSubInvalid();
+ Recurrence *mRecurrence;
protected:
QPtrList<Alarm> mAlarms;
QPtrList<Incidence> mRelations;
QDateTime mRecurrenceID;
bool mHasRecurrenceID;
private:
void checkCategories();
bool mHoliday, mBirthday, mAnniversary;
int mRevision;
bool mCancelled;
// base components of jounal, event and todo
QDateTime mCreated;
QDateTime mLastModifiedSub;
QString mDescription;
QString mSummary;
QStringList mCategories;
Incidence *mRelatedTo;
QString mRelatedToUid;
DateList mExDates;
QPtrList<Attachment> mAttachments;
QStringList mResources;
bool mHasStartDate; // if todo has associated start date
int mSecrecy;
int mPriority; // 1 = highest, 2 = less, etc.
//QPtrList<Alarm> mAlarms;
- Recurrence *mRecurrence;
QString mLocation;
};
bool operator==( const Incidence&, const Incidence& );
}
#endif
diff --git a/libkcal/kincidenceformatter.cpp b/libkcal/kincidenceformatter.cpp
index 9359fad..f8f40f1 100644
--- a/libkcal/kincidenceformatter.cpp
+++ b/libkcal/kincidenceformatter.cpp
@@ -1,425 +1,425 @@
#include "kincidenceformatter.h"
#include <kstaticdeleter.h>
#include <kglobal.h>
#include <klocale.h>
#ifdef DEKTOP_VERSION
#include <kabc/stdaddressbook.h>
#define size count
#endif
KIncidenceFormatter* KIncidenceFormatter::mInstance = 0;
static KStaticDeleter<KIncidenceFormatter> insd;
QString KIncidenceFormatter::getFormattedText( Incidence * inc, bool details, bool created , bool modified )
{
// #ifndef QT_NO_INPUTDIALOG
// return QInputDialog::getItem( caption, label, items, current, editable );
// #else
// return QString::null;
// #endif
mDetails = details;
mCreated = created ;
mModified = modified;
mText = "";
if ( inc->typeID() == eventID )
setEvent((Event *) inc );
else if ( inc->typeID() == todoID )
setTodo((Todo *) inc );
return mText;
}
KIncidenceFormatter* KIncidenceFormatter::instance()
{
if (!mInstance) {
mInstance = insd.setObject(new KIncidenceFormatter());
}
return mInstance;
}
KIncidenceFormatter::~KIncidenceFormatter()
{
if (mInstance == this)
mInstance = insd.setObject(0);
//qDebug("KIncidenceFormatter::~KIncidenceFormatter ");
}
KIncidenceFormatter::KIncidenceFormatter()
{
mColorMode = 0;
}
void KIncidenceFormatter::setEvent(Event *event)
{
int mode = 0;
mCurrentIncidence = event;
bool shortDate = true;
if ( mode == 0 ) {
addTag("h3",deTag(event->summary()));
formatReadOnly(event);
}
else {
if ( mColorMode == 1 ) {
mText +="<font color=\"#00A000\">";
}
if ( mColorMode == 2 ) {
mText +="<font color=\"#C00000\">";
}
// mText +="<font color=\"#F00000\">" + i18n("O-due!") + "</font>";
if ( mode == 1 ) {
addTag("h2",i18n( "Local: " ) +deTag(event->summary()));
} else {
addTag("h2",i18n( "Remote: " ) +deTag(event->summary()));
}
formatReadOnly(event);
addTag("h3",i18n( "Last modified: " ) + KGlobal::locale()->formatDateTime(event->lastModified(),shortDate, true ) );
if ( mColorMode )
mText += "</font>";
}
if (event->cancelled ()) {
mText +="<font color=\"#B00000\">";
addTag("i",i18n("This event has been cancelled!"));
mText.append("<br>");
mText += "</font>";
}
if (event->doesFloat()) {
if (event->isMultiDay()) {
mText.append(i18n("<p><b>From:</b> %1 </p><p><b>To:</b> %2</p>")
.arg(event->dtStartDateStr(shortDate))
.arg(event->dtEndDateStr(shortDate)));
} else {
mText.append(i18n("<p><b>On:</b> %1</p>").arg(event->dtStartDateStr( shortDate )));
}
} else {
if (event->isMultiDay()) {
mText.append(i18n("<p><b>From:</b> %1</p> ")
.arg(event->dtStartStr( shortDate)));
mText.append(i18n("<p><b>To:</b> %1</p>")
.arg(event->dtEndStr(shortDate)));
} else {
mText.append(i18n("<p><b>From:</b> %1 <b>To:</b> %2</p>")
.arg(event->dtStartTimeStr())
.arg(event->dtEndTimeStr()));
mText.append(i18n("<p><b>On:</b> %1</p> ")
.arg(event->dtStartDateStr( shortDate )));
}
}
if (!event->location().isEmpty()) {
addTag("b",i18n("Location: "));
mText.append(deTag(event->location())+"<br>");
}
- if (event->recurrence()->doesRecur()) {
+ if (event->doesRecur()) {
QString recurText = event->recurrence()->recurrenceText();
addTag("p","<em>" + i18n("This is a %1 recurring event.").arg(recurText ) + "</em>");
bool ok;
QDate start = QDate::currentDate();
QDateTime next;
next = event->getNextOccurence( QDateTime::currentDateTime() , &ok );
if ( ok ) {
addTag("p",i18n("<b>Next recurrence is on:</b>") );
addTag("p", KGlobal::locale()->formatDate( next.date(), shortDate ));
} else {
bool last;
QDate nextd;
nextd = event->recurrence()->getPreviousDate( QDate::currentDate() , &last );
if ( last ) {
addTag("p",i18n("<b>Last recurrence was on:</b>") );
addTag("p", KGlobal::locale()->formatDate( nextd, shortDate ));
}
}
}
if (event->isAlarmEnabled()) {
Alarm *alarm =event->alarms().first() ;
QDateTime t = alarm->time();
QString s =i18n("( %1 before )").arg( alarm->offsetText() );
addTag("p",i18n("<b>Alarm on: </b>") + s + ": "+KGlobal::locale()->formatDateTime( t, shortDate ));
//addTag("p", KGlobal::locale()->formatDateTime( t, shortDate ));
//addTag("p",s);
}
addTag("p",i18n("<b>Access: </b>") +event->secrecyStr() );
// mText.append(event->secrecyStr()+"<br>");
formatCategories(event);
formatAttendees(event);
if ( mCreated ) {
#ifdef DESKTOP_VERSION
addTag("p",i18n("<b>Created: ") +" </b>"+KGlobal::locale()->formatDateTime( event->created(), shortDate ));
#else
addTag("p",i18n("<b>Created: ") +" </b>");
addTag("p", KGlobal::locale()->formatDateTime( event->created(), shortDate ));
#endif
}
if ( mModified ) {
#ifdef DESKTOP_VERSION
addTag("p",i18n("<b>Last modified: ") +" </b>"+KGlobal::locale()->formatDateTime( event->lastModified(), shortDate ));
#else
addTag("p",i18n("<b>Last modified: ") +" </b>");
addTag("p", KGlobal::locale()->formatDateTime( event->lastModified(), shortDate ));
#endif
}
if ( mDetails ) {
if (!event->description().isEmpty()) {
addTag("p",i18n("<b>Details: </b>"));
addTag("p",deTag(event->description()));
}
}
}
void KIncidenceFormatter::setTodo(Todo *event )
{
int mode = 0;
mCurrentIncidence = event;
bool shortDate = true;
if (mode == 0 ) {
addTag("h3",deTag(event->summary()));
formatReadOnly(event);
}
else {
if ( mColorMode == 1 ) {
mText +="<font color=\"#00A000\">";
}
if ( mColorMode == 2 ) {
mText +="<font color=\"#B00000\">";
}
if ( mode == 1 ) {
addTag("h2",i18n( "Local: " ) +deTag(event->summary()));
} else {
addTag("h2",i18n( "Remote: " ) +deTag(event->summary()));
}
formatReadOnly(event);
addTag("h3",i18n( "Last modified: " ) + KGlobal::locale()->formatDateTime(event->lastModified(),shortDate, true ) );
if ( mColorMode )
mText += "</font>";
}
if ( event->percentComplete() == 100 && event->hasCompletedDate() ) {
mText +="<font color=\"#B00000\">";
addTag("i", i18n("<p><i>Completed on %1</i></p>").arg( event->completedStr(shortDate) ) );
mText += "</font>";
} else {
mText.append(i18n("<p><i>%1 % completed</i></p>")
.arg(event->percentComplete()));
}
if (event->cancelled ()) {
mText +="<font color=\"#B00000\">";
addTag("i",i18n("This todo has been cancelled!"));
mText.append("<br>");
mText += "</font>";
}
- if (event->recurrence()->doesRecur()) {
+ if (event->doesRecur()) {
QString recurText = event->recurrence()->recurrenceText();
addTag("p","<em>" + i18n("This is a %1 recurring todo.").arg(recurText ) + "</em>");
}
if (event->hasStartDate()) {
mText.append(i18n("<p><b>Start on:</b> %1</p>").arg(event->dtStartStr(shortDate)));
}
if (event->hasDueDate()) {
mText.append(i18n("<p><b>Due on:</b> %1</p>").arg(event->dtDueStr(shortDate)));
}
if (!event->location().isEmpty()) {
addTag("b",i18n("Location: "));
mText.append(deTag(event->location())+"<br>");
}
mText.append(i18n("<p><b>Priority:</b> %2</p>")
.arg(QString::number(event->priority())));
if (event->isAlarmEnabled()) {
Alarm *alarm =event->alarms().first() ;
QDateTime t = alarm->time();
QString s =i18n("( %1 before )").arg( alarm->offsetText() );
addTag("p",i18n("<b>Alarm on: ") + s +" </b>");
addTag("p", KGlobal::locale()->formatDateTime( t, shortDate ));
//addTag("p",s);
}
addTag("p",i18n("<b>Access: </b>") +event->secrecyStr() );
formatCategories(event);
formatAttendees(event);
if ( mCreated ) {
#ifdef DESKTOP_VERSION
addTag("p",i18n("<b>Created: ") +" </b>"+KGlobal::locale()->formatDateTime( event->created(), shortDate ));
#else
addTag("p",i18n("<b>Created: ") +" </b>");
addTag("p", KGlobal::locale()->formatDateTime( event->created(), shortDate ));
#endif
}
if ( mModified ) {
#ifdef DESKTOP_VERSION
addTag("p",i18n("<b>Last modified: ") +" </b>"+KGlobal::locale()->formatDateTime( event->lastModified(), shortDate ));
#else
addTag("p",i18n("<b>Last modified: ") +" </b>");
addTag("p", KGlobal::locale()->formatDateTime( event->lastModified(), shortDate ));
#endif
}
if ( mDetails ) {
if (!event->description().isEmpty()) {
addTag("p",i18n("<b>Details: </b>"));
addTag("p",deTag(event->description()));
}
}
}
void KIncidenceFormatter::setJournal(Journal* )
{
}
void KIncidenceFormatter::formatCategories(Incidence *event)
{
if (!event->categoriesStr().isEmpty()) {
addTag("p",i18n("<b>Categories: </b>")+event->categoriesStrWithSpace() );
//mText.append(event->categoriesStr());
}
}
void KIncidenceFormatter::addTag(const QString & tag,const QString & text)
{
int number=text.contains("\n");
QString str = "<" + tag + ">";
QString tmpText=text;
QString tmpStr=str;
if(number !=-1)
{
if (number > 0) {
int pos=0;
QString tmp;
for(int i=0;i<=number;i++) {
pos=tmpText.find("\n");
tmp=tmpText.left(pos);
tmpText=tmpText.right(tmpText.length()-pos-1);
tmpStr+=tmp+"<br>";
}
}
else tmpStr += tmpText;
tmpStr+="</" + tag + ">";
mText.append(tmpStr);
}
else
{
str += text + "</" + tag + ">";
mText.append(str);
}
}
void KIncidenceFormatter::formatAttendees(Incidence *event)
{
QPtrList<Attendee> attendees = event->attendees();
if (attendees.count()) {
QString iconPath = KGlobal::iconLoader()->iconPath("mailappt",KIcon::Small);
QString NOiconPath = KGlobal::iconLoader()->iconPath("nomailappt",KIcon::Small);
addTag("h3",i18n("Organizer"));
mText.append("<ul><li>");
#if 0
//ndef KORG_NOKABC
KABC::AddressBook *add_book = KABC::StdAddressBook::self();
KABC::Addressee::List addressList;
addressList = add_book->findByEmail(event->organizer());
KABC::Addressee o = addressList.first();
if (!o.isEmpty() && addressList.size()<2) {
mText += "<a href=\"uid:" + o.uid() + "\">";
mText += o.formattedName();
mText += "</a>\n";
} else {
mText.append(event->organizer());
}
#else
mText.append(event->organizer());
#endif
if (iconPath) {
mText += " <a href=\"mailto:" + event->organizer() + "\">";
mText += "<IMG src=\"" + iconPath + "\">";
mText += "</a>\n";
}
mText.append("</li></ul>");
addTag("h3",i18n("Attendees"));
Attendee *a;
mText.append("<ul>");
for(a=attendees.first();a;a=attendees.next()) {
#if 0
//ndef KORG_NOKABC
if (a->name().isEmpty()) {
addressList = add_book->findByEmail(a->email());
KABC::Addressee o = addressList.first();
if (!o.isEmpty() && addressList.size()<2) {
mText += "<a href=\"uid:" + o.uid() + "\">";
mText += o.formattedName();
mText += "</a>\n";
} else {
mText += "<li>";
mText.append(a->email());
mText += "\n";
}
} else {
mText += "<li><a href=\"uid:" + a->uid() + "\">";
if (!a->name().isEmpty()) mText += a->name();
else mText += a->email();
mText += "</a>\n";
}
#else
//qDebug("nokabc ");
mText += "<li><a href=\"uid:" + a->uid() + "\">";
if (!a->name().isEmpty()) mText += a->name();
else mText += a->email();
mText += "</a>\n";
#endif
if (!a->email().isEmpty()) {
if (iconPath) {
mText += "<a href=\"mailto:" + a->name() +" "+ "<" + a->email() + ">" + "\">";
if ( a->RSVP() )
mText += "<IMG src=\"" + iconPath + "\">";
else
mText += "<IMG src=\"" + NOiconPath + "\">";
mText += "</a>\n";
}
}
if (a->status() != Attendee::NeedsAction )
mText +="[" + a->statusStr() + "] ";
if (a->role() == Attendee::Chair )
mText +="(" + a->roleStr().left(1) + ".)";
}
mText.append("</li></ul>");
}
}
void KIncidenceFormatter::formatReadOnly(Incidence *event)
{
if (event->isReadOnly()) {
addTag("p","<em>(" + i18n("read-only") + ")</em>");
}
}
QString KIncidenceFormatter::deTag(QString text)
{
#if QT_VERSION >= 0x030000
text.replace( '<' , "&lt;" );
text.replace( '>' , "&gt;" );
#else
if ( text.find ('<') >= 0 ) {
text.replace( QRegExp("<") , "&lt;" );
}
if ( text.find ('>') >= 0 ) {
text.replace( QRegExp(">") , "&gt;" );
}
#endif
return text;
}
diff --git a/libkcal/vcalformat.cpp b/libkcal/vcalformat.cpp
index 8efc1ea..2e19740 100644
--- a/libkcal/vcalformat.cpp
+++ b/libkcal/vcalformat.cpp
@@ -1,1230 +1,1230 @@
/*
This file is part of libkcal.
Copyright (c) 1998 Preston Brwon
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 <qapplication.h>
#include <qdatetime.h>
#include <qstring.h>
#include <qptrlist.h>
#include <qregexp.h>
#include <qclipboard.h>
#include <qdialog.h>
#include <qfile.h>
#include <kdebug.h>
#include <kglobal.h>
#include <kmessagebox.h>
#include <kiconloader.h>
#include <klocale.h>
#include "vcc.h"
#include "vobject.h"
#include "vcaldrag.h"
#include "calendar.h"
#include "vcalformat.h"
using namespace KCal;
VCalFormat::VCalFormat()
{
mCalendar = 0;
useLocalTime = false;
}
VCalFormat::~VCalFormat()
{
}
void VCalFormat::setLocalTime ( bool b )
{
useLocalTime = b;
}
bool VCalFormat::load(Calendar *calendar, const QString &fileName)
{
mCalendar = calendar;
clearException();
if ( ! useLocalTime )
useLocalTime = mCalendar->isLocalTime();
VObject *vcal = 0;
// this is not necessarily only 1 vcal. Could be many vcals, or include
// a vcard...
vcal = Parse_MIME_FromFileName(const_cast<char *>(QFile::encodeName(fileName).data()));
if (!vcal) {
setException(new ErrorFormat(ErrorFormat::CalVersionUnknown));
return FALSE;
}
// any other top-level calendar stuff should be added/initialized here
// put all vobjects into their proper places
populate(vcal);
// clean up from vcal API stuff
cleanVObjects(vcal);
cleanStrTbl();
return true;
}
bool VCalFormat::save(Calendar *calendar, const QString &fileName)
{
mCalendar = calendar;
if ( ! useLocalTime )
useLocalTime = mCalendar->isLocalTime();
QString tmpStr;
VObject *vcal, *vo;
vcal = newVObject(VCCalProp);
// addPropValue(vcal,VCLocationProp, "0.0");
addPropValue(vcal,VCProdIdProp, productId());
tmpStr = mCalendar->getTimeZoneStr();
//qDebug("mCalendar->getTimeZoneStr() %s",tmpStr.latin1() );
addPropValue(vcal,VCTimeZoneProp, tmpStr.local8Bit());
addPropValue(vcal,VCVersionProp, _VCAL_VERSION);
// TODO STUFF
QPtrList<Todo> todoList = mCalendar->rawTodos();
QPtrListIterator<Todo> qlt(todoList);
for (; qlt.current(); ++qlt) {
vo = eventToVTodo(qlt.current());
addVObjectProp(vcal, vo);
}
// EVENT STUFF
QPtrList<Event> events = mCalendar->rawEvents();
Event *ev;
for(ev=events.first();ev;ev=events.next()) {
vo = eventToVEvent(ev);
addVObjectProp(vcal, vo);
}
writeVObjectToFile(QFile::encodeName(fileName).data() ,vcal);
cleanVObjects(vcal);
cleanStrTbl();
if (QFile::exists(fileName)) {
return true;
} else {
return false; // error
}
}
bool VCalFormat::fromString( Calendar *calendar, const QString &text )
{
// TODO: Factor out VCalFormat::fromString()
QCString data = text.utf8();
if ( !data.size() ) return false;
VObject *vcal = Parse_MIME( data.data(), data.size());
if ( !vcal ) return false;
VObjectIterator i;
VObject *curvo;
initPropIterator( &i, vcal );
// we only take the first object. TODO: parse all incidences.
do {
curvo = nextVObject( &i );
} while ( strcmp( vObjectName( curvo ), VCEventProp ) &&
strcmp( vObjectName( curvo ), VCTodoProp ) );
if ( strcmp( vObjectName( curvo ), VCEventProp ) == 0 ) {
Event *event = VEventToEvent( curvo );
calendar->addEvent( event );
} else {
qDebug("VCalFormat::fromString(): Unknown object type. ");
deleteVObject( vcal );
return false;
}
deleteVObject( vcal );
return true;
}
QString VCalFormat::eventToString( Event * event, Calendar *calendar, bool useLocal)
{
if ( !event ) return QString::null;
bool useL = useLocalTime;
useLocalTime = useLocal;
mCalendar = calendar;
VObject *vevent = eventToVEvent( event );
char *buf = writeMemVObject( 0, 0, vevent );
QString result( buf );
cleanVObject( vevent );
useLocalTime = useL;
return result;
}
QString VCalFormat::todoToString( Todo * todo, Calendar *calendar, bool useLocal )
{
if ( !todo ) return QString::null;
bool useL = useLocalTime;
useLocalTime = useLocal;
mCalendar = calendar;
VObject *vevent = eventToVTodo( todo );
char *buf = writeMemVObject( 0, 0, vevent );
QString result( buf );
cleanVObject( vevent );
useLocalTime = useL;
return result;
}
QString VCalFormat::toString( Calendar *calendar )
{
// TODO: Factor out VCalFormat::asString()
VObject *vcal = newVObject(VCCalProp);
addPropValue( vcal, VCProdIdProp, CalFormat::productId() );
QString tmpStr = mCalendar->getTimeZoneStr();
addPropValue( vcal, VCTimeZoneProp, tmpStr.local8Bit() );
addPropValue( vcal, VCVersionProp, _VCAL_VERSION );
// TODO: Use all data.
QPtrList<Event> events = calendar->events();
Event *event = events.first();
if ( !event ) return QString::null;
VObject *vevent = eventToVEvent( event );
addVObjectProp( vcal, vevent );
char *buf = writeMemVObject( 0, 0, vcal );
QString result( buf );
cleanVObject( vcal );
return result;
}
VObject *VCalFormat::eventToVTodo(const Todo *anEvent)
{
VObject *vtodo;
QString tmpStr;
vtodo = newVObject(VCTodoProp);
// due date
if (anEvent->hasDueDate()) {
tmpStr = qDateTimeToISO(anEvent->dtDue(),
!anEvent->doesFloat());
addPropValue(vtodo, VCDueProp, tmpStr.local8Bit());
}
// start date
if (anEvent->hasStartDate()) {
tmpStr = qDateTimeToISO(anEvent->dtStart(),
!anEvent->doesFloat());
addPropValue(vtodo, VCDTstartProp, tmpStr.local8Bit());
}
// creation date
tmpStr = qDateTimeToISO(anEvent->created());
addPropValue(vtodo, VCDCreatedProp, tmpStr.local8Bit());
// unique id
addPropValue(vtodo, VCUniqueStringProp,
anEvent->uid().local8Bit());
// revision
tmpStr.sprintf("%i", anEvent->revision());
addPropValue(vtodo, VCSequenceProp, tmpStr.local8Bit());
// last modification date
tmpStr = qDateTimeToISO(anEvent->lastModified());
addPropValue(vtodo, VCLastModifiedProp, tmpStr.local8Bit());
// organizer stuff
tmpStr = "MAILTO:" + anEvent->organizer();
addPropValue(vtodo, ICOrganizerProp, tmpStr.local8Bit());
// attendees
if (anEvent->attendeeCount() != 0) {
QPtrList<Attendee> al = anEvent->attendees();
QPtrListIterator<Attendee> ai(al);
Attendee *curAttendee;
for (; ai.current(); ++ai) {
curAttendee = ai.current();
if (!curAttendee->email().isEmpty() &&
!curAttendee->name().isEmpty())
tmpStr = "MAILTO:" + curAttendee->name() + " <" +
curAttendee->email() + ">";
else if (curAttendee->name().isEmpty())
tmpStr = "MAILTO: " + curAttendee->email();
else if (curAttendee->email().isEmpty())
tmpStr = "MAILTO: " + curAttendee->name();
else if (curAttendee->name().isEmpty() &&
curAttendee->email().isEmpty())
kdDebug(5800) << "warning! this Event has an attendee w/o name or email!" << endl;
VObject *aProp = addPropValue(vtodo, VCAttendeeProp, tmpStr.local8Bit());
addPropValue(aProp, VCRoleProp, writeRole(curAttendee->role()));
addPropValue(aProp, VCRSVPProp, curAttendee->RSVP() ? "TRUE" : "FALSE");
addPropValue(aProp, VCStatusProp, writeStatus(curAttendee->status()));
}
}
// description BL:
if (!anEvent->description().isEmpty()) {
VObject *d = addPropValue(vtodo, VCDescriptionProp,
anEvent->description().local8Bit());
if (anEvent->description().find('\n') != -1)
addProp(d, VCQuotedPrintableProp);
}
// summary
if (!anEvent->summary().isEmpty())
addPropValue(vtodo, VCSummaryProp, anEvent->summary().local8Bit());
if (!anEvent->location().isEmpty())
addPropValue(vtodo, VCLocationProp, anEvent->location().local8Bit());
// completed
// status
// backward compatibility, KOrganizer used to interpret only these two values
addPropValue(vtodo, VCStatusProp, anEvent->isCompleted() ? "COMPLETED" :
"NEEDS_ACTION");
// completion date
if (anEvent->hasCompletedDate()) {
tmpStr = qDateTimeToISO(anEvent->completed());
addPropValue(vtodo, VCCompletedProp, tmpStr.local8Bit());
}
// priority
tmpStr.sprintf("%i",anEvent->priority());
addPropValue(vtodo, VCPriorityProp, tmpStr.local8Bit());
// related event
if (anEvent->relatedToUid()) {
addPropValue(vtodo, VCRelatedToProp,
anEvent->relatedToUid().local8Bit());
}
// categories
QStringList tmpStrList = anEvent->categories();
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);
addPropValue(vtodo, VCCategoriesProp, tmpStr.local8Bit());
}
// alarm stuff
kdDebug(5800) << "vcalformat::eventToVTodo was called" << endl;
QPtrList<Alarm> alarms = anEvent->alarms();
Alarm* alarm;
for (alarm = alarms.first(); alarm; alarm = alarms.next()) {
if (alarm->enabled()) {
VObject *a;
tmpStr = qDateTimeToISO(alarm->time());
if (alarm->type() == Alarm::Audio) {
a = addProp(vtodo, VCAAlarmProp);
addPropValue(a, VCRunTimeProp, tmpStr.local8Bit());
addPropValue(a, VCRepeatCountProp, "1");
addPropValue(a, VCAudioContentProp, QFile::encodeName(alarm->audioFile()));
}
else if (alarm->type() == Alarm::Procedure) {
a = addProp(vtodo, VCPAlarmProp);
addPropValue(a, VCRunTimeProp, tmpStr.local8Bit());
addPropValue(a, VCRepeatCountProp, "1");
addPropValue(a, VCProcedureNameProp, QFile::encodeName(alarm->programFile()));
} else {
a = addProp(vtodo, VCDAlarmProp);
addPropValue(a, VCRunTimeProp, tmpStr.local8Bit());
addPropValue(a, VCRepeatCountProp, "1");
addPropValue(a, VCDisplayStringProp, "beep!");
}
}
}
if (anEvent->pilotId()) {
// pilot sync stuff
tmpStr.sprintf("%i",anEvent->pilotId());
addPropValue(vtodo, XPilotIdProp, tmpStr.local8Bit());
tmpStr.sprintf("%i",anEvent->syncStatus());
addPropValue(vtodo, XPilotStatusProp, tmpStr.local8Bit());
}
return vtodo;
}
-VObject* VCalFormat::eventToVEvent(const Event *anEvent)
+VObject* VCalFormat::eventToVEvent(Event *anEvent)
{
VObject *vevent;
QString tmpStr;
vevent = newVObject(VCEventProp);
// start and end time
tmpStr = qDateTimeToISO(anEvent->dtStart(),
!anEvent->doesFloat());
addPropValue(vevent, VCDTstartProp, tmpStr.local8Bit());
// events that have time associated but take up no time should
// not have both DTSTART and DTEND.
if (anEvent->dtStart() != anEvent->dtEnd()) {
tmpStr = qDateTimeToISO(anEvent->dtEnd(),
!anEvent->doesFloat());
addPropValue(vevent, VCDTendProp, tmpStr.local8Bit());
}
// creation date
tmpStr = qDateTimeToISO(anEvent->created());
addPropValue(vevent, VCDCreatedProp, tmpStr.local8Bit());
// unique id
addPropValue(vevent, VCUniqueStringProp,
anEvent->uid().local8Bit());
// revision
tmpStr.sprintf("%i", anEvent->revision());
addPropValue(vevent, VCSequenceProp, tmpStr.local8Bit());
// last modification date
tmpStr = qDateTimeToISO(anEvent->lastModified());
addPropValue(vevent, VCLastModifiedProp, tmpStr.local8Bit());
// attendee and organizer stuff
tmpStr = "MAILTO:" + anEvent->organizer();
addPropValue(vevent, ICOrganizerProp, tmpStr.local8Bit());
if (anEvent->attendeeCount() != 0) {
QPtrList<Attendee> al = anEvent->attendees();
QPtrListIterator<Attendee> ai(al);
Attendee *curAttendee;
// TODO: Put this functionality into Attendee class
for (; ai.current(); ++ai) {
curAttendee = ai.current();
if (!curAttendee->email().isEmpty() &&
!curAttendee->name().isEmpty())
tmpStr = "MAILTO:" + curAttendee->name() + " <" +
curAttendee->email() + ">";
else if (curAttendee->name().isEmpty())
tmpStr = "MAILTO: " + curAttendee->email();
else if (curAttendee->email().isEmpty())
tmpStr = "MAILTO: " + curAttendee->name();
else if (curAttendee->name().isEmpty() &&
curAttendee->email().isEmpty())
kdDebug(5800) << "warning! this Event has an attendee w/o name or email!" << endl;
VObject *aProp = addPropValue(vevent, VCAttendeeProp, tmpStr.local8Bit());
addPropValue(aProp, VCRoleProp, writeRole(curAttendee->role()));
addPropValue(aProp, VCRSVPProp, curAttendee->RSVP() ? "TRUE" : "FALSE");
addPropValue(aProp, VCStatusProp, writeStatus(curAttendee->status()));
}
}
// recurrence rule stuff
- if (anEvent->recurrence()->doesRecur()) {
+ if (anEvent->doesRecur()) {
// some more variables
QPtrList<Recurrence::rMonthPos> tmpPositions;
QPtrList<int> tmpDays;
int *tmpDay;
Recurrence::rMonthPos *tmpPos;
QString tmpStr2;
int i;
switch(anEvent->recurrence()->doesRecur()) {
case Recurrence::rDaily:
tmpStr.sprintf("D%i ",anEvent->recurrence()->frequency());
// if (anEvent->rDuration > 0)
// tmpStr += "#";
break;
case Recurrence::rWeekly:
tmpStr.sprintf("W%i ",anEvent->recurrence()->frequency());
for (i = 0; i < 7; i++) {
if (anEvent->recurrence()->days().testBit(i))
tmpStr += dayFromNum(i);
}
break;
case Recurrence::rMonthlyPos:
tmpStr.sprintf("MP%i ", anEvent->recurrence()->frequency());
// write out all rMonthPos's
tmpPositions = anEvent->recurrence()->monthPositions();
for (tmpPos = tmpPositions.first();
tmpPos;
tmpPos = tmpPositions.next()) {
tmpStr2.sprintf("%i", tmpPos->rPos);
if (tmpPos->negative)
tmpStr2 += "- ";
else
tmpStr2 += "+ ";
tmpStr += tmpStr2;
for (i = 0; i < 7; i++) {
if (tmpPos->rDays.testBit(i))
tmpStr += dayFromNum(i);
}
} // loop for all rMonthPos's
break;
case Recurrence::rMonthlyDay:
tmpStr.sprintf("MD%i ", anEvent->recurrence()->frequency());
// write out all rMonthDays;
tmpDays = anEvent->recurrence()->monthDays();
for (tmpDay = tmpDays.first();
tmpDay;
tmpDay = tmpDays.next()) {
tmpStr2.sprintf("%i ", *tmpDay);
tmpStr += tmpStr2;
}
break;
case Recurrence::rYearlyMonth:
tmpStr.sprintf("YM%i ", anEvent->recurrence()->frequency());
// write out all the rYearNums;
tmpDays = anEvent->recurrence()->yearNums();
for (tmpDay = tmpDays.first();
tmpDay;
tmpDay = tmpDays.next()) {
tmpStr2.sprintf("%i ", *tmpDay);
tmpStr += tmpStr2;
}
break;
case Recurrence::rYearlyDay:
tmpStr.sprintf("YD%i ", anEvent->recurrence()->frequency());
// write out all the rYearNums;
tmpDays = anEvent->recurrence()->yearNums();
for (tmpDay = tmpDays.first();
tmpDay;
tmpDay = tmpDays.next()) {
tmpStr2.sprintf("%i ", *tmpDay);
tmpStr += tmpStr2;
}
break;
default:
kdDebug(5800) << "ERROR, it should never get here in eventToVEvent!" << endl;
break;
} // switch
if (anEvent->recurrence()->duration() > 0) {
tmpStr2.sprintf("#%i",anEvent->recurrence()->duration());
tmpStr += tmpStr2;
} else if (anEvent->recurrence()->duration() == -1) {
tmpStr += "#0"; // defined as repeat forever
} else {
tmpStr += qDateTimeToISO(anEvent->recurrence()->endDate(), FALSE);
}
addPropValue(vevent,VCRRuleProp, tmpStr.local8Bit());
} // event repeats
// exceptions to recurrence
DateList dateList = anEvent->exDates();
DateList::ConstIterator it;
QString tmpStr2;
for (it = dateList.begin(); it != dateList.end(); ++it) {
tmpStr = qDateToISO(*it) + ";";
tmpStr2 += tmpStr;
}
if (!tmpStr2.isEmpty()) {
tmpStr2.truncate(tmpStr2.length()-1);
addPropValue(vevent, VCExpDateProp, tmpStr2.local8Bit());
}
// description
if (!anEvent->description().isEmpty()) {
VObject *d = addPropValue(vevent, VCDescriptionProp,
anEvent->description().local8Bit());
if (anEvent->description().find('\n') != -1)
addProp(d, VCQuotedPrintableProp);
}
// summary
if (!anEvent->summary().isEmpty())
addPropValue(vevent, VCSummaryProp, anEvent->summary().local8Bit());
if (!anEvent->location().isEmpty())
addPropValue(vevent, VCLocationProp, anEvent->location().local8Bit());
// status
// TODO: define Event status
// addPropValue(vevent, VCStatusProp, anEvent->statusStr().local8Bit());
// secrecy
const char *text = 0;
switch (anEvent->secrecy()) {
case Incidence::SecrecyPublic:
text = "PUBLIC";
break;
case Incidence::SecrecyPrivate:
text = "PRIVATE";
break;
case Incidence::SecrecyConfidential:
text = "CONFIDENTIAL";
break;
}
if (text) {
addPropValue(vevent, VCClassProp, text);
}
// categories
QStringList tmpStrList = anEvent->categories();
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);
addPropValue(vevent, VCCategoriesProp, tmpStr.local8Bit());
}
// attachments
// TODO: handle binary attachments!
QPtrList<Attachment> attachments = anEvent->attachments();
for ( Attachment *at = attachments.first(); at; at = attachments.next() )
addPropValue(vevent, VCAttachProp, at->uri().local8Bit());
// resources
tmpStrList = anEvent->resources();
tmpStr = tmpStrList.join(";");
if (!tmpStr.isEmpty())
addPropValue(vevent, VCResourcesProp, tmpStr.local8Bit());
// alarm stuff
QPtrList<Alarm> alarms = anEvent->alarms();
Alarm* alarm;
for (alarm = alarms.first(); alarm; alarm = alarms.next()) {
if (alarm->enabled()) {
VObject *a ;
tmpStr = qDateTimeToISO(alarm->time());
if (alarm->type() == Alarm::Audio) {
a = addProp(vevent, VCAAlarmProp);
addPropValue(a, VCRunTimeProp, tmpStr.local8Bit());
addPropValue(a, VCRepeatCountProp, "1");
addPropValue(a, VCAudioContentProp, QFile::encodeName(alarm->audioFile()));
}
if (alarm->type() == Alarm::Procedure) {
a = addProp(vevent, VCPAlarmProp);
addPropValue(a, VCRunTimeProp, tmpStr.local8Bit());
addPropValue(a, VCRepeatCountProp, "1");
addPropValue(a, VCProcedureNameProp, QFile::encodeName(alarm->programFile()));
} else {
a = addProp(vevent, VCDAlarmProp);
addPropValue(a, VCRunTimeProp, tmpStr.local8Bit());
addPropValue(a, VCRepeatCountProp, "1");
addPropValue(a, VCDisplayStringProp, "beep!");
}
}
}
// priority
tmpStr.sprintf("%i",anEvent->priority());
addPropValue(vevent, VCPriorityProp, tmpStr.local8Bit());
// transparency
tmpStr.sprintf("%i",anEvent->transparency());
addPropValue(vevent, VCTranspProp, tmpStr.local8Bit());
// related event
if (anEvent->relatedToUid()) {
addPropValue(vevent, VCRelatedToProp,
anEvent->relatedToUid().local8Bit());
}
if (anEvent->pilotId()) {
// pilot sync stuff
tmpStr.sprintf("%i",anEvent->pilotId());
addPropValue(vevent, XPilotIdProp, tmpStr.local8Bit());
tmpStr.sprintf("%i",anEvent->syncStatus());
addPropValue(vevent, XPilotStatusProp, tmpStr.local8Bit());
}
return vevent;
}
Todo *VCalFormat::VTodoToEvent(VObject *vtodo)
{
VObject *vo;
VObjectIterator voi;
char *s;
Todo *anEvent = new Todo;
// creation date
if ((vo = isAPropertyOf(vtodo, VCDCreatedProp)) != 0) {
anEvent->setCreated(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo))));
deleteStr(s);
}
// unique id
vo = isAPropertyOf(vtodo, VCUniqueStringProp);
// while the UID property is preferred, it is not required. We'll use the
// default Event UID if none is given.
if (vo) {
anEvent->setUid(s = fakeCString(vObjectUStringZValue(vo)));
deleteStr(s);
}
// last modification date
if ((vo = isAPropertyOf(vtodo, VCLastModifiedProp)) != 0) {
anEvent->setLastModified(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo))));
deleteStr(s);
}
else
anEvent->setLastModified(QDateTime(QDate::currentDate(),
QTime::currentTime()));
// organizer
// if our extension property for the event's ORGANIZER exists, add it.
if ((vo = isAPropertyOf(vtodo, ICOrganizerProp)) != 0) {
anEvent->setOrganizer(s = fakeCString(vObjectUStringZValue(vo)));
deleteStr(s);
} else {
anEvent->setOrganizer(mCalendar->getEmail());
}
// attendees.
initPropIterator(&voi, vtodo);
while (moreIteration(&voi)) {
vo = nextVObject(&voi);
if (strcmp(vObjectName(vo), VCAttendeeProp) == 0) {
Attendee *a;
VObject *vp;
s = fakeCString(vObjectUStringZValue(vo));
QString tmpStr = QString::fromLocal8Bit(s);
deleteStr(s);
tmpStr = tmpStr.simplifyWhiteSpace();
int emailPos1, emailPos2;
if ((emailPos1 = tmpStr.find('<')) > 0) {
// both email address and name
emailPos2 = tmpStr.findRev('>');
a = new Attendee(tmpStr.left(emailPos1 - 1),
tmpStr.mid(emailPos1 + 1,
emailPos2 - (emailPos1 + 1)));
} else if (tmpStr.find('@') > 0) {
// just an email address
a = new Attendee(0, tmpStr);
} else {
// just a name
// QString email = tmpStr.replace( QRegExp(" "), "." );
a = new Attendee(tmpStr,0);
}
// is there a Role property?
if ((vp = isAPropertyOf(vo, VCRoleProp)) != 0)
a->setRole(readRole(vObjectStringZValue(vp)));
// is there an RSVP property?
if ((vp = isAPropertyOf(vo, VCRSVPProp)) != 0)
a->setRSVP(vObjectStringZValue(vp));
// is there a status property?
if ((vp = isAPropertyOf(vo, VCStatusProp)) != 0)
a->setStatus(readStatus(vObjectStringZValue(vp)));
// add the attendee
anEvent->addAttendee(a);
}
}
// description for todo
if ((vo = isAPropertyOf(vtodo, VCDescriptionProp)) != 0) {
s = fakeCString(vObjectUStringZValue(vo));
anEvent->setDescription(QString::fromLocal8Bit(s));
deleteStr(s);
}
// summary
if ((vo = isAPropertyOf(vtodo, VCSummaryProp))) {
s = fakeCString(vObjectUStringZValue(vo));
anEvent->setSummary(QString::fromLocal8Bit(s));
deleteStr(s);
}
if ((vo = isAPropertyOf(vtodo, VCLocationProp))) {
s = fakeCString(vObjectUStringZValue(vo));
anEvent->setLocation(QString::fromLocal8Bit(s));
deleteStr(s);
}
// completed
// was: status
if ((vo = isAPropertyOf(vtodo, VCStatusProp)) != 0) {
s = fakeCString(vObjectUStringZValue(vo));
if (strcmp(s,"COMPLETED") == 0) {
anEvent->setCompleted(true);
} else {
anEvent->setCompleted(false);
}
deleteStr(s);
}
else
anEvent->setCompleted(false);
// completion date
if ((vo = isAPropertyOf(vtodo, VCCompletedProp)) != 0) {
anEvent->setCompleted(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo))));
deleteStr(s);
}
// priority
if ((vo = isAPropertyOf(vtodo, VCPriorityProp))) {
anEvent->setPriority(atoi(s = fakeCString(vObjectUStringZValue(vo))));
deleteStr(s);
}
// due date
if ((vo = isAPropertyOf(vtodo, VCDueProp)) != 0) {
anEvent->setDtDue(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo))));
deleteStr(s);
anEvent->setHasDueDate(true);
} else {
anEvent->setHasDueDate(false);
}
// start time
if ((vo = isAPropertyOf(vtodo, VCDTstartProp)) != 0) {
anEvent->setDtStart(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo))));
// kdDebug(5800) << "s is " << // s << ", ISO is " << ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo))).toString() << endl;
deleteStr(s);
anEvent->setHasStartDate(true);
} else {
anEvent->setHasStartDate(false);
}
/* alarm stuff */
//kdDebug(5800) << "vcalformat::VTodoToEvent called" << endl;
if ((vo = isAPropertyOf(vtodo, VCDAlarmProp))) {
Alarm* alarm = anEvent->newAlarm();
VObject *a;
if ((a = isAPropertyOf(vo, VCRunTimeProp))) {
alarm->setTime(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(a))));
deleteStr(s);
}
alarm->setEnabled(true);
if ((vo = isAPropertyOf(vtodo, VCPAlarmProp))) {
if ((a = isAPropertyOf(vo, VCProcedureNameProp))) {
s = fakeCString(vObjectUStringZValue(a));
alarm->setProcedureAlarm(QFile::decodeName(s));
deleteStr(s);
}
}
if ((vo = isAPropertyOf(vtodo, VCAAlarmProp))) {
if ((a = isAPropertyOf(vo, VCAudioContentProp))) {
s = fakeCString(vObjectUStringZValue(a));
alarm->setAudioAlarm(QFile::decodeName(s));
deleteStr(s);
}
}
}
// related todo
if ((vo = isAPropertyOf(vtodo, VCRelatedToProp)) != 0) {
anEvent->setRelatedToUid(s = fakeCString(vObjectUStringZValue(vo)));
deleteStr(s);
mTodosRelate.append(anEvent);
}
// categories
if ((vo = isAPropertyOf(vtodo, VCCategoriesProp)) != 0) {
s = fakeCString(vObjectUStringZValue(vo));
QString categories = QString::fromLocal8Bit(s);
deleteStr(s);
QStringList tmpStrList = QStringList::split( ';', categories );
anEvent->setCategories(tmpStrList);
}
/* PILOT SYNC STUFF */
if ((vo = isAPropertyOf(vtodo, XPilotIdProp))) {
anEvent->setPilotId(atoi(s = fakeCString(vObjectUStringZValue(vo))));
deleteStr(s);
}
else
anEvent->setPilotId(0);
if ((vo = isAPropertyOf(vtodo, XPilotStatusProp))) {
anEvent->setSyncStatus(atoi(s = fakeCString(vObjectUStringZValue(vo))));
deleteStr(s);
}
else
anEvent->setSyncStatus(Event::SYNCMOD);
return anEvent;
}
Event* VCalFormat::VEventToEvent(VObject *vevent)
{
VObject *vo;
VObjectIterator voi;
char *s;
Event *anEvent = new Event;
// creation date
if ((vo = isAPropertyOf(vevent, VCDCreatedProp)) != 0) {
anEvent->setCreated(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo))));
deleteStr(s);
}
// unique id
vo = isAPropertyOf(vevent, VCUniqueStringProp);
// while the UID property is preferred, it is not required. We'll use the
// default Event UID if none is given.
if (vo) {
anEvent->setUid(s = fakeCString(vObjectUStringZValue(vo)));
deleteStr(s);
}
// revision
// again NSCAL doesn't give us much to work with, so we improvise...
if ((vo = isAPropertyOf(vevent, VCSequenceProp)) != 0) {
anEvent->setRevision(atoi(s = fakeCString(vObjectUStringZValue(vo))));
deleteStr(s);
}
else
anEvent->setRevision(0);
// last modification date
if ((vo = isAPropertyOf(vevent, VCLastModifiedProp)) != 0) {
anEvent->setLastModified(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo))));
deleteStr(s);
}
else
anEvent->setLastModified(QDateTime(QDate::currentDate(),
QTime::currentTime()));
// organizer
// if our extension property for the event's ORGANIZER exists, add it.
if ((vo = isAPropertyOf(vevent, ICOrganizerProp)) != 0) {
anEvent->setOrganizer(s = fakeCString(vObjectUStringZValue(vo)));
deleteStr(s);
} else {
anEvent->setOrganizer(mCalendar->getEmail());
}
// deal with attendees.
initPropIterator(&voi, vevent);
while (moreIteration(&voi)) {
vo = nextVObject(&voi);
if (strcmp(vObjectName(vo), VCAttendeeProp) == 0) {
Attendee *a;
VObject *vp;
s = fakeCString(vObjectUStringZValue(vo));
QString tmpStr = QString::fromLocal8Bit(s);
deleteStr(s);
tmpStr = tmpStr.simplifyWhiteSpace();
int emailPos1, emailPos2;
if ((emailPos1 = tmpStr.find('<')) > 0) {
// both email address and name
emailPos2 = tmpStr.findRev('>');
a = new Attendee(tmpStr.left(emailPos1 - 1),
tmpStr.mid(emailPos1 + 1,
emailPos2 - (emailPos1 + 1)));
} else if (tmpStr.find('@') > 0) {
// just an email address
a = new Attendee(0, tmpStr);
} else {
// just a name
//QString email = tmpStr.replace( QRegExp(" "), "." );
a = new Attendee(tmpStr,0);
}
// is there a Role property?
if ((vp = isAPropertyOf(vo, VCRoleProp)) != 0)
a->setRole(readRole(vObjectStringZValue(vp)));
// is there an RSVP property?
if ((vp = isAPropertyOf(vo, VCRSVPProp)) != 0)
a->setRSVP(vObjectStringZValue(vp));
// is there a status property?
if ((vp = isAPropertyOf(vo, VCStatusProp)) != 0)
a->setStatus(readStatus(vObjectStringZValue(vp)));
// add the attendee
anEvent->addAttendee(a);
}
}
// This isn't strictly true. An event that doesn't have a start time
// or an end time doesn't "float", it has an anchor in time but it doesn't
// "take up" any time.
/*if ((isAPropertyOf(vevent, VCDTstartProp) == 0) ||
(isAPropertyOf(vevent, VCDTendProp) == 0)) {
anEvent->setFloats(TRUE);
} else {
}*/
anEvent->setFloats(FALSE);
// start time
if ((vo = isAPropertyOf(vevent, VCDTstartProp)) != 0) {
anEvent->setDtStart(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo))));
// kdDebug(5800) << "s is " << // s << ", ISO is " << ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo))).toString() << endl;
deleteStr(s);
if (anEvent->dtStart().time().isNull())
anEvent->setFloats(TRUE);
}
// stop time
if ((vo = isAPropertyOf(vevent, VCDTendProp)) != 0) {
anEvent->setDtEnd(ISOToQDateTime(s = fakeCString(vObjectUStringZValue(vo))));
deleteStr(s);
if (anEvent->dtEnd().time().isNull())
anEvent->setFloats(TRUE);
}
// at this point, there should be at least a start or end time.
// fix up for events that take up no time but have a time associated
if (!(vo = isAPropertyOf(vevent, VCDTstartProp)))
anEvent->setDtStart(anEvent->dtEnd());
if (!(vo = isAPropertyOf(vevent, VCDTendProp)))
anEvent->setDtEnd(anEvent->dtStart());
///////////////////////////////////////////////////////////////////////////
// repeat stuff
if ((vo = isAPropertyOf(vevent, VCRRuleProp)) != 0) {
QString tmpStr = (s = fakeCString(vObjectUStringZValue(vo)));
deleteStr(s);
tmpStr.simplifyWhiteSpace();
tmpStr = tmpStr.upper();
/********************************* DAILY ******************************/
if (tmpStr.left(1) == "D") {
int index = tmpStr.find(' ');
int rFreq = tmpStr.mid(1, (index-1)).toInt();
index = tmpStr.findRev(' ') + 1; // advance to last field
if (tmpStr.mid(index,1) == "#") index++;
if (tmpStr.find('T', index) != -1) {
QDate rEndDate = (ISOToQDateTime(tmpStr.mid(index, tmpStr.length()-index))).date();
anEvent->recurrence()->setDaily(rFreq, rEndDate);
} else {
int rDuration = tmpStr.mid(index, tmpStr.length()-index).toInt();
if (rDuration == 0) // VEvents set this to 0 forever, we use -1
anEvent->recurrence()->setDaily(rFreq, -1);
else
anEvent->recurrence()->setDaily(rFreq, rDuration);
}
}
/********************************* WEEKLY ******************************/
else if (tmpStr.left(1) == "W") {
int index = tmpStr.find(' ');
int last = tmpStr.findRev(' ') + 1;
int rFreq = tmpStr.mid(1, (index-1)).toInt();
index += 1; // advance to beginning of stuff after freq
QBitArray qba(7);
QString dayStr;
if( index == last ) {
// e.g. W1 #0
qba.setBit(anEvent->dtStart().date().dayOfWeek() - 1);
}
else {
// e.g. W1 SU #0
while (index < last) {
dayStr = tmpStr.mid(index, 3);
int dayNum = numFromDay(dayStr);
qba.setBit(dayNum);
index += 3; // advance to next day, or possibly "#"
}
}
index = last; if (tmpStr.mid(index,1) == "#") index++;
if (tmpStr.find('T', index) != -1) {
QDate rEndDate = (ISOToQDateTime(tmpStr.mid(index, tmpStr.length()-index))).date();
anEvent->recurrence()->setWeekly(rFreq, qba, rEndDate);
} else {
int rDuration = tmpStr.mid(index, tmpStr.length()-index).toInt();
if (rDuration == 0)
anEvent->recurrence()->setWeekly(rFreq, qba, -1);
else
anEvent->recurrence()->setWeekly(rFreq, qba, rDuration);
}
}
/**************************** MONTHLY-BY-POS ***************************/
else if (tmpStr.left(2) == "MP") {
int index = tmpStr.find(' ');
int last = tmpStr.findRev(' ') + 1;
int rFreq = tmpStr.mid(2, (index-1)).toInt();
index += 1; // advance to beginning of stuff after freq
QBitArray qba(7);
short tmpPos;
if( index == last ) {
// e.g. MP1 #0
tmpPos = anEvent->dtStart().date().day()/7 + 1;
if( tmpPos == 5 )
tmpPos = -1;
qba.setBit(anEvent->dtStart().date().dayOfWeek() - 1);
anEvent->recurrence()->addMonthlyPos(tmpPos, qba);
}
else {
// e.g. MP1 1+ SU #0
while (index < last) {
tmpPos = tmpStr.mid(index,1).toShort();
index += 1;
if (tmpStr.mid(index,1) == "-")
// convert tmpPos to negative
tmpPos = 0 - tmpPos;
index += 2; // advance to day(s)
while (numFromDay(tmpStr.mid(index,3)) >= 0) {
int dayNum = numFromDay(tmpStr.mid(index,3));
qba.setBit(dayNum);
index += 3; // advance to next day, or possibly pos or "#"
}
anEvent->recurrence()->addMonthlyPos(tmpPos, qba);
qba.detach();
qba.fill(FALSE); // clear out
} // while != "#"
}
index = last; if (tmpStr.mid(index,1) == "#") index++;
if (tmpStr.find('T', index) != -1) {
QDate rEndDate = (ISOToQDateTime(tmpStr.mid(index, tmpStr.length() -
index))).date();
anEvent->recurrence()->setMonthly(Recurrence::rMonthlyPos, rFreq, rEndDate);
} else {
int rDuration = tmpStr.mid(index, tmpStr.length()-index).toInt();
if (rDuration == 0)
anEvent->recurrence()->setMonthly(Recurrence::rMonthlyPos, rFreq, -1);
else
anEvent->recurrence()->setMonthly(Recurrence::rMonthlyPos, rFreq, rDuration);
}
}
/**************************** MONTHLY-BY-DAY ***************************/
else if (tmpStr.left(2) == "MD") {
int index = tmpStr.find(' ');
int last = tmpStr.findRev(' ') + 1;
int rFreq = tmpStr.mid(2, (index-1)).toInt();
index += 1;
short tmpDay;
if( index == last ) {
// e.g. MD1 #0
tmpDay = anEvent->dtStart().date().day();
anEvent->recurrence()->addMonthlyDay(tmpDay);
}
else {
// e.g. MD1 3 #0
while (index < last) {
int index2 = tmpStr.find(' ', index);
tmpDay = tmpStr.mid(index, (index2-index)).toShort();
index = index2-1;
if (tmpStr.mid(index, 1) == "-")
tmpDay = 0 - tmpDay;
index += 2; // advance the index;
anEvent->recurrence()->addMonthlyDay(tmpDay);
} // while != #
}
index = last; if (tmpStr.mid(index,1) == "#") index++;
if (tmpStr.find('T', index) != -1) {
QDate rEndDate = (ISOToQDateTime(tmpStr.mid(index, tmpStr.length()-index))).date();
anEvent->recurrence()->setMonthly(Recurrence::rMonthlyDay, rFreq, rEndDate);
} else {
int rDuration = tmpStr.mid(index, tmpStr.length()-index).toInt();
if (rDuration == 0)
anEvent->recurrence()->setMonthly(Recurrence::rMonthlyDay, rFreq, -1);
else
anEvent->recurrence()->setMonthly(Recurrence::rMonthlyDay, rFreq, rDuration);
}
}
/*********************** YEARLY-BY-MONTH *******************************/
else if (tmpStr.left(2) == "YM") {
// we have to set this such that recurrence accepts addYearlyNum(tmpDay);
anEvent->recurrence()->setYearly(Recurrence::rYearlyMonth, 1, -1);
int index = tmpStr.find(' ');
int last = tmpStr.findRev(' ') + 1;
int rFreq = tmpStr.mid(2, (index-1)).toInt();
index += 1;
short tmpMonth;
if( index == last ) {
// e.g. YM1 #0
tmpMonth = anEvent->dtStart().date().month();
anEvent->recurrence()->addYearlyNum(tmpMonth);
}
else {
// e.g. YM1 3 #0
while (index < last) {
int index2 = tmpStr.find(' ', index);
tmpMonth = tmpStr.mid(index, (index2-index)).toShort();
index = index2+1;
anEvent->recurrence()->addYearlyNum(tmpMonth);
} // while != #
}
index = last; if (tmpStr.mid(index,1) == "#") index++;
if (tmpStr.find('T', index) != -1) {
QDate rEndDate = (ISOToQDateTime(tmpStr.mid(index, tmpStr.length()-index))).date();
anEvent->recurrence()->setYearly(Recurrence::rYearlyMonth, rFreq, rEndDate);
} else {
int rDuration = tmpStr.mid(index, tmpStr.length()-index).toInt();
if (rDuration == 0)
anEvent->recurrence()->setYearly(Recurrence::rYearlyMonth, rFreq, -1);
else
anEvent->recurrence()->setYearly(Recurrence::rYearlyMonth, rFreq, rDuration);
}
}
/*********************** YEARLY-BY-DAY *********************************/
else if (tmpStr.left(2) == "YD") {
// we have to set this such that recurrence accepts addYearlyNum(tmpDay);
anEvent->recurrence()->setYearly(Recurrence::rYearlyDay, 1, -1);
int index = tmpStr.find(' ');
int last = tmpStr.findRev(' ') + 1;
int rFreq = tmpStr.mid(2, (index-1)).toInt();
index += 1;
short tmpDay;
if( index == last ) {
// e.g. YD1 #0
tmpDay = anEvent->dtStart().date().dayOfYear();
anEvent->recurrence()->addYearlyNum(tmpDay);
}
else {
// e.g. YD1 123 #0
while (index < last) {
int index2 = tmpStr.find(' ', index);
tmpDay = tmpStr.mid(index, (index2-index)).toShort();
index = index2+1;
anEvent->recurrence()->addYearlyNum(tmpDay);
} // while != #
}
index = last; if (tmpStr.mid(index,1) == "#") index++;
if (tmpStr.find('T', index) != -1) {
diff --git a/libkcal/vcalformat.h b/libkcal/vcalformat.h
index c7df017..6dae3d2 100644
--- a/libkcal/vcalformat.h
+++ b/libkcal/vcalformat.h
@@ -1,113 +1,113 @@
/*
This file is part of libkcal.
Copyright (c) 1998 Preston Brown
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.
*/
#ifndef _VCALFORMAT_H
#define _VCALFORMAT_H
#include "calformat.h"
#define _VCAL_VERSION "1.0"
class VObject;
namespace KCal {
/**
This class implements the vCalendar format. It provides methods for
loading/saving/converting vCalendar format data into the internal KOrganizer
representation as Calendar and Events.
@short vCalendar format implementation
*/
class VCalFormat : public CalFormat {
public:
VCalFormat();
virtual ~VCalFormat();
/** loads a calendar on disk in vCalendar format into the current calendar.
* any information already present is lost. Returns TRUE if successful,
* else returns FALSE.
* @param fileName the name of the calendar on disk.
*/
bool load(Calendar *,const QString &fileName );
/** writes out the calendar to disk in vCalendar format. Returns true if
* successful and false on error.
* @param fileName the name of the file
*/
bool save(Calendar *,const QString &fileName );
/**
Parse string and populate calendar with that information.
*/
bool fromString( Calendar *, const QString & );
/**
Return calendar information as string.
*/
void setLocalTime ( bool );
QString toString( Calendar * );
QString eventToString( Event *, Calendar *calendar, bool useLocalTime = true );
QString todoToString( Todo * ,Calendar *calendar, bool useLocalTime = true );
protected:
/** translates a VObject of the TODO type into a Event */
Todo *VTodoToEvent(VObject *vtodo);
/** translates a VObject into a Event and returns a pointer to it. */
Event *VEventToEvent(VObject *vevent);
/** translate a Event into a VTodo-type VObject and return pointer */
VObject *eventToVTodo(const Todo *anEvent);
/** translate a Event into a VObject and returns a pointer to it. */
- VObject* eventToVEvent(const Event *anEvent);
+ VObject* eventToVEvent(Event *anEvent);
/** takes a QDate and returns a string in the format YYYYMMDDTHHMMSS */
QString qDateToISO(const QDate &);
/** takes a QDateTime and returns a string in format YYYYMMDDTHHMMSS */
QString qDateTimeToISO(const QDateTime &, bool zulu=TRUE);
/** takes a string in the format YYYYMMDDTHHMMSS and returns a
* valid QDateTime. */
QDateTime ISOToQDateTime(const QString & dtStr);
/** takes a string in the format YYYYMMDD and returns a
* valid QDate. */
QDate ISOToQDate(const QString & dtStr);
/** takes a vCalendar tree of VObjects, and puts all of them that have
* the "event" property into the dictionary, todos in the todo-list, etc. */
void populate(VObject *vcal);
/** takes a number 0 - 6 and returns the two letter string of that day,
* i.e. MO, TU, WE, etc. */
const char *dayFromNum(int day);
/** the reverse of the above function. */
int numFromDay(const QString &day);
Attendee::Role VCalFormat::readRole(const char *s) const;
QCString writeRole(Attendee::Role role) const;
Attendee::PartStat readStatus(const char *s) const;
QCString writeStatus(Attendee::PartStat status) const;
private:
Calendar *mCalendar;
bool useLocalTime;
QPtrList<Event> mEventsRelate; // events with relations
QPtrList<Todo> mTodosRelate; // todos with relations
};
}
#endif