-rw-r--r-- | libopie2/opiepim/backend/ocontactaccessbackend_vcard.cpp | 11 | ||||
-rw-r--r-- | libopie2/opiepim/core/orecur.cpp | 25 | ||||
-rw-r--r-- | libopie2/opiepim/core/orecur.h | 12 | ||||
-rw-r--r-- | libopie2/opiepim/core/otimezone.cpp | 104 | ||||
-rw-r--r-- | libopie2/opiepim/core/otimezone.h | 71 | ||||
-rw-r--r-- | libopie2/opiepim/oevent.cpp | 427 | ||||
-rw-r--r-- | libopie2/opiepim/oevent.h | 198 | ||||
-rw-r--r-- | libopie2/opiepim/otodo.cpp | 2 |
8 files changed, 830 insertions, 20 deletions
diff --git a/libopie2/opiepim/backend/ocontactaccessbackend_vcard.cpp b/libopie2/opiepim/backend/ocontactaccessbackend_vcard.cpp index 622d40a..e537269 100644 --- a/libopie2/opiepim/backend/ocontactaccessbackend_vcard.cpp +++ b/libopie2/opiepim/backend/ocontactaccessbackend_vcard.cpp @@ -1,205 +1,214 @@ /* * VCard Backend for the OPIE-Contact Database. * * Copyright (C) 2000 Trolltech AS. All rights reserved. * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) * * ===================================================================== * This program 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. * ===================================================================== * ToDo: * * ===================================================================== * Version: $Id$ * ===================================================================== * History: * $Log$ + * Revision 1.8 2003/02/21 16:52:49 zecke + * -Remove old Todo classes they're deprecated and today I already using the + * new API + * -Guard against self assignment in OTodo + * -Add test apps for OPIM + * -Opiefied Event classes + * -Added TimeZone handling and pinning of TimeZones to OEvent + * -Adjust ORecur and the widget to better timezone behaviour + * * Revision 1.7 2003/02/16 22:25:46 zecke * 0000276 Fix for that bug.. or better temp workaround * A Preferred Number is HOME|VOICE * A CellPhone is HOME|VOICE|CELL the type & HOME|VOICE test * triggers both * and the cell phone number overrides the other entries.. * * as a temp I check that it's not equal to HOME|VOICE|CELL before setting the * number * * The right and final fix would be to reorder the if statement to make it * if else based and the less common thing put to the bottom * * OTodoAccessVcal fix the date for beaming * * Revision 1.6 2003/01/13 15:49:31 eilers * Fixing crash when businesscard.vcf is missing.. * * Revision 1.5 2002/12/07 13:26:22 eilers * Fixing bug in storing anniversary.. * * Revision 1.4 2002/11/13 14:14:51 eilers * Added sorted for Contacts.. * * Revision 1.3 2002/11/11 16:41:09 kergoth * no default arguments in implementation * * Revision 1.2 2002/11/10 15:41:53 eilers * Bugfixes.. * * Revision 1.1 2002/11/09 14:34:52 eilers * Added VCard Backend. * */ #include "ocontactaccessbackend_vcard.h" #include "../../library/backend/vobject_p.h" #include "../../library/backend/qfiledirect_p.h" #include <qpe/timeconversion.h> #include <qfile.h> OContactAccessBackend_VCard::OContactAccessBackend_VCard ( QString , QString filename ): m_dirty( false ), m_file( filename ) { load(); } bool OContactAccessBackend_VCard::load () { m_map.clear(); m_dirty = false; VObject* obj = 0l; - if ( QFile( m_file ).exists() ){ + if ( QFile::exists(m_file) ){ obj = Parse_MIME_FromFileName( QFile::encodeName(m_file).data() ); if ( !obj ) return false; }else{ qWarning("File \"%s\" not found !", m_file.latin1() ); return false; } while ( obj ) { OContact con = parseVObject( obj ); /* * if uid is 0 assign a new one * this at least happens on * Nokia6210 */ if ( con.uid() == 0 ){ con.setUid( 1 ); qWarning("assigned new uid %d",con.uid() ); } m_map.insert( con.uid(), con ); VObject *t = obj; obj = nextVObjectInList(obj); cleanVObject( t ); } return true; } bool OContactAccessBackend_VCard::reload() { return load(); } bool OContactAccessBackend_VCard::save() { if (!m_dirty ) return true; QFileDirect file( m_file ); if (!file.open(IO_WriteOnly ) ) return false; VObject *obj; obj = newVObject( VCCalProp ); addPropValue( obj, VCVersionProp, "1.0" ); VObject *vo; for(QMap<int, OContact>::ConstIterator it=m_map.begin(); it !=m_map.end(); ++it ){ vo = createVObject( *it ); writeVObject( file.directHandle() , vo ); cleanVObject( vo ); } cleanStrTbl(); m_dirty = false; return true; } void OContactAccessBackend_VCard::clear () { m_map.clear(); m_dirty = true; // ??? sure ? (se) } bool OContactAccessBackend_VCard::add ( const OContact& newcontact ) { m_map.insert( newcontact.uid(), newcontact ); m_dirty = true; return true; } bool OContactAccessBackend_VCard::remove ( int uid ) { m_map.remove( uid ); m_dirty = true; return true; } bool OContactAccessBackend_VCard::replace ( const OContact &contact ) { m_map.replace( contact.uid(), contact ); m_dirty = true; return true; } OContact OContactAccessBackend_VCard::find ( int uid ) const { return m_map[uid]; } QArray<int> OContactAccessBackend_VCard::allRecords() const { QArray<int> ar( m_map.count() ); QMap<int, OContact>::ConstIterator it; int i = 0; for ( it = m_map.begin(); it != m_map.end(); ++it ) { ar[i] = it.key(); i++; } return ar; } // Not implemented QArray<int> OContactAccessBackend_VCard::queryByExample ( const OContact&, int ) { QArray<int> ar(0); return ar; } // Not implemented QArray<int> OContactAccessBackend_VCard::matchRegexp( const QRegExp& ) const { QArray<int> ar(0); return ar; } const uint OContactAccessBackend_VCard::querySettings() { return 0; // No search possible } bool OContactAccessBackend_VCard::hasQuerySettings (uint ) const { return false; // No search possible, therefore all settings invalid ;) } diff --git a/libopie2/opiepim/core/orecur.cpp b/libopie2/opiepim/core/orecur.cpp index daf3506..e6a4787 100644 --- a/libopie2/opiepim/core/orecur.cpp +++ b/libopie2/opiepim/core/orecur.cpp @@ -1,182 +1,184 @@ #include <qshared.h> #include <qtopia/timeconversion.h> #include "orecur.h" struct ORecur::Data : public QShared { Data() : QShared() { type = ORecur::NoRepeat; freq = -1; days = 0; pos = 0; - create = -1; + create = QDateTime::currentDateTime(); hasEnd = FALSE; - end = 0; + end = QDate::currentDate(); } char days; // Q_UINT8 for 8 seven days;) ORecur::RepeatType type; int freq; int pos; bool hasEnd : 1; - time_t end; - time_t create; + QDate end; + QDateTime create; int rep; QString app; ExceptionList list; QDate start; }; ORecur::ORecur() { data = new Data; } ORecur::ORecur( const ORecur& rec) : data( rec.data ) { data->ref(); } ORecur::~ORecur() { if ( data->deref() ) { delete data; data = 0l; } } void ORecur::deref() { if ( data->deref() ) { delete data; data = 0l; } } bool ORecur::operator==( const ORecur& )const { return false; } ORecur &ORecur::operator=( const ORecur& re) { + if ( *this == re ) return *this; + re.data->ref(); deref(); data = re.data; return *this; } bool ORecur::doesRecur()const { return !( type() == NoRepeat ); } /* * we try to be smart here * */ bool ORecur::doesRecur( const QDate& date ) { /* the day before the recurrance */ QDate da = date.addDays(-1); QDate recur; if (!nextOcurrence( da, recur ) ) return false; return (recur == date); } // FIXME unuglify! // GPL from Datebookdb.cpp // FIXME exception list! bool ORecur::nextOcurrence( const QDate& from, QDate& next ) { // easy checks, first are we too far in the future or too far in the past? QDate tmpDate; int freq = frequency(); int diff, diff2, a; int iday, imonth, iyear; int dayOfWeek = 0; int firstOfWeek = 0; int weekOfMonth; if (hasEndDate() && endDate() < from) return FALSE; if (start() >= from) { next = start(); return TRUE; } switch ( type() ) { case Weekly: /* weekly is just daily by 7 */ /* first convert the repeatPattern.Days() mask to the next day of week valid after from */ dayOfWeek = from.dayOfWeek(); dayOfWeek--; /* we want 0-6, doco for above specs 1-7 */ /* this is done in case freq > 1 and from in week not for this round */ // firstOfWeek = 0; this is already done at decl. while(!((1 << firstOfWeek) & days() )) firstOfWeek++; /* there is at least one 'day', or there would be no event */ while(!((1 << (dayOfWeek % 7)) & days() )) dayOfWeek++; dayOfWeek = dayOfWeek % 7; /* the actual day of week */ dayOfWeek -= start().dayOfWeek() -1; firstOfWeek = firstOfWeek % 7; /* the actual first of week */ firstOfWeek -= start().dayOfWeek() -1; // dayOfWeek may be negitive now // day of week is number of days to add to start day freq *= 7; // FALL-THROUGH !!!!! case Daily: // the add is for the possible fall through from weekly */ if(start().addDays(dayOfWeek) > from) { /* first week exception */ next = QDate(start().addDays(dayOfWeek) ); if ((next > endDate()) && hasEndDate() ) return FALSE; return TRUE; } /* if from is middle of a non-week */ diff = start().addDays(dayOfWeek).daysTo(from) % freq; diff2 = start().addDays(firstOfWeek).daysTo(from) % freq; if(diff != 0) diff = freq - diff; if(diff2 != 0) diff2 = freq - diff2; diff = QMIN(diff, diff2); next = QDate(from.addDays(diff)); if ( (next > endDate()) && hasEndDate() ) return FALSE; return TRUE; case MonthlyDay: iday = from.day(); iyear = from.year(); imonth = from.month(); /* find equivelent day of month for this month */ dayOfWeek = start().dayOfWeek(); weekOfMonth = (start().day() - 1) / 7; /* work out when the next valid month is */ a = from.year() - start().year(); a *= 12; a = a + (imonth - start().month()); /* a is e.start()monthsFrom(from); */ if(a % freq) { a = freq - (a % freq); imonth = from.month() + a; if (imonth > 12) { imonth--; iyear += imonth / 12; imonth = imonth % 12; imonth++; } } /* imonth is now the first month after or on from that matches the frequency given */ /* find for this month */ @@ -241,211 +243,204 @@ bool ORecur::nextOcurrence( const QDate& from, QDate& next ) { a = from.year() - start().year(); a *= 12; a = a + (imonth - start().month()); /* a is e.start()monthsFrom(from); */ if(a % freq) { a = freq - (a % freq); imonth = from.month() + a; if (imonth > 12) { imonth--; iyear += imonth / 12; imonth = imonth % 12; imonth++; } } /* imonth is now the first month after or on from that matches the frequencey given */ /* this could go for a while, worse case, 4*12 iterations, probably */ while(!QDate::isValid(iyear, imonth, iday) ) { imonth += freq; if (imonth > 12) { imonth--; iyear += imonth / 12; imonth = imonth % 12; imonth++; } /* these loops could go for a while, check end case now */ if ((QDate(iyear, imonth, 1) > endDate()) && hasEndDate() ) return FALSE; } if(QDate(iyear, imonth, iday) >= from) { /* done */ next = QDate(iyear, imonth, iday); if ((next > endDate()) && hasEndDate() ) return FALSE; return TRUE; } /* ok, need to cycle */ imonth += freq; imonth--; iyear += imonth / 12; imonth = imonth % 12; imonth++; while(!QDate::isValid(iyear, imonth, iday) ) { imonth += freq; imonth--; iyear += imonth / 12; imonth = imonth % 12; imonth++; if ((QDate(iyear, imonth, 1) > endDate()) && hasEndDate() ) return FALSE; } next = QDate(iyear, imonth, iday); if ((next > endDate()) && hasEndDate() ) return FALSE; return TRUE; case Yearly: iday = start().day(); imonth = start().month(); iyear = from.year(); // after all, we want to start in this year diff = 1; if(imonth == 2 && iday > 28) { /* leap year, and it counts, calculate actual frequency */ if(freq % 4) if (freq % 2) freq = freq * 4; else freq = freq * 2; /* else divides by 4 already, leave freq alone */ diff = 4; } a = from.year() - start().year(); if(a % freq) { a = freq - (a % freq); iyear = iyear + a; } /* under the assumption we won't hit one of the special not-leap years twice */ if(!QDate::isValid(iyear, imonth, iday)) { /* must have been skipping by leap years and hit one that wasn't, (e.g. 2100) */ iyear += freq; } if(QDate(iyear, imonth, iday) >= from) { next = QDate(iyear, imonth, iday); if ((next > endDate()) && hasEndDate() ) return FALSE; return TRUE; } /* iyear == from.year(), need to advance again */ iyear += freq; /* under the assumption we won't hit one of the special not-leap years twice */ if(!QDate::isValid(iyear, imonth, iday)) { /* must have been skipping by leap years and hit one that wasn't, (e.g. 2100) */ iyear += freq; } next = QDate(iyear, imonth, iday); if ((next > endDate()) && hasEndDate() ) return FALSE; return TRUE; default: return FALSE; } } ORecur::RepeatType ORecur::type()const{ return data->type; } int ORecur::frequency()const { return data->freq; } int ORecur::position()const { return data->pos; } char ORecur::days() const{ return data->days; } bool ORecur::hasEndDate()const { return data->hasEnd; } QDate ORecur::endDate()const { - return TimeConversion::fromUTC( data->end ).date(); + return data->end; } QDate ORecur::start()const{ return data->start; } -time_t ORecur::endDateUTC()const { - return data->end; -} -time_t ORecur::createTime()const { +QDateTime ORecur::createdDateTime()const { return data->create; } int ORecur::repetition()const { return data->rep; } QString ORecur::service()const { return data->app; } ORecur::ExceptionList& ORecur::exceptions() { return data->list; } void ORecur::setType( const RepeatType& z) { checkOrModify(); data->type = z; } void ORecur::setFrequency( int freq ) { checkOrModify(); data->freq = freq; } void ORecur::setPosition( int pos ) { checkOrModify(); data->pos = pos; } void ORecur::setDays( char c ) { checkOrModify(); data->days = c; } void ORecur::setEndDate( const QDate& dt) { checkOrModify(); - data->end = TimeConversion::toUTC( dt ); -} -void ORecur::setEndDateUTC( time_t t) { - checkOrModify(); - data->end = t; + data->end = dt; } -void ORecur::setCreateTime( time_t t) { +void ORecur::setCreatedDateTime( const QDateTime& t) { checkOrModify(); data->create = t; } void ORecur::setHasEndDate( bool b) { checkOrModify(); data->hasEnd = b; } void ORecur::setRepitition( int rep ) { checkOrModify(); data->rep = rep; } void ORecur::setService( const QString& app ) { checkOrModify(); data->app = app; } void ORecur::setStart( const QDate& dt ) { checkOrModify(); data->start = dt; } void ORecur::checkOrModify() { if ( data->count != 1 ) { data->deref(); Data* d2 = new Data; d2->days = data->days; d2->type = data->type; d2->freq = data->freq; d2->pos = data->pos; d2->hasEnd = data->hasEnd; d2->end = data->end; d2->create = data->create; d2->rep = data->rep; d2->app = data->app; d2->list = data->list; d2->start = data->start; data = d2; } } diff --git a/libopie2/opiepim/core/orecur.h b/libopie2/opiepim/core/orecur.h index 8713d97..1e0014b 100644 --- a/libopie2/opiepim/core/orecur.h +++ b/libopie2/opiepim/core/orecur.h @@ -1,83 +1,87 @@ /* * GPL from TT */ #ifndef OPIE_RECUR_H #define OPIE_RECUR_H #include <sys/types.h> #include <qdatetime.h> #include <qvaluelist.h> class ORecur { public: typedef QValueList<QDate> ExceptionList; enum RepeatType{ NoRepeat = -1, Daily, Weekly, MonthlyDay, MonthlyDate, Yearly }; enum Days { MON = 0x01, TUE = 0x02, WED = 0x04, THU = 0x08, FRI = 0x10, SAT = 0x20, SUN = 0x40 }; ORecur(); ORecur( const ORecur& ); ~ORecur(); ORecur &operator=( const ORecur& ); bool operator==(const ORecur& )const; bool doesRecur()const; /* if it recurrs on that day */ bool doesRecur( const QDate& ); RepeatType type()const; int frequency()const; int position()const; char days()const; bool hasEndDate()const; QDate start()const; QDate endDate()const; - time_t endDateUTC()const; - time_t createTime()const; + QDateTime createdDateTime()const; + /** + * starting on monday=0, sunday=6 + * for convience + */ + bool repeatOnWeekDay( int day )const; /** * FromWhereToStart is not included!!! */ bool nextOcurrence( const QDate& FromWhereToStart, QDate &recurDate ); + /** * The module this ORecur belongs to */ QString service()const; /* * reference to the exception list */ ExceptionList &exceptions(); /** * the current repetition */ int repetition()const; void setType( const RepeatType& ); void setFrequency( int freq ); void setPosition( int pos ); void setDays( char c); void setEndDate( const QDate& dt ); void setStart( const QDate& dt ); - void setEndDateUTC( time_t ); - void setCreateTime( time_t ); + void setCreatedDateTime( const QDateTime& ); void setHasEndDate( bool b ); void setRepitition(int ); void setService( const QString& ser ); private: void deref(); inline void checkOrModify(); class Data; Data* data; class ORecurPrivate; ORecurPrivate *d; }; #endif diff --git a/libopie2/opiepim/core/otimezone.cpp b/libopie2/opiepim/core/otimezone.cpp new file mode 100644 index 0000000..b2bd3aa --- a/dev/null +++ b/libopie2/opiepim/core/otimezone.cpp @@ -0,0 +1,104 @@ +#include <stdio.h> +#include <stdlib.h> + +#include <sys/types.h> + +#include "otimezone.h" + +namespace { + + QDateTime utcTime( time_t t) { + tm* broken = ::gmtime( &t ); + QDateTime ret; + ret.setDate( QDate( broken->tm_year + 1900, broken->tm_mon +1, broken->tm_mday ) ); + ret.setTime( QTime( broken->tm_hour, broken->tm_min, broken->tm_sec ) ); + return ret; + } + QDateTime utcTime( time_t t, const QString& zone) { + QCString org = ::getenv( "TZ" ); + ::setenv( "TZ", zone.latin1(), true ); + ::tzset(); + + tm* broken = ::localtime( &t ); + ::setenv( "TZ", org, true ); + + QDateTime ret; + ret.setDate( QDate( broken->tm_year + 1900, broken->tm_mon +1, broken->tm_mday ) ); + ret.setTime( QTime( broken->tm_hour, broken->tm_min, broken->tm_sec ) ); + + return ret; + } + time_t to_Time_t( const QDateTime& utc, const QString& str ) { + QDate d = utc.date(); + QTime t = utc.time(); + + tm broken; + broken.tm_year = d.year() - 1900; + broken.tm_mon = d.month() - 1; + broken.tm_mday = d.day(); + broken.tm_hour = t.hour(); + broken.tm_min = t.minute(); + broken.tm_sec = t.second(); + + QCString org = ::getenv( "TZ" ); + ::setenv( "TZ", str.latin1(), true ); + ::tzset(); + + time_t ti = ::mktime( &broken ); + ::setenv( "TZ", org, true ); + + return ti; + } +} +OTimeZone::OTimeZone( const ZoneName& zone ) + : m_name(zone) { +} +OTimeZone::~OTimeZone() { +} + +bool OTimeZone::isValid()const { + return !m_name.isEmpty(); +} + +/* + * we will get the current timezone + * and ask it to convert to the timezone date + */ +QDateTime OTimeZone::toLocalDateTime( const QDateTime& dt) { + return OTimeZone::current().toDateTime( dt, *this ); +} +QDateTime OTimeZone::toUTCDateTime( const QDateTime& dt ) { + return OTimeZone::utc().toDateTime( dt, *this ); +} +QDateTime OTimeZone::fromUTCDateTime( time_t t) { + return utcTime( t ); +} +QDateTime OTimeZone::toDateTime( time_t t) { + return utcTime( t, m_name ); +} +/* + * convert dt to utc using zone.m_name + * convert utc -> timeZoneDT using this->m_name + */ +QDateTime OTimeZone::toDateTime( const QDateTime& dt, const OTimeZone& zone ) { + time_t utc = to_Time_t( dt, zone.m_name ); + qWarning("%d %s", utc, zone.m_name.latin1() ); + return utcTime( utc, m_name ); +} +time_t OTimeZone::fromDateTime( const QDateTime& time ) { + return to_Time_t( time, m_name ); +} +time_t OTimeZone::fromUTCDateTime( const QDateTime& time ) { + return to_Time_t( time, "UTC" ); +} +OTimeZone OTimeZone::current() { + QCString str = ::getenv("TZ"); + OTimeZone zone( str ); + return zone; +} +OTimeZone OTimeZone::utc() { + return OTimeZone("UTC"); +} +QString OTimeZone::timeZone()const { + return m_name; +} diff --git a/libopie2/opiepim/core/otimezone.h b/libopie2/opiepim/core/otimezone.h new file mode 100644 index 0000000..bb08349 --- a/dev/null +++ b/libopie2/opiepim/core/otimezone.h @@ -0,0 +1,71 @@ +#ifndef OPIE_TIME_ZONE_H +#define OPIE_TIME_ZONE_H + +#include <time.h> +#include <qdatetime.h> + +/** + * A very primitive class to convert time + * from one timezone to another + * and to localtime + * and time_t + */ +class OTimeZone { + public: + typedef QString ZoneName; + OTimeZone( const ZoneName& = ZoneName::null ); + virtual ~OTimeZone(); // just in case. + + bool isValid()const; + + /** + * converts the QDateTime to a DateTime + * in the local timezone + * if QDateTime is 25th Jan and takes place in Europe/Berlin at 12h + * and the current timezone is Europe/London the returned + * time will be 11h. + */ + QDateTime toLocalDateTime( const QDateTime& dt ); + + /** + * converts the QDateTime to UTC time + */ + QDateTime toUTCDateTime( const QDateTime& dt ); + + /** + * reads the time_t into a QDateTime using UTC as timezone! + */ + QDateTime fromUTCDateTime( time_t ); + + /** + * converts the time_t to the time in the timezone + */ + QDateTime toDateTime( time_t ); + + /** + * converts the QDateTime from one timezone to this timeZone + */ + QDateTime toDateTime( const QDateTime&, const OTimeZone& timeZone ); + + /** + * converts the date time into a time_t. It takes the timezone into account + */ + time_t fromDateTime( const QDateTime& ); + + /** + * converts the datetime with timezone UTC + */ + time_t fromUTCDateTime( const QDateTime& ); + + static OTimeZone current(); + static OTimeZone utc(); + + QString timeZone()const; + private: + ZoneName m_name; + class Private; + Private* d; +}; + + +#endif diff --git a/libopie2/opiepim/oevent.cpp b/libopie2/opiepim/oevent.cpp new file mode 100644 index 0000000..71b9441 --- a/dev/null +++ b/libopie2/opiepim/oevent.cpp @@ -0,0 +1,427 @@ +#include <qshared.h> + +#include <qpe/palmtopuidgen.h> +#include <qpe/categories.h> + +#include "orecur.h" +#include "opimresolver.h" +#include "opimnotifymanager.h" + +#include "oevent.h" + +namespace OCalendarHelper { + static int week( const QDate& date) { + // Calculates the week this date is in within that + // month. Equals the "row" is is in in the month view + int week = 1; + QDate tmp( date.year(), date.month(), 1 ); + if ( date.dayOfWeek() < tmp.dayOfWeek() ) + ++week; + + week += ( date.day() - 1 ) / 7; + + return week; + } + static int occurence( const QDate& date) { + // calculates the number of occurrances of this day of the + // week till the given date (e.g 3rd Wednesday of the month) + return ( date.day() - 1 ) / 7 + 1; + } + static int dayOfWeek( char day ) { + int dayOfWeek = 1; + char i = ORecur::MON; + while ( !( i & day ) && i <= ORecur::SUN ) { + i <<= 1; + ++dayOfWeek; + } + return dayOfWeek; + } + static int monthDiff( const QDate& first, const QDate& second ) { + return ( second.year() - first.year() ) * 12 + + second.month() - first.month(); + } +} + +struct OEvent::Data : public QShared { + Data() : QShared() { + recur = 0; + manager = 0; + isAllDay = false; + } + ~Data() { + delete manager; + delete recur; + } + QString description; + QString location; + OPimNotifyManager* manager; + ORecur* recur; + QString note; + QDateTime created; + QDateTime start; + QDateTime end; + bool isAllDay : 1; + QString timezone; +}; + +OEvent::OEvent( int uid ) + : OPimRecord( uid ) { + data = new Data; +} +OEvent::OEvent( const OEvent& ev) + : OPimRecord( ev ), data( ev.data ) +{ + data->ref(); +} +OEvent::~OEvent() { + if ( data->deref() ) { + delete data; + data = 0; + } +} +OEvent& OEvent::operator=( const OEvent& ev) { + if ( *this == ev ) return *this; + + OPimRecord::operator=( ev ); + ev.data->ref(); + deref(); + data = ev.data; + + + return *this; +} +QString OEvent::description()const { + return data->description; +} +void OEvent::setDescription( const QString& description ) { + changeOrModify(); + data->description = description; +} +void OEvent::setLocation( const QString& loc ) { + changeOrModify(); + data->location = loc; +} +QString OEvent::location()const { + return data->location; +} +OPimNotifyManager &OEvent::notifiers() { + // I hope we can skip the changeOrModify here + // the notifier should take care of it + // and OPimNotify is shared too + if (!data->manager ) + data->manager = new OPimNotifyManager; + + return *data->manager; +} +bool OEvent::hasNotifiers()const { + return ( data->manager); +} +ORecur OEvent::recurrence()const { + if (!data->recur) + data->recur = new ORecur; + + return *data->recur; +} +void OEvent::setRecurrence( const ORecur& rec) { + changeOrModify(); + if (data->recur ) + (*data->recur) = rec; + else + data->recur = new ORecur( rec ); +} +bool OEvent::hasRecurrence()const { + return data->recur; +} +QString OEvent::note()const { + return data->note; +} +void OEvent::setNote( const QString& note ) { + changeOrModify(); + data->note = note; +} +QDateTime OEvent::createdDateTime()const { + return data->created; +} +void OEvent::setCreatedDateTime( const QDateTime& time ) { + changeOrModify(); + data->created = time; +} +QDateTime OEvent::startDateTime()const { + if ( data->isAllDay ) + return QDateTime( data->start.date(), QTime(0, 0, 0 ) ); + return data->start; +} +QDateTime OEvent::startDateTimeInZone()const { + /* if no timezone, or all day event or if the current and this timeZone match... */ + if (data->timezone.isEmpty() || data->isAllDay || data->timezone == OTimeZone::current().timeZone() ) return startDateTime(); + + OTimeZone zone(data->timezone ); + return zone.toDateTime( data->start, OTimeZone::current() ); +} +void OEvent::setStartDateTime( const QDateTime& dt ) { + changeOrModify(); + data->start = dt; +} +QDateTime OEvent::endDateTime()const { + /* + * if all Day event the end time needs + * to be on the same day as the start + */ + if ( data->isAllDay ) + return QDateTime( data->start.date(), QTime(23, 59, 59 ) ); + return data->end; +} +QDateTime OEvent::endDateTimeInZone()const { + /* if no timezone, or all day event or if the current and this timeZone match... */ + if (data->timezone.isEmpty() || data->isAllDay || data->timezone == OTimeZone::current().timeZone() ) return endDateTime(); + + OTimeZone zone(data->timezone ); + return zone.toDateTime( data->end, OTimeZone::current() ); +} +void OEvent::setEndDateTime( const QDateTime& dt ) { + changeOrModify(); + data->end = dt; +} +bool OEvent::isMultipleDay()const { + return data->end.date().day() - data->start.date().day(); +} +bool OEvent::isAllDay()const { + return data->isAllDay; +} +void OEvent::setTimeZone( const QString& tz ) { + changeOrModify(); + data->timezone = tz; +} +QString OEvent::timeZone()const { + return data->timezone; +} +bool OEvent::match( const QRegExp& )const { + // FIXME + return false; +} +QString OEvent::toRichText()const { + // FIXME + return "OEvent test"; +} +QString OEvent::toShortText()const { + return "OEvent shotText"; +} +QString OEvent::type()const { + return QString::fromLatin1("OEvent"); +} +QString OEvent::recordField( int /*id */ )const { + return QString::null; +} +int OEvent::rtti() { + return OPimResolver::DateBook; +} +bool OEvent::loadFromStream( QDataStream& ) { + return true; +} +bool OEvent::saveToStream( QDataStream& )const { + return true; +} +void OEvent::changeOrModify() { + if ( data->count != 1 ) { + data->deref(); + Data* d2 = new Data; + d2->description = data->description; + d2->location = data->location; + d2->manager = data->manager; + d2->recur = data->recur; + d2->note = data->note; + d2->created = data->created; + d2->start = data->start; + d2->end = data->end; + d2->isAllDay = data->isAllDay; + d2->timezone = data->timezone; + + data = d2; + } +} +void OEvent::deref() { + if ( data->deref() ) { + delete data; + data = 0; + } +} +// FIXME +QMap<int, QString> OEvent::toMap()const { + return QMap<int, QString>(); +} +QMap<QString, QString> OEvent::toExtraMap()const { + return QMap<QString, QString>(); +} + + +struct OEffectiveEvent::Data : public QShared { + Data() : QShared() { + } + OEvent event; + QDate date; + QTime start, end; + QDate startDate, endDate; + bool dates : 1; +}; + +OEffectiveEvent::OEffectiveEvent() { + data = new Data; + data->date = QDate::currentDate(); + data->start = data->end = QTime::currentTime(); + data->dates = false; +} +OEffectiveEvent::OEffectiveEvent( const OEvent& ev, const QDate& startDate, + Position pos ) { + data = new Data; + data->event = ev; + data->date = startDate; + if ( pos & Start ) + data->start = ev.startDateTime().time(); + else + data->start = QTime( 0, 0, 0 ); + + if ( pos & End ) + data->end = ev.endDateTime().time(); + else + data->end = QTime( 23, 59, 59 ); + + data->dates = false; +} +OEffectiveEvent::OEffectiveEvent( const OEffectiveEvent& ev) { + data = ev.data; + data->ref(); +} +OEffectiveEvent::~OEffectiveEvent() { + if ( data->deref() ) { + delete data; + data = 0; + } +} +OEffectiveEvent& OEffectiveEvent::operator=( const OEffectiveEvent& ev ) { + if ( *this == ev ) return *this; + + ev.data->ref(); + deref(); + data = ev.data; + + return *this; +} + +void OEffectiveEvent::setStartTime( const QTime& ti) { + changeOrModify(); + data->start = ti; +} +void OEffectiveEvent::setEndTime( const QTime& en) { + changeOrModify(); + data->end = en; +} +void OEffectiveEvent::setEvent( const OEvent& ev) { + changeOrModify(); + data->event = ev; +} +void OEffectiveEvent::setDate( const QDate& da) { + changeOrModify(); + data->date = da; +} +void OEffectiveEvent::setEffectiveDates( const QDate& from, + const QDate& to ) { + if (!from.isValid() ) { + data->dates = false; + return; + } + + data->startDate = from; + data->endDate = to; +} +QString OEffectiveEvent::description()const { + return data->event.description(); +} +QString OEffectiveEvent::location()const { + return data->event.location(); +} +QString OEffectiveEvent::note()const { + return data->event.note(); +} +OEvent OEffectiveEvent::event()const { + return data->event; +} +QTime OEffectiveEvent::startTime()const { + return data->start; +} +QTime OEffectiveEvent::endTime()const { + return data->end; +} +QDate OEffectiveEvent::date()const { + return data->date; +} +int OEffectiveEvent::length()const { + return (data->end.hour() * 60 - data->start.hour() * 60) + + QABS(data->start.minute() - data->end.minute() ); +} +int OEffectiveEvent::size()const { + return ( data->end.hour() - data->start.hour() ) * 3600 + + (data->end.minute() - data->start.minute() * 60 + + data->end.second() - data->start.second() ); +} +QDate OEffectiveEvent::startDate()const { + if ( data->dates ) + return data->startDate; + else if ( data->event.hasRecurrence() ) // single day, since multi-day should have a d pointer + return data->date; + else + return data->event.startDateTime().date(); +} +QDate OEffectiveEvent::endDate()const { + if ( data->dates ) + return data->endDate; + else if ( data->event.hasRecurrence() ) + return data->date; + else + return data->event.endDateTime().date(); +} +void OEffectiveEvent::deref() { + if ( data->deref() ) { + delete data; + data = 0; + } +} +void OEffectiveEvent::changeOrModify() { + if ( data->count != 1 ) { + data->deref(); + Data* d2 = new Data; + d2->event = data->event; + d2->date = data->date; + d2->start = data->start; + d2->end = data->end; + d2->startDate = data->startDate; + d2->endDate = data->endDate; + d2->dates = data->dates; + data = d2; + } +} +bool OEffectiveEvent::operator<( const OEffectiveEvent &e ) const{ + if ( data->date < e.date() ) + return TRUE; + if ( data->date == e.date() ) + return ( startTime() < e.startTime() ); + else + return FALSE; +} +bool OEffectiveEvent::operator<=( const OEffectiveEvent &e ) const{ + return (data->date <= e.date() ); +} +bool OEffectiveEvent::operator==( const OEffectiveEvent &e ) const { + return ( date() == e.date() + && startTime() == e.startTime() + && endTime()== e.endTime() + && event() == e.event() ); +} +bool OEffectiveEvent::operator!=( const OEffectiveEvent &e ) const { + return !(*this == e ); +} +bool OEffectiveEvent::operator>( const OEffectiveEvent &e ) const { + return !(*this <= e ); +} +bool OEffectiveEvent::operator>= ( const OEffectiveEvent &e ) const { + return !(*this < e); +} diff --git a/libopie2/opiepim/oevent.h b/libopie2/opiepim/oevent.h new file mode 100644 index 0000000..4489be7 --- a/dev/null +++ b/libopie2/opiepim/oevent.h @@ -0,0 +1,198 @@ +// CONTAINS GPLed code of TT + +#ifndef OPIE_PIM_EVENT_H +#define OPIE_PIM_EVENT_H + +#include <qstring.h> +#include <qdatetime.h> +#include <qvaluelist.h> + +#include <qpe/recordfields.h> +#include <qpe/palmtopuidgen.h> + +#include "otimezone.h" +#include "opimrecord.h" + +namespace OCalendarHelper { + /** calculate the week number of the date */ + static int week( const QDate& ); + /** calculate the occurence of week days since the start of the month */ + static int ocurrence( const QDate& ); + + // returns the dayOfWeek for the *first* day it finds (ignores + // any further days!). Returns 1 (Monday) if there isn't any day found + static int dayOfWeek( char day ); + + /** returns the diff of month */ + static int monthDiff( const QDate& first, const QDate& second ); + +} + +class OPimNotifyManager; +class ORecur; +class OEvent : public OPimRecord { +public: + typedef QValueList<OEvent> ValueList; + enum RecordFields { + Uid = Qtopia::UID_ID, + Category = Qtopia::CATEGORY_ID, + Description, + Location, + Alarm, + Reminder, + Recurrence, + Note, + Created, + StartDate, + EndDate, + AllDay, + TimeZone + }; + + OEvent(int uid = 0); + OEvent( const OEvent& ); + ~OEvent(); + OEvent &operator=( const OEvent& ); + + QString description()const; + void setDescription( const QString& description ); + + QString location()const; + void setLocation( const QString& loc ); + + bool hasNotifiers()const; + OPimNotifyManager ¬ifiers(); + + ORecur recurrence()const; + void setRecurrence( const ORecur& ); + bool hasRecurrence()const; + + QString note()const; + void setNote( const QString& note ); + + + QDateTime createdDateTime()const; + void setCreatedDateTime( const QDateTime& dt); + + /** set the date to dt. dt is the QDateTime in localtime */ + void setStartDateTime( const QDateTime& ); + /** returns the datetime in the local timeZone */ + QDateTime startDateTime()const; + + /** returns the start datetime in the current zone */ + QDateTime startDateTimeInZone()const; + + /** in current timezone */ + void setEndDateTime( const QDateTime& ); + /** in current timezone */ + QDateTime endDateTime()const; + QDateTime endDateTimeInZone()const; + + bool isMultipleDay()const; + bool isAllDay()const; + void setAllDay( bool isAllDay ); + + /* pin this event to a timezone! FIXME */ + void setTimeZone( const QString& timeZone ); + QString timeZone()const; + + + bool match( const QRegExp& )const; + + + + + /* needed reimp */ + QString toRichText()const; + QString toShortText()const; + QString type()const; + + QMap<int, QString> toMap()const; + QMap<QString, QString> toExtraMap()const; + QString recordField(int )const; + + static int rtti(); + + bool loadFromStream( QDataStream& ); + bool saveToStream( QDataStream& )const; + +/* bool operator==( const OEvent& ); + bool operator!=( const OEvent& ); + bool operator<( const OEvent& ); + bool operator<=( const OEvent& ); + bool operator>( const OEvent& ); + bool operator>=(const OEvent& ); +*/ +private: + inline void changeOrModify(); + void deref(); + struct Data; + Data* data; + class Private; + Private* priv; + +}; + +/** + * AN Event can span through multiple days. We split up a multiday eve + */ + +class OEffectiveEvent { +public: + QValueList<OEffectiveEvent> ValueList; + enum Position { MidWay, Start, End, StartEnd }; + // If we calculate the effective event of a multi-day event + // we have to figure out whether we are at the first day, + // at the end, or anywhere else ("middle"). This is important + // for the start/end times (00:00/23:59) + // MidWay: 00:00 -> 23:59, as we are "in the middle" of a multi- + // day event + // Start: start time -> 23:59 + // End: 00:00 -> end time + // Start | End == StartEnd: for single-day events (default) + // here we draw start time -> end time + OEffectiveEvent(); + OEffectiveEvent( const OEvent& event, const QDate& startDate, Position pos = StartEnd ); + OEffectiveEvent( const OEffectiveEvent& ); + OEffectiveEvent &operator=(const OEffectiveEvent& ); + ~OEffectiveEvent(); + + void setStartTime( const QTime& ); + void setEndTime( const QTime& ); + void setEvent( const OEvent& ); + void setDate( const QDate& ); + + void setEffectiveDates( const QDate& from, const QDate& to ); + + QString description()const; + QString location()const; + QString note()const; + OEvent event()const; + QTime startTime()const; + QTime endTime()const; + QDate date()const; + + /* return the length in hours */ + int length()const; + int size()const; + + QDate startDate()const; + QDate endDate()const; + + bool operator<( const OEffectiveEvent &e ) const; + bool operator<=( const OEffectiveEvent &e ) const; + bool operator==( const OEffectiveEvent &e ) const; + bool operator!=( const OEffectiveEvent &e ) const; + bool operator>( const OEffectiveEvent &e ) const; + bool operator>= ( const OEffectiveEvent &e ) const; + +private: + void deref(); + inline void changeOrModify(); + class Private; + Private* priv; + struct Data; + Data* data; + +}; +#endif diff --git a/libopie2/opiepim/otodo.cpp b/libopie2/opiepim/otodo.cpp index b4d4aa9..049359e 100644 --- a/libopie2/opiepim/otodo.cpp +++ b/libopie2/opiepim/otodo.cpp @@ -215,208 +215,210 @@ bool OTodo::isOverdue( ) { if( data->hasDate && !data->isCompleted) return QDate::currentDate() > data->date; return false; } void OTodo::setProgress(ushort progress ) { changeOrModify(); data->prog = progress; } QString OTodo::toShortText() const { return summary(); } /*! Returns a richt text string */ QString OTodo::toRichText() const { QString text; QStringList catlist; // Description of the todo if ( !summary().isEmpty() ) { text += "<b>" + QObject::tr( "Summary:") + "</b><br>"; text += Qtopia::escapeString(summary() ).replace(QRegExp( "[\n]"), "<br>" ) + "<br>"; } if( !description().isEmpty() ){ text += "<b>" + QObject::tr( "Description:" ) + "</b><br>"; text += Qtopia::escapeString(description() ).replace(QRegExp( "[\n]"), "<br>" ) ; } text += "<br><br><br>"; text += "<b>" + QObject::tr( "Priority:") +" </b>" + QString::number( priority() ) + " <br>"; text += "<b>" + QObject::tr( "Progress:") + " </b>" + QString::number( progress() ) + " %<br>"; if (hasDueDate() ){ text += "<b>" + QObject::tr( "Deadline:") + " </b>"; text += dueDate().toString(); text += "<br>"; } text += "<b>" + QObject::tr( "Category:") + "</b> "; text += categoryNames( "Todo List" ).join(", "); text += "<br>"; return text; } OPimNotifyManager& OTodo::notifiers() { return data->notifiers; } bool OTodo::operator<( const OTodo &toDoEvent )const{ if( !hasDueDate() && !toDoEvent.hasDueDate() ) return true; if( !hasDueDate() && toDoEvent.hasDueDate() ) return false; if( hasDueDate() && toDoEvent.hasDueDate() ){ if( dueDate() == toDoEvent.dueDate() ){ // let's the priority decide return priority() < toDoEvent.priority(); }else{ return dueDate() < toDoEvent.dueDate(); } } return false; } bool OTodo::operator<=(const OTodo &toDoEvent )const { if( !hasDueDate() && !toDoEvent.hasDueDate() ) return true; if( !hasDueDate() && toDoEvent.hasDueDate() ) return true; if( hasDueDate() && toDoEvent.hasDueDate() ){ if( dueDate() == toDoEvent.dueDate() ){ // let's the priority decide return priority() <= toDoEvent.priority(); }else{ return dueDate() <= toDoEvent.dueDate(); } } return true; } bool OTodo::operator>(const OTodo &toDoEvent )const { if( !hasDueDate() && !toDoEvent.hasDueDate() ) return false; if( !hasDueDate() && toDoEvent.hasDueDate() ) return false; if( hasDueDate() && toDoEvent.hasDueDate() ){ if( dueDate() == toDoEvent.dueDate() ){ // let's the priority decide return priority() > toDoEvent.priority(); }else{ return dueDate() > toDoEvent.dueDate(); } } return false; } bool OTodo::operator>=(const OTodo &toDoEvent )const { if( !hasDueDate() && !toDoEvent.hasDueDate() ) return true; if( !hasDueDate() && toDoEvent.hasDueDate() ) return false; if( hasDueDate() && toDoEvent.hasDueDate() ){ if( dueDate() == toDoEvent.dueDate() ){ // let's the priority decide return priority() > toDoEvent.priority(); }else{ return dueDate() > toDoEvent.dueDate(); } } return true; } bool OTodo::operator==(const OTodo &toDoEvent )const { if ( data->priority != toDoEvent.data->priority ) return false; if ( data->priority != toDoEvent.data->prog ) return false; if ( data->isCompleted != toDoEvent.data->isCompleted ) return false; if ( data->hasDate != toDoEvent.data->hasDate ) return false; if ( data->date != toDoEvent.data->date ) return false; if ( data->sum != toDoEvent.data->sum ) return false; if ( data->desc != toDoEvent.data->desc ) return false; if ( data->maintainer != toDoEvent.data->maintainer ) return false; return OPimRecord::operator==( toDoEvent ); } void OTodo::deref() { // qWarning("deref in ToDoEvent"); if ( data->deref() ) { // qWarning("deleting"); delete data; data= 0; } } OTodo &OTodo::operator=(const OTodo &item ) { + if ( *this == item ) return *this; + OPimRecord::operator=( item ); //qWarning("operator= ref "); item.data->ref(); deref(); data = item.data; return *this; } QMap<int, QString> OTodo::toMap() const { QMap<int, QString> map; map.insert( Uid, QString::number( uid() ) ); map.insert( Category, idsToString( categories() ) ); map.insert( HasDate, QString::number( data->hasDate ) ); map.insert( Completed, QString::number( data->isCompleted ) ); map.insert( Description, data->desc ); map.insert( Summary, data->sum ); map.insert( Priority, QString::number( data->priority ) ); map.insert( DateDay, QString::number( data->date.day() ) ); map.insert( DateMonth, QString::number( data->date.month() ) ); map.insert( DateYear, QString::number( data->date.year() ) ); map.insert( Progress, QString::number( data->prog ) ); // map.insert( CrossReference, crossToString() ); /* FIXME!!! map.insert( State, ); map.insert( Recurrence, ); map.insert( Reminders, ); map. */ return map; } QMap<QString, QString> OTodo::toExtraMap()const { return data->extra; } /** * change or modify looks at the ref count and either * creates a new QShared Object or it can modify it * right in place */ void OTodo::changeOrModify() { if ( data->count != 1 ) { qWarning("changeOrModify"); data->deref(); OTodoData* d2 = new OTodoData(); copy(data, d2 ); data = d2; } } // WATCHOUT /* * if you add something to the Data struct * be sure to copy it here */ void OTodo::copy( OTodoData* src, OTodoData* dest ) { dest->date = src->date; dest->isCompleted = src->isCompleted; dest->hasDate = src->hasDate; dest->priority = src->priority; dest->desc = src->desc; dest->sum = src->sum; dest->extra = src->extra; dest->prog = src->prog; dest->state = src->state; dest->recur = src->recur; dest->maintainer = src->maintainer; dest->start = src->start; dest->completed = src->completed; dest->notifiers = src->notifiers; } QString OTodo::type() const { return QString::fromLatin1("OTodo"); } QString OTodo::recordField(int /*id*/ )const { return QString::null; } int OTodo::rtti(){ return OPimResolver::TodoList; } |