karm Library API Documentation

taskview.cpp

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" // kapp 00012 #include <kconfig.h> 00013 #include <kdebug.h> 00014 #include <klocale.h> // i18n 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 // setup default values 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 // set up the minuteTimer 00059 _minuteTimer = new QTimer(this); 00060 connect( _minuteTimer, SIGNAL( timeout() ), this, SLOT( minuteUpdate() )); 00061 _minuteTimer->start(1000 * secsPerMinute); 00062 00063 // React when user changes iCalFile 00064 connect(_preferences, SIGNAL(iCalFile(QString)), 00065 this, SLOT(iCalFileChanged(QString))); 00066 00067 // resize columns when config is changed 00068 connect(_preferences, SIGNAL( setupChanged() ), this,SLOT( adaptColumns() )); 00069 00070 _minuteTimer->start(1000 * secsPerMinute); 00071 00072 // Set up the idle detection. 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 // Setup auto save timer 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 // Setup manual save timer (to save changes a little while after they happen) 00094 _manualSaveTimer = new QTimer(this); 00095 connect( _manualSaveTimer, SIGNAL( timeout() ), this, SLOT( save() )); 00096 00097 // Connect desktop tracker events to task starting/stopping 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 // TODO: If empty, ask if user wants to import tasks from another file 00137 //if (_storage.isEmpty()) 00138 //{ 00139 //} 00140 00141 // Register tasks with desktop tracker 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 //KFileDialog::getSaveFileName("icalout.ics",i18n("*.ics|ICalendars"),this); 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 // Register tasks with desktop tracker 00172 int task_idx = 0; 00173 Task* task = item_at_index(task_idx++); 00174 while (task) 00175 { 00176 // item_at_index returns 0 where no more items. 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 /*single-shot*/ ); 00191 } 00192 00193 void TaskView::save() 00194 { 00195 // DF: this code created a new event for the running task(s), 00196 // at every call (very frequent with autosave) !!! 00197 // -> if one wants autosave to save the current event, then 00198 // Task needs to store the "current event" and we need to update 00199 // it before calling save. 00200 #if 0 00201 // Stop then start all timers so history entries are written. This is 00202 // inefficient if more than one task running, but it is correct. It is 00203 // inefficient because the iCalendar file is saved every time a task's 00204 // setRunning(false, ...) is called. For a big ics file, this could be a 00205 // drag. However, it does ensure that the data will be consistent. And 00206 // if the most common use case is that one task is running most of the time, 00207 // it won't make any difference. 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 // If there was an active task, the iCal file has already been saved. 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 // Stop all the other timers. 00303 for (unsigned int i=0; i<activeTasks.count();i++) { 00304 (activeTasks.at(i))->setRunning(false, _storage); 00305 } 00306 activeTasks.clear(); 00307 00308 // Start the new timer. 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 // If all available desktops are checked, disable auto tracking, 00350 // since it makes no sense to track for every desktop. 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 // setName only does something if the new name is different 00413 task->setName(taskName, _storage); 00414 00415 // update session time as well if the time was changed 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 // If all available desktops are checked, disable auto tracking, 00425 // since it makes no sense to track for every desktop. 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 //void TaskView::addCommentToTask() 00439 //{ 00440 // Task *task = current_item(); 00441 // if (!task) 00442 // return; 00443 00444 // bool ok; 00445 // QString comment = KLineEditDlg::getText(i18n("Comment"), 00446 // i18n("Log comment for task '%1':").arg(task->name()), 00447 // QString(), &ok, this); 00448 // if ( ok ) 00449 // task->addComment( comment, _storage ); 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 // Have to remove after saving, as the save routine only affects tasks 00488 // that are in the view. Otherwise, the new percent complete does not 00489 // get saved. (No longer remove when marked as complete.) 00490 //task->removeFromView(); 00491 00492 } 00493 else 00494 { 00495 task->remove(activeTasks, _storage); 00496 task->removeFromView(); 00497 save(); 00498 } 00499 00500 // remove root decoration if there is no more children. 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 // Stop idle detection if no more counters are running 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 /*minutes*/) 00542 { 00543 autoSaveChanged(_preferences->autoSave()); 00544 } 00545 00546 void TaskView::adaptColumns() 00547 { 00548 // to hide a column X we set it's width to 0 00549 // at that moment we'll remember the original column within 00550 // previousColumnWidths[X] 00551 // 00552 // When unhiding a previously hidden column 00553 // (previousColumnWidths[X] != HIDDEN_COLUMN !) 00554 // we restore it's width from the saved value and set 00555 // previousColumnWidths[X] to HIDDEN_COLUMN 00556 00557 for( int x=1; x <= 4; x++) { 00558 // the column was invisible before and were switching it on now 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 // the column was visible before and were switching it off now 00567 else 00568 if( ! _preferences->displayColumn(x-1) 00569 && previousColumnWidths[x-1] == HIDDEN_COLUMN ) 00570 { 00571 setColumnWidthMode( x, QListView::Manual ); // we don't want update() 00572 // to resize/unhide the col 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"
KDE Logo
This file is part of the documentation for karm Library Version 3.2.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Jul 28 23:58:06 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003