author | eilers <eilers> | 2004-05-08 12:38:51 (UTC) |
---|---|---|
committer | eilers <eilers> | 2004-05-08 12:38:51 (UTC) |
commit | 81bc0cecdeb7c49f4f2950c1e5649bad05593d0c (patch) (side-by-side diff) | |
tree | b687e3562c432414df407d5d4e776b7c785588a3 | |
parent | 91eccd3d535a8fb0022865bd1e1c100628a65431 (diff) | |
download | opie-81bc0cecdeb7c49f4f2950c1e5649bad05593d0c.zip opie-81bc0cecdeb7c49f4f2950c1e5649bad05593d0c.tar.gz opie-81bc0cecdeb7c49f4f2950c1e5649bad05593d0c.tar.bz2 |
Fixed a lot of worse bugs in the databook-backend for SQL.
It was found by doing equivalence checks between events, moved between xml
and sql backend, using opimconverter..
More bugfixes will follow..
-rw-r--r-- | libopie2/opiepim/backend/odatebookaccessbackend_sql.cpp | 2 | ||||
-rw-r--r-- | libopie2/opiepim/core/opimevent.cpp | 30 | ||||
-rw-r--r-- | libopie2/opiepim/core/opimevent.h | 2 |
3 files changed, 21 insertions, 13 deletions
diff --git a/libopie2/opiepim/backend/odatebookaccessbackend_sql.cpp b/libopie2/opiepim/backend/odatebookaccessbackend_sql.cpp index 6c32b40..f4f3c94 100644 --- a/libopie2/opiepim/backend/odatebookaccessbackend_sql.cpp +++ b/libopie2/opiepim/backend/odatebookaccessbackend_sql.cpp @@ -1,454 +1,454 @@ /* This file is part of the Opie Project Copyright (C) Stefan Eilers (Eilers.Stefan@epost.de) =. Copyright (C) The Opie Team <opie-devel@handhelds.org> .=l. .>+-= _;:, .> :=|. This program is free software; you can .> <`_, > . <= redistribute it and/or modify it under :`=1 )Y*s>-.-- : the terms of the GNU Library General Public .="- .-=="i, .._ License as published by the Free Software - . .-<_> .<> Foundation; either version 2 of the License, ._= =} : or (at your option) any later version. .%`+i> _;_. .i_,=:_. -<s. This program is distributed in the hope that + . -:. = it will be useful, but WITHOUT ANY WARRANTY; : .. .:, . . . without even the implied warranty of =_ + =;=|` MERCHANTABILITY or FITNESS FOR A _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU ..}^=.= = ; Library General Public License for more ++= -. .` .: details. : = ...= . :.=- -. .:....=;==+<; You should have received a copy of the GNU -_. . . )=. = Library General Public License along with -- :-=` this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* * SQL Backend for the OPIE-Calender Database. * */ #include <stdio.h> #include <stdlib.h> #include <qarray.h> #include <qstringlist.h> #include <qpe/global.h> #include <opie2/osqldriver.h> #include <opie2/osqlmanager.h> #include <opie2/osqlquery.h> #include <opie2/opimrecurrence.h> #include <opie2/odatebookaccessbackend_sql.h> using namespace Opie::DB; namespace { /** * a find query for custom elements */ class FindCustomQuery : public OSQLQuery { public: FindCustomQuery(int uid); FindCustomQuery(const QArray<int>& ); ~FindCustomQuery(); QString query()const; private: QString single()const; QString multi()const; QArray<int> m_uids; int m_uid; }; FindCustomQuery::FindCustomQuery(int uid) : OSQLQuery(), m_uid( uid ) { } FindCustomQuery::FindCustomQuery(const QArray<int>& ints) : OSQLQuery(), m_uids( ints ){ } FindCustomQuery::~FindCustomQuery() { } QString FindCustomQuery::query()const{ // if ( m_uids.count() == 0 ) return single(); } QString FindCustomQuery::single()const{ QString qu = "select uid, type, value from custom_data where uid = "; qu += QString::number(m_uid); return qu; } } namespace Opie { ODateBookAccessBackend_SQL::ODateBookAccessBackend_SQL( const QString& , const QString& fileName ) : ODateBookAccessBackend(), m_driver( NULL ) { m_fileName = fileName.isEmpty() ? Global::applicationFileName( "datebook", "datebook.db" ) : fileName; // Get the standart sql-driver from the OSQLManager.. OSQLManager man; m_driver = man.standard(); m_driver->setUrl( m_fileName ); initFields(); load(); } ODateBookAccessBackend_SQL::~ODateBookAccessBackend_SQL() { if( m_driver ) delete m_driver; } void ODateBookAccessBackend_SQL::initFields() { // This map contains the translation of the fieldtype id's to // the names of the table columns m_fieldMap.insert( OPimEvent::FUid, "uid" ); m_fieldMap.insert( OPimEvent::FCategories, "Categories" ); m_fieldMap.insert( OPimEvent::FDescription, "Description" ); m_fieldMap.insert( OPimEvent::FLocation, "Location" ); m_fieldMap.insert( OPimEvent::FType, "Type" ); m_fieldMap.insert( OPimEvent::FAlarm, "Alarm" ); m_fieldMap.insert( OPimEvent::FSound, "Sound" ); m_fieldMap.insert( OPimEvent::FRType, "RType" ); m_fieldMap.insert( OPimEvent::FRWeekdays, "RWeekdays" ); m_fieldMap.insert( OPimEvent::FRPosition, "RPosition" ); m_fieldMap.insert( OPimEvent::FRFreq, "RFreq" ); m_fieldMap.insert( OPimEvent::FRHasEndDate, "RHasEndDate" ); m_fieldMap.insert( OPimEvent::FREndDate, "REndDate" ); m_fieldMap.insert( OPimEvent::FRCreated, "RCreated" ); m_fieldMap.insert( OPimEvent::FRExceptions, "RExceptions" ); m_fieldMap.insert( OPimEvent::FStart, "Start" ); m_fieldMap.insert( OPimEvent::FEnd, "End" ); m_fieldMap.insert( OPimEvent::FNote, "Note" ); m_fieldMap.insert( OPimEvent::FTimeZone, "TimeZone" ); m_fieldMap.insert( OPimEvent::FRecParent, "RecParent" ); m_fieldMap.insert( OPimEvent::FRecChildren, "Recchildren" ); // Create a map that maps the column name to the id QMapConstIterator<int, QString> it; - for ( it = ++m_fieldMap.begin(); it != m_fieldMap.end(); ++it ){ + for ( it = m_fieldMap.begin(); it != m_fieldMap.end(); ++it ){ m_reverseFieldMap.insert( it.data(), it.key() ); } } bool ODateBookAccessBackend_SQL::load() { if (!m_driver->open() ) return false; // Don't expect that the database exists. // It is save here to create the table, even if it // do exist. ( Is that correct for all databases ?? ) QString qu = "create table datebook( uid INTEGER PRIMARY KEY "; QMap<int, QString>::Iterator it; for ( it = ++m_fieldMap.begin(); it != m_fieldMap.end(); ++it ){ qu += QString( ",%1 VARCHAR(10)" ).arg( it.data() ); } qu += " );"; qu += "create table custom_data( uid INTEGER, id INTEGER, type VARCHAR(10), priority INTEGER, value VARCHAR(10), PRIMARY KEY /* identifier */ (uid, id) );"; qWarning( "command: %s", qu.latin1() ); OSQLRawQuery raw( qu ); OSQLResult res = m_driver->query( &raw ); if ( res.state() != OSQLResult::Success ) return false; update(); return true; } void ODateBookAccessBackend_SQL::update() { QString qu = "select uid from datebook"; OSQLRawQuery raw( qu ); OSQLResult res = m_driver->query( &raw ); if ( res.state() != OSQLResult::Success ){ // m_uids.clear(); return; } m_uids = extractUids( res ); } bool ODateBookAccessBackend_SQL::reload() { return load(); } bool ODateBookAccessBackend_SQL::save() { return m_driver->close(); // Shouldn't m_driver->sync be better than close ? (eilers) } QArray<int> ODateBookAccessBackend_SQL::allRecords()const { return m_uids; } QArray<int> ODateBookAccessBackend_SQL::queryByExample(const OPimEvent&, int, const QDateTime& ) { return QArray<int>(); } void ODateBookAccessBackend_SQL::clear() { QString qu = "drop table datebook;"; qu += "drop table custom_data;"; OSQLRawQuery raw( qu ); OSQLResult res = m_driver->query( &raw ); reload(); } OPimEvent ODateBookAccessBackend_SQL::find( int uid ) const{ qDebug( "ODateBookAccessBackend_SQL::find( %d )", uid ); QString qu = "select *"; qu += "from datebook where uid = " + QString::number(uid); qDebug( "Query: %s", qu.latin1() ); OSQLRawQuery raw( qu ); OSQLResult res = m_driver->query( &raw ); OSQLResultItem resItem = res.first(); // Create Map for date event and insert UID QMap<int,QString> dateEventMap; dateEventMap.insert( OPimEvent::FUid, QString::number( uid ) ); // Now insert the data out of the columns into the map. QMapConstIterator<int, QString> it; for ( it = ++m_fieldMap.begin(); it != m_fieldMap.end(); ++it ){ dateEventMap.insert( m_reverseFieldMap[*it], resItem.data( *it ) ); } // Last step: Put map into date event, add custom map and return it OPimEvent retDate( dateEventMap ); retDate.setExtraMap( requestCustom( uid ) ); qDebug( "ODateBookAccessBackend_SQL::find( %d ) end", uid ); return retDate; } // FIXME: Speed up update of uid's.. bool ODateBookAccessBackend_SQL::add( const OPimEvent& ev ) { QMap<int,QString> eventMap = ev.toMap(); QString qu = "insert into datebook VALUES( " + QString::number( ev.uid() ); QMap<int, QString>::Iterator it; for ( it = ++m_fieldMap.begin(); it != m_fieldMap.end(); ++it ){ if ( !eventMap[it.key()].isEmpty() ) qu += QString( ",\"%1\"" ).arg( eventMap[it.key()] ); else qu += QString( ",\"\"" ); } qu += " );"; // Add custom entries int id = 0; QMap<QString, QString> customMap = ev.toExtraMap(); for( QMap<QString, QString>::Iterator it = customMap.begin(); it != customMap.end(); ++it ){ qu += "insert into custom_data VALUES(" + QString::number( ev.uid() ) + "," + QString::number( id++ ) + ",'" + it.key() //.latin1() + "'," + "0" // Priority for future enhancements + ",'" + it.data() //.latin1() + "');"; } qWarning("add %s", qu.latin1() ); OSQLRawQuery raw( qu ); OSQLResult res = m_driver->query( &raw ); if ( res.state() != OSQLResult::Success ){ return false; } // Update list of uid's update(); return true; } // FIXME: Speed up update of uid's.. bool ODateBookAccessBackend_SQL::remove( int uid ) { QString qu = "DELETE from datebook where uid = " + QString::number( uid ) + ";"; qu += "DELETE from custom_data where uid = " + QString::number( uid ) + ";"; OSQLRawQuery raw( qu ); OSQLResult res = m_driver->query( &raw ); if ( res.state() != OSQLResult::Success ){ return false; } // Update list of uid's update(); return true; } bool ODateBookAccessBackend_SQL::replace( const OPimEvent& ev ) { remove( ev.uid() ); return add( ev ); } QArray<int> ODateBookAccessBackend_SQL::rawEvents()const { return allRecords(); } QArray<int> ODateBookAccessBackend_SQL::rawRepeats()const { QString qu = "select uid from datebook where RType!=\"\" AND RType!=\"NoRepeat\""; OSQLRawQuery raw( qu ); OSQLResult res = m_driver->query( &raw ); if ( res.state() != OSQLResult::Success ){ QArray<int> nix; return nix; } return extractUids( res ); } QArray<int> ODateBookAccessBackend_SQL::nonRepeats()const { QString qu = "select uid from datebook where RType=\"\" or RType=\"NoRepeat\""; OSQLRawQuery raw( qu ); OSQLResult res = m_driver->query( &raw ); if ( res.state() != OSQLResult::Success ){ QArray<int> nix; return nix; } return extractUids( res ); } OPimEvent::ValueList ODateBookAccessBackend_SQL::directNonRepeats() { QArray<int> nonRepUids = nonRepeats(); OPimEvent::ValueList list; for (uint i = 0; i < nonRepUids.count(); ++i ){ list.append( find( nonRepUids[i] ) ); } return list; } OPimEvent::ValueList ODateBookAccessBackend_SQL::directRawRepeats() { QArray<int> rawRepUids = rawRepeats(); OPimEvent::ValueList list; for (uint i = 0; i < rawRepUids.count(); ++i ){ list.append( find( rawRepUids[i] ) ); } return list; } QArray<int> ODateBookAccessBackend_SQL::matchRegexp( const QRegExp &r ) const { QString qu = "SELECT uid FROM datebook WHERE ("; // Do it make sense to search other fields, too ? qu += " rlike(\""+ r.pattern() + "\", Location ) OR"; qu += " rlike(\""+ r.pattern() + "\", Note )"; qu += " )"; qDebug( "query: %s", qu.latin1() ); OSQLRawQuery raw( qu ); OSQLResult res = m_driver->query( &raw ); return extractUids( res ); } /* ===== Private Functions ========================================== */ QArray<int> ODateBookAccessBackend_SQL::extractUids( OSQLResult& res ) const { qWarning("extractUids"); QTime t; t.start(); OSQLResultItem::ValueList list = res.results(); OSQLResultItem::ValueList::Iterator it; QArray<int> ints(list.count() ); qWarning(" count = %d", list.count() ); int i = 0; for (it = list.begin(); it != list.end(); ++it ) { ints[i] = (*it).data("uid").toInt(); i++; } qWarning("extractUids ready: count2 = %d needs %d ms", i, t.elapsed() ); return ints; } QMap<QString, QString> ODateBookAccessBackend_SQL::requestCustom( int uid ) const { QTime t; t.start(); QMap<QString, QString> customMap; FindCustomQuery query( uid ); OSQLResult res_custom = m_driver->query( &query ); if ( res_custom.state() == OSQLResult::Failure ) { qWarning("OSQLResult::Failure in find query !!"); QMap<QString, QString> empty; return empty; } OSQLResultItem::ValueList list = res_custom.results(); OSQLResultItem::ValueList::Iterator it = list.begin(); for ( ; it != list.end(); ++it ) { customMap.insert( (*it).data( "type" ), (*it).data( "value" ) ); } qDebug("RequestCustom needed: %d ms", t.elapsed() ); return customMap; } } diff --git a/libopie2/opiepim/core/opimevent.cpp b/libopie2/opiepim/core/opimevent.cpp index 8bf8b25..9d46651 100644 --- a/libopie2/opiepim/core/opimevent.cpp +++ b/libopie2/opiepim/core/opimevent.cpp @@ -1,1022 +1,1030 @@ /* This file is part of the Opie Project Copyright (C) Stefan Eilers <Eilers.Stefan@epost.de> =. Copyright (C) The Opie Team <opie-devel@handhelds.org> .=l. .>+-= _;:, .> :=|. This program is free software; you can .> <`_, > . <= redistribute it and/or modify it under :`=1 )Y*s>-.-- : the terms of the GNU Library General Public .="- .-=="i, .._ License as published by the Free Software - . .-<_> .<> Foundation; either version 2 of the License, ._= =} : or (at your option) any later version. .%`+i> _;_. .i_,=:_. -<s. This program is distributed in the hope that + . -:. = it will be useful, but WITHOUT ANY WARRANTY; : .. .:, . . . without even the implied warranty of =_ + =;=|` MERCHANTABILITY or FITNESS FOR A _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU ..}^=.= = ; Library General Public License for more ++= -. .` .: details. : = ...= . :.=- -. .:....=;==+<; You should have received a copy of the GNU -_. . . )=. = Library General Public License along with -- :-=` this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "opimevent.h" /* OPIE */ #include <opie2/opimrecurrence.h> #include <opie2/opimresolver.h> #include <opie2/opimnotifymanager.h> #include <qpe/categories.h> #include <qpe/stringutil.h> /* QT */ namespace Opie { 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 = OPimRecurrence::MON; while ( !( i & day ) && i <= OPimRecurrence::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 OPimEvent::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; OPimRecurrence* recur; QString note; QDateTime created; QDateTime start; QDateTime end; bool isAllDay : 1; QString timezone; QArray<int>* child; int parent; }; OPimEvent::OPimEvent( int uid ) : OPimRecord( uid ) { data = new Data; } OPimEvent::OPimEvent( const OPimEvent& ev ) : OPimRecord( ev ), data( ev.data ) { data->ref(); } OPimEvent::OPimEvent( const QMap<int, QString> map ) : OPimRecord( 0 ) { data = new Data; fromMap( map ); } OPimEvent::~OPimEvent() { if ( data->deref() ) { delete data; data = 0; } } OPimEvent& OPimEvent::operator=( const OPimEvent& ev ) { if ( this == &ev ) return * this; OPimRecord::operator=( ev ); ev.data->ref(); deref(); data = ev.data; return *this; } QString OPimEvent::description() const { return data->description; } void OPimEvent::setDescription( const QString& description ) { changeOrModify(); data->description = description; } void OPimEvent::setLocation( const QString& loc ) { changeOrModify(); data->location = loc; } QString OPimEvent::location() const { return data->location; } OPimNotifyManager &OPimEvent::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 OPimEvent::hasNotifiers() const { if ( !data->manager ) return false; if ( data->manager->reminders().isEmpty() && data->manager->alarms().isEmpty() ) return false; return true; } OPimRecurrence OPimEvent::recurrence() const { if ( !data->recur ) data->recur = new OPimRecurrence; return *data->recur; } void OPimEvent::setRecurrence( const OPimRecurrence& rec ) { changeOrModify(); if ( data->recur ) ( *data->recur ) = rec; else data->recur = new OPimRecurrence( rec ); } bool OPimEvent::hasRecurrence() const { if ( !data->recur ) return false; return data->recur->doesRecur(); } QString OPimEvent::note() const { return data->note; } void OPimEvent::setNote( const QString& note ) { changeOrModify(); data->note = note; } QDateTime OPimEvent::createdDateTime() const { return data->created; } void OPimEvent::setCreatedDateTime( const QDateTime& time ) { changeOrModify(); data->created = time; } QDateTime OPimEvent::startDateTime() const { if ( data->isAllDay ) return QDateTime( data->start.date(), QTime( 0, 0, 0 ) ); return data->start; } QDateTime OPimEvent::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 == OPimTimeZone::current().timeZone() ) return startDateTime(); OPimTimeZone zone( data->timezone ); return zone.toDateTime( data->start, OPimTimeZone::current() ); } void OPimEvent::setStartDateTime( const QDateTime& dt ) { changeOrModify(); data->start = dt; } QDateTime OPimEvent::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 OPimEvent::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 == OPimTimeZone::current().timeZone() ) return endDateTime(); OPimTimeZone zone( data->timezone ); return zone.toDateTime( data->end, OPimTimeZone::current() ); } void OPimEvent::setEndDateTime( const QDateTime& dt ) { changeOrModify(); data->end = dt; } bool OPimEvent::isMultipleDay() const { return data->end.date().day() - data->start.date().day(); } bool OPimEvent::isAllDay() const { return data->isAllDay; } void OPimEvent::setAllDay( bool allDay ) { changeOrModify(); data->isAllDay = allDay; if ( allDay ) data->timezone = "UTC"; } void OPimEvent::setTimeZone( const QString& tz ) { changeOrModify(); data->timezone = tz; } QString OPimEvent::timeZone() const { if ( data->isAllDay ) return QString::fromLatin1( "UTC" ); return data->timezone; } bool OPimEvent::match( const QRegExp& re ) const { if ( re.match( data->description ) != -1 ) { setLastHitField( Qtopia::DatebookDescription ); return true; } if ( re.match( data->note ) != -1 ) { setLastHitField( Qtopia::Note ); return true; } if ( re.match( data->location ) != -1 ) { setLastHitField( Qtopia::Location ); return true; } if ( re.match( data->start.toString() ) != -1 ) { setLastHitField( Qtopia::StartDateTime ); return true; } if ( re.match( data->end.toString() ) != -1 ) { setLastHitField( Qtopia::EndDateTime ); return true; } return false; } QString OPimEvent::toRichText() const { QString text, value; // description text += "<b><h3><img src=\"datebook/DateBook\">"; if ( !description().isEmpty() ) { text += Qtopia::escapeString( description() ).replace( QRegExp( "[\n]" ), "" ); } text += "</h3></b><br><hr><br>"; // location if ( !( value = location() ).isEmpty() ) { text += "<b>" + QObject::tr( "Location:" ) + "</b> "; text += Qtopia::escapeString( value ) + "<br>"; } // all day event if ( isAllDay() ) { text += "<b><i>" + QObject::tr( "This is an all day event" ) + "</i></b><br>"; } // multiple day event else if ( isMultipleDay () ) { text += "<b><i>" + QObject::tr( "This is a multiple day event" ) + "</i></b><br>"; } // start & end times else { // start time if ( startDateTime().isValid() ) { text += "<b>" + QObject::tr( "Start:" ) + "</b> "; text += Qtopia::escapeString( startDateTime().toString() ). replace( QRegExp( "[\n]" ), "<br>" ) + "<br>"; } // end time if ( endDateTime().isValid() ) { text += "<b>" + QObject::tr( "End:" ) + "</b> "; text += Qtopia::escapeString( endDateTime().toString() ). replace( QRegExp( "[\n]" ), "<br>" ) + "<br>"; } } // categories if ( categoryNames( "Calendar" ).count() ) { text += "<b>" + QObject::tr( "Category:" ) + "</b> "; text += categoryNames( "Calendar" ).join( ", " ); text += "<br>"; } //notes if ( !note().isEmpty() ) { text += "<b>" + QObject::tr( "Note:" ) + "</b><br>"; text += note(); // text += Qtopia::escapeString(note() ). // replace(QRegExp( "[\n]"), "<br>" ) + "<br>"; } return text; } QString OPimEvent::toShortText() const { QString text; text += QString::number( startDateTime().date().day() ); text += "."; text += QString::number( startDateTime().date().month() ); text += "."; text += QString::number( startDateTime().date().year() ); text += " "; text += QString::number( startDateTime().time().hour() ); text += ":"; text += QString::number( startDateTime().time().minute() ); text += " - "; text += description(); return text; } QString OPimEvent::type() const { return QString::fromLatin1( "OPimEvent" ); } QString OPimEvent::recordField( int /*id */ ) const { return QString::null; } int OPimEvent::rtti() const { return OPimResolver::DateBook; } bool OPimEvent::loadFromStream( QDataStream& ) { return true; } bool OPimEvent::saveToStream( QDataStream& ) const { return true; } void OPimEvent::changeOrModify() { if ( data->count != 1 ) { data->deref(); Data* d2 = new Data; d2->description = data->description; d2->location = data->location; if ( data->manager ) d2->manager = new OPimNotifyManager( *data->manager ); if ( data->recur ) d2->recur = new OPimRecurrence( *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; if ( data->child ) { d2->child = new QArray<int>( *data->child ); d2->child->detach(); } data = d2; } } void OPimEvent::deref() { if ( data->deref() ) { delete data; data = 0; } } // Exporting Event data to map. Using the same // encoding as ODateBookAccessBackend_xml does.. // Thus, we could remove the stuff there and use this // for it and for all other places.. // Encoding should happen at one place, only ! (eilers) QMap<int, QString> OPimEvent::toMap() const { QMap<int, QString> retMap; retMap.insert( OPimEvent::FUid, QString::number( uid() ) ); retMap.insert( OPimEvent::FCategories, Qtopia::escapeString( Qtopia::Record::idsToString( categories() ) ) ); retMap.insert( OPimEvent::FDescription, Qtopia::escapeString( description() ) ); retMap.insert( OPimEvent::FLocation, Qtopia::escapeString( location() ) ); retMap.insert( OPimEvent::FType, isAllDay() ? "AllDay" : "" ); + if ( notifiers().alarms().count() ){ + // Currently we just support one alarm.. (eilers) OPimAlarm alarm = notifiers().alarms() [ 0 ]; retMap.insert( OPimEvent::FAlarm, QString::number( alarm.dateTime().secsTo( startDateTime() ) / 60 ) ); retMap.insert( OPimEvent::FSound, ( alarm.sound() == OPimAlarm::Loud ) ? "loud" : "silent" ); + } OPimTimeZone zone( timeZone().isEmpty() ? OPimTimeZone::current() : timeZone() ); retMap.insert( OPimEvent::FStart, QString::number( zone.fromUTCDateTime( zone.toDateTime( startDateTime(), OPimTimeZone::utc() ) ) ) ); retMap.insert( OPimEvent::FEnd, QString::number( zone.fromUTCDateTime( zone.toDateTime( endDateTime(), OPimTimeZone::utc() ) ) ) ); retMap.insert( OPimEvent::FNote, Qtopia::escapeString( note() ) ); retMap.insert( OPimEvent::FTimeZone, timeZone().isEmpty() ? QString( "None" ) : timeZone() ); if ( parent() ) retMap.insert( OPimEvent::FRecParent, QString::number( parent() ) ); if ( children().count() ) { QArray<int> childr = children(); QString buf; for ( uint i = 0; i < childr.count(); i++ ) { if ( i != 0 ) buf += " "; buf += QString::number( childr[ i ] ); } retMap.insert( OPimEvent::FRecChildren, buf ); } // Add recurrence stuff if ( hasRecurrence() ) { OPimRecurrence recur = recurrence(); QMap<int, QString> recFields = recur.toMap(); retMap.insert( OPimEvent::FRType, recFields[ OPimRecurrence::RType ] ); retMap.insert( OPimEvent::FRWeekdays, recFields[ OPimRecurrence::RWeekdays ] ); retMap.insert( OPimEvent::FRPosition, recFields[ OPimRecurrence::RPosition ] ); retMap.insert( OPimEvent::FRFreq, recFields[ OPimRecurrence::RFreq ] ); retMap.insert( OPimEvent::FRHasEndDate, recFields[ OPimRecurrence::RHasEndDate ] ); retMap.insert( OPimEvent::FREndDate, recFields[ OPimRecurrence::EndDate ] ); retMap.insert( OPimEvent::FRCreated, recFields[ OPimRecurrence::Created ] ); retMap.insert( OPimEvent::FRExceptions, recFields[ OPimRecurrence::Exceptions ] ); } else { OPimRecurrence recur = recurrence(); QMap<int, QString> recFields = recur.toMap(); retMap.insert( OPimEvent::FRType, recFields[ OPimRecurrence::RType ] ); } return retMap; } void OPimEvent::fromMap( const QMap<int, QString>& map ) { // We just want to set the UID if it is really stored. if ( !map[ OPimEvent::FUid ].isEmpty() ) setUid( map[ OPimEvent::FUid ].toInt() ); setCategories( idsFromString( map[ OPimEvent::FCategories ] ) ); setDescription( map[ OPimEvent::FDescription ] ); setLocation( map[ OPimEvent::FLocation ] ); if ( map[ OPimEvent::FType ] == "AllDay" ) setAllDay( true ); else setAllDay( false ); - int alarmTime = -1; - if ( !map[ OPimEvent::FAlarm ].isEmpty() ) - alarmTime = map[ OPimEvent::FAlarm ].toInt(); - - int sound = ( ( map[ OPimEvent::FSound ] == "loud" ) ? OPimAlarm::Loud : OPimAlarm::Silent ); - if ( ( alarmTime != -1 ) ) - { - QDateTime dt = startDateTime().addSecs( -1 * alarmTime * 60 ); - OPimAlarm al( sound , dt ); - notifiers().add( al ); - } if ( !map[ OPimEvent::FTimeZone ].isEmpty() && ( map[ OPimEvent::FTimeZone ] != "None" ) ) { setTimeZone( map[ OPimEvent::FTimeZone ] ); } time_t start = ( time_t ) map[ OPimEvent::FStart ].toLong(); time_t end = ( time_t ) map[ OPimEvent::FEnd ].toLong(); /* AllDay is always in UTC */ if ( isAllDay() ) { OPimTimeZone utc = OPimTimeZone::utc(); setStartDateTime( utc.fromUTCDateTime( start ) ); setEndDateTime ( utc.fromUTCDateTime( end ) ); setTimeZone( "UTC" ); // make sure it is really utc } else { /* to current date time */ // qWarning(" Start is %d", start ); OPimTimeZone zone( timeZone().isEmpty() ? OPimTimeZone::current() : timeZone() ); QDateTime date = zone.toDateTime( start ); qWarning( " Start is %s", date.toString().latin1() ); setStartDateTime( zone.toDateTime( date, OPimTimeZone::current() ) ); date = zone.toDateTime( end ); setEndDateTime ( zone.toDateTime( date, OPimTimeZone::current() ) ); } + int alarmTime = -1; + if ( !map[ OPimEvent::FAlarm ].isEmpty() ) + alarmTime = map[ OPimEvent::FAlarm ].toInt(); + + int sound = ( ( map[ OPimEvent::FSound ] == "loud" ) ? OPimAlarm::Loud : OPimAlarm::Silent ); + if ( ( alarmTime != -1 ) ) + { + QDateTime dt = startDateTime().addSecs( -1 * alarmTime * 60 ); + OPimAlarm al( sound , dt ); + notifiers().add( al ); + } + + + if ( !map[ OPimEvent::FNote ].isEmpty() ) + setNote( map[ OPimEvent::FNote ] ); + if ( !map[ OPimEvent::FRecParent ].isEmpty() ) setParent( map[ OPimEvent::FRecParent ].toInt() ); if ( !map[ OPimEvent::FRecChildren ].isEmpty() ) { QStringList list = QStringList::split( ' ', map[ OPimEvent::FRecChildren ] ); for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) { addChild( ( *it ).toInt() ); } } // Fill recurrence stuff and put it directly into the OPimRecurrence-Object using fromMap.. if ( !map[ OPimEvent::FRType ].isEmpty() ) { QMap<int, QString> recFields; recFields.insert( OPimRecurrence::RType, map[ OPimEvent::FRType ] ); recFields.insert( OPimRecurrence::RWeekdays, map[ OPimEvent::FRWeekdays ] ); recFields.insert( OPimRecurrence::RPosition, map[ OPimEvent::FRPosition ] ); recFields.insert( OPimRecurrence::RFreq, map[ OPimEvent::FRFreq ] ); recFields.insert( OPimRecurrence::RHasEndDate, map[ OPimEvent::FRHasEndDate ] ); recFields.insert( OPimRecurrence::EndDate, map[ OPimEvent::FREndDate ] ); recFields.insert( OPimRecurrence::Created, map[ OPimEvent::FRCreated ] ); recFields.insert( OPimRecurrence::Exceptions, map[ OPimEvent::FRExceptions ] ); OPimRecurrence recur( recFields ); setRecurrence( recur ); } } int OPimEvent::parent() const { return data->parent; } void OPimEvent::setParent( int uid ) { changeOrModify(); data->parent = uid; } QArray<int> OPimEvent::children() const { if ( !data->child ) return QArray<int>(); else return data->child->copy(); } void OPimEvent::setChildren( const QArray<int>& arr ) { changeOrModify(); if ( data->child ) delete data->child; data->child = new QArray<int>( arr ); data->child->detach(); } void OPimEvent::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 OPimEvent::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() {} OPimEvent 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 OPimEvent& ev, const QDate& startDate, Position pos ) { data = new Data; data->event = ev; data->date = startDate; if ( pos & Start ) data->start = ev.startDateTime().time(); else data->start = QTime( 0, 0, 0 ); if ( pos & End ) data->end = ev.endDateTime().time(); else data->end = QTime( 23, 59, 59 ); data->dates = false; } OEffectiveEvent::OEffectiveEvent( const OEffectiveEvent& ev ) { data = ev.data; data->ref(); } OEffectiveEvent::~OEffectiveEvent() { if ( data->deref() ) { delete data; data = 0; } } OEffectiveEvent& OEffectiveEvent::operator=( const OEffectiveEvent& ev ) { if ( *this == ev ) return * this; ev.data->ref(); deref(); data = ev.data; return *this; } void OEffectiveEvent::setStartTime( const QTime& ti ) { changeOrModify(); data->start = ti; } void OEffectiveEvent::setEndTime( const QTime& en ) { changeOrModify(); data->end = en; } void OEffectiveEvent::setEvent( const OPimEvent& ev ) { changeOrModify(); data->event = ev; } void OEffectiveEvent::setDate( const QDate& da ) { changeOrModify(); data->date = da; } void OEffectiveEvent::setEffectiveDates( const QDate& from, const QDate& to ) { if ( !from.isValid() ) { data->dates = false; return ; } data->startDate = from; data->endDate = to; } QString OEffectiveEvent::description() const { return data->event.description(); } QString OEffectiveEvent::location() const { return data->event.location(); } QString OEffectiveEvent::note() const { return data->event.note(); } OPimEvent OEffectiveEvent::event() const { return data->event; } QTime OEffectiveEvent::startTime() const { return data->start; } QTime OEffectiveEvent::endTime() const { return data->end; } QDate OEffectiveEvent::date() const { return data->date; } int OEffectiveEvent::length() const { return ( data->end.hour() * 60 - data->start.hour() * 60 ) + QABS( data->start.minute() - data->end.minute() ); } int OEffectiveEvent::size() const { return ( data->end.hour() - data->start.hour() ) * 3600 + ( data->end.minute() - data->start.minute() * 60 + data->end.second() - data->start.second() ); } QDate OEffectiveEvent::startDate() const { if ( data->dates ) return data->startDate; else if ( data->event.hasRecurrence() ) // single day, since multi-day should have a d pointer return data->date; else return data->event.startDateTime().date(); } QDate OEffectiveEvent::endDate() const { if ( data->dates ) return data->endDate; else if ( data->event.hasRecurrence() ) return data->date; else return data->event.endDateTime().date(); } void OEffectiveEvent::deref() { if ( data->deref() ) { delete data; data = 0; } } void OEffectiveEvent::changeOrModify() { if ( data->count != 1 ) { data->deref(); Data* d2 = new Data; d2->event = data->event; d2->date = data->date; d2->start = data->start; d2->end = data->end; d2->startDate = data->startDate; d2->endDate = data->endDate; d2->dates = data->dates; data = d2; } } bool OEffectiveEvent::operator<( const OEffectiveEvent &e ) const { if ( data->date < e.date() ) return TRUE; if ( data->date == e.date() ) return ( startTime() < e.startTime() ); else return FALSE; } bool OEffectiveEvent::operator<=( const OEffectiveEvent &e ) const { return ( data->date <= e.date() ); } bool OEffectiveEvent::operator==( const OEffectiveEvent &e ) const { return ( date() == e.date() && startTime() == e.startTime() && endTime() == e.endTime() && event() == e.event() ); } bool OEffectiveEvent::operator!=( const OEffectiveEvent &e ) const { return !( *this == e ); } bool OEffectiveEvent::operator>( const OEffectiveEvent &e ) const { return !( *this <= e ); } bool OEffectiveEvent::operator>= ( const OEffectiveEvent &e ) const { return !( *this < e ); } } diff --git a/libopie2/opiepim/core/opimevent.h b/libopie2/opiepim/core/opimevent.h index 56fe917..5553cac 100644 --- a/libopie2/opiepim/core/opimevent.h +++ b/libopie2/opiepim/core/opimevent.h @@ -1,275 +1,275 @@ /* This file is part of the Opie Project Copyright (C) Stefan Eilers <Eilers.Stefan@epost.de> =. Copyright (C) The Opie Team <opie-devel@handhelds.org> .=l. .>+-= _;:, .> :=|. This program is free software; you can .> <`_, > . <= redistribute it and/or modify it under :`=1 )Y*s>-.-- : the terms of the GNU Library General Public .="- .-=="i, .._ License as published by the Free Software - . .-<_> .<> Foundation; either version 2 of the License, ._= =} : or (at your option) any later version. .%`+i> _;_. .i_,=:_. -<s. This program is distributed in the hope that + . -:. = it will be useful, but WITHOUT ANY WARRANTY; : .. .:, . . . without even the implied warranty of =_ + =;=|` MERCHANTABILITY or FITNESS FOR A _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU ..}^=.= = ; Library General Public License for more ++= -. .` .: details. : = ...= . :.=- -. .:....=;==+<; You should have received a copy of the GNU -_. . . )=. = Library General Public License along with -- :-=` this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // CONTAINS GPLed code of TT #ifndef OEVENT_H #define OEVENT_H /* OPIE */ #include <opie2/opimtimezone.h> #include <opie2/opimrecord.h> #include <qpe/recordfields.h> #include <qpe/palmtopuidgen.h> /* QT */ #include <qstring.h> #include <qdatetime.h> #include <qvaluelist.h> namespace Opie { 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 OPimRecurrence; /** * This is the container for all Events. It encapsules all * available information for a single Event * @short container for events. */ class OPimEvent : public OPimRecord { public: typedef QValueList<OPimEvent> ValueList; /** * RecordFields contain possible attributes * used in the Results of toMap().. */ enum RecordFields { FUid = Qtopia::UID_ID, FCategories = Qtopia::CATEGORY_ID, - FDescription = 0, + FDescription /* = 0 Why this ? (eilers) */, FLocation, FType, FAlarm, FSound, FRType, FRWeekdays, FRPosition, FRFreq, FRHasEndDate, FREndDate, FRCreated, FRExceptions, FStart, FEnd, FNote, FTimeZone, FRecParent, FRecChildren, }; /** * Start with an Empty OPimEvent. UID == 0 means that it is empty */ OPimEvent( int uid = 0 ); /** * copy c'tor */ OPimEvent( const OPimEvent& ); /** * Create OPimEvent, initialized by map * @see enum RecordFields */ OPimEvent( const QMap<int, QString> map ); ~OPimEvent(); OPimEvent &operator=( const OPimEvent& ); QString description() const; void setDescription( const QString& description ); QString location() const; void setLocation( const QString& loc ); bool hasNotifiers() const; OPimNotifyManager ¬ifiers() const; OPimRecurrence recurrence() const; void setRecurrence( const OPimRecurrence& ); 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; virtual 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 OPimEvent */ int parent() const; void setParent( int uid ); /* needed reimp */ QString toRichText() const; QString toShortText() const; QString type() const; QMap<int, QString> toMap() const; void fromMap( const QMap<int, QString>& map ); QString recordField( int ) const; int rtti() const; bool loadFromStream( QDataStream& ); bool saveToStream( QDataStream& ) const; /* bool operator==( const OPimEvent& ); bool operator!=( const OPimEvent& ); bool operator<( const OPimEvent& ); bool operator<=( const OPimEvent& ); bool operator>( const OPimEvent& ); bool operator>=(const OPimEvent& ); */ 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 // End: 00:00 -> end time // Start | End == StartEnd: for single-day events (default) // here we draw start time -> end time OEffectiveEvent(); OEffectiveEvent( const OPimEvent& event, const QDate& startDate, Position pos = StartEnd ); OEffectiveEvent( const OEffectiveEvent& ); OEffectiveEvent &operator=( const OEffectiveEvent& ); ~OEffectiveEvent(); void setStartTime( const QTime& ); void setEndTime( const QTime& ); void setEvent( const OPimEvent& ); void setDate( const QDate& ); void setEffectiveDates( const QDate& from, const QDate& to ); QString description() const; QString location() const; QString note() const; OPimEvent event() const; QTime startTime() const; QTime endTime() const; QDate date() const; /* return the length in hours */ int length() const; int size() const; QDate startDate() const; QDate endDate() const; bool operator<( const OEffectiveEvent &e ) const; bool operator<=( const OEffectiveEvent &e ) const; bool operator==( const OEffectiveEvent &e ) const; bool operator!=( const OEffectiveEvent &e ) const; bool operator>( const OEffectiveEvent &e ) const; bool operator>= ( const OEffectiveEvent &e ) const; private: void deref(); inline void changeOrModify(); class Private; Private* priv; struct Data; Data* data; }; } #endif |