tasksWidget.cpp 9.28 KB
Newer Older
1
2
3
4
5
6
7
/*
    KT list view item tasks implementation.
    --------------------------------------------------------------------
    SPDX-FileCopyrightText: 1999 Gary Meyer <gary@meyer.net>
    --------------------------------------------------------------------
    SPDX-License-Identifier: GPL-2.0-or-later
*/
Nicolas Ternisien's avatar
Nicolas Ternisien committed
8
9
10

#include "tasksWidget.h"

Nicolas Ternisien's avatar
Nicolas Ternisien committed
11
12
#include <QAction>
#include <QList>
Laurent Montel's avatar
Laurent Montel committed
13
#include <QProcess>
Nicolas Ternisien's avatar
Nicolas Ternisien committed
14

Laurent Montel's avatar
Laurent Montel committed
15
#include <KLocalizedString>
Laurent Montel's avatar
Laurent Montel committed
16
#include <KStandardAction>
Nicolas Ternisien's avatar
Nicolas Ternisien committed
17
18
19
20
21

#include "ctcron.h"
#include "cttask.h"
#include "ctvariable.h"

Nicolas Ternisien's avatar
   
Nicolas Ternisien committed
22
#include "crontabWidget.h"
Nicolas Ternisien's avatar
Nicolas Ternisien committed
23
#include "taskEditorDialog.h"
Laurent Montel's avatar
Laurent Montel committed
24
#include "taskWidget.h"
Nicolas Ternisien's avatar
Nicolas Ternisien committed
25

Laurent Montel's avatar
Laurent Montel committed
26
#include "kcm_cron_debug.h"
Nicolas Ternisien's avatar
Nicolas Ternisien committed
27
28
29
30

/**
 * Construct tasks folder from branch.
 */
31
32
33
34
TasksWidget::TasksWidget(CrontabWidget *crontabWidget)
    : GenericListWidget(crontabWidget, i18n("<b>Scheduled Tasks</b>"), QIcon::fromTheme(QStringLiteral("system-run")))
{
    refreshHeaders();
Nicolas Ternisien's avatar
Nicolas Ternisien committed
35

36
    treeWidget()->sortItems(1, Qt::AscendingOrder);
Nicolas Ternisien's avatar
Nicolas Ternisien committed
37

38
39
    setupActions(crontabWidget);
    prepareContextualMenu();
Nicolas Ternisien's avatar
Nicolas Ternisien committed
40

41
    connect(treeWidget(), &QTreeWidget::itemSelectionChanged, this, &TasksWidget::changeCurrentSelection);
Nicolas Ternisien's avatar
Nicolas Ternisien committed
42

Laurent Montel's avatar
Laurent Montel committed
43
    qCDebug(KCM_CRON_LOG) << "Tasks list created";
Nicolas Ternisien's avatar
Nicolas Ternisien committed
44
45
}

46
47
TasksWidget::~TasksWidget()
{
Nicolas Ternisien's avatar
Nicolas Ternisien committed
48
49
}

50
51
52
QList<TaskWidget *> TasksWidget::selectedTasksWidget() const
{
    QList<TaskWidget *> tasksWidget;
53

Laurent Montel's avatar
Laurent Montel committed
54
    const QList<QTreeWidgetItem *> tasksItems = treeWidget()->selectedItems();
Laurent Montel's avatar
Laurent Montel committed
55
    tasksWidget.reserve(tasksItems.count());
Laurent Montel's avatar
Laurent Montel committed
56
    for (QTreeWidgetItem *item : tasksItems) {
Laurent Montel's avatar
Laurent Montel committed
57
        auto taskWidget = static_cast<TaskWidget *>(item);
58
59
        tasksWidget.append(taskWidget);
    }
60

61
    return tasksWidget;
62
63
}

64
65
66
TaskWidget *TasksWidget::firstSelectedTaskWidget() const
{
    QTreeWidgetItem *item = firstSelected();
Laurent Montel's avatar
Laurent Montel committed
67
    if (!item) {
68
69
        return nullptr;
    }
70

71
    return static_cast<TaskWidget *>(item);
Nicolas Ternisien's avatar
Nicolas Ternisien committed
72
73
}

74
75
76
77
78
int TasksWidget::statusColumnIndex()
{
    if (needUserColumn()) {
        return 3;
    }
Nicolas Ternisien's avatar
Nicolas Ternisien committed
79

80
    return 2;
Nicolas Ternisien's avatar
Nicolas Ternisien committed
81
82
}

83
84
85
86
87
88
void TasksWidget::runTaskNow() const
{
    TaskWidget *taskWidget = firstSelectedTaskWidget();
    if (taskWidget == nullptr) {
        return;
    }
89

90
    CTCron *ctCron = crontabWidget()->currentCron();
Laurent Montel's avatar
Laurent Montel committed
91
    if (!ctCron) {
92
        qCDebug(KCM_CRON_LOG) << "Unable to find the related CtCron, please report this bug to the developers.";
93
94
        return;
    }
Nicolas Ternisien's avatar
Nicolas Ternisien committed
95

Laurent Montel's avatar
Laurent Montel committed
96
97
98
    const QString taskCommand = taskWidget->getCTTask()->command;

    const QString echoMessage = i18nc("Do not use any quote characters (') in this string", "End of script execution. Type Enter or Ctrl+C to exit.");
99
    QStringList commandList;
100

Laurent Montel's avatar
Laurent Montel committed
101
    const auto variables = ctCron->variables();
Laurent Montel's avatar
Laurent Montel committed
102
    commandList.reserve(variables.count() + 5);
Laurent Montel's avatar
Laurent Montel committed
103
    for (CTVariable *variable : variables) {
104
105
        commandList << QStringLiteral("export %1=\"%2\"").arg(variable->variable, variable->value);
    }
106

107
108
109
110
111
    commandList << taskCommand;
    commandList << QStringLiteral("echo '-------------------------------------------------------------------------'");
    commandList << QLatin1String("echo ") + echoMessage;
    commandList << QStringLiteral("echo '-------------------------------------------------------------------------'");
    commandList << QStringLiteral("read");
112

113
114
    QStringList parameters;
    parameters << QStringLiteral("-e") << QStringLiteral("bash") << QStringLiteral("-c");
115
    parameters << commandList.join(QLatin1Char(';'));
Nicolas Ternisien's avatar
Nicolas Ternisien committed
116

117
118
    QProcess process;
    process.startDetached(QStringLiteral("konsole"), parameters);
Nicolas Ternisien's avatar
Nicolas Ternisien committed
119
120
}

121
122
void TasksWidget::createTask()
{
Laurent Montel's avatar
Laurent Montel committed
123
    auto task =
Laurent Montel's avatar
Laurent Montel committed
124
        new CTTask(QLatin1String(""), QLatin1String(""), crontabWidget()->currentCron()->userLogin(), crontabWidget()->currentCron()->isMultiUserCron());
Nicolas Ternisien's avatar
Nicolas Ternisien committed
125

126
    TaskEditorDialog taskEditorDialog(task, i18n("New Task"), crontabWidget());
Laurent Montel's avatar
Laurent Montel committed
127
    const int result = taskEditorDialog.exec();
128

129
130
    if (result == QDialog::Accepted) {
        addTask(task);
Laurent Montel's avatar
Laurent Montel committed
131
        Q_EMIT taskModified(true);
132

133
134
135
136
        changeCurrentSelection();
    } else {
        delete task;
    }
Nicolas Ternisien's avatar
Nicolas Ternisien committed
137
138
}

139
140
141
void TasksWidget::addTask(CTTask *task)
{
    CTCron *cron = crontabWidget()->currentCron();
142

143
144
    cron->addTask(task);
    new TaskWidget(this, task);
145
}
Nicolas Ternisien's avatar
   
Nicolas Ternisien committed
146

147
148
149
void TasksWidget::modifySelection()
{
    modifySelection(firstSelectedTaskWidget(), -1);
150
151
}

152
153
void TasksWidget::modifySelection(QTreeWidgetItem *item, int position)
{
Laurent Montel's avatar
Laurent Montel committed
154
    auto taskWidget = static_cast<TaskWidget *>(item);
155
    if (taskWidget) {
156
157
        if (position == statusColumnIndex()) {
            taskWidget->toggleEnable();
Laurent Montel's avatar
Laurent Montel committed
158
            Q_EMIT taskModified(true);
159
160
161
162
163
164
165
166
        } else {
            CTTask *task = taskWidget->getCTTask();
            TaskEditorDialog taskEditorDialog(task, i18n("Modify Task"), crontabWidget());
            int result = taskEditorDialog.exec();

            if (result == QDialog::Accepted) {
                crontabWidget()->currentCron()->modifyTask(task);
                taskWidget->refresh();
Laurent Montel's avatar
Laurent Montel committed
167
                Q_EMIT taskModified(true);
168
169
170
171
            }
        }
    }

Laurent Montel's avatar
Laurent Montel committed
172
    qCDebug(KCM_CRON_LOG) << "End of modification";
173
174
}

175
176
void TasksWidget::deleteSelection()
{
Laurent Montel's avatar
Laurent Montel committed
177
    qCDebug(KCM_CRON_LOG) << "Selection deleting...";
178

Laurent Montel's avatar
Laurent Montel committed
179
    const QList<QTreeWidgetItem *> tasksItems = treeWidget()->selectedItems();
180

181
    bool deleteSomething = !(tasksItems.isEmpty());
182

Laurent Montel's avatar
Laurent Montel committed
183
    for (QTreeWidgetItem *item : tasksItems) {
Laurent Montel's avatar
Laurent Montel committed
184
        auto taskWidget = static_cast<TaskWidget *>(item);
185

186
187
188
189
190
        crontabWidget()->currentCron()->removeTask(taskWidget->getCTTask());
        delete taskWidget->getCTTask();
        treeWidget()->takeTopLevelItem(treeWidget()->indexOfTopLevelItem(taskWidget));
        delete taskWidget;
    }
191

192
    if (deleteSomething) {
Laurent Montel's avatar
Laurent Montel committed
193
        Q_EMIT taskModified(true);
194
195
        changeCurrentSelection();
    }
196

Laurent Montel's avatar
Laurent Montel committed
197
    qCDebug(KCM_CRON_LOG) << "End of deletion";
198
199
}

200
201
void TasksWidget::refreshTasks(CTCron *cron)
{
Laurent Montel's avatar
Laurent Montel committed
202
    // Remove previous items
203
    removeAll();
204

205
    refreshHeaders();
206

Laurent Montel's avatar
Laurent Montel committed
207
    // Add new items
208
209
    const auto tasks = cron->tasks();
    for (CTTask *ctTask : tasks) {
210
211
        new TaskWidget(this, ctTask);
    }
Nicolas Ternisien's avatar
   
Nicolas Ternisien committed
212

213
    resizeColumnContents();
Nicolas Ternisien's avatar
   
Nicolas Ternisien committed
214
}
215

216
217
218
void TasksWidget::refreshHeaders()
{
    QStringList headerLabels;
219

220
221
222
    if (needUserColumn()) {
        headerLabels << i18n("User");
    }
223

224
    headerLabels << i18n("Scheduling");
225

226
227
228
229
    headerLabels << i18n("Command");
    headerLabels << i18n("Status");
    headerLabels << i18n("Description");
    headerLabels << i18n("Scheduling Details");
230

231
    treeWidget()->setHeaderLabels(headerLabels);
232

233
234
235
236
237
    if (needUserColumn()) {
        treeWidget()->setColumnCount(6);
    } else {
        treeWidget()->setColumnCount(5);
    }
238
}
239

240
241
242
243
244
245
bool TasksWidget::needUserColumn() const
{
    CTCron *ctCron = crontabWidget()->currentCron();
    if (ctCron && ctCron->isMultiUserCron()) {
        return true;
    }
246

247
    return false;
248
}
Nicolas Ternisien's avatar
Nicolas Ternisien committed
249

250
251
void TasksWidget::setupActions(CrontabWidget *crontabWidget)
{
Laurent Montel's avatar
Laurent Montel committed
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
    mNewTaskAction = new QAction(this);
    mNewTaskAction->setIcon(QIcon::fromTheme(QStringLiteral("document-new")));
    mNewTaskAction->setText(i18nc("Adds a new task", "New &Task..."));
    mNewTaskAction->setToolTip(i18n("Create a new task."));
    addRightAction(mNewTaskAction, this, SLOT(createTask()));

    mModifyAction = new QAction(this);
    mModifyAction->setText(i18n("M&odify..."));
    mModifyAction->setIcon(QIcon::fromTheme(QStringLiteral("document-open")));
    mModifyAction->setToolTip(i18n("Modify the selected task."));
    addRightAction(mModifyAction, this, SLOT(modifySelection()));

    mDeleteAction = new QAction(this);
    mDeleteAction->setText(i18n("&Delete"));
    mDeleteAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete")));
    mDeleteAction->setToolTip(i18n("Delete the selected task."));
    addRightAction(mDeleteAction, this, SLOT(deleteSelection()));

    mRunNowAction = new QAction(this);
    mRunNowAction->setText(i18n("&Run Now"));
    mRunNowAction->setIcon(QIcon::fromTheme(QStringLiteral("system-run")));
    mRunNowAction->setToolTip(i18n("Run the selected task now."));
    addRightAction(mRunNowAction, this, SLOT(runTaskNow()));

    mPrintAction = KStandardAction::print(crontabWidget, SLOT(print()), this);
    addRightAction(mPrintAction, crontabWidget, SLOT(print()));
278
279

    addRightStretch();
Nicolas Ternisien's avatar
Nicolas Ternisien committed
280
281
}

282
283
void TasksWidget::prepareContextualMenu()
{
Laurent Montel's avatar
Laurent Montel committed
284
    treeWidget()->addAction(mNewTaskAction);
Nicolas Ternisien's avatar
Nicolas Ternisien committed
285

286
    treeWidget()->addAction(createSeparator());
Nicolas Ternisien's avatar
Nicolas Ternisien committed
287

Laurent Montel's avatar
Laurent Montel committed
288
289
    treeWidget()->addAction(mModifyAction);
    treeWidget()->addAction(mDeleteAction);
Nicolas Ternisien's avatar
Nicolas Ternisien committed
290

291
    treeWidget()->addAction(createSeparator());
292
    const auto cutCopyPasteActions = crontabWidget()->cutCopyPasteActions();
Nicolas Ternisien's avatar
Nicolas Ternisien committed
293

294
    for (QAction *action : cutCopyPasteActions) {
295
296
        treeWidget()->addAction(action);
    }
Nicolas Ternisien's avatar
Nicolas Ternisien committed
297

298
    treeWidget()->addAction(createSeparator());
299

Laurent Montel's avatar
Laurent Montel committed
300
    treeWidget()->addAction(mRunNowAction);
Nicolas Ternisien's avatar
Nicolas Ternisien committed
301
302
}

303
304
void TasksWidget::toggleRunNowAction(bool state)
{
Laurent Montel's avatar
Laurent Montel committed
305
    setActionEnabled(mRunNowAction, state);
Nicolas Ternisien's avatar
Nicolas Ternisien committed
306
307
}

308
309
void TasksWidget::togglePrintAction(bool state)
{
Laurent Montel's avatar
Laurent Montel committed
310
    setActionEnabled(mPrintAction, state);
Nicolas Ternisien's avatar
Nicolas Ternisien committed
311
312
}

313
314
void TasksWidget::toggleModificationActions(bool state)
{
Laurent Montel's avatar
Laurent Montel committed
315
316
    setActionEnabled(mModifyAction, state);
    setActionEnabled(mDeleteAction, state);
Nicolas Ternisien's avatar
Nicolas Ternisien committed
317
318
}

319
320
void TasksWidget::toggleNewEntryAction(bool state)
{
Laurent Montel's avatar
Laurent Montel committed
321
    setActionEnabled(mNewTaskAction, state);
Nicolas Ternisien's avatar
Nicolas Ternisien committed
322
323
}

324
325
void TasksWidget::changeCurrentSelection()
{
Laurent Montel's avatar
Laurent Montel committed
326
    // qCDebug(KCM_CRON_LOG) << "Change selection...";
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342

    if (treeWidget()->topLevelItemCount() == 0) {
        togglePrintAction(false);
    } else {
        togglePrintAction(true);
    }

    bool enabled;
    if (treeWidget()->selectedItems().isEmpty()) {
        enabled = false;
    } else {
        enabled = true;
    }

    toggleModificationActions(enabled);
    toggleRunNowAction(enabled);
Nicolas Ternisien's avatar
Nicolas Ternisien committed
343
}