libopie PIM API Documentation

otodoaccessxml.cpp

Go to the documentation of this file.
00001 #include <errno.h>
00002 #include <fcntl.h>
00003 
00004 #include <sys/mman.h>
00005 #include <sys/stat.h>
00006 #include <sys/types.h>
00007 
00008 #include <unistd.h>
00009 
00010 
00011 #include <qfile.h>
00012 #include <qvector.h>
00013 
00014 #include <qpe/global.h>
00015 #include <qpe/stringutil.h>
00016 #include <qpe/timeconversion.h>
00017 
00018 #include "oconversion.h"
00019 #include "opimstate.h"
00020 #include "otimezone.h"
00021 #include "opimnotifymanager.h"
00022 #include "orecur.h"
00023 #include "otodoaccessxml.h"
00024 
00025 namespace {
00026     time_t rp_end;
00027     ORecur* rec;
00028     ORecur *recur() {
00029         if (!rec ) rec = new ORecur;
00030         return rec;
00031     }
00032     int snd;
00033     enum MoreAttributes {
00034         FRType = OTodo::CompletedDate + 2,
00035         FRWeekdays,
00036         FRPosition,
00037         FRFreq,
00038         FRHasEndDate,
00039         FREndDate,
00040         FRStart,
00041         FREnd
00042     };
00043     // FROM TT again
00044 char *strstrlen(const char *haystack, int hLen, const char* needle, int nLen)
00045 {
00046     char needleChar;
00047     char haystackChar;
00048     if (!needle || !haystack || !hLen || !nLen)
00049     return 0;
00050 
00051     const char* hsearch = haystack;
00052 
00053     if ((needleChar = *needle++) != 0) {
00054     nLen--; //(to make up for needle++)
00055     do {
00056         do {
00057         if ((haystackChar = *hsearch++) == 0)
00058             return (0);
00059         if (hsearch >= haystack + hLen)
00060             return (0);
00061         } while (haystackChar != needleChar);
00062     } while (strncmp(hsearch, needle, QMIN(hLen - (hsearch - haystack), nLen)) != 0);
00063     hsearch--;
00064     }
00065     return ((char *)hsearch);
00066 }
00067 }
00068 
00069 
00070 OTodoAccessXML::OTodoAccessXML( const QString& appName,
00071                                 const QString& fileName )
00072     : OTodoAccessBackend(), m_app( appName ),  m_opened( false ), m_changed( false )
00073 {
00074     if (!fileName.isEmpty() )
00075         m_file = fileName;
00076     else
00077         m_file = Global::applicationFileName( "todolist", "todolist.xml" );
00078 }
00079 OTodoAccessXML::~OTodoAccessXML() {
00080 
00081 }
00082 bool OTodoAccessXML::load() {
00083     rec = 0;
00084     m_opened = true;
00085     m_changed = false;
00086     /* initialize dict */
00087     /*
00088      * UPDATE dict if you change anything!!!
00089      */
00090     QAsciiDict<int> dict(26);
00091     dict.setAutoDelete( TRUE );
00092     dict.insert("Categories" ,     new int(OTodo::Category)         );
00093     dict.insert("Uid" ,            new int(OTodo::Uid)              );
00094     dict.insert("HasDate" ,        new int(OTodo::HasDate)          );
00095     dict.insert("Completed" ,      new int(OTodo::Completed)        );
00096     dict.insert("Description" ,    new int(OTodo::Description)      );
00097     dict.insert("Summary" ,        new int(OTodo::Summary)          );
00098     dict.insert("Priority" ,       new int(OTodo::Priority)         );
00099     dict.insert("DateDay" ,        new int(OTodo::DateDay)          );
00100     dict.insert("DateMonth" ,      new int(OTodo::DateMonth)        );
00101     dict.insert("DateYear" ,       new int(OTodo::DateYear)         );
00102     dict.insert("Progress" ,       new int(OTodo::Progress)         );
00103     dict.insert("CompletedDate",   new int(OTodo::CompletedDate)    );
00104     dict.insert("StartDate",       new int(OTodo::StartDate)        );
00105     dict.insert("CrossReference",  new int(OTodo::CrossReference)   );
00106     dict.insert("State",           new int(OTodo::State)            );
00107     dict.insert("Alarms",          new int(OTodo::Alarms)           );
00108     dict.insert("Reminders",       new int(OTodo::Reminders)        );
00109     dict.insert("Notifiers",       new int(OTodo::Notifiers)        );
00110     dict.insert("Maintainer",      new int(OTodo::Maintainer)       );
00111     dict.insert("rtype",           new int(FRType)                  );
00112     dict.insert("rweekdays",       new int(FRWeekdays)              );
00113     dict.insert("rposition",       new int(FRPosition)              );
00114     dict.insert("rfreq",           new int(FRFreq)                  );
00115     dict.insert("start",           new int(FRStart)                 );
00116     dict.insert("rhasenddate",     new int(FRHasEndDate)            );
00117     dict.insert("enddt",           new int(FREndDate)               );
00118 
00119     // here the custom XML parser from TT it's GPL
00120     // but we want to push OpiePIM... to TT.....
00121     // mmap part from zecke :)
00122     int fd = ::open( QFile::encodeName(m_file).data(), O_RDONLY );
00123     struct stat attribut;
00124     if ( fd < 0 ) return false;
00125 
00126     if ( fstat(fd, &attribut ) == -1 ) {
00127         ::close( fd );
00128         return false;
00129     }
00130     void* map_addr = ::mmap(NULL,  attribut.st_size, PROT_READ, MAP_SHARED, fd, 0 );
00131     if ( map_addr == ( (caddr_t)-1) ) {
00132         ::close(fd );
00133         return false;
00134     }
00135     /* advise the kernel who we want to read it */
00136     ::madvise( map_addr,  attribut.st_size,  MADV_SEQUENTIAL );
00137     /* we do not the file any more */
00138     ::close( fd );
00139 
00140     char* dt = (char*)map_addr;
00141     int len = attribut.st_size;
00142     int i = 0;
00143     char *point;
00144     const char* collectionString = "<Task ";
00145     int strLen = strlen(collectionString);
00146     while ( ( point = strstrlen( dt+i, len -i, collectionString, strLen ) ) != 0l ) {
00147         i = point -dt;
00148         i+= strLen;
00149         qWarning("Found a start at %d %d", i,  (point-dt) );
00150 
00151         OTodo ev;
00152         m_year = m_month = m_day = 0;
00153 
00154         while ( TRUE ) {
00155             while ( i < len && (dt[i] == ' ' || dt[i] == '\n' || dt[i] == '\r') )
00156         ++i;
00157         if ( i >= len-2 || (dt[i] == '/' && dt[i+1] == '>') )
00158         break;
00159 
00160         // we have another attribute, read it.
00161         int j = i;
00162         while ( j < len && dt[j] != '=' )
00163         ++j;
00164         QCString attr( dt+i, j-i+1);
00165 
00166         i = ++j; // skip =
00167 
00168         // find the start of quotes
00169         while ( i < len && dt[i] != '"' )
00170         ++i;
00171         j = ++i;
00172 
00173         bool haveUtf = FALSE;
00174         bool haveEnt = FALSE;
00175         while ( j < len && dt[j] != '"' ) {
00176         if ( ((unsigned char)dt[j]) > 0x7f )
00177             haveUtf = TRUE;
00178         if ( dt[j] == '&' )
00179             haveEnt = TRUE;
00180         ++j;
00181         }
00182         if ( i == j ) {
00183         // empty value
00184         i = j + 1;
00185         continue;
00186         }
00187 
00188         QCString value( dt+i, j-i+1 );
00189         i = j + 1;
00190 
00191         QString str = (haveUtf ? QString::fromUtf8( value )
00192             : QString::fromLatin1( value ) );
00193         if ( haveEnt )
00194         str = Qtopia::plainString( str );
00195 
00196             /*
00197              * add key + value
00198              */
00199             todo( &dict, ev, attr, str );
00200 
00201         }
00202         /*
00203          * now add it
00204          */
00205         qWarning("End at %d", i );
00206         if (m_events.contains( ev.uid() ) || ev.uid() == 0) {
00207             ev.setUid( 1 );
00208             m_changed = true;
00209         }
00210         if ( ev.hasDueDate() ) {
00211             ev.setDueDate( QDate(m_year, m_month, m_day) );
00212         }
00213         if ( rec && rec->doesRecur() ) {
00214             OTimeZone utc = OTimeZone::utc();
00215             ORecur recu( *rec ); // call copy c'tor
00216             recu.setEndDate( utc.fromUTCDateTime( rp_end ).date() );
00217             recu.setStart( ev.dueDate() );
00218             ev.setRecurrence( recu );
00219         }
00220         m_events.insert(ev.uid(), ev );
00221         m_year = m_month = m_day = -1;
00222         delete rec;
00223         rec = 0;
00224     }
00225 
00226     munmap(map_addr, attribut.st_size );
00227 
00228     qWarning("counts %d records loaded!", m_events.count() );
00229     return true;
00230 }
00231 bool OTodoAccessXML::reload() {
00232     m_events.clear();
00233     return load();
00234 }
00235 bool OTodoAccessXML::save() {
00236 //    qWarning("saving");
00237     if (!m_opened || !m_changed ) {
00238 //        qWarning("not saving");
00239         return true;
00240     }
00241     QString strNewFile = m_file + ".new";
00242     QFile f( strNewFile );
00243     if (!f.open( IO_WriteOnly|IO_Raw ) )
00244         return false;
00245 
00246     int written;
00247     QString out;
00248     out = "<!DOCTYPE Tasks>\n<Tasks>\n";
00249 
00250     // for all todos
00251     QMap<int, OTodo>::Iterator it;
00252     for (it = m_events.begin(); it != m_events.end(); ++it ) {
00253         out+= "<Task " + toString( (*it) ) + " />\n";
00254         QCString cstr = out.utf8();
00255         written = f.writeBlock( cstr.data(),  cstr.length() );
00256 
00257         /* less written then we wanted */
00258         if ( written != (int)cstr.length() ) {
00259             f.close();
00260             QFile::remove( strNewFile );
00261             return false;
00262         }
00263         out = QString::null;
00264     }
00265 
00266     out +=  "</Tasks>";
00267     QCString cstr = out.utf8();
00268     written = f.writeBlock( cstr.data(), cstr.length() );
00269 
00270     if ( written != (int)cstr.length() ) {
00271         f.close();
00272         QFile::remove( strNewFile );
00273         return false;
00274     }
00275     /* flush before renaming */
00276     f.close();
00277 
00278     if( ::rename( strNewFile.latin1(),  m_file.latin1() ) < 0 ) {
00279 //        qWarning("error renaming");
00280         QFile::remove( strNewFile );
00281     }
00282 
00283     m_changed = false;
00284     return true;
00285 }
00286 QArray<int> OTodoAccessXML::allRecords()const {
00287     QArray<int> ids( m_events.count() );
00288     QMap<int, OTodo>::ConstIterator it;
00289     int i = 0;
00290 
00291     for ( it = m_events.begin(); it != m_events.end(); ++it ) {
00292         ids[i] = it.key();
00293         i++;
00294     }
00295     return ids;
00296 }
00297 QArray<int> OTodoAccessXML::queryByExample( const OTodo&, int, const QDateTime& ) {
00298     QArray<int> ids(0);
00299     return ids;
00300 }
00301 OTodo OTodoAccessXML::find( int uid )const {
00302     OTodo todo;
00303     todo.setUid( 0 ); // isEmpty()
00304     QMap<int, OTodo>::ConstIterator it = m_events.find( uid );
00305     if ( it != m_events.end() )
00306         todo = it.data();
00307 
00308     return todo;
00309 }
00310 void OTodoAccessXML::clear() {
00311     if (m_opened )
00312         m_changed = true;
00313 
00314     m_events.clear();
00315 }
00316 bool OTodoAccessXML::add( const OTodo& todo ) {
00317 //    qWarning("add");
00318     m_changed = true;
00319     m_events.insert( todo.uid(), todo );
00320 
00321     return true;
00322 }
00323 bool OTodoAccessXML::remove( int uid ) {
00324     m_changed = true;
00325     m_events.remove( uid );
00326 
00327     return true;
00328 }
00329 bool OTodoAccessXML::replace( const OTodo& todo) {
00330     m_changed = true;
00331     m_events.replace( todo.uid(), todo );
00332 
00333     return true;
00334 }
00335 QArray<int> OTodoAccessXML::effectiveToDos( const QDate& start,
00336                                             const QDate& end,
00337                                             bool includeNoDates ) {
00338     QArray<int> ids( m_events.count() );
00339     QMap<int, OTodo>::Iterator it;
00340 
00341     int i = 0;
00342     for ( it = m_events.begin(); it != m_events.end(); ++it ) {
00343         if ( !it.data().hasDueDate() ) {
00344             if ( includeNoDates ) {
00345                 ids[i] = it.key();
00346                 i++;
00347             }
00348         }else if ( it.data().dueDate() >= start &&
00349                    it.data().dueDate() <= end ) {
00350             ids[i] = it.key();
00351             i++;
00352         }
00353     }
00354     ids.resize( i );
00355     return ids;
00356 }
00357 QArray<int> OTodoAccessXML::overDue() {
00358     QArray<int> ids( m_events.count() );
00359     int i = 0;
00360 
00361     QMap<int, OTodo>::Iterator it;
00362     for ( it = m_events.begin(); it != m_events.end(); ++it ) {
00363         if ( it.data().isOverdue() ) {
00364             ids[i] = it.key();
00365             i++;
00366         }
00367     }
00368     ids.resize( i );
00369     return ids;
00370 }
00371 
00372 
00373 /* private */
00374 void OTodoAccessXML::todo( QAsciiDict<int>* dict, OTodo& ev,
00375                             const QCString& attr, const QString& val) {
00376 //    qWarning("parse to do from XMLElement" );
00377 
00378     int *find=0;
00379 
00380     find = (*dict)[ attr.data() ];
00381     if (!find ) {
00382 //            qWarning("Unknown option" + it.key() );
00383         ev.setCustomField( attr, val );
00384         return;
00385     }
00386 
00387     switch( *find ) {
00388     case OTodo::Uid:
00389         ev.setUid( val.toInt() );
00390         break;
00391     case OTodo::Category:
00392         ev.setCategories( ev.idsFromString( val ) );
00393         break;
00394     case OTodo::HasDate:
00395         ev.setHasDueDate( val.toInt() );
00396         break;
00397     case OTodo::Completed:
00398         ev.setCompleted( val.toInt() );
00399         break;
00400     case OTodo::Description:
00401         ev.setDescription( val );
00402         break;
00403     case OTodo::Summary:
00404         ev.setSummary( val );
00405         break;
00406     case OTodo::Priority:
00407         ev.setPriority( val.toInt() );
00408         break;
00409     case OTodo::DateDay:
00410         m_day = val.toInt();
00411         break;
00412     case OTodo::DateMonth:
00413         m_month = val.toInt();
00414         break;
00415     case OTodo::DateYear:
00416         m_year = val.toInt();
00417         break;
00418     case OTodo::Progress:
00419         ev.setProgress( val.toInt() );
00420         break;
00421     case OTodo::CompletedDate:
00422         ev.setCompletedDate( OConversion::dateFromString( val ) );
00423         break;
00424     case OTodo::StartDate:
00425         ev.setStartDate( OConversion::dateFromString( val ) );
00426         break;
00427     case OTodo::State:
00428         ev.setState( val.toInt() );
00429         break;
00430     case OTodo::Alarms:{
00431         OPimNotifyManager &manager = ev.notifiers();
00432         QStringList als = QStringList::split(";", val );
00433         for (QStringList::Iterator it = als.begin(); it != als.end(); ++it ) {
00434             QStringList alarm = QStringList::split(":", (*it), TRUE ); // allow empty
00435             qWarning("alarm: %s", alarm.join("___").latin1() );
00436             qWarning("alarm[0]: %s %s", alarm[0].latin1(), OConversion::dateTimeFromString( alarm[0] ).toString().latin1() );
00437             OPimAlarm al( alarm[2].toInt(), OConversion::dateTimeFromString( alarm[0] ), alarm[1].toInt() );
00438             manager.add( al );
00439         }
00440     }
00441         break;
00442     case OTodo::Reminders:{
00443         OPimNotifyManager &manager = ev.notifiers();
00444         QStringList rems = QStringList::split(";", val );
00445         for (QStringList::Iterator it = rems.begin(); it != rems.end(); ++it ) {
00446             OPimReminder rem( (*it).toInt() );
00447             manager.add( rem );
00448         }
00449     }
00450         break;
00451     case OTodo::CrossReference:
00452     {
00453         /*
00454          * A cross refernce looks like
00455          * appname,id;appname,id
00456          * we need to split it up
00457          */
00458         QStringList  refs = QStringList::split(';', val );
00459         QStringList::Iterator strIt;
00460         for (strIt = refs.begin(); strIt != refs.end(); ++strIt ) {
00461             int pos = (*strIt).find(',');
00462             if ( pos > -1 )
00463                 ; // ev.addRelation( (*strIt).left(pos),  (*strIt).mid(pos+1).toInt() );
00464 
00465         }
00466         break;
00467     }
00468     /* Recurrence stuff below + post processing later */
00469     case FRType:
00470         if ( val == "Daily" )
00471             recur()->setType( ORecur::Daily );
00472         else if ( val == "Weekly" )
00473             recur()->setType( ORecur::Weekly);
00474         else if ( val == "MonthlyDay" )
00475             recur()->setType( ORecur::MonthlyDay );
00476         else if ( val == "MonthlyDate" )
00477             recur()->setType( ORecur::MonthlyDate );
00478         else if ( val == "Yearly" )
00479             recur()->setType( ORecur::Yearly );
00480         else
00481             recur()->setType( ORecur::NoRepeat );
00482         break;
00483     case FRWeekdays:
00484         recur()->setDays( val.toInt() );
00485         break;
00486     case FRPosition:
00487         recur()->setPosition( val.toInt() );
00488         break;
00489     case FRFreq:
00490         recur()->setFrequency( val.toInt() );
00491         break;
00492     case FRHasEndDate:
00493         recur()->setHasEndDate( val.toInt() );
00494         break;
00495     case FREndDate: {
00496         rp_end = (time_t) val.toLong();
00497         break;
00498     }
00499     default:
00500         ev.setCustomField( attr, val );
00501         break;
00502     }
00503 }
00504 
00505 // from PalmtopRecord... GPL ### FIXME
00506 namespace {
00507 QString customToXml(const QMap<QString, QString>& customMap )
00508 {
00509     //qWarning(QString("writing custom %1").arg(customMap.count()));
00510     QString buf(" ");
00511     for ( QMap<QString, QString>::ConstIterator cit = customMap.begin();
00512         cit != customMap.end(); ++cit) {
00513 //  qWarning(".ITEM.");
00514     buf += cit.key();
00515     buf += "=\"";
00516     buf += Qtopia::escapeString(cit.data());
00517     buf += "\" ";
00518     }
00519     return buf;
00520 }
00521 
00522 
00523 }
00524 
00525 QString OTodoAccessXML::toString( const OTodo& ev )const {
00526     QString str;
00527 
00528     str += "Completed=\"" + QString::number( ev.isCompleted() ) + "\" ";
00529     str += "HasDate=\"" + QString::number( ev.hasDueDate() ) + "\" ";
00530     str += "Priority=\"" + QString::number( ev.priority() ) + "\" ";
00531     str += "Progress=\"" + QString::number(ev.progress() ) + "\" ";
00532 
00533     str += "Categories=\"" + toString( ev.categories() ) + "\" ";
00534     str += "Description=\"" + Qtopia::escapeString( ev.description() ) + "\" ";
00535     str += "Summary=\"" + Qtopia::escapeString( ev.summary() ) + "\" ";
00536 
00537     if ( ev.hasDueDate() ) {
00538         str += "DateYear=\"" + QString::number( ev.dueDate().year() ) + "\" ";
00539         str += "DateMonth=\"" + QString::number( ev.dueDate().month() ) + "\" ";
00540         str += "DateDay=\"" + QString::number( ev.dueDate().day() ) + "\" ";
00541     }
00542 //    qWarning( "Uid %d",  ev.uid() );
00543     str += "Uid=\"" + QString::number( ev.uid() ) + "\" ";
00544 
00545 // append the extra options
00546     /* FIXME Qtopia::Record this is currently not
00547      * possible you can set custom fields
00548      * but don' iterate over the list
00549      * I may do #define private protected
00550      * for this case - cough  --zecke
00551      */
00552     /*
00553     QMap<QString, QString> extras = ev.extras();
00554     QMap<QString, QString>::Iterator extIt;
00555     for (extIt = extras.begin(); extIt != extras.end(); ++extIt )
00556         str += extIt.key() + "=\"" +  extIt.data() + "\" ";
00557     */
00558     // cross refernce
00559     if ( ev.hasRecurrence() ) {
00560         str += ev.recurrence().toString();
00561     }
00562     if ( ev.hasStartDate() )
00563         str += "StartDate=\""+ OConversion::dateToString( ev.startDate() ) +"\" ";
00564     if ( ev.hasCompletedDate() )
00565         str += "CompletedDate=\""+ OConversion::dateToString( ev.completedDate() ) +"\" ";
00566     if ( ev.hasState() )
00567         str += "State=\""+QString::number( ev.state().state() )+"\" ";
00568 
00569     /*
00570      * save reminders and notifiers!
00571      * DATE_TIME:DURATION:SOUND:NOT_USED_YET;OTHER_DATE_TIME:OTHER_DURATION:SOUND:....
00572      */
00573     if ( ev.hasNotifiers() ) {
00574         OPimNotifyManager manager = ev.notifiers();
00575         OPimNotifyManager::Alarms alarms = manager.alarms();
00576         if (!alarms.isEmpty() ) {
00577             QStringList als;
00578             OPimNotifyManager::Alarms::Iterator it = alarms.begin();
00579             for ( ; it != alarms.end(); ++it ) {
00580                 /* only if time is valid */
00581                 if ( (*it).dateTime().isValid() ) {
00582                     als << OConversion::dateTimeToString( (*it).dateTime() )
00583                         + ":" + QString::number( (*it).duration() )
00584                         + ":" + QString::number( (*it).sound() )
00585                         + ":";
00586                 }
00587             }
00588             // now write the list
00589             qWarning("als: %s", als.join("____________").latin1() );
00590             str += "Alarms=\""+als.join(";") +"\" ";
00591         }
00592 
00593         /*
00594          * now the same for reminders but more easy. We just save the uid of the OEvent.
00595          */
00596         OPimNotifyManager::Reminders reminders = manager.reminders();
00597         if (!reminders.isEmpty() ) {
00598             OPimNotifyManager::Reminders::Iterator it = reminders.begin();
00599             QStringList records;
00600             for ( ; it != reminders.end(); ++it ) {
00601                 records << QString::number( (*it).recordUid() );
00602             }
00603             str += "Reminders=\""+ records.join(";") +"\" ";
00604         }
00605     }
00606     str += customToXml( ev.toExtraMap() );
00607 
00608 
00609     return str;
00610 }
00611 QString OTodoAccessXML::toString( const QArray<int>& ints ) const {
00612     return Qtopia::Record::idsToString( ints );
00613 }
00614 
00615 /* internal class for sorting
00616  *
00617  * Inspired by todoxmlio.cpp from TT
00618  */
00619 
00620 struct OTodoXMLContainer {
00621     OTodo todo;
00622 };
00623 
00624 namespace {
00625     inline QString string( const OTodo& todo) {
00626         return  todo.summary().isEmpty() ?
00627             todo.description().left(20 ) :
00628             todo.summary();
00629     }
00630     inline int completed( const OTodo& todo1, const OTodo& todo2) {
00631         int ret = 0;
00632         if ( todo1.isCompleted() ) ret++;
00633         if ( todo2.isCompleted() ) ret--;
00634         return ret;
00635     }
00636     inline int priority( const OTodo& t1, const OTodo& t2) {
00637         return ( t1.priority() - t2.priority() );
00638     }
00639     inline int description( const OTodo& t1, const OTodo& t2) {
00640         return QString::compare( string(t1), string(t2) );
00641     }
00642     inline int deadline( const OTodo& t1, const OTodo& t2) {
00643         int ret = 0;
00644         if ( t1.hasDueDate() &&
00645              t2.hasDueDate() )
00646             ret = t2.dueDate().daysTo( t1.dueDate() );
00647         else if ( t1.hasDueDate() )
00648             ret = -1;
00649         else if ( t2.hasDueDate() )
00650             ret = 1;
00651         else
00652             ret = 0;
00653 
00654         return ret;
00655     }
00656 
00657 };
00658 
00659 /*
00660    * Returns:
00661    *       0 if item1 == item2
00662    *
00663    *   non-zero if item1 != item2
00664    *
00665    *   This function returns int rather than bool so that reimplementations
00666    *   can return one of three values and use it to sort by:
00667    *
00668    *   0 if item1 == item2
00669    *
00670    *   > 0 (positive integer) if item1 > item2
00671    *
00672    *   < 0 (negative integer) if item1 < item2
00673    *
00674    */
00675 class OTodoXMLVector : public QVector<OTodoXMLContainer> {
00676 public:
00677     OTodoXMLVector(int size, bool asc,  int sort)
00678         : QVector<OTodoXMLContainer>( size )
00679         {
00680             setAutoDelete( true );
00681             m_asc = asc;
00682             m_sort = sort;
00683         }
00684         /* return the summary/description */
00685     QString string( const OTodo& todo) {
00686         return  todo.summary().isEmpty() ?
00687             todo.description().left(20 ) :
00688             todo.summary();
00689     }
00694     int compareItems( Item d1, Item d2 ) {
00695         bool seComp, sePrio, seDesc, seDeadline;
00696         seComp = sePrio = seDeadline = seDesc = false;
00697         int ret =0;
00698         OTodoXMLContainer* con1 = (OTodoXMLContainer*)d1;
00699         OTodoXMLContainer* con2 = (OTodoXMLContainer*)d2;
00700 
00701         /* same item */
00702         if ( con1->todo.uid() == con2->todo.uid() )
00703             return 0;
00704 
00705         switch ( m_sort ) {
00706             /* completed */
00707         case 0: {
00708             ret = completed( con1->todo, con2->todo );
00709             seComp = TRUE;
00710             break;
00711         }
00712             /* priority */
00713         case 1: {
00714             ret = priority( con1->todo, con2->todo );
00715             sePrio = TRUE;
00716             break;
00717         }
00718             /* description */
00719         case 2: {
00720             ret  = description( con1->todo, con2->todo );
00721             seDesc = TRUE;
00722             break;
00723         }
00724             /* deadline */
00725         case 3: {
00726             ret = deadline( con1->todo, con2->todo );
00727             seDeadline = TRUE;
00728             break;
00729         }
00730         default:
00731             ret = 0;
00732             break;
00733         };
00734         /*
00735          * FIXME do better sorting if the first sort criteria
00736          * ret equals 0 start with complete and so on...
00737          */
00738 
00739         /* twist it we're not ascending*/
00740         if (!m_asc)
00741             ret = ret * -1;
00742 
00743         if ( ret )
00744             return ret;
00745 
00746         // default did not gave difference let's try it other way around
00747         /*
00748          * General try if already checked if not test
00749          * and return
00750          * 1.Completed
00751          * 2.Priority
00752          * 3.Description
00753          * 4.DueDate
00754          */
00755         if (!seComp ) {
00756             if ( (ret = completed( con1->todo, con2->todo ) ) ) {
00757                 if (!m_asc ) ret *= -1;
00758                 return ret;
00759             }
00760         }
00761         if (!sePrio ) {
00762             if ( (ret = priority( con1->todo, con2->todo ) ) ) {
00763                 if (!m_asc ) ret *= -1;
00764                 return ret;
00765             }
00766         }
00767         if (!seDesc ) {
00768             if ( (ret = description(con1->todo, con2->todo ) ) ) {
00769                 if (!m_asc) ret *= -1;
00770                 return ret;
00771             }
00772         }
00773         if (!seDeadline) {
00774             if ( (ret = deadline( con1->todo, con2->todo ) ) ) {
00775                 if (!m_asc) ret *= -1;
00776                 return ret;
00777             }
00778         }
00779 
00780         return 0;
00781     }
00782  private:
00783     bool m_asc;
00784     int m_sort;
00785 
00786 };
00787 
00788 QArray<int> OTodoAccessXML::sorted( bool asc,  int sortOrder,
00789                                     int sortFilter,  int cat ) {
00790     OTodoXMLVector vector(m_events.count(), asc,sortOrder );
00791     QMap<int, OTodo>::Iterator it;
00792     int item = 0;
00793 
00794     bool bCat = sortFilter & 1 ? true : false;
00795     bool bOnly = sortFilter & 2 ? true : false;
00796     bool comp = sortFilter & 4 ? true : false;
00797     for ( it = m_events.begin(); it != m_events.end(); ++it ) {
00798 
00799         /* show category */
00800         /* -1 == unfiled */
00801         if ( bCat && cat == -1 ) {
00802             if(!(*it).categories().isEmpty() )
00803                 continue;
00804         }else if ( bCat && cat != 0)
00805             if (!(*it).categories().contains( cat ) ) {
00806                 continue;
00807             }
00808         /* isOverdue but we should not show overdue - why?*/
00809 /*        if ( (*it).isOverdue() &&  !bOnly  ) {
00810             qWarning("item is overdue but !bOnly");
00811             continue;
00812         }
00813 */
00814         if ( !(*it).isOverdue() && bOnly ) {
00815             continue;
00816         }
00817 
00818         if ((*it).isCompleted() && comp ) {
00819             continue;
00820         }
00821 
00822 
00823         OTodoXMLContainer* con = new OTodoXMLContainer();
00824         con->todo = (*it);
00825         vector.insert(item, con );
00826         item++;
00827     }
00828     vector.resize( item );
00829     /* sort it now */
00830     vector.sort();
00831     /* now get the uids */
00832     QArray<int> array( vector.count() );
00833     for (uint i= 0; i < vector.count(); i++ ) {
00834         array[i] = ( vector.at(i) )->todo.uid();
00835     }
00836     return array;
00837 };
00838 void OTodoAccessXML::removeAllCompleted() {
00839     QMap<int, OTodo> events = m_events;
00840     for ( QMap<int, OTodo>::Iterator it = m_events.begin(); it != m_events.end(); ++it ) {
00841         if ( (*it).isCompleted() )
00842             events.remove( it.key() );
00843     }
00844     m_events = events;
00845 }
00846 QBitArray OTodoAccessXML::supports()const {
00847     static QBitArray ar = sup();
00848     return ar;
00849 }
00850 QBitArray OTodoAccessXML::sup() {
00851     QBitArray ar( OTodo::CompletedDate +1 );
00852     ar.fill( true );
00853     ar[OTodo::CrossReference] = false;
00854     ar[OTodo::State ] = false;
00855     ar[OTodo::Reminders] = false;
00856     ar[OTodo::Notifiers] = false;
00857     ar[OTodo::Maintainer] = false;
00858 
00859     return ar;
00860 }
00861 QArray<int> OTodoAccessXML::matchRegexp(  const QRegExp &r ) const
00862 {
00863     QArray<int> m_currentQuery( m_events.count() );
00864     uint arraycounter = 0;
00865 
00866         QMap<int, OTodo>::ConstIterator it;
00867         for (it = m_events.begin(); it != m_events.end(); ++it ) {
00868         if ( it.data().match( r ) )
00869             m_currentQuery[arraycounter++] = it.data().uid();
00870 
00871     }
00872     // Shrink to fit..
00873     m_currentQuery.resize(arraycounter);
00874 
00875     return m_currentQuery;
00876 }
KDE Logo
This file is part of the documentation for OPIE Version 1.1.
Documentation copyright © 1997-2003 the KDE developers. 2003 OPIE developers
Generated on Tue Feb 10 20:25:22 2004 by doxygen 1.3.5 written by Dimitri van Heesch, © 1997-2001