00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "qtopiaformat.h"
00023
00024 #include "calendar.h"
00025 #include "calendarlocal.h"
00026
00027 #include <QtCore/QDateTime>
00028 #include <QtCore/QString>
00029 #include <QtCore/QRegExp>
00030 #include <QtGui/QClipboard>
00031 #include <QtCore/QFile>
00032 #include <QtCore/QTextStream>
00033
00034 #include <QtGui/QTextDocument>
00035
00036 #include <QtXml/QXmlAttributes>
00037 #include <QtXml/QXmlDefaultHandler>
00038 #include <QtXml/QXmlParseException>
00039 #include <QtXml/QXmlInputSource>
00040 #include <QtXml/QXmlSimpleReader>
00041
00042 #include <kdebug.h>
00043 #include <klocale.h>
00044 #include <kdatetime.h>
00045
00046 using namespace KCal;
00047
00048
00049 class QtopiaParser : public QXmlDefaultHandler
00050 {
00051 public:
00052 QtopiaParser( Calendar *calendar ) : mCalendar( calendar ) {}
00053
00054 bool startElement( const QString &, const QString &, const QString &qName,
00055 const QXmlAttributes &attributes )
00056 {
00057 if ( qName == "event" ) {
00058 Event *event = new Event;
00059 QString uid = "Qtopia" + attributes.value( "uid" );
00060 event->setUid( uid );
00061
00062 event->setSummary( attributes.value( "description" ),
00063 Qt::mightBeRichText( attributes.value( "description" ) ) );
00064 event->setLocation( attributes.value( "location" ),
00065 Qt::mightBeRichText( attributes.value( "location" ) ) );
00066 event->setDescription( attributes.value( "note" ),
00067 Qt::mightBeRichText( attributes.value( "note" ) ) );
00068 event->setDtStart( toDateTime( attributes.value( "start" ) ) );
00069 event->setDtEnd( toDateTime( attributes.value( "end" ) ) );
00070
00071 if ( attributes.value( "type" ) == "AllDay" ) {
00072 event->setAllDay( true );
00073 } else {
00074 event->setAllDay( false );
00075 }
00076
00077 QString rtype = attributes.value( "rtype" );
00078 if ( !rtype.isEmpty() ) {
00079 QDate startDate = event->dtStart().date();
00080
00081 QString freqStr = attributes.value( "rfreq" );
00082 int freq = freqStr.toInt();
00083
00084 QString hasEndDateStr = attributes.value( "rhasenddate" );
00085 bool hasEndDate = hasEndDateStr == "1";
00086
00087 QString endDateStr = attributes.value( "enddt" );
00088 QDate endDate = toDateTime( endDateStr ).date();
00089
00090 QString weekDaysStr = attributes.value( "rweekdays" );
00091 int weekDaysNum = weekDaysStr.toInt();
00092 QBitArray weekDays( 7 );
00093 int i;
00094 for ( i = 1; i <= 7; ++i ) {
00095 weekDays.setBit( i - 1, ( 2 << i ) & weekDaysNum );
00096 }
00097
00098 QString posStr = attributes.value( "rposition" );
00099 int pos = posStr.toInt();
00100
00101 Recurrence *r = event->recurrence();
00102
00103 if ( rtype == "Daily" ) {
00104 r->setDaily( freq );
00105 if ( hasEndDate ) {
00106 r->setEndDate( endDate );
00107 }
00108 } else if ( rtype == "Weekly" ) {
00109 r->setWeekly( freq, weekDays );
00110 if ( hasEndDate ) {
00111 r->setEndDate( endDate );
00112 }
00113 } else if ( rtype == "MonthlyDate" ) {
00114 r->setMonthly( freq );
00115 if ( hasEndDate ) {
00116 r->setEndDate( endDate );
00117 }
00118 r->addMonthlyDate( static_cast<short>( startDate.day() ) );
00119 } else if ( rtype == "MonthlyDay" ) {
00120 r->setMonthly( freq );
00121 if ( hasEndDate ) {
00122 r->setEndDate( endDate );
00123 }
00124 QBitArray days( 7 );
00125 days.fill( false );
00126 days.setBit( startDate.dayOfWeek() - 1 );
00127 r->addMonthlyPos( static_cast<short>( pos ), days );
00128 } else if ( rtype == "Yearly" ) {
00129 r->setYearly( freq );
00130 if ( hasEndDate ) {
00131 r->setEndDate( endDate );
00132 }
00133 }
00134 }
00135
00136 QString categoryList = attributes.value( "categories" );
00137 event->setCategories( lookupCategories( categoryList ) );
00138
00139 QString alarmStr = attributes.value( "alarm" );
00140 if ( !alarmStr.isEmpty() ) {
00141 kDebug() << "Alarm:" << alarmStr;
00142 Alarm *alarm = new Alarm( event );
00143 alarm->setType( Alarm::Display );
00144 alarm->setEnabled( true );
00145 int alarmOffset = alarmStr.toInt();
00146 alarm->setStartOffset( Duration( alarmOffset * -60 ) );
00147 event->addAlarm( alarm );
00148 }
00149
00150 Event *oldEvent = mCalendar->event( uid );
00151 if ( oldEvent ) {
00152 mCalendar->deleteEvent( oldEvent );
00153 }
00154
00155 mCalendar->addEvent( event );
00156 } else if ( qName == "Task" ) {
00157 Todo *todo = new Todo;
00158
00159 QString uid = "Qtopia" + attributes.value( "Uid" );
00160 todo->setUid( uid );
00161
00162 QString description = attributes.value( "Description" );
00163 int pos = description.indexOf( '\n' );
00164 if ( pos > 0 ) {
00165 QString summary = description.left( pos );
00166 todo->setSummary( summary, Qt::mightBeRichText( summary ) );
00167 todo->setDescription( description, Qt::mightBeRichText( description ) );
00168 } else {
00169 todo->setSummary( description, Qt::mightBeRichText( description ) );
00170 }
00171
00172 int priority = attributes.value( "Priority" ).toInt();
00173
00174 todo->setPriority( priority );
00175
00176 QString categoryList = attributes.value( "Categories" );
00177 todo->setCategories( lookupCategories( categoryList ) );
00178
00179 QString completedStr = attributes.value( "Completed" );
00180 if ( completedStr == "1" ) {
00181 todo->setCompleted( true );
00182 }
00183
00184 QString hasDateStr = attributes.value( "HasDate" );
00185 if ( hasDateStr == "1" ) {
00186 int year = attributes.value( "DateYear" ).toInt();
00187 int month = attributes.value( "DateMonth" ).toInt();
00188 int day = attributes.value( "DateDay" ).toInt();
00189
00190 todo->setDtDue( KDateTime( QDate( year, month, day ), KDateTime::UTC ) );
00191 todo->setHasDueDate( true );
00192 }
00193
00194 Todo *oldTodo = mCalendar->todo( uid );
00195 if ( oldTodo ) {
00196 mCalendar->deleteTodo( oldTodo );
00197 }
00198
00199 mCalendar->addTodo( todo );
00200 } else if ( qName == "Category" ) {
00201 QString id = attributes.value( "id" );
00202 QString name = attributes.value( "name" );
00203 setCategory( id, name );
00204 }
00205
00206 return true;
00207 }
00208
00209 bool warning ( const QXmlParseException &exception )
00210 {
00211 kDebug() << "WARNING";
00212 printException( exception );
00213 return true;
00214 }
00215
00216 bool error ( const QXmlParseException &exception )
00217 {
00218 kDebug() << "ERROR";
00219 printException( exception );
00220 return false;
00221 }
00222
00223 bool fatalError ( const QXmlParseException &exception )
00224 {
00225 kDebug() << "FATALERROR";
00226 printException( exception );
00227 return false;
00228 }
00229
00230 QString errorString () const
00231 {
00232 return "QtopiaParser: Error!";
00233 }
00234
00235 protected:
00236 void printException( const QXmlParseException &exception )
00237 {
00238 kError() << "XML Parse Error (line" << exception.lineNumber()
00239 << ", col" << exception.columnNumber() << "):"
00240 << exception.message() << "(public ID: '"
00241 << exception.publicId() << "' system ID: '"
00242 << exception.systemId() << "')";
00243 }
00244
00245 KDateTime toDateTime( const QString &value )
00246 {
00247 KDateTime dt;
00248 dt.setTime_t( value.toUInt() );
00249
00250 return dt;
00251 }
00252
00253 QStringList lookupCategories( const QString &categoryList )
00254 {
00255 const QStringList categoryIds = categoryList.split( ';' );
00256 QStringList categories;
00257 QStringList::ConstIterator it;
00258 for ( it = categoryIds.constBegin(); it != categoryIds.constEnd(); ++it ) {
00259 categories.append( category( *it ) );
00260 }
00261 return categories;
00262 }
00263
00264 private:
00265 Calendar *mCalendar;
00266
00267 static QString category( const QString &id )
00268 {
00269 QMap<QString,QString>::ConstIterator it = mCategoriesMap.constFind( id );
00270 if ( it == mCategoriesMap.constEnd() ) {
00271 return id;
00272 } else {
00273 return *it;
00274 }
00275 }
00276
00277 static void setCategory( const QString &id, const QString &name )
00278 {
00279 mCategoriesMap.insert( id, name );
00280 }
00281
00282 static QMap<QString,QString> mCategoriesMap;
00283 };
00284
00285 QMap<QString,QString> QtopiaParser::mCategoriesMap;
00286
00287
00288 QtopiaFormat::QtopiaFormat() : d( 0 )
00289 {
00290 }
00291
00292 QtopiaFormat::~QtopiaFormat()
00293 {
00294 }
00295
00296 bool QtopiaFormat::load( Calendar *calendar, const QString &fileName )
00297 {
00298 kDebug() << fileName;
00299
00300 clearException();
00301
00302 QtopiaParser handler( calendar );
00303 QFile xmlFile( fileName );
00304 QXmlInputSource source( &xmlFile );
00305 QXmlSimpleReader reader;
00306 reader.setContentHandler( &handler );
00307 return reader.parse( source );
00308 }
00309
00310 bool QtopiaFormat::save( Calendar *calendar, const QString &fileName )
00311 {
00312 kDebug() << fileName;
00313
00314 clearException();
00315
00316 QString text = toString( calendar );
00317
00318 if ( text.isNull() ) {
00319 return false;
00320 }
00321
00322
00323
00324 QFile file( fileName );
00325 if (!file.open( QIODevice::WriteOnly ) ) {
00326 setException( new ErrorFormat( ErrorFormat::SaveError,
00327 i18n( "Could not open file '%1'", fileName ) ) );
00328 return false;
00329 }
00330 QTextStream ts( &file );
00331 ts << text;
00332 file.close();
00333
00334 return true;
00335 }
00336
00337 bool QtopiaFormat::fromString( Calendar *, const QString & )
00338 {
00339 kDebug() << "not yet implemented.";
00340 return false;
00341 }
00342
00343 bool QtopiaFormat::fromRawString( Calendar *, const QByteArray & )
00344 {
00345 kDebug() << "not yet implemented.";
00346 return false;
00347 }
00348
00349 QString QtopiaFormat::toString( Calendar * )
00350 {
00351 return QString();
00352 }