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