00001 #include <qfile.h>
00002 #include <qclipboard.h>
00003 #include <qlayout.h>
00004 #include <qlistbox.h>
00005 #include <qptrlist.h>
00006 #include <qptrstack.h>
00007 #include <qtextstream.h>
00008 #include <qlistview.h>
00009 #include <qtimer.h>
00010
00011 #include "kapplication.h"
00012 #include <kconfig.h>
00013 #include <kdebug.h>
00014 #include <klocale.h>
00015 #include <kfiledialog.h>
00016 #include <klineeditdlg.h>
00017 #include <kmessagebox.h>
00018
00019 #include "desktoptracker.h"
00020 #include "edittaskdialog.h"
00021 #include "idletimedetector.h"
00022 #include "preferences.h"
00023 #include "task.h"
00024 #include "taskview.h"
00025 #include "timekard.h"
00026 #include "karmstorage.h"
00027 #include "printdialog.h"
00028
00029 #define T_LINESIZE 1023
00030 #define HIDDEN_COLUMN -10
00031
00032 class DesktopTracker;
00033
00034 TaskView::TaskView(QWidget *parent, const char *name):KListView(parent,name)
00035 {
00036 _preferences = Preferences::instance();
00037 _storage = KarmStorage::instance();
00038
00039 connect(this, SIGNAL( doubleClicked( QListViewItem * )),
00040 this, SLOT( changeTimer( QListViewItem * )));
00041
00042
00043 previousColumnWidths[0] = previousColumnWidths[1]
00044 = previousColumnWidths[2] = previousColumnWidths[3] = HIDDEN_COLUMN;
00045
00046 addColumn( i18n("Task Name") );
00047 addColumn( i18n("Session Time") );
00048 addColumn( i18n("Time") );
00049 addColumn( i18n("Total Session Time") );
00050 addColumn( i18n("Total Time") );
00051 setColumnAlignment( 1, Qt::AlignRight );
00052 setColumnAlignment( 2, Qt::AlignRight );
00053 setColumnAlignment( 3, Qt::AlignRight );
00054 setColumnAlignment( 4, Qt::AlignRight );
00055 adaptColumns();
00056 setAllColumnsShowFocus( true );
00057
00058
00059 _minuteTimer = new QTimer(this);
00060 connect( _minuteTimer, SIGNAL( timeout() ), this, SLOT( minuteUpdate() ));
00061 _minuteTimer->start(1000 * secsPerMinute);
00062
00063
00064 connect(_preferences, SIGNAL(iCalFile(QString)),
00065 this, SLOT(iCalFileChanged(QString)));
00066
00067
00068 connect(_preferences, SIGNAL( setupChanged() ), this,SLOT( adaptColumns() ));
00069
00070 _minuteTimer->start(1000 * secsPerMinute);
00071
00072
00073 _idleTimeDetector = new IdleTimeDetector( _preferences->idlenessTimeout() );
00074 connect( _idleTimeDetector, SIGNAL( extractTime(int) ),
00075 this, SLOT( extractTime(int) ));
00076 connect( _idleTimeDetector, SIGNAL( stopAllTimers() ),
00077 this, SLOT( stopAllTimers() ));
00078 connect( _preferences, SIGNAL( idlenessTimeout(int) ),
00079 _idleTimeDetector, SLOT( setMaxIdle(int) ));
00080 connect( _preferences, SIGNAL( detectIdleness(bool) ),
00081 _idleTimeDetector, SLOT( toggleOverAllIdleDetection(bool) ));
00082 if (!_idleTimeDetector->isIdleDetectionPossible())
00083 _preferences->disableIdleDetection();
00084
00085
00086 _autoSaveTimer = new QTimer(this);
00087 connect( _preferences, SIGNAL( autoSave(bool) ),
00088 this, SLOT( autoSaveChanged(bool) ));
00089 connect( _preferences, SIGNAL( autoSavePeriod(int) ),
00090 this, SLOT( autoSavePeriodChanged(int) ));
00091 connect( _autoSaveTimer, SIGNAL( timeout() ), this, SLOT( save() ));
00092
00093
00094 _manualSaveTimer = new QTimer(this);
00095 connect( _manualSaveTimer, SIGNAL( timeout() ), this, SLOT( save() ));
00096
00097
00098 _desktopTracker = new DesktopTracker();
00099 connect( _desktopTracker, SIGNAL( reachedtActiveDesktop( Task* ) ),
00100 this, SLOT( startTimerFor(Task*) ));
00101 connect( _desktopTracker, SIGNAL( leftActiveDesktop( Task* ) ),
00102 this, SLOT( stopTimerFor(Task*) ));
00103 }
00104
00105 TaskView::~TaskView()
00106 {
00107 _preferences->save();
00108 }
00109
00110 Task* TaskView::first_child() const
00111 {
00112 return static_cast<Task*>(firstChild());
00113 }
00114
00115 Task* TaskView::current_item() const
00116 {
00117 return static_cast<Task*>(currentItem());
00118 }
00119
00120 Task* TaskView::item_at_index(int i)
00121 {
00122 return static_cast<Task*>(itemAtIndex(i));
00123 }
00124
00125 void TaskView::load()
00126 {
00127
00128 QString err = _storage->load(this, _preferences);
00129
00130 if (!err.isEmpty())
00131 {
00132 KMessageBox::error(this, err);
00133 return;
00134 }
00135
00136
00137
00138
00139
00140
00141
00142 int task_idx = 0;
00143 for (Task* task = item_at_index(task_idx);
00144 task;
00145 task = item_at_index(++task_idx))
00146 {
00147 _desktopTracker->registerForDesktops( task, task->getDesktops() );
00148 }
00149
00150 setSelected(first_child(), true);
00151 setCurrentItem(first_child());
00152 _desktopTracker->startTracking();
00153 }
00154
00155 void TaskView::loadFromFlatFile()
00156 {
00157 kdDebug() << "TaskView::loadFromFlatFile()" << endl;
00158
00159
00160
00161 QString fileName(KFileDialog::getOpenFileName(QString::null, QString::null,
00162 0));
00163 if (!fileName.isEmpty()) {
00164 QString err = _storage->loadFromFlatFile(this, fileName);
00165 if (!err.isEmpty())
00166 {
00167 KMessageBox::error(this, err);
00168 return;
00169 }
00170
00171
00172 int task_idx = 0;
00173 Task* task = item_at_index(task_idx++);
00174 while (task)
00175 {
00176
00177 _desktopTracker->registerForDesktops( task, task->getDesktops() );
00178 task = item_at_index(task_idx++);
00179 }
00180
00181 setSelected(first_child(), true);
00182 setCurrentItem(first_child());
00183
00184 _desktopTracker->startTracking();
00185 }
00186 }
00187
00188 void TaskView::scheduleSave()
00189 {
00190 _manualSaveTimer->start( 10, true );
00191 }
00192
00193 void TaskView::save()
00194 {
00195
00196
00197
00198
00199
00200 #if 0
00201
00202
00203
00204
00205
00206
00207
00208 for (unsigned int i = 0; i < activeTasks.count(); i++)
00209 {
00210 activeTasks.at(i)->setRunning(false, _storage);
00211 activeTasks.at(i)->setRunning(true, _storage);
00212 }
00213
00214
00215 if (activeTasks.count() == 0)
00216 #endif
00217 {
00218 _storage->save(this);
00219 }
00220 }
00221
00222 void TaskView::startCurrentTimer()
00223 {
00224 startTimerFor( current_item() );
00225 }
00226
00227 long TaskView::count()
00228 {
00229 long n = 0;
00230 for (Task* t = item_at_index(n); t; t=item_at_index(++n));
00231 return n;
00232 }
00233
00234 void TaskView::startTimerFor(Task* task)
00235 {
00236 if (task != 0 && activeTasks.findRef(task) == -1) {
00237 _idleTimeDetector->startIdleDetection();
00238 task->setRunning(true, _storage);
00239 activeTasks.append(task);
00240 emit updateButtons();
00241 if ( activeTasks.count() == 1 )
00242 emit timersActive();
00243
00244 emit tasksChanged( activeTasks);
00245 }
00246 }
00247
00248 void TaskView::stopAllTimers()
00249 {
00250 for (unsigned int i=0; i<activeTasks.count();i++) {
00251 activeTasks.at(i)->setRunning(false, _storage);
00252 }
00253 _idleTimeDetector->stopIdleDetection();
00254 activeTasks.clear();
00255 emit updateButtons();
00256 emit timersInactive();
00257 emit tasksChanged( activeTasks);
00258 }
00259
00260 void TaskView::startNewSession()
00261 {
00262 QListViewItemIterator item( first_child());
00263 for ( ; item.current(); ++item ) {
00264 Task * task = (Task *) item.current();
00265 task->startNewSession();
00266 }
00267 }
00268
00269 void TaskView::resetTimeForAllTasks()
00270 {
00271 QListViewItemIterator item( first_child());
00272 for ( ; item.current(); ++item ) {
00273 Task * task = (Task *) item.current();
00274 task->resetTimes();
00275 }
00276 }
00277
00278 void TaskView::stopTimerFor(Task* task)
00279 {
00280 if (task != 0 && activeTasks.findRef(task) != -1) {
00281 activeTasks.removeRef(task);
00282 task->setRunning(false, _storage);
00283 if (activeTasks.count()== 0) {
00284 _idleTimeDetector->stopIdleDetection();
00285 emit timersInactive();
00286 }
00287 emit updateButtons();
00288 }
00289 emit tasksChanged( activeTasks);
00290 }
00291
00292 void TaskView::stopCurrentTimer()
00293 {
00294 stopTimerFor( current_item());
00295 }
00296
00297
00298 void TaskView::changeTimer(QListViewItem *)
00299 {
00300 Task *task = current_item();
00301 if (task != 0 && activeTasks.findRef(task) == -1) {
00302
00303 for (unsigned int i=0; i<activeTasks.count();i++) {
00304 (activeTasks.at(i))->setRunning(false, _storage);
00305 }
00306 activeTasks.clear();
00307
00308
00309 startCurrentTimer();
00310 }
00311 else {
00312 stopCurrentTimer();
00313 }
00314 }
00315
00316 void TaskView::minuteUpdate()
00317 {
00318 addTimeToActiveTasks(1, false);
00319 }
00320
00321 void TaskView::addTimeToActiveTasks(int minutes, bool do_logging)
00322 {
00323 for(unsigned int i=0; i<activeTasks.count();i++)
00324 activeTasks.at(i)->changeTime(minutes, do_logging, _storage);
00325 }
00326
00327 void TaskView::newTask()
00328 {
00329 newTask(i18n("New Task"), 0);
00330 }
00331
00332 void TaskView::newTask(QString caption, Task *parent)
00333 {
00334 EditTaskDialog *dialog = new EditTaskDialog(caption, false);
00335 long total, totalDiff, session, sessionDiff;
00336 DesktopList desktopList;
00337 Task *task;
00338
00339 int result = dialog->exec();
00340 if (result == QDialog::Accepted) {
00341 QString taskName = i18n("Unnamed Task");
00342 if (!dialog->taskName().isEmpty()) {
00343 taskName = dialog->taskName();
00344 }
00345
00346 total = totalDiff = session = sessionDiff = 0;
00347 dialog->status( &total, &totalDiff, &session, &sessionDiff, &desktopList);
00348
00349
00350
00351 if (desktopList.size() == (unsigned int)_desktopTracker->desktopCount())
00352 desktopList.clear();
00353
00354 if (parent == 0)
00355 {
00356 task = new Task(taskName, total, session, desktopList, this);
00357 task->setUid(_storage->addTask(task, 0));
00358 }
00359 else
00360 {
00361 task = new Task(taskName, total, session, desktopList, parent);
00362 task->setUid(_storage->addTask(task, parent));
00363 }
00364
00365 if (!task->uid().isNull())
00366 {
00367 _desktopTracker->registerForDesktops( task, desktopList );
00368
00369 setCurrentItem( task );
00370 setSelected( task, true );
00371
00372 save();
00373 }
00374 else
00375 {
00376 delete task;
00377 KMessageBox::error(0,i18n(
00378 "Error storing new task--your changes were not saved."));
00379 }
00380 }
00381
00382 delete dialog;
00383 }
00384
00385 void TaskView::newSubTask()
00386 {
00387 Task* task = current_item();
00388 if(!task)
00389 return;
00390 newTask(i18n("New Sub Task"), task);
00391 task->setOpen(true);
00392 setRootIsDecorated(true);
00393 }
00394
00395 void TaskView::editTask()
00396 {
00397 Task *task = current_item();
00398 if (!task)
00399 return;
00400
00401 DesktopList desktopList = task->getDesktops();
00402 EditTaskDialog *dialog = new EditTaskDialog(i18n("Edit Task"), true, &desktopList);
00403 dialog->setTask( task->name(),
00404 task->time(),
00405 task->sessionTime() );
00406 int result = dialog->exec();
00407 if (result == QDialog::Accepted) {
00408 QString taskName = i18n("Unnamed Task");
00409 if (!dialog->taskName().isEmpty()) {
00410 taskName = dialog->taskName();
00411 }
00412
00413 task->setName(taskName, _storage);
00414
00415
00416 long total, session, totalDiff, sessionDiff;
00417 total = totalDiff = session = sessionDiff = 0;
00418 DesktopList desktopList;
00419 dialog->status( &total, &totalDiff, &session, &sessionDiff, &desktopList);
00420
00421 if( totalDiff != 0 || sessionDiff != 0)
00422 task->changeTimes( sessionDiff ,totalDiff, true, _storage );
00423
00424
00425
00426 if (desktopList.size() == (unsigned int)_desktopTracker->desktopCount())
00427 desktopList.clear();
00428
00429 task->setDesktopList(desktopList);
00430
00431 _desktopTracker->registerForDesktops( task, desktopList );
00432
00433 emit updateButtons();
00434 }
00435 delete dialog;
00436 }
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453 void TaskView::deleteTask(bool markingascomplete)
00454 {
00455 Task *task = current_item();
00456 if (task == 0) {
00457 KMessageBox::information(0,i18n("No task selected."));
00458 return;
00459 }
00460
00461 int response = KMessageBox::Yes;
00462 if (!markingascomplete && _preferences->promptDelete()) {
00463 if (task->childCount() == 0) {
00464 response = KMessageBox::warningYesNo( 0,
00465 i18n( "Are you sure you want to delete "
00466 "the task named\n\"%1\" and its entire history?")
00467 .arg(task->name()),
00468 i18n( "Deleting Task"));
00469 }
00470 else {
00471 response = KMessageBox::warningYesNo( 0,
00472 i18n( "Are you sure you want to delete the task named"
00473 "\n\"%1\" and its entire history?\n"
00474 "NOTE: all its subtasks and their history will also "
00475 "be deleted!").arg(task->name()),
00476 i18n( "Deleting Task"));
00477 }
00478 }
00479
00480 if (response == KMessageBox::Yes)
00481 {
00482 if (markingascomplete)
00483 {
00484 task->setPercentComplete(100, _storage);
00485 save();
00486
00487
00488
00489
00490
00491
00492 }
00493 else
00494 {
00495 task->remove(activeTasks, _storage);
00496 task->removeFromView();
00497 save();
00498 }
00499
00500
00501 bool anyChilds = false;
00502 for(Task* child = first_child();
00503 child;
00504 child = child->nextSibling()) {
00505 if (child->childCount() != 0) {
00506 anyChilds = true;
00507 break;
00508 }
00509 }
00510 if (!anyChilds) {
00511 setRootIsDecorated(false);
00512 }
00513
00514
00515 if (activeTasks.count() == 0) {
00516 _idleTimeDetector->stopIdleDetection();
00517 emit timersInactive();
00518 }
00519
00520 emit tasksChanged( activeTasks );
00521 }
00522 }
00523
00524 void TaskView::extractTime(int minutes)
00525 {
00526 addTimeToActiveTasks(-minutes, true);
00527 }
00528
00529 void TaskView::autoSaveChanged(bool on)
00530 {
00531 if (on) {
00532 _autoSaveTimer->start(_preferences->autoSavePeriod()*1000*secsPerMinute);
00533 }
00534 else {
00535 if (_autoSaveTimer->isActive()) {
00536 _autoSaveTimer->stop();
00537 }
00538 }
00539 }
00540
00541 void TaskView::autoSavePeriodChanged(int )
00542 {
00543 autoSaveChanged(_preferences->autoSave());
00544 }
00545
00546 void TaskView::adaptColumns()
00547 {
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557 for( int x=1; x <= 4; x++) {
00558
00559 if( _preferences->displayColumn(x-1)
00560 && previousColumnWidths[x-1] != HIDDEN_COLUMN )
00561 {
00562 setColumnWidth( x, previousColumnWidths[x-1] );
00563 previousColumnWidths[x-1] = HIDDEN_COLUMN;
00564 setColumnWidthMode( x, QListView::Maximum );
00565 }
00566
00567 else
00568 if( ! _preferences->displayColumn(x-1)
00569 && previousColumnWidths[x-1] == HIDDEN_COLUMN )
00570 {
00571 setColumnWidthMode( x, QListView::Manual );
00572
00573 previousColumnWidths[x-1] = columnWidth( x );
00574 setColumnWidth( x, 0 );
00575 }
00576 }
00577 }
00578
00579 void TaskView::deletingTask(Task* deletedTask)
00580 {
00581 DesktopList desktopList;
00582
00583 _desktopTracker->registerForDesktops( deletedTask, desktopList );
00584 activeTasks.removeRef( deletedTask );
00585
00586 emit tasksChanged( activeTasks);
00587 }
00588
00589 void TaskView::iCalFileChanged(QString file)
00590 {
00591 kdDebug() << "TaskView:iCalFileChanged: " << file << endl;
00592 load();
00593 }
00594
00595 QValueList<HistoryEvent> TaskView::getHistory(const QDate& from,
00596 const QDate& to) const
00597 {
00598 return _storage->getHistory(from, to);
00599 }
00600
00601 void TaskView::markTaskAsComplete()
00602 {
00603 if (current_item())
00604 kdDebug() << "TaskView::markTaskAsComplete: "
00605 << current_item()->uid() << endl;
00606 else
00607 kdDebug() << "TaskView::markTaskAsComplete: null current_item()" << endl;
00608
00609 bool markingascomplete = true;
00610 deleteTask(markingascomplete);
00611 }
00612
00613 void TaskView::clipTotals()
00614 {
00615 TimeKard *t = new TimeKard();
00616 if (current_item() && current_item()->isRoot())
00617 {
00618 int response = KMessageBox::questionYesNo( 0,
00619 i18n("Copy totals for just this task and its subtasks?"
00620 " (Click No to copy totals for all tasks.)"));
00621 if (response == KMessageBox::Yes)
00622 {
00623 KApplication::clipboard()->setText(t->totalsAsText(this));
00624 }
00625 else
00626 {
00627 KApplication::clipboard()->setText(t->totalsAsText(this, false));
00628 }
00629 }
00630 else
00631 {
00632 KApplication::clipboard()->setText(t->totalsAsText(this));
00633 }
00634 }
00635
00636 void TaskView::clipHistory()
00637 {
00638
00639 PrintDialog *dialog = new PrintDialog();
00640 if (dialog->exec()== QDialog::Accepted)
00641 {
00642 TimeKard *t = new TimeKard();
00643 KApplication::clipboard()->
00644 setText(t->historyAsText(this, dialog->from(), dialog->to()));
00645 }
00646 }
00647
00648 #include "taskview.moc"