File indexing completed on 2024-04-21 05:45:51

0001 /*
0002     KT list view item tasks implementation.
0003     --------------------------------------------------------------------
0004     SPDX-FileCopyrightText: 1999 Gary Meyer <gary@meyer.net>
0005     --------------------------------------------------------------------
0006     SPDX-License-Identifier: GPL-2.0-or-later
0007 */
0008 
0009 #include "tasksWidget.h"
0010 
0011 #include <QAction>
0012 #include <QList>
0013 #include <QProcess>
0014 
0015 #include <KLocalizedString>
0016 #include <KStandardAction>
0017 
0018 #include "ctcron.h"
0019 #include "cttask.h"
0020 #include "ctvariable.h"
0021 
0022 #include "crontabWidget.h"
0023 #include "taskEditorDialog.h"
0024 #include "taskWidget.h"
0025 
0026 #include "kcm_cron_debug.h"
0027 
0028 /**
0029  * Construct tasks folder from branch.
0030  */
0031 TasksWidget::TasksWidget(CrontabWidget *crontabWidget)
0032     : GenericListWidget(crontabWidget, i18n("<b>Scheduled Tasks</b>"), QIcon::fromTheme(QStringLiteral("system-run")))
0033 {
0034     refreshHeaders();
0035 
0036     treeWidget()->sortItems(1, Qt::AscendingOrder);
0037 
0038     setupActions(crontabWidget);
0039     prepareContextualMenu();
0040 
0041     connect(treeWidget(), &QTreeWidget::itemSelectionChanged, this, &TasksWidget::changeCurrentSelection);
0042 
0043     qCDebug(KCM_CRON_LOG) << "Tasks list created";
0044 }
0045 
0046 TasksWidget::~TasksWidget()
0047 {
0048 }
0049 
0050 QList<TaskWidget *> TasksWidget::selectedTasksWidget() const
0051 {
0052     QList<TaskWidget *> tasksWidget;
0053 
0054     const QList<QTreeWidgetItem *> tasksItems = treeWidget()->selectedItems();
0055     tasksWidget.reserve(tasksItems.count());
0056     for (QTreeWidgetItem *item : tasksItems) {
0057         auto taskWidget = static_cast<TaskWidget *>(item);
0058         tasksWidget.append(taskWidget);
0059     }
0060 
0061     return tasksWidget;
0062 }
0063 
0064 TaskWidget *TasksWidget::firstSelectedTaskWidget() const
0065 {
0066     QTreeWidgetItem *item = firstSelected();
0067     if (!item) {
0068         return nullptr;
0069     }
0070 
0071     return static_cast<TaskWidget *>(item);
0072 }
0073 
0074 int TasksWidget::statusColumnIndex()
0075 {
0076     if (needUserColumn()) {
0077         return 3;
0078     }
0079 
0080     return 2;
0081 }
0082 
0083 void TasksWidget::runTaskNow() const
0084 {
0085     TaskWidget *taskWidget = firstSelectedTaskWidget();
0086     if (taskWidget == nullptr) {
0087         return;
0088     }
0089 
0090     CTCron *ctCron = crontabWidget()->currentCron();
0091     if (!ctCron) {
0092         qCDebug(KCM_CRON_LOG) << "Unable to find the related CtCron, please report this bug to the developers.";
0093         return;
0094     }
0095 
0096     const QString taskCommand = taskWidget->getCTTask()->command;
0097 
0098     const QString echoMessage = i18nc("Do not use any quote characters (') in this string", "End of script execution. Type Enter or Ctrl+C to exit.");
0099     QStringList commandList;
0100 
0101     const auto variables = ctCron->variables();
0102     commandList.reserve(variables.count() + 5);
0103     for (CTVariable *variable : variables) {
0104         commandList << QStringLiteral("export %1=\"%2\"").arg(variable->variable, variable->value);
0105     }
0106 
0107     commandList << taskCommand;
0108     commandList << QStringLiteral("echo '-------------------------------------------------------------------------'");
0109     commandList << QLatin1String("echo ") + echoMessage;
0110     commandList << QStringLiteral("echo '-------------------------------------------------------------------------'");
0111     commandList << QStringLiteral("read");
0112 
0113     QStringList parameters;
0114     parameters << QStringLiteral("-e") << QStringLiteral("bash") << QStringLiteral("-c");
0115     parameters << commandList.join(QLatin1Char(';'));
0116 
0117     QProcess process;
0118     process.startDetached(QStringLiteral("konsole"), parameters);
0119 }
0120 
0121 void TasksWidget::createTask()
0122 {
0123     // Gather necessary data to combine it into a CTTask, opening the taskEditor dialog.
0124     auto task =
0125         new CTTask(QLatin1String(""), QLatin1String(""), crontabWidget()->currentCron()->userLogin(), crontabWidget()->currentCron()->isMultiUserCron());
0126 
0127     TaskEditorDialog taskEditorDialog(task, i18n("New Task"), crontabWidget());
0128     const int result = taskEditorDialog.exec();
0129 
0130     // Signal that changes were made if the task was created, or clean up if not.
0131     if (result == QDialog::Accepted) {
0132         addTask(task);
0133         Q_EMIT taskModified(true);
0134 
0135         changeCurrentSelection();
0136     } else {
0137         delete task;
0138     }
0139 }
0140 
0141 void TasksWidget::addTask(CTTask *task)
0142 {
0143     CTCron *cron = crontabWidget()->currentCron();
0144 
0145     cron->addTask(task);
0146     new TaskWidget(this, task);
0147 }
0148 
0149 void TasksWidget::modifySelection()
0150 {
0151     modifySelection(firstSelectedTaskWidget(), -1);
0152 }
0153 
0154 void TasksWidget::modifySelection(QTreeWidgetItem *item, int position)
0155 {
0156     auto taskWidget = static_cast<TaskWidget *>(item);
0157     if (taskWidget) {
0158         if (position == statusColumnIndex()) {
0159             taskWidget->toggleEnable();
0160             Q_EMIT taskModified(true);
0161         } else {
0162             CTTask *task = taskWidget->getCTTask();
0163             TaskEditorDialog taskEditorDialog(task, i18n("Modify Task"), crontabWidget());
0164             int result = taskEditorDialog.exec();
0165 
0166             if (result == QDialog::Accepted) {
0167                 crontabWidget()->currentCron()->modifyTask(task);
0168                 taskWidget->refresh();
0169                 Q_EMIT taskModified(true);
0170             }
0171         }
0172     }
0173 
0174     qCDebug(KCM_CRON_LOG) << "End of modification";
0175 }
0176 
0177 void TasksWidget::deleteSelection()
0178 {
0179     qCDebug(KCM_CRON_LOG) << "Selection deleting...";
0180 
0181     const QList<QTreeWidgetItem *> tasksItems = treeWidget()->selectedItems();
0182 
0183     bool deleteSomething = !(tasksItems.isEmpty());
0184 
0185     for (QTreeWidgetItem *item : tasksItems) {
0186         auto taskWidget = static_cast<TaskWidget *>(item);
0187 
0188         crontabWidget()->currentCron()->removeTask(taskWidget->getCTTask());
0189         delete taskWidget->getCTTask();
0190         treeWidget()->takeTopLevelItem(treeWidget()->indexOfTopLevelItem(taskWidget));
0191         delete taskWidget;
0192     }
0193 
0194     if (deleteSomething) {
0195         Q_EMIT taskModified(true);
0196         changeCurrentSelection();
0197     }
0198 
0199     qCDebug(KCM_CRON_LOG) << "End of deletion";
0200 }
0201 
0202 void TasksWidget::refreshTasks(CTCron *cron)
0203 {
0204     // Remove previous items
0205     removeAll();
0206 
0207     refreshHeaders();
0208 
0209     // Add new items
0210     const auto tasks = cron->tasks();
0211     for (CTTask *ctTask : tasks) {
0212         new TaskWidget(this, ctTask);
0213     }
0214 
0215     resizeColumnContents();
0216 }
0217 
0218 void TasksWidget::refreshHeaders()
0219 {
0220     QStringList headerLabels;
0221 
0222     if (needUserColumn()) {
0223         headerLabels << i18n("User");
0224     }
0225 
0226     headerLabels << i18n("Scheduling");
0227 
0228     headerLabels << i18n("Command");
0229     headerLabels << i18n("Status");
0230     headerLabels << i18n("Description");
0231     headerLabels << i18n("Scheduling Details");
0232 
0233     treeWidget()->setHeaderLabels(headerLabels);
0234 
0235     if (needUserColumn()) {
0236         treeWidget()->setColumnCount(6);
0237     } else {
0238         treeWidget()->setColumnCount(5);
0239     }
0240 }
0241 
0242 bool TasksWidget::needUserColumn() const
0243 {
0244     CTCron *ctCron = crontabWidget()->currentCron();
0245     if (ctCron && ctCron->isMultiUserCron()) {
0246         return true;
0247     }
0248 
0249     return false;
0250 }
0251 
0252 void TasksWidget::setupActions(CrontabWidget *crontabWidget)
0253 {
0254     mNewTaskAction = new QAction(this);
0255     mNewTaskAction->setIcon(QIcon::fromTheme(QStringLiteral("document-new")));
0256     mNewTaskAction->setText(i18nc("Adds a new task", "New &Task..."));
0257     mNewTaskAction->setToolTip(i18n("Create a new task."));
0258     addRightAction(mNewTaskAction, this, SLOT(createTask()));
0259 
0260     mModifyAction = new QAction(this);
0261     mModifyAction->setText(i18n("M&odify..."));
0262     mModifyAction->setIcon(QIcon::fromTheme(QStringLiteral("document-open")));
0263     mModifyAction->setToolTip(i18n("Modify the selected task."));
0264     addRightAction(mModifyAction, this, SLOT(modifySelection()));
0265 
0266     mDeleteAction = new QAction(this);
0267     mDeleteAction->setText(i18n("&Delete"));
0268     mDeleteAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete")));
0269     mDeleteAction->setToolTip(i18n("Delete the selected task."));
0270     addRightAction(mDeleteAction, this, SLOT(deleteSelection()));
0271 
0272     mRunNowAction = new QAction(this);
0273     mRunNowAction->setText(i18n("&Run Now"));
0274     mRunNowAction->setIcon(QIcon::fromTheme(QStringLiteral("system-run")));
0275     mRunNowAction->setToolTip(i18n("Run the selected task now."));
0276     addRightAction(mRunNowAction, this, SLOT(runTaskNow()));
0277 
0278     mPrintAction = KStandardAction::print(crontabWidget, SLOT(print()), this);
0279     addRightAction(mPrintAction, crontabWidget, SLOT(print()));
0280 
0281     addRightStretch();
0282 }
0283 
0284 void TasksWidget::prepareContextualMenu()
0285 {
0286     treeWidget()->addAction(mNewTaskAction);
0287 
0288     treeWidget()->addAction(createSeparator());
0289 
0290     treeWidget()->addAction(mModifyAction);
0291     treeWidget()->addAction(mDeleteAction);
0292 
0293     treeWidget()->addAction(createSeparator());
0294     const auto cutCopyPasteActions = crontabWidget()->cutCopyPasteActions();
0295 
0296     for (QAction *action : cutCopyPasteActions) {
0297         treeWidget()->addAction(action);
0298     }
0299 
0300     treeWidget()->addAction(createSeparator());
0301 
0302     treeWidget()->addAction(mRunNowAction);
0303 }
0304 
0305 void TasksWidget::toggleRunNowAction(bool state)
0306 {
0307     setActionEnabled(mRunNowAction, state);
0308 }
0309 
0310 void TasksWidget::togglePrintAction(bool state)
0311 {
0312     setActionEnabled(mPrintAction, state);
0313 }
0314 
0315 void TasksWidget::toggleModificationActions(bool state)
0316 {
0317     setActionEnabled(mModifyAction, state);
0318     setActionEnabled(mDeleteAction, state);
0319 }
0320 
0321 void TasksWidget::toggleNewEntryAction(bool state)
0322 {
0323     setActionEnabled(mNewTaskAction, state);
0324 }
0325 
0326 void TasksWidget::changeCurrentSelection()
0327 {
0328     // qCDebug(KCM_CRON_LOG) << "Change selection...";
0329 
0330     if (treeWidget()->topLevelItemCount() == 0) {
0331         togglePrintAction(false);
0332     } else {
0333         togglePrintAction(true);
0334     }
0335 
0336     bool enabled;
0337     if (treeWidget()->selectedItems().isEmpty()) {
0338         enabled = false;
0339     } else {
0340         enabled = true;
0341     }
0342 
0343     toggleModificationActions(enabled);
0344     toggleRunNowAction(enabled);
0345 }
0346 
0347 #include "moc_tasksWidget.cpp"