Warning, file /pim/kalarm/src/prefdlg.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 * prefdlg.cpp - program preferences dialog 0003 * Program: kalarm 0004 * SPDX-FileCopyrightText: 2001-2024 David Jarvie <djarvie@kde.org> 0005 * 0006 * SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 0009 #include "prefdlg.h" 0010 #include "prefdlg_p.h" 0011 0012 #include "alarmtimewidget.h" 0013 #include "editdlg.h" 0014 #include "editdlgtypes.h" 0015 #include "fontcolour.h" 0016 #include "kalarmapp.h" 0017 #include "kamail.h" 0018 #include "latecancel.h" 0019 #include "mainwindow.h" 0020 #include "pluginmanager.h" 0021 #include "preferences.h" 0022 #include "recurrenceedit.h" 0023 #include "resourcescalendar.h" 0024 #include "sounddlg.h" 0025 #include "soundpicker.h" 0026 #include "specialactions.h" 0027 #include "resources/resources.h" 0028 #include "lib/buttongroup.h" 0029 #include "lib/checkbox.h" 0030 #include "lib/colourbutton.h" 0031 #include "lib/config.h" 0032 #include "lib/desktop.h" 0033 #include "lib/label.h" 0034 #include "lib/locale.h" 0035 #include "lib/messagebox.h" 0036 #include "lib/radiobutton.h" 0037 #include "lib/slider.h" 0038 #include "lib/stackedwidgets.h" 0039 #include "lib/timeedit.h" 0040 #include "lib/timespinbox.h" 0041 #include "lib/timezonecombo.h" 0042 #include "kalarmcalendar/holidays.h" 0043 #include "kalarmcalendar/identities.h" 0044 #include "config-kalarm.h" 0045 #include "kalarm_debug.h" 0046 0047 #include <KHolidays/HolidayRegion> 0048 using namespace KHolidays; 0049 0050 #ifdef HAVE_TEXT_TO_SPEECH_SUPPORT 0051 #include <TextEditTextToSpeech/TextToSpeech> 0052 #endif 0053 0054 #include <KLocalizedString> 0055 #include <KShell> 0056 #include <KAboutData> 0057 #include <KStandardGuiItem> 0058 #include <QIcon> 0059 #if ENABLE_X11 0060 #include <KX11Extras> 0061 #include <KWindowInfo> 0062 #endif 0063 #include <KWindowSystem> 0064 #include <KHelpClient> 0065 0066 #include <QLabel> 0067 #include <QCheckBox> 0068 #include <QRadioButton> 0069 #include <QPushButton> 0070 #include <QTabWidget> 0071 #include <QSpinBox> 0072 #include <QGroupBox> 0073 #include <QGridLayout> 0074 #include <QHBoxLayout> 0075 #include <QVBoxLayout> 0076 #include <QStyle> 0077 #include <QResizeEvent> 0078 #include <QStandardPaths> 0079 #include <QComboBox> 0080 #include <QLocale> 0081 #include <QLineEdit> 0082 0083 using namespace KCalendarCore; 0084 using namespace KAlarmCal; 0085 0086 static const char PREF_DIALOG_NAME[] = "PrefDialog"; 0087 0088 0089 /*============================================================================= 0090 = Class KAlarmPrefDlg 0091 =============================================================================*/ 0092 0093 KAlarmPrefDlg* KAlarmPrefDlg::mInstance = nullptr; 0094 KAlarmPrefDlg::TabType KAlarmPrefDlg::mLastTab = AnyTab; 0095 0096 /****************************************************************************** 0097 * Display the Preferences dialog as a non-modal window. 0098 */ 0099 void KAlarmPrefDlg::display() 0100 { 0101 if (!mInstance) 0102 { 0103 mInstance = new KAlarmPrefDlg; 0104 QSize s; 0105 if (Config::readWindowSize(PREF_DIALOG_NAME, s)) 0106 mInstance->resize(s); 0107 mInstance->restoreTab(); 0108 mInstance->show(); 0109 } 0110 else 0111 { 0112 mInstance->restoreTab(); 0113 // Switch to the virtual desktop which the dialog is in 0114 #if ENABLE_X11 0115 KWindowInfo info = KWindowInfo(mInstance->winId(), NET::WMGeometry | NET::WMDesktop); 0116 KX11Extras::setCurrentDesktop(info.desktop()); 0117 #endif 0118 mInstance->setWindowState(mInstance->windowState() & ~Qt::WindowMinimized); // un-minimize it if necessary 0119 mInstance->raise(); 0120 mInstance->activateWindow(); 0121 } 0122 } 0123 0124 KAlarmPrefDlg::KAlarmPrefDlg() 0125 : KPageDialog() 0126 { 0127 setAttribute(Qt::WA_DeleteOnClose); 0128 setObjectName(QLatin1StringView("PrefDlg")); // used by LikeBack 0129 setWindowTitle(i18nc("@title:window", "Configure")); 0130 setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::Help | QDialogButtonBox::RestoreDefaults | QDialogButtonBox::Apply); 0131 button(QDialogButtonBox::Ok)->setDefault(true); 0132 button(QDialogButtonBox::RestoreDefaults)->setToolTip(KStandardGuiItem::defaults().toolTip()); 0133 button(QDialogButtonBox::Help)->setToolTip(KStandardGuiItem::help().toolTip()); 0134 button(QDialogButtonBox::Apply)->setToolTip(KStandardGuiItem::apply().toolTip()); 0135 setFaceType(List); 0136 mTabScrollGroup = new StackedScrollGroup(this, this); 0137 0138 mMiscPage = new MiscPrefTab(mTabScrollGroup); 0139 mMiscPageItem = new KPageWidgetItem(mMiscPage, i18nc("@title:tab General preferences", "General")); 0140 mMiscPageItem->setHeader(i18nc("@title General preferences", "General")); 0141 mMiscPageItem->setIcon(QIcon::fromTheme(QStringLiteral("preferences-other"))); 0142 addPage(mMiscPageItem); 0143 0144 mTimePage = new TimePrefTab(mTabScrollGroup); 0145 mTimePageItem = new KPageWidgetItem(mTimePage, i18nc("@title:tab", "Time & Date")); 0146 mTimePageItem->setHeader(i18nc("@title", "Time and Date")); 0147 mTimePageItem->setIcon(QIcon::fromTheme(QStringLiteral("preferences-system-time"))); 0148 addPage(mTimePageItem); 0149 0150 mStorePage = new StorePrefTab(mTabScrollGroup); 0151 mStorePageItem = new KPageWidgetItem(mStorePage, i18nc("@title:tab", "Storage")); 0152 mStorePageItem->setHeader(i18nc("@title", "Alarm Storage")); 0153 mStorePageItem->setIcon(QIcon::fromTheme(QStringLiteral("system-file-manager"))); 0154 addPage(mStorePageItem); 0155 0156 mEmailPage = new EmailPrefTab(mTabScrollGroup); 0157 mEmailPageItem = new KPageWidgetItem(mEmailPage, i18nc("@title:tab Email preferences", "Email")); 0158 mEmailPageItem->setHeader(i18nc("@title", "Email Alarm Settings")); 0159 mEmailPageItem->setIcon(QIcon::fromTheme(QStringLiteral("internet-mail"))); 0160 addPage(mEmailPageItem); 0161 0162 mEditPage = new EditPrefTab(mTabScrollGroup); 0163 mEditPageItem = new KPageWidgetItem(mEditPage, i18nc("@title:tab", "Alarm Defaults")); 0164 mEditPageItem->setHeader(i18nc("@title", "Default Alarm Edit Settings")); 0165 mEditPageItem->setIcon(QIcon::fromTheme(QStringLiteral("document-properties"))); 0166 addPage(mEditPageItem); 0167 0168 mViewPage = new ViewPrefTab(mTabScrollGroup); 0169 mViewPageItem = new KPageWidgetItem(mViewPage, i18nc("@title:tab", "View")); 0170 mViewPageItem->setHeader(i18nc("@title", "View Settings")); 0171 mViewPageItem->setIcon(QIcon::fromTheme(QStringLiteral("preferences-desktop-theme"))); 0172 addPage(mViewPageItem); 0173 0174 connect(button(QDialogButtonBox::Ok), &QAbstractButton::clicked, this, &KAlarmPrefDlg::slotOk); 0175 connect(button(QDialogButtonBox::Cancel), &QAbstractButton::clicked, this, &KAlarmPrefDlg::slotCancel); 0176 connect(button(QDialogButtonBox::Apply), &QAbstractButton::clicked, this, &KAlarmPrefDlg::slotApply); 0177 connect(button(QDialogButtonBox::RestoreDefaults), &QAbstractButton::clicked, this, &KAlarmPrefDlg::slotDefault); 0178 connect(button(QDialogButtonBox::Help), &QAbstractButton::clicked, this, &KAlarmPrefDlg::slotHelp); 0179 connect(this, &KPageDialog::currentPageChanged, this, &KAlarmPrefDlg::slotTabChanged); 0180 0181 restore(false); 0182 adjustSize(); 0183 } 0184 0185 KAlarmPrefDlg::~KAlarmPrefDlg() 0186 { 0187 mInstance = nullptr; 0188 } 0189 0190 void KAlarmPrefDlg::slotHelp() 0191 { 0192 KHelpClient::invokeHelp(QStringLiteral("preferences")); 0193 } 0194 0195 // Apply the preferences that are currently selected 0196 void KAlarmPrefDlg::slotApply() 0197 { 0198 qCDebug(KALARM_LOG) << "KAlarmPrefDlg::slotApply"; 0199 mValid = true; 0200 apply(); 0201 } 0202 0203 // Apply the preferences that are currently selected 0204 void KAlarmPrefDlg::apply() 0205 { 0206 QString errmsg = mEmailPage->validate(); 0207 if (!errmsg.isEmpty()) 0208 { 0209 setCurrentPage(mEmailPageItem); 0210 if (KAMessageBox::warningYesNo(this, errmsg) != KMessageBox::ButtonCode::PrimaryAction) 0211 { 0212 mValid = false; 0213 return; 0214 } 0215 } 0216 errmsg = mEditPage->validate(); 0217 if (!errmsg.isEmpty()) 0218 { 0219 setCurrentPage(mEditPageItem); 0220 KAMessageBox::error(this, errmsg); 0221 mValid = false; 0222 return; 0223 } 0224 mValid = mEmailPage->apply(false) && mValid; 0225 mValid = mViewPage->apply(false) && mValid; 0226 mValid = mEditPage->apply(false) && mValid; 0227 mValid = mStorePage->apply(false) && mValid; 0228 mValid = mTimePage->apply(false) && mValid; 0229 mValid = mMiscPage->apply(false) && mValid; 0230 Preferences::self()->save(); 0231 } 0232 0233 // Apply the preferences that are currently selected 0234 void KAlarmPrefDlg::slotOk() 0235 { 0236 qCDebug(KALARM_LOG) << "KAlarmPrefDlg::slotOk"; 0237 mValid = true; 0238 apply(); 0239 if (mValid) 0240 QDialog::accept(); 0241 } 0242 0243 void KAlarmPrefDlg::accept() 0244 { 0245 // accept() is called automatically by KPageDialog when OK button is clicked. 0246 // Don't accept and close the dialog until slotOk() has finished processing. 0247 } 0248 0249 // Discard the current preferences and close the dialog 0250 void KAlarmPrefDlg::slotCancel() 0251 { 0252 qCDebug(KALARM_LOG) << "KAlarmPrefDlg::slotCancel"; 0253 restore(false); 0254 KPageDialog::reject(); 0255 } 0256 0257 // Reset all controls to the application defaults 0258 void KAlarmPrefDlg::slotDefault() 0259 { 0260 switch (KAMessageBox::questionYesNoCancel(this, 0261 i18nc("@info", "Reset all tabs to their default values, or only reset the current tab?"), 0262 QString(), 0263 KGuiItem(i18nc("@action:button Reset ALL tabs", "All")), 0264 KGuiItem(i18nc("@action:button Reset the CURRENT tab", "Current")))) 0265 { 0266 case KMessageBox::ButtonCode::PrimaryAction: 0267 restore(true); // restore all tabs 0268 break; 0269 case KMessageBox::ButtonCode::SecondaryAction: 0270 Preferences::self()->useDefaults(true); 0271 static_cast<PrefsTabBase*>(currentPage()->widget())->restore(true, false); 0272 Preferences::self()->useDefaults(false); 0273 break; 0274 default: 0275 break; 0276 } 0277 } 0278 0279 // Discard the current preferences and use the present ones 0280 void KAlarmPrefDlg::restore(bool defaults) 0281 { 0282 qCDebug(KALARM_LOG) << "KAlarmPrefDlg::restore:" << (defaults ? "defaults" : ""); 0283 if (defaults) 0284 Preferences::self()->useDefaults(true); 0285 mEmailPage->restore(defaults, true); 0286 mViewPage->restore(defaults, true); 0287 mEditPage->restore(defaults, true); 0288 mStorePage->restore(defaults, true); 0289 mTimePage->restore(defaults, true); 0290 mMiscPage->restore(defaults, true); 0291 if (defaults) 0292 Preferences::self()->useDefaults(false); 0293 } 0294 0295 /****************************************************************************** 0296 * Return the minimum size for the dialog. 0297 * If the minimum size would be too high to fit the desktop, the tab contents 0298 * are made scrollable. 0299 */ 0300 QSize KAlarmPrefDlg::minimumSizeHint() const 0301 { 0302 if (!mTabScrollGroup->sized()) 0303 { 0304 QSize s = mTabScrollGroup->adjustSize(); 0305 if (s.isValid()) 0306 { 0307 if (mTabScrollGroup->heightReduction()) 0308 { 0309 s = QSize(s.width(), s.height() - mTabScrollGroup->heightReduction()); 0310 const_cast<KAlarmPrefDlg*>(this)->resize(s); 0311 } 0312 return s; 0313 } 0314 } 0315 return KPageDialog::minimumSizeHint(); 0316 } 0317 0318 void KAlarmPrefDlg::showEvent(QShowEvent* e) 0319 { 0320 KPageDialog::showEvent(e); 0321 if (!mShown) 0322 { 0323 mTabScrollGroup->adjustSize(true); 0324 mShown = true; 0325 } 0326 } 0327 0328 /****************************************************************************** 0329 * Called when the dialog's size has changed. 0330 * Records the new size in the config file. 0331 */ 0332 void KAlarmPrefDlg::resizeEvent(QResizeEvent* re) 0333 { 0334 if (isVisible()) 0335 Config::writeWindowSize(PREF_DIALOG_NAME, re->size()); 0336 KPageDialog::resizeEvent(re); 0337 } 0338 0339 /****************************************************************************** 0340 * Called when a new tab is selected, to note which one it is. 0341 */ 0342 void KAlarmPrefDlg::slotTabChanged(KPageWidgetItem* item) 0343 { 0344 mLastTab = (item == mMiscPageItem) ? Misc 0345 : (item == mTimePageItem) ? Time 0346 : (item == mStorePageItem) ? Store 0347 : (item == mEditPageItem) ? Edit 0348 : (item == mEmailPageItem) ? Email 0349 : (item == mViewPageItem) ? View : AnyTab; 0350 } 0351 0352 /****************************************************************************** 0353 * Selects the tab noted in mLastTab. 0354 */ 0355 void KAlarmPrefDlg::restoreTab() 0356 { 0357 KPageWidgetItem* item = nullptr; 0358 switch (mLastTab) 0359 { 0360 case Misc: item = mMiscPageItem; break; 0361 case Time: item = mTimePageItem; break; 0362 case Store: item = mStorePageItem; break; 0363 case Edit: item = mEditPageItem; break; 0364 case Email: item = mEmailPageItem; break; 0365 case View: item = mViewPageItem; break; 0366 default: 0367 return; 0368 } 0369 setCurrentPage(item); 0370 } 0371 0372 0373 /*============================================================================= 0374 = Class PrefsTabBase 0375 =============================================================================*/ 0376 int PrefsTabBase::mIndentWidth = 0; 0377 int PrefsTabBase::mGridIndentWidth = 0; 0378 0379 PrefsTabBase::PrefsTabBase(StackedScrollGroup* scrollGroup) 0380 : StackedScrollWidget(scrollGroup) 0381 { 0382 QFrame* topWidget = new QFrame(this); 0383 setWidget(topWidget); 0384 mTopLayout = new QVBoxLayout(topWidget); 0385 mTopLayout->setContentsMargins( 0386 style()->pixelMetric(QStyle::PM_LayoutLeftMargin), 0387 style()->pixelMetric(QStyle::PM_LayoutTopMargin), 0388 style()->pixelMetric(QStyle::PM_LayoutRightMargin), 0389 style()->pixelMetric(QStyle::PM_LayoutBottomMargin)); 0390 0391 if (!mIndentWidth) 0392 { 0393 QCheckBox cb(this); 0394 mIndentWidth = CheckBox::textIndent(&cb); 0395 mGridIndentWidth = mIndentWidth - style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing); 0396 } 0397 } 0398 0399 bool PrefsTabBase::apply(bool syncToDisc) 0400 { 0401 if (syncToDisc) 0402 Preferences::self()->save(); 0403 return true; 0404 } 0405 0406 void PrefsTabBase::addAlignedLabel(QLabel* label) 0407 { 0408 mLabels += label; 0409 } 0410 0411 void PrefsTabBase::showEvent(QShowEvent*) 0412 { 0413 if (!mLabelsAligned) 0414 { 0415 int wid = 0; 0416 int i; 0417 const int labelCount = mLabels.count(); 0418 QList<int> xpos; 0419 xpos.reserve(labelCount); 0420 for (const QLabel* label : std::as_const(mLabels)) 0421 { 0422 const int x = label->mapTo(this, QPoint(0, 0)).x(); 0423 xpos += x; 0424 const int w = x + label->sizeHint().width(); 0425 if (w > wid) 0426 wid = w; 0427 } 0428 for (i = 0; i < labelCount; ++i) 0429 { 0430 mLabels[i]->setFixedWidth(wid - xpos[i]); 0431 mLabels[i]->setAlignment(Qt::AlignRight | Qt::AlignVCenter); 0432 } 0433 mLabelsAligned = true; 0434 } 0435 } 0436 0437 0438 /*============================================================================= 0439 = Class MiscPrefTab 0440 =============================================================================*/ 0441 0442 MiscPrefTab::MiscPrefTab(StackedScrollGroup* scrollGroup) 0443 : PrefsTabBase(scrollGroup) 0444 { 0445 QGroupBox* group = new QGroupBox(i18nc("@title:group", "Run Mode")); 0446 topLayout()->addWidget(group); 0447 auto vlayout = new QVBoxLayout(group); 0448 0449 // Start at login 0450 mAutoStart = new QCheckBox(i18nc("@option:check", "Start at login"), group); 0451 connect(mAutoStart, &QAbstractButton::clicked, this, &MiscPrefTab::slotAutostartClicked); 0452 mAutoStart->setWhatsThis(xi18nc("@info:whatsthis", 0453 "<para>Automatically start <application>KAlarm</application> whenever you start KDE.</para>" 0454 "<para>This option should always be checked unless you intend to discontinue use of <application>KAlarm</application>.</para>")); 0455 vlayout->addWidget(mAutoStart, 0, Qt::AlignLeft); 0456 0457 mQuitWarn = new QCheckBox(i18nc("@option:check", "Warn before quitting"), group); 0458 mQuitWarn->setWhatsThis(xi18nc("@info:whatsthis", "Check to display a warning prompt before quitting <application>KAlarm</application>.")); 0459 vlayout->addWidget(mQuitWarn, 0, Qt::AlignLeft); 0460 0461 // Enable alarm names? 0462 QWidget* widget = new QWidget; // this is for consistent left alignment 0463 topLayout()->addWidget(widget); 0464 auto hbox = new QHBoxLayout(widget); 0465 mUseAlarmNames = new QCheckBox(i18nc("@option:check", "Enable alarm names")); 0466 mUseAlarmNames->setMinimumSize(mUseAlarmNames->sizeHint()); 0467 mUseAlarmNames->setWhatsThis(i18nc("@info:whatsthis", "Check to have the option to give alarms a name. This is a convenience to help you to identify alarms.")); 0468 hbox->addWidget(mUseAlarmNames); 0469 hbox->addStretch(); // left adjust the controls 0470 0471 // Confirm alarm deletion? 0472 widget = new QWidget; // this is for consistent left alignment 0473 topLayout()->addWidget(widget); 0474 hbox = new QHBoxLayout(widget); 0475 mConfirmAlarmDeletion = new QCheckBox(i18nc("@option:check", "Confirm alarm deletions")); 0476 mConfirmAlarmDeletion->setMinimumSize(mConfirmAlarmDeletion->sizeHint()); 0477 mConfirmAlarmDeletion->setWhatsThis(i18nc("@info:whatsthis", "Check to be prompted for confirmation each time you delete an alarm.")); 0478 hbox->addWidget(mConfirmAlarmDeletion); 0479 hbox->addStretch(); // left adjust the controls 0480 0481 // Default alarm deferral time 0482 widget = new QWidget; // this is to control the QWhatsThis text display area 0483 topLayout()->addWidget(widget); 0484 hbox = new QHBoxLayout(widget); 0485 QLabel* label = new QLabel(i18nc("@label:spinbox", "Default defer time interval:")); 0486 hbox->addWidget(label); 0487 mDefaultDeferTime = new TimeSpinBox(1, 5999); 0488 mDefaultDeferTime->setMinimumSize(mDefaultDeferTime->sizeHint()); 0489 hbox->addWidget(mDefaultDeferTime); 0490 widget->setWhatsThis(i18nc("@info:whatsthis", 0491 "Enter the default time interval (hours & minutes) to defer alarms, used by the Defer Alarm dialog.")); 0492 label->setBuddy(mDefaultDeferTime); 0493 hbox->addStretch(); // left adjust the controls 0494 0495 // Terminal window to use for command alarms 0496 group = new QGroupBox(i18nc("@title:group", "Terminal for Command Alarms")); 0497 group->setWhatsThis(i18nc("@info:whatsthis", "Choose which application to use when a command alarm is executed in a terminal window")); 0498 topLayout()->addWidget(group); 0499 auto grid = new QGridLayout(group); 0500 int row = 0; 0501 0502 mXtermType = new ButtonGroup(group); 0503 int index = 0; 0504 const auto xtermCommands = Preferences::cmdXTermStandardCommands(); 0505 for (auto it = xtermCommands.constBegin(); it != xtermCommands.constEnd(); ++it, ++index) 0506 { 0507 QString cmd = it.value(); 0508 const QStringList args = KShell::splitArgs(cmd); 0509 auto radio = new QRadioButton(args[0], group); 0510 radio->setMinimumSize(radio->sizeHint()); 0511 mXtermType->addButton(radio, it.key()); 0512 cmd.replace(QStringLiteral("%t"), KAboutData::applicationData().displayName()); 0513 cmd.replace(QStringLiteral("%c"), QStringLiteral("<command>")); 0514 cmd.replace(QStringLiteral("%w"), QStringLiteral("<command; sleep>")); 0515 cmd.replace(QStringLiteral("%C"), QStringLiteral("[command]")); 0516 cmd.replace(QStringLiteral("%W"), QStringLiteral("[command; sleep]")); 0517 radio->setWhatsThis( 0518 xi18nc("@info:whatsthis", "Check to execute command alarms in a terminal window by <icode>%1</icode>", cmd)); 0519 grid->addWidget(radio, (row = index/3), index % 3, Qt::AlignLeft); 0520 } 0521 0522 // QHBox used here doesn't allow the QLineEdit to expand!? 0523 auto hlayout = new QHBoxLayout(); 0524 grid->addLayout(hlayout, row + 1, 0, 1, 3, Qt::AlignLeft); 0525 QRadioButton* radio = new QRadioButton(i18nc("@option:radio Other terminal window command", "Other:"), group); 0526 hlayout->addWidget(radio); 0527 connect(radio, &QAbstractButton::toggled, this, &MiscPrefTab::slotOtherTerminalToggled); 0528 mXtermType->addButton(radio, 0); 0529 0530 mXtermCommand = new QLineEdit(group); 0531 mXtermCommand->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum); 0532 hlayout->addWidget(mXtermCommand); 0533 const QString wt = 0534 xi18nc("@info:whatsthis", "Enter the full command line needed to execute a command in your chosen terminal window. " 0535 "By default the alarm's command string will be appended to what you enter here. " 0536 "See the <application>KAlarm</application> Handbook for details of special codes to tailor the command line."); 0537 radio->setWhatsThis(wt); 0538 mXtermCommand->setWhatsThis(wt); 0539 0540 if (PluginManager::instance()->akonadiPlugin()) 0541 { 0542 // Plugins 0543 group = new QGroupBox(i18nc("@title:group", "Plugins")); 0544 topLayout()->addWidget(group); 0545 vlayout = new QVBoxLayout(group); 0546 0547 // Akonadi plugin 0548 mUseAkonadi = new QCheckBox(i18nc("@option:check", "Enable Akonadi"), group); 0549 mUseAkonadi->setToolTip(i18nc("@info:tooltip", 0550 "Enable the use of Akonadi to provide features including birthday import, some email functions, and email address book lookup.")); 0551 mUseAkonadi->setWhatsThis(i18nc("@info:whatsthis", 0552 "Enable the use of Akonadi to provide features including birthday import, some email functions, and email address book lookup.")); 0553 vlayout->addWidget(mUseAkonadi, 0, Qt::AlignLeft); 0554 } 0555 0556 topLayout()->addStretch(); // top adjust the widgets 0557 } 0558 0559 void MiscPrefTab::restore(bool defaults, bool) 0560 { 0561 mAutoStart->setChecked(defaults ? true : Preferences::autoStart()); 0562 mQuitWarn->setChecked(Preferences::quitWarn()); 0563 mUseAlarmNames->setChecked(Preferences::useAlarmName()); 0564 mConfirmAlarmDeletion->setChecked(Preferences::confirmAlarmDeletion()); 0565 mDefaultDeferTime->setValue(Preferences::defaultDeferTime()); 0566 const auto xtermCmd = Preferences::cmdXTermCommandIndex(); 0567 int id = xtermCmd.first; 0568 if (id > 0 && !mXtermType->find(id)) 0569 { 0570 // The command is a standard command, but there is no button for it 0571 // (because the executable doesn't exist on this system). So set it 0572 // into the 'Other' option. 0573 id = 0; 0574 } 0575 mXtermType->setButton(id); 0576 mXtermCommand->setEnabled(id == 0); 0577 mXtermCommand->setText(id == 0 ? xtermCmd.second : QString()); 0578 if (mUseAkonadi) 0579 mUseAkonadi->setChecked(Preferences::useAkonadi()); 0580 } 0581 0582 bool MiscPrefTab::apply(bool syncToDisc) 0583 { 0584 // First validate anything entered in Other X-terminal command 0585 int xtermID = mXtermType->selectedId(); 0586 if (!xtermID) 0587 { 0588 // 'Other' is selected. 0589 QString cmd = mXtermCommand->text(); 0590 if (cmd.isEmpty()) 0591 { 0592 mXtermCommand->setFocus(); 0593 const QList<QAbstractButton*> buttons = mXtermType->buttons(); 0594 if (buttons.count() == 2) 0595 { 0596 // There are only radio buttons for one standard command, plus 'Other' 0597 const int id = mXtermType->id(buttons[0]); 0598 cmd = Preferences::cmdXTermStandardCommand(id); 0599 const QStringList args = KShell::splitArgs(cmd); 0600 if (KAMessageBox::warningContinueCancel(topLayout()->parentWidget(), xi18nc("@info", "<para>No command is specified to invoke a terminal window.</para><para>The default command (<command>%1</command>) will be used.</para>", args[0])) 0601 != KMessageBox::Continue) 0602 return false; 0603 xtermID = id; 0604 mXtermType->setButton(id); 0605 } 0606 else 0607 { 0608 if (KAMessageBox::warningContinueCancel(topLayout()->parentWidget(), xi18nc("@info", "No command is specified to invoke a terminal window")) 0609 != KMessageBox::Continue) 0610 return false; 0611 xtermID = -1; 0612 } 0613 } 0614 else 0615 { 0616 const QStringList args = KShell::splitArgs(cmd); 0617 cmd = args.isEmpty() ? QString() : args[0]; 0618 if (QStandardPaths::findExecutable(cmd).isEmpty()) 0619 { 0620 mXtermCommand->setFocus(); 0621 if (KAMessageBox::warningContinueCancel(topLayout()->parentWidget(), xi18nc("@info", "Command to invoke terminal window not found: <command>%1</command>", cmd)) 0622 != KMessageBox::Continue) 0623 return false; 0624 } 0625 } 0626 } 0627 0628 if (mQuitWarn->isEnabled()) 0629 { 0630 const bool b = mQuitWarn->isChecked(); 0631 if (b != Preferences::quitWarn()) 0632 Preferences::setQuitWarn(b); 0633 } 0634 bool b = mAutoStart->isChecked(); 0635 if (b != Preferences::autoStart()) 0636 { 0637 Preferences::setAutoStart(b); 0638 Preferences::setAskAutoStart(true); // cancel any start-at-login prompt suppression 0639 if (b) 0640 Preferences::setNoAutoStart(false); 0641 Preferences::setAutoStartChangedByUser(true); // prevent prompting the user on quit, about start-at-login 0642 } 0643 b = mUseAlarmNames->isChecked(); 0644 if (b != Preferences::useAlarmName()) 0645 Preferences::setUseAlarmName(b); 0646 b = mConfirmAlarmDeletion->isChecked(); 0647 if (b != Preferences::confirmAlarmDeletion()) 0648 Preferences::setConfirmAlarmDeletion(b); 0649 int i = mDefaultDeferTime->value(); 0650 if (i != Preferences::defaultDeferTime()) 0651 Preferences::setDefaultDeferTime(i); 0652 const auto xtermCmd = Preferences::cmdXTermCommandIndex(); 0653 if (xtermID != xtermCmd.first || (!xtermID && mXtermCommand->text() != xtermCmd.second)) 0654 { 0655 if (xtermID > 0) 0656 Preferences::setCmdXTermCommand(xtermID); 0657 else 0658 Preferences::setCmdXTermSpecialCommand(mXtermCommand->text()); 0659 } 0660 if (mUseAkonadi) 0661 { 0662 b = mUseAkonadi->isChecked(); 0663 if (b != Preferences::useAkonadi()) 0664 Preferences::setUseAkonadi(b); 0665 } 0666 return PrefsTabBase::apply(syncToDisc); 0667 } 0668 0669 void MiscPrefTab::slotAutostartClicked() 0670 { 0671 if (!mAutoStart->isChecked() 0672 && KAMessageBox::warningYesNo(topLayout()->parentWidget(), 0673 xi18nc("@info", "You should not uncheck this option unless you intend to discontinue use of <application>KAlarm</application>"), 0674 QString(), KStandardGuiItem::cont(), KStandardGuiItem::cancel() 0675 ) != KMessageBox::ButtonCode::PrimaryAction) 0676 mAutoStart->setChecked(true); 0677 } 0678 0679 void MiscPrefTab::slotOtherTerminalToggled(bool on) 0680 { 0681 mXtermCommand->setEnabled(on); 0682 } 0683 0684 0685 /*============================================================================= 0686 = Class TimePrefTab 0687 =============================================================================*/ 0688 0689 TimePrefTab::TimePrefTab(StackedScrollGroup* scrollGroup) 0690 : PrefsTabBase(scrollGroup) 0691 { 0692 const int marLeft = style()->pixelMetric(QStyle::PM_LayoutLeftMargin); 0693 const int marRight = style()->pixelMetric(QStyle::PM_LayoutRightMargin); 0694 const int marTop = style()->pixelMetric(QStyle::PM_LayoutTopMargin); 0695 0696 // Default time zone 0697 auto itemBox = new QHBoxLayout(); 0698 itemBox->setContentsMargins(marLeft, marTop, marRight, 0); 0699 topLayout()->addLayout(itemBox); 0700 0701 QWidget* widget = new QWidget; // this is to control the QWhatsThis text display area 0702 itemBox->addWidget(widget); 0703 auto box = new QHBoxLayout(widget); 0704 box->setContentsMargins(0, 0, 0, 0); 0705 QLabel* label = new QLabel(i18nc("@label:listbox", "Time zone:")); 0706 box->addWidget(label); 0707 addAlignedLabel(label); 0708 mTimeZone = new TimeZoneCombo(widget); 0709 mTimeZone->setMaxVisibleItems(15); 0710 box->addWidget(mTimeZone); 0711 widget->setWhatsThis(xi18nc("@info:whatsthis", 0712 "Select the time zone which <application>KAlarm</application> should use " 0713 "as its default for displaying and entering dates and times.")); 0714 label->setBuddy(mTimeZone); 0715 itemBox->addStretch(); 0716 0717 // Holiday region 0718 itemBox = new QHBoxLayout(); 0719 itemBox->setContentsMargins(marLeft, 0, marRight, 0); 0720 topLayout()->addLayout(itemBox); 0721 0722 widget = new QWidget; // this is to control the QWhatsThis text display area 0723 itemBox->addWidget(widget); 0724 box = new QHBoxLayout(widget); 0725 box->setContentsMargins(0, 0, 0, 0); 0726 label = new QLabel(i18nc("@label:listbox", "Holiday region:")); 0727 addAlignedLabel(label); 0728 box->addWidget(label); 0729 mHolidays = new QComboBox(); 0730 mHolidays->setSizeAdjustPolicy(QComboBox::AdjustToContentsOnFirstShow); 0731 box->addWidget(mHolidays); 0732 itemBox->addStretch(); 0733 label->setBuddy(mHolidays); 0734 widget->setWhatsThis(i18nc("@info:whatsthis", 0735 "Select which holiday region to use")); 0736 0737 const QStringList regions = HolidayRegion::regionCodes(); 0738 QMap<QString, QString> regionsMap; 0739 for (const QString& regionCode : regions) 0740 { 0741 const QString name = HolidayRegion::name(regionCode); 0742 const QString languageName = QLocale::languageToString(QLocale(HolidayRegion::languageCode(regionCode)).language()); 0743 const QString labelText = languageName.isEmpty() ? name : i18nc("Holiday region, region language", "%1 (%2)", name, languageName); 0744 regionsMap.insert(labelText, regionCode); 0745 } 0746 0747 mHolidays->addItem(i18nc("No holiday region", "None"), QString()); 0748 for (QMapIterator<QString, QString> it(regionsMap); it.hasNext(); ) 0749 { 0750 it.next(); 0751 mHolidays->addItem(it.key(), it.value()); 0752 } 0753 0754 if (KernelWakeAlarm::isAvailable()) 0755 { 0756 // Wake from suspend in advance of alarm time 0757 itemBox = new QHBoxLayout(); 0758 itemBox->setContentsMargins(marLeft, 0, marRight, 0); 0759 topLayout()->addLayout(itemBox); 0760 0761 widget = new QWidget; // this is to control the QWhatsThis text display area 0762 itemBox->addWidget(widget); 0763 box = new QHBoxLayout(widget); 0764 box->setContentsMargins(0, 0, 0, 0); 0765 label = new QLabel(i18nc("@label:spinbox How long before alarm to wake system from suspend", "Wake from suspend before alarm:")); 0766 addAlignedLabel(label); 0767 box->addWidget(label); 0768 mPreWakeSuspend = new SpinBox; 0769 mPreWakeSuspend->setMaximum(10); // 10 minutes maximum 0770 box->addWidget(mPreWakeSuspend); 0771 label->setBuddy(mPreWakeSuspend); 0772 widget->setWhatsThis(i18nc("@info:whatsthis", 0773 "Enter how many minutes before the alarm trigger time to wake the system, for alarms set to wake from suspend. This can be used to ensure that the system is fully restored by the time the alarm triggers.")); 0774 label = new QLabel(i18nc("@label Time unit for user entered number", "minutes")); 0775 box->addWidget(label); 0776 itemBox->addStretch(); 0777 } 0778 0779 // Start-of-day time 0780 itemBox = new QHBoxLayout(); 0781 itemBox->setContentsMargins(marLeft, 0, marRight, 0); 0782 topLayout()->addLayout(itemBox); 0783 0784 widget = new QWidget; // this is to control the QWhatsThis text display area 0785 itemBox->addWidget(widget); 0786 box = new QHBoxLayout(widget); 0787 box->setContentsMargins(0, 0, 0, 0); 0788 label = new QLabel(i18nc("@label:spinbox", "Start of day for date-only alarms:")); 0789 addAlignedLabel(label); 0790 box->addWidget(label); 0791 mStartOfDay = new TimeEdit(); 0792 box->addWidget(mStartOfDay); 0793 label->setBuddy(mStartOfDay); 0794 widget->setWhatsThis(xi18nc("@info:whatsthis", 0795 "<para>The earliest time of day at which a date-only alarm will be triggered.</para>" 0796 "<para>%1</para>", TimeSpinBox::shiftWhatsThis())); 0797 itemBox->addStretch(); 0798 0799 // Working hours 0800 QGroupBox* group = new QGroupBox(i18nc("@title:group", "Working Hours")); 0801 topLayout()->addWidget(group); 0802 QBoxLayout* layout = new QVBoxLayout(group); 0803 0804 QWidget* daybox = new QWidget(group); // this is to control the QWhatsThis text display area 0805 layout->addWidget(daybox); 0806 auto wgrid = new QGridLayout(daybox); 0807 wgrid->setContentsMargins(0, 0, 0, 0); 0808 const QLocale locale; 0809 for (int i = 0; i < 7; ++i) 0810 { 0811 int day = Locale::localeDayInWeek_to_weekDay(i); 0812 mWorkDays[i] = new QCheckBox(locale.dayName(day), daybox); 0813 wgrid->addWidget(mWorkDays[i], i/3, i%3, Qt::AlignLeft); 0814 } 0815 daybox->setWhatsThis(i18nc("@info:whatsthis", "Check the days in the week which are work days")); 0816 0817 itemBox = new QHBoxLayout(); 0818 itemBox->setContentsMargins(0, 0, 0, 0); 0819 layout->addLayout(itemBox); 0820 0821 widget = new QWidget; // this is to control the QWhatsThis text display area 0822 itemBox->addWidget(widget); 0823 box = new QHBoxLayout(widget); 0824 box->setContentsMargins(0, 0, 0, 0); 0825 label = new QLabel(i18nc("@label:spinbox", "Daily start time:")); 0826 addAlignedLabel(label); 0827 box->addWidget(label); 0828 mWorkStart = new TimeEdit(); 0829 box->addWidget(mWorkStart); 0830 label->setBuddy(mWorkStart); 0831 widget->setWhatsThis(xi18nc("@info:whatsthis", 0832 "<para>Enter the start time of the working day.</para>" 0833 "<para>%1</para>", TimeSpinBox::shiftWhatsThis())); 0834 itemBox->addStretch(); 0835 0836 itemBox = new QHBoxLayout(); 0837 itemBox->setContentsMargins(0, 0, 0, 0); 0838 layout->addLayout(itemBox); 0839 0840 widget = new QWidget; // this is to control the QWhatsThis text display area 0841 itemBox->addWidget(widget); 0842 box = new QHBoxLayout(widget); 0843 box->setContentsMargins(0, 0, 0, 0); 0844 label = new QLabel(i18nc("@label:spinbox", "Daily end time:")); 0845 addAlignedLabel(label); 0846 box->addWidget(label); 0847 mWorkEnd = new TimeEdit(); 0848 box->addWidget(mWorkEnd); 0849 label->setBuddy(mWorkEnd); 0850 widget->setWhatsThis(xi18nc("@info:whatsthis", 0851 "<para>Enter the end time of the working day.</para>" 0852 "<para>%1</para>", TimeSpinBox::shiftWhatsThis())); 0853 itemBox->addStretch(); 0854 0855 // KOrganizer event duration 0856 group = new QGroupBox(i18nc("@title:group", "KOrganizer")); 0857 topLayout()->addWidget(group); 0858 layout = new QVBoxLayout(group); 0859 0860 widget = new QWidget; // this is to control the QWhatsThis text display area 0861 layout->addWidget(widget); 0862 box = new QHBoxLayout(widget); 0863 box->setContentsMargins(0, 0, 0, 0); 0864 label = new QLabel(i18nc("@label:spinbox", "KOrganizer event duration:")); 0865 addAlignedLabel(label); 0866 box->addWidget(label); 0867 mKOrgEventDuration = new TimeSpinBox(0, 5999); 0868 mKOrgEventDuration->setMinimumSize(mKOrgEventDuration->sizeHint()); 0869 box->addWidget(mKOrgEventDuration); 0870 widget->setWhatsThis(xi18nc("@info:whatsthis", 0871 "<para>Enter the event duration in hours and minutes, for alarms which are copied to KOrganizer.</para>" 0872 "<para>%1</para>", TimeSpinBox::shiftWhatsThis())); 0873 label->setBuddy(mKOrgEventDuration); 0874 box->addStretch(); // left adjust the controls 0875 0876 topLayout()->addStretch(); // top adjust the widgets 0877 } 0878 0879 void TimePrefTab::restore(bool, bool) 0880 { 0881 KADateTime::Spec timeSpec = Preferences::timeSpec(); 0882 mTimeZone->setTimeZone(timeSpec.type() == KADateTime::TimeZone ? timeSpec.timeZone() : QTimeZone()); 0883 const int ix = Preferences::holidays().isValid() ? mHolidays->findData(Preferences::holidays().regionCode()) : 0; 0884 mHolidays->setCurrentIndex(ix); 0885 if (mPreWakeSuspend) 0886 mPreWakeSuspend->setValue(Preferences::wakeFromSuspendAdvance()); 0887 mStartOfDay->setValue(Preferences::startOfDay()); 0888 mWorkStart->setValue(Preferences::workDayStart()); 0889 mWorkEnd->setValue(Preferences::workDayEnd()); 0890 QBitArray days = Preferences::workDays(); 0891 for (int i = 0; i < 7; ++i) 0892 { 0893 const bool x = days.testBit(Locale::localeDayInWeek_to_weekDay(i) - 1); 0894 mWorkDays[i]->setChecked(x); 0895 } 0896 mKOrgEventDuration->setValue(Preferences::kOrgEventDuration()); 0897 } 0898 0899 bool TimePrefTab::apply(bool syncToDisc) 0900 { 0901 Preferences::setTimeSpec(mTimeZone->timeZone()); 0902 const QString hol = mHolidays->itemData(mHolidays->currentIndex()).toString(); 0903 if (hol != Preferences::holidays().regionCode()) 0904 Preferences::setHolidayRegion(hol); 0905 if (mPreWakeSuspend) 0906 { 0907 unsigned t = static_cast<unsigned>(mPreWakeSuspend->value()); 0908 if (t != Preferences::wakeFromSuspendAdvance()) 0909 Preferences::setWakeFromSuspendAdvance(t); 0910 } 0911 int t = mStartOfDay->value(); 0912 const QTime sodt(t/60, t%60, 0); 0913 if (sodt != Preferences::startOfDay()) 0914 Preferences::setStartOfDay(sodt); 0915 t = mWorkStart->value(); 0916 Preferences::setWorkDayStart(QTime(t/60, t%60, 0)); 0917 t = mWorkEnd->value(); 0918 Preferences::setWorkDayEnd(QTime(t/60, t%60, 0)); 0919 QBitArray workDays(7); 0920 for (int i = 0; i < 7; ++i) 0921 if (mWorkDays[i]->isChecked()) 0922 workDays.setBit(Locale::localeDayInWeek_to_weekDay(i) - 1, true); 0923 Preferences::setWorkDays(workDays); 0924 Preferences::setKOrgEventDuration(mKOrgEventDuration->value()); 0925 t = mKOrgEventDuration->value(); 0926 if (t != Preferences::kOrgEventDuration()) 0927 Preferences::setKOrgEventDuration(t); 0928 return PrefsTabBase::apply(syncToDisc); 0929 } 0930 0931 0932 /*============================================================================= 0933 = Class StorePrefTab 0934 =============================================================================*/ 0935 0936 StorePrefTab::StorePrefTab(StackedScrollGroup* scrollGroup) 0937 : PrefsTabBase(scrollGroup) 0938 { 0939 // Which resource to save to 0940 QGroupBox* group = new QGroupBox(i18nc("@title:group", "New Alarms && Templates")); 0941 topLayout()->addWidget(group); 0942 auto bgroup = new QButtonGroup(group); 0943 QBoxLayout* layout = new QVBoxLayout(group); 0944 0945 mDefaultResource = new QRadioButton(i18nc("@option:radio", "Store in default calendar"), group); 0946 bgroup->addButton(mDefaultResource); 0947 mDefaultResource->setWhatsThis(i18nc("@info:whatsthis", "Add all new alarms and alarm templates to the default calendars, without prompting.")); 0948 layout->addWidget(mDefaultResource, 0, Qt::AlignLeft); 0949 mAskResource = new QRadioButton(i18nc("@option:radio", "Prompt for which calendar to store in"), group); 0950 bgroup->addButton(mAskResource); 0951 mAskResource->setWhatsThis(xi18nc("@info:whatsthis", 0952 "<para>When saving a new alarm or alarm template, prompt for which calendar to store it in, if there is more than one active calendar.</para>" 0953 "<para>Note that archived alarms are always stored in the default archived alarm calendar.</para>")); 0954 layout->addWidget(mAskResource, 0, Qt::AlignLeft); 0955 0956 // Archived alarms 0957 group = new QGroupBox(i18nc("@title:group", "Archived Alarms")); 0958 topLayout()->addWidget(group); 0959 auto grid = new QGridLayout(group); 0960 grid->setColumnStretch(1, 1); 0961 grid->setColumnMinimumWidth(0, gridIndentWidth()); 0962 mKeepArchived = new QCheckBox(i18nc("@option:check", "Keep alarms after expiry"), group); 0963 connect(mKeepArchived, &QAbstractButton::toggled, this, &StorePrefTab::slotArchivedToggled); 0964 mKeepArchived->setWhatsThis( 0965 i18nc("@info:whatsthis", "Check to archive alarms after expiry or deletion (except deleted alarms which were never triggered).")); 0966 grid->addWidget(mKeepArchived, 0, 0, 1, 2, Qt::AlignLeft); 0967 0968 QWidget* widget = new QWidget; 0969 auto box = new QHBoxLayout(widget); 0970 box->setContentsMargins(0, 0, 0, 0); 0971 mPurgeArchived = new QCheckBox(i18nc("@option:check", "Discard archived alarms after:")); 0972 mPurgeArchived->setMinimumSize(mPurgeArchived->sizeHint()); 0973 box->addWidget(mPurgeArchived); 0974 connect(mPurgeArchived, &QAbstractButton::toggled, this, &StorePrefTab::slotArchivedToggled); 0975 mPurgeAfter = new SpinBox; 0976 mPurgeAfter->setMinimum(1); 0977 mPurgeAfter->setSingleShiftStep(10); 0978 mPurgeAfter->setMinimumSize(mPurgeAfter->sizeHint()); 0979 box->addWidget(mPurgeAfter); 0980 mPurgeAfterLabel = new QLabel(i18nc("@label Time unit for user-entered number", "days")); 0981 mPurgeAfterLabel->setMinimumSize(mPurgeAfterLabel->sizeHint()); 0982 mPurgeAfterLabel->setBuddy(mPurgeAfter); 0983 box->addWidget(mPurgeAfterLabel); 0984 widget->setWhatsThis(i18nc("@info:whatsthis", "Uncheck to store archived alarms indefinitely. Check to enter how long archived alarms should be stored.")); 0985 grid->addWidget(widget, 1, 1, Qt::AlignLeft); 0986 0987 mClearArchived = new QPushButton(i18nc("@action:button", "Clear Archived Alarms"), group); 0988 connect(mClearArchived, &QAbstractButton::clicked, this, &StorePrefTab::slotClearArchived); 0989 mClearArchived->setWhatsThis((Resources::enabledResources(CalEvent::ARCHIVED, false).count() <= 1) 0990 ? i18nc("@info:whatsthis", "Delete all existing archived alarms.") 0991 : i18nc("@info:whatsthis", "Delete all existing archived alarms (from the default archived alarm calendar only).")); 0992 grid->addWidget(mClearArchived, 2, 1, Qt::AlignLeft); 0993 0994 topLayout()->addStretch(); // top adjust the widgets 0995 } 0996 0997 void StorePrefTab::restore(bool defaults, bool) 0998 { 0999 mCheckKeepChanges = defaults; 1000 if (Preferences::askResource()) 1001 mAskResource->setChecked(true); 1002 else 1003 mDefaultResource->setChecked(true); 1004 const int keepDays = Preferences::archivedKeepDays(); 1005 if (!defaults) 1006 mOldKeepArchived = keepDays; 1007 setArchivedControls(keepDays); 1008 mCheckKeepChanges = true; 1009 } 1010 1011 bool StorePrefTab::apply(bool syncToDisc) 1012 { 1013 const bool b = mAskResource->isChecked(); 1014 if (b != Preferences::askResource()) 1015 Preferences::setAskResource(mAskResource->isChecked()); 1016 const int days = !mKeepArchived->isChecked() ? 0 : mPurgeArchived->isChecked() ? mPurgeAfter->value() : -1; 1017 if (days != Preferences::archivedKeepDays()) 1018 Preferences::setArchivedKeepDays(days); 1019 return PrefsTabBase::apply(syncToDisc); 1020 } 1021 1022 void StorePrefTab::setArchivedControls(int purgeDays) 1023 { 1024 mKeepArchived->setChecked(purgeDays); 1025 mPurgeArchived->setChecked(purgeDays > 0); 1026 mPurgeAfter->setValue(purgeDays > 0 ? purgeDays : 0); 1027 slotArchivedToggled(true); 1028 } 1029 1030 void StorePrefTab::slotArchivedToggled(bool) 1031 { 1032 const bool keep = mKeepArchived->isChecked(); 1033 if (keep && !mOldKeepArchived && mCheckKeepChanges 1034 && !Resources::getStandard(CalEvent::ARCHIVED, true).isValid()) 1035 { 1036 KAMessageBox::error(topLayout()->parentWidget(), 1037 xi18nc("@info", "<para>A default calendar is required in order to archive alarms, but none is currently enabled.</para>" 1038 "<para>If you wish to keep expired alarms, please first use the calendars view to select a default " 1039 "archived alarms calendar.</para>")); 1040 mKeepArchived->setChecked(false); 1041 return; 1042 } 1043 mOldKeepArchived = keep; 1044 mPurgeArchived->setEnabled(keep); 1045 mPurgeAfter->setEnabled(keep && mPurgeArchived->isChecked()); 1046 mPurgeAfterLabel->setEnabled(keep); 1047 mClearArchived->setEnabled(keep); 1048 } 1049 1050 void StorePrefTab::slotClearArchived() 1051 { 1052 const bool single = Resources::enabledResources(CalEvent::ARCHIVED, false).count() <= 1; 1053 if (KAMessageBox::warningContinueCancel(topLayout()->parentWidget(), 1054 single ? i18nc("@info", "Do you really want to delete all archived alarms?") 1055 : i18nc("@info", "Do you really want to delete all alarms in the default archived alarm calendar?")) 1056 != KMessageBox::Continue) 1057 return; 1058 theApp()->purgeAll(); 1059 } 1060 1061 1062 /*============================================================================= 1063 = Class EmailPrefTab 1064 =============================================================================*/ 1065 1066 EmailPrefTab::EmailPrefTab(StackedScrollGroup* scrollGroup) 1067 : PrefsTabBase(scrollGroup) 1068 { 1069 QWidget* widget = new QWidget; 1070 topLayout()->addWidget(widget); 1071 auto box = new QHBoxLayout(widget); 1072 box->setSpacing(2 * style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing)); 1073 QLabel* label = new QLabel(i18nc("@label", "Email client:")); 1074 box->addWidget(label); 1075 mEmailClient = new ButtonGroup(widget); 1076 const QString kmailOption = i18nc("@option:radio", "KMail"); 1077 const QString sendmailOption = i18nc("@option:radio", "Sendmail"); 1078 if (PluginManager::instance()->akonadiPlugin()) 1079 { 1080 mKMailButton = new RadioButton(kmailOption); 1081 mKMailButton->setMinimumSize(mKMailButton->sizeHint()); 1082 box->addWidget(mKMailButton); 1083 mEmailClient->addButton(mKMailButton, Preferences::kmail); 1084 } 1085 mSendmailButton = new RadioButton(sendmailOption); 1086 mSendmailButton->setMinimumSize(mSendmailButton->sizeHint()); 1087 box->addWidget(mSendmailButton); 1088 mEmailClient->addButton(mSendmailButton, Preferences::sendmail); 1089 connect(mEmailClient, &ButtonGroup::buttonSet, this, &EmailPrefTab::slotEmailClientChanged); 1090 const QString sendText = i18nc("@info", "Choose how to send email when an email alarm is triggered."); 1091 if (PluginManager::instance()->akonadiPlugin()) 1092 widget->setWhatsThis(xi18nc("@info:whatsthis", 1093 "<para>%1<list><item><interface>%2</interface>: " 1094 "The email is sent automatically via <application>KMail</application>.</item>" 1095 "<item><interface>%3</interface>: " 1096 "The email is sent automatically. This option will only work if your system is " 1097 "configured to use <application>sendmail</application> or a sendmail compatible mail transport agent.</item></list></para>", 1098 sendText, kmailOption, sendmailOption)); 1099 else 1100 widget->setWhatsThis(xi18nc("@info:whatsthis", 1101 "<para>%1<list><item><interface>%2</interface>: " 1102 "The email is sent automatically. This option will only work if your system is " 1103 "configured to use <application>sendmail</application> or a sendmail compatible mail transport agent.</item></list></para>", 1104 sendText, sendmailOption)); 1105 1106 if (PluginManager::instance()->akonadiPlugin()) 1107 { 1108 widget = new QWidget; // this is to allow left adjustment 1109 topLayout()->addWidget(widget); 1110 box = new QHBoxLayout(widget); 1111 mEmailCopyToKMail = new QCheckBox(xi18nc("@option:check", "Copy sent emails into <application>KMail</application>'s <resource>%1</resource> folder", KAMail::i18n_sent_mail())); 1112 mEmailCopyToKMail->setWhatsThis(xi18nc("@info:whatsthis", "After sending an email, store a copy in <application>KMail</application>'s <resource>%1</resource> folder", KAMail::i18n_sent_mail())); 1113 box->addWidget(mEmailCopyToKMail); 1114 box->addStretch(); // left adjust the controls 1115 } 1116 1117 widget = new QWidget; // this is to allow left adjustment 1118 topLayout()->addWidget(widget); 1119 box = new QHBoxLayout(widget); 1120 mEmailQueuedNotify = new QCheckBox(i18nc("@option:check", "Notify when remote emails are queued")); 1121 mEmailQueuedNotify->setWhatsThis( 1122 i18nc("@info:whatsthis", "Display a notification message whenever an email alarm has queued an email for sending to a remote system. " 1123 "This could be useful if, for example, you have a dial-up connection, so that you can then ensure that the email is actually transmitted.")); 1124 box->addWidget(mEmailQueuedNotify); 1125 box->addStretch(); // left adjust the controls 1126 1127 // Your Email Address group box 1128 QGroupBox* group = new QGroupBox(i18nc("@title:group", "Your Email Address")); 1129 topLayout()->addWidget(group); 1130 auto grid = new QGridLayout(group); 1131 grid->setColumnStretch(2, 1); 1132 1133 // 'From' email address controls ... 1134 label = new Label(i18nc("@label 'From' email address", "From:"), group); 1135 grid->addWidget(label, 1, 0); 1136 mFromAddressGroup = new ButtonGroup(group); 1137 connect(mFromAddressGroup, &ButtonGroup::buttonSet, this, &EmailPrefTab::slotFromAddrChanged); 1138 1139 // Line edit to enter a 'From' email address 1140 mFromAddrButton = new RadioButton(group); 1141 mFromAddressGroup->addButton(mFromAddrButton, Preferences::MAIL_FROM_ADDR); 1142 label->setBuddy(mFromAddrButton); 1143 grid->addWidget(mFromAddrButton, 1, 1); 1144 mEmailAddress = new QLineEdit(group); 1145 connect(mEmailAddress, &QLineEdit::textChanged, this, &EmailPrefTab::slotAddressChanged); 1146 QString whatsThis = i18nc("@info:whatsthis", "Your email address, used to identify you as the sender when sending email alarms."); 1147 mFromAddrButton->setWhatsThis(whatsThis); 1148 mEmailAddress->setWhatsThis(whatsThis); 1149 mFromAddrButton->setFocusWidget(mEmailAddress); 1150 grid->addWidget(mEmailAddress, 1, 2); 1151 1152 // 'From' email address to be taken from KMail 1153 mFromCCentreButton = new RadioButton(xi18nc("@option:radio", "Use default <application>KMail</application> identity"), group); 1154 mFromAddressGroup->addButton(mFromCCentreButton, Preferences::MAIL_FROM_SYS_SETTINGS); 1155 mFromCCentreButton->setWhatsThis( 1156 xi18nc("@info:whatsthis", "Check to use the default email address set in <application>KMail</application>, to identify you as the sender when sending email alarms.")); 1157 grid->addWidget(mFromCCentreButton, 2, 1, 1, 2, Qt::AlignLeft); 1158 1159 // 'From' email address to be picked from KMail's identities when the email alarm is configured 1160 mFromKMailButton = new RadioButton(xi18nc("@option:radio", "Use <application>KMail</application> identities"), group); 1161 mFromAddressGroup->addButton(mFromKMailButton, Preferences::MAIL_FROM_KMAIL); 1162 mFromKMailButton->setWhatsThis( 1163 xi18nc("@info:whatsthis", "Check to use <application>KMail</application>'s email identities to identify you as the sender when sending email alarms. " 1164 "For existing email alarms, <application>KMail</application>'s default identity will be used. " 1165 "For new email alarms, you will be able to pick which of <application>KMail</application>'s identities to use.")); 1166 grid->addWidget(mFromKMailButton, 3, 1, 1, 2, Qt::AlignLeft); 1167 1168 // 'Bcc' email address controls ... 1169 grid->setRowMinimumHeight(4, style()->pixelMetric(QStyle::PM_LayoutVerticalSpacing)); 1170 label = new Label(i18nc("@label 'Bcc' email address", "Bcc:"), group); 1171 grid->addWidget(label, 5, 0); 1172 mBccAddressGroup = new ButtonGroup(group); 1173 connect(mBccAddressGroup, &ButtonGroup::buttonSet, this, &EmailPrefTab::slotBccAddrChanged); 1174 1175 // Line edit to enter a 'Bcc' email address 1176 mBccAddrButton = new RadioButton(group); 1177 mBccAddressGroup->addButton(mBccAddrButton, Preferences::MAIL_FROM_ADDR); 1178 label->setBuddy(mBccAddrButton); 1179 grid->addWidget(mBccAddrButton, 5, 1); 1180 mEmailBccAddress = new QLineEdit(group); 1181 whatsThis = xi18nc("@info:whatsthis", "Your email address, used for blind copying email alarms to yourself. " 1182 "If you want blind copies to be sent to your account on the computer which <application>KAlarm</application> runs on, you can simply enter your user login name."); 1183 mBccAddrButton->setWhatsThis(whatsThis); 1184 mEmailBccAddress->setWhatsThis(whatsThis); 1185 mBccAddrButton->setFocusWidget(mEmailBccAddress); 1186 grid->addWidget(mEmailBccAddress, 5, 2); 1187 1188 // 'Bcc' email address to be taken from KMail 1189 mBccCCentreButton = new RadioButton(xi18nc("@option:radio", "Use default <application>KMail</application> identity"), group); 1190 mBccAddressGroup->addButton(mBccCCentreButton, Preferences::MAIL_FROM_SYS_SETTINGS); 1191 mBccCCentreButton->setWhatsThis( 1192 xi18nc("@info:whatsthis", "Check to use the default email address set in <application>KMail</application>, for blind copying email alarms to yourself.")); 1193 grid->addWidget(mBccCCentreButton, 6, 1, 1, 2, Qt::AlignLeft); 1194 1195 topLayout()->addStretch(); // top adjust the widgets 1196 } 1197 1198 void EmailPrefTab::restore(bool defaults, bool) 1199 { 1200 mEmailClient->setButton(Preferences::emailClient()); 1201 if (mEmailCopyToKMail) 1202 mEmailCopyToKMail->setChecked(Preferences::emailCopyToKMail()); 1203 setEmailAddress(Preferences::emailFrom(), Preferences::emailAddress()); 1204 setEmailBccAddress((Preferences::emailBccFrom() == Preferences::MAIL_FROM_SYS_SETTINGS), Preferences::emailBccAddress()); 1205 mEmailQueuedNotify->setChecked(Preferences::emailQueuedNotify()); 1206 if (!defaults) 1207 mAddressChanged = mBccAddressChanged = false; 1208 } 1209 1210 bool EmailPrefTab::apply(bool syncToDisc) 1211 { 1212 const int client = mEmailClient->selectedId(); 1213 if (client >= 0 && static_cast<Preferences::MailClient>(client) != Preferences::emailClient()) 1214 Preferences::setEmailClient(static_cast<Preferences::MailClient>(client)); 1215 if (mEmailCopyToKMail) 1216 { 1217 bool b = mEmailCopyToKMail->isChecked(); 1218 if (b != Preferences::emailCopyToKMail()) 1219 Preferences::setEmailCopyToKMail(b); 1220 } 1221 int from = mFromAddressGroup->selectedId(); 1222 QString text = mEmailAddress->text().trimmed(); 1223 if ((from >= 0 && static_cast<Preferences::MailFrom>(from) != Preferences::emailFrom()) 1224 || text != Preferences::emailAddress()) 1225 Preferences::setEmailAddress(static_cast<Preferences::MailFrom>(from), text); 1226 bool b = (mBccAddressGroup->checkedButton() == mBccCCentreButton); 1227 Preferences::MailFrom bfrom = b ? Preferences::MAIL_FROM_SYS_SETTINGS : Preferences::MAIL_FROM_ADDR;; 1228 text = mEmailBccAddress->text().trimmed(); 1229 if (bfrom != Preferences::emailBccFrom() || text != Preferences::emailBccAddress()) 1230 Preferences::setEmailBccAddress(b, text); 1231 b = mEmailQueuedNotify->isChecked(); 1232 if (b != Preferences::emailQueuedNotify()) 1233 Preferences::setEmailQueuedNotify(mEmailQueuedNotify->isChecked()); 1234 return PrefsTabBase::apply(syncToDisc); 1235 } 1236 1237 void EmailPrefTab::showEvent(QShowEvent* e) 1238 { 1239 bool enable = Preferences::useAkonadiIfAvailable(); 1240 if (mKMailButton) 1241 { 1242 mKMailButton->setEnabled(enable); 1243 if (!enable) 1244 mEmailClient->setButton(Preferences::sendmail); 1245 } 1246 if (mEmailCopyToKMail) 1247 mEmailCopyToKMail->setEnabled(enable); 1248 1249 PrefsTabBase::showEvent(e); 1250 } 1251 1252 void EmailPrefTab::setEmailAddress(Preferences::MailFrom from, const QString& address) 1253 { 1254 mFromAddressGroup->setButton(from); 1255 mEmailAddress->setText(from == Preferences::MAIL_FROM_ADDR ? address.trimmed() : QString()); 1256 } 1257 1258 void EmailPrefTab::setEmailBccAddress(bool useSystemSettings, const QString& address) 1259 { 1260 mBccAddressGroup->setButton(useSystemSettings ? Preferences::MAIL_FROM_SYS_SETTINGS : Preferences::MAIL_FROM_ADDR); 1261 mEmailBccAddress->setText(useSystemSettings ? QString() : address.trimmed()); 1262 } 1263 1264 void EmailPrefTab::slotEmailClientChanged(QAbstractButton* button) 1265 { 1266 if (mEmailCopyToKMail) 1267 mEmailCopyToKMail->setEnabled(button == mSendmailButton && Preferences::useAkonadiIfAvailable()); 1268 } 1269 1270 void EmailPrefTab::slotFromAddrChanged(QAbstractButton* button) 1271 { 1272 mEmailAddress->setEnabled(button == mFromAddrButton); 1273 mAddressChanged = true; 1274 } 1275 1276 void EmailPrefTab::slotBccAddrChanged(QAbstractButton* button) 1277 { 1278 mEmailBccAddress->setEnabled(button == mBccAddrButton); 1279 mBccAddressChanged = true; 1280 } 1281 1282 QString EmailPrefTab::validate() 1283 { 1284 if (mAddressChanged) 1285 { 1286 mAddressChanged = false; 1287 QString errmsg = validateAddr(mFromAddressGroup, mEmailAddress, KAMail::i18n_NeedFromEmailAddress()); 1288 if (!errmsg.isEmpty()) 1289 return errmsg; 1290 } 1291 if (mBccAddressChanged) 1292 { 1293 mBccAddressChanged = false; 1294 return validateAddr(mBccAddressGroup, mEmailBccAddress, i18nc("@info", "No valid 'Bcc' email address is specified.")); 1295 } 1296 return {}; 1297 } 1298 1299 QString EmailPrefTab::validateAddr(ButtonGroup* group, QLineEdit* addr, const QString& msg) 1300 { 1301 QString errmsg = i18nc("@info", "Are you sure you want to save your changes?"); 1302 switch (group->selectedId()) 1303 { 1304 case Preferences::MAIL_FROM_SYS_SETTINGS: 1305 if (!KAMail::controlCentreAddress().isEmpty()) 1306 return {}; 1307 errmsg = xi18nc("@info", "<para>No default email address is currently set in <application>KMail</application>.</para><para>%1</para><para>%2</para>", msg, errmsg); 1308 break; 1309 case Preferences::MAIL_FROM_KMAIL: 1310 if (Identities::identitiesExist()) 1311 return {}; 1312 errmsg = xi18nc("@info", "<para>No <application>KMail</application> identities currently exist.</para><para>%1</para><para>%2</para>", msg, errmsg); 1313 break; 1314 case Preferences::MAIL_FROM_ADDR: 1315 if (!addr->text().trimmed().isEmpty()) 1316 return {}; 1317 break; 1318 } 1319 return errmsg; 1320 } 1321 1322 1323 /*============================================================================= 1324 = Class EditPrefTab 1325 =============================================================================*/ 1326 1327 EditPrefTab::EditPrefTab(StackedScrollGroup* scrollGroup) 1328 : PrefsTabBase(scrollGroup) 1329 { 1330 KLocalizedString defsetting = kxi18nc("@info:whatsthis", "The default setting for <interface>%1</interface> in the alarm edit dialog."); 1331 1332 mTabs = new QTabWidget(); 1333 mTabs->setDocumentMode(true); 1334 topLayout()->addWidget(mTabs); 1335 auto tabgroup = new StackedGroup(mTabs); 1336 1337 auto topGeneral = new StackedGroupWidget(tabgroup); 1338 auto tgLayout = new QVBoxLayout(topGeneral); 1339 mTabGeneral = mTabs->addTab(topGeneral, i18nc("@title:tab", "General")); 1340 1341 auto topTypes = new StackedGroupWidget(tabgroup); 1342 auto ttLayout = new QVBoxLayout(topTypes); 1343 ttLayout->setContentsMargins(0, style()->pixelMetric(QStyle::PM_LayoutTopMargin), 1344 0, style()->pixelMetric(QStyle::PM_LayoutBottomMargin)); 1345 mTabTypes = mTabs->addTab(topTypes, i18nc("@title:tab Settings specific to alarm type", "Type Specific")); 1346 1347 auto topFontColour = new StackedGroupWidget(tabgroup); 1348 auto tfLayout = new QVBoxLayout(topFontColour); 1349 tfLayout->setContentsMargins(0, style()->pixelMetric(QStyle::PM_LayoutTopMargin), 1350 0, style()->pixelMetric(QStyle::PM_LayoutBottomMargin)); 1351 mTabFontColour = mTabs->addTab(topFontColour, i18nc("@title:tab", "Font && Color")); 1352 1353 // MISCELLANEOUS 1354 // Alarm message display method 1355 QWidget* widget = new QWidget; // this is to control the QWhatsThis text display area 1356 tgLayout->addWidget(widget); 1357 auto box = new QHBoxLayout(widget); 1358 box->setContentsMargins(0, 0, 0, 0); 1359 QLabel* label = new QLabel(EditDisplayAlarmDlg::i18n_lbl_DisplayMethod()); 1360 box->addWidget(label); 1361 mDisplayMethod = new QComboBox(); 1362 mDisplayMethod->addItem(EditDisplayAlarmDlg::i18n_combo_Window()); 1363 mDisplayMethod->addItem(EditDisplayAlarmDlg::i18n_combo_Notify()); 1364 box->addWidget(mDisplayMethod); 1365 box->addStretch(); 1366 label->setBuddy(mDisplayMethod); 1367 widget->setWhatsThis(i18nc("@info:whatsthis", "The default setting for the alarm message display method in the alarm edit dialog.")); 1368 1369 // Show in KOrganizer 1370 mCopyToKOrganizer = new QCheckBox(EditAlarmDlg::i18n_chk_ShowInKOrganizer()); 1371 mCopyToKOrganizer->setMinimumSize(mCopyToKOrganizer->sizeHint()); 1372 mCopyToKOrganizer->setWhatsThis(defsetting.subs(EditAlarmDlg::i18n_chk_ShowInKOrganizer()).toString()); 1373 tgLayout->addWidget(mCopyToKOrganizer); 1374 1375 // Late cancellation 1376 widget = new QWidget; 1377 tgLayout->addWidget(widget); 1378 box = new QHBoxLayout(widget); 1379 box->setContentsMargins(0, 0, 0, 0); 1380 box->setSpacing(0); 1381 mLateCancel = new QCheckBox(LateCancelSelector::i18n_chk_CancelIfLate()); 1382 mLateCancel->setMinimumSize(mLateCancel->sizeHint()); 1383 mLateCancel->setWhatsThis(defsetting.subs(LateCancelSelector::i18n_chk_CancelIfLate()).toString()); 1384 box->addWidget(mLateCancel); 1385 1386 // Recurrence 1387 widget = new QWidget; // this is to control the QWhatsThis text display area 1388 tgLayout->addWidget(widget); 1389 box = new QHBoxLayout(widget); 1390 box->setContentsMargins(0, 0, 0, 0); 1391 label = new QLabel(i18nc("@label:listbox", "Recurrence:")); 1392 box->addWidget(label); 1393 mRecurPeriod = new ComboBox(); 1394 mRecurPeriod->addItem(RecurrenceEdit::i18n_combo_NoRecur()); 1395 mRecurPeriod->addItem(RecurrenceEdit::i18n_combo_AtLogin()); 1396 mRecurPeriod->addItem(RecurrenceEdit::i18n_combo_HourlyMinutely()); 1397 mRecurPeriod->addItem(RecurrenceEdit::i18n_combo_Daily()); 1398 mRecurPeriod->addItem(RecurrenceEdit::i18n_combo_Weekly()); 1399 mRecurPeriod->addItem(RecurrenceEdit::i18n_combo_Monthly()); 1400 mRecurPeriod->addItem(RecurrenceEdit::i18n_combo_Yearly()); 1401 box->addWidget(mRecurPeriod); 1402 box->addStretch(); 1403 label->setBuddy(mRecurPeriod); 1404 widget->setWhatsThis(i18nc("@info:whatsthis", "The default setting for the recurrence rule in the alarm edit dialog.")); 1405 1406 // How to handle February 29th in yearly recurrences 1407 QWidget* febBox = new QWidget; // this is to control the QWhatsThis text display area 1408 tgLayout->addWidget(febBox); 1409 auto vbox = new QVBoxLayout(febBox); 1410 vbox->setContentsMargins(0, 0, 0, 0); 1411 label = new QLabel(i18nc("@label", "In non-leap years, repeat yearly February 29th alarms on:")); 1412 // *** Workaround for the bug that QLabel doesn't align correctly in right-to-left mode. *** 1413 label->setAlignment((layoutDirection() == Qt::LeftToRight ? Qt::AlignLeft : Qt::AlignRight) | Qt::AlignAbsolute); 1414 label->setWordWrap(true); 1415 vbox->addWidget(label); 1416 box = new QHBoxLayout(); 1417 vbox->addLayout(box); 1418 vbox->setContentsMargins(0, 0, 0, 0); 1419 box->setSpacing(2 * style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing)); 1420 mFeb29 = new ButtonGroup(febBox); 1421 widget = new QWidget(); 1422 widget->setFixedWidth(3 * style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing)); 1423 box->addWidget(widget); 1424 QRadioButton* radio = new QRadioButton(i18nc("@option:radio", "February 28th")); 1425 radio->setMinimumSize(radio->sizeHint()); 1426 box->addWidget(radio); 1427 mFeb29->addButton(radio, Preferences::Feb29_Feb28); 1428 radio = new QRadioButton(i18nc("@option:radio", "March 1st")); 1429 radio->setMinimumSize(radio->sizeHint()); 1430 box->addWidget(radio); 1431 mFeb29->addButton(radio, Preferences::Feb29_Mar1); 1432 radio = new QRadioButton(i18nc("@option:radio", "Do not repeat")); 1433 radio->setMinimumSize(radio->sizeHint()); 1434 box->addWidget(radio); 1435 mFeb29->addButton(radio, Preferences::Feb29_None); 1436 febBox->setWhatsThis(xi18nc("@info:whatsthis", 1437 "For yearly recurrences, choose what date, if any, alarms due on February 29th should occur in non-leap years." 1438 "<note>The next scheduled occurrence of existing alarms is not re-evaluated when you change this setting.</note>")); 1439 1440 tgLayout->addStretch(); // top adjust the widgets 1441 1442 // DISPLAY ALARMS 1443 QGroupBox* group = new QGroupBox(i18nc("@title:group", "Display Alarms")); 1444 ttLayout->addWidget(group); 1445 auto vlayout = new QVBoxLayout(group); 1446 1447 mConfirmAck = new QCheckBox(EditDisplayAlarmDlg::i18n_chk_ConfirmAck()); 1448 mConfirmAck->setMinimumSize(mConfirmAck->sizeHint()); 1449 mConfirmAck->setWhatsThis(defsetting.subs(EditDisplayAlarmDlg::i18n_chk_ConfirmAck()).toString()); 1450 vlayout->addWidget(mConfirmAck, 0, Qt::AlignLeft); 1451 1452 mAutoClose = new QCheckBox(LateCancelSelector::i18n_chk_AutoCloseWinLC()); 1453 mAutoClose->setMinimumSize(mAutoClose->sizeHint()); 1454 mAutoClose->setWhatsThis(defsetting.subs(LateCancelSelector::i18n_chk_AutoCloseWin()).toString()); 1455 vlayout->addWidget(mAutoClose, 0, Qt::AlignLeft); 1456 1457 widget = new QWidget; 1458 vlayout->addWidget(widget); 1459 box = new QHBoxLayout(widget); 1460 box->setContentsMargins(0, 0, 0, 0); 1461 label = new QLabel(i18nc("@label:listbox", "Reminder units:")); 1462 box->addWidget(label); 1463 mReminderUnits = new QComboBox(); 1464 mReminderUnits->addItem(i18nc("@item:inlistbox", "Minutes"), TimePeriod::Minutes); 1465 mReminderUnits->addItem(i18nc("@item:inlistbox", "Hours/Minutes"), TimePeriod::HoursMinutes); 1466 box->addWidget(mReminderUnits); 1467 label->setBuddy(mReminderUnits); 1468 widget->setWhatsThis(i18nc("@info:whatsthis", "The default units for the reminder in the alarm edit dialog, for alarms due soon.")); 1469 box->addStretch(); // left adjust the control 1470 mSpecialActionsButton = new SpecialActionsButton(true); 1471 box->addWidget(mSpecialActionsButton); 1472 1473 // SOUND 1474 QGroupBox* bbox = new QGroupBox(i18nc("@title:group Audio options group", "Sound")); 1475 ttLayout->addWidget(bbox); 1476 vlayout = new QVBoxLayout(bbox); 1477 1478 auto hlayout = new QHBoxLayout; 1479 hlayout->setContentsMargins(0, 0, 0, 0); 1480 vlayout->addLayout(hlayout); 1481 mSound = new QComboBox(); 1482 mSound->addItem(SoundPicker::i18n_combo_None()); // index 0 1483 mSound->addItem(SoundPicker::i18n_combo_Beep()); // index 1 1484 mSound->addItem(SoundPicker::i18n_combo_File()); // index 2 1485 #ifdef HAVE_TEXT_TO_SPEECH_SUPPORT 1486 if (TextEditTextToSpeech::TextToSpeech::self()->isReady()) 1487 mSound->addItem(SoundPicker::i18n_combo_Speak()); // index 3 1488 #endif 1489 mSound->setMinimumSize(mSound->sizeHint()); 1490 mSound->setWhatsThis(defsetting.subs(SoundPicker::i18n_label_Sound()).toString()); 1491 hlayout->addWidget(mSound); 1492 hlayout->addStretch(); 1493 mSoundRepeat = new QCheckBox(i18nc("@option:check", "Repeat sound file")); 1494 mSoundRepeat->setMinimumSize(mSoundRepeat->sizeHint()); 1495 mSoundRepeat->setWhatsThis( 1496 xi18nc("@info:whatsthis sound file 'Repeat' checkbox", "The default setting for sound file <interface>%1</interface> in the alarm edit dialog.", SoundWidget::i18n_chk_Repeat())); 1497 hlayout->addWidget(mSoundRepeat); 1498 1499 widget = new QWidget; // this is to control the QWhatsThis text display area 1500 box = new QHBoxLayout(widget); 1501 box->setContentsMargins(0, 0, 0, 0); 1502 mSoundFileLabel = new QLabel(i18nc("@label:textbox", "Sound file:")); 1503 box->addWidget(mSoundFileLabel); 1504 mSoundFile = new QLineEdit(); 1505 box->addWidget(mSoundFile); 1506 mSoundFileLabel->setBuddy(mSoundFile); 1507 mSoundFileBrowse = new QPushButton(); 1508 mSoundFileBrowse->setIcon(QIcon::fromTheme(QStringLiteral("document-open"))); 1509 connect(mSoundFileBrowse, &QAbstractButton::clicked, this, &EditPrefTab::slotBrowseSoundFile); 1510 mSoundFileBrowse->setToolTip(i18nc("@info:tooltip", "Choose a sound file")); 1511 box->addWidget(mSoundFileBrowse); 1512 widget->setWhatsThis(i18nc("@info:whatsthis", "Enter the default sound file to use in the alarm edit dialog.")); 1513 vlayout->addWidget(widget); 1514 1515 box = new QHBoxLayout(); 1516 box->setContentsMargins(0, 0, 0, 0); 1517 mSoundVolumeCheckbox = new CheckBox(SoundWidget::i18n_chk_SetVolume(), nullptr); 1518 connect(mSoundVolumeCheckbox, &CheckBox::toggled, this, [this](bool on) { mSoundVolumeSlider->setEnabled(on); }); 1519 box->addWidget(mSoundVolumeCheckbox); 1520 mSoundVolumeSlider = new Slider(0, 100, 10, Qt::Horizontal); 1521 mSoundVolumeCheckbox->setWhatsThis(i18nc("@info:whatsthis", "Select to set the default volume for sound files in the alarm edit dialog.")); 1522 mSoundVolumeSlider->setTickPosition(QSlider::TicksBelow); 1523 mSoundVolumeSlider->setTickInterval(10); 1524 mSoundVolumeSlider->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed)); 1525 mSoundVolumeSlider->setWhatsThis(i18nc("@info:whatsthis", "The default volume for sound files in the alarm edit dialog.")); 1526 mSoundVolumeSlider->setEnabled(false); 1527 box->addWidget(mSoundVolumeSlider); 1528 label = new QLabel; 1529 mSoundVolumeSlider->setValueLabel(label, QStringLiteral("%1%"), true); 1530 box->addWidget(label); 1531 mSoundVolumeCheckbox->setFocusWidget(mSoundVolumeSlider); 1532 vlayout->addLayout(box); 1533 1534 // COMMAND ALARMS 1535 group = new QGroupBox(i18nc("@title:group", "Command Alarms")); 1536 ttLayout->addWidget(group); 1537 vlayout = new QVBoxLayout(group); 1538 hlayout = new QHBoxLayout(); 1539 hlayout->setContentsMargins(0, 0, 0, 0); 1540 vlayout->addLayout(hlayout); 1541 1542 mCmdScript = new QCheckBox(EditCommandAlarmDlg::i18n_chk_EnterScript(), group); 1543 mCmdScript->setMinimumSize(mCmdScript->sizeHint()); 1544 mCmdScript->setWhatsThis(defsetting.subs(EditCommandAlarmDlg::i18n_chk_EnterScript()).toString()); 1545 hlayout->addWidget(mCmdScript); 1546 hlayout->addStretch(); 1547 1548 mCmdXterm = new QCheckBox(EditCommandAlarmDlg::i18n_chk_ExecInTermWindow(), group); 1549 mCmdXterm->setMinimumSize(mCmdXterm->sizeHint()); 1550 mCmdXterm->setWhatsThis(defsetting.subs(EditCommandAlarmDlg::i18n_radio_ExecInTermWindow()).toString()); 1551 hlayout->addWidget(mCmdXterm); 1552 1553 // EMAIL ALARMS 1554 group = new QGroupBox(i18nc("@title:group", "Email Alarms")); 1555 ttLayout->addWidget(group); 1556 vlayout = new QVBoxLayout(group); 1557 1558 // BCC email to sender 1559 mEmailBcc = new QCheckBox(EditEmailAlarmDlg::i18n_chk_CopyEmailToSelf(), group); 1560 mEmailBcc->setMinimumSize(mEmailBcc->sizeHint()); 1561 mEmailBcc->setWhatsThis(defsetting.subs(EditEmailAlarmDlg::i18n_chk_CopyEmailToSelf()).toString()); 1562 vlayout->addWidget(mEmailBcc, 0, Qt::AlignLeft); 1563 1564 ttLayout->addStretch(); 1565 1566 // FONT / COLOUR TAB 1567 mFontChooser = new FontColourChooser(topFontColour, QStringList(), i18nc("@title:group", "Message Font && Color"), true); 1568 tfLayout->addWidget(mFontChooser); 1569 tfLayout->setContentsMargins(0, 0, 0, 0); 1570 } 1571 1572 void EditPrefTab::restore(bool, bool allTabs) 1573 { 1574 int index; 1575 if (allTabs || mTabs->currentIndex() == mTabGeneral) 1576 { 1577 mDisplayMethod->setCurrentIndex(Preferences::defaultDisplayMethod() == Preferences::Display_Window ? 0 : 1); 1578 mCopyToKOrganizer->setChecked(Preferences::defaultCopyToKOrganizer()); 1579 mLateCancel->setChecked(Preferences::defaultLateCancel()); 1580 switch (Preferences::defaultRecurPeriod()) 1581 { 1582 case Preferences::Recur_Yearly: index = 6; break; 1583 case Preferences::Recur_Monthly: index = 5; break; 1584 case Preferences::Recur_Weekly: index = 4; break; 1585 case Preferences::Recur_Daily: index = 3; break; 1586 case Preferences::Recur_SubDaily: index = 2; break; 1587 case Preferences::Recur_Login: index = 1; break; 1588 case Preferences::Recur_None: 1589 default: index = 0; break; 1590 } 1591 mRecurPeriod->setCurrentIndex(index); 1592 mFeb29->setButton(Preferences::defaultFeb29Type()); 1593 } 1594 if (allTabs || mTabs->currentIndex() == mTabTypes) 1595 { 1596 mConfirmAck->setChecked(Preferences::defaultConfirmAck()); 1597 mAutoClose->setChecked(Preferences::defaultAutoClose()); 1598 switch (Preferences::defaultReminderUnits()) 1599 { 1600 case TimePeriod::Weeks: index = 3; break; 1601 case TimePeriod::Days: index = 2; break; 1602 default: 1603 case TimePeriod::HoursMinutes: index = 1; break; 1604 case TimePeriod::Minutes: index = 0; break; 1605 } 1606 mReminderUnits->setCurrentIndex(index); 1607 KAEvent::ExtraActionOptions opts{}; 1608 if (Preferences::defaultExecPreActionOnDeferral()) 1609 opts |= KAEvent::ExecPreActOnDeferral; 1610 if (Preferences::defaultCancelOnPreActionError()) 1611 opts |= KAEvent::CancelOnPreActError; 1612 if (Preferences::defaultDontShowPreActionError()) 1613 opts |= KAEvent::DontShowPreActError; 1614 mSpecialActionsButton->setActions(Preferences::defaultPreAction(), Preferences::defaultPostAction(), opts); 1615 mSound->setCurrentIndex(soundIndex(Preferences::defaultSoundType())); 1616 mSoundFile->setText(Preferences::defaultSoundFile()); 1617 mSoundRepeat->setChecked(Preferences::defaultSoundRepeat()); 1618 const int volume = Preferences::defaultSoundVolume() * 100; 1619 mSoundVolumeCheckbox->setChecked(volume >= 0); 1620 mSoundVolumeSlider->setValue(volume >= 0 ? volume : 100); 1621 mCmdScript->setChecked(Preferences::defaultCmdScript()); 1622 mCmdXterm->setChecked(Preferences::defaultCmdLogType() == Preferences::Log_Terminal); 1623 mEmailBcc->setChecked(Preferences::defaultEmailBcc()); 1624 } 1625 if (allTabs || mTabs->currentIndex() == mTabFontColour) 1626 { 1627 mFontChooser->setFgColour(Preferences::defaultFgColour()); 1628 mFontChooser->setBgColour(Preferences::defaultBgColour()); 1629 mFontChooser->setFont(Preferences::messageFont()); 1630 } 1631 } 1632 1633 bool EditPrefTab::apply(bool syncToDisc) 1634 { 1635 bool b = mAutoClose->isChecked(); 1636 if (b != Preferences::defaultAutoClose()) 1637 Preferences::setDefaultAutoClose(b); 1638 b = mConfirmAck->isChecked(); 1639 if (b != Preferences::defaultConfirmAck()) 1640 Preferences::setDefaultConfirmAck(b); 1641 TimePeriod::Units units; 1642 switch (mReminderUnits->currentIndex()) 1643 { 1644 case 3: units = TimePeriod::Weeks; break; 1645 case 2: units = TimePeriod::Days; break; 1646 default: 1647 case 1: units = TimePeriod::HoursMinutes; break; 1648 case 0: units = TimePeriod::Minutes; break; 1649 } 1650 if (units != Preferences::defaultReminderUnits()) 1651 Preferences::setDefaultReminderUnits(units); 1652 QString text = mSpecialActionsButton->preAction(); 1653 if (text != Preferences::defaultPreAction()) 1654 Preferences::setDefaultPreAction(text); 1655 text = mSpecialActionsButton->postAction(); 1656 if (text != Preferences::defaultPostAction()) 1657 Preferences::setDefaultPostAction(text); 1658 KAEvent::ExtraActionOptions opts = mSpecialActionsButton->options(); 1659 b = opts & KAEvent::ExecPreActOnDeferral; 1660 if (b != Preferences::defaultExecPreActionOnDeferral()) 1661 Preferences::setDefaultExecPreActionOnDeferral(b); 1662 b = opts & KAEvent::CancelOnPreActError; 1663 if (b != Preferences::defaultCancelOnPreActionError()) 1664 Preferences::setDefaultCancelOnPreActionError(b); 1665 b = opts & KAEvent::DontShowPreActError; 1666 if (b != Preferences::defaultDontShowPreActionError()) 1667 Preferences::setDefaultDontShowPreActionError(b); 1668 Preferences::SoundType snd; 1669 switch (mSound->currentIndex()) 1670 { 1671 #ifdef HAVE_TEXT_TO_SPEECH_SUPPORT 1672 case 3: snd = Preferences::Sound_Speak; break; 1673 #endif 1674 case 2: snd = Preferences::Sound_File; break; 1675 case 1: snd = Preferences::Sound_Beep; break; 1676 case 0: 1677 default: snd = Preferences::Sound_None; break; 1678 } 1679 if (snd != Preferences::defaultSoundType()) 1680 Preferences::setDefaultSoundType(snd); 1681 text = mSoundFile->text(); 1682 if (text != Preferences::defaultSoundFile()) 1683 Preferences::setDefaultSoundFile(text); 1684 b = mSoundRepeat->isChecked(); 1685 if (b != Preferences::defaultSoundRepeat()) 1686 Preferences::setDefaultSoundRepeat(b); 1687 const float v = mSoundVolumeCheckbox->isChecked() ? (float)mSoundVolumeSlider->value() / 100 : -1; 1688 if (v != Preferences::defaultSoundVolume()) 1689 Preferences::setDefaultSoundVolume(v); 1690 b = mCmdScript->isChecked(); 1691 if (b != Preferences::defaultCmdScript()) 1692 Preferences::setDefaultCmdScript(b); 1693 Preferences::CmdLogType log = mCmdXterm->isChecked() ? Preferences::Log_Terminal : Preferences::Log_Discard; 1694 if (log != Preferences::defaultCmdLogType()) 1695 Preferences::setDefaultCmdLogType(log); 1696 b = mEmailBcc->isChecked(); 1697 if (b != Preferences::defaultEmailBcc()) 1698 Preferences::setDefaultEmailBcc(b); 1699 Preferences::DisplayMethod disp; 1700 switch(mDisplayMethod->currentIndex()) 1701 { 1702 case 1: disp = Preferences::Display_Notification; break; 1703 case 0: 1704 default: disp = Preferences::Display_Window; break; 1705 } 1706 if (disp != Preferences::defaultDisplayMethod()) 1707 Preferences::setDefaultDisplayMethod(disp); 1708 b = mCopyToKOrganizer->isChecked(); 1709 if (b != Preferences::defaultCopyToKOrganizer()) 1710 Preferences::setDefaultCopyToKOrganizer(b); 1711 const int i = mLateCancel->isChecked() ? 1 : 0; 1712 if (i != Preferences::defaultLateCancel()) 1713 Preferences::setDefaultLateCancel(i); 1714 Preferences::RecurType period; 1715 switch (mRecurPeriod->currentIndex()) 1716 { 1717 case 6: period = Preferences::Recur_Yearly; break; 1718 case 5: period = Preferences::Recur_Monthly; break; 1719 case 4: period = Preferences::Recur_Weekly; break; 1720 case 3: period = Preferences::Recur_Daily; break; 1721 case 2: period = Preferences::Recur_SubDaily; break; 1722 case 1: period = Preferences::Recur_Login; break; 1723 case 0: 1724 default: period = Preferences::Recur_None; break; 1725 } 1726 if (period != Preferences::defaultRecurPeriod()) 1727 Preferences::setDefaultRecurPeriod(period); 1728 const int feb29 = mFeb29->selectedId(); 1729 if (feb29 >= 0 && static_cast<Preferences::Feb29Type>(feb29) != Preferences::defaultFeb29Type()) 1730 Preferences::setDefaultFeb29Type(static_cast<Preferences::Feb29Type>(feb29)); 1731 QColor colour = mFontChooser->fgColour(); 1732 if (colour != Preferences::defaultFgColour()) 1733 Preferences::setDefaultFgColour(colour); 1734 colour = mFontChooser->bgColour(); 1735 if (colour != Preferences::defaultBgColour()) 1736 Preferences::setDefaultBgColour(colour); 1737 const QFont font = mFontChooser->font(); 1738 if (font != Preferences::messageFont()) 1739 Preferences::setMessageFont(font); 1740 return PrefsTabBase::apply(syncToDisc); 1741 } 1742 1743 void EditPrefTab::slotBrowseSoundFile() 1744 { 1745 QString defaultDir; 1746 QString file; 1747 if (SoundPicker::browseFile(file, defaultDir, mSoundFile->text())) 1748 { 1749 if (!file.isEmpty()) 1750 mSoundFile->setText(file); 1751 } 1752 } 1753 1754 int EditPrefTab::soundIndex(Preferences::SoundType type) 1755 { 1756 switch (type) 1757 { 1758 #ifdef HAVE_TEXT_TO_SPEECH_SUPPORT 1759 case Preferences::Sound_Speak: return 3; 1760 #endif 1761 case Preferences::Sound_File: return 2; 1762 case Preferences::Sound_Beep: return 1; 1763 case Preferences::Sound_None: 1764 default: return 0; 1765 } 1766 } 1767 1768 QString EditPrefTab::validate() 1769 { 1770 if (mSound->currentIndex() == soundIndex(Preferences::Sound_File) && mSoundFile->text().isEmpty()) 1771 { 1772 mSoundFile->setFocus(); 1773 return xi18nc("@info", "You must enter a sound file when <interface>%1</interface> is selected as the default sound type", SoundPicker::i18n_combo_File());; 1774 } 1775 return {}; 1776 } 1777 1778 1779 /*============================================================================= 1780 = Class ViewPrefTab 1781 =============================================================================*/ 1782 1783 ViewPrefTab::ViewPrefTab(StackedScrollGroup* scrollGroup) 1784 : PrefsTabBase(scrollGroup) 1785 { 1786 mTabs = new QTabWidget(); 1787 mTabs->setDocumentMode(true); 1788 topLayout()->addWidget(mTabs); 1789 1790 QWidget* widget = new QWidget; 1791 auto topGeneral = new QVBoxLayout(widget); 1792 topGeneral->setContentsMargins(0, style()->pixelMetric(QStyle::PM_LayoutTopMargin), 1793 0, style()->pixelMetric(QStyle::PM_LayoutBottomMargin)); 1794 mTabGeneral = mTabs->addTab(widget, i18nc("@title:tab", "General")); 1795 1796 widget = new QWidget; 1797 auto topWindows = new QVBoxLayout(widget); 1798 topWindows->setContentsMargins(0, style()->pixelMetric(QStyle::PM_LayoutTopMargin), 1799 0, style()->pixelMetric(QStyle::PM_LayoutBottomMargin)); 1800 mTabWindows = mTabs->addTab(widget, i18nc("@title:tab", "Alarm Windows")); 1801 1802 // Run-in-system-tray check box or group. 1803 static const QString showInSysTrayText = i18nc("@option:check", "Show in system tray"); 1804 static const QString showInSysTrayWhatsThis = xi18nc("@info:whatsthis", 1805 "<para>Check to show <application>KAlarm</application>'s icon in the system tray." 1806 " Showing it in the system tray provides easy access and a status indication.</para>"); 1807 if (Preferences::noAutoHideSystemTrayDesktops().contains(Desktop::currentIdentityName())) 1808 { 1809 // Run-in-system-tray check box. 1810 // This desktop type doesn't provide GUI controls to view hidden system tray 1811 // icons, so don't show options to hide the system tray icon. 1812 widget = new QWidget; // this is to allow left adjustment 1813 topGeneral->addWidget(widget); 1814 auto box = new QHBoxLayout(widget); 1815 mShowInSystemTrayCheck = new QCheckBox(showInSysTrayText); 1816 mShowInSystemTrayCheck->setWhatsThis(showInSysTrayWhatsThis); 1817 box->addWidget(mShowInSystemTrayCheck); 1818 box->addStretch(); // left adjust the controls 1819 } 1820 else 1821 { 1822 // Run-in-system-tray group box 1823 mShowInSystemTrayGroup = new QGroupBox(showInSysTrayText); 1824 mShowInSystemTrayGroup->setCheckable(true); 1825 mShowInSystemTrayGroup->setWhatsThis(showInSysTrayWhatsThis); 1826 topGeneral->addWidget(mShowInSystemTrayGroup); 1827 auto grid = new QGridLayout(mShowInSystemTrayGroup); 1828 grid->setColumnStretch(1, 1); 1829 grid->setColumnMinimumWidth(0, gridIndentWidth()); 1830 1831 mAutoHideSystemTray = new ButtonGroup(mShowInSystemTrayGroup); 1832 connect(mAutoHideSystemTray, &ButtonGroup::buttonSet, this, &ViewPrefTab::slotAutoHideSysTrayChanged); 1833 1834 QRadioButton* radio = new QRadioButton(i18nc("@option:radio Always show KAlarm icon", "Always show"), mShowInSystemTrayGroup); 1835 mAutoHideSystemTray->addButton(radio, 0); 1836 radio->setWhatsThis( 1837 xi18nc("@info:whatsthis", 1838 "Check to show <application>KAlarm</application>'s icon in the system tray " 1839 "regardless of whether alarms are due.")); 1840 grid->addWidget(radio, 0, 0, 1, 2, Qt::AlignLeft); 1841 1842 radio = new QRadioButton(i18nc("@option:radio", "Automatically hide if no active alarms"), mShowInSystemTrayGroup); 1843 mAutoHideSystemTray->addButton(radio, 1); 1844 radio->setWhatsThis( 1845 xi18nc("@info:whatsthis", 1846 "Check to automatically hide <application>KAlarm</application>'s icon in " 1847 "the system tray if there are no active alarms. When hidden, the icon can " 1848 "always be made visible by use of the system tray option to show hidden icons.")); 1849 grid->addWidget(radio, 1, 0, 1, 2, Qt::AlignLeft); 1850 1851 QString text = xi18nc("@info:whatsthis", 1852 "Check to automatically hide <application>KAlarm</application>'s icon in the " 1853 "system tray if no alarms are due within the specified time period. When hidden, " 1854 "the icon can always be made visible by use of the system tray option to show hidden icons."); 1855 radio = new QRadioButton(i18nc("@option:radio", "Automatically hide if no alarm due within time period:"), mShowInSystemTrayGroup); 1856 radio->setWhatsThis(text); 1857 mAutoHideSystemTray->addButton(radio, 2); 1858 grid->addWidget(radio, 2, 0, 1, 2, Qt::AlignLeft); 1859 mAutoHideSystemTrayPeriod = new TimePeriod(TimePeriod::ShowMinutes, mShowInSystemTrayGroup); 1860 mAutoHideSystemTrayPeriod->setWhatsThis(text); 1861 mAutoHideSystemTrayPeriod->setMaximumWidth(mAutoHideSystemTrayPeriod->sizeHint().width()); 1862 grid->addWidget(mAutoHideSystemTrayPeriod, 3, 1, 1, 1, Qt::AlignLeft); 1863 mShowInSystemTrayGroup->setMaximumHeight(mShowInSystemTrayGroup->sizeHint().height()); 1864 } 1865 1866 // System tray tooltip group box 1867 QGroupBox* group = new QGroupBox(i18nc("@title:group", "System Tray Tooltip")); 1868 topGeneral->addWidget(group); 1869 auto grid = new QGridLayout(group); 1870 grid->setColumnStretch(2, 1); 1871 grid->setColumnMinimumWidth(0, gridIndentWidth()); 1872 grid->setColumnMinimumWidth(1, gridIndentWidth()); 1873 1874 mTooltipShowAlarms = new QCheckBox(i18nc("@option:check", "Show next 24 hours' alarms"), group); 1875 mTooltipShowAlarms->setMinimumSize(mTooltipShowAlarms->sizeHint()); 1876 connect(mTooltipShowAlarms, &QAbstractButton::toggled, this, &ViewPrefTab::slotTooltipAlarmsToggled); 1877 mTooltipShowAlarms->setWhatsThis( 1878 i18nc("@info:whatsthis", "Specify whether to include in the system tray tooltip, a summary of alarms due in the next 24 hours.")); 1879 grid->addWidget(mTooltipShowAlarms, 0, 0, 1, 3, Qt::AlignLeft); 1880 1881 widget = new QWidget; 1882 auto box = new QHBoxLayout(widget); 1883 box->setContentsMargins(0, 0, 0, 0); 1884 mTooltipMaxAlarms = new QCheckBox(i18nc("@option:check", "Maximum number of alarms to show:")); 1885 mTooltipMaxAlarms->setMinimumSize(mTooltipMaxAlarms->sizeHint()); 1886 box->addWidget(mTooltipMaxAlarms); 1887 connect(mTooltipMaxAlarms, &QAbstractButton::toggled, this, &ViewPrefTab::slotTooltipMaxToggled); 1888 mTooltipMaxAlarmCount = new SpinBox(1, 99); 1889 mTooltipMaxAlarmCount->setSingleShiftStep(5); 1890 mTooltipMaxAlarmCount->setMinimumSize(mTooltipMaxAlarmCount->sizeHint()); 1891 box->addWidget(mTooltipMaxAlarmCount); 1892 widget->setWhatsThis( 1893 i18nc("@info:whatsthis", "Uncheck to display all of the next 24 hours' alarms in the system tray tooltip. " 1894 "Check to enter an upper limit on the number to be displayed.")); 1895 grid->addWidget(widget, 1, 1, 1, 2, Qt::AlignLeft); 1896 1897 mTooltipShowTime = new QCheckBox(i18nc("@option:check", "Show alarm time"), group); 1898 mTooltipShowTime->setMinimumSize(mTooltipShowTime->sizeHint()); 1899 connect(mTooltipShowTime, &QAbstractButton::toggled, this, &ViewPrefTab::slotTooltipTimeToggled); 1900 mTooltipShowTime->setWhatsThis(i18nc("@info:whatsthis", "Specify whether to show in the system tray tooltip, the time at which each alarm is due.")); 1901 grid->addWidget(mTooltipShowTime, 2, 1, 1, 2, Qt::AlignLeft); 1902 1903 mTooltipShowTimeTo = new QCheckBox(i18nc("@option:check", "Show time until alarm"), group); 1904 mTooltipShowTimeTo->setMinimumSize(mTooltipShowTimeTo->sizeHint()); 1905 connect(mTooltipShowTimeTo, &QAbstractButton::toggled, this, &ViewPrefTab::slotTooltipTimeToToggled); 1906 mTooltipShowTimeTo->setWhatsThis(i18nc("@info:whatsthis", "Specify whether to show in the system tray tooltip, how long until each alarm is due.")); 1907 grid->addWidget(mTooltipShowTimeTo, 3, 1, 1, 2, Qt::AlignLeft); 1908 1909 widget = new QWidget; // this is to control the QWhatsThis text display area 1910 box = new QHBoxLayout(widget); 1911 box->setContentsMargins(0, 0, 0, 0); 1912 mTooltipTimeToPrefixLabel = new QLabel(i18nc("@label:textbox", "Prefix:")); 1913 box->addWidget(mTooltipTimeToPrefixLabel); 1914 mTooltipTimeToPrefix = new QLineEdit(); 1915 box->addWidget(mTooltipTimeToPrefix); 1916 mTooltipTimeToPrefixLabel->setBuddy(mTooltipTimeToPrefix); 1917 widget->setWhatsThis(i18nc("@info:whatsthis", "Enter the text to be displayed in front of the time until the alarm, in the system tray tooltip.")); 1918 grid->addWidget(widget, 4, 2, Qt::AlignLeft); 1919 group->setMaximumHeight(group->sizeHint().height()); 1920 1921 group = new QGroupBox(i18nc("@title:group", "Alarm List")); 1922 topGeneral->addWidget(group); 1923 auto hlayout = new QHBoxLayout(group); 1924 auto colourLayout = new QVBoxLayout(); 1925 colourLayout->setContentsMargins(0, 0, 0, 0); 1926 hlayout->addLayout(colourLayout); 1927 1928 widget = new QWidget; // to group widgets for QWhatsThis text 1929 box = new QHBoxLayout(widget); 1930 box->setContentsMargins(0, 0, 0, 0); 1931 box->setSpacing(style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing) / 2); 1932 colourLayout->addWidget(widget); 1933 QLabel* label1 = new QLabel(i18nc("@label:listbox", "Disabled alarm color:")); 1934 box->addWidget(label1); 1935 box->setStretchFactor(new QWidget(widget), 0); 1936 mDisabledColour = new ColourButton(); 1937 box->addWidget(mDisabledColour); 1938 label1->setBuddy(mDisabledColour); 1939 widget->setWhatsThis(i18nc("@info:whatsthis", "Choose the text color in the alarm list for disabled alarms.")); 1940 1941 widget = new QWidget; // to group widgets for QWhatsThis text 1942 box = new QHBoxLayout(widget); 1943 box->setContentsMargins(0, 0, 0, 0); 1944 box->setSpacing(style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing) / 2); 1945 colourLayout->addWidget(widget); 1946 QLabel* label2 = new QLabel(i18nc("@label:listbox", "Archived alarm color:")); 1947 box->addWidget(label2); 1948 box->setStretchFactor(new QWidget(widget), 0); 1949 mArchivedColour = new ColourButton(); 1950 box->addWidget(mArchivedColour); 1951 label2->setBuddy(mArchivedColour); 1952 widget->setWhatsThis(i18nc("@info:whatsthis", "Choose the text color in the alarm list for archived alarms.")); 1953 hlayout->addStretch(); 1954 1955 if (topGeneral) 1956 topGeneral->addStretch(); // top adjust the widgets 1957 1958 1959 group = new QGroupBox(i18nc("@title:group", "Alarm Message Windows")); 1960 topWindows->addWidget(group); 1961 grid = new QGridLayout(group); 1962 grid->setColumnStretch(1, 1); 1963 if (!KWindowSystem::isPlatformWayland()) // Wayland doesn't allow positioning of windows 1964 { 1965 grid->setColumnMinimumWidth(0, gridIndentWidth()); 1966 1967 mWindowPosition = new ButtonGroup(group); 1968 connect(mWindowPosition, &ButtonGroup::buttonSet, this, &ViewPrefTab::slotWindowPosChanged); 1969 1970 const QString whatsthis = xi18nc("@info:whatsthis", 1971 "<para>Choose how to reduce the chance of alarm messages being accidentally acknowledged:" 1972 "<list><item>Position alarm message windows as far as possible from the current mouse cursor location, or</item>" 1973 "<item>Position alarm message windows in the center of the screen, but disable buttons for a short time after the window is displayed.</item></list></para>"); 1974 QRadioButton* radio = new QRadioButton(i18nc("@option:radio", "Position windows far from mouse cursor"), group); 1975 mWindowPosition->addButton(radio, 0); 1976 radio->setWhatsThis(whatsthis); 1977 grid->addWidget(radio, 0, 0, 1, 2, Qt::AlignLeft); 1978 radio = new QRadioButton(i18nc("@option:radio", "Center windows, delay activating window buttons"), group); 1979 mWindowPosition->addButton(radio, 1); 1980 radio->setWhatsThis(whatsthis); 1981 grid->addWidget(radio, 1, 0, 1, 2, Qt::AlignLeft); 1982 } 1983 1984 widget = new QWidget; // this is to control the QWhatsThis text display area 1985 box = new QHBoxLayout(widget); 1986 box->setContentsMargins(0, 0, 0, 0); 1987 mWindowButtonDelayLabel = new QLabel(i18nc("@label:spinbox", "Button activation delay (seconds):")); 1988 box->addWidget(mWindowButtonDelayLabel); 1989 mWindowButtonDelay = new QSpinBox(); 1990 mWindowButtonDelay->setRange(1, 10); 1991 mWindowButtonDelayLabel->setBuddy(mWindowButtonDelay); 1992 box->addWidget(mWindowButtonDelay); 1993 if (KWindowSystem::isPlatformWayland()) // Wayland doesn't allow positioning of windows 1994 widget->setWhatsThis(i18nc("@info:whatsthis", 1995 "Enter how long its buttons should remain disabled after the alarm message window is shown, " 1996 "to reduce the chance of alarm messages being accidentally acknowledged.")); 1997 else 1998 widget->setWhatsThis(i18nc("@info:whatsthis", 1999 "Enter how long its buttons should remain disabled after the alarm message window is shown.")); 2000 box->addStretch(); // left adjust the controls 2001 grid->addWidget(widget, 2, 1, Qt::AlignLeft); 2002 2003 if (KWindowSystem::isPlatformX11()) 2004 { 2005 grid->setRowMinimumHeight(3, style()->pixelMetric(QStyle::PM_LayoutVerticalSpacing)); 2006 2007 mModalMessages = new QCheckBox(i18nc("@option:check", "Message windows have a title bar and take keyboard focus"), group); 2008 mModalMessages->setMinimumSize(mModalMessages->sizeHint()); 2009 mModalMessages->setWhatsThis(xi18nc("@info:whatsthis", 2010 "<para>Specify the characteristics of alarm message windows:" 2011 "<list><item>If checked, the window is a normal window with a title bar, which grabs keyboard input when it is displayed.</item>" 2012 "<item>If unchecked, the window does not interfere with your typing when " 2013 "it is displayed, but it has no title bar and cannot be moved or resized.</item></list></para>")); 2014 grid->addWidget(mModalMessages, 4, 0, 1, 2, Qt::AlignLeft); 2015 } 2016 2017 if (topWindows) 2018 topWindows->addStretch(); // top adjust the widgets 2019 } 2020 2021 void ViewPrefTab::restore(bool, bool allTabs) 2022 { 2023 if (allTabs || mTabs->currentIndex() == mTabGeneral) 2024 { 2025 if (mShowInSystemTrayGroup) 2026 mShowInSystemTrayGroup->setChecked(Preferences::showInSystemTray()); 2027 else 2028 mShowInSystemTrayCheck->setChecked(Preferences::showInSystemTray()); 2029 int id; 2030 const int mins = Preferences::autoHideSystemTray(); 2031 switch (mins) 2032 { 2033 case -1: id = 1; break; // hide if no active alarms 2034 case 0: id = 0; break; // never hide 2035 default: 2036 { 2037 id = 2; 2038 int days = 0; 2039 int secs = 0; 2040 if (mins % 1440) 2041 secs = mins * 60; 2042 else 2043 days = mins / 1440; 2044 const TimePeriod::Units units = secs ? TimePeriod::HoursMinutes 2045 : (days % 7) ? TimePeriod::Days : TimePeriod::Weeks; 2046 const Duration duration((secs ? secs : days), (secs ? Duration::Seconds : Duration::Days)); 2047 mAutoHideSystemTrayPeriod->setPeriod(duration, false, units); 2048 break; 2049 } 2050 } 2051 if (mAutoHideSystemTray) 2052 mAutoHideSystemTray->setButton(id); 2053 setTooltip(Preferences::tooltipAlarmCount(), 2054 Preferences::showTooltipAlarmTime(), 2055 Preferences::showTooltipTimeToAlarm(), 2056 Preferences::tooltipTimeToPrefix()); 2057 mDisabledColour->setColor(Preferences::disabledColour()); 2058 mArchivedColour->setColor(Preferences::archivedColour()); 2059 } 2060 if (allTabs || mTabs->currentIndex() == mTabWindows) 2061 { 2062 if (mWindowPosition) 2063 mWindowPosition->setButton(Preferences::messageButtonDelay() ? 1 : 0); 2064 mWindowButtonDelay->setValue(Preferences::messageButtonDelay()); 2065 if (mModalMessages) 2066 mModalMessages->setChecked(Preferences::modalMessages()); 2067 } 2068 } 2069 2070 bool ViewPrefTab::apply(bool syncToDisc) 2071 { 2072 QColor colour = mDisabledColour->color(); 2073 if (colour != Preferences::disabledColour()) 2074 Preferences::setDisabledColour(colour); 2075 colour = mArchivedColour->color(); 2076 if (colour != Preferences::archivedColour()) 2077 Preferences::setArchivedColour(colour); 2078 int n = mTooltipShowAlarms->isChecked() ? -1 : 0; 2079 if (n && mTooltipMaxAlarms->isChecked()) 2080 n = mTooltipMaxAlarmCount->value(); 2081 if (n != Preferences::tooltipAlarmCount()) 2082 Preferences::setTooltipAlarmCount(n); 2083 bool b = mTooltipShowTime->isChecked(); 2084 if (b != Preferences::showTooltipAlarmTime()) 2085 Preferences::setShowTooltipAlarmTime(b); 2086 b = mTooltipShowTimeTo->isChecked(); 2087 if (b != Preferences::showTooltipTimeToAlarm()) 2088 Preferences::setShowTooltipTimeToAlarm(b); 2089 QString text = mTooltipTimeToPrefix->text(); 2090 if (text != Preferences::tooltipTimeToPrefix()) 2091 Preferences::setTooltipTimeToPrefix(text); 2092 b = mShowInSystemTrayGroup ? mShowInSystemTrayGroup->isChecked() : mShowInSystemTrayCheck->isChecked(); 2093 if (b != Preferences::showInSystemTray()) 2094 Preferences::setShowInSystemTray(b); 2095 if (b && mAutoHideSystemTray) 2096 { 2097 switch (mAutoHideSystemTray->selectedId()) 2098 { 2099 case 0: n = 0; break; // never hide 2100 case 1: n = -1; break; // hide if no active alarms 2101 case 2: // hide if no alarms due within period 2102 n = mAutoHideSystemTrayPeriod->period().asSeconds() / 60; 2103 break; 2104 } 2105 if (n != Preferences::autoHideSystemTray()) 2106 Preferences::setAutoHideSystemTray(n); 2107 } 2108 n = mWindowPosition ? mWindowPosition->selectedId() : 1; 2109 if (n) 2110 n = mWindowButtonDelay->value(); 2111 if (n != Preferences::messageButtonDelay()) 2112 Preferences::setMessageButtonDelay(n); 2113 if (mModalMessages) 2114 { 2115 b = mModalMessages->isChecked(); 2116 if (b != Preferences::modalMessages()) 2117 Preferences::setModalMessages(b); 2118 } 2119 return PrefsTabBase::apply(syncToDisc); 2120 } 2121 2122 void ViewPrefTab::setTooltip(int maxAlarms, bool time, bool timeTo, const QString& prefix) 2123 { 2124 if (!timeTo) 2125 time = true; // ensure that at least one time option is ticked 2126 2127 // Set the states of the controls without calling signal 2128 // handlers, since these could change the checkboxes' states. 2129 mTooltipShowAlarms->blockSignals(true); 2130 mTooltipShowTime->blockSignals(true); 2131 mTooltipShowTimeTo->blockSignals(true); 2132 2133 mTooltipShowAlarms->setChecked(maxAlarms); 2134 mTooltipMaxAlarms->setChecked(maxAlarms > 0); 2135 mTooltipMaxAlarmCount->setValue(maxAlarms > 0 ? maxAlarms : 1); 2136 mTooltipShowTime->setChecked(time); 2137 mTooltipShowTimeTo->setChecked(timeTo); 2138 mTooltipTimeToPrefix->setText(prefix); 2139 2140 mTooltipShowAlarms->blockSignals(false); 2141 mTooltipShowTime->blockSignals(false); 2142 mTooltipShowTimeTo->blockSignals(false); 2143 2144 // Enable/disable controls according to their states 2145 slotTooltipTimeToToggled(timeTo); 2146 slotTooltipAlarmsToggled(maxAlarms); 2147 } 2148 2149 void ViewPrefTab::slotTooltipAlarmsToggled(bool on) 2150 { 2151 mTooltipMaxAlarms->setEnabled(on); 2152 mTooltipMaxAlarmCount->setEnabled(on && mTooltipMaxAlarms->isChecked()); 2153 mTooltipShowTime->setEnabled(on); 2154 mTooltipShowTimeTo->setEnabled(on); 2155 on = on && mTooltipShowTimeTo->isChecked(); 2156 mTooltipTimeToPrefix->setEnabled(on); 2157 mTooltipTimeToPrefixLabel->setEnabled(on); 2158 } 2159 2160 void ViewPrefTab::slotTooltipMaxToggled(bool on) 2161 { 2162 mTooltipMaxAlarmCount->setEnabled(on && mTooltipMaxAlarms->isEnabled()); 2163 } 2164 2165 void ViewPrefTab::slotTooltipTimeToggled(bool on) 2166 { 2167 if (!on && !mTooltipShowTimeTo->isChecked()) 2168 mTooltipShowTimeTo->setChecked(true); 2169 } 2170 2171 void ViewPrefTab::slotTooltipTimeToToggled(bool on) 2172 { 2173 if (!on && !mTooltipShowTime->isChecked()) 2174 mTooltipShowTime->setChecked(true); 2175 on = on && mTooltipShowTimeTo->isEnabled(); 2176 mTooltipTimeToPrefix->setEnabled(on); 2177 mTooltipTimeToPrefixLabel->setEnabled(on); 2178 } 2179 2180 void ViewPrefTab::slotAutoHideSysTrayChanged(QAbstractButton* button) 2181 { 2182 if (mAutoHideSystemTray) 2183 mAutoHideSystemTrayPeriod->setEnabled(mAutoHideSystemTray->id(button) == 2); 2184 } 2185 2186 void ViewPrefTab::slotWindowPosChanged(QAbstractButton* button) 2187 { 2188 const bool enable = mWindowPosition ? mWindowPosition->id(button) : true; 2189 mWindowButtonDelay->setEnabled(enable); 2190 mWindowButtonDelayLabel->setEnabled(enable); 2191 } 2192 2193 #include "moc_prefdlg_p.cpp" 2194 #include "moc_prefdlg.cpp" 2195 2196 // vim: et sw=4: