summaryrefslogtreecommitdiff
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
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 (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
-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
11 files changed, 631 insertions, 35 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,95 +1,225 @@
#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();
@@ -162,67 +292,71 @@ OEvent::ValueList ODateBookAccessBackend_XML::directRawRepeats() {
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;
@@ -268,52 +402,57 @@ bool ODateBookAccessBackend_XML::loadFile() {
*/
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 );
}
@@ -368,28 +507,51 @@ void ODateBookAccessBackend_XML::setField( OEvent& e, int id, const QString& val
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
@@ -21,119 +21,129 @@ int OCalendarHelper::week( const QDate& date) {
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;
@@ -176,109 +186,157 @@ QDateTime OEvent::endDateTimeInZone()const {
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
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
@@ -40,87 +40,95 @@ public:
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:
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,28 +1,31 @@
+#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;
};
@@ -60,63 +63,71 @@ ORecur &ORecur::operator=( const ORecur& re) {
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;
@@ -422,25 +433,78 @@ void ORecur::setService( const QString& app ) {
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
@@ -52,36 +52,40 @@ public:
*/
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;
}
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,95 +1,225 @@
#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();
@@ -162,67 +292,71 @@ OEvent::ValueList ODateBookAccessBackend_XML::directRawRepeats() {
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;
@@ -268,52 +402,57 @@ bool ODateBookAccessBackend_XML::loadFile() {
*/
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 );
}
@@ -368,28 +507,51 @@ void ODateBookAccessBackend_XML::setField( OEvent& e, int id, const QString& val
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/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,28 +1,31 @@
+#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;
};
@@ -60,63 +63,71 @@ ORecur &ORecur::operator=( const ORecur& re) {
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;
@@ -422,25 +433,78 @@ void ORecur::setService( const QString& app ) {
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/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
@@ -52,36 +52,40 @@ public:
*/
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/libopie2/opiepim/oevent.cpp b/libopie2/opiepim/oevent.cpp
index ada596c..c3eeee2 100644
--- a/libopie2/opiepim/oevent.cpp
+++ b/libopie2/opiepim/oevent.cpp
@@ -21,119 +21,129 @@ int OCalendarHelper::week( const QDate& date) {
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;
@@ -176,109 +186,157 @@ QDateTime OEvent::endDateTimeInZone()const {
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
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
@@ -40,87 +40,95 @@ public:
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: