summaryrefslogtreecommitdiff
path: root/libopie2
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 /libopie2
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 'libopie2') (more/less context) (ignore whitespace changes)
-rw-r--r--libopie2/opiepim/backend/odatebookaccessbackend_xml.cpp184
-rw-r--r--libopie2/opiepim/core/orecur.cpp66
-rw-r--r--libopie2/opiepim/core/orecur.h4
-rw-r--r--libopie2/opiepim/oevent.cpp64
-rw-r--r--libopie2/opiepim/oevent.h10
5 files changed, 312 insertions, 16 deletions
diff --git a/libopie2/opiepim/backend/odatebookaccessbackend_xml.cpp b/libopie2/opiepim/backend/odatebookaccessbackend_xml.cpp
index a4c514b..5239d84 100644
--- a/libopie2/opiepim/backend/odatebookaccessbackend_xml.cpp
+++ b/libopie2/opiepim/backend/odatebookaccessbackend_xml.cpp
@@ -1,22 +1,26 @@
#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;
@@ -25,34 +29,115 @@ namespace {
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;
}
@@ -61,19 +146,64 @@ 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 ) {
@@ -178,17 +308,17 @@ bool ODateBookAccessBackend_XML::loadFile() {
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) );
@@ -197,16 +327,20 @@ bool ODateBookAccessBackend_XML::loadFile() {
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;
@@ -284,20 +418,25 @@ bool ODateBookAccessBackend_XML::loadFile() {
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 );
@@ -384,12 +523,35 @@ void ODateBookAccessBackend_XML::setField( OEvent& e, int id, const QString& val
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/libopie2/opiepim/core/orecur.cpp b/libopie2/opiepim/core/orecur.cpp
index e6a4787..e3b45b4 100644
--- a/libopie2/opiepim/core/orecur.cpp
+++ b/libopie2/opiepim/core/orecur.cpp
@@ -1,12 +1,15 @@
+#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;
@@ -76,31 +79,39 @@ bool ORecur::doesRecur( const QDate& date ) {
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
@@ -438,9 +449,62 @@ void ORecur::checkOrModify() {
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/libopie2/opiepim/core/orecur.h b/libopie2/opiepim/core/orecur.h
index 1e0014b..b214b3f 100644
--- a/libopie2/opiepim/core/orecur.h
+++ b/libopie2/opiepim/core/orecur.h
@@ -68,17 +68,21 @@ public:
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;
diff --git a/libopie2/opiepim/oevent.cpp b/libopie2/opiepim/oevent.cpp
index ada596c..c3eeee2 100644
--- a/libopie2/opiepim/oevent.cpp
+++ b/libopie2/opiepim/oevent.cpp
@@ -37,34 +37,38 @@ int OCalendarHelper::dayOfWeek( char day ) {
}
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 )
@@ -97,27 +101,33 @@ void OEvent::setDescription( const QString& 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) {
@@ -192,16 +202,17 @@ void OEvent::setAllDay( bool allDay ) {
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
@@ -234,16 +245,21 @@ void OEvent::changeOrModify() {
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;
@@ -251,18 +267,60 @@ void OEvent::deref() {
}
// 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;
diff --git a/libopie2/opiepim/oevent.h b/libopie2/opiepim/oevent.h
index c718e2e..585515c 100644
--- a/libopie2/opiepim/oevent.h
+++ b/libopie2/opiepim/oevent.h
@@ -56,17 +56,17 @@ public:
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 );
@@ -94,17 +94,25 @@ public:
/* 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;