File indexing completed on 2024-05-19 05:21:55

0001 /*
0002  * Copyright (C) 2007 by Mathias Soeken <msoeken@tzi.de>
0003  * Copyright (C) 2019  Alexander Potashev <aspotashev@gmail.com>
0004  *
0005  *   This program is free software; you can redistribute it and/or modify
0006  *   it under the terms of the GNU General Public License as published by
0007  *   the Free Software Foundation; either version 2 of the License, or
0008  *   (at your option) any later version.
0009  *
0010  *   This program is distributed in the hope that it will be useful,
0011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
0012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0013  *   GNU General Public License for more details.
0014  *
0015  *   You should have received a copy of the GNU General Public License along
0016  *   with this program; if not, write to the
0017  *      Free Software Foundation, Inc.
0018  *      51 Franklin Street, Fifth Floor
0019  *      Boston, MA  02110-1301  USA.
0020  *
0021  */
0022 
0023 #include "timetrackerwidget.h"
0024 
0025 #include <QFileDialog>
0026 #include <QPointer>
0027 
0028 #include <KActionCollection>
0029 #include <KConfigDialog>
0030 #include <KMessageBox>
0031 #include <KStandardAction>
0032 
0033 #include "dialogs/edittimedialog.h"
0034 #include "dialogs/exportdialog.h"
0035 #include "dialogs/historydialog.h"
0036 #include "export/export.h"
0037 #include "idletimedetector.h"
0038 #include "ktimetracker-version.h"
0039 #include "ktimetracker.h"
0040 #include "ktimetrackerutility.h"
0041 #include "ktt_debug.h"
0042 #include "mainwindow.h"
0043 #include "model/eventsmodel.h"
0044 #include "model/projectmodel.h"
0045 #include "model/task.h"
0046 #include "model/tasksmodel.h"
0047 #include "reportcriteria.h"
0048 #include "settings/ktimetrackerconfigdialog.h"
0049 #include "taskview.h"
0050 #include "widgets/searchline.h"
0051 #include "widgets/taskswidget.h"
0052 
0053 TimeTrackerWidget::TimeTrackerWidget(QWidget *parent)
0054     : QWidget(parent)
0055     , m_searchLine(nullptr)
0056     , m_taskView(nullptr)
0057     , m_actionCollection(nullptr)
0058 {
0059     registerDBus();
0060 
0061     QLayout *layout = new QVBoxLayout;
0062     layout->setContentsMargins(0,0,0,0);
0063     layout->setSpacing(0);
0064     setLayout(layout);
0065 
0066     fillLayout(nullptr);
0067 }
0068 
0069 void TimeTrackerWidget::fillLayout(TasksWidget *tasksWidget)
0070 {
0071     // Remove all items from layout
0072     QLayoutItem *child;
0073     while ((child = layout()->takeAt(0)) != nullptr) {
0074         delete child->widget();
0075         delete child;
0076     }
0077 
0078     if (tasksWidget) {
0079         m_searchLine = new SearchLine(this);
0080         connect(m_searchLine, &SearchLine::textSubmitted, this, &TimeTrackerWidget::slotAddTask);
0081         connect(m_searchLine, &SearchLine::searchUpdated, tasksWidget, &TasksWidget::setFilterText);
0082         layout()->addWidget(m_searchLine);
0083 
0084         layout()->addWidget(tasksWidget);
0085 
0086         showSearchBar(!KTimeTrackerSettings::configPDA() && KTimeTrackerSettings::showSearchBar());
0087     } else {
0088         auto *placeholderWidget = new QWidget(this);
0089         placeholderWidget->setBackgroundRole(QPalette::Dark);
0090         placeholderWidget->setAutoFillBackground(true);
0091         layout()->addWidget(placeholderWidget);
0092     }
0093 }
0094 
0095 int TimeTrackerWidget::focusSearchBar()
0096 {
0097     if (m_searchLine->isEnabled()) {
0098         m_searchLine->setFocus();
0099     }
0100     return 0;
0101 }
0102 
0103 void TimeTrackerWidget::addTaskView(const QUrl &url)
0104 {
0105     qCDebug(KTT_LOG) << "Entering function (url=" << url << ")";
0106 
0107     closeFile();
0108 
0109     m_taskView = new TaskView(this);
0110     connect(m_taskView, &TaskView::contextMenuRequested, this, &TimeTrackerWidget::contextMenuRequested);
0111     connect(m_taskView, &TaskView::timersActive, this, &TimeTrackerWidget::timersActive);
0112     connect(m_taskView, &TaskView::timersInactive, this, &TimeTrackerWidget::timersInactive);
0113     connect(m_taskView, &TaskView::tasksChanged, this, &TimeTrackerWidget::tasksChanged);
0114 
0115     Q_EMIT currentFileChanged(url);
0116     m_taskView->load(url);
0117 
0118     fillLayout(m_taskView->tasksWidget());
0119 
0120     Q_EMIT currentTaskViewChanged();
0121     slotCurrentChanged();
0122 }
0123 
0124 TaskView *TimeTrackerWidget::currentTaskView() const
0125 {
0126     return m_taskView;
0127 }
0128 
0129 Task *TimeTrackerWidget::currentTask()
0130 {
0131     auto *taskView = currentTaskView();
0132     if (taskView == nullptr) {
0133         return nullptr;
0134     }
0135 
0136     auto *tasksWidget = taskView->tasksWidget();
0137     if (tasksWidget == nullptr) {
0138         return nullptr;
0139     }
0140 
0141     return tasksWidget->currentItem();
0142 }
0143 
0144 void TimeTrackerWidget::setupActions(KActionCollection *actionCollection)
0145 {
0146     Q_INIT_RESOURCE(pics);
0147 
0148     KStandardAction::open(this, &TimeTrackerWidget::openFileDialog, actionCollection);
0149     KStandardAction::save(this, &TimeTrackerWidget::saveFile, actionCollection);
0150     KStandardAction::preferences(this, &TimeTrackerWidget::showSettingsDialog, actionCollection);
0151 
0152     {
0153         QAction *action = actionCollection->addAction(QStringLiteral("ktimetracker_start_new_session"));
0154         action->setText(i18nc("@action:inmenu", "Start &New Session"));
0155         action->setToolTip(i18nc("@info:tooltip", "Starts a new session"));
0156         action->setWhatsThis(i18nc("@info:whatsthis",
0157                                    "This will reset the "
0158                                    "session time to 0 for all tasks, to start a new session, without "
0159                                    "affecting the totals."));
0160         connect(action, &QAction::triggered, this, &TimeTrackerWidget::startNewSession);
0161     }
0162 
0163     {
0164         QAction *action = actionCollection->addAction(QStringLiteral("edit_history"));
0165         action->setText(i18nc("@action:inmenu", "Edit History..."));
0166         action->setToolTip(i18nc("@info:tooltip", "Edits history of all tasks of the current document"));
0167         action->setWhatsThis(i18nc("@info:whatsthis",
0168                                    "A window will "
0169                                    "be opened where you can change start and "
0170                                    "stop times of tasks or add a "
0171                                    "comment to them."));
0172         action->setIcon(QIcon::fromTheme(QStringLiteral("view-history")));
0173         connect(action, &QAction::triggered, this, &TimeTrackerWidget::editHistory);
0174     }
0175 
0176     {
0177         QAction *action = actionCollection->addAction(QStringLiteral("reset_all_times"));
0178         action->setText(i18nc("@action:inmenu", "&Reset All Times"));
0179         action->setToolTip(i18nc("@info:tooltip", "Resets all times"));
0180         action->setWhatsThis(i18nc("@info:whatsthis",
0181                                    "This will reset the session "
0182                                    "and total time to 0 for all tasks, to restart from scratch."));
0183         connect(action, &QAction::triggered, this, &TimeTrackerWidget::resetAllTimes);
0184     }
0185 
0186     {
0187         QAction *action = actionCollection->addAction(QStringLiteral("start"));
0188         action->setText(i18nc("@action:inmenu", "&Start"));
0189         action->setToolTip(i18nc("@info:tooltip", "Starts timing for selected task"));
0190         action->setWhatsThis(i18nc("@info:whatsthis",
0191                                    "This will start timing for the "
0192                                    "selected task.\nIt is even possible to time several tasks "
0193                                    "simultaneously.\n\nYou may also start timing of tasks by "
0194                                    "double clicking "
0195                                    "the left mouse button on a given task. This will, however, "
0196                                    "stop timing "
0197                                    "of other tasks."));
0198         action->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-start")));
0199         actionCollection->setDefaultShortcut(action, QKeySequence(Qt::Key_G));
0200         connect(action, &QAction::triggered, this, &TimeTrackerWidget::startCurrentTimer);
0201     }
0202 
0203     {
0204         QAction *action = actionCollection->addAction(QStringLiteral("stop"));
0205         action->setText(i18nc("@action:inmenu", "S&top"));
0206         action->setToolTip(i18nc("@info:tooltip", "Stops timing of the selected task"));
0207         action->setWhatsThis(i18nc("@info:whatsthis", "Stops timing of the selected task"));
0208         action->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-stop")));
0209         connect(action, &QAction::triggered, this, &TimeTrackerWidget::stopCurrentTimer);
0210     }
0211 
0212     {
0213         QAction *action = actionCollection->addAction(QStringLiteral("focusSearchBar"));
0214         action->setText(i18nc("@action:inmenu", "Focus on Searchbar"));
0215         action->setToolTip(i18nc("@info:tooltip", "Sets the focus on the searchbar"));
0216         action->setWhatsThis(i18nc("@info:whatsthis", "Sets the focus on the searchbar"));
0217         actionCollection->setDefaultShortcut(action, QKeySequence(Qt::Key_S));
0218         connect(action, &QAction::triggered, this, &TimeTrackerWidget::focusSearchBar);
0219     }
0220 
0221     {
0222         QAction *action = actionCollection->addAction(QStringLiteral("stopAll"));
0223         action->setText(i18nc("@action:inmenu", "Stop &All Timers"));
0224         action->setToolTip(i18nc("@info:tooltip", "Stops all of the active timers"));
0225         action->setWhatsThis(i18nc("@info:whatsthis", "Stops all of the active timers"));
0226         actionCollection->setDefaultShortcut(action, QKeySequence(Qt::Key_Escape));
0227         connect(action, &QAction::triggered, this, &TimeTrackerWidget::stopAllTimers);
0228     }
0229 
0230     {
0231         QAction *action = actionCollection->addAction(QStringLiteral("focustracking"));
0232         action->setCheckable(true);
0233         action->setText(i18nc("@action:inmenu", "Track Active Applications"));
0234         action->setToolTip(i18nc("@info:tooltip",
0235                                  "Auto-creates and updates tasks when the "
0236                                  "focus of the current window has changed"));
0237         action->setWhatsThis(i18nc("@info:whatsthis",
0238                                    "If the focus of a window changes for the "
0239                                    "first time when this action is enabled, a new task will be "
0240                                    "created "
0241                                    "with the title of the window as its name and will be "
0242                                    "started. If there "
0243                                    "already exists such an task it will be started."));
0244         connect(action, &QAction::triggered, this, &TimeTrackerWidget::focusTracking);
0245     }
0246 
0247     {
0248         QAction *action = actionCollection->addAction(QStringLiteral("new_task"));
0249         action->setText(i18nc("@action:inmenu", "&New Task..."));
0250         action->setToolTip(i18nc("@info:tooltip", "Creates new top level task"));
0251         action->setWhatsThis(i18nc("@info:whatsthis", "This will create a new top level task."));
0252         action->setIcon(QIcon::fromTheme(QStringLiteral("task-new")));
0253         actionCollection->setDefaultShortcut(action, QKeySequence(Qt::CTRL | Qt::Key_T));
0254         connect(action, &QAction::triggered, this, &TimeTrackerWidget::newTask);
0255     }
0256 
0257     {
0258         QAction *action = actionCollection->addAction(QStringLiteral("new_sub_task"));
0259         action->setText(i18nc("@action:inmenu", "New &Subtask..."));
0260         action->setToolTip(i18nc("@info:tooltip", "Creates a new subtask to the current selected task"));
0261         action->setWhatsThis(i18nc("@info:whatsthis", "This will create a new subtask to the current selected task."));
0262         action->setIcon(QIcon::fromTheme(QStringLiteral("view-task-child")));
0263         actionCollection->setDefaultShortcut(action, QKeySequence(Qt::CTRL | Qt::Key_B));
0264         connect(action, &QAction::triggered, this, &TimeTrackerWidget::newSubTask);
0265     }
0266 
0267     {
0268         QAction *action = actionCollection->addAction(QStringLiteral("delete_task"));
0269         action->setText(i18nc("@action:inmenu", "&Delete"));
0270         action->setToolTip(i18nc("@info:tooltip", "Deletes selected task"));
0271         action->setWhatsThis(i18nc("@info:whatsthis", "This will delete the selected task(s) and all subtasks."));
0272         action->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete")));
0273         actionCollection->setDefaultShortcut(action, QKeySequence(Qt::Key_Delete));
0274         connect(action, &QAction::triggered, this, QOverload<>::of(&TimeTrackerWidget::deleteTask));
0275     }
0276 
0277     {
0278         QAction *action = actionCollection->addAction(QStringLiteral("edit_task"));
0279         action->setText(i18nc("@action:inmenu", "&Properties"));
0280         action->setToolTip(i18nc("@info:tooltip", "Edit name or description for selected task"));
0281         action->setWhatsThis(i18nc("@info:whatsthis",
0282                                    "This will bring up a dialog "
0283                                    "box where you may edit the parameters for the selected task."));
0284         action->setIcon(QIcon::fromTheme(QStringLiteral("document-properties")));
0285         actionCollection->setDefaultShortcut(action, QKeySequence(Qt::CTRL | Qt::Key_E));
0286         connect(action, &QAction::triggered, this, &TimeTrackerWidget::editTask);
0287     }
0288 
0289     {
0290         QAction *action = actionCollection->addAction(QStringLiteral("edit_task_time"));
0291         action->setText(i18nc("@action:inmenu", "Edit &Time..."));
0292         action->setToolTip(i18nc("@info:tooltip", "Edit time for selected task"));
0293         action->setWhatsThis(i18nc("@info:whatsthis",
0294                                    "This will bring up a dialog "
0295                                    "box where you may edit the times for the selected task."));
0296         action->setIcon(QIcon::fromTheme(QStringLiteral("document-edit")));
0297         actionCollection->setDefaultShortcut(action, QKeySequence(Qt::Key_E));
0298         connect(action, &QAction::triggered, this, &TimeTrackerWidget::editTaskTime);
0299     }
0300 
0301     {
0302         QAction *action = actionCollection->addAction(QStringLiteral("mark_as_complete"));
0303         action->setText(i18nc("@action:inmenu", "&Mark as Complete"));
0304         action->setIcon(QPixmap(QStringLiteral(":/pics/task-complete.xpm")));
0305         actionCollection->setDefaultShortcut(action, QKeySequence(Qt::CTRL | Qt::Key_M));
0306         connect(action, &QAction::triggered, this, &TimeTrackerWidget::markTaskAsComplete);
0307     }
0308 
0309     {
0310         QAction *action = actionCollection->addAction(QStringLiteral("mark_as_incomplete"));
0311         action->setText(i18nc("@action:inmenu", "&Mark as Incomplete"));
0312         action->setIcon(QPixmap(QStringLiteral(":/pics/task-incomplete.xpm")));
0313         actionCollection->setDefaultShortcut(action, QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_M));
0314         connect(action, &QAction::triggered, this, &TimeTrackerWidget::markTaskAsIncomplete);
0315     }
0316 
0317     {
0318         QAction *action = actionCollection->addAction(QStringLiteral("export_dialog"));
0319         action->setText(i18nc("@action:inmenu", "&Export..."));
0320         action->setIcon(QIcon::fromTheme(QStringLiteral("document-export")));
0321         connect(action, &QAction::triggered, this, &TimeTrackerWidget::exportDialog);
0322     }
0323 
0324     {
0325         QAction *action = actionCollection->addAction(QStringLiteral("import_planner"));
0326         action->setText(i18nc("@action:inmenu", "Import Tasks From &Planner..."));
0327         action->setIcon(QIcon::fromTheme(QStringLiteral("document-import")));
0328         connect(action, &QAction::triggered, [=]() {
0329             const QString &fileName = QFileDialog::getOpenFileName();
0330             importPlannerFile(fileName);
0331         });
0332     }
0333 
0334     {
0335         QAction *action = actionCollection->addAction(QStringLiteral("searchbar"));
0336         action->setCheckable(true);
0337         action->setChecked(KTimeTrackerSettings::showSearchBar());
0338         action->setText(i18nc("@action:inmenu", "Show Searchbar"));
0339         connect(action, &QAction::triggered, this, &TimeTrackerWidget::slotSearchBar);
0340     }
0341 
0342     m_actionCollection = actionCollection;
0343 
0344     connect(this, &TimeTrackerWidget::currentTaskChanged, this, &TimeTrackerWidget::slotUpdateButtons);
0345     connect(this, &TimeTrackerWidget::currentTaskViewChanged, this, &TimeTrackerWidget::slotUpdateButtons);
0346     connect(this, &TimeTrackerWidget::updateButtons, this, &TimeTrackerWidget::slotUpdateButtons);
0347     slotUpdateButtons();
0348 }
0349 
0350 QAction *TimeTrackerWidget::action(const QString &name) const
0351 {
0352     return m_actionCollection->action(name);
0353 }
0354 
0355 void TimeTrackerWidget::openFile(const QUrl &url)
0356 {
0357     qCDebug(KTT_LOG) << "Entering function, url is " << url;
0358     addTaskView(url);
0359 }
0360 
0361 void TimeTrackerWidget::openFileDialog()
0362 {
0363     const QString &path = QFileDialog::getOpenFileName(this);
0364     if (!path.isEmpty()) {
0365         openFile(QUrl::fromLocalFile(path));
0366     }
0367 }
0368 
0369 bool TimeTrackerWidget::closeFile()
0370 {
0371     qCDebug(KTT_LOG) << "Entering TimeTrackerWidget::closeFile";
0372     TaskView *taskView = currentTaskView();
0373 
0374     if (taskView) {
0375         taskView->save();
0376         taskView->closeStorage();
0377     }
0378 
0379     Q_EMIT currentTaskViewChanged();
0380     Q_EMIT currentFileChanged(QUrl());
0381     slotCurrentChanged();
0382 
0383     delete taskView; // removeTab does not delete its widget.
0384     m_taskView = nullptr;
0385     return true;
0386 }
0387 
0388 void TimeTrackerWidget::saveFile()
0389 {
0390     currentTaskView()->save();
0391 }
0392 
0393 void TimeTrackerWidget::showSearchBar(bool visible)
0394 {
0395     m_searchLine->setVisible(visible);
0396 }
0397 
0398 bool TimeTrackerWidget::closeAllFiles()
0399 {
0400     qCDebug(KTT_LOG) << "Entering TimeTrackerWidget::closeAllFiles";
0401     bool err = true;
0402     if (m_taskView) {
0403         m_taskView->stopAllTimers();
0404         err = closeFile();
0405     }
0406     return err;
0407 }
0408 
0409 void TimeTrackerWidget::slotCurrentChanged()
0410 {
0411     qDebug() << "entering KTimeTrackerWidget::slotCurrentChanged";
0412 
0413     if (m_taskView) {
0414         connect(m_taskView, &TaskView::updateButtons, this, &TimeTrackerWidget::updateButtons, Qt::UniqueConnection);
0415         connect(m_taskView,
0416                 &TaskView::setStatusBarText,
0417                 this,
0418                 &TimeTrackerWidget::statusBarTextChangeRequested,
0419                 Qt::UniqueConnection);
0420         connect(m_taskView, &TaskView::timersActive, this, &TimeTrackerWidget::timersActive, Qt::UniqueConnection);
0421         connect(m_taskView, &TaskView::timersInactive, this, &TimeTrackerWidget::timersInactive, Qt::UniqueConnection);
0422         connect(m_taskView, &TaskView::tasksChanged, this, &TimeTrackerWidget::tasksChanged, Qt::UniqueConnection);
0423         connect(m_taskView, &TaskView::minutesUpdated, this, &TimeTrackerWidget::minutesUpdated, Qt::UniqueConnection);
0424 
0425         Q_EMIT currentFileChanged(m_taskView->storage()->fileUrl());
0426     }
0427 }
0428 
0429 void TimeTrackerWidget::slotAddTask(const QString &taskName)
0430 {
0431     TaskView *taskView = currentTaskView();
0432     taskView->addTask(taskName, QString(), 0, 0, DesktopList(), nullptr);
0433 }
0434 
0435 void TimeTrackerWidget::slotUpdateButtons()
0436 {
0437     Task *item = currentTask();
0438 
0439     action(QStringLiteral("start"))->setEnabled(item && !item->isRunning() && !item->isComplete());
0440     action(QStringLiteral("stop"))->setEnabled(item && item->isRunning());
0441     action(QStringLiteral("delete_task"))->setEnabled(item);
0442     action(QStringLiteral("edit_task_time"))->setEnabled(item);
0443     action(QStringLiteral("edit_task"))->setEnabled(item);
0444     action(QStringLiteral("mark_as_complete"))->setEnabled(item && !item->isComplete());
0445     action(QStringLiteral("mark_as_incomplete"))->setEnabled(item && item->isComplete());
0446 
0447     action(QStringLiteral("new_task"))->setEnabled(currentTaskView());
0448     action(QStringLiteral("new_sub_task"))
0449         ->setEnabled(currentTaskView() && currentTaskView()->storage()->isLoaded()
0450                      && currentTaskView()->storage()->tasksModel()->getAllTasks().size());
0451     action(QStringLiteral("focustracking"))->setEnabled(currentTaskView());
0452     action(QStringLiteral("focustracking"))
0453         ->setChecked(currentTaskView() && currentTaskView()->isFocusTrackingActive());
0454     action(QStringLiteral("ktimetracker_start_new_session"))->setEnabled(currentTaskView());
0455     action(QStringLiteral("edit_history"))->setEnabled(currentTaskView());
0456     action(QStringLiteral("reset_all_times"))->setEnabled(currentTaskView());
0457     action(QStringLiteral("export_dialog"))->setEnabled(currentTaskView());
0458     action(QStringLiteral("import_planner"))->setEnabled(currentTaskView());
0459     action(QStringLiteral("file_save"))->setEnabled(currentTaskView());
0460 }
0461 
0462 void TimeTrackerWidget::showSettingsDialog()
0463 {
0464     if (KConfigDialog::showDialog(QStringLiteral("settings"))) {
0465         return;
0466     }
0467 
0468     auto *dialog = new KConfigDialog(this, QStringLiteral("settings"), KTimeTrackerSettings::self());
0469     dialog->setFaceType(KPageDialog::List);
0470     KTimeTrackerBehaviorConfig *behaviorConfig = new KTimeTrackerBehaviorConfig(dialog);
0471     QWidget *behaviorConfigWidget = behaviorConfig->widget();
0472     dialog->addPage(behaviorConfigWidget,
0473                     i18nc("@title:tab", "Behavior"),
0474                     QStringLiteral("preferences-other"));
0475     KTimeTrackerDisplayConfig *displayConfig = new KTimeTrackerDisplayConfig(dialog);
0476     QWidget *displayConfigWidget = displayConfig->widget();
0477     dialog->addPage(displayConfigWidget,
0478                     i18nc("@title:tab", "Appearance"),
0479                     QStringLiteral("preferences-desktop-theme"));
0480     KTimeTrackerStorageConfig *storageConfig = new KTimeTrackerStorageConfig(dialog);
0481     QWidget *storageConfigWidget = storageConfig->widget();
0482     dialog->addPage(storageConfigWidget,
0483                     i18nc("@title:tab", "Storage"),
0484                     QStringLiteral("system-file-manager"));
0485     connect(dialog, &KConfigDialog::settingsChanged, this, &TimeTrackerWidget::loadSettings);
0486     dialog->show();
0487 }
0488 
0489 void TimeTrackerWidget::loadSettings()
0490 {
0491     KTimeTrackerSettings::self()->load();
0492 
0493     showSearchBar(!KTimeTrackerSettings::configPDA() && KTimeTrackerSettings::showSearchBar());
0494     currentTaskView()->reconfigureModel();
0495     currentTaskView()->tasksWidget()->reconfigure();
0496 
0497     //  for updating window caption
0498     Q_EMIT currentFileChanged(m_taskView->storage()->fileUrl());
0499     Q_EMIT tasksChanged(currentTaskView()->storage()->tasksModel()->getActiveTasks());
0500 }
0501 
0502 //BEGIN wrapper slots
0503 void TimeTrackerWidget::startCurrentTimer()
0504 {
0505     currentTaskView()->startCurrentTimer();
0506 }
0507 
0508 void TimeTrackerWidget::stopCurrentTimer()
0509 {
0510     currentTaskView()->stopCurrentTimer();
0511 }
0512 
0513 void TimeTrackerWidget::stopAllTimers()
0514 {
0515     currentTaskView()->stopAllTimers(QDateTime::currentDateTime());
0516 }
0517 
0518 void TimeTrackerWidget::newTask()
0519 {
0520     currentTaskView()->newTask(i18nc("@title:window", "New Task"), nullptr);
0521 }
0522 
0523 void TimeTrackerWidget::newSubTask()
0524 {
0525     currentTaskView()->newSubTask();
0526 }
0527 
0528 void TimeTrackerWidget::editTask()
0529 {
0530     currentTaskView()->editTask();
0531 }
0532 
0533 void TimeTrackerWidget::editTaskTime()
0534 {
0535     qCDebug(KTT_LOG) << "Entering editTask";
0536     Task *task = currentTask();
0537     if (!task) {
0538         return;
0539     }
0540 
0541     QPointer<EditTimeDialog> editTimeDialog =
0542         new EditTimeDialog(this, task->name(), task->description(), static_cast<int>(task->time()));
0543 
0544     if (editTimeDialog->exec() == QDialog::Accepted) {
0545         if (editTimeDialog->editHistoryRequested()) {
0546             editHistory();
0547         } else {
0548             currentTaskView()->editTaskTime(task->uid(), editTimeDialog->changeMinutes());
0549         }
0550     }
0551 
0552     delete editTimeDialog;
0553 }
0554 
0555 void TimeTrackerWidget::deleteTask()
0556 {
0557     currentTaskView()->deleteTask();
0558 }
0559 
0560 void TimeTrackerWidget::markTaskAsComplete()
0561 {
0562     currentTaskView()->markTaskAsComplete();
0563 }
0564 
0565 void TimeTrackerWidget::markTaskAsIncomplete()
0566 {
0567     currentTaskView()->markTaskAsIncomplete();
0568 }
0569 
0570 void TimeTrackerWidget::exportDialog()
0571 {
0572     qCDebug(KTT_LOG) << "TimeTrackerWidget::exportDialog()";
0573 
0574     auto *taskView = currentTaskView();
0575     ExportDialog dialog(taskView->tasksWidget(), taskView);
0576     if (taskView->tasksWidget()->currentItem() && taskView->tasksWidget()->currentItem()->isRoot()) {
0577         dialog.enableTasksToExportQuestion();
0578     }
0579     dialog.exec();
0580 }
0581 
0582 void TimeTrackerWidget::startNewSession()
0583 {
0584     currentTaskView()->storage()->tasksModel()->startNewSession();
0585 }
0586 
0587 void TimeTrackerWidget::editHistory()
0588 {
0589     // HistoryDialog is the new HistoryDialog, but the EditHiStoryDiaLog exists as well.
0590     // HistoryDialog can be edited with qtcreator and qtdesigner, EditHiStoryDiaLog cannot.
0591     if (currentTaskView()) {
0592         QPointer<HistoryDialog> dialog =
0593             new HistoryDialog(currentTaskView()->tasksWidget(), currentTaskView()->storage()->projectModel());
0594         if (currentTaskView()->storage()->eventsModel()->events().count() != 0) {
0595             dialog->exec();
0596         } else {
0597             KMessageBox::information(nullptr,
0598                                      i18nc("@info in message box",
0599                                            "There is no history yet. Start and stop a task and you "
0600                                            "will have an entry in your history."));
0601         }
0602     }
0603 }
0604 
0605 void TimeTrackerWidget::resetAllTimes()
0606 {
0607     if (currentTaskView()) {
0608         if (KMessageBox::warningContinueCancel(this,
0609                                                i18n("Do you really want to reset the time to zero for all "
0610                                                     "tasks? This will delete the entire history."),
0611                                                i18nc("@title:window", "Confirmation Required"),
0612                                                KGuiItem(i18nc("@action:button", "Reset All Times")))
0613             == KMessageBox::Continue) {
0614             currentTaskView()->storage()->projectModel()->resetTimeForAllTasks();
0615         }
0616     }
0617 }
0618 
0619 void TimeTrackerWidget::focusTracking()
0620 {
0621     currentTaskView()->toggleFocusTracking();
0622     action(QStringLiteral("focustracking"))->setChecked(currentTaskView()->isFocusTrackingActive());
0623 }
0624 
0625 void TimeTrackerWidget::slotSearchBar()
0626 {
0627     bool currentVisible = KTimeTrackerSettings::showSearchBar();
0628     KTimeTrackerSettings::setShowSearchBar(!currentVisible);
0629     action(QStringLiteral("searchbar"))->setChecked(!currentVisible);
0630     showSearchBar(!currentVisible);
0631 }
0632 //END
0633 
0634 /** \defgroup dbus slots ‘‘dbus slots’’ */
0635 /* @{ */
0636 #include "mainadaptor.h"
0637 
0638 void TimeTrackerWidget::registerDBus()
0639 {
0640     new MainAdaptor(this);
0641     QDBusConnection::sessionBus().registerObject(QStringLiteral("/KTimeTracker"), this);
0642 }
0643 
0644 QString TimeTrackerWidget::version() const
0645 {
0646     return QStringLiteral(KTIMETRACKER_VERSION_STRING);
0647 }
0648 
0649 QStringList TimeTrackerWidget::taskIdsFromName(const QString &taskName) const
0650 {
0651     QStringList result;
0652 
0653     TaskView *taskView = currentTaskView();
0654     if (!taskView) {
0655         return result;
0656     }
0657 
0658     for (Task *task : taskView->storage()->tasksModel()->getAllTasks()) {
0659         if (task->name() == taskName) {
0660             result << task->uid();
0661         }
0662     }
0663 
0664     return result;
0665 }
0666 
0667 void TimeTrackerWidget::addTask(const QString &taskName)
0668 {
0669     TaskView *taskView = currentTaskView();
0670 
0671     if (taskView) {
0672         taskView->addTask(taskName, QString(), 0, 0, DesktopList(), nullptr);
0673     }
0674 }
0675 
0676 void TimeTrackerWidget::addSubTask(const QString &taskName, const QString &taskId)
0677 {
0678     TaskView *taskView = currentTaskView();
0679 
0680     if (taskView) {
0681         taskView
0682             ->addTask(taskName, QString(), 0, 0, DesktopList(), taskView->storage()->tasksModel()->taskByUID(taskId));
0683         taskView->storage()->projectModel()->refresh();
0684         taskView->tasksWidget()->refresh();
0685     }
0686 }
0687 
0688 void TimeTrackerWidget::deleteTask(const QString &taskId)
0689 {
0690     TaskView *taskView = currentTaskView();
0691 
0692     if (!taskView) {
0693         return;
0694     }
0695 
0696     for (Task *task : taskView->storage()->tasksModel()->getAllTasks()) {
0697         if (task->uid() == taskId) {
0698             taskView->deleteTaskBatch(task);
0699             break;
0700         }
0701     }
0702 }
0703 
0704 void TimeTrackerWidget::setPercentComplete(const QString &taskId, int percent)
0705 {
0706     TaskView *taskView = currentTaskView();
0707 
0708     if (!taskView) {
0709         return;
0710     }
0711 
0712     for (Task *task : taskView->storage()->tasksModel()->getAllTasks()) {
0713         if (task->uid() == taskId) {
0714             task->setPercentComplete(percent);
0715         }
0716     }
0717 }
0718 
0719 int TimeTrackerWidget::bookTime(const QString &taskId, const QString &dateTime, int64_t minutes)
0720 {
0721     QDate startDate;
0722     QTime startTime;
0723     QDateTime startDateTime;
0724 
0725     if (minutes <= 0) {
0726         return KTIMETRACKER_ERR_INVALID_DURATION;
0727     }
0728 
0729     Task *task = nullptr;
0730     TaskView *taskView = currentTaskView();
0731     if (taskView) {
0732         for (Task *t : taskView->storage()->tasksModel()->getAllTasks()) {
0733             if (t->uid() == taskId) {
0734                 task = t;
0735                 break;
0736             }
0737         }
0738     }
0739 
0740     if (!task) {
0741         return KTIMETRACKER_ERR_UID_NOT_FOUND;
0742     }
0743 
0744     // Parse datetime
0745     startDate = QDate::fromString(dateTime, Qt::ISODate);
0746 
0747     if (dateTime.length() > 10) { // "YYYY-MM-DD".length() = 10
0748         startTime = QTime::fromString(dateTime, Qt::ISODate);
0749     } else {
0750         startTime = QTime(12, 0);
0751     }
0752 
0753     if (startDate.isValid() && startTime.isValid()) {
0754         startDateTime = QDateTime(startDate, startTime);
0755     } else {
0756         return KTIMETRACKER_ERR_INVALID_DATE;
0757     }
0758 
0759     // Update task totals (session and total) and save to disk
0760     task->changeTotalTimes(task->sessionTime() + minutes, task->totalTime() + minutes);
0761     if (!taskView->storage()->bookTime(task, startDateTime, minutes * 60)) {
0762         return KTIMETRACKER_ERR_GENERIC_SAVE_FAILED;
0763     }
0764 
0765     return 0;
0766 }
0767 
0768 int TimeTrackerWidget::changeTime(const QString &taskId, int64_t minutes)
0769 {
0770     if (minutes <= 0) {
0771         return KTIMETRACKER_ERR_INVALID_DURATION;
0772     }
0773 
0774     // Find task
0775     TaskView *taskView = currentTaskView();
0776     if (!taskView) {
0777         //FIXME: it mimics the behaviour with the for loop, but I am not sure semantics were right. Maybe a new error code must be defined?
0778         return KTIMETRACKER_ERR_UID_NOT_FOUND;
0779     }
0780 
0781     Task *task = nullptr;
0782     for (Task *t : taskView->storage()->tasksModel()->getAllTasks()) {
0783         if (t->uid() == taskId) {
0784             task = t;
0785             break;
0786         }
0787     }
0788 
0789     if (!task) {
0790         return KTIMETRACKER_ERR_UID_NOT_FOUND;
0791     }
0792 
0793     task->changeTime(minutes, taskView->storage()->eventsModel());
0794     return 0;
0795 }
0796 
0797 QString TimeTrackerWidget::error(int errorCode) const
0798 {
0799     switch (errorCode) {
0800     case KTIMETRACKER_ERR_GENERIC_SAVE_FAILED:
0801         return i18n("Save failed, most likely because the file could not be locked.");
0802     case KTIMETRACKER_ERR_COULD_NOT_MODIFY_RESOURCE:
0803         return i18n("Could not modify calendar resource.");
0804     case KTIMETRACKER_ERR_MEMORY_EXHAUSTED:
0805         return i18n("Out of memory--could not create object.");
0806     case KTIMETRACKER_ERR_UID_NOT_FOUND:
0807         return i18n("UID not found.");
0808     case KTIMETRACKER_ERR_INVALID_DATE:
0809         return i18n("Invalidate date--format is YYYY-MM-DD.");
0810     case KTIMETRACKER_ERR_INVALID_TIME:
0811         return i18n("Invalid time--format is YYYY-MM-DDTHH:MM:SS.");
0812     case KTIMETRACKER_ERR_INVALID_DURATION:
0813         return i18n("Invalid task duration--must be greater than zero.");
0814     default:
0815         return i18n("Invalid error number: %1", errorCode);
0816     }
0817 }
0818 
0819 bool TimeTrackerWidget::isIdleDetectionPossible() const
0820 {
0821     return IdleTimeDetector::isIdleDetectionPossible();
0822 }
0823 
0824 int TimeTrackerWidget::totalMinutesForTaskId(const QString &taskId) const
0825 {
0826     TaskView *taskView = currentTaskView();
0827     if (!taskView) {
0828         return -1;
0829     }
0830 
0831     for (Task *task : taskView->storage()->tasksModel()->getAllTasks()) {
0832         if (task->uid() == taskId) {
0833             return task->totalTime();
0834         }
0835     }
0836 
0837     return -1;
0838 }
0839 
0840 void TimeTrackerWidget::startTimerFor(const QString &taskId)
0841 {
0842     qDebug();
0843 
0844     TaskView *taskView = currentTaskView();
0845     if (!taskView) {
0846         return;
0847     }
0848 
0849     for (Task *task : taskView->storage()->tasksModel()->getAllTasks()) {
0850         if (task->uid() == taskId) {
0851             taskView->startTimerForNow(task);
0852             return;
0853         }
0854     }
0855 }
0856 
0857 bool TimeTrackerWidget::startTimerForTaskName(const QString &taskName)
0858 {
0859     TaskView *taskView = currentTaskView();
0860     if (!taskView) {
0861         return false;
0862     }
0863 
0864     for (Task *task : taskView->storage()->tasksModel()->getAllTasks()) {
0865         if (task->name() == taskName) {
0866             taskView->startTimerForNow(task);
0867             return true;
0868         }
0869     }
0870 
0871     return false;
0872 }
0873 
0874 bool TimeTrackerWidget::stopTimerForTaskName(const QString &taskName)
0875 {
0876     TaskView *taskView = currentTaskView();
0877     if (!taskView) {
0878         return false;
0879     }
0880 
0881     for (Task *task : taskView->storage()->tasksModel()->getAllTasks()) {
0882         if (task->name() == taskName) {
0883             taskView->stopTimerFor(task);
0884             return true;
0885         }
0886     }
0887 
0888     return false;
0889 }
0890 
0891 void TimeTrackerWidget::stopTimerFor(const QString &taskId)
0892 {
0893     TaskView *taskView = currentTaskView();
0894     if (!taskView) {
0895         return;
0896     }
0897 
0898     for (Task *task : taskView->storage()->tasksModel()->getAllTasks()) {
0899         if (task->uid() == taskId) {
0900             taskView->stopTimerFor(task);
0901             return;
0902         }
0903     }
0904 }
0905 
0906 void TimeTrackerWidget::stopAllTimersDBUS()
0907 {
0908     TaskView *taskView = currentTaskView();
0909     if (taskView) {
0910         taskView->stopAllTimers();
0911     }
0912 }
0913 
0914 QString TimeTrackerWidget::exportCSVFile(const QString &filename,
0915                                          const QString &from,
0916                                          const QString &to,
0917                                          int type,
0918                                          bool decimalMinutes,
0919                                          bool allTasks,
0920                                          const QString &delimiter,
0921                                          const QString &quote)
0922 {
0923     TaskView *taskView = currentTaskView();
0924 
0925     if (!taskView) {
0926         return QStringLiteral("");
0927     }
0928 
0929     ReportCriteria rc;
0930 
0931     rc.from = QDate::fromString(from);
0932     if (rc.from.isNull()) {
0933         rc.from = QDate::fromString(from, Qt::ISODate);
0934     }
0935 
0936     rc.to = QDate::fromString(to);
0937     if (rc.to.isNull()) {
0938         rc.to = QDate::fromString(to, Qt::ISODate);
0939     }
0940 
0941     rc.reportType = static_cast<ReportCriteria::REPORTTYPE>(type);
0942     rc.decimalMinutes = decimalMinutes;
0943     rc.allTasks = allTasks;
0944     rc.delimiter = delimiter;
0945     rc.quote = quote;
0946 
0947     QString output = exportToString(taskView->storage()->projectModel(), taskView->tasksWidget()->currentItem(), rc);
0948     return writeExport(output, QUrl::fromLocalFile(filename));
0949 }
0950 
0951 void TimeTrackerWidget::importPlannerFile(const QString &filename)
0952 {
0953     TaskView *taskView = currentTaskView();
0954     if (!taskView) {
0955         return;
0956     }
0957 
0958     taskView->importPlanner(filename);
0959 }
0960 
0961 bool TimeTrackerWidget::isActive(const QString &taskId) const
0962 {
0963     TaskView *taskView = currentTaskView();
0964     if (!taskView) {
0965         return false;
0966     }
0967 
0968     for (Task *task : taskView->storage()->tasksModel()->getAllTasks()) {
0969         if (task->uid() == taskId) {
0970             return task->isRunning();
0971         }
0972     }
0973 
0974     return false;
0975 }
0976 
0977 bool TimeTrackerWidget::isTaskNameActive(const QString &taskName) const
0978 {
0979     TaskView *taskView = currentTaskView();
0980     if (!taskView) {
0981         return false;
0982     }
0983 
0984     for (Task *task : taskView->storage()->tasksModel()->getAllTasks()) {
0985         if (task->name() == taskName) {
0986             return task->isRunning();
0987         }
0988     }
0989 
0990     return false;
0991 }
0992 
0993 QStringList TimeTrackerWidget::tasks() const
0994 {
0995     QStringList result;
0996 
0997     TaskView *taskView = currentTaskView();
0998     if (!taskView) {
0999         return result;
1000     }
1001 
1002     for (Task *task : taskView->storage()->tasksModel()->getAllTasks()) {
1003         result << task->name();
1004     }
1005 
1006     return result;
1007 }
1008 
1009 QStringList TimeTrackerWidget::activeTasks() const
1010 {
1011     QStringList result;
1012     TaskView *taskView = currentTaskView();
1013     if (!taskView) {
1014         return result;
1015     }
1016 
1017     for (Task *task : taskView->storage()->tasksModel()->getActiveTasks()) {
1018         result << task->name();
1019     }
1020 
1021     return result;
1022 }
1023 
1024 void TimeTrackerWidget::saveAll()
1025 {
1026     currentTaskView()->save();
1027 }
1028 
1029 void TimeTrackerWidget::quit()
1030 {
1031     auto *mainWindow = dynamic_cast<MainWindow *>(parent()->parent());
1032     if (mainWindow) {
1033         mainWindow->quit();
1034     } else {
1035         qCWarning(KTT_LOG) << "Cast to MainWindow failed";
1036     }
1037 }
1038 
1039 bool TimeTrackerWidget::event(QEvent *event) // inherited from QWidget
1040 {
1041     if (event->type() == QEvent::QueryWhatsThis) {
1042         if (m_taskView->storage()->tasksModel()->getAllTasks().empty()) {
1043             setWhatsThis(i18nc("@info:whatsthis",
1044                                "This is ktimetracker, KDE's program to help "
1045                                "you track your time. "
1046                                "Best, start with creating your first task - "
1047                                "enter it into the field "
1048                                "where you see \"Search or add task\"."));
1049         } else {
1050             setWhatsThis(i18nc("@info:whatsthis",
1051                                "You have already created a task. You can now "
1052                                "start and stop timing."));
1053         }
1054     }
1055 
1056     return QWidget::event(event);
1057 }
1058 // END of dbus slots group
1059 /* @} */
1060 
1061 #include "moc_timetrackerwidget.cpp"