summaryrefslogtreecommitdiffabout
authorzautrix <zautrix>2004-08-09 18:02:44 (UTC)
committer zautrix <zautrix>2004-08-09 18:02:44 (UTC)
commit4f05a9fcbb9e54184aef93883886aaf865104463 (patch) (side-by-side diff)
treef5e94f7694b74dca3b11e1e74a94058a4526dafe
parente1909ade2188e53feee65089d5f2882563876c58 (diff)
downloadkdepimpi-4f05a9fcbb9e54184aef93883886aaf865104463.zip
kdepimpi-4f05a9fcbb9e54184aef93883886aaf865104463.tar.gz
kdepimpi-4f05a9fcbb9e54184aef93883886aaf865104463.tar.bz2
more syncing
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--korganizer/mainwindow.cpp21
-rw-r--r--libkcal/phoneformat.cpp60
-rw-r--r--libkcal/phoneformat.h2
-rw-r--r--libkcal/vcalformat.cpp19
-rw-r--r--libkcal/vcalformat.h2
5 files changed, 52 insertions, 52 deletions
diff --git a/korganizer/mainwindow.cpp b/korganizer/mainwindow.cpp
index cce182a..6c0aa9b 100644
--- a/korganizer/mainwindow.cpp
+++ b/korganizer/mainwindow.cpp
@@ -1008,131 +1008,150 @@ void MainWindow::slotSyncMenu( int action )
} else
syncRemote( temp );
}
}
delete temp;
mBlockSaveFlag = false;
}
void MainWindow::setDefaultPreferences()
{
KOPrefs *p = KOPrefs::instance();
p->mCompactDialogs = true;
p->mConfirm = true;
// p->mEnableQuickTodo = false;
}
QString MainWindow::resourcePath()
{
return KGlobal::iconLoader()->iconPath();
}
void MainWindow::displayText( QString text ,QString cap )
{
QDialog dia( this, "name", true ); ;
dia.setCaption( cap );
QVBoxLayout* lay = new QVBoxLayout( &dia );
lay->setSpacing( 3 );
lay->setMargin( 3 );
QTextBrowser tb ( &dia );
lay->addWidget( &tb );
tb.setText( text );
#ifdef DESKTOP_VERSION
dia.resize( 640, 480);
#else
dia.showMaximized();
#endif
dia.exec();
}
void MainWindow::displayFile( QString fn, QString cap )
{
QString fileName = resourcePath() + fn;
QString text;
QFile file( fileName );
if (!file.open( IO_ReadOnly ) ) {
return ;
}
QTextStream ts( &file );
text = ts.read();
file.close();
displayText( text, cap);
}
void MainWindow::features()
{
displayFile( "featuresKOPI.txt",i18n("KO/Pi Features and hints") );
}
void MainWindow::usertrans()
{
displayFile( "usertranslationHOWTO.txt",i18n("KO/Pi User translation HowTo") );
}
+#if 0
+#include <libkcal/vcalformat.h>
+#include <libkcal/event.h>
+#include <libkcal/todo.h>
+#include <libkcal/incidence.h>
+#endif
void MainWindow::synchowto()
{
-
+#if 0
+ QPtrList<Incidence> er = mCalendar->rawIncidences();
+ Incidence* inR = er.first();
+ VCalFormat vf;
+ QString strout;
+ while ( inR ) {
+ if ( inR->type() == "Todo" )
+ strout = vf.todoToString( (Todo *) inR );
+ if ( inR->type() == "Event" )
+ strout = vf.eventToString( (Event *) inR );
+ qDebug("incidence: \n%s\n ente\n\n",strout.latin1() );
+ inR = er.next();
+ }
+#endif
displayFile( "howtoSYNC.txt",i18n("KO/Pi Synchronization HowTo") );
}
void MainWindow::faq()
{
displayFile( "kopiFAQ.txt",i18n("KO/Pi FAQ") );
}
void MainWindow::whatsNew()
{
displayFile( "kopiWhatsNew.txt",i18n("KO/Pi Version Info") );
}
void MainWindow::licence()
{
KApplication::showLicence();
}
void MainWindow::about()
{
QString version;
#include <../version>
QMessageBox::about( this, i18n("About KOrganizer/Pi"),
i18n("KOrganizer/Platform-independent\n") +
"(KO/Pi) " + version + " - " +
#ifdef DESKTOP_VERSION
i18n("Desktop Edition\n") +
#else
i18n("PDA-Edition\nfor: Zaurus 5x00 / 7x0 / 8x0\n") +
#endif
i18n("(c) 2004 Lutz Rogowski\nEmail:lutz@pi-sync.net\nKO/Pi is based on KOrganizer\n(c) 2002,2003 Cornelius Schumacher\nEmail: schumacher@kde.org\nKOrganizer/Pi is licensed\nunder the GPL.\nKO/Pi can be compiled for\nLinux, Zaurus-PDA and Windows\nwww.korganizer.org\nwww.pi-sync.net\n") );
}
void MainWindow::keyBindings()
{
QString cap = i18n("Key bindings KOrganizer/Pi");
QString text = i18n("<p><h2>KO/Pi key shortcuts:</h2></p>\n") +
i18n("<p><b>H</b>: This help dialog | <b>S</b>: Search dialog</p>\n")+
i18n("<p><b>I</b>: Show info for selected event/todo</p>\n") +
i18n("<p><b>Space</b>: Toggle fullscreen | <b>P</b>: Date picker</p>\n")+
i18n("<p><b>F</b>: Toggle filterview |<b>F+ctrl</b>: Edit filter </p>\n")+
i18n("<p><b>O</b>: Filter On/Off | <b>J</b>: Journal view</p>\n")+
i18n("<p><b>1-0</b> (+<b>ctrl</b>): Select filter 1-10 (11-20)</p>\n")+
i18n("<p><b>N</b>: Next days view| <b>W</b>: What's next view\n ")+
i18n("<p><b>V</b>: Todo view | <b>L</b>: Event list view</p>\n")+
i18n("<p><b>Z,Y</b>: Work week view | <b>U</b>: Week view</p>\n")+
i18n("<p><b>D</b>: One day view | <b>M</b>: Month view</p>\n")+
i18n("<p><b>E</b>: Edit selected item |<b> E+ctrl</b>: New Event</p>\n")+
i18n("<p><b>T</b>: Goto today | <b>T+ctrl</b>: New Todo</p>\n")+
i18n("<p><b>S+ctrl</b>: Add sub-todo | <b>X</b>: Toggle datenavigator</p>\n")+
i18n("<p><b>+,-</b> : Zoom in/out agenda | <b>A</b>: Toggle allday agenda height</p>\n")+
i18n("<p><b>C</b>: Show current time in agenda view</p>\n")+
i18n("<p><b>B</b>: Edit description (details) of selected item</p>\n")+
i18n("<p><b>right</b>: Next week | <b>right+ctrl</b>: Next month</p>\n")+
i18n("<p><b>left</b>: Prev. week | <b>left+ctrl</b>: Prev. month</p>\n")+
i18n("<p><b>del,backspace</b>: Delete selected item</p>\n")+
i18n("<p><h3>In agenda view:</h3></p>\n") +
i18n("<p><b>up/down</b>: Scroll agenda view</p>\n")+
i18n("<p><b>ctrl+up/down</b>: Scroll small todo view</p>\n")+
i18n("<p><h3>In todo view:</h3></p>\n") +
i18n("<p><b>Q</b>: Toggle quick todo line edit.</p>\n")+
i18n("<p><b>I</b>: Show info of current item+one step down.</p>\n")+
i18n("<p><b>return</b>: Mark item as completed+one step down.</p>\n")+
i18n("<p><b>return+shift</b>: Mark item as not completed+one step down</p>\n")+
i18n("<p><h3>In list view:</h3></p>\n") +
diff --git a/libkcal/phoneformat.cpp b/libkcal/phoneformat.cpp
index 11c68c5..e6d4879 100644
--- a/libkcal/phoneformat.cpp
+++ b/libkcal/phoneformat.cpp
@@ -809,181 +809,139 @@ bool PhoneFormat::load( Calendar *calendar, Calendar *existingCal)
}
/* Wanted user specific configuration? */
if (!GSM_ReadConfig(cfg, &s.Config[i], i) && i != 0) break;
s.ConfigNum++;
/* We want to use only one file descriptor for global and state machine debug output */
s.Config[i].UseGlobalDebugFile = true;
/* We wanted to read just user specified configuration. */
{break;}
}
#endif
int error=initDevice(&s);
qDebug("GSM Init %d (no error is %d)", error, ERR_NONE);
if ( error != ERR_NONE )
return false;
GSM_Phone_Functions *Phone;
GSM_CalendarEntry note;
bool start = true;
Phone=s.Phone.Functions;
bool gshutdown = false;
PhoneParser handler( calendar, mProfileName );
int ccc = 0;
QString message = i18n("Processing event # ");
int procCount = 0;
qDebug("Debug: only 10 calender items are downloaded ");
while (!gshutdown && ccc++ < 10) {
status.setText ( message + QString::number ( ++procCount ) );
qApp->processEvents();
qDebug("readEvent %d ", ccc);
error=Phone->GetNextCalendar(&s,&note,start);
if (error == ERR_EMPTY) break;
start = false;
handler.readEvent( existingCal, &note );
}
start = true;
GSM_ToDoEntry ToDo;
ccc = 0;
message = i18n("Processing todo # ");
procCount = 0;
while (!gshutdown) {
status.setText ( message + QString::number ( ++procCount ) );
qApp->processEvents();
error = Phone->GetNextToDo(&s, &ToDo, start);
if (error == ERR_EMPTY) break;
start = false;
qDebug("ReadTodo %d ", ++ccc);
handler.readTodo( existingCal, &ToDo, &s);
}
error=GSM_TerminateConnection(&s);
return true;
}
void PhoneFormat::event2GSM( Event* ev, GSM_CalendarEntry*Note )
{
-
+ QString eText = vfconverter.eventToString( ev );
+ int pos = 0;
+ GSM_ToDoEntry dummy;
+ GSM_DecodeVCALENDAR_VTODO( (unsigned char*)eText.latin1(), &pos, Note , &dummy, Nokia_VCalendar, Nokia_VToDo );
}
-void PhoneFormat::todo2GSM( Todo* todo, GSM_ToDoEntry *gsm )
+void PhoneFormat::todo2GSM( Todo* todo, GSM_ToDoEntry *gsmTodo )
{
-#if 0
- QStringList list;
- list.append( QString::number( todo->zaurusId() ) );
- list.append( todo->categories().join(",") );
-
- if ( todo->hasStartDate() ) {
- list.append( dtToString( todo->dtStart()) );
- } else
- list.append( QString() );
-
- if ( todo->hasDueDate() ) {
- QTime tim;
- if ( todo->doesFloat()) {
- list.append( dtToString( QDateTime(todo->dtDue().date(),QTime( 0,0,0 )), false)) ;
- } else {
- list.append( dtToString(todo->dtDue() ) );
- }
- } else
- list.append( QString() );
-
- if ( todo->isCompleted() ) {
- list.append( dtToString( todo->completed()) );
- list.append( "0" ); // yes 0 == completed
- } else {
- list.append( dtToString( todo->completed()) );
- list.append( "1" );
- }
- list.append( QString::number( todo->priority() ));
- if( ! todo->summary().isEmpty() )
- list.append( todo->summary() );
- else
- list.append( "" );
- if (! todo->description().isEmpty() )
- list.append( todo->description() );
- else
- list.append( "" );
- for(QStringList::Iterator it=list.begin();
- it!=list.end(); ++it){
- QString& s = (*it);
- s.replace(QRegExp("\""), "\"\"");
- if(s.contains(QRegExp("[,\"\r\n]")) || s.stripWhiteSpace() != s){
- s.prepend('\"');
- s.append('\"');
- } else if(s.isEmpty() && !s.isNull()){
- s = "\"\"";
- }
- }
- return list.join(",");
-#endif
+ QString tText = vfconverter.todoToString( todo );
+ int pos = 0;
+ GSM_CalendarEntry dummy;
+ GSM_DecodeVCALENDAR_VTODO( (unsigned char*)tText.latin1(), &pos, &dummy, gsmTodo, Nokia_VCalendar, Nokia_VToDo );
}
void PhoneFormat::afterSave( Incidence* inc)
{
uint csum;
if ( inc->type() == "Event")
csum = PhoneFormat::getCsumEvent( (Event*) inc );
else
csum = PhoneFormat::getCsumTodo( (Todo*) inc );
inc->setCsum( mProfileName, QString::number( csum ));
inc->setTempSyncStat( SYNC_TEMPSTATE_NEW_ID );
}
bool PhoneFormat::save( Calendar *calendar)
{
GSM_StateMachine s;
qDebug(" save ");
s.opened = false;
s.msg = NULL;
s.ConfigNum = 0;
QLabel status ( i18n("Writing data. Opening device ..."), 0 );
int w = status.sizeHint().width()+20 ;
if ( w < 200 ) w = 200;
int h = status.sizeHint().height()+20 ;
int dw = QApplication::desktop()->width();
int dh = QApplication::desktop()->height();
status.setCaption(i18n("Writing Phone Data") );
status.setGeometry( (dw-w)/2, (dh - h )/2 ,w,h );
status.show();
status.raise();
qApp->processEvents();
int error=initDevice(&s);
qDebug("GSM Init %d (no error is %d)", error, ERR_NONE);
if ( error != ERR_NONE )
return false;
GSM_Phone_Functions *Phone;
GSM_CalendarEntry Note;
bool start = true;
Phone=s.Phone.Functions;
bool gshutdown = false;
QPtrList<Event> er = calendar->rawEvents();
Event* ev = er.first();
QString message = i18n("Processing event # ");
int procCount = 0;
while ( ev ) {
//qDebug("i %d ", ++i);
if ( ev->tempSyncStat() != SYNC_TEMPSTATE_NEW_EXTERNAL ) { // event was changed during sync or is a new one
status.setText ( message + QString::number ( ++procCount ) );
qApp->processEvents();
event2GSM( ev, &Note );
if ( ev->tempSyncStat() == SYNC_TEMPSTATE_DELETE ) { // delete
error = Phone->DeleteCalendar(&s, &Note);
}
else if ( ev->getID(mProfileName).isEmpty() ) { // add new
// we have to do this later after deleting
}
else { // change existing
error = Phone->SetCalendar(&s, &Note);
}
}
ev = er.next();
}
diff --git a/libkcal/phoneformat.h b/libkcal/phoneformat.h
index 7b7dd04..33b2091 100644
--- a/libkcal/phoneformat.h
+++ b/libkcal/phoneformat.h
@@ -1,65 +1,67 @@
/*
This file is part of libkcal.
Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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.
*/
#ifndef PHONEFORMAT_H
#define PHONEFORMAT_H
#include <qstring.h>
#include "scheduler.h"
+#include "vcalformat.h"
#include "calformat.h"
extern "C" {
#include "../gammu/emb/common/gammu.h"
}
namespace KCal {
/**
This class implements the calendar format used by Phone.
*/
class Event;
class Todo;
class PhoneFormat : public QObject {
public:
/** Create new iCalendar format. */
PhoneFormat(QString profileName, QString device,QString connection, QString model);
virtual ~PhoneFormat();
bool load( Calendar * ,Calendar * );
bool save( Calendar * );
bool fromString( Calendar *, const QString & );
QString toString( Calendar * );
static ulong getCsum( const QStringList & );
static ulong getCsumTodo( Todo* to );
static ulong getCsumEvent( Event* ev );
private:
+ VCalFormat vfconverter;
void event2GSM( Event* ev, GSM_CalendarEntry*Note );
void todo2GSM( Todo* ev, GSM_ToDoEntry *ToDo );
int initDevice(GSM_StateMachine *s);
QString getEventString( Event* );
QString getTodoString( Todo* );
QString dtToGSM( const QDateTime& dt, bool useTZ = true );
QString mProfileName, mDevice, mConnection, mModel;
void afterSave( Incidence* );
};
}
#endif
diff --git a/libkcal/vcalformat.cpp b/libkcal/vcalformat.cpp
index 72a781a..1167e58 100644
--- a/libkcal/vcalformat.cpp
+++ b/libkcal/vcalformat.cpp
@@ -104,128 +104,147 @@ bool VCalFormat::save(Calendar *calendar, const QString &fileName)
// TODO STUFF
QPtrList<Todo> todoList = mCalendar->rawTodos();
QPtrListIterator<Todo> qlt(todoList);
for (; qlt.current(); ++qlt) {
vo = eventToVTodo(qlt.current());
addVObjectProp(vcal, vo);
}
// EVENT STUFF
QPtrList<Event> events = mCalendar->rawEvents();
Event *ev;
for(ev=events.first();ev;ev=events.next()) {
vo = eventToVEvent(ev);
addVObjectProp(vcal, vo);
}
writeVObjectToFile(QFile::encodeName(fileName).data() ,vcal);
cleanVObjects(vcal);
cleanStrTbl();
if (QFile::exists(fileName)) {
kdDebug(5800) << "No error" << endl;
return true;
} else {
kdDebug(5800) << "Error" << endl;
return false; // error
}
}
bool VCalFormat::fromString( Calendar *calendar, const QString &text )
{
// TODO: Factor out VCalFormat::fromString()
QCString data = text.utf8();
if ( !data.size() ) return false;
VObject *vcal = Parse_MIME( data.data(), data.size());
if ( !vcal ) return false;
VObjectIterator i;
VObject *curvo;
initPropIterator( &i, vcal );
// we only take the first object. TODO: parse all incidences.
do {
curvo = nextVObject( &i );
} while ( strcmp( vObjectName( curvo ), VCEventProp ) &&
strcmp( vObjectName( curvo ), VCTodoProp ) );
if ( strcmp( vObjectName( curvo ), VCEventProp ) == 0 ) {
Event *event = VEventToEvent( curvo );
calendar->addEvent( event );
} else {
kdDebug(5800) << "VCalFormat::fromString(): Unknown object type." << endl;
deleteVObject( vcal );
return false;
}
deleteVObject( vcal );
return true;
}
+QString VCalFormat::eventToString( Event * event)
+{
+ if ( !event ) return QString::null;
+ VObject *vevent = eventToVEvent( event );
+ char *buf = writeMemVObject( 0, 0, vevent );
+ QString result( buf );
+ cleanVObject( vevent );
+ return result;
+}
+QString VCalFormat::todoToString( Todo * todo )
+{
+ if ( !todo ) return QString::null;
+ VObject *vevent = eventToVTodo( todo );
+ char *buf = writeMemVObject( 0, 0, vevent );
+ QString result( buf );
+ cleanVObject( vevent );
+ return result;
+}
+
QString VCalFormat::toString( Calendar *calendar )
{
// TODO: Factor out VCalFormat::asString()
VObject *vcal = newVObject(VCCalProp);
addPropValue( vcal, VCProdIdProp, CalFormat::productId() );
QString tmpStr = mCalendar->getTimeZoneStr();
addPropValue( vcal, VCTimeZoneProp, tmpStr.local8Bit() );
addPropValue( vcal, VCVersionProp, _VCAL_VERSION );
// TODO: Use all data.
QPtrList<Event> events = calendar->events();
Event *event = events.first();
if ( !event ) return QString::null;
VObject *vevent = eventToVEvent( event );
addVObjectProp( vcal, vevent );
char *buf = writeMemVObject( 0, 0, vcal );
QString result( buf );
cleanVObject( vcal );
return result;
}
VObject *VCalFormat::eventToVTodo(const Todo *anEvent)
{
VObject *vtodo;
QString tmpStr;
QStringList tmpStrList;
vtodo = newVObject(VCTodoProp);
// due date
if (anEvent->hasDueDate()) {
tmpStr = qDateTimeToISO(anEvent->dtDue(),
!anEvent->doesFloat());
addPropValue(vtodo, VCDueProp, tmpStr.local8Bit());
}
// start date
if (anEvent->hasStartDate()) {
tmpStr = qDateTimeToISO(anEvent->dtStart(),
!anEvent->doesFloat());
addPropValue(vtodo, VCDTstartProp, tmpStr.local8Bit());
}
// creation date
tmpStr = qDateTimeToISO(anEvent->created());
addPropValue(vtodo, VCDCreatedProp, tmpStr.local8Bit());
// unique id
addPropValue(vtodo, VCUniqueStringProp,
anEvent->uid().local8Bit());
// revision
tmpStr.sprintf("%i", anEvent->revision());
addPropValue(vtodo, VCSequenceProp, tmpStr.local8Bit());
// last modification date
diff --git a/libkcal/vcalformat.h b/libkcal/vcalformat.h
index d4cecbc..8490125 100644
--- a/libkcal/vcalformat.h
+++ b/libkcal/vcalformat.h
@@ -1,108 +1,110 @@
/*
This file is part of libkcal.
Copyright (c) 1998 Preston Brown
Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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.
*/
#ifndef _VCALFORMAT_H
#define _VCALFORMAT_H
#include "calformat.h"
#define _VCAL_VERSION "1.0"
class VObject;
namespace KCal {
/**
This class implements the vCalendar format. It provides methods for
loading/saving/converting vCalendar format data into the internal KOrganizer
representation as Calendar and Events.
@short vCalendar format implementation
*/
class VCalFormat : public CalFormat {
public:
VCalFormat();
virtual ~VCalFormat();
/** loads a calendar on disk in vCalendar format into the current calendar.
* any information already present is lost. Returns TRUE if successful,
* else returns FALSE.
* @param fileName the name of the calendar on disk.
*/
bool load(Calendar *,const QString &fileName);
/** writes out the calendar to disk in vCalendar format. Returns true if
* successful and false on error.
* @param fileName the name of the file
*/
bool save(Calendar *,const QString &fileName);
/**
Parse string and populate calendar with that information.
*/
bool fromString( Calendar *, const QString & );
/**
Return calendar information as string.
*/
QString toString( Calendar * );
+ QString eventToString( Event * );
+ QString todoToString( Todo * );
protected:
/** translates a VObject of the TODO type into a Event */
Todo *VTodoToEvent(VObject *vtodo);
/** translates a VObject into a Event and returns a pointer to it. */
Event *VEventToEvent(VObject *vevent);
/** translate a Event into a VTodo-type VObject and return pointer */
VObject *eventToVTodo(const Todo *anEvent);
/** translate a Event into a VObject and returns a pointer to it. */
VObject* eventToVEvent(const Event *anEvent);
/** takes a QDate and returns a string in the format YYYYMMDDTHHMMSS */
QString qDateToISO(const QDate &);
/** takes a QDateTime and returns a string in format YYYYMMDDTHHMMSS */
QString qDateTimeToISO(const QDateTime &, bool zulu=TRUE);
/** takes a string in the format YYYYMMDDTHHMMSS and returns a
* valid QDateTime. */
QDateTime ISOToQDateTime(const QString & dtStr);
/** takes a string in the format YYYYMMDD and returns a
* valid QDate. */
QDate ISOToQDate(const QString & dtStr);
/** takes a vCalendar tree of VObjects, and puts all of them that have
* the "event" property into the dictionary, todos in the todo-list, etc. */
void populate(VObject *vcal);
/** takes a number 0 - 6 and returns the two letter string of that day,
* i.e. MO, TU, WE, etc. */
const char *dayFromNum(int day);
/** the reverse of the above function. */
int numFromDay(const QString &day);
Attendee::PartStat readStatus(const char *s) const;
QCString writeStatus(Attendee::PartStat status) const;
private:
Calendar *mCalendar;
QPtrList<Event> mEventsRelate; // events with relations
QPtrList<Todo> mTodosRelate; // todos with relations
};
}
#endif