karm

taskview.cpp

00001 #include <qclipboard.h>
00002 #include <qfile.h>
00003 #include <qlayout.h>
00004 #include <qlistbox.h>
00005 #include <qlistview.h>
00006 #include <qptrlist.h>
00007 #include <qptrstack.h>
00008 #include <qstring.h>
00009 #include <qtextstream.h>
00010 #include <qtimer.h>
00011 #include <qxml.h>
00012 
00013 #include "kapplication.h"       // kapp
00014 #include <kconfig.h>
00015 #include <kdebug.h>
00016 #include <kfiledialog.h>
00017 #include <klocale.h>            // i18n
00018 #include <kmessagebox.h>
00019 #include <kurlrequester.h>
00020 
00021 #include "csvexportdialog.h"
00022 #include "desktoptracker.h"
00023 #include "edittaskdialog.h"
00024 #include "idletimedetector.h"
00025 #include "karmstorage.h"
00026 #include "plannerparser.h"
00027 #include "preferences.h"
00028 #include "printdialog.h"
00029 #include "reportcriteria.h"
00030 #include "task.h"
00031 #include "taskview.h"
00032 #include "timekard.h"
00033 #include "taskviewwhatsthis.h"
00034 
00035 #define T_LINESIZE 1023
00036 #define HIDDEN_COLUMN -10
00037 
00038 class DesktopTracker;
00039 
00040 TaskView::TaskView(QWidget *parent, const char *name, const QString &icsfile ):KListView(parent,name)
00041 {
00042   _preferences = Preferences::instance( icsfile );
00043   _storage = KarmStorage::instance();
00044 
00045   connect( this, SIGNAL( expanded( QListViewItem * ) ),
00046            this, SLOT( itemStateChanged( QListViewItem * ) ) );
00047   connect( this, SIGNAL( collapsed( QListViewItem * ) ),
00048            this, SLOT( itemStateChanged( QListViewItem * ) ) );
00049 
00050   // setup default values
00051   previousColumnWidths[0] = previousColumnWidths[1]
00052   = previousColumnWidths[2] = previousColumnWidths[3] = HIDDEN_COLUMN;
00053 
00054   addColumn( i18n("Task Name") );
00055   addColumn( i18n("Session Time") );
00056   addColumn( i18n("Time") );
00057   addColumn( i18n("Total Session Time") );
00058   addColumn( i18n("Total Time") );
00059   setColumnAlignment( 1, Qt::AlignRight );
00060   setColumnAlignment( 2, Qt::AlignRight );
00061   setColumnAlignment( 3, Qt::AlignRight );
00062   setColumnAlignment( 4, Qt::AlignRight );
00063   adaptColumns();
00064   setAllColumnsShowFocus( true );
00065 
00066   // set up the minuteTimer
00067   _minuteTimer = new QTimer(this);
00068   connect( _minuteTimer, SIGNAL( timeout() ), this, SLOT( minuteUpdate() ));
00069   _minuteTimer->start(1000 * secsPerMinute);
00070 
00071   // React when user changes iCalFile
00072   connect(_preferences, SIGNAL(iCalFile(QString)),
00073       this, SLOT(iCalFileChanged(QString)));
00074 
00075   // resize columns when config is changed
00076   connect(_preferences, SIGNAL( setupChanged() ), this,SLOT( adaptColumns() ));
00077 
00078   _minuteTimer->start(1000 * secsPerMinute);
00079 
00080   // Set up the idle detection.
00081   _idleTimeDetector = new IdleTimeDetector( _preferences->idlenessTimeout() );
00082   connect( _idleTimeDetector, SIGNAL( extractTime(int) ),
00083            this, SLOT( extractTime(int) ));
00084   connect( _idleTimeDetector, SIGNAL( stopAllTimersAt(QDateTime) ),
00085            this, SLOT( stopAllTimersAt(QDateTime) ));
00086   connect( _preferences, SIGNAL( idlenessTimeout(int) ),
00087            _idleTimeDetector, SLOT( setMaxIdle(int) ));
00088   connect( _preferences, SIGNAL( detectIdleness(bool) ),
00089            _idleTimeDetector, SLOT( toggleOverAllIdleDetection(bool) ));
00090   if (!_idleTimeDetector->isIdleDetectionPossible())
00091     _preferences->disableIdleDetection();
00092 
00093   // Setup auto save timer
00094   _autoSaveTimer = new QTimer(this);
00095   connect( _preferences, SIGNAL( autoSave(bool) ),
00096            this, SLOT( autoSaveChanged(bool) ));
00097   connect( _preferences, SIGNAL( autoSavePeriod(int) ),
00098            this, SLOT( autoSavePeriodChanged(int) ));
00099   connect( _autoSaveTimer, SIGNAL( timeout() ), this, SLOT( save() ));
00100 
00101   // Setup manual save timer (to save changes a little while after they happen)
00102   _manualSaveTimer = new QTimer(this);
00103   connect( _manualSaveTimer, SIGNAL( timeout() ), this, SLOT( save() ));
00104 
00105   // Connect desktop tracker events to task starting/stopping
00106   _desktopTracker = new DesktopTracker();
00107   connect( _desktopTracker, SIGNAL( reachedtActiveDesktop( Task* ) ),
00108            this, SLOT( startTimerFor(Task*) ));
00109   connect( _desktopTracker, SIGNAL( leftActiveDesktop( Task* ) ),
00110            this, SLOT( stopTimerFor(Task*) ));
00111   new TaskViewWhatsThis( this );
00112 }
00113 
00114 KarmStorage* TaskView::storage()
00115 {
00116   return _storage;
00117 }
00118 
00119 void TaskView::contentsMousePressEvent ( QMouseEvent * e )
00120 {
00121   kdDebug(5970) << "entering contentsMousePressEvent" << endl;
00122   KListView::contentsMousePressEvent(e);
00123   Task* task = current_item();
00124   // This checks that there has been a click onto an item,  
00125   // not into an empty part of the KListView.
00126   if ( task != 0 &&  // zero can happen if there is no task
00127         e->pos().y() >= current_item()->itemPos() &&
00128         e->pos().y() < current_item()->itemPos()+current_item()->height() )
00129   { 
00130     // see if the click was on the completed icon
00131     int leftborder = treeStepSize() * ( task->depth() + ( rootIsDecorated() ? 1 : 0)) + itemMargin();
00132     if ((leftborder < e->x()) && (e->x() < 19 + leftborder ))
00133     {
00134       if ( e->button() == LeftButton )
00135         if ( task->isComplete() ) task->setPercentComplete( 0, _storage );
00136         else task->setPercentComplete( 100, _storage );
00137     }
00138     emit updateButtons();
00139   }
00140 }
00141 
00142 void TaskView::contentsMouseDoubleClickEvent ( QMouseEvent * e )
00143 // if the user double-clicks onto a tasks, he says "I am now working exclusively
00144 // on that task". That means, on a doubleclick, we check if it occurs on an item
00145 // not in the blank space, if yes, stop all other tasks and start the new timer.
00146 {
00147   kdDebug(5970) << "entering contentsMouseDoubleClickEvent" << endl;
00148   KListView::contentsMouseDoubleClickEvent(e);
00149   
00150   Task *task = current_item();
00151 
00152   if ( task != 0 )  // current_item() exists
00153   {
00154     if ( e->pos().y() >= task->itemPos() &&  // doubleclick was onto current_item()
00155           e->pos().y() < task->itemPos()+task->height() )
00156     {
00157       if ( activeTasks.findRef(task) == -1 )  // task is active
00158       {
00159         stopAllTimers();
00160         startCurrentTimer();
00161       }
00162       else stopCurrentTimer();
00163     }
00164   }
00165 }
00166 
00167 TaskView::~TaskView()
00168 {
00169   _preferences->save();
00170 }
00171 
00172 Task* TaskView::first_child() const
00173 {
00174   return static_cast<Task*>(firstChild());
00175 }
00176 
00177 Task* TaskView::current_item() const
00178 {
00179   return static_cast<Task*>(currentItem());
00180 }
00181 
00182 Task* TaskView::item_at_index(int i)
00183 {
00184   return static_cast<Task*>(itemAtIndex(i));
00185 }
00186 
00187 void TaskView::load( QString fileName )
00188 {
00189   // if the program is used as an embedded plugin for konqueror, there may be a need
00190   // to load from a file without touching the preferences.
00191   _isloading = true;
00192   QString err = _storage->load(this, _preferences, fileName);
00193 
00194   if (!err.isEmpty())
00195   {
00196     KMessageBox::error(this, err);
00197     _isloading = false;
00198     return;
00199   }
00200 
00201   // Register tasks with desktop tracker
00202   int i = 0;
00203   for ( Task* t = item_at_index(i); t; t = item_at_index(++i) )
00204     _desktopTracker->registerForDesktops( t, t->getDesktops() );
00205 
00206   restoreItemState( first_child() );
00207 
00208   setSelected(first_child(), true);
00209   setCurrentItem(first_child());
00210   if ( _desktopTracker->startTracking() != QString() ) 
00211     KMessageBox::error( 0, i18n("You are on a too high logical desktop, desktop tracking will not work") );
00212   _isloading = false;
00213   refresh();
00214 }
00215 
00216 void TaskView::restoreItemState( QListViewItem *item )
00217 {
00218   while( item ) 
00219   {
00220     Task *t = (Task *)item;
00221     t->setOpen( _preferences->readBoolEntry( t->uid() ) );
00222     if( item->childCount() > 0 ) restoreItemState( item->firstChild() );
00223     item = item->nextSibling();
00224   }
00225 }
00226 
00227 void TaskView::itemStateChanged( QListViewItem *item )
00228 {
00229   if ( !item || _isloading ) return;
00230   Task *t = (Task *)item;
00231   kdDebug(5970) << "TaskView::itemStateChanged()" 
00232     << " uid=" << t->uid() << " state=" << t->isOpen()
00233     << endl;
00234   if( _preferences ) _preferences->writeEntry( t->uid(), t->isOpen() );
00235 }
00236 
00237 void TaskView::closeStorage() { _storage->closeStorage( this ); }
00238 
00239 void TaskView::iCalFileModified(ResourceCalendar *rc)
00240 {
00241   kdDebug(5970) << "entering iCalFileModified" << endl;
00242   kdDebug(5970) << rc->infoText() << endl;
00243   rc->dump();
00244   _storage->buildTaskView(rc,this);
00245   kdDebug(5970) << "exiting iCalFileModified" << endl;
00246 }
00247 
00248 void TaskView::refresh()
00249 {
00250   kdDebug(5970) << "entering TaskView::refresh()" << endl;
00251   this->setRootIsDecorated(true);
00252   int i = 0;
00253   for ( Task* t = item_at_index(i); t; t = item_at_index(++i) )
00254   {
00255     t->setPixmapProgress();
00256   }
00257   
00258   // remove root decoration if there is no more children.
00259   bool anyChilds = false;
00260   for(Task* child = first_child();
00261             child;
00262             child = child->nextSibling()) {
00263     if (child->childCount() != 0) {
00264       anyChilds = true;
00265       break;
00266     }
00267   }
00268   if (!anyChilds) {
00269     setRootIsDecorated(false);
00270   }
00271   emit updateButtons();
00272   kdDebug(5970) << "exiting TaskView::refresh()" << endl;
00273 }
00274     
00275 void TaskView::loadFromFlatFile()
00276 {
00277   kdDebug(5970) << "TaskView::loadFromFlatFile()" << endl;
00278 
00279   //KFileDialog::getSaveFileName("icalout.ics",i18n("*.ics|ICalendars"),this);
00280 
00281   QString fileName(KFileDialog::getOpenFileName(QString::null, QString::null,
00282         0));
00283   if (!fileName.isEmpty()) {
00284     QString err = _storage->loadFromFlatFile(this, fileName);
00285     if (!err.isEmpty())
00286     {
00287       KMessageBox::error(this, err);
00288       return;
00289     }
00290     // Register tasks with desktop tracker
00291     int task_idx = 0;
00292     Task* task = item_at_index(task_idx++);
00293     while (task)
00294     {
00295       // item_at_index returns 0 where no more items.
00296       _desktopTracker->registerForDesktops( task, task->getDesktops() );
00297       task = item_at_index(task_idx++);
00298     }
00299 
00300     setSelected(first_child(), true);
00301     setCurrentItem(first_child());
00302 
00303     if ( _desktopTracker->startTracking() != QString() )
00304       KMessageBox::error(0, i18n("You are on a too high logical desktop, desktop tracking will not work") );
00305   }
00306 }
00307 
00308 QString TaskView::importPlanner(QString fileName)
00309 {
00310   kdDebug(5970) << "entering importPlanner" << endl;
00311   PlannerParser* handler=new PlannerParser(this);
00312   if (fileName.isEmpty()) fileName=KFileDialog::getOpenFileName(QString::null, QString::null, 0);
00313   QFile xmlFile( fileName );
00314   QXmlInputSource source( xmlFile );
00315   QXmlSimpleReader reader;
00316   reader.setContentHandler( handler );
00317   reader.parse( source );
00318   refresh();
00319   return "";
00320 }
00321 
00322 QString TaskView::report( const ReportCriteria& rc )
00323 {
00324   return _storage->report( this, rc );
00325 }
00326 
00327 void TaskView::exportcsvFile()
00328 {
00329   kdDebug(5970) << "TaskView::exportcsvFile()" << endl;
00330 
00331   CSVExportDialog dialog( ReportCriteria::CSVTotalsExport, this );
00332   if ( current_item() && current_item()->isRoot() )
00333     dialog.enableTasksToExportQuestion();
00334   dialog.urlExportTo->KURLRequester::setMode(KFile::File);
00335   if ( dialog.exec() ) {
00336     QString err = _storage->report( this, dialog.reportCriteria() );
00337     if ( !err.isEmpty() ) KMessageBox::error( this, i18n(err.ascii()) );
00338   }
00339 }
00340 
00341 QString TaskView::exportcsvHistory()
00342 {
00343   kdDebug(5970) << "TaskView::exportcsvHistory()" << endl;
00344   QString err;
00345   
00346   CSVExportDialog dialog( ReportCriteria::CSVHistoryExport, this );
00347   if ( current_item() && current_item()->isRoot() )
00348     dialog.enableTasksToExportQuestion();
00349   dialog.urlExportTo->KURLRequester::setMode(KFile::File);
00350   if ( dialog.exec() ) {
00351     err = _storage->report( this, dialog.reportCriteria() );
00352   }
00353   return err;
00354 }
00355 
00356 void TaskView::scheduleSave()
00357 {
00358   kdDebug(5970) << "Entering TaskView::scheduleSave" << endl;
00359   // save changes a little while after they happen
00360   _manualSaveTimer->start( 10, true /*single-shot*/ );
00361 }
00362 
00363 Preferences* TaskView::preferences() { return _preferences; }
00364 
00365 QString TaskView::save()
00366 // This saves the tasks. If they do not yet have an endDate, their startDate is also not saved.
00367 {
00368   kdDebug(5970) << "Entering TaskView::save" << endl;
00369   QString err = _storage->save(this);
00370   emit(setStatusBar(err));
00371   return err;
00372 }
00373 
00374 void TaskView::startCurrentTimer()
00375 {
00376   startTimerFor( current_item() );
00377 }
00378 
00379 long TaskView::count()
00380 {
00381   long n = 0;
00382   for (Task* t = item_at_index(n); t; t=item_at_index(++n));
00383   return n;
00384 }
00385 
00386 void TaskView::startTimerFor(Task* task, QDateTime startTime )
00387 {
00388   kdDebug(5970) << "Entering TaskView::startTimerFor" << endl;
00389   if (save()==QString())
00390   {
00391     if (task != 0 && activeTasks.findRef(task) == -1) 
00392     {
00393       _idleTimeDetector->startIdleDetection();
00394       if (!task->isComplete())
00395       {
00396         task->setRunning(true, _storage, startTime);
00397         activeTasks.append(task);
00398         emit updateButtons();
00399         if ( activeTasks.count() == 1 )
00400           emit timersActive();
00401         emit tasksChanged( activeTasks);
00402       }
00403     }
00404   }
00405   else KMessageBox::error(0,i18n("Saving is impossible, so timing is useless. \nSaving problems may result from a full harddisk, a directory name instead of a file name, or stale locks. Check that your harddisk has enough space, that your calendar file exists and is a file and remove stale locks, typically from ~/.kde/share/apps/kabc/lock."));
00406 }
00407 
00408 void TaskView::clearActiveTasks()
00409 {
00410   activeTasks.clear();
00411 }
00412 
00413 void TaskView::stopAllTimers()
00414 {
00415   kdDebug(5970) << "Entering TaskView::stopAllTimers()" << endl;
00416   for ( unsigned int i = 0; i < activeTasks.count(); i++ )
00417     activeTasks.at(i)->setRunning(false, _storage);
00418 
00419   _idleTimeDetector->stopIdleDetection();
00420   activeTasks.clear();
00421   emit updateButtons();
00422   emit timersInactive();
00423   emit tasksChanged( activeTasks );
00424 }
00425 
00426 void TaskView::stopAllTimersAt(QDateTime qdt)
00427 // stops all timers for the time qdt. This makes sense, if the idletimedetector detected
00428 // the last work has been done 50 minutes ago.
00429 {
00430   kdDebug(5970) << "Entering TaskView::stopAllTimersAt " << qdt << endl;
00431   for ( unsigned int i = 0; i < activeTasks.count(); i++ )
00432   {
00433     activeTasks.at(i)->setRunning(false, _storage, qdt, qdt);
00434     kdDebug() << activeTasks.at(i)->name() << endl;
00435   }
00436 
00437   _idleTimeDetector->stopIdleDetection();
00438   activeTasks.clear();
00439   emit updateButtons();
00440   emit timersInactive();
00441   emit tasksChanged( activeTasks );
00442 }
00443 
00444 void TaskView::startNewSession()
00445 {
00446   QListViewItemIterator item( first_child());
00447   for ( ; item.current(); ++item ) {
00448     Task * task = (Task *) item.current();
00449     task->startNewSession();
00450   }
00451 }
00452 
00453 void TaskView::resetTimeForAllTasks()
00454 {
00455   QListViewItemIterator item( first_child());
00456   for ( ; item.current(); ++item ) {
00457     Task * task = (Task *) item.current();
00458     task->resetTimes();
00459   }
00460 }
00461 
00462 void TaskView::stopTimerFor(Task* task)
00463 {
00464   kdDebug(5970) << "Entering stopTimerFor. task = " << task->name() << endl;
00465   if ( task != 0 && activeTasks.findRef(task) != -1 ) {
00466     activeTasks.removeRef(task);
00467     task->setRunning(false, _storage);
00468     if ( activeTasks.count() == 0 ) {
00469       _idleTimeDetector->stopIdleDetection();
00470       emit timersInactive();
00471     }
00472     emit updateButtons();
00473   }
00474   emit tasksChanged( activeTasks);
00475 }
00476 
00477 void TaskView::stopCurrentTimer()
00478 {
00479   stopTimerFor( current_item());
00480 }
00481 
00482 void TaskView::minuteUpdate()
00483 {
00484   addTimeToActiveTasks(1, false);
00485 }
00486 
00487 void TaskView::addTimeToActiveTasks(int minutes, bool save_data)
00488 {
00489   for( unsigned int i = 0; i < activeTasks.count(); i++ )
00490     activeTasks.at(i)->changeTime(minutes, ( save_data ? _storage : 0 ) );
00491 }
00492 
00493 void TaskView::newTask()
00494 {
00495   newTask(i18n("New Task"), 0);
00496 }
00497 
00498 void TaskView::newTask(QString caption, Task *parent)
00499 {
00500   EditTaskDialog *dialog = new EditTaskDialog(caption, false);
00501   long total, totalDiff, session, sessionDiff;
00502   DesktopList desktopList;
00503 
00504   int result = dialog->exec();
00505   if ( result == QDialog::Accepted ) {
00506     QString taskName = i18n( "Unnamed Task" );
00507     if ( !dialog->taskName().isEmpty()) taskName = dialog->taskName();
00508 
00509     total = totalDiff = session = sessionDiff = 0;
00510     dialog->status( &total, &totalDiff, &session, &sessionDiff, &desktopList );
00511 
00512     // If all available desktops are checked, disable auto tracking,
00513     // since it makes no sense to track for every desktop.
00514     if ( desktopList.size() == ( unsigned int ) _desktopTracker->desktopCount() )
00515       desktopList.clear();
00516 
00517     QString uid = addTask( taskName, total, session, desktopList, parent );
00518     if ( uid.isNull() )
00519     {
00520       KMessageBox::error( 0, i18n(
00521             "Error storing new task. Your changes were not saved. Make sure you can edit your iCalendar file. Also quit all applications using this file and remove any lock file related to its name from ~/.kde/share/apps/kabc/lock/ " ) );
00522     }
00523 
00524     delete dialog;
00525   }
00526 }
00527 
00528 QString TaskView::addTask
00529 ( const QString& taskname, long total, long session, 
00530   const DesktopList& desktops, Task* parent )
00531 {
00532   Task *task;
00533   kdDebug(5970) << "TaskView::addTask: taskname = " << taskname << endl;
00534 
00535   if ( parent ) task = new Task( taskname, total, session, desktops, parent );
00536   else          task = new Task( taskname, total, session, desktops, this );
00537 
00538   task->setUid( _storage->addTask( task, parent ) );
00539   QString taskuid=task->uid();
00540   if ( ! taskuid.isNull() )
00541   {
00542     _desktopTracker->registerForDesktops( task, desktops );
00543     setCurrentItem( task );
00544     setSelected( task, true );
00545     task->setPixmapProgress();
00546     save();
00547   }
00548   else
00549   {
00550     delete task;
00551   }
00552   return taskuid;
00553 }
00554 
00555 void TaskView::newSubTask()
00556 {
00557   Task* task = current_item();
00558   if(!task)
00559     return;
00560   newTask(i18n("New Sub Task"), task);
00561   task->setOpen(true);
00562   refresh();
00563 }
00564 
00565 void TaskView::editTask()
00566 {
00567   Task *task = current_item();
00568   if (!task)
00569     return;
00570 
00571   DesktopList desktopList = task->getDesktops();
00572   EditTaskDialog *dialog = new EditTaskDialog(i18n("Edit Task"), true, &desktopList);
00573   dialog->setTask( task->name(),
00574                    task->time(),
00575                    task->sessionTime() );
00576   int result = dialog->exec();
00577   if (result == QDialog::Accepted) {
00578     QString taskName = i18n("Unnamed Task");
00579     if (!dialog->taskName().isEmpty()) {
00580       taskName = dialog->taskName();
00581     }
00582     // setName only does something if the new name is different
00583     task->setName(taskName, _storage);
00584 
00585     // update session time as well if the time was changed
00586     long total, session, totalDiff, sessionDiff;
00587     total = totalDiff = session = sessionDiff = 0;
00588     DesktopList desktopList;
00589     dialog->status( &total, &totalDiff, &session, &sessionDiff, &desktopList);
00590 
00591     if( totalDiff != 0 || sessionDiff != 0)
00592       task->changeTimes( sessionDiff, totalDiff, _storage );
00593 
00594     // If all available desktops are checked, disable auto tracking,
00595     // since it makes no sense to track for every desktop.
00596     if (desktopList.size() == (unsigned int)_desktopTracker->desktopCount())
00597       desktopList.clear();
00598 
00599     task->setDesktopList(desktopList);
00600 
00601     _desktopTracker->registerForDesktops( task, desktopList );
00602 
00603     emit updateButtons();
00604   }
00605   delete dialog;
00606 }
00607 
00608 //void TaskView::addCommentToTask()
00609 //{
00610 //  Task *task = current_item();
00611 //  if (!task)
00612 //    return;
00613 
00614 //  bool ok;
00615 //  QString comment = KLineEditDlg::getText(i18n("Comment"),
00616 //                       i18n("Log comment for task '%1':").arg(task->name()),
00617 //                       QString(), &ok, this);
00618 //  if ( ok )
00619 //    task->addComment( comment, _storage );
00620 //}
00621 
00622 void TaskView::reinstateTask(int completion)
00623 {
00624   Task* task = current_item();
00625   if (task == 0) {
00626     KMessageBox::information(0,i18n("No task selected."));
00627     return;
00628   }
00629 
00630   if (completion<0) completion=0;
00631   if (completion<100)
00632   {
00633     task->setPercentComplete(completion, _storage);
00634     task->setPixmapProgress();
00635     save();
00636     emit updateButtons();
00637   }
00638 }
00639 
00640 void TaskView::deleteTask(bool markingascomplete)
00641 {
00642   Task *task = current_item();
00643   if (task == 0) {
00644     KMessageBox::information(0,i18n("No task selected."));
00645     return;
00646   }
00647 
00648   int response = KMessageBox::Continue;
00649   if (!markingascomplete && _preferences->promptDelete()) {
00650     if (task->childCount() == 0) {
00651       response = KMessageBox::warningContinueCancel( 0,
00652           i18n( "Are you sure you want to delete "
00653           "the task named\n\"%1\" and its entire history?")
00654           .arg(task->name()),
00655           i18n( "Deleting Task"), KStdGuiItem::del());
00656     }
00657     else {
00658       response = KMessageBox::warningContinueCancel( 0,
00659           i18n( "Are you sure you want to delete the task named"
00660           "\n\"%1\" and its entire history?\n"
00661           "NOTE: all its subtasks and their history will also "
00662           "be deleted.").arg(task->name()),
00663           i18n( "Deleting Task"), KStdGuiItem::del());
00664     }
00665   }
00666 
00667   if (response == KMessageBox::Continue)
00668   {
00669     if (markingascomplete)
00670     {
00671       task->setPercentComplete(100, _storage);
00672       task->setPixmapProgress();
00673       save();
00674       emit updateButtons();
00675 
00676       // Have to remove after saving, as the save routine only affects tasks
00677       // that are in the view.  Otherwise, the new percent complete does not
00678       // get saved.   (No longer remove when marked as complete.)
00679       //task->removeFromView();
00680 
00681     }
00682     else
00683     {
00684       QString uid=task->uid();
00685       task->remove(activeTasks, _storage);
00686       task->removeFromView();
00687       if( _preferences ) _preferences->deleteEntry( uid ); // forget if the item was expanded or collapsed
00688       save();
00689     }
00690 
00691     // remove root decoration if there is no more children.
00692     refresh();
00693 
00694     // Stop idle detection if no more counters are running
00695     if (activeTasks.count() == 0) {
00696       _idleTimeDetector->stopIdleDetection();
00697       emit timersInactive();
00698     }
00699 
00700     emit tasksChanged( activeTasks );
00701   }
00702 }
00703 
00704 void TaskView::extractTime(int minutes)
00705 // This procedure subtracts ''minutes'' from the active task's time in the memory.
00706 // It is called by the idletimedetector class.
00707 // When the desktop has been idle for the past 20 minutes, the past 20 minutes have 
00708 // already been added to the task's time in order for the time to be displayed correctly.
00709 // That is why idletimedetector needs to subtract this time first.
00710 {
00711   kdDebug(5970) << "Entering extractTime" << endl;
00712   addTimeToActiveTasks(-minutes,false); // subtract minutes, but do not store it
00713 }
00714 
00715 void TaskView::autoSaveChanged(bool on)
00716 {
00717   if (on) _autoSaveTimer->start(_preferences->autoSavePeriod()*1000*secsPerMinute);
00718   else if (_autoSaveTimer->isActive()) _autoSaveTimer->stop();
00719 }
00720 
00721 void TaskView::autoSavePeriodChanged(int /*minutes*/)
00722 {
00723   autoSaveChanged(_preferences->autoSave());
00724 }
00725 
00726 void TaskView::adaptColumns()
00727 {
00728   // to hide a column X we set it's width to 0
00729   // at that moment we'll remember the original column within
00730   // previousColumnWidths[X]
00731   //
00732   // When unhiding a previously hidden column
00733   // (previousColumnWidths[X] != HIDDEN_COLUMN !)
00734   // we restore it's width from the saved value and set
00735   // previousColumnWidths[X] to HIDDEN_COLUMN
00736 
00737   for( int x=1; x <= 4; x++) {
00738     // the column was invisible before and were switching it on now
00739     if(   _preferences->displayColumn(x-1)
00740        && previousColumnWidths[x-1] != HIDDEN_COLUMN )
00741     {
00742       setColumnWidth( x, previousColumnWidths[x-1] );
00743       previousColumnWidths[x-1] = HIDDEN_COLUMN;
00744       setColumnWidthMode( x, QListView::Maximum );
00745     }
00746     // the column was visible before and were switching it off now
00747     else
00748     if( ! _preferences->displayColumn(x-1)
00749        && previousColumnWidths[x-1] == HIDDEN_COLUMN )
00750     {
00751       setColumnWidthMode( x, QListView::Manual ); // we don't want update()
00752                                                   // to resize/unhide the col
00753       previousColumnWidths[x-1] = columnWidth( x );
00754       setColumnWidth( x, 0 );
00755     }
00756   }
00757 }
00758 
00759 void TaskView::deletingTask(Task* deletedTask)
00760 {
00761   DesktopList desktopList;
00762 
00763   _desktopTracker->registerForDesktops( deletedTask, desktopList );
00764   activeTasks.removeRef( deletedTask );
00765 
00766   emit tasksChanged( activeTasks);
00767 }
00768 
00769 void TaskView::iCalFileChanged(QString file)
00770 // User might have picked a new file in the preferences dialog.
00771 // This is not iCalFileModified.
00772 {
00773   kdDebug(5970) << "TaskView:iCalFileChanged: " << file << endl;
00774   if (_storage->icalfile() != file)
00775   {
00776     stopAllTimers();
00777     _storage->save(this);
00778     load();
00779   }
00780 }
00781 
00782 QValueList<HistoryEvent> TaskView::getHistory(const QDate& from,
00783     const QDate& to) const
00784 {
00785   return _storage->getHistory(from, to);
00786 }
00787 
00788 void TaskView::markTaskAsComplete()
00789 {
00790   if (current_item())
00791     kdDebug(5970) << "TaskView::markTaskAsComplete: "
00792       << current_item()->uid() << endl;
00793   else
00794     kdDebug(5970) << "TaskView::markTaskAsComplete: null current_item()" << endl;
00795 
00796   bool markingascomplete = true;
00797   deleteTask(markingascomplete);
00798 }
00799 
00800 void TaskView::markTaskAsIncomplete()
00801 {
00802   if (current_item())
00803     kdDebug(5970) << "TaskView::markTaskAsComplete: "
00804       << current_item()->uid() << endl;
00805   else
00806     kdDebug(5970) << "TaskView::markTaskAsComplete: null current_item()" << endl;
00807 
00808   reinstateTask(50); // if it has been reopened, assume half-done
00809 }
00810 
00811 
00812 void TaskView::clipTotals()
00813 {
00814   TimeKard t;
00815   if (current_item() && current_item()->isRoot())
00816   {
00817     int response = KMessageBox::questionYesNo( 0,
00818         i18n("Copy totals for just this task and its subtasks, or copy totals for all tasks?"),
00819         i18n("Copy Totals to Clipboard"),
00820         i18n("Copy This Task"), i18n("Copy All Tasks") );
00821     if (response == KMessageBox::Yes) // This task only
00822     {
00823       KApplication::clipboard()->setText(t.totalsAsText(this, true, TimeKard::TotalTime));
00824     }
00825     else // All tasks
00826     {
00827       KApplication::clipboard()->setText(t.totalsAsText(this, false, TimeKard::TotalTime));
00828     }
00829   }
00830   else
00831   {
00832     KApplication::clipboard()->setText(t.totalsAsText(this, true, TimeKard::TotalTime));
00833   }
00834 }
00835 
00836 void TaskView::clipSession()
00837 {
00838   TimeKard t;
00839   if (current_item() && current_item()->isRoot())
00840   {
00841     int response = KMessageBox::questionYesNo( 0,
00842         i18n("Copy session time for just this task and its subtasks, or copy session time for all tasks?"),
00843         i18n("Copy Session Time to Clipboard"),
00844         i18n("Copy This Task"), i18n("Copy All Tasks") );
00845     if (response == KMessageBox::Yes) // this task only
00846     {
00847       KApplication::clipboard()->setText(t.totalsAsText(this, true, TimeKard::SessionTime));
00848     }
00849     else // only task
00850     {
00851       KApplication::clipboard()->setText(t.totalsAsText(this, false, TimeKard::SessionTime));
00852     }
00853   }
00854   else
00855   {
00856     KApplication::clipboard()->setText(t.totalsAsText(this, true, TimeKard::SessionTime));
00857   }
00858 }
00859 
00860 void TaskView::clipHistory()
00861 {
00862   PrintDialog dialog;
00863   if (dialog.exec()== QDialog::Accepted)
00864   {
00865     TimeKard t;
00866     KApplication::clipboard()->
00867       setText( t.historyAsText(this, dialog.from(), dialog.to(), !dialog.allTasks(), dialog.perWeek(), dialog.totalsOnly() ) );
00868   }
00869 }
00870 
00871 #include "taskview.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys