27 #include <QDBusConnection>
29 #include <QHBoxLayout>
31 #include <QKeySequence>
33 #include <QVBoxLayout>
36 #include <KApplication>
38 #include <KActionCollection>
40 #include <KConfigDialog>
42 #include <KFileDialog>
46 #include <KMessageBox>
47 #include <KRecentFilesAction>
48 #include <KStandardAction>
50 #include <KTemporaryFile>
51 #include <KTreeWidgetSearchLine>
59 #include "mainadaptor.h"
63 #include "kdepim-version.h"
67 class TimetrackerWidget::Private
74 KTreeWidgetSearchLine *mSearchWidget;
76 QMap<QString, KAction*> mActions;
85 const char* whatsThis;
93 kDebug(5970) <<
"Entering function";
94 new MainAdaptor(
this );
95 QDBusConnection::sessionBus().registerObject(
"/KTimeTracker",
this );
97 QLayout *layout =
new QVBoxLayout;
98 layout->setMargin( 0 );
99 layout->setSpacing( 0 );
101 QLayout *innerLayout =
new QHBoxLayout;
102 d->mSearchLine =
new QWidget(
this );
103 innerLayout->setMargin( KDialog::marginHint() );
104 innerLayout->setSpacing( KDialog::spacingHint() );
105 d->mSearchWidget =
new KTreeWidgetSearchLine( d->mSearchLine );
106 d->mSearchWidget->setClickMessage( i18n(
"Search or add task" ) );
107 d->mSearchWidget->setWhatsThis( i18n(
"This is a combined field. As long as you do not type ENTER, it acts as a filter. Then, only tasks that match your input are shown. As soon as you type ENTER, your input is used as name to create a new task." ) );
108 d->mSearchWidget->installEventFilter(
this );
109 innerLayout->addWidget( d->mSearchWidget );
110 d->mSearchLine->setLayout( innerLayout );
112 d->mTaskView =
new TaskView(
this );
113 layout->addWidget( d->mSearchLine );
114 layout->addWidget( d->mTaskView );
132 kDebug(5970) <<
"Entering function";
133 if ( d->mSearchWidget->isVisible() ) d->mSearchWidget->setFocus();
137 void TimetrackerWidget::addTaskView(
const QString &fileName )
139 kDebug(5970) <<
"Entering function (fileName=" << fileName <<
")";
140 bool isNew = fileName.isEmpty();
141 QString lFileName = fileName;
145 KTemporaryFile tempFile;
146 tempFile.setAutoRemove(
false );
147 if ( tempFile.open() )
149 lFileName = tempFile.fileName();
154 KMessageBox::error(
this, i18n(
"Cannot create new file." ) );
171 taskView->
load( lFileName );
172 d->mSearchWidget->addTreeWidget( taskView );
178 slotCurrentChanged();
184 return qobject_cast<
TaskView* >( d->mTaskView );
202 d->mActions.insert (
"file_open",
203 KStandardAction::open(
this, SLOT(
openFile()), actionCollection ) );
204 d->mActions.insert (
"file_save",
205 KStandardAction::save(
this, SLOT(
saveFile()), actionCollection ) );
206 d->mActions.insert (
"file_quit",
207 KStandardAction::quit(
this, SLOT(
quit()), actionCollection ) );
208 d->mActions.insert (
"configure_ktimetracker",
209 KStandardAction::preferences(
this, SLOT(showSettingsDialog()),
210 actionCollection ) );
212 Private::ActionData actions[] =
215 "start_new_session", I18N_NOOP(
"Starts a new session"), I18N_NOOP(
"This will reset the "
216 "session time to 0 for all tasks, to start a new session, without "
217 "affecting the totals.")
219 {
"view-history", I18N_NOOP(
"Edit History..."), SLOT(
editHistory()),
"edit_history",
220 I18N_NOOP(
"Edits history of all tasks of the current document"), I18N_NOOP(
"A window will "
221 "be opened where you can change start and stop times of tasks or add a "
224 { QString(), I18N_NOOP(
"&Reset All Times"), SLOT(
resetAllTimes()),
225 "reset_all_times", I18N_NOOP(
"Resets all times"), I18N_NOOP(
"This will reset the session "
226 "and total time to 0 for all tasks, to restart from scratch.")
228 {
"media-playback-start", I18N_NOOP(
"&Start"), SLOT(
startCurrentTimer()),
"start",
229 I18N_NOOP(
"Starts timing for selected task"), I18N_NOOP(
"This will start timing for the "
230 "selected task.\nIt is even possible to time several tasks "
231 "simultanously.\n\nYou may also start timing of tasks by double clicking "
232 "the left mouse button on a given task. This will, however, stop timing "
235 {
"media-playback-stop", I18N_NOOP(
"S&top"), SLOT(
stopCurrentTimer()),
"stop",
236 I18N_NOOP(
"Stops timing of the selected task"), I18N_NOOP(
"Stops timing of the selected task")
238 { QString(), I18N_NOOP(
"Focus on Searchbar"), SLOT(
focusSearchBar()),
"focusSearchBar",
239 I18N_NOOP(
"Sets the focus on the searchbar"), I18N_NOOP(
"Sets the focus on the searchbar")
241 { QString(), I18N_NOOP(
"Stop &All Timers"), SLOT(
stopAllTimers()),
"stopAll",
242 I18N_NOOP(
"Stops all of the active timers"), I18N_NOOP(
"Stops all of the active timers")
244 { QString(), I18N_NOOP(
"Track Active Applications"), SLOT(
focusTracking()),
245 "focustracking", I18N_NOOP(
"Auto-creates and updates tasks when the focus of the "
246 "current window has changed"), I18N_NOOP(
"If the focus of a window changes for the "
247 "first time when this action is enabled, a new task will be created "
248 "with the title of the window as its name and will be started. If there "
249 "already exists such an task it will be started.")
254 {
"document-new", I18N_NOOP(
"&New Task..."), SLOT(
newTask()),
"new_task", I18N_NOOP(
"Creates "
255 "new top level task"), I18N_NOOP(
"This will create a new top level task.")
257 {
"subtask-new-ktimetracker", I18N_NOOP(
"New &Subtask..."), SLOT(
newSubTask()),
258 "new_sub_task", I18N_NOOP(
"Creates a new subtask to the current selected task"),
259 I18N_NOOP(
"This will create a new subtask to the current selected task.")
261 {
"edit-delete", I18N_NOOP(
"&Delete"), SLOT(
deleteTask()),
"delete_task", I18N_NOOP(
"Deletes "
262 "selected task"), I18N_NOOP(
"This will delete the selected task(s) and all "
265 {
"document-properties", I18N_NOOP(
"&Edit..."), SLOT(
editTask()),
"edit_task",
266 I18N_NOOP(
"Edits name or times for selected task"), I18N_NOOP(
"This will bring up a dialog "
267 "box where you may edit the parameters for the selected task.")
270 "mark_as_complete",
"",
""
273 "mark_as_incomplete",
"",
""
275 { QString(), I18N_NOOP(
"&Export Times..."), SLOT(
exportcsvFile()),
"export_times",
279 "export_history",
"",
""
281 { QString(), I18N_NOOP(
"Import Tasks From &Planner..."), SLOT(
importPlanner()),
282 "import_planner",
"",
""
284 { QString(), I18N_NOOP(
"Show Searchbar"), SLOT(
slotSearchBar()),
"searchbar",
289 for (
unsigned int i = 0; i < (
sizeof( actions ) /
sizeof( Private::ActionData ) ); ++i )
291 Private::ActionData actionData = actions[i];
293 if ( actionData.iconName.isEmpty() )
295 action =
new KAction( i18n( actionData.caption ),
this );
299 action =
new KAction( KIcon( actionData.iconName ),
300 i18n( actionData.caption ),
this );
303 actionCollection->addAction( actionData.name, action );
304 connect( action, SIGNAL(triggered(
bool)), actionData.slot );
305 action->setToolTip( i18n( actionData.toolTip ) );
306 action->setWhatsThis( i18n( actionData.whatsThis ) );
308 d->mActions.insert( actionData.name, action );
312 d->mActions[
"start" ]->setShortcut( QKeySequence( Qt::Key_G) );
313 d->mActions[
"stopAll" ]->setShortcut( QKeySequence( Qt::Key_Escape ) );
314 d->mActions[
"new_task" ]->setShortcut( QKeySequence( Qt::CTRL + Qt::Key_T ) );
315 d->mActions[
"focusSearchBar" ]->setShortcut( QKeySequence( Qt::Key_S ) );
316 d->mActions[
"new_sub_task" ]->setShortcut( QKeySequence( Qt::CTRL + Qt::ALT + Qt::Key_N ) );
317 d->mActions[
"delete_task" ]->setShortcut( QKeySequence( Qt::Key_Delete ) );
318 d->mActions[
"edit_task" ]->setShortcut( QKeySequence( Qt::CTRL + Qt::Key_E ) );
319 d->mActions[
"mark_as_complete" ]->setShortcut( QKeySequence( Qt::CTRL + Qt::Key_M ) );
320 d->mActions[
"mark_as_incomplete" ]->setShortcut( QKeySequence( Qt::CTRL + Qt::Key_M ) );
322 d->mActions[
"mark_as_complete" ]->setIcon( UserIcon(
"task-complete.xpm" ) );
323 d->mActions[
"mark_as_incomplete" ]->setIcon( UserIcon(
"task-incomplete.xpm" ) );
325 d->mActions[
"focustracking" ]->setCheckable(
true );
326 d->mActions[
"searchbar" ]->setCheckable(
true );
331 this, SLOT(slotUpdateButtons()) );
333 this, SLOT(slotUpdateButtons()) );
335 this, SLOT(slotUpdateButtons()) );
340 return d->mActions.value( name );
345 kDebug(5970) <<
"Entering function, fileName is " << fileName;
346 QString newFileName = fileName;
347 if ( newFileName.isEmpty() )
349 newFileName = KFileDialog::getOpenFileName( QString(), QString(),
this );
350 if ( newFileName.isEmpty() )
355 addTaskView( newFileName );
365 kDebug(5970) <<
"Entering TimetrackerWidget::closeFile";
374 d->mSearchWidget->removeTreeWidget( taskView );
378 slotCurrentChanged();
392 d->mSearchLine->setVisible( visible );
397 kDebug(5970) <<
"Entering TimetrackerWidget::closeAllFiles";
401 d->mTaskView->stopAllTimers();
407 void TimetrackerWidget::slotCurrentChanged()
409 kDebug() <<
"entering KTimetrackerWidget::slotCurrentChanged";
414 disconnect( d->mTaskView, SIGNAL(
reSetTimes()) );
415 disconnect( d->mTaskView, SIGNAL(itemSelectionChanged()) );
417 disconnect( d->mTaskView, SIGNAL(setStatusBarText(QString)) );
420 disconnect( d->mTaskView, SIGNAL(
tasksChanged(QList<Task*>)),
427 connect( d->mTaskView, SIGNAL(itemSelectionChanged()),
431 connect( d->mTaskView, SIGNAL(setStatusBarText(QString)),
437 connect( d->mTaskView, SIGNAL(
tasksChanged(QList<Task*>)),
439 emit
setCaption( d->mTaskView->storage()->icalfile() );
441 d->mSearchWidget->setEnabled( d->mTaskView );
445 bool TimetrackerWidget::eventFilter(
QObject *obj, QEvent *event )
447 if ( obj == d->mSearchWidget )
449 if ( event->type() == QEvent::KeyPress )
451 QKeyEvent *keyEvent =
static_cast< QKeyEvent*
>(
event );
452 if ( keyEvent->key() == Qt::Key_Enter ||
453 keyEvent->key() == Qt::Key_Return )
455 if ( !d->mSearchWidget->displayText().isEmpty() ) slotAddTask( d->mSearchWidget->displayText() );
460 return QObject::eventFilter( obj, event );
463 void TimetrackerWidget::slotAddTask(
const QString &taskName )
468 d->mSearchWidget->clear();
471 void TimetrackerWidget::slotUpdateButtons()
473 kDebug(5970) <<
"Entering function";
476 d->mActions[
"start" ]->setEnabled( item && !item->
isRunning() &&
478 d->mActions[
"stop" ]->setEnabled( item && item->
isRunning() );
479 d->mActions[
"delete_task" ]->setEnabled( item );
480 d->mActions[
"edit_task" ]->setEnabled( item );
481 d->mActions[
"mark_as_complete" ]->setEnabled( item && !item->
isComplete() );
482 d->mActions[
"mark_as_incomplete" ]->setEnabled( item && item->
isComplete() );
496 kDebug(5970) <<
"Leaving function";
499 void TimetrackerWidget::showSettingsDialog()
501 kDebug(5970) <<
"Entering function";
589 else KMessageBox::information(0, i18nc(
"@info in message box",
"There is no history yet. Start and stop a task and you will have an entry in your history."));
597 if ( KMessageBox::warningContinueCancel(
this,
598 i18n(
"Do you really want to reset the time to zero for all tasks? This will delete the entire history." ),
599 i18n(
"Confirmation Required" ), KGuiItem( i18n(
"Reset All Times" ) ) ) == KMessageBox::Continue )
607 d->mActions[
"focustracking"]->setChecked(
currentTaskView()->isFocusTrackingActive());
614 d->mActions[
"searchbar" ]->setChecked( !currentVisible );
623 return KDEPIM_VERSION;
631 if ( !taskView )
return result;
632 QTreeWidgetItemIterator it( taskView );
635 Task *task =
static_cast< Task*
>( *it );
636 if ( task && task->
name() == taskName )
638 result << task->
uid();
671 if ( !taskView )
return;
673 QTreeWidgetItemIterator it( taskView );
676 Task *task =
static_cast< Task*
>( *it );
677 if ( task && task->
uid() == taskId )
689 if ( !taskView )
return;
691 QTreeWidgetItemIterator it( taskView );
694 Task *task =
static_cast< Task*
>( *it );
695 if ( task && task->
uid() == taskId )
708 QDateTime startDateTime;
709 Task *task = 0, *t = 0;
719 QTreeWidgetItemIterator it( taskView );
721 t =
static_cast< Task*
>( *it );
722 if ( t && t->uid() == taskId ) {
739 return i18n(
"Save failed, most likely because the file could not be locked." );
741 return i18n(
"Could not modify calendar resource." );
743 return i18n(
"Out of memory--could not create object." );
745 return i18n(
"UID not found." );
747 return i18n(
"Invalidate date--format is YYYY-MM-DD." );
749 return i18n(
"Invalid time--format is YYYY-MM-DDTHH:MM:SS." );
751 return i18n(
"Invalid task duration--must be greater than zero." );
753 return i18n(
"Invalid error number: %1", errorCode );
762 delete idletimedetector1;
769 if ( !taskView )
return -1;
770 QTreeWidgetItemIterator it( taskView );
773 Task *task =
static_cast< Task*
>( *it );
774 if ( task && task->
uid() == taskId )
788 if ( !taskView )
return;
789 QTreeWidgetItemIterator it( taskView );
792 Task *task =
static_cast< Task*
>( *it );
793 if ( task && task->
uid() == taskId )
805 if ( !taskView )
return false;
806 QTreeWidgetItemIterator it( taskView );
809 Task *task =
static_cast< Task*
>( *it );
810 if ( task && task->
name() == taskName )
824 if ( !taskView )
return false;
826 QTreeWidgetItemIterator it( taskView );
829 Task *task =
static_cast< Task*
>( *it );
831 if ( task && task->
name() == taskName )
845 if ( !taskView )
return;
846 QTreeWidgetItemIterator it( taskView );
849 Task *task =
static_cast< Task*
>( *it );
850 if ( task && task->
uid() == taskId )
867 const QString &to,
int type,
870 const QString &delimiter,
871 const QString "e )
875 if ( !taskView )
return "";
878 rc.
from = QDate::fromString( from );
879 if ( rc.
from.isNull() )
880 rc.
from = QDate::fromString( from, Qt::ISODate );
881 rc.
to = QDate::fromString( to );
882 if ( rc.
to.isNull() )
883 rc.
to = QDate::fromString( to, Qt::ISODate );
890 return taskView->
report( rc );
896 if ( !taskView )
return;
903 if ( !taskView )
return false;
904 QTreeWidgetItemIterator it( taskView );
907 Task *task =
static_cast< Task*
>( *it );
909 if ( task && task->
uid() == taskId )
921 if ( !taskView )
return false;
922 QTreeWidgetItemIterator it( taskView );
925 Task *task =
static_cast< Task*
>( *it );
926 if ( task && task->
name() == taskName )
940 if ( !taskView )
return result;
941 QTreeWidgetItemIterator it( taskView );
944 result << static_cast< Task* >( *it )->name();
954 if ( !taskView )
return result;
955 for (
int j = 0; j < taskView->
count(); ++j )
972 if (event->type()==QEvent::QueryWhatsThis)
974 if ( d->mTaskView->count() == 0 )
975 setWhatsThis( i18n(
"This is ktimetracker, KDE's program to help you track your time. Best, start with creating your first task - enter it into the field where you see \"search or add task\".") );
976 else setWhatsThis( i18n(
"You have already created a task. You can now start and stop timing") );
978 return QWidget::event(event);
983 kDebug(5970) <<
"Entering TimetrackerWidget::quit";
991 #include "timetrackerwidget.moc"
QDate from
For history reports, the lower bound of the date range to report on.
void setPercentComplete(const int percent, timetrackerstorage *storage)
Update percent complete for this task.
TaskView * taskView() const
Return task view for this task.
QString quote
The quote to use for text fields when outputting comma-separated reports.
bool isIdleDetectionPossible()
Returns true if it is possible to do idle detection.
QString exportCSVFile(const QString &filename, const QString &from, const QString &to, int type, bool decimalMinutes, bool allTasks, const QString &delimiter, const QString "e)
void importPlannerFile(const QString &filename)
int changeTime(const QString &taskId, int minutes)
bool stopTimerForTaskName(const QString &taskName)
QString error(int errorCode) const
QStringList tasks() const
bool isTaskNameActive(const QString &taskId) const
void toggleFocusTracking()
Toggles the automatic tracking of focused windows.
QString name() const
returns the name of this task.
void editTask()
Calls editTask dialog for the current task.
void importPlanner(const QString &fileName="")
used to import tasks from imendio planner
Task * itemAt(int i)
Return the i'th item (zero-based), cast to a Task pointer.
KUrl url
For reports that write to a file, the filename to write to.
long count()
Return the total number of items in the view.
void startTimerFor(Task *task, const QDateTime &startTime=QDateTime::currentDateTime())
starts timer for task.
QStringList activeTasks() const
bool event(QEvent *event)
Keep track of how long the computer has been idle.
Task * task(const QString &uid)
return the task with the given UID
void stopCurrentTimer()
Stop the timer for the current item in the view.
int totalMinutesForTaskId(const QString &taskId) const
bool isComplete()
Return true if task is complete (percent complete equals 100).
void markTaskAsIncomplete()
void markTaskAsComplete()
void setPercentComplete(const QString &taskId, int percent)
QString delimiter
The delimiter to use when outputting comma-separated value reports.
REPORTTYPE reportType
The type of report we are running.
void newTask()
Calls newTask dialog with caption "New Task".
static bool showSearchBar()
Get showSearchBar.
void startNewSession()
Reset session time to zero for all tasks.
void refresh()
Used to refresh (e.g.
bool isIdleDetectionPossible() const
void startCurrentTimer()
Start the timer on the current item (task) in view.
bool allEventsHaveEndTiMe()
Deliver if all events from the storage have and end time.
QString uid() const
Return unique iCalendar Todo ID for this task.
void exportcsvFile()
Export comma separated values format for task time totals.
void closeStorage()
Close the storage and release lock.
Stores entries from export dialog.
timetrackerstorage * storage()
Returns a pointer to storage object.
void stopTimerFor(const QString &taskId)
bool isRunning() const
return the state of a task - if it's running or not
void deleteTask(Task *task=0)
Deletes the given or the current task (and children) from the view.
void stopTimerFor(Task *task)
void addTask(const QString &taskName)
void deleteTaskBatch(Task *task=0)
Deletes the given or the current task (and children) from the view.
void addSubTask(const QString &taskName, const QString &taskId)
void changeTime(long minutes, timetrackerstorage *storage)
Change task time.
static void setShowSearchBar(bool v)
Set showSearchBar.
static KTimeTrackerSettings * self()
QVector< int > DesktopList
bool decimalMinutes
True if the durations should be output in decimal hours.
bool allTasks
True if user chose to export all tasks, not only the selected one.
REPORTTYPE
The different report types.
void reconfigure()
Reconfigures taskView depending on current configuration.
void load(const QString &filename)
Load the view from storage.
QStringList taskIdsFromName(const QString &taskName) const
QString report(const ReportCriteria &rc)
call export function for csv totals or history
bool isActive(const QString &taskId) const
void startTimerFor(const QString &taskId)
void save()
Save to persistent storage.
void stopAllTimers(const QDateTime &when=QDateTime::currentDateTime())
Stop all running timers.
void newSubTask()
Calls newTask dialog with caption "New Sub Task".
static bool configPDA()
Get configPDA.
QDate to
For history reports, the upper bound of the date range to report on.
Container and interface for the tasks.
A class representing a task.
QString exportcsvHistory()
Export comma-separated values format for task history.
bool startTimerForTaskName(const QString &taskName)
Task * currentItem() const
Return the current item in the view, cast to a Task pointer.
void resetTimeForAllTasks()
Reset session and total time to zero for all tasks.
QString addTask(const QString &taskame, const QString &taskdescription=QString(), long total=0, long session=0, const DesktopList &desktops=QVector< int >(0, 0), Task *parent=0)
Add a task to view and storage.