00001
00002 #include "kaccelmenuwatch.h"
00003 #include "karm_part.h"
00004 #include "karmerrors.h"
00005 #include "task.h"
00006 #include "preferences.h"
00007 #include "tray.h"
00008 #include "version.h"
00009 #include <kaccel.h>
00010
00011 #include <kinstance.h>
00012 #include <kaction.h>
00013 #include <kstdaction.h>
00014 #include <kfiledialog.h>
00015 #include <kglobal.h>
00016 #include <klocale.h>
00017
00018 #include <qfile.h>
00019 #include <qtextstream.h>
00020 #include <qmultilineedit.h>
00021 #include <qpopupmenu.h>
00022 #include "mainwindow.h"
00023
00024 karmPart::karmPart( QWidget *parentWidget, const char *widgetName,
00025 QObject *parent, const char *name )
00026 : DCOPObject ( "KarmDCOPIface" ), KParts::ReadWritePart(parent, name),
00027 _accel ( new KAccel( parentWidget ) ),
00028 _watcher ( new KAccelMenuWatch( _accel, parentWidget ) )
00029 {
00030
00031 setInstance( karmPartFactory::instance() );
00032
00033
00034 _taskView = new TaskView( parentWidget, widgetName );
00035
00036
00037 _preferences = Preferences::instance();
00038
00039
00040 setWidget(_taskView);
00041
00042
00043 KStdAction::open(this, SLOT(fileOpen()), actionCollection());
00044 KStdAction::saveAs(this, SLOT(fileSaveAs()), actionCollection());
00045 KStdAction::save(this, SLOT(save()), actionCollection());
00046
00047 makeMenus();
00048
00049 _watcher->updateMenus();
00050
00051
00052
00053 connect( _taskView, SIGNAL( totalTimesChanged( long, long ) ),
00054 this, SLOT( updateTime( long, long ) ) );
00055 connect( _taskView, SIGNAL( selectionChanged ( QListViewItem * )),
00056 this, SLOT(slotSelectionChanged()));
00057 connect( _taskView, SIGNAL( updateButtons() ),
00058 this, SLOT(slotSelectionChanged()));
00059
00060
00061 connect( _taskView,
00062 SIGNAL( contextMenuRequested( QListViewItem*, const QPoint&, int )),
00063 this,
00064 SLOT( contextMenuRequest( QListViewItem*, const QPoint&, int )));
00065
00066 _tray = new KarmTray( this );
00067
00068 connect( _tray, SIGNAL( quitSelected() ), SLOT( quit() ) );
00069
00070 connect( _taskView, SIGNAL( timersActive() ), _tray, SLOT( startClock() ) );
00071 connect( _taskView, SIGNAL( timersActive() ), this, SLOT( enableStopAll() ));
00072 connect( _taskView, SIGNAL( timersInactive() ), _tray, SLOT( stopClock() ) );
00073 connect( _taskView, SIGNAL( timersInactive() ), this, SLOT( disableStopAll()));
00074 connect( _taskView, SIGNAL( tasksChanged( QPtrList<Task> ) ),
00075 _tray, SLOT( updateToolTip( QPtrList<Task> ) ));
00076
00077 _taskView->load();
00078
00079
00080
00081 _preferences->emitSignals();
00082 slotSelectionChanged();
00083
00084
00085 setXMLFile("karmui.rc");
00086
00087
00088 setReadWrite(true);
00089
00090
00091 setModified(false);
00092 }
00093
00094 karmPart::~karmPart()
00095 {
00096 }
00097
00098 void karmPart::slotSelectionChanged()
00099 {
00100 Task* item= _taskView->current_item();
00101 actionDelete->setEnabled(item);
00102 actionEdit->setEnabled(item);
00103 actionStart->setEnabled(item && !item->isRunning() && !item->isComplete());
00104 actionStop->setEnabled(item && item->isRunning());
00105 actionMarkAsComplete->setEnabled(item && !item->isComplete());
00106 actionMarkAsIncomplete->setEnabled(item && item->isComplete());
00107 }
00108
00109 void karmPart::makeMenus()
00110 {
00111 KAction
00112 *actionKeyBindings,
00113 *actionNew,
00114 *actionNewSub;
00115
00116 (void) KStdAction::quit( this, SLOT( quit() ), actionCollection());
00117 (void) KStdAction::print( this, SLOT( print() ), actionCollection());
00118 actionKeyBindings = KStdAction::keyBindings( this, SLOT( keyBindings() ),
00119 actionCollection() );
00120 actionPreferences = KStdAction::preferences(_preferences,
00121 SLOT(showDialog()),
00122 actionCollection() );
00123 (void) KStdAction::save( this, SLOT( save() ), actionCollection() );
00124 KAction* actionStartNewSession = new KAction( i18n("Start &New Session"),
00125 0,
00126 this,
00127 SLOT( startNewSession() ),
00128 actionCollection(),
00129 "start_new_session");
00130 KAction* actionResetAll = new KAction( i18n("&Reset All Times"),
00131 0,
00132 this,
00133 SLOT( resetAllTimes() ),
00134 actionCollection(),
00135 "reset_all_times");
00136 actionStart = new KAction( i18n("&Start"),
00137 QString::fromLatin1("1rightarrow"), Key_S,
00138 _taskView,
00139 SLOT( startCurrentTimer() ), actionCollection(),
00140 "start");
00141 actionStop = new KAction( i18n("S&top"),
00142 QString::fromLatin1("stop"), 0,
00143 _taskView,
00144 SLOT( stopCurrentTimer() ), actionCollection(),
00145 "stop");
00146 actionStopAll = new KAction( i18n("Stop &All Timers"),
00147 Key_Escape,
00148 _taskView,
00149 SLOT( stopAllTimers() ), actionCollection(),
00150 "stopAll");
00151 actionStopAll->setEnabled(false);
00152
00153 actionNew = new KAction( i18n("&New..."),
00154 QString::fromLatin1("filenew"), CTRL+Key_N,
00155 _taskView,
00156 SLOT( newTask() ), actionCollection(),
00157 "new_task");
00158 actionNewSub = new KAction( i18n("New &Subtask..."),
00159 QString::fromLatin1("kmultiple"), CTRL+ALT+Key_N,
00160 _taskView,
00161 SLOT( newSubTask() ), actionCollection(),
00162 "new_sub_task");
00163 actionDelete = new KAction( i18n("&Delete"),
00164 QString::fromLatin1("editdelete"), Key_Delete,
00165 _taskView,
00166 SLOT( deleteTask() ), actionCollection(),
00167 "delete_task");
00168 actionEdit = new KAction( i18n("&Edit..."),
00169 QString::fromLatin1("edit"), CTRL + Key_E,
00170 _taskView,
00171 SLOT( editTask() ), actionCollection(),
00172 "edit_task");
00173
00174
00175
00176
00177
00178
00179
00180 actionMarkAsComplete = new KAction( i18n("&Mark as Complete"),
00181 QString::fromLatin1("document"),
00182 CTRL+Key_M,
00183 _taskView,
00184 SLOT( markTaskAsComplete() ),
00185 actionCollection(),
00186 "mark_as_complete");
00187 actionMarkAsIncomplete = new KAction( i18n("&Mark as Incomplete"),
00188 QString::fromLatin1("document"),
00189 CTRL+Key_M,
00190 _taskView,
00191 SLOT( markTaskAsIncomplete() ),
00192 actionCollection(),
00193 "mark_as_incomplete");
00194 actionClipTotals = new KAction( i18n("&Copy Totals to Clipboard"),
00195 QString::fromLatin1("klipper"),
00196 CTRL+Key_C,
00197 _taskView,
00198 SLOT( clipTotals() ),
00199 actionCollection(),
00200 "clip_totals");
00201 actionClipHistory = new KAction( i18n("Copy &History to Clipboard"),
00202 QString::fromLatin1("klipper"),
00203 CTRL+ALT+Key_C,
00204 _taskView,
00205 SLOT( clipHistory() ),
00206 actionCollection(),
00207 "clip_history");
00208
00209 new KAction( i18n("Import &Legacy Flat File..."), 0,
00210 _taskView, SLOT(loadFromFlatFile()), actionCollection(),
00211 "import_flatfile");
00212 new KAction( i18n("&Export to CSV File..."), 0,
00213 _taskView, SLOT(exportcsvFile()), actionCollection(),
00214 "export_csvfile");
00215 new KAction( i18n("Export &History to CSV File..."), 0,
00216 this, SLOT(exportcsvHistory()), actionCollection(),
00217 "export_csvhistory");
00218 new KAction( i18n("Import Tasks From &Planner..."), 0,
00219 _taskView, SLOT(importPlanner()), actionCollection(),
00220 "import_planner");
00221 new KAction( i18n("Configure KArm..."), 0,
00222 _preferences, SLOT(showDialog()), actionCollection(),
00223 "configure_karm");
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233 actionKeyBindings->setToolTip( i18n("Configure key bindings") );
00234 actionKeyBindings->setWhatsThis( i18n("This will let you configure key"
00235 "bindings which is specific to karm") );
00236
00237 actionStartNewSession->setToolTip( i18n("Start a new session") );
00238 actionStartNewSession->setWhatsThis( i18n("This will reset the session time "
00239 "to 0 for all tasks, to start a "
00240 "new session, without affecting "
00241 "the totals.") );
00242 actionResetAll->setToolTip( i18n("Reset all times") );
00243 actionResetAll->setWhatsThis( i18n("This will reset the session and total "
00244 "time to 0 for all tasks, to restart from "
00245 "scratch.") );
00246
00247 actionStart->setToolTip( i18n("Start timing for selected task") );
00248 actionStart->setWhatsThis( i18n("This will start timing for the selected "
00249 "task.\n"
00250 "It is even possible to time several tasks "
00251 "simultaneously.\n\n"
00252 "You may also start timing of a tasks by "
00253 "double clicking the left mouse "
00254 "button on a given task. This will, however, "
00255 "stop timing of other tasks."));
00256
00257 actionStop->setToolTip( i18n("Stop timing of the selected task") );
00258 actionStop->setWhatsThis( i18n("Stop timing of the selected task") );
00259
00260 actionStopAll->setToolTip( i18n("Stop all of the active timers") );
00261 actionStopAll->setWhatsThis( i18n("Stop all of the active timers") );
00262
00263 actionNew->setToolTip( i18n("Create new top level task") );
00264 actionNew->setWhatsThis( i18n("This will create a new top level task.") );
00265
00266 actionDelete->setToolTip( i18n("Delete selected task") );
00267 actionDelete->setWhatsThis( i18n("This will delete the selected task and "
00268 "all its subtasks.") );
00269
00270 actionEdit->setToolTip( i18n("Edit name or times for selected task") );
00271 actionEdit->setWhatsThis( i18n("This will bring up a dialog box where you "
00272 "may edit the parameters for the selected "
00273 "task."));
00274
00275
00276
00277
00278
00279
00280 actionClipTotals->setToolTip(i18n("Copy task totals to clipboard"));
00281 actionClipHistory->setToolTip(i18n("Copy time card history to clipboard."));
00282
00283 slotSelectionChanged();
00284 }
00285
00286 void karmPart::setReadWrite(bool rw)
00287 {
00288
00289 if (rw)
00290 connect(_taskView, SIGNAL(textChanged()),
00291 this, SLOT(setModified()));
00292 else
00293 {
00294 disconnect(_taskView, SIGNAL(textChanged()),
00295 this, SLOT(setModified()));
00296 }
00297
00298 ReadWritePart::setReadWrite(rw);
00299 }
00300
00301 void karmPart::setModified(bool modified)
00302 {
00303
00304 KAction *save = actionCollection()->action(KStdAction::stdName(KStdAction::Save));
00305 if (!save)
00306 return;
00307
00308
00309
00310 if (modified)
00311 save->setEnabled(true);
00312 else
00313 save->setEnabled(false);
00314
00315
00316 ReadWritePart::setModified(modified);
00317 }
00318
00319 bool karmPart::openFile()
00320 {
00321
00322 _taskView->load(m_file);
00323
00324
00325 emit setStatusBarText( m_url.prettyURL() );
00326
00327 return true;
00328 }
00329
00330 bool karmPart::saveFile()
00331 {
00332
00333 if (isReadWrite() == false)
00334 return false;
00335
00336
00337 QFile file(m_file);
00338 if (file.open(IO_WriteOnly) == false)
00339 return false;
00340
00341
00342 QTextStream stream(&file);
00343
00344 file.close();
00345
00346 return true;
00347 }
00348
00349 void karmPart::fileOpen()
00350 {
00351
00352
00353
00354 QString file_name = KFileDialog::getOpenFileName();
00355
00356 if (file_name.isEmpty() == false)
00357 openURL(file_name);
00358 }
00359
00360 void karmPart::fileSaveAs()
00361 {
00362
00363 QString file_name = KFileDialog::getSaveFileName();
00364 if (file_name.isEmpty() == false)
00365 saveAs(file_name);
00366 }
00367
00368
00369
00370
00371 #include <kaboutdata.h>
00372 #include <klocale.h>
00373
00374 KInstance* karmPartFactory::s_instance = 0L;
00375 KAboutData* karmPartFactory::s_about = 0L;
00376
00377 karmPartFactory::karmPartFactory()
00378 : KParts::Factory()
00379 {
00380 }
00381
00382 karmPartFactory::~karmPartFactory()
00383 {
00384 delete s_instance;
00385 delete s_about;
00386
00387 s_instance = 0L;
00388 }
00389
00390 KParts::Part* karmPartFactory::createPartObject( QWidget *parentWidget, const char *widgetName,
00391 QObject *parent, const char *name,
00392 const char *classname, const QStringList &args )
00393 {
00394
00395 karmPart* obj = new karmPart( parentWidget, widgetName, parent, name );
00396
00397
00398 if (QCString(classname) == "KParts::ReadOnlyPart")
00399 obj->setReadWrite(false);
00400
00401 return obj;
00402 }
00403
00404 KInstance* karmPartFactory::instance()
00405 {
00406 if( !s_instance )
00407 {
00408 s_about = new KAboutData("karmpart", I18N_NOOP("karmPart"), "0.1");
00409 s_about->addAuthor("Thorsten Staerk", 0, "thorsten@staerk.de");
00410 s_instance = new KInstance(s_about);
00411 }
00412 return s_instance;
00413 }
00414
00415 extern "C"
00416 {
00417 KDE_EXPORT void* init_libkarmpart()
00418 {
00419 KGlobal::locale()->insertCatalogue("karm");
00420 return new karmPartFactory;
00421 }
00422 }
00423
00424 void karmPart::contextMenuRequest( QListViewItem*, const QPoint& point, int )
00425 {
00426 QPopupMenu* pop = dynamic_cast<QPopupMenu*>(
00427 factory()->container( i18n( "task_popup" ), this ) );
00428 if ( pop )
00429 pop->popup( point );
00430 }
00431
00432
00433
00434
00435
00436
00437
00438 QString karmPart::version() const
00439 {
00440 return KARM_VERSION;
00441 }
00442
00443 QString karmPart::deletetodo()
00444 {
00445 _taskView->deleteTask();
00446 return "";
00447 }
00448
00449 bool karmPart::getpromptdelete()
00450 {
00451 return _preferences->promptDelete();
00452 }
00453
00454 QString karmPart::setpromptdelete( bool prompt )
00455 {
00456 _preferences->setPromptDelete( prompt );
00457 return "";
00458 }
00459
00460 QString karmPart::taskIdFromName( const QString &taskname ) const
00461 {
00462 QString rval = "";
00463
00464 Task* task = _taskView->first_child();
00465 while ( rval.isEmpty() && task )
00466 {
00467 rval = _hasTask( task, taskname );
00468 task = task->nextSibling();
00469 }
00470
00471 return rval;
00472 }
00473
00474 void karmPart::quit()
00475 {
00476
00477 }
00478
00479 bool karmPart::save()
00480 {
00481 kdDebug(5970) << "Saving time data to disk." << endl;
00482 QString err=_taskView->save();
00483
00484
00485
00486 return true;
00487 }
00488
00489 int karmPart::addTask( const QString& taskname )
00490 {
00491 DesktopList desktopList;
00492 QString uid = _taskView->addTask( taskname, 0, 0, desktopList );
00493 kdDebug(5970) << "MainWindow::addTask( " << taskname << " ) returns " << uid << endl;
00494 if ( uid.length() > 0 ) return 0;
00495 else
00496 {
00497
00498
00499 return KARM_ERR_GENERIC_SAVE_FAILED;
00500 }
00501 }
00502
00503 QString karmPart::setPerCentComplete( const QString& taskName, int perCent )
00504 {
00505 int index;
00506 QString err="no such task";
00507 for (int i=0; i<_taskView->count(); i++)
00508 {
00509 if ((_taskView->item_at_index(i)->name()==taskName))
00510 {
00511 index=i;
00512 if (err==QString::null) err="task name is abigious";
00513 if (err=="no such task") err=QString::null;
00514 }
00515 }
00516 if (err==QString::null)
00517 {
00518 _taskView->item_at_index(index)->setPercentComplete( perCent, _taskView->storage() );
00519 }
00520 return err;
00521 }
00522
00523 int karmPart::bookTime
00524 ( const QString& taskId, const QString& datetime, long minutes )
00525 {
00526 int rval = 0;
00527 QDate startDate;
00528 QTime startTime;
00529 QDateTime startDateTime;
00530 Task *task, *t;
00531
00532 if ( minutes <= 0 ) rval = KARM_ERR_INVALID_DURATION;
00533
00534
00535 task = _taskView->first_child();
00536 t = NULL;
00537 while ( !t && task )
00538 {
00539 t = _hasUid( task, taskId );
00540 task = task->nextSibling();
00541 }
00542 if ( t == NULL ) rval = KARM_ERR_UID_NOT_FOUND;
00543
00544
00545 if ( !rval )
00546 {
00547 startDate = QDate::fromString( datetime, Qt::ISODate );
00548 if ( datetime.length() > 10 )
00549 {
00550 startTime = QTime::fromString( datetime, Qt::ISODate );
00551 }
00552 else startTime = QTime( 12, 0 );
00553 if ( startDate.isValid() && startTime.isValid() )
00554 {
00555 startDateTime = QDateTime( startDate, startTime );
00556 }
00557 else rval = KARM_ERR_INVALID_DATE;
00558
00559 }
00560
00561
00562 if ( !rval )
00563 {
00564 t->changeTotalTimes( t->sessionTime() + minutes, t->totalTime() + minutes );
00565 if ( ! _taskView->storage()->bookTime( t, startDateTime, minutes * 60 ) )
00566 {
00567 rval = KARM_ERR_GENERIC_SAVE_FAILED;
00568 }
00569 }
00570
00571 return rval;
00572 }
00573
00574
00575
00576 QString karmPart::getError( int mkb ) const
00577 {
00578 if ( mkb <= KARM_MAX_ERROR_NO ) return m_error[ mkb ];
00579 else return i18n( "Invalid error number: %1" ).arg( mkb );
00580 }
00581
00582 int karmPart::totalMinutesForTaskId( const QString& taskId )
00583 {
00584 int rval = 0;
00585 Task *task, *t;
00586
00587 kdDebug(5970) << "MainWindow::totalTimeForTask( " << taskId << " )" << endl;
00588
00589
00590 task = _taskView->first_child();
00591 t = NULL;
00592 while ( !t && task )
00593 {
00594 t = _hasUid( task, taskId );
00595 task = task->nextSibling();
00596 }
00597 if ( t != NULL )
00598 {
00599 rval = t->totalTime();
00600 kdDebug(5970) << "MainWindow::totalTimeForTask - task found: rval = " << rval << endl;
00601 }
00602 else
00603 {
00604 kdDebug(5970) << "MainWindow::totalTimeForTask - task not found" << endl;
00605 rval = KARM_ERR_UID_NOT_FOUND;
00606 }
00607
00608 return rval;
00609 }
00610
00611 QString karmPart::_hasTask( Task* task, const QString &taskname ) const
00612 {
00613 QString rval = "";
00614 if ( task->name() == taskname )
00615 {
00616 rval = task->uid();
00617 }
00618 else
00619 {
00620 Task* nexttask = task->firstChild();
00621 while ( rval.isEmpty() && nexttask )
00622 {
00623 rval = _hasTask( nexttask, taskname );
00624 nexttask = nexttask->nextSibling();
00625 }
00626 }
00627 return rval;
00628 }
00629
00630 Task* karmPart::_hasUid( Task* task, const QString &uid ) const
00631 {
00632 Task *rval = NULL;
00633
00634
00635
00636 if ( task->uid() == uid ) rval = task;
00637 else
00638 {
00639 Task* nexttask = task->firstChild();
00640 while ( !rval && nexttask )
00641 {
00642 rval = _hasUid( nexttask, uid );
00643 nexttask = nexttask->nextSibling();
00644 }
00645 }
00646 return rval;
00647 }
00648
00649 QString karmPart::starttimerfor( const QString& taskname )
00650 {
00651 QString err="no such task";
00652 for (int i=0; i<_taskView->count(); i++)
00653 {
00654 if ((_taskView->item_at_index(i)->name()==taskname))
00655 {
00656 _taskView->startTimerFor( _taskView->item_at_index(i) );
00657 err="";
00658 }
00659 }
00660 return err;
00661 }
00662
00663 QString karmPart::stoptimerfor( const QString& taskname )
00664 {
00665 QString err="no such task";
00666 for (int i=0; i<_taskView->count(); i++)
00667 {
00668 if ((_taskView->item_at_index(i)->name()==taskname))
00669 {
00670 _taskView->stopTimerFor( _taskView->item_at_index(i) );
00671 err="";
00672 }
00673 }
00674 return err;
00675 }
00676
00677 QString karmPart::exportcsvfile( QString filename, QString from, QString to, int type, bool decimalMinutes, bool allTasks, QString delimiter, QString quote )
00678 {
00679 ReportCriteria rc;
00680 rc.allTasks=allTasks;
00681 rc.decimalMinutes=decimalMinutes;
00682 rc.delimiter=delimiter;
00683 rc.from=QDate::fromString( from );
00684 rc.quote=quote;
00685 rc.reportType=(ReportCriteria::REPORTTYPE) type;
00686 rc.to=QDate::fromString( to );
00687 rc.url=filename;
00688 return _taskView->report( rc );
00689 }
00690
00691 QString karmPart::importplannerfile( QString fileName )
00692 {
00693 return _taskView->importPlanner(fileName);
00694 }
00695
00696 void karmPart::startNewSession()
00697 {
00698 _taskView->startNewSession();
00699 _taskView->save();
00700 }
00701
00702 #include <qpopupmenu.h>
00703 #include "karm_part.moc"