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 "e) 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"