File indexing completed on 2024-05-12 05:14:58
0001 /* 0002 * specialactions.cpp - widget to specify special alarm actions 0003 * Program: kalarm 0004 * SPDX-FileCopyrightText: 2004-2021 David Jarvie <djarvie@kde.org> 0005 * 0006 * SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 0009 #include "specialactions.h" 0010 0011 #include "lib/autoqpointer.h" 0012 #include "lib/checkbox.h" 0013 #include "lib/config.h" 0014 0015 #include <KLocalizedString> 0016 0017 #include <QLabel> 0018 #include <QGroupBox> 0019 #include <QHBoxLayout> 0020 #include <QVBoxLayout> 0021 #include <QResizeEvent> 0022 #include <QDialogButtonBox> 0023 #include <QLineEdit> 0024 0025 0026 /*============================================================================= 0027 = Class SpecialActionsButton 0028 = Button to display the Special Alarm Actions dialog. 0029 =============================================================================*/ 0030 0031 SpecialActionsButton::SpecialActionsButton(bool enableCheckboxes, QWidget* parent) 0032 : QPushButton(i18nc("@action:button", "Special Actions..."), parent) 0033 , mOptions{} 0034 , mEnableCheckboxes(enableCheckboxes) 0035 { 0036 setCheckable(true); 0037 setChecked(false); 0038 connect(this, &SpecialActionsButton::clicked, this, &SpecialActionsButton::slotButtonPressed); 0039 setToolTip(i18nc("@info:tooltip", "Set commands to execute")); 0040 setWhatsThis(i18nc("@info:whatsthis", "Specify actions to execute before and after the alarm is displayed.")); 0041 } 0042 0043 /****************************************************************************** 0044 * Set the pre- and post-alarm actions. 0045 * The button's pressed state is set to reflect whether any actions are set. 0046 */ 0047 void SpecialActionsButton::setActions(const QString& pre, const QString& post, KAEvent::ExtraActionOptions options) 0048 { 0049 mPreAction = pre; 0050 mPostAction = post; 0051 mOptions = options; 0052 setChecked(!mPreAction.isEmpty() || !mPostAction.isEmpty()); 0053 } 0054 0055 /****************************************************************************** 0056 * Called when the OK button is clicked. 0057 * Display a font and colour selection dialog and get the selections. 0058 */ 0059 void SpecialActionsButton::slotButtonPressed() 0060 { 0061 // Use AutoQPointer to guard against crash on application exit while 0062 // the dialogue is still open. It prevents double deletion (both on 0063 // deletion of SpecialActionsButton, and on return from this function). 0064 AutoQPointer<SpecialActionsDlg> dlg = new SpecialActionsDlg(mPreAction, mPostAction, mOptions, mEnableCheckboxes, this); 0065 dlg->setReadOnly(mReadOnly); 0066 if (dlg->exec() == QDialog::Accepted) 0067 { 0068 mPreAction = dlg->preAction(); 0069 mPostAction = dlg->postAction(); 0070 mOptions = dlg->options(); 0071 Q_EMIT selected(); 0072 } 0073 if (dlg) 0074 setChecked(!mPreAction.isEmpty() || !mPostAction.isEmpty()); 0075 } 0076 0077 0078 /*============================================================================= 0079 = Class SpecialActionsDlg 0080 = Pre- and post-alarm actions dialog. 0081 =============================================================================*/ 0082 0083 static const char SPEC_ACT_DIALOG_NAME[] = "SpecialActionsDialog"; 0084 0085 0086 SpecialActionsDlg::SpecialActionsDlg(const QString& preAction, const QString& postAction, 0087 KAEvent::ExtraActionOptions options, bool enableCheckboxes, 0088 QWidget* parent) 0089 : QDialog(parent) 0090 { 0091 setWindowTitle(i18nc("@title:window", "Special Alarm Actions")); 0092 auto mainLayout = new QVBoxLayout; 0093 setLayout(mainLayout); 0094 0095 QWidget* page = new QWidget(this); 0096 mainLayout->addWidget(page); 0097 auto layout = new QVBoxLayout(page); 0098 layout->setContentsMargins(0, 0, 0, 0); 0099 0100 mActions = new SpecialActions(enableCheckboxes, page); 0101 layout->addWidget(mActions); 0102 mActions->setActions(preAction, postAction, options); 0103 0104 QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); 0105 mainLayout->addWidget(buttonBox); 0106 QPushButton* okButton = buttonBox->button(QDialogButtonBox::Ok); 0107 okButton->setDefault(true); 0108 okButton->setShortcut(Qt::CTRL | Qt::Key_Return); 0109 connect(buttonBox, &QDialogButtonBox::rejected, this, &SpecialActionsDlg::reject); 0110 connect(okButton, &QPushButton::clicked, this, &SpecialActionsDlg::slotOk); 0111 0112 QSize s; 0113 if (Config::readWindowSize(SPEC_ACT_DIALOG_NAME, s)) 0114 resize(s); 0115 } 0116 0117 /****************************************************************************** 0118 * Called when the OK button is clicked. 0119 */ 0120 void SpecialActionsDlg::slotOk() 0121 { 0122 if (mActions->isReadOnly()) 0123 reject(); 0124 accept(); 0125 } 0126 0127 /****************************************************************************** 0128 * Called when the dialog's size has changed. 0129 * Records the new size in the config file. 0130 */ 0131 void SpecialActionsDlg::resizeEvent(QResizeEvent* re) 0132 { 0133 if (isVisible()) 0134 Config::writeWindowSize(SPEC_ACT_DIALOG_NAME, re->size()); 0135 QDialog::resizeEvent(re); 0136 } 0137 0138 0139 /*============================================================================= 0140 = Class SpecialActions 0141 = Pre- and post-alarm actions widget. 0142 =============================================================================*/ 0143 0144 SpecialActions::SpecialActions(bool enableCheckboxes, QWidget* parent) 0145 : QWidget(parent) 0146 , mEnableCheckboxes(enableCheckboxes) 0147 { 0148 auto topLayout = new QVBoxLayout(this); 0149 topLayout->setContentsMargins(0, 0, 0, 0); 0150 0151 // Pre-alarm action 0152 QGroupBox* group = new QGroupBox(i18nc("@title:group", "Pre-Alarm Action"), this); 0153 topLayout->addWidget(group); 0154 auto vlayout = new QVBoxLayout(group); 0155 0156 QWidget* box = new QWidget(group); // this is to control the QWhatsThis text display area 0157 vlayout->addWidget(box); 0158 auto boxLayout = new QHBoxLayout(box); 0159 boxLayout->setContentsMargins(0, 0, 0, 0); 0160 QLabel* label = new QLabel(i18nc("@label:textbox", "Command:"), box); 0161 boxLayout->addWidget(label); 0162 mPreAction = new QLineEdit(box); 0163 boxLayout->addWidget(mPreAction); 0164 label->setBuddy(mPreAction); 0165 connect(mPreAction, &QLineEdit::textChanged, this, &SpecialActions::slotPreActionChanged); 0166 box->setWhatsThis(xi18nc("@info:whatsthis", 0167 "<para>Enter a shell command to execute before the alarm is displayed.</para>" 0168 "<para>Note that it is executed only when the alarm proper is displayed, not when a reminder or deferred alarm is displayed.</para>" 0169 "<para><note>KAlarm will wait for the command to complete before displaying the alarm.</note></para>")); 0170 boxLayout->setStretchFactor(mPreAction, 1); 0171 0172 // Cancel if error in pre-alarm action 0173 mExecOnDeferral = new CheckBox(i18nc("@option:check", "Execute for deferred alarms"), group); 0174 mExecOnDeferral->setWhatsThis(xi18nc("@info:whatsthis", "<para>If unchecked, the command is only executed before the alarm proper is displayed.</para>" 0175 "<para>If checked, the pre-alarm command is also executed before a deferred alarm is displayed.</para>")); 0176 vlayout->addWidget(mExecOnDeferral, 0, Qt::AlignLeft); 0177 0178 mCancelOnError = new CheckBox(i18nc("@option:check", "Cancel alarm on error"), group); 0179 mCancelOnError->setWhatsThis(i18nc("@info:whatsthis", "Cancel the alarm if the pre-alarm command fails, i.e. do not display the alarm or execute any post-alarm action command.")); 0180 vlayout->addWidget(mCancelOnError, 0, Qt::AlignLeft); 0181 0182 mDontShowError = new CheckBox(i18nc("@option:check", "Do not notify errors"), group); 0183 mDontShowError->setWhatsThis(i18nc("@info:whatsthis", "Do not show error status or error message if the pre-alarm command fails.")); 0184 vlayout->addWidget(mDontShowError, 0, Qt::AlignLeft); 0185 0186 // Post-alarm action 0187 group = new QGroupBox(i18nc("@title:group", "Post-Alarm Action"), this); 0188 topLayout->addWidget(group); 0189 vlayout = new QVBoxLayout(group); 0190 0191 box = new QWidget(group); // this is to control the QWhatsThis text display area 0192 vlayout->addWidget(box); 0193 boxLayout = new QHBoxLayout(box); 0194 boxLayout->setContentsMargins(0, 0, 0, 0); 0195 label = new QLabel(i18nc("@label:textbox", "Command:"), box); 0196 boxLayout->addWidget(label); 0197 mPostAction = new QLineEdit(box); 0198 boxLayout->addWidget(mPostAction); 0199 label->setBuddy(mPostAction); 0200 box->setWhatsThis(xi18nc("@info:whatsthis", 0201 "<para>Enter a shell command to execute after the alarm window is closed.</para>" 0202 "<para>Note that it is not executed after closing a reminder window. If you defer " 0203 "the alarm, it is not executed until the alarm is finally acknowledged or closed.</para>")); 0204 boxLayout->setStretchFactor(mPostAction, 1); 0205 0206 mExecOnDeferral->setEnabled(enableCheckboxes); 0207 mCancelOnError->setEnabled(enableCheckboxes); 0208 mDontShowError->setEnabled(enableCheckboxes); 0209 } 0210 0211 void SpecialActions::setActions(const QString& pre, const QString& post, KAEvent::ExtraActionOptions options) 0212 { 0213 mPreAction->setText(pre); 0214 mPostAction->setText(post); 0215 mExecOnDeferral->setChecked(options & KAEvent::ExecPreActOnDeferral); 0216 mCancelOnError->setChecked(options & KAEvent::CancelOnPreActError); 0217 mDontShowError->setChecked(options & KAEvent::DontShowPreActError); 0218 } 0219 0220 QString SpecialActions::preAction() const 0221 { 0222 return mPreAction->text(); 0223 } 0224 0225 QString SpecialActions::postAction() const 0226 { 0227 return mPostAction->text(); 0228 } 0229 0230 KAEvent::ExtraActionOptions SpecialActions::options() const 0231 { 0232 KAEvent::ExtraActionOptions opts = {}; 0233 if (mExecOnDeferral->isChecked()) opts |= KAEvent::ExecPreActOnDeferral; 0234 if (mCancelOnError->isChecked()) opts |= KAEvent::CancelOnPreActError; 0235 if (mDontShowError->isChecked()) opts |= KAEvent::DontShowPreActError; 0236 return opts; 0237 } 0238 0239 void SpecialActions::setReadOnly(bool ro) 0240 { 0241 mReadOnly = ro; 0242 mPreAction->setReadOnly(mReadOnly); 0243 mPostAction->setReadOnly(mReadOnly); 0244 mExecOnDeferral->setReadOnly(mReadOnly); 0245 mCancelOnError->setReadOnly(mReadOnly); 0246 mDontShowError->setReadOnly(mReadOnly); 0247 } 0248 0249 void SpecialActions::slotPreActionChanged(const QString& text) 0250 { 0251 if (!mEnableCheckboxes) 0252 { 0253 bool textValid = !text.isEmpty(); 0254 mExecOnDeferral->setEnabled(textValid); 0255 mCancelOnError->setEnabled(textValid); 0256 mDontShowError->setEnabled(textValid); 0257 } 0258 } 0259 0260 #include "moc_specialactions.cpp" 0261 0262 // vim: et sw=4: