00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
#include <sys/types.h>
00024
#include <sys/stat.h>
00025
#include <fcntl.h>
00026
#include <unistd.h>
00027
00028
#include <cassert>
00029
00030
#include <qfile.h>
00031
#include <qdict.h>
00032
#include <qdatetime.h>
00033
#include <qstringlist.h>
00034
00035
#include "kapplication.h"
00036
#include <kdebug.h>
00037
#include <kemailsettings.h>
00038
#include <klocale.h>
00039
#include <taskview.h>
00040
00041
#include "incidence.h"
00042
00043
00044
00045
00046
00047
00048
#include "karmstorage.h"
00049
#include "preferences.h"
00050
#include "task.h"
00051
00052
00053
KarmStorage *KarmStorage::_instance = 0;
00054
00055
KarmStorage *KarmStorage::instance()
00056 {
00057
if (_instance == 0) {
00058 _instance =
new KarmStorage();
00059 }
00060
return _instance;
00061 }
00062
00063 KarmStorage::KarmStorage() { }
00064
00065 QString KarmStorage::load(
TaskView* view,
const Preferences* preferences)
00066 {
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077 QString err;
00078 KEMailSettings settings;
00079
int handle;
00080
00081
00082
if (preferences->
iCalFile() == _icalfile)
00083
return err;
00084
00085
00086
00087
00088
00089 handle = open(QFile::encodeName(preferences->
iCalFile()),
00090 O_CREAT|O_EXCL|O_WRONLY,
00091 S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH);
00092
00093
if (handle != -1)
00094 {
00095 close(handle);
00096 }
00097
00098
00099 view->clear();
00100 _calendar.close();
00101
00102
00103 _icalfile = preferences->
iCalFile();
00104 kdDebug() <<
"KarmStorage::load - loading " << _icalfile << endl;
00105 _calendar.setEmail( settings.getSetting( KEMailSettings::EmailAddress ) );
00106 _calendar.setOwner( settings.getSetting( KEMailSettings::RealName ) );
00107
if (!_calendar.load(_icalfile))
00108 err = i18n(
"Error loading file \"%1\"")
00109 .arg(_icalfile);
00110
00111
00112
if (!err)
00113 {
00114 KCal::Todo::List todoList;
00115 KCal::Todo::List::ConstIterator todo;
00116 QDict< Task > map;
00117
00118
00119
00120 todoList = _calendar.rawTodos();
00121 kdDebug() <<
"KarmStorage::load "
00122 <<
"rawTodo count (includes completed todos) ="
00123 << todoList.count() << endl;
00124
for( todo = todoList.begin(); todo != todoList.end(); ++todo )
00125 {
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
Task* task =
new Task(*todo, view);
00144 map.insert( (*todo)->uid(), task );
00145 view->setRootIsDecorated(
true);
00146
if ((*todo)->isCompleted())
00147 {
00148 task->setEnabled(
false);
00149 task->setOpen(
false);
00150 }
00151
else
00152 task->setOpen(
true);
00153
00154 }
00155
00156
00157
for( todo = todoList.begin(); todo != todoList.end(); ++todo )
00158 {
00159
Task* task = map.find( (*todo)->uid() );
00160
00161
00162
if ( (*todo)->relatedTo() )
00163 {
00164
Task* newParent = map.find( (*todo)->relatedToUid() );
00165
00166
00167
if ( !newParent )
00168 err = i18n(
"Error loading \"%1\": could not find parent (uid=%2)")
00169 .arg(task->
name())
00170 .arg((*todo)->relatedToUid());
00171
00172
if (!err)
00173 task->
move( newParent);
00174 }
00175 }
00176
00177 kdDebug() <<
"KarmStorage::load - loaded " << view->
count()
00178 <<
" tasks from " << _icalfile << endl;
00179 }
00180
00181
return err;
00182 }
00183
00184
void KarmStorage::save(
TaskView* taskview)
00185 {
00186 QPtrStack< KCal::Todo > parents;
00187
00188
for (
Task* task=taskview->
first_child(); task; task = task->
nextSibling())
00189 {
00190 writeTaskAsTodo(task, 1, parents );
00191 }
00192
00193 _calendar.save(_icalfile);
00194
00195 kdDebug()
00196 <<
"KarmStorage::save : wrote "
00197 << taskview->
count() <<
" tasks to " << _icalfile << endl;
00198 }
00199
00200
void KarmStorage::writeTaskAsTodo(
Task* task,
const int level,
00201 QPtrStack< KCal::Todo >& parents )
00202 {
00203
00204 KCal::Todo* todo;
00205
00206 todo = _calendar.todo(task->
uid());
00207 task->
asTodo(todo);
00208
00209
if ( !parents.isEmpty() )
00210 todo->setRelatedTo( parents.top() );
00211
00212 parents.push( todo );
00213
00214
for (
Task* nextTask = task->
firstChild(); nextTask;
00215 nextTask = nextTask->
nextSibling() )
00216 {
00217 writeTaskAsTodo(nextTask, level+1, parents );
00218 }
00219
00220 parents.pop();
00221 }
00222
00223 bool KarmStorage::isEmpty()
00224 {
00225 KCal::Todo::List todoList;
00226
00227 todoList = _calendar.rawTodos();
00228
return todoList.empty();
00229 }
00230
00231 bool KarmStorage::isNewStorage(
const Preferences* preferences)
const
00232
{
00233
if (!_icalfile.isNull())
00234
return preferences->
iCalFile() != _icalfile;
00235
else
00236
return false;
00237 }
00238
00239
00240
00241
00242
00243
00244 QString
KarmStorage::loadFromFlatFile(
TaskView* taskview,
00245
const QString& filename)
00246 {
00247 QString err;
00248
00249 kdDebug()
00250 <<
"KarmStorage::loadFromFlatFile: " << filename << endl;
00251
00252 QFile f(filename);
00253
if( !f.exists() )
00254 err = i18n(
"File \"%1\" not found.").arg(filename);
00255
00256
if (!err)
00257 {
00258
if( !f.open( IO_ReadOnly ) )
00259 err = i18n(
"Could not open \"%1\".").arg(filename);
00260 }
00261
00262
if (!err)
00263 {
00264
00265 QString line;
00266
00267 QPtrStack<Task> stack;
00268
Task *task;
00269
00270 QTextStream stream(&f);
00271
00272
while( !stream.atEnd() ) {
00273
00274
00275
00276
00277 line = stream.readLine();
00278 kdDebug() <<
"DEBUG: line: " << line <<
"\n";
00279
00280
if (line.isNull())
00281
break;
00282
00283
long minutes;
00284
int level;
00285 QString name;
00286 DesktopList desktopList;
00287
if (!parseLine(line, &minutes, &name, &level, &desktopList))
00288
continue;
00289
00290
unsigned int stackLevel = stack.count();
00291
for (
unsigned int i = level; i<=stackLevel ; i++) {
00292 stack.pop();
00293 }
00294
00295
if (level == 1) {
00296 kdDebug() <<
"KarmStorage::loadFromFlatFile - toplevel task: "
00297 << name <<
" min: " << minutes <<
"\n";
00298 task =
new Task(name, minutes, 0, desktopList, taskview);
00299 task->
setUid(
addTask(task, 0));
00300 }
00301
else {
00302
Task *parent = stack.top();
00303 kdDebug() <<
"KarmStorage::loadFromFlatFile - task: " << name
00304 <<
" min: " << minutes <<
" parent" << parent->
name() <<
"\n";
00305 task =
new Task(name, minutes, 0, desktopList, parent);
00306
00307 task->
setUid(
addTask(task, parent));
00308
00309
00310 parent->
changeTimes(0, -minutes,
false);
00311 taskview->setRootIsDecorated(
true);
00312 parent->setOpen(
true);
00313 }
00314
if (!task->
uid().isNull())
00315 stack.push(task);
00316
else
00317
delete task;
00318 }
00319
00320 f.close();
00321
00322 }
00323
00324
return err;
00325 }
00326
00327 QString
KarmStorage::loadFromFlatFileCumulative(
TaskView* taskview,
00328
const QString& filename)
00329 {
00330 QString err =
loadFromFlatFile(taskview, filename);
00331
if (!err)
00332 {
00333
for (
Task* task = taskview->
first_child(); task;
00334 task = task->
nextSibling())
00335 {
00336 adjustFromLegacyFileFormat(task);
00337 }
00338 }
00339
return err;
00340 }
00341
00342
bool KarmStorage::parseLine(QString line,
long *time, QString *name,
00343
int *level, DesktopList* desktopList)
00344 {
00345
if (line.find(
'#') == 0) {
00346
00347
return false;
00348 }
00349
00350
int index = line.find(
'\t');
00351
if (index == -1) {
00352
00353
return false;
00354 }
00355
00356 QString levelStr = line.left(index);
00357 QString rest = line.remove(0,index+1);
00358
00359 index = rest.find(
'\t');
00360
if (index == -1) {
00361
00362
return false;
00363 }
00364
00365 QString timeStr = rest.left(index);
00366 rest = rest.remove(0,index+1);
00367
00368
bool ok;
00369
00370 index = rest.find(
'\t');
00371
if (index >= 0) {
00372 *name = rest.left(index);
00373 QString deskLine = rest.remove(0,index+1);
00374
00375
00376
00377 QString ds;
00378
int d;
00379
int commaIdx = deskLine.find(
',');
00380
while (commaIdx >= 0) {
00381 ds = deskLine.left(commaIdx);
00382 d = ds.toInt(&ok);
00383
if (!ok)
00384
return false;
00385
00386 desktopList->push_back(d);
00387 deskLine.remove(0,commaIdx+1);
00388 commaIdx = deskLine.find(
',');
00389 }
00390
00391 d = deskLine.toInt(&ok);
00392
00393
if (!ok)
00394
return false;
00395
00396 desktopList->push_back(d);
00397 }
00398
else {
00399 *name = rest.remove(0,index+1);
00400 }
00401
00402 *time = timeStr.toLong(&ok);
00403
00404
if (!ok) {
00405
00406
return false;
00407 }
00408 *level = levelStr.toInt(&ok);
00409
if (!ok) {
00410
00411
return false;
00412 }
00413
00414
return true;
00415 }
00416
00417
void KarmStorage::adjustFromLegacyFileFormat(
Task* task)
00418 {
00419
00420
if ( task->
parent() )
00421 task->
parent()->
changeTimes(-task->
sessionTime(), -task->
time(),
false);
00422
00423
00424
00425
00426
00427
for (
Task* subtask = task->
firstChild(); subtask;
00428 subtask = subtask->
nextSibling() )
00429 adjustFromLegacyFileFormat(subtask);
00430 }
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440 QString
KarmStorage::addTask(
const Task* task,
const Task* parent)
00441 {
00442 KCal::Todo* todo;
00443 QString uid;
00444
00445 todo =
new KCal::Todo();
00446
if (_calendar.addTodo(todo))
00447 {
00448 task->
asTodo(todo);
00449
if (parent)
00450 todo->setRelatedTo(_calendar.todo(parent->
uid()));
00451 uid = todo->uid();
00452 }
00453
00454
return uid;
00455 }
00456
00457 bool KarmStorage::removeTask(
Task* task)
00458 {
00459
00460
00461 KCal::Event::List eventList = _calendar.rawEvents();
00462
for(KCal::Event::List::iterator i = eventList.begin();
00463 i != eventList.end();
00464 ++i)
00465 {
00466
00467
00468
00469
00470
if ( (*i)->relatedToUid() == task->
uid()
00471 || ( (*i)->relatedTo()
00472 && (*i)->relatedTo()->uid() == task->
uid()))
00473 {
00474 _calendar.deleteEvent(*i);
00475 }
00476 }
00477
00478
00479 KCal::Todo *todo = _calendar.todo(task->
uid());
00480 _calendar.deleteTodo(todo);
00481
00482
00483 _calendar.save(_icalfile);
00484
00485
return true;
00486 }
00487
00488 void KarmStorage::addComment(
const Task* task,
const QString& comment)
00489 {
00490 KCal::Todo* todo;
00491
00492 todo = _calendar.todo(task->
uid());
00493
00494
00495
00496 QString s = comment;
00497
00498
00499
00500
00501
00502
00503 todo->setDescription(task->
comment());
00504
00505 _calendar.save(_icalfile);
00506 }
00507
00508 void KarmStorage::stopTimer(
const Task* task)
00509 {
00510
long delta = task->
startTime().secsTo(QDateTime::currentDateTime());
00511 changeTime(task, delta);
00512 }
00513
00514
void KarmStorage::changeTime(
const Task* task,
const long deltaSeconds)
00515 {
00516
00517 KCal::Event* e;
00518 QDateTime end;
00519
00520 e = baseEvent(task);
00521
00522
00523
00524 end = task->
startTime();
00525
if (deltaSeconds > 0)
00526 end = task->
startTime().addSecs(deltaSeconds);
00527 e->setDtEnd(end);
00528
00529
00530 e->setCustomProperty( kapp->instanceName(),
00531 QCString(
"duration"),
00532 QString::number(deltaSeconds));
00533
00534 _calendar.addEvent(e);
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544 task->
taskView()->
scheduleSave();
00545 }
00546
00547
00548 KCal::Event* KarmStorage::baseEvent(
const Task * task)
00549 {
00550 KCal::Event* e;
00551 QStringList categories;
00552
00553 e =
new KCal::Event;
00554 e->setSummary(task->
name());
00555
00556
00557 e->setRelatedTo(_calendar.todo(task->
uid()));
00558
00559
00560 assert(e->relatedTo()->uid() == task->
uid());
00561
00562
00563 e->setFloats(
false);
00564 e->setDtStart(task->
startTime());
00565
00566
00567 categories.append(i18n(
"KArm"));
00568 e->setCategories(categories);
00569
00570
return e;
00571 }
00572
00573
HistoryEvent::HistoryEvent(QString uid, QString name,
long duration,
00574 QDateTime start, QDateTime stop, QString todoUid)
00575 {
00576 _uid = uid;
00577 _name = name;
00578 _duration = duration;
00579 _start = start;
00580 _stop = stop;
00581 _todoUid = todoUid;
00582 }
00583
00584
00585 QValueList<HistoryEvent>
KarmStorage::getHistory(
const QDate& from,
00586
const QDate& to)
00587 {
00588 QValueList<HistoryEvent> retval;
00589 QStringList processed;
00590 KCal::Event::List events;
00591 KCal::Event::List::iterator event;
00592 QString duration;
00593
00594
for(QDate d = from; d <= to; d = d.addDays(1))
00595 {
00596 events = _calendar.rawEventsForDate(d);
00597
for (event = events.begin(); event != events.end(); ++event)
00598 {
00599
00600
00601
if (! processed.contains( (*event)->uid()))
00602 {
00603
00604
00605
00606
00607
00608 processed.append( (*event)->uid());
00609
00610 duration = (*event)->customProperty(kapp->instanceName(),
00611 QCString(
"duration"));
00612
if ( ! duration.isNull() )
00613 {
00614
if ( (*event)->relatedTo()
00615 && ! (*event)->relatedTo()->uid().isEmpty() )
00616 {
00617 retval.append(
HistoryEvent(
00618 (*event)->uid(),
00619 (*event)->summary(),
00620 duration.toLong(),
00621 (*event)->dtStart(),
00622 (*event)->dtEnd(),
00623 (*event)->relatedTo()->uid()
00624 ));
00625 }
00626
else
00627
00628
00629
00630 kdDebug() <<
"KarmStorage::getHistory(): "
00631 <<
"The event " << (*event)->uid()
00632 <<
" is not related to a todo. Dropped." << endl;
00633 }
00634 }
00635 }
00636 }
00637
00638
return retval;
00639 }
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696