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