summaryrefslogtreecommitdiff
path: root/libopie2/opiepim/backend/otodoaccessxml.cpp
Side-by-side diff
Diffstat (limited to 'libopie2/opiepim/backend/otodoaccessxml.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--libopie2/opiepim/backend/otodoaccessxml.cpp145
1 files changed, 145 insertions, 0 deletions
diff --git a/libopie2/opiepim/backend/otodoaccessxml.cpp b/libopie2/opiepim/backend/otodoaccessxml.cpp
index 5fe733c..692483e 100644
--- a/libopie2/opiepim/backend/otodoaccessxml.cpp
+++ b/libopie2/opiepim/backend/otodoaccessxml.cpp
@@ -1,366 +1,511 @@
#include <qfile.h>
+#include <qvector.h>
#include <qpe/global.h>
#include <qpe/stringutil.h>
#include <qpe/timeconversion.h>
#include <opie/xmltree.h>
#include "otodoaccessxml.h"
OTodoAccessXML::OTodoAccessXML( const QString& appName,
const QString& fileName )
: OTodoAccessBackend(), m_app( appName ), m_opened( false ), m_changed( false )
{
if (!fileName.isEmpty() )
m_file = fileName;
else
m_file = Global::applicationFileName( "todolist", "todolist.xml" );
}
OTodoAccessXML::~OTodoAccessXML() {
}
bool OTodoAccessXML::load() {
m_opened = true;
m_changed = false;
/* initialize dict */
/*
* UPDATE dict if you change anything!!!
*/
QAsciiDict<int> dict(15);
dict.setAutoDelete( TRUE );
dict.insert("Categories" , new int(OTodo::Category) );
dict.insert("Uid" , new int(OTodo::Uid) );
dict.insert("HasDate" , new int(OTodo::HasDate) );
dict.insert("Completed" , new int(OTodo::Completed) );
dict.insert("Description" , new int(OTodo::Description) );
dict.insert("Summary" , new int(OTodo::Summary) );
dict.insert("Priority" , new int(OTodo::Priority) );
dict.insert("DateDay" , new int(OTodo::DateDay) );
dict.insert("DateMonth" , new int(OTodo::DateMonth) );
dict.insert("DateYear" , new int(OTodo::DateYear) );
dict.insert("Progress" , new int(OTodo::Progress) );
dict.insert("Completed", new int(OTodo::Completed) );
dict.insert("CrossReference", new int(OTodo::CrossReference) );
dict.insert("HasAlarmDateTime",new int(OTodo::HasAlarmDateTime) );
dict.insert("AlarmDateTime", new int(OTodo::AlarmDateTime) );
Opie::XMLElement *root = Opie::XMLElement::load( m_file );
int day, year, month;
day = year = month = -1;
/* if opened */
if ( root != 0l ) {
Opie::XMLElement *element = root->firstChild();
if ( element == 0l )
return false;
element = element->firstChild();
while ( element ) {
if ( element->tagName() != QString::fromLatin1("Task") ) {
element = element->nextChild();
continue;
}
/* here is the right element for a task */
OTodo ev = todo( &dict, element );
m_events.insert( ev.uid(), ev );
element = element->nextChild();
}
}else {
// qWarning("could not parse");
return false;;
}
delete root;
// qWarning("Access %d" + m_events.count() );
return true;
}
bool OTodoAccessXML::reload() {
return load();
}
bool OTodoAccessXML::save() {
// qWarning("saving");
if (!m_opened || !m_changed ) {
// qWarning("not saving");
return true;
}
QString strNewFile = m_file + ".new";
QFile f( strNewFile );
if (!f.open( IO_WriteOnly|IO_Raw ) )
return false;
int written;
QString out;
out = "<!DOCTYPE Tasks>\n<Tasks>\n";
// for all todos
QMap<int, OTodo>::Iterator it;
for (it = m_events.begin(); it != m_events.end(); ++it ) {
out+= "<Task " + toString( (*it) ) + " />\n";
QCString cstr = out.utf8();
written = f.writeBlock( cstr.data(), cstr.length() );
/* less written then we wanted */
if ( written != (int)cstr.length() ) {
f.close();
QFile::remove( strNewFile );
return false;
}
out = QString::null;
}
out += "</Tasks>";
QCString cstr = out.utf8();
written = f.writeBlock( cstr.data(), cstr.length() );
if ( written != (int)cstr.length() ) {
f.close();
QFile::remove( strNewFile );
return false;
}
/* flush before renaming */
f.close();
if( ::rename( strNewFile.latin1(), m_file.latin1() ) < 0 ) {
// qWarning("error renaming");
QFile::remove( strNewFile );
}
m_changed = false;
return true;
}
QArray<int> OTodoAccessXML::allRecords()const {
QArray<int> ids( m_events.count() );
QMap<int, OTodo>::ConstIterator it;
int i = 0;
for ( it = m_events.begin(); it != m_events.end(); ++it ) {
ids[i] = it.key();
i++;
}
return ids;
}
QArray<int> OTodoAccessXML::queryByExample( const OTodo&, int sort ) {
QArray<int> ids(0);
return ids;
}
OTodo OTodoAccessXML::find( int uid )const {
OTodo todo;
todo.setUid( 0 ); // isEmpty()
QMap<int, OTodo>::ConstIterator it = m_events.find( uid );
if ( it != m_events.end() )
todo = it.data();
return todo;
}
void OTodoAccessXML::clear() {
if (m_opened )
m_changed = true;
m_events.clear();
}
bool OTodoAccessXML::add( const OTodo& todo ) {
// qWarning("add");
m_changed = true;
m_events.insert( todo.uid(), todo );
return true;
}
bool OTodoAccessXML::remove( int uid ) {
m_changed = true;
m_events.remove( uid );
return true;
}
bool OTodoAccessXML::replace( const OTodo& todo) {
m_changed = true;
m_events.replace( todo.uid(), todo );
return true;
}
QArray<int> OTodoAccessXML::effectiveToDos( const QDate& start,
const QDate& end,
bool includeNoDates ) {
QArray<int> ids( m_events.count() );
QMap<int, OTodo>::Iterator it;
int i = 0;
for ( it = m_events.begin(); it != m_events.end(); ++it ) {
if ( !it.data().hasDueDate() ) {
if ( includeNoDates ) {
ids[i] = it.key();
i++;
}
}else if ( it.data().dueDate() >= start &&
it.data().dueDate() <= end ) {
ids[i] = it.key();
i++;
}
}
ids.resize( i );
return ids;
}
QArray<int> OTodoAccessXML::overDue() {
QArray<int> ids( m_events.count() );
int i = 0;
QMap<int, OTodo>::Iterator it;
for ( it = m_events.begin(); it != m_events.end(); ++it ) {
if ( it.data().isOverdue() ) {
ids[i] = it.key();
i++;
}
}
ids.resize( i );
return ids;
}
/* private */
OTodo OTodoAccessXML::todo( QAsciiDict<int>* dict, Opie::XMLElement* element)const {
// qWarning("parse to do from XMLElement" );
OTodo ev;
QMap<QString, QString> attributes = element->attributes();
QMap<QString, QString>::Iterator it;
int *find=0;
int day, month, year;
day = month = year = -1;
for ( it = attributes.begin(); it != attributes.end(); ++it ) {
find = (*dict)[ it.key() ];
if (!find ) {
// qWarning("Unknown option" + it.key() );
ev.setCustomField( it.key(), it.data() );
continue;
}
switch( *find ) {
case OTodo::Uid:
ev.setUid( it.data().toInt() );
break;
case OTodo::Category:
ev.setCategories( ev.idsFromString( it.data() ) );
break;
case OTodo::HasDate:
ev.setHasDueDate( it.data().toInt() );
break;
case OTodo::Completed:
ev.setCompleted( it.data().toInt() );
break;
case OTodo::Description:
ev.setDescription( it.data() );
break;
case OTodo::Summary:
ev.setSummary( it.data() );
break;
case OTodo::Priority:
+ qWarning("ParsePriority " + it.data() );
ev.setPriority( it.data().toInt() );
break;
case OTodo::DateDay:
day = it.data().toInt();
break;
case OTodo::DateMonth:
month = it.data().toInt();
break;
case OTodo::DateYear:
year = it.data().toInt();
break;
case OTodo::Progress:
ev.setProgress( it.data().toInt() );
break;
case OTodo::CrossReference:
{
/*
* A cross refernce looks like
* appname,id;appname,id
* we need to split it up
*/
QStringList refs = QStringList::split(';', it.data() );
QStringList::Iterator strIt;
for (strIt = refs.begin(); strIt != refs.end(); ++strIt ) {
int pos = (*strIt).find(',');
if ( pos > -1 )
ev.addRelation( (*strIt).left(pos), (*strIt).mid(pos+1).toInt() );
}
break;
}
case OTodo::HasAlarmDateTime:
ev.setHasAlarmDateTime( it.data().toInt() );
break;
case OTodo::AlarmDateTime: {
/* this sounds better ;) zecke */
ev.setAlarmDateTime( TimeConversion::fromISO8601( it.data().local8Bit() ) );
break;
}
default:
break;
}
}
if ( ev.hasDueDate() ) {
QDate date( year, month, day );
ev.setDueDate( date );
}
return ev;
}
QString OTodoAccessXML::toString( const OTodo& ev )const {
QString str;
str += "Completed=\"" + QString::number( ev.isCompleted() ) + "\" ";
str += "HasDate=\"" + QString::number( ev.hasDueDate() ) + "\" ";
str += "Priority=\"" + QString::number( ev.priority() ) + "\" ";
str += "Progress=\"" + QString::number(ev.progress() ) + "\" ";
str += "Categories=\"" + toString( ev.categories() ) + "\" ";
str += "Description=\"" + Qtopia::escapeString( ev.description() ) + "\" ";
str += "Summary=\"" + Qtopia::escapeString( ev.summary() ) + "\" ";
if ( ev.hasDueDate() ) {
str += "DateYear=\"" + QString::number( ev.dueDate().year() ) + "\" ";
str += "DateMonth=\"" + QString::number( ev.dueDate().month() ) + "\" ";
str += "DateDay=\"" + QString::number( ev.dueDate().day() ) + "\" ";
}
// qWarning( "Uid %d", ev.uid() );
str += "Uid=\"" + QString::number( ev.uid() ) + "\" ";
// append the extra options
/* FIXME Qtopia::Record this is currently not
* possible you can set custom fields
* but don' iterate over the list
* I may do #define private protected
* for this case - cough --zecke
*/
/*
QMap<QString, QString> extras = ev.extras();
QMap<QString, QString>::Iterator extIt;
for (extIt = extras.begin(); extIt != extras.end(); ++extIt )
str += extIt.key() + "=\"" + extIt.data() + "\" ";
*/
// cross refernce
QStringList list = ev.relatedApps();
QStringList::Iterator listIt;
QString refs;
str += "CrossReference=\"";
bool added = false;
for ( listIt = list.begin(); listIt != list.end(); ++listIt ) {
added = true;
QArray<int> ints = ev.relations( (*listIt) );
for ( uint i = 0; i< ints.count(); i++ ) {
str += (*listIt) + "," + QString::number( i ) + ";";
}
}
if ( added )
str = str.remove( str.length()-1, 1 );
str += "\" ";
str += "AlarmDateTime=\"" + TimeConversion::toISO8601( ev.alarmDateTime() ) + "\" ";
return str;
}
QString OTodoAccessXML::toString( const QArray<int>& ints ) const {
return Qtopia::Record::idsToString( ints );
}
+
+/* internal class for sorting */
+
+struct OTodoXMLContainer {
+ OTodo todo;
+};
+ /*
+ * Returns:
+ * 0 if item1 == item2
+ *
+ * non-zero if item1 != item2
+ *
+ * This function returns int rather than bool so that reimplementations
+ * can return one of three values and use it to sort by:
+ *
+ * 0 if item1 == item2
+ *
+ * > 0 (positive integer) if item1 > item2
+ *
+ * < 0 (negative integer) if item1 < item2
+ *
+ */
+class OTodoXMLVector : public QVector<OTodoXMLContainer> {
+public:
+ OTodoXMLVector(int size, bool asc, int sort)
+ : QVector<OTodoXMLContainer>( size )
+ {
+ setAutoDelete( true );
+ m_asc = asc;
+ m_sort = sort;
+ }
+ /* return the summary/description */
+ QString string( const OTodo& todo) {
+ return todo.summary().isEmpty() ?
+ todo.description().left(20 ) :
+ todo.summary();
+ }
+ /**
+ * we take the sortorder( switch on it )
+ *
+ */
+ int compareItems( Item d1, Item d2 ) {
+ qWarning("compare items");
+ int ret =0;
+ OTodoXMLContainer* con1 = (OTodoXMLContainer*)d1;
+ OTodoXMLContainer* con2 = (OTodoXMLContainer*)d2;
+
+ /* same item */
+ if ( con1->todo.uid() == con2->todo.uid() )
+ return 0;
+ qWarning("m_sort %d", m_sort );
+
+ switch ( m_sort ) {
+ /* completed */
+ case 0: {
+ ret = 0;
+ if ( con1->todo.isCompleted() ) ret++;
+ if ( con2->todo.isCompleted() ) ret--;
+ break;
+ }
+ /* priority */
+ case 1: {
+ ret = con1->todo.priority() - con2->todo.priority();
+ qWarning(" priority %d %d %d", ret,
+ con1->todo.priority(),
+ con2->todo.priority()
+ );
+ break;
+ }
+ /* description */
+ case 2: {
+ QString str1 = string( con1->todo );
+ QString str2 = string( con2->todo );
+ ret = QString::compare( str1, str2 );
+ break;
+ }
+ /* deadline */
+ case 3: {
+ /* either bot got a dueDate
+ * or one of them got one
+ */
+ if ( con1->todo.hasDueDate() &&
+ con2->todo.hasDueDate() )
+ ret = con1->todo.dueDate().daysTo( con2->todo.dueDate() );
+ else if ( con1->todo.hasDueDate() )
+ ret = -1;
+ else if ( con2->todo.hasDueDate() )
+ ret = 0;
+ break;
+ }
+ default:
+ ret = 0;
+ break;
+ };
+
+ /* twist it we're not ascending*/
+ if (!m_asc)
+ ret = ret * -1;
+ return ret;
+ }
+ private:
+ bool m_asc;
+ int m_sort;
+
+};
+
+QArray<int> OTodoAccessXML::sorted( bool asc, int sortOrder,
+ int sortFilter, int cat ) {
+ OTodoXMLVector vector(m_events.count(), asc,sortOrder );
+ QMap<int, OTodo>::Iterator it;
+ int item = 0;
+
+ bool bCat = sortFilter & 1 ? true : false;
+ bool bOver = sortFilter & 0 ? true : false;
+ bool bOnly = split & 2 ? true : false;
+ for ( it = m_events.begin(); it != m_events.end(); ++it ) {
+
+ /* show category */
+ if ( bCat )
+ if (!(*it).categories().contains( cat ) )
+ continue;
+ /* isOverdue but we should not show overdue */
+ if ( (*it).isOverdue() && ( !bOver || !bOnly ) )
+ continue;
+ if ( !(*it).isOverdue() && bOnly )
+ continue;
+
+
+ OTodoXMLContainer* con = new OTodoXMLContainer();
+ con->todo = (*it);
+ vector.insert(item, con );
+ item++;
+ }
+ vector.resize( item );
+ /* sort it now */
+ vector.sort();
+ /* now get the uids */
+ QArray<int> array( vector.count() );
+ for (uint i= 0; i < vector.count(); i++ ) {
+ array[i] = ( vector.at(i) )->todo.uid();
+ }
+ return array;
+};