File indexing completed on 2024-04-21 05:45:51
0001 /* 0002 KT task editor window 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 "taskEditorDialog.h" 0010 0011 #include <QCheckBox> 0012 #include <QEvent> 0013 #include <QGridLayout> 0014 #include <QHBoxLayout> 0015 #include <QPalette> 0016 #include <QPushButton> 0017 #include <QStandardPaths> 0018 #include <QVBoxLayout> 0019 0020 #include <QLocale> 0021 0022 #include <QStyleOption> 0023 #include <QStylePainter> 0024 0025 #include <KAcceleratorManager> 0026 #include <KLocalizedString> 0027 #include <KStandardShortcut> 0028 #include <QDialogButtonBox> 0029 #include <QPushButton> 0030 #include <kurlrequester.h> 0031 0032 #include "cttask.h" 0033 #include "kcm_cron_debug.h" 0034 0035 #include "crontabWidget.h" 0036 0037 #include "kcronHelper.h" 0038 0039 /** 0040 * TaskEditorDialog class implementation 0041 */ 0042 0043 TaskEditorDialog::TaskEditorDialog(CTTask *_ctTask, const QString &_caption, CrontabWidget *_crontabWidget) 0044 : QDialog(_crontabWidget) 0045 { 0046 setModal(true); 0047 0048 // window 0049 setWindowIcon(QIcon::fromTheme(QStringLiteral("kcron"))); 0050 setWindowTitle(_caption); 0051 0052 mCtTask = _ctTask; 0053 mCrontabWidget = _crontabWidget; 0054 0055 auto main = new QWidget(this); 0056 auto mainLayout = new QVBoxLayout(main); 0057 mainLayout->setContentsMargins(0, 0, 0, 0); 0058 0059 auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); 0060 mOkButton = buttonBox->button(QDialogButtonBox::Ok); 0061 0062 auto dialogLayout = new QVBoxLayout(); 0063 dialogLayout->addWidget(main); 0064 dialogLayout->addWidget(buttonBox); 0065 setLayout(dialogLayout); 0066 0067 // top title widget 0068 mTitleWidget = new KTitleWidget(main); 0069 mTitleWidget->setText(i18n("Add or modify a scheduled task")); 0070 setupTitleWidget(i18n("<i>This task will be executed at the specified intervals.</i>")); 0071 0072 mainLayout->addWidget(mTitleWidget); 0073 0074 auto commandConfigurationLayout = new QGridLayout(); 0075 mainLayout->addLayout(commandConfigurationLayout); 0076 0077 // command 0078 auto labCommand = new QLabel(i18n("&Command:"), main); 0079 commandConfigurationLayout->addWidget(labCommand, 0, 0); 0080 0081 auto commandLayout = new QHBoxLayout(); 0082 mCommandIcon = new QLabel(main); 0083 mMissingCommandPixmap = QIcon::fromTheme(QStringLiteral("image-missing")).pixmap(style()->pixelMetric(QStyle::PM_SmallIconSize, nullptr, this)); 0084 commandLayout->addWidget(mCommandIcon); 0085 0086 mCommand = new KUrlRequester(main); 0087 labCommand->setBuddy(mCommand); 0088 commandLayout->addWidget(mCommand); 0089 0090 mCommand->setMode(KFile::File | KFile::ExistingOnly | KFile::LocalOnly); 0091 mCommand->setUrl(QUrl::fromLocalFile(mCtTask->command)); 0092 0093 // Initialize special valid commands 0094 mSpecialValidCommands << QStringLiteral("cd"); 0095 0096 commandConfigurationLayout->addLayout(commandLayout, 0, 1); 0097 0098 // User Combo 0099 auto userLabel = new QLabel(i18n("&Run as:"), main); 0100 commandConfigurationLayout->addWidget(userLabel, 1, 0); 0101 0102 mUserCombo = new QComboBox(main); 0103 0104 userLabel->setBuddy(mUserCombo); 0105 commandConfigurationLayout->addWidget(mUserCombo, 1, 1); 0106 0107 // When in multiuser (system) mode, a user column is required. 0108 if (mCrontabWidget->tasksWidget()->needUserColumn()) { 0109 KCronHelper::initUserCombo(mUserCombo, mCrontabWidget, mCtTask->userLogin); 0110 } else { 0111 userLabel->hide(); 0112 mUserCombo->hide(); 0113 } 0114 0115 // comment 0116 auto labComment = new QLabel(i18n("Co&mment:"), main); 0117 commandConfigurationLayout->addWidget(labComment, 2, 0, Qt::AlignTop); 0118 0119 mLeComment = KCronHelper::createCommentEdit(main); 0120 labComment->setBuddy(mLeComment); 0121 commandConfigurationLayout->addWidget(mLeComment, 2, 1); 0122 0123 mLeComment->setText(mCtTask->comment); 0124 0125 auto checkboxesLayout = new QHBoxLayout(); 0126 mainLayout->addLayout(checkboxesLayout); 0127 0128 // enabled 0129 mChkEnabled = new QCheckBox(i18n("&Enable this task"), main); 0130 mChkEnabled->setChecked(mCtTask->enabled); 0131 checkboxesLayout->addWidget(mChkEnabled); 0132 0133 // @reboot 0134 mChkReboot = new QCheckBox(i18n("Run at system &bootup"), main); 0135 mChkReboot->setChecked(mCtTask->reboot); 0136 checkboxesLayout->addWidget(mChkReboot); 0137 0138 // Every day 0139 bool everyDay = isEveryDay(); 0140 mCbEveryDay = new QCheckBox(i18n("Run &every day"), main); 0141 mCbEveryDay->setChecked(everyDay); 0142 checkboxesLayout->addWidget(mCbEveryDay); 0143 0144 auto schedulingLayout = new QHBoxLayout(); 0145 mainLayout->addLayout(schedulingLayout); 0146 0147 auto monthLayout = new QVBoxLayout(); 0148 schedulingLayout->addLayout(monthLayout); 0149 0150 // months 0151 mBgMonth = createMonthsGroup(main); 0152 monthLayout->addWidget(mBgMonth); 0153 monthLayout->addStretch(1); 0154 0155 auto v1 = new QVBoxLayout(); 0156 schedulingLayout->addLayout(v1); 0157 0158 // days of the month 0159 mBgDayOfMonth = createDaysOfMonthGroup(main); 0160 v1->addWidget(mBgDayOfMonth); 0161 0162 // days of the week 0163 mBgDayOfWeek = createDaysOfWeekGroup(main); 0164 v1->addWidget(mBgDayOfWeek); 0165 0166 v1->addStretch(1); 0167 0168 auto v2 = new QVBoxLayout(); 0169 schedulingLayout->addLayout(v2); 0170 0171 mHoursGroup = createHoursGroup(main); 0172 v2->addWidget(mHoursGroup); 0173 0174 createMinutesGroup(main); 0175 v2->addWidget(mMinutesGroup); 0176 0177 v2->addStretch(1); 0178 0179 // schedulingLayout->addStretch(1); 0180 0181 mCommand->setFocus(); 0182 0183 connect(mCommand, &KUrlRequester::textChanged, this, &TaskEditorDialog::slotWizard); 0184 0185 connect(mChkEnabled, &QCheckBox::clicked, this, &TaskEditorDialog::slotEnabledChanged); 0186 connect(mChkEnabled, &QCheckBox::clicked, this, &TaskEditorDialog::slotWizard); 0187 0188 connect(mChkReboot, &QCheckBox::clicked, this, &TaskEditorDialog::slotRebootChanged); 0189 connect(mChkReboot, &QCheckBox::clicked, this, &TaskEditorDialog::slotWizard); 0190 0191 connect(mCbEveryDay, &QCheckBox::clicked, this, &TaskEditorDialog::slotDailyChanged); 0192 connect(mCbEveryDay, &QCheckBox::clicked, this, &TaskEditorDialog::slotWizard); 0193 0194 connect(buttonBox, &QDialogButtonBox::accepted, this, &TaskEditorDialog::slotOK); 0195 connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); 0196 0197 if (!mChkEnabled->isChecked()) { 0198 slotEnabledChanged(); 0199 } else if (mChkReboot->isChecked()) { 0200 slotRebootChanged(); 0201 } else if (mCbEveryDay->isChecked()) { 0202 slotDailyChanged(); 0203 } 0204 0205 slotMonthChanged(); 0206 slotDayOfMonthChanged(); 0207 slotDayOfWeekChanged(); 0208 slotHourChanged(); 0209 slotMinuteChanged(); 0210 0211 slotWizard(); 0212 } 0213 0214 TaskEditorDialog::~TaskEditorDialog() 0215 { 0216 } 0217 0218 bool TaskEditorDialog::isEveryDay() 0219 { 0220 for (int dw = CTDayOfWeek::MINIMUM; dw <= CTDayOfWeek::MAXIMUM; dw++) { 0221 if (!mCtTask->dayOfWeek.isEnabled(dw)) { 0222 return false; 0223 } 0224 } 0225 0226 for (int mo = mCtTask->month.minimum(); mo <= mCtTask->month.maximum(); mo++) { 0227 if (!mCtTask->month.isEnabled(mo)) { 0228 return false; 0229 } 0230 } 0231 0232 for (int dm = CTDayOfMonth::MINIMUM; dm <= CTDayOfMonth::MAXIMUM; dm++) { 0233 if (!mCtTask->dayOfMonth.isEnabled(dm)) { 0234 return false; 0235 } 0236 } 0237 0238 return true; 0239 } 0240 0241 QGroupBox *TaskEditorDialog::createDaysOfMonthGroup(QWidget *main) 0242 { 0243 auto daysOfMonthGroup = new QGroupBox(i18n("Days of Month"), main); 0244 auto daysOfMonthLayout = new QGridLayout(daysOfMonthGroup); 0245 0246 int dm = CTDayOfMonth::MINIMUM; 0247 for (int row = 0; row < 5; ++row) { 0248 for (int column = 0; column < 7; ++column) { 0249 auto day = new NumberPushButton(true, daysOfMonthGroup); 0250 day->setText(QString::number(dm)); 0251 day->setCheckable(true); 0252 day->setChecked(mCtTask->dayOfMonth.isEnabled(dm)); 0253 mDayOfMonthButtons[dm] = day; 0254 0255 connect(mDayOfMonthButtons[dm], &QAbstractButton::clicked, this, &TaskEditorDialog::slotDayOfMonthChanged); 0256 connect(mDayOfMonthButtons[dm], &QAbstractButton::clicked, this, &TaskEditorDialog::slotWizard); 0257 0258 daysOfMonthLayout->addWidget(day, row, column); 0259 0260 if (dm == CTDayOfMonth::MAXIMUM) { 0261 break; 0262 break; 0263 } 0264 0265 dm++; 0266 } 0267 } 0268 0269 mAllDaysOfMonth = new SetOrClearAllButton(daysOfMonthGroup, SetOrClearAllButton::SET_ALL); 0270 daysOfMonthLayout->addWidget(mAllDaysOfMonth, 4, 3, 1, 4); 0271 0272 connect(mAllDaysOfMonth, &SetOrClearAllButton::clicked, this, &TaskEditorDialog::slotAllDaysOfMonth); 0273 connect(mAllDaysOfMonth, &SetOrClearAllButton::clicked, this, &TaskEditorDialog::slotWizard); 0274 0275 return daysOfMonthGroup; 0276 } 0277 0278 QGroupBox *TaskEditorDialog::createMonthsGroup(QWidget *main) 0279 { 0280 auto monthsGroup = new QGroupBox(i18n("Months"), main); 0281 auto monthsLayout = new QGridLayout(monthsGroup); 0282 0283 int column = 0; 0284 int row = 0; 0285 0286 for (int mo = CTMonth::MINIMUM; mo <= CTMonth::MAXIMUM; mo++) { 0287 mMonthButtons[mo] = new NumberPushButton(monthsGroup); 0288 mMonthButtons[mo]->setText(mCtTask->month.getName(mo)); 0289 mMonthButtons[mo]->setCheckable(true); 0290 mMonthButtons[mo]->setChecked(mCtTask->month.isEnabled(mo)); 0291 0292 monthsLayout->addWidget(mMonthButtons[mo], row, column); 0293 0294 connect(mMonthButtons[mo], &QAbstractButton::clicked, this, &TaskEditorDialog::slotMonthChanged); 0295 connect(mMonthButtons[mo], &QAbstractButton::clicked, this, &TaskEditorDialog::slotWizard); 0296 0297 if (column == 1) { 0298 column = 0; 0299 row++; 0300 } else { 0301 column = 1; 0302 } 0303 } 0304 0305 mAllMonths = new SetOrClearAllButton(monthsGroup, SetOrClearAllButton::SET_ALL); 0306 monthsLayout->addWidget(mAllMonths, row, 0, 1, 2); 0307 0308 connect(mAllMonths, &SetOrClearAllButton::clicked, this, &TaskEditorDialog::slotAllMonths); 0309 connect(mAllMonths, &SetOrClearAllButton::clicked, this, &TaskEditorDialog::slotWizard); 0310 0311 return monthsGroup; 0312 } 0313 0314 QGroupBox *TaskEditorDialog::createDaysOfWeekGroup(QWidget *main) 0315 { 0316 auto daysOfWeekGroup = new QGroupBox(i18n("Days of Week"), main); 0317 auto daysOfWeekLayout = new QGridLayout(daysOfWeekGroup); 0318 0319 int column = 0; 0320 int row = 0; 0321 for (int dw = CTDayOfWeek::MINIMUM; dw <= CTDayOfWeek::MAXIMUM; dw++) { 0322 mDayOfWeekButtons[dw] = new NumberPushButton(daysOfWeekGroup); 0323 mDayOfWeekButtons[dw]->setText(mCtTask->dayOfWeek.getName(dw)); 0324 mDayOfWeekButtons[dw]->setCheckable(true); 0325 mDayOfWeekButtons[dw]->setChecked(mCtTask->dayOfWeek.isEnabled(dw)); 0326 daysOfWeekLayout->addWidget(mDayOfWeekButtons[dw], row, column); 0327 0328 connect(mDayOfWeekButtons[dw], &QAbstractButton::clicked, this, &TaskEditorDialog::slotDayOfWeekChanged); 0329 connect(mDayOfWeekButtons[dw], &QAbstractButton::clicked, this, &TaskEditorDialog::slotWizard); 0330 0331 if (column == 1) { 0332 column = 0; 0333 row++; 0334 } else { 0335 column = 1; 0336 } 0337 } 0338 0339 mAllDaysOfWeek = new SetOrClearAllButton(daysOfWeekGroup, SetOrClearAllButton::SET_ALL); 0340 daysOfWeekLayout->addWidget(mAllDaysOfWeek); 0341 0342 connect(mAllDaysOfWeek, &SetOrClearAllButton::clicked, this, &TaskEditorDialog::slotAllDaysOfWeek); 0343 connect(mAllDaysOfWeek, &SetOrClearAllButton::clicked, this, &TaskEditorDialog::slotWizard); 0344 0345 return daysOfWeekGroup; 0346 } 0347 0348 bool TaskEditorDialog::canReduceMinutesGroup() 0349 { 0350 for (int minuteIndex = 0; minuteIndex <= minuteTotal; ++minuteIndex) { 0351 if (minuteIndex % reducedMinuteStep != 0) { 0352 if (mMinuteButtons[minuteIndex]->isChecked()) { 0353 return false; 0354 } 0355 } 0356 } 0357 0358 return true; 0359 } 0360 0361 void TaskEditorDialog::emptyMinutesGroup() 0362 { 0363 qCDebug(KCM_CRON_LOG) << "Empty minutes layout"; 0364 0365 for (int minuteIndex = 0; minuteIndex <= minuteTotal; ++minuteIndex) { 0366 mMinutesLayout->removeWidget(mMinuteButtons[minuteIndex]); 0367 mMinuteButtons[minuteIndex]->hide(); 0368 qCDebug(KCM_CRON_LOG) << "Layout count" << mMinutesLayout->count(); 0369 } 0370 0371 mMinutesLayout->removeItem(mMinutesPreselectionLayout); 0372 } 0373 0374 void TaskEditorDialog::increaseMinutesGroup() 0375 { 0376 /* 0377 * Test if the increase is already done. If this is the case, no need to redo it 0378 * 0379 * We test : 0380 * minutesButtons[1] will be hidden because 1%reducedMinuteStep != 0 0381 */ 0382 /* 0383 if (minuteButtons[1]->isHidden() == false) 0384 return; 0385 */ 0386 emptyMinutesGroup(); 0387 0388 qCDebug(KCM_CRON_LOG) << "Show all minutes"; 0389 0390 int minuteIndex = 0; 0391 for (int row = 0; row < (minuteTotal + 1) / minutePerColumn; ++row) { 0392 for (int column = 0; column < minutePerColumn; ++column) { 0393 mMinutesLayout->addWidget(mMinuteButtons[minuteIndex], row, column); 0394 mMinuteButtons[minuteIndex]->show(); 0395 minuteIndex++; 0396 } 0397 } 0398 0399 mMinutesLayout->addLayout(mMinutesPreselectionLayout, ((minuteTotal + 1) / minutePerColumn), 0, 1, minutePerColumn); 0400 mMinutesLayout->invalidate(); 0401 this->resize(sizeHint()); 0402 } 0403 0404 void TaskEditorDialog::reduceMinutesGroup() 0405 { 0406 qCDebug(KCM_CRON_LOG) << "Reducing view"; 0407 0408 emptyMinutesGroup(); 0409 0410 int nextRow = 0; 0411 int nextColumn = 0; 0412 0413 for (int minuteIndex = 0; minuteIndex <= minuteTotal; ++minuteIndex) { 0414 if (minuteIndex % reducedMinuteStep == 0) { 0415 mMinutesLayout->addWidget(mMinuteButtons[minuteIndex], nextRow, nextColumn); 0416 mMinuteButtons[minuteIndex]->show(); 0417 0418 nextColumn++; 0419 if (nextColumn == 6) { 0420 nextColumn = 0; 0421 nextRow = 1; 0422 } 0423 } else { 0424 qCDebug(KCM_CRON_LOG) << "Reducing id" << minuteIndex; 0425 mCtTask->minute.setEnabled(minuteIndex, false); 0426 mMinuteButtons[minuteIndex]->setChecked(false); 0427 } 0428 } 0429 0430 mMinutesLayout->addLayout(mMinutesPreselectionLayout, 2, 0, 1, 6); 0431 mMinutesLayout->invalidate(); 0432 this->resize(sizeHint()); 0433 } 0434 0435 NumberPushButton *TaskEditorDialog::createMinuteButton(int minuteIndex) 0436 { 0437 auto minuteButton = new NumberPushButton(true, mMinutesGroup); 0438 minuteButton->setText(QString::number(minuteIndex)); 0439 minuteButton->setCheckable(true); 0440 minuteButton->setChecked(mCtTask->minute.isEnabled(minuteIndex)); 0441 0442 connect(minuteButton, &NumberPushButton::clicked, this, &TaskEditorDialog::slotMinuteChanged); 0443 connect(minuteButton, &NumberPushButton::clicked, this, &TaskEditorDialog::slotWizard); 0444 0445 return minuteButton; 0446 } 0447 0448 void TaskEditorDialog::createMinutesGroup(QWidget *main) 0449 { 0450 qCDebug(KCM_CRON_LOG) << "Creating minutes group"; 0451 0452 mMinutesGroup = new QGroupBox(i18n("Minutes"), main); 0453 0454 mMinutesLayout = new QGridLayout(mMinutesGroup); 0455 0456 for (int minuteIndex = 0; minuteIndex <= minuteTotal; ++minuteIndex) { 0457 mMinuteButtons[minuteIndex] = createMinuteButton(minuteIndex); 0458 } 0459 0460 mMinutesPreselectionLayout = new QHBoxLayout(); 0461 0462 auto minutesPreselectionLabel = new QLabel(i18n("Preselection:")); 0463 mMinutesPreselectionLayout->addWidget(minutesPreselectionLabel); 0464 0465 mMinutesPreselection = new QComboBox(this); 0466 0467 minutesPreselectionLabel->setBuddy(mMinutesPreselection); 0468 0469 mMinutesPreselection->addItem(QIcon::fromTheme(QStringLiteral("edit-clear-locationbar-ltr")), i18n("Clear selection"), -1); 0470 mMinutesPreselection->addItem(QIcon::fromTheme(QStringLiteral("edit-rename")), i18n("Custom selection"), 0); 0471 mMinutesPreselection->addItem(QIcon::fromTheme(QStringLiteral("view-calendar-month")), i18n("Each minute"), 1); 0472 mMinutesPreselection->addItem(QIcon::fromTheme(QStringLiteral("view-calendar-week")), i18n("Every 2 minutes"), 2); 0473 mMinutesPreselection->addItem(QIcon::fromTheme(QStringLiteral("view-calendar-workweek")), i18n("Every 5 minutes"), 5); 0474 mMinutesPreselection->addItem(QIcon::fromTheme(QStringLiteral("view-calendar-upcoming-days")), i18n("Every 10 minutes"), 10); 0475 mMinutesPreselection->addItem(QIcon::fromTheme(QStringLiteral("view-calendar-upcoming-days")), i18n("Every 15 minutes"), 15); 0476 mMinutesPreselection->addItem(QIcon::fromTheme(QStringLiteral("view-calendar-day")), i18n("Every 20 minutes"), 20); 0477 mMinutesPreselection->addItem(QIcon::fromTheme(QStringLiteral("view-calendar-day")), i18n("Every 30 minutes"), 30); 0478 0479 mMinutesPreselectionLayout->addWidget(mMinutesPreselection); 0480 0481 connect(mMinutesPreselection, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this, &TaskEditorDialog::slotMinutesPreselection); 0482 connect(mMinutesPreselection, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this, &TaskEditorDialog::slotWizard); 0483 0484 // First mandatory increase 0485 increaseMinutesGroup(); 0486 0487 if (canReduceMinutesGroup()) { 0488 reduceMinutesGroup(); 0489 } 0490 0491 qCDebug(KCM_CRON_LOG) << "Minutes group created"; 0492 } 0493 0494 NumberPushButton *TaskEditorDialog::createHourButton(QGroupBox *hoursGroup, int hour) 0495 { 0496 auto hourButton = new NumberPushButton(true, hoursGroup); 0497 hourButton->setText(QString::number(hour)); 0498 hourButton->setCheckable(true); 0499 hourButton->setChecked(mCtTask->hour.isEnabled(hour)); 0500 0501 connect(hourButton, &NumberPushButton::clicked, this, &TaskEditorDialog::slotHourChanged); 0502 connect(hourButton, &NumberPushButton::clicked, this, &TaskEditorDialog::slotWizard); 0503 0504 return hourButton; 0505 } 0506 0507 QGroupBox *TaskEditorDialog::createHoursGroup(QWidget *main) 0508 { 0509 // Hide the AM/PM labels if the locale is set to 24h format. 0510 // 'A' or 'a' means am/pm is shown (and then 'h' uses 12-hour format) 0511 // but 'H' forces a 24-hour format anyway, even with am/pm shown. 0512 const QString str = QLocale().timeFormat(); 0513 static bool use12Clock = str.contains(QLatin1Char('a'), Qt::CaseInsensitive) && !str.contains(QLatin1Char('H')); 0514 0515 qCDebug(KCM_CRON_LOG) << "Creating hours group"; 0516 auto hoursGroup = new QGroupBox(i18n("Hours"), main); 0517 0518 auto hoursLayout = new QGridLayout(hoursGroup); // 5 x 6 (24h) // 5 x 7 (12h) 0519 0520 if (use12Clock) { 0521 mMorningLabel = new QLabel(i18n("AM:"), this); 0522 mMorningLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); 0523 mMorningLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum); 0524 hoursLayout->addWidget(mMorningLabel, 0, 0, Qt::AlignLeft | Qt::AlignVCenter); 0525 } 0526 0527 int hourCount = 0; 0528 for (int column = 0; column <= 3; ++column) { 0529 for (int hour = 0; hour <= 5; ++hour) { 0530 NumberPushButton *hourButton = createHourButton(hoursGroup, hourCount); 0531 mHourButtons[hourCount] = hourButton; 0532 // When using the 12h format, the hour buttons need to be inserted 1 column over to leave room for the AM/PM labels. 0533 hoursLayout->addWidget(hourButton, column, hour + (use12Clock ? 1 : 0)); 0534 hourCount++; 0535 } 0536 } 0537 0538 if (use12Clock) { 0539 mAfternoonLabel = new QLabel(i18n("PM:"), this); 0540 mAfternoonLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); 0541 mAfternoonLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum); 0542 hoursLayout->addWidget(mAfternoonLabel, 2, 0, Qt::AlignLeft | Qt::AlignVCenter); 0543 } 0544 0545 mAllHours = new SetOrClearAllButton(this, SetOrClearAllButton::SET_ALL); 0546 hoursLayout->addWidget(mAllHours, 4, 0, 1, use12Clock ? 7 : 6); 0547 0548 connect(mAllHours, &SetOrClearAllButton::clicked, this, &TaskEditorDialog::slotAllHours); 0549 connect(mAllHours, &SetOrClearAllButton::clicked, this, &TaskEditorDialog::slotWizard); 0550 0551 qCDebug(KCM_CRON_LOG) << "Create hours group"; 0552 return hoursGroup; 0553 } 0554 0555 void TaskEditorDialog::setupTitleWidget(const QString &comment, KTitleWidget::MessageType messageType) 0556 { 0557 mTitleWidget->setComment(comment, messageType); 0558 if (messageType == KTitleWidget::ErrorMessage) { 0559 mTitleWidget->setIcon(QIcon::fromTheme(QStringLiteral("dialog-error")), KTitleWidget::ImageRight); 0560 } else { 0561 mTitleWidget->setIcon(QIcon::fromTheme(QStringLiteral("system-run")), KTitleWidget::ImageRight); 0562 } 0563 } 0564 0565 void TaskEditorDialog::slotEnabledChanged() 0566 { 0567 bool enabled = mChkEnabled->isChecked(); 0568 mUserCombo->setEnabled(enabled); 0569 mLeComment->setEnabled(enabled); 0570 mCommand->setEnabled(enabled); 0571 mChkReboot->setEnabled(enabled); 0572 0573 // if chkReboot is already checked, allow setEnabled(false) but not setEnable(true) ... 0574 if (!mChkReboot->isChecked() || !enabled) { 0575 mCbEveryDay->setEnabled(enabled); 0576 mHoursGroup->setEnabled(enabled); 0577 mMinutesGroup->setEnabled(enabled); 0578 } 0579 0580 // if cbEveryDay is already checked, allow setEnabled(false) but not setEnable(true) ... 0581 if ((!mChkReboot->isChecked() && !mCbEveryDay->isChecked()) || !enabled) { 0582 mBgMonth->setEnabled(enabled); 0583 mBgDayOfMonth->setEnabled(enabled); 0584 mBgDayOfWeek->setEnabled(enabled); 0585 } 0586 } 0587 0588 void TaskEditorDialog::slotRebootChanged() 0589 { 0590 bool reboot = !mChkReboot->isChecked(); 0591 mCbEveryDay->setEnabled(reboot); 0592 mHoursGroup->setEnabled(reboot); 0593 mMinutesGroup->setEnabled(reboot); 0594 0595 // if cbEveryDay is already checked, bgMonth, bgDayOfMonth, bgDayOfWeek are already setEnable(flase) 0596 // so don't override them ! ... 0597 if (!mCbEveryDay->isChecked()) { 0598 mBgMonth->setEnabled(reboot); 0599 mBgDayOfMonth->setEnabled(reboot); 0600 mBgDayOfWeek->setEnabled(reboot); 0601 } 0602 } 0603 0604 void TaskEditorDialog::slotDailyChanged() 0605 { 0606 if (mCbEveryDay->isChecked()) { 0607 for (int mo = 1; mo <= 12; mo++) { 0608 mMonthButtons[mo]->setChecked(true); 0609 } 0610 for (int dm = 1; dm <= 31; dm++) { 0611 mDayOfMonthButtons[dm]->setChecked(true); 0612 } 0613 for (int dw = 1; dw <= 7; dw++) { 0614 mDayOfWeekButtons[dw]->setChecked(true); 0615 } 0616 mBgMonth->setEnabled(false); 0617 mBgDayOfMonth->setEnabled(false); 0618 mBgDayOfWeek->setEnabled(false); 0619 mAllMonths->setEnabled(false); 0620 mAllDaysOfMonth->setEnabled(false); 0621 mAllDaysOfWeek->setEnabled(false); 0622 } else { 0623 mBgMonth->setEnabled(true); 0624 mBgDayOfMonth->setEnabled(true); 0625 mBgDayOfWeek->setEnabled(true); 0626 mAllMonths->setEnabled(true); 0627 mAllDaysOfMonth->setEnabled(true); 0628 mAllDaysOfWeek->setEnabled(true); 0629 } 0630 0631 slotMonthChanged(); 0632 slotDayOfMonthChanged(); 0633 slotDayOfWeekChanged(); 0634 } 0635 0636 void TaskEditorDialog::slotOK() 0637 { 0638 // Make it friendly for just selecting days of the month or 0639 // days of the week. 0640 0641 int monthDaysSelected(0); 0642 for (int dm = 1; dm <= 31; dm++) { 0643 if (mDayOfMonthButtons[dm]->isChecked()) { 0644 monthDaysSelected++; 0645 } 0646 } 0647 0648 int weekDaysSelected(0); 0649 for (int dw = 1; dw <= 7; dw++) { 0650 if (mDayOfWeekButtons[dw]->isChecked()) { 0651 weekDaysSelected++; 0652 } 0653 } 0654 0655 if ((monthDaysSelected == 0) && (weekDaysSelected > 0)) { 0656 for (int dm = 1; dm <= 31; dm++) { 0657 mDayOfMonthButtons[dm]->setChecked(true); 0658 } 0659 } 0660 0661 if ((weekDaysSelected == 0) && (monthDaysSelected > 0)) { 0662 for (int dw = 1; dw <= 7; dw++) { 0663 mDayOfWeekButtons[dw]->setChecked(true); 0664 } 0665 } 0666 0667 // save work in process 0668 if (mCrontabWidget->tasksWidget()->needUserColumn()) { 0669 mCtTask->userLogin = mUserCombo->currentText(); 0670 } 0671 0672 mCtTask->comment = mLeComment->toPlainText(); 0673 mCtTask->command = mCommand->url().path(); 0674 mCtTask->enabled = mChkEnabled->isChecked(); 0675 mCtTask->reboot = mChkReboot->isChecked(); 0676 0677 for (int mo = CTMonth::MINIMUM; mo <= CTMonth::MAXIMUM; mo++) { 0678 mCtTask->month.setEnabled(mo, mMonthButtons[mo]->isChecked()); 0679 } 0680 0681 for (int dm = 1; dm <= 31; dm++) { 0682 mCtTask->dayOfMonth.setEnabled(dm, mDayOfMonthButtons[dm]->isChecked()); 0683 } 0684 for (int dw = 1; dw <= 7; dw++) { 0685 mCtTask->dayOfWeek.setEnabled(dw, mDayOfWeekButtons[dw]->isChecked()); 0686 } 0687 for (int ho = 0; ho <= 23; ho++) { 0688 mCtTask->hour.setEnabled(ho, mHourButtons[ho]->isChecked()); 0689 } 0690 0691 for (int mi = 0; mi <= minuteTotal; ++mi) { 0692 mCtTask->minute.setEnabled(mi, mMinuteButtons[mi]->isChecked()); 0693 } 0694 0695 accept(); 0696 } 0697 0698 void TaskEditorDialog::defineCommandIcon() 0699 { 0700 CTTask tempTask(*mCtTask); 0701 tempTask.command = mCommand->url().path(); 0702 0703 mCommandIcon->setPixmap(tempTask.commandIcon().pixmap(style()->pixelMetric(QStyle::PM_SmallIconSize, nullptr, this))); 0704 } 0705 0706 bool TaskEditorDialog::checkCommand() 0707 { 0708 CTTask tempTask(*mCtTask); 0709 tempTask.command = mCommand->url().path(); 0710 0711 QPair<QString, bool> commandQuoted = tempTask.unQuoteCommand(); 0712 0713 if (commandQuoted.first.isEmpty()) { 0714 setupTitleWidget(i18n("<i>Please type a valid command line...</i>"), KTitleWidget::ErrorMessage); 0715 mOkButton->setEnabled(false); 0716 mCommand->setFocus(); 0717 mCommandIcon->setPixmap(mMissingCommandPixmap); 0718 0719 return false; 0720 } 0721 0722 QStringList pathCommand = tempTask.separatePathCommand(commandQuoted.first, commandQuoted.second); 0723 if (pathCommand.isEmpty()) { 0724 setupTitleWidget(i18n("<i>Please type a valid command line...</i>"), KTitleWidget::ErrorMessage); 0725 mOkButton->setEnabled(false); 0726 mCommand->setFocus(); 0727 mCommandIcon->setPixmap(mMissingCommandPixmap); 0728 0729 return false; 0730 } 0731 0732 QString path = pathCommand.at(0); 0733 QString binaryCommand = pathCommand.at(1); 0734 0735 qCDebug(KCM_CRON_LOG) << "Looking for " << binaryCommand << "in" << path; 0736 0737 bool found = false; 0738 bool exec = false; 0739 if (!QStandardPaths::findExecutable(binaryCommand, QStringList() << path).isEmpty() || mSpecialValidCommands.contains(binaryCommand)) { 0740 found = true; 0741 } 0742 // FIXME check if actually executable 0743 if (found) { 0744 exec = true; 0745 } 0746 0747 if (found && !exec) { 0748 setupTitleWidget(i18n("<i>Please select an executable program...</i>"), KTitleWidget::ErrorMessage); 0749 mOkButton->setEnabled(false); 0750 mCommand->setFocus(); 0751 mCommandIcon->setPixmap(mMissingCommandPixmap); 0752 return false; 0753 } 0754 0755 if (!found) { 0756 setupTitleWidget(i18n("<i>Please browse for a program to execute...</i>"), KTitleWidget::ErrorMessage); 0757 mOkButton->setEnabled(false); 0758 mCommand->setFocus(); 0759 mCommandIcon->setPixmap(mMissingCommandPixmap); 0760 return false; 0761 } 0762 0763 return true; 0764 } 0765 0766 void TaskEditorDialog::slotWizard() 0767 { 0768 if (!mChkEnabled->isChecked()) { 0769 setupTitleWidget(i18n("<i>This task is disabled.</i>")); 0770 mOkButton->setEnabled(true); 0771 mChkEnabled->setFocus(); 0772 return; 0773 } 0774 0775 if (mChkReboot->isChecked()) { 0776 setupTitleWidget(i18n("<i>This task will be run on system bootup.</i>")); 0777 mOkButton->setEnabled(true); 0778 return; 0779 } 0780 0781 if (mCommand->url().path().isEmpty()) { 0782 setupTitleWidget(i18n("<i>Please browse for a program to execute...</i>"), KTitleWidget::ErrorMessage); 0783 mOkButton->setEnabled(false); 0784 mCommand->setFocus(); 0785 mCommandIcon->setPixmap(mMissingCommandPixmap); 0786 return; 0787 } 0788 0789 bool validCommand = checkCommand(); 0790 if (!validCommand) { 0791 return; 0792 } 0793 0794 // the months 0795 bool valid(false); 0796 for (int mo = CTMonth::MINIMUM; mo <= CTMonth::MAXIMUM; mo++) { 0797 if (mMonthButtons[mo]->isChecked()) { 0798 valid = true; 0799 } 0800 } 0801 0802 if (!valid) { 0803 setupTitleWidget(i18n("<i>Please select from the 'Months' section...</i>"), KTitleWidget::ErrorMessage); 0804 mOkButton->setEnabled(false); 0805 if (!mCommand->hasFocus()) { 0806 mMonthButtons[1]->setFocus(); 0807 } 0808 return; 0809 } 0810 0811 // the days 0812 valid = false; 0813 for (int dm = CTDayOfMonth::MINIMUM; dm <= CTDayOfMonth::MAXIMUM; dm++) { 0814 if (mDayOfMonthButtons[dm]->isChecked()) { 0815 valid = true; 0816 } 0817 } 0818 for (int dw = CTDayOfWeek::MINIMUM; dw <= CTDayOfWeek::MAXIMUM; dw++) { 0819 if (mDayOfWeekButtons[dw]->isChecked()) { 0820 valid = true; 0821 } 0822 } 0823 0824 if (!valid) { 0825 setupTitleWidget(i18n("<i>Please select from either the 'Days of Month' or the 'Days of Week' section...</i>"), KTitleWidget::ErrorMessage); 0826 mOkButton->setEnabled(false); 0827 if (!mCommand->hasFocus()) { 0828 mDayOfMonthButtons[1]->setFocus(); 0829 } 0830 return; 0831 } 0832 0833 // the hours 0834 valid = false; 0835 for (int ho = 0; ho <= 23; ho++) { 0836 if (mHourButtons[ho]->isChecked()) { 0837 valid = true; 0838 } 0839 } 0840 0841 if (!valid) { 0842 setupTitleWidget(i18n("<i>Please select from the 'Hours' section...</i>"), KTitleWidget::ErrorMessage); 0843 mOkButton->setEnabled(false); 0844 if (!mCommand->hasFocus()) { 0845 mHourButtons[0]->setFocus(); 0846 } 0847 return; 0848 } 0849 0850 // the mins 0851 valid = false; 0852 for (int mi = 0; mi <= minuteTotal; ++mi) { 0853 if (mMinuteButtons[mi]->isChecked()) { 0854 valid = true; 0855 } 0856 } 0857 0858 if (!valid) { 0859 setupTitleWidget(i18n("<i>Please select from the 'Minutes' section...</i>"), KTitleWidget::ErrorMessage); 0860 mOkButton->setEnabled(false); 0861 if (!mCommand->hasFocus()) { 0862 mMinuteButtons[0]->setFocus(); 0863 } 0864 return; 0865 } 0866 0867 defineCommandIcon(); 0868 setupTitleWidget(i18n("<i>This task will be executed at the specified intervals.</i>")); 0869 0870 mOkButton->setEnabled(true); 0871 } 0872 0873 void TaskEditorDialog::slotAllMonths() 0874 { 0875 bool checked = false; 0876 if (mAllMonths->isSetAll()) { 0877 checked = true; 0878 } 0879 0880 for (int mo = CTMonth::MINIMUM; mo <= CTMonth::MAXIMUM; mo++) { 0881 mMonthButtons[mo]->setChecked(checked); 0882 } 0883 0884 slotMonthChanged(); 0885 } 0886 0887 void TaskEditorDialog::slotMonthChanged() 0888 { 0889 bool allCleared = true; 0890 for (int mo = CTMonth::MINIMUM; mo <= CTMonth::MAXIMUM; mo++) { 0891 if (mMonthButtons[mo]->isChecked()) { 0892 allCleared = false; 0893 break; 0894 } 0895 } 0896 0897 if (allCleared) { 0898 mAllMonths->setStatus(SetOrClearAllButton::SET_ALL); 0899 } else { 0900 mAllMonths->setStatus(SetOrClearAllButton::CLEAR_ALL); 0901 } 0902 } 0903 0904 void TaskEditorDialog::slotAllDaysOfMonth() 0905 { 0906 bool checked = false; 0907 if (mAllDaysOfMonth->isSetAll()) { 0908 checked = true; 0909 } 0910 0911 for (int dm = CTDayOfMonth::MINIMUM; dm <= CTDayOfMonth::MAXIMUM; dm++) { 0912 mDayOfMonthButtons[dm]->setChecked(checked); 0913 } 0914 0915 slotDayOfMonthChanged(); 0916 } 0917 0918 void TaskEditorDialog::slotDayOfMonthChanged() 0919 { 0920 bool allCleared = true; 0921 for (int dm = CTDayOfMonth::MINIMUM; dm <= CTDayOfMonth::MAXIMUM; dm++) { 0922 if (mDayOfMonthButtons[dm]->isChecked()) { 0923 allCleared = false; 0924 break; 0925 } 0926 } 0927 0928 if (allCleared) { 0929 mAllDaysOfMonth->setStatus(SetOrClearAllButton::SET_ALL); 0930 } else { 0931 mAllDaysOfMonth->setStatus(SetOrClearAllButton::CLEAR_ALL); 0932 } 0933 } 0934 0935 void TaskEditorDialog::slotAllDaysOfWeek() 0936 { 0937 if (mAllDaysOfWeek->isSetAll()) { 0938 for (int dw = 1; dw <= 7; dw++) { 0939 mDayOfWeekButtons[dw]->setChecked(true); 0940 } 0941 } else { 0942 for (int dw = 1; dw <= 7; dw++) { 0943 mDayOfWeekButtons[dw]->setChecked(false); 0944 } 0945 } 0946 slotDayOfWeekChanged(); 0947 } 0948 0949 void TaskEditorDialog::slotDayOfWeekChanged() 0950 { 0951 bool allCleared = true; 0952 for (int dw = 1; dw <= 7; dw++) { 0953 if (mDayOfWeekButtons[dw]->isChecked()) { 0954 allCleared = false; 0955 } 0956 } 0957 if (allCleared) { 0958 mAllDaysOfWeek->setStatus(SetOrClearAllButton::SET_ALL); 0959 } else { 0960 mAllDaysOfWeek->setStatus(SetOrClearAllButton::CLEAR_ALL); 0961 } 0962 } 0963 0964 void TaskEditorDialog::slotAllHours() 0965 { 0966 if (mAllHours->isSetAll()) { 0967 for (int ho = 0; ho <= 23; ho++) { 0968 mHourButtons[ho]->setChecked(true); 0969 } 0970 } else { 0971 for (int ho = 0; ho <= 23; ho++) { 0972 mHourButtons[ho]->setChecked(false); 0973 } 0974 } 0975 slotHourChanged(); 0976 } 0977 0978 void TaskEditorDialog::slotHourChanged() 0979 { 0980 bool allCleared = true; 0981 for (int ho = 0; ho <= 23; ho++) { 0982 if (mHourButtons[ho]->isChecked()) { 0983 allCleared = false; 0984 } 0985 } 0986 0987 if (allCleared) { 0988 mAllHours->setStatus(SetOrClearAllButton::SET_ALL); 0989 } else { 0990 mAllHours->setStatus(SetOrClearAllButton::CLEAR_ALL); 0991 } 0992 } 0993 0994 void TaskEditorDialog::slotMinutesPreselection(int index) 0995 { 0996 QVariant itemData = mMinutesPreselection->itemData(index); 0997 int step = itemData.toInt(); 0998 qCDebug(KCM_CRON_LOG) << "Selected step " << step; 0999 1000 if (step == -1) { 1001 // Unselect everything 1002 for (int mi = 0; mi <= minuteTotal; ++mi) { 1003 mMinuteButtons[mi]->setChecked(false); 1004 } 1005 1006 // Select Custom selection in the combo box 1007 for (int index = 0; index < mMinutesPreselection->count(); ++index) { 1008 if (mMinutesPreselection->itemData(index).toInt() == 0) { 1009 mMinutesPreselection->setCurrentIndex(index); 1010 break; 1011 } 1012 } 1013 } else if (step != 0) { 1014 for (int mi = 0; mi <= minuteTotal; ++mi) { 1015 if (mi % step == 0) { 1016 mMinuteButtons[mi]->setChecked(true); 1017 } else { 1018 mMinuteButtons[mi]->setChecked(false); 1019 } 1020 } 1021 } 1022 1023 if (step < reducedMinuteStep && index != 0) { 1024 increaseMinutesGroup(); 1025 } else { 1026 reduceMinutesGroup(); 1027 } 1028 } 1029 1030 void TaskEditorDialog::slotMinuteChanged() 1031 { 1032 CTMinute minutes; 1033 1034 for (int index = 0; index <= minuteTotal; ++index) { 1035 minutes.setEnabled(index, mMinuteButtons[index]->isChecked()); 1036 } 1037 1038 int period = minutes.findPeriod(); 1039 1040 for (int index = 0; index < mMinutesPreselection->count(); ++index) { 1041 if (mMinutesPreselection->itemData(index).toInt() == period) { 1042 mMinutesPreselection->setCurrentIndex(index); 1043 break; 1044 } 1045 } 1046 } 1047 1048 /** 1049 * SetOrClearAllButton class implementation 1050 */ 1051 1052 SetOrClearAllButton::SetOrClearAllButton(QWidget *parent, SetOrClearAllButton::Status status) 1053 : QPushButton(parent) 1054 { 1055 setStatus(status); 1056 } 1057 1058 void SetOrClearAllButton::setStatus(SetOrClearAllButton::Status status) 1059 { 1060 currentStatus = status; 1061 1062 if (currentStatus == SetOrClearAllButton::SET_ALL) { 1063 setText(i18n("Set All")); 1064 } else { 1065 setText(i18n("Clear All")); 1066 } 1067 } 1068 1069 bool SetOrClearAllButton::isSetAll() 1070 { 1071 return currentStatus == SetOrClearAllButton::SET_ALL; 1072 } 1073 1074 bool SetOrClearAllButton::isClearAll() 1075 { 1076 return currentStatus == SetOrClearAllButton::CLEAR_ALL; 1077 } 1078 1079 /** 1080 * KTPushButton class implementation 1081 */ 1082 1083 NumberPushButton::NumberPushButton(QWidget *parent) 1084 : QPushButton(parent) 1085 , mIsDirty(false) 1086 { 1087 updatePalette(); 1088 } 1089 1090 NumberPushButton::NumberPushButton(bool digitMode, QWidget *parent) 1091 : QPushButton(parent) 1092 , mIsDirty(false) 1093 { 1094 if (digitMode) { 1095 setFixedWidth(12 + fontMetrics().boundingRect(QStringLiteral("44")).width()); 1096 KAcceleratorManager::setNoAccel(this); 1097 } 1098 updatePalette(); 1099 } 1100 1101 void NumberPushButton::updatePalette() 1102 { 1103 mPalNormal = ((QWidget *)parent())->palette(); 1104 mPalSelected = mPalNormal; 1105 for (int cg = (int)QPalette::Active; cg < (int)QPalette::NColorGroups; cg++) { 1106 mPalSelected.setColor((QPalette::ColorGroup)cg, QPalette::Button, mPalSelected.color((QPalette::ColorGroup)cg, QPalette::Highlight)); 1107 mPalSelected.setColor((QPalette::ColorGroup)cg, QPalette::ButtonText, mPalSelected.color((QPalette::ColorGroup)cg, QPalette::HighlightedText)); 1108 } 1109 mIsDirty = true; 1110 } 1111 1112 bool NumberPushButton::event(QEvent *e) 1113 { 1114 if (e->type() == QEvent::PaletteChange) { 1115 updatePalette(); 1116 update(); 1117 } 1118 return QPushButton::event(e); 1119 } 1120 1121 void NumberPushButton::paintEvent(QPaintEvent *) 1122 { 1123 QStylePainter p(this); 1124 QStyleOptionButton option; 1125 initStyleOption(&option); 1126 1127 if (mIsDirty || isChecked()) { 1128 mIsDirty = false; 1129 if (isChecked()) { 1130 option.palette = mPalSelected; 1131 QFont f = p.font(); 1132 f.setBold(true); 1133 p.setFont(f); 1134 } 1135 } 1136 p.drawControl(QStyle::CE_PushButton, option); 1137 } 1138 1139 #include "moc_taskEditorDialog.cpp"