summaryrefslogtreecommitdiff
path: root/libopie
authorzecke <zecke>2003-02-22 16:11:16 (UTC)
committer zecke <zecke>2003-02-22 16:11:16 (UTC)
commit397a7b1635488deda02b36df70692e27f59bb3e0 (patch) (side-by-side diff)
tree1232b1b7e8ac84c5d48df79b635ba61acbdf0f62 /libopie
parente7981098a5c373748d98158e8a6c59750bb0d7dc (diff)
downloadopie-397a7b1635488deda02b36df70692e27f59bb3e0.zip
opie-397a7b1635488deda02b36df70692e27f59bb3e0.tar.gz
opie-397a7b1635488deda02b36df70692e27f59bb3e0.tar.bz2
Implement saving of events
Implement the ExceptionList Add Children and parent to OEvent Make ORecur honor exceptions Extend the test app to add and save
Diffstat (limited to 'libopie') (more/less context) (ignore whitespace changes)
-rw-r--r--libopie/pim/odatebookaccessbackend_xml.cpp184
-rw-r--r--libopie/pim/oevent.cpp64
-rw-r--r--libopie/pim/oevent.h10
-rw-r--r--libopie/pim/orecur.cpp66
-rw-r--r--libopie/pim/orecur.h4
-rw-r--r--libopie/pim/test/oevent_test.cpp10
6 files changed, 319 insertions, 19 deletions
diff --git a/libopie/pim/odatebookaccessbackend_xml.cpp b/libopie/pim/odatebookaccessbackend_xml.cpp
index a4c514b..5239d84 100644
--- a/libopie/pim/odatebookaccessbackend_xml.cpp
+++ b/libopie/pim/odatebookaccessbackend_xml.cpp
@@ -1,119 +1,249 @@
#include <errno.h>
#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#include <qasciidict.h>
#include <qfile.h>
#include <qtopia/global.h>
#include <qtopia/stringutil.h>
+#include <qtopia/timeconversion.h>
#include "opimnotifymanager.h"
#include "orecur.h"
#include "otimezone.h"
#include "odatebookaccessbackend_xml.h"
namespace {
time_t start, end, created, rp_end;
ORecur* rec;
ORecur* recur() {
if (!rec)
rec = new ORecur;
return rec;
}
int alarmTime;
int snd;
enum Attribute{
- FDescription = 0,
- FLocation,
- FCategories,
- FUid,
- FType,
+ FDescription = 0,
+ FLocation,
+ FCategories,
+ FUid,
+ FType,
FAlarm,
FSound,
FRType,
FRWeekdays,
FRPosition,
FRFreq,
FRHasEndDate,
FREndDate,
FRStart,
FREnd,
FNote,
- FCreated
+ FCreated,
+ FTimeZone,
+ FRecParent,
+ FRecChildren,
+ FExceptions
};
+ inline void save( const OEvent& ev, QString& buf ) {
+ buf += " description=\"" + Qtopia::escapeString(ev.description() ) + "\"";
+ if (!ev.location().isEmpty() )
+ buf += " location=\"" + Qtopia::escapeString(ev.location() ) + "\"";
+
+ buf += " categories=\""+ Qtopia::escapeString( Qtopia::Record::idsToString( ev.categories() ) ) + "\"";
+ buf += " uid=\"" + QString::number( ev.uid() ) + "\"";
+
+ if (ev.isAllDay() )
+ buf += " type=\"AllDay\"";
+
+ if (ev.hasNotifiers() ) {
+ OPimAlarm alarm = ev.notifiers().alarms()[0]; // take only the first
+ int minutes = alarm.dateTime().secsTo( ev.startDateTime() ) / 60;
+ buf += " alarm=\"" + QString::number(minutes) + "\" sound=\"";
+ if ( alarm.sound() == OPimAlarm::Loud )
+ buf += "loud";
+ else
+ buf += "silent";
+ buf += "\"";
+ }
+ if ( ev.hasRecurrence() ) {
+ buf += ev.recurrence().toString();
+ }
+
+ /*
+ * fscking timezones :) well, we'll first convert
+ * the QDateTime to a QDateTime in UTC time
+ * and then we'll create a nice time_t
+ */
+ OTimeZone zone( ev.timeZone().isEmpty() ? OTimeZone::current() : ev.timeZone() );
+ buf += " start=\"" + QString::number( zone.fromUTCDateTime( zone.toDateTime( ev.startDateTime(), OTimeZone::utc() ) ) ) + "\"";
+ buf += " end=\"" + QString::number( zone.fromUTCDateTime( zone.toDateTime( ev.endDateTime() , OTimeZone::utc() ) ) ) + "\"";
+ if (!ev.note().isEmpty() ) {
+ buf += " note=\"" + Qtopia::escapeString( ev.note() ) + "\"";
+ }
+
+ buf += " timezone=\"";
+ if ( ev.timeZone().isEmpty() )
+ buf += "None";
+ else
+ buf += ev.timeZone();
+
+ if (ev.parent() != 0 ) {
+ buf += " recparent=\""+QString::number(ev.parent() )+"\"";
+ }
+
+ if (ev.children().count() != 0 ) {
+ QArray<int> children = ev.children();
+ buf += " recchildren=\"";
+ for ( uint i = 0; i < children.count(); i++ ) {
+ if ( i != 0 ) buf += " ";
+ buf += QString::number( children[i] );
+ }
+ buf+= "\"";
+ }
+
+ // skip custom writing
+ }
+
+ inline bool forAll( const QMap<int, OEvent>& list, QFile& file ) {
+ QMap<int, OEvent>::ConstIterator it;
+ QString buf;
+ QCString str;
+ int total_written;
+ for ( it = list.begin(); it != list.end(); ++it ) {
+ buf = "<event";
+ save( it.data(), buf );
+ buf += " />\n";
+ str = buf.utf8();
+
+ total_written = file.writeBlock(str.data(), str.length() );
+ if ( total_written != int(str.length() ) )
+ return false;
+ }
+ return true;
+ }
}
ODateBookAccessBackend_XML::ODateBookAccessBackend_XML( const QString& ,
const QString& fileName )
: ODateBookAccessBackend() {
m_name = fileName.isEmpty() ? Global::applicationFileName( "datebook", "datebook.xml" ) : fileName;
m_changed = false;
}
ODateBookAccessBackend_XML::~ODateBookAccessBackend_XML() {
}
bool ODateBookAccessBackend_XML::load() {
return loadFile();
}
bool ODateBookAccessBackend_XML::reload() {
clear();
return load();
}
bool ODateBookAccessBackend_XML::save() {
- if (!m_changed) return true;
- m_changed = false;
+ qWarning("going to save now");
+// if (!m_changed) return true;
+
+ int total_written;
+ QString strFileNew = m_name + ".new";
+
+ QFile f( strFileNew );
+ if (!f.open( IO_WriteOnly | IO_Raw ) ) return false;
+
+ QString buf( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" );
+ buf += "<!DOCTYPE DATEBOOK><DATEBOOK>\n";
+ buf += "<events>\n";
+ QCString str = buf.utf8();
+ total_written = f.writeBlock( str.data(), str.length() );
+ if ( total_written != int(str.length() ) ) {
+ f.close();
+ QFile::remove( strFileNew );
+ return false;
+ }
+ if (!forAll( m_raw, f ) ) {
+ f.close();
+ QFile::remove( strFileNew );
+ return false;
+ }
+ if (!forAll( m_rep, f ) ) {
+ f.close();
+ QFile::remove( strFileNew );
+ return false;
+ }
+
+ buf = "</events>\n</DATEBOOK>\n";
+ str = buf.utf8();
+ total_written = f.writeBlock( str.data(), str.length() );
+ if ( total_written != int(str.length() ) ) {
+ f.close();
+ QFile::remove( strFileNew );
+ return false;
+ }
+ f.close();
+
+ exit(0);
+ if ( ::rename( strFileNew, m_name ) < 0 ) {
+ QFile::remove( strFileNew );
+ return false;
+ }
+
+ m_changed = false;
return true;
}
QArray<int> ODateBookAccessBackend_XML::allRecords()const {
QArray<int> ints( m_raw.count()+ m_rep.count() );
uint i = 0;
QMap<int, OEvent>::ConstIterator it;
for ( it = m_raw.begin(); it != m_raw.end(); ++it ) {
ints[i] = it.key();
i++;
}
for ( it = m_rep.begin(); it != m_rep.end(); ++it ) {
ints[i] = it.key();
i++;
}
return ints;
}
QArray<int> ODateBookAccessBackend_XML::queryByExample(const OEvent&, int ) {
return QArray<int>();
}
void ODateBookAccessBackend_XML::clear() {
m_raw.clear();
m_rep.clear();
}
OEvent ODateBookAccessBackend_XML::find( int uid ) const{
if ( m_raw.contains( uid ) )
return m_raw[uid];
else
return m_rep[uid];
}
bool ODateBookAccessBackend_XML::add( const OEvent& ev ) {
m_changed = true;
if (ev.hasRecurrence() )
m_rep.insert( ev.uid(), ev );
else
m_raw.insert( ev.uid(), ev );
return true;
}
bool ODateBookAccessBackend_XML::remove( int uid ) {
m_changed = true;
m_rep.remove( uid );
m_rep.remove( uid );
return true;
}
bool ODateBookAccessBackend_XML::replace( const OEvent& ev ) {
@@ -138,258 +268,290 @@ QArray<int> ODateBookAccessBackend_XML::rawRepeats()const {
QArray<int> ODateBookAccessBackend_XML::nonRepeats()const {
QArray<int> ints( m_raw.count() );
uint i = 0;
QMap<int, OEvent>::ConstIterator it;
for ( it = m_raw.begin(); it != m_raw.end(); ++it ) {
ints[i] = it.key();
i++;
}
return ints;
}
OEvent::ValueList ODateBookAccessBackend_XML::directNonRepeats() {
OEvent::ValueList list;
QMap<int, OEvent>::ConstIterator it;
for (it = m_raw.begin(); it != m_raw.end(); ++it )
list.append( it.data() );
return list;
}
OEvent::ValueList ODateBookAccessBackend_XML::directRawRepeats() {
OEvent::ValueList list;
QMap<int, OEvent>::ConstIterator it;
for (it = m_rep.begin(); it != m_rep.end(); ++it )
list.append( it.data() );
return list;
}
bool ODateBookAccessBackend_XML::loadFile() {
m_changed = false;
int fd = ::open( QFile::encodeName(m_name).data(), O_RDONLY );
if ( fd < 0 ) return false;
struct stat attribute;
if ( ::fstat(fd, &attribute ) == -1 ) {
::close( fd );
return false;
}
void* map_addr = ::mmap(NULL, attribute.st_size, PROT_READ, MAP_SHARED, fd, 0 );
if ( map_addr == ( (caddr_t)-1) ) {
::close( fd );
return false;
}
::madvise( map_addr, attribute.st_size, MADV_SEQUENTIAL );
::close( fd );
- QAsciiDict<int> dict(FCreated+1);
+ QAsciiDict<int> dict(FExceptions+1);
dict.setAutoDelete( true );
dict.insert( "description", new int(FDescription) );
dict.insert( "location", new int(FLocation) );
dict.insert( "categories", new int(FCategories) );
dict.insert( "uid", new int(FUid) );
dict.insert( "type", new int(FType) );
dict.insert( "alarm", new int(FAlarm) );
dict.insert( "sound", new int(FSound) );
dict.insert( "rtype", new int(FRType) );
dict.insert( "rweekdays", new int(FRWeekdays) );
dict.insert( "rposition", new int(FRPosition) );
dict.insert( "rfreq", new int(FRFreq) );
dict.insert( "rhasenddate", new int(FRHasEndDate) );
dict.insert( "enddt", new int(FREndDate) );
dict.insert( "start", new int(FRStart) );
dict.insert( "end", new int(FREnd) );
dict.insert( "note", new int(FNote) );
dict.insert( "created", new int(FCreated) );
+ dict.insert( "recparent", new int(FRecParent) );
+ dict.insert( "recchildren", new int(FRecChildren) );
+ dict.insert( "exceptions", new int(FExceptions) );
+ dict.insert( "timezone", new int(FTimeZone) );
char* dt = (char*)map_addr;
int len = attribute.st_size;
int i = 0;
char* point;
const char* collectionString = "<event ";
int strLen = ::strlen(collectionString);
int *find;
while ( dt + 1 != 0 && (( point = ::strstr( dt+i, collectionString ) ) != 0 ) ) {
i = point -dt;
i+= strLen;
alarmTime = -1;
snd = 0; // silent
OEvent ev;
rec = 0;
while ( TRUE ) {
while ( i < len && (dt[i] == ' ' || dt[i] == '\n' || dt[i] == '\r') )
++i;
if ( i >= len-2 || (dt[i] == '/' && dt[i+1] == '>') )
break;
// we have another attribute, read it.
int j = i;
while ( j < len && dt[j] != '=' )
++j;
QCString attr( dt+i, j-i+1);
i = ++j; // skip =
// find the start of quotes
while ( i < len && dt[i] != '"' )
++i;
j = ++i;
bool haveUtf = FALSE;
bool haveEnt = FALSE;
while ( j < len && dt[j] != '"' ) {
if ( ((unsigned char)dt[j]) > 0x7f )
haveUtf = TRUE;
if ( dt[j] == '&' )
haveEnt = TRUE;
++j;
}
if ( i == j ) {
// empty value
i = j + 1;
continue;
}
QCString value( dt+i, j-i+1 );
i = j + 1;
QString str = (haveUtf ? QString::fromUtf8( value )
: QString::fromLatin1( value ) );
if ( haveEnt )
str = Qtopia::plainString( str );
/*
* add key + value
*/
find = dict[attr.data()];
if (!find)
ev.setCustomField( attr, value );
else {
setField( ev, *find, value );
}
}
/* time to finalize */
finalizeRecord( ev );
add( ev );
delete rec;
}
::munmap(map_addr, attribute.st_size );
m_changed = false; // changed during add
return true;
}
void ODateBookAccessBackend_XML::finalizeRecord( OEvent& ev ) {
/* AllDay is alway in UTC */
if ( ev.isAllDay() ) {
OTimeZone utc = OTimeZone::utc();
ev.setStartDateTime( utc.fromUTCDateTime( start ) );
ev.setEndDateTime ( utc.fromUTCDateTime( end ) );
+ ev.setTimeZone( "UTC"); // make sure it is really utc
}else {
+ /* to current date time */
OTimeZone zone( ev.timeZone().isEmpty() ? OTimeZone::current() : ev.timeZone() );
- ev.setStartDateTime( zone.toDateTime( start ) );
- ev.setEndDateTime ( zone.toDateTime( end ) );
+ QDateTime date = zone.toDateTime( start );
+ ev.setStartDateTime( zone.toDateTime( date, OTimeZone::current() ) );
+
+ date = zone.toDateTime( end );
+ ev.setEndDateTime ( zone.toDateTime( date, OTimeZone::current() ) );
}
if ( rec && rec->doesRecur() ) {
OTimeZone utc = OTimeZone::utc();
ORecur recu( *rec ); // call copy c'tor;
recu.setEndDate ( utc.fromUTCDateTime( rp_end ).date() );
recu.setCreatedDateTime( utc.fromUTCDateTime( created ) );
recu.setStart( ev.startDateTime().date() );
ev.setRecurrence( recu );
}
if (alarmTime != -1 ) {
QDateTime dt = ev.startDateTime().addSecs( -1*alarmTime*60 );
OPimAlarm al( snd , dt );
ev.notifiers().add( al );
}
if ( m_raw.contains( ev.uid() ) || m_rep.contains( ev.uid() ) ) {
ev.setUid( 1 );
}
if ( ev.hasRecurrence() )
m_rep.insert( ev.uid(), ev );
else
m_raw.insert( ev.uid(), ev );
}
void ODateBookAccessBackend_XML::setField( OEvent& e, int id, const QString& value) {
// qWarning(" setting %s", value.latin1() );
switch( id ) {
case FDescription:
e.setDescription( value );
break;
case FLocation:
e.setLocation( value );
break;
case FCategories:
e.setCategories( e.idsFromString( value ) );
break;
case FUid:
e.setUid( value.toInt() );
break;
case FType:
if ( value == "AllDay" ) {
e.setAllDay( true );
e.setTimeZone( "UTC" );
}
break;
case FAlarm:
alarmTime = value.toInt();
break;
case FSound:
snd = value == "loud" ? OPimAlarm::Loud : OPimAlarm::Silent;
break;
// recurrence stuff
case FRType:
if ( value == "Daily" )
recur()->setType( ORecur::Daily );
else if ( value == "Weekly" )
recur()->setType( ORecur::Weekly);
else if ( value == "MonthlyDay" )
recur()->setType( ORecur::MonthlyDay );
else if ( value == "MonthlyDate" )
recur()->setType( ORecur::MonthlyDate );
else if ( value == "Yearly" )
recur()->setType( ORecur::Yearly );
else
recur()->setType( ORecur::NoRepeat );
break;
case FRWeekdays:
recur()->setDays( value.toInt() );
break;
case FRPosition:
recur()->setPosition( value.toInt() );
break;
case FRFreq:
recur()->setFrequency( value.toInt() );
break;
case FRHasEndDate:
recur()->setHasEndDate( value.toInt() );
break;
case FREndDate: {
rp_end = (time_t) value.toLong();
break;
}
case FRStart: {
start = (time_t) value.toLong();
break;
}
case FREnd: {
end = ( (time_t) value.toLong() );
break;
}
case FNote:
e.setNote( value );
break;
case FCreated:
created = value.toInt();
break;
+ case FRecParent:
+ e.setParent( value.toInt() );
+ break;
+ case FRecChildren:{
+ QStringList list = QStringList::split(' ', value );
+ for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) {
+ e.addChild( (*it).toInt() );
+ }
+ }
+ break;
+ case FExceptions:{
+ QStringList list = QStringList::split(' ', value );
+ for (QStringList::Iterator it = list.begin(); it != list.end(); ++it ) {
+ QDate date( (*it).left(4).toInt(), (*it).mid(4, 2).toInt(), (*it).right(2).toInt() );
+ qWarning("adding exception %s", date.toString().latin1() );
+ recur()->exceptions().append( date );
+ }
+ }
+ break;
+ case FTimeZone:
+ if ( value != "None" )
+ e.setTimeZone( value );
+ break;
default:
break;
}
}
diff --git a/libopie/pim/oevent.cpp b/libopie/pim/oevent.cpp
index ada596c..c3eeee2 100644
--- a/libopie/pim/oevent.cpp
+++ b/libopie/pim/oevent.cpp
@@ -1,308 +1,366 @@
#include <qshared.h>
#include <qpe/palmtopuidgen.h>
#include <qpe/categories.h>
#include "orecur.h"
#include "opimresolver.h"
#include "opimnotifymanager.h"
#include "oevent.h"
int OCalendarHelper::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;
}
int OCalendarHelper::ocurrence( 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;
}
int OCalendarHelper::dayOfWeek( char day ) {
int dayOfWeek = 1;
char i = ORecur::MON;
while ( !( i & day ) && i <= ORecur::SUN ) {
i <<= 1;
++dayOfWeek;
}
return dayOfWeek;
}
int OCalendarHelper::monthDiff( const QDate& first, const QDate& second ) {
return ( second.year() - first.year() ) * 12 +
second.month() - first.month();
}
struct OEvent::Data : public QShared {
Data() : QShared() {
+ child = 0;
recur = 0;
manager = 0;
isAllDay = false;
+ parent = 0;
}
~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;
+ QArray<int>* child;
+ int parent;
};
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() {
+OPimNotifyManager &OEvent::notifiers()const {
// 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);
+ if (!data->manager )
+ return false;
+ if (data->manager->reminders().isEmpty() &&
+ data->manager->alarms().isEmpty() )
+ return false;
+
+ return true;
}
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 {
if (!data->recur ) return false;
return data->recur->doesRecur();
}
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::setAllDay( bool allDay ) {
changeOrModify();
data->isAllDay = allDay;
if (allDay ) data->timezone = "UTC";
}
void OEvent::setTimeZone( const QString& tz ) {
changeOrModify();
data->timezone = tz;
}
QString OEvent::timeZone()const {
+ if (data->isAllDay ) return QString::fromLatin1("UTC");
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;
+ d2->parent = data->parent;
+ d2->child = data->child;
+
+ if (d2->child )
+ d2->child->detach();
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>();
}
+int OEvent::parent()const {
+ return data->parent;
+}
+void OEvent::setParent( int uid ) {
+ changeOrModify();
+ data->parent = uid;
+}
+QArray<int> OEvent::children() const{
+ if (!data->child) return QArray<int>();
+ else
+ return data->child->copy();
+}
+void OEvent::setChildren( const QArray<int>& arr ) {
+ changeOrModify();
+ if (data->child) delete data->child;
-
+ data->child = new QArray<int>( arr );
+ data->child->detach();
+}
+void OEvent::addChild( int uid ) {
+ changeOrModify();
+ if (!data->child ) {
+ data->child = new QArray<int>(1);
+ (*data->child)[0] = uid;
+ }else{
+ int count = data->child->count();
+ data->child->resize( count + 1 );
+ (*data->child)[count] = uid;
+ }
+}
+void OEvent::removeChild( int uid ) {
+ if (!data->child || !data->child->contains( uid ) ) return;
+ changeOrModify();
+ QArray<int> newAr( data->child->count() - 1 );
+ int j = 0;
+ uint count = data->child->count();
+ for ( uint i = 0; i < count; i++ ) {
+ if ( (*data->child)[i] != uid ) {
+ newAr[j] = (*data->child)[i];
+ j++;
+ }
+ }
+ (*data->child) = newAr;
+}
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();
diff --git a/libopie/pim/oevent.h b/libopie/pim/oevent.h
index c718e2e..585515c 100644
--- a/libopie/pim/oevent.h
+++ b/libopie/pim/oevent.h
@@ -16,135 +16,143 @@
struct 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 &notifiers();
+ OPimNotifyManager &notifiers()const;
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;
+ /** For exception to recurrence here is a list of children... */
+ QArray<int> children()const;
+ void setChildren( const QArray<int>& );
+ void addChild( int uid );
+ void removeChild( int uid );
+ /** return the parent OEvent */
+ int parent()const;
+ void setParent( int uid );
/* 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:
typedef 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
diff --git a/libopie/pim/orecur.cpp b/libopie/pim/orecur.cpp
index e6a4787..e3b45b4 100644
--- a/libopie/pim/orecur.cpp
+++ b/libopie/pim/orecur.cpp
@@ -1,146 +1,157 @@
+#include <time.h>
+
#include <qshared.h>
#include <qtopia/timeconversion.h>
+#include "otimezone.h"
#include "orecur.h"
struct ORecur::Data : public QShared {
Data() : QShared() {
type = ORecur::NoRepeat;
freq = -1;
days = 0;
pos = 0;
create = QDateTime::currentDateTime();
hasEnd = FALSE;
end = QDate::currentDate();
}
char days; // Q_UINT8 for 8 seven days;)
ORecur::RepeatType type;
int freq;
int pos;
bool hasEnd : 1;
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 ) {
+ bool stillLooking;
+ stillLooking = p_nextOccurrence( from, next );
+ while ( stillLooking && data->list.contains(next) )
+ stillLooking = p_nextOccurrence( next.addDays(1), next );
+
+ return stillLooking;
+}
+bool ORecur::p_nextOccurrence( 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) {
+ 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;
@@ -398,49 +409,102 @@ void ORecur::setPosition( int pos ) {
data->pos = pos;
}
void ORecur::setDays( char c ) {
checkOrModify();
data->days = c;
}
void ORecur::setEndDate( const QDate& dt) {
checkOrModify();
data->end = dt;
}
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;
}
}
+QString ORecur::toString()const {
+ QString buf;
+
+ buf += " rtype=\"";
+ switch ( data->type ) {
+ case ORecur::Daily:
+ buf += "Daily";
+ break;
+ case ORecur::Weekly:
+ buf += "Weekly";
+ break;
+ case ORecur::MonthlyDay:
+ buf += "MonthlyDay";
+ break;
+ case ORecur::MonthlyDate:
+ buf += "MonthlyDate";
+ break;
+ case ORecur::Yearly:
+ buf += "Yearly";
+ break;
+ default:
+ buf += "NoRepeat";
+ break;
+ }
+ buf += "\"";
+ if (data->days > 0 )
+ buf += " rweekdays=\"" + QString::number( static_cast<int>( data->days ) ) + "\"";
+ if ( data->pos != 0 )
+ buf += " rposition=\"" + QString::number(data->pos ) + "\"";
+
+ buf += " rfreq=\"" + QString::number( data->freq ) + "\"";
+ buf += " rhasenddate=\"" + QString::number( static_cast<int>( data->hasEnd ) ) + "\"";
+ if ( data->hasEnd )
+ buf += " enddt=\""
+ + QString::number( OTimeZone::utc().fromUTCDateTime( QDateTime( data->end, QTime(12,0,0) ) ) )
+ + "\"";
+ buf += " created=\"" + QString::number( OTimeZone::utc().fromUTCDateTime( data->create ) ) + "\"";
+
+ if ( data->list.isEmpty() ) return buf;
+ // save exceptions list here!!
+ ExceptionList::ConstIterator it;
+ ExceptionList list = data->list;
+ buf += " exceptions=\"";
+ QDate date;
+ for ( it = list.begin(); it != list.end(); ++it ) {
+ date = (*it);
+ if ( it != list.begin() ) buf += " ";
+
+ buf += QCString().sprintf("%04d%02d%02d", date.year(), date.month(), date.day() );
+ }
+ buf += "\"";
+ return buf;
+}
diff --git a/libopie/pim/orecur.h b/libopie/pim/orecur.h
index 1e0014b..b214b3f 100644
--- a/libopie/pim/orecur.h
+++ b/libopie/pim/orecur.h
@@ -28,60 +28,64 @@ public:
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;
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 setCreatedDateTime( const QDateTime& );
void setHasEndDate( bool b );
void setRepitition(int );
void setService( const QString& ser );
+
+ /* almost internal */
+ QString toString()const;
private:
+ bool p_nextOccurrence( const QDate& from, QDate& next );
void deref();
inline void checkOrModify();
class Data;
Data* data;
class ORecurPrivate;
ORecurPrivate *d;
};
#endif
diff --git a/libopie/pim/test/oevent_test.cpp b/libopie/pim/test/oevent_test.cpp
index 6f04995..247b83b 100644
--- a/libopie/pim/test/oevent_test.cpp
+++ b/libopie/pim/test/oevent_test.cpp
@@ -1,50 +1,54 @@
#include <qdatetime.h>
#include "../oevent.h"
#include "../odatebookaccess.h"
int main(int argc, char* argv ) {
OEvent ev;
- ev.setUid( 20 );
+// ev.setUid( 20 );
- ev.setDescription( "Foo" );
+ ev.setDescription( "Foo Descsfewrf" );
OEvent ev2 = ev;
- ev2.setDescription("Foo2");
+ ev2.setDescription("Foo3");
qWarning("%s", ev2.description().latin1() );
qWarning("%s", ev.description().latin1() );
QDateTime time = QDateTime::currentDateTime();
ev2.setStartDateTime( time );
ev2.setTimeZone( "Europe/London" );
qWarning("%s", ev2.startDateTime().toString().latin1() );
qWarning("%s", ev2.startDateTimeInZone().toString().latin1() );
+ qWarning("%d %d", ev.isAllDay(), ev2.isAllDay() );
ODateBookAccess acc;
if(!acc.load() ) qWarning("could not load");
ODateBookAccess::List::Iterator it;
ODateBookAccess::List list = acc.allRecords();
for( it = list.begin(); it != list.end(); ++it ){
OEvent ev = (*it);
qWarning("Summary: %s",ev.description().latin1() );
qWarning("Start: %s End: %s",ev.startDateTime().toString().latin1(), ev.endDateTime().toString().latin1() );
qWarning("All Day: %d",ev.isAllDay() );
}
QDate date1(2003,02,01 );
QDate date2(2003,03,01 );
OEffectiveEvent::ValueList effList = acc.effectiveEvents( date1,date2 );
OEffectiveEvent::ValueList::Iterator effIt;
for( effIt = effList.begin(); effIt != effList.end(); ++effIt ){
OEffectiveEvent ef = (*effIt);
qWarning("Summary: %s", ef.description().latin1() );
qWarning("Date: %s", ef.date().toString().latin1() );
}
+ ev.setUid( 1 );
+ acc.add( ev );
+ acc.save();
return 0;
}