File indexing completed on 2024-06-23 05:14:04
0001 /* -*- mode: c++; c-basic-offset:4 -*- 0002 dialogs/expirydialog.cpp 0003 0004 This file is part of Kleopatra, the KDE keymanager 0005 SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB 0006 SPDX-FileCopyrightText: 2021 g10 Code GmbH 0007 SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de> 0008 0009 SPDX-License-Identifier: GPL-2.0-or-later 0010 */ 0011 0012 #include <config-kleopatra.h> 0013 0014 #include "expirydialog.h" 0015 0016 #include "utils/accessibility.h" 0017 #include "utils/expiration.h" 0018 #include "utils/gui-helper.h" 0019 0020 #include <Libkleo/Formatting> 0021 0022 #include <KDateComboBox> 0023 #include <KLocalizedString> 0024 #include <KMessageBox> 0025 #include <KStandardGuiItem> 0026 0027 #include <QCheckBox> 0028 #include <QDate> 0029 #include <QDialogButtonBox> 0030 #include <QHBoxLayout> 0031 #include <QLabel> 0032 #include <QPushButton> 0033 #include <QRadioButton> 0034 #include <QVBoxLayout> 0035 0036 using namespace Kleo; 0037 using namespace Kleo::Dialogs; 0038 0039 class ExpiryDialog::Private 0040 { 0041 friend class ::Kleo::Dialogs::ExpiryDialog; 0042 ExpiryDialog *const q; 0043 0044 public: 0045 Private(Mode mode, ExpiryDialog *qq) 0046 : q{qq} 0047 , ui{mode, qq} 0048 { 0049 ui.neverRB->setEnabled(unlimitedValidityAllowed()); 0050 ui.onRB->setEnabled(!fixedExpirationDate()); 0051 0052 connect(ui.onCB, &KDateComboBox::dateChanged, q, [this]() { 0053 slotOnDateChanged(); 0054 }); 0055 } 0056 0057 private: 0058 void slotOnDateChanged(); 0059 0060 private: 0061 bool unlimitedValidityAllowed() const; 0062 bool fixedExpirationDate() const; 0063 void setInitialFocus(); 0064 0065 private: 0066 bool initialFocusWasSet = false; 0067 0068 struct UI { 0069 QRadioButton *neverRB; 0070 QRadioButton *onRB; 0071 KDateComboBox *onCB; 0072 QCheckBox *updateSubkeysCheckBox; 0073 QLabel *primaryKeyExpirationDate; 0074 LabelHelper labelHelper; 0075 0076 explicit UI(Mode mode, Dialogs::ExpiryDialog *qq) 0077 { 0078 auto mainLayout = new QVBoxLayout{qq}; 0079 0080 auto mainWidget = new QWidget{qq}; 0081 0082 auto vboxLayout = new QVBoxLayout{mainWidget}; 0083 vboxLayout->setContentsMargins(0, 0, 0, 0); 0084 0085 { 0086 auto label = new QLabel{qq}; 0087 label->setText(mode == Mode::UpdateIndividualSubkey ? i18n("Please select until when the subkey should be valid:") 0088 : i18n("Please select until when the certificate should be valid:")); 0089 vboxLayout->addWidget(label); 0090 } 0091 0092 neverRB = new QRadioButton(i18n("Unlimited validity"), mainWidget); 0093 neverRB->setChecked(false); 0094 0095 vboxLayout->addWidget(neverRB); 0096 0097 { 0098 auto hboxLayout = new QHBoxLayout; 0099 0100 onRB = new QRadioButton{i18n("Valid until:"), mainWidget}; 0101 onRB->setChecked(true); 0102 0103 hboxLayout->addWidget(onRB); 0104 0105 onCB = new KDateComboBox{mainWidget}; 0106 setUpExpirationDateComboBox(onCB); 0107 0108 hboxLayout->addWidget(onCB); 0109 0110 hboxLayout->addStretch(1); 0111 0112 vboxLayout->addLayout(hboxLayout); 0113 } 0114 0115 primaryKeyExpirationDate = new QLabel(qq); 0116 primaryKeyExpirationDate->setVisible(false); 0117 vboxLayout->addWidget(primaryKeyExpirationDate); 0118 labelHelper.addLabel(primaryKeyExpirationDate); 0119 0120 { 0121 updateSubkeysCheckBox = new QCheckBox{i18n("Also update the validity period of the subkeys"), qq}; 0122 updateSubkeysCheckBox->setVisible(mode == Mode::UpdateCertificateWithSubkeys); 0123 vboxLayout->addWidget(updateSubkeysCheckBox); 0124 } 0125 0126 vboxLayout->addStretch(1); 0127 0128 mainLayout->addWidget(mainWidget); 0129 0130 auto buttonBox = new QDialogButtonBox{QDialogButtonBox::Ok | QDialogButtonBox::Cancel, qq}; 0131 auto okButton = buttonBox->button(QDialogButtonBox::Ok); 0132 KGuiItem::assign(okButton, KStandardGuiItem::ok()); 0133 okButton->setDefault(true); 0134 okButton->setShortcut(static_cast<int>(Qt::CTRL) | static_cast<int>(Qt::Key_Return)); 0135 KGuiItem::assign(buttonBox->button(QDialogButtonBox::Cancel), KStandardGuiItem::cancel()); 0136 qq->connect(buttonBox, &QDialogButtonBox::accepted, qq, &ExpiryDialog::accept); 0137 qq->connect(buttonBox, &QDialogButtonBox::rejected, qq, &QDialog::reject); 0138 0139 mainLayout->addWidget(buttonBox); 0140 0141 connect(onRB, &QRadioButton::toggled, onCB, &QWidget::setEnabled); 0142 } 0143 } ui; 0144 }; 0145 0146 void ExpiryDialog::Private::slotOnDateChanged() 0147 { 0148 ui.onRB->setAccessibleName(i18nc("Valid until DATE", "Valid until %1", Formatting::accessibleDate(ui.onCB->date()))); 0149 } 0150 0151 bool Kleo::Dialogs::ExpiryDialog::Private::unlimitedValidityAllowed() const 0152 { 0153 return !Kleo::maximumExpirationDate().isValid(); 0154 } 0155 0156 bool Kleo::Dialogs::ExpiryDialog::Private::fixedExpirationDate() const 0157 { 0158 return ui.onCB->minimumDate() == ui.onCB->maximumDate(); 0159 } 0160 0161 void ExpiryDialog::Private::setInitialFocus() 0162 { 0163 if (initialFocusWasSet) { 0164 return; 0165 } 0166 // give focus to the checked radio button 0167 (void)focusFirstCheckedButton({ui.neverRB, ui.onRB}); 0168 initialFocusWasSet = true; 0169 } 0170 0171 ExpiryDialog::ExpiryDialog(Mode mode, QWidget *p) 0172 : QDialog{p} 0173 , d{new Private{mode, this}} 0174 { 0175 setWindowTitle(i18nc("@title:window", "Change Validity Period")); 0176 } 0177 0178 ExpiryDialog::~ExpiryDialog() = default; 0179 0180 void ExpiryDialog::setDateOfExpiry(const QDate &date) 0181 { 0182 const QDate current = QDate::currentDate(); 0183 if (date.isValid()) { 0184 d->ui.onRB->setChecked(true); 0185 if (date <= current) { 0186 d->ui.onCB->setDate(defaultExpirationDate(ExpirationOnUnlimitedValidity::InternalDefaultExpiration)); 0187 } else { 0188 d->ui.onCB->setDate(date); 0189 } 0190 } else { 0191 if (d->unlimitedValidityAllowed()) { 0192 d->ui.neverRB->setChecked(true); 0193 } else { 0194 d->ui.onRB->setChecked(true); 0195 } 0196 d->ui.onCB->setDate(defaultExpirationDate(ExpirationOnUnlimitedValidity::InternalDefaultExpiration)); 0197 } 0198 } 0199 0200 QDate ExpiryDialog::dateOfExpiry() const 0201 { 0202 return d->ui.onRB->isChecked() ? d->ui.onCB->date() : QDate{}; 0203 } 0204 0205 void ExpiryDialog::setUpdateExpirationOfAllSubkeys(bool update) 0206 { 0207 d->ui.updateSubkeysCheckBox->setChecked(update); 0208 } 0209 0210 bool ExpiryDialog::updateExpirationOfAllSubkeys() const 0211 { 0212 return d->ui.updateSubkeysCheckBox->isChecked(); 0213 } 0214 0215 void ExpiryDialog::accept() 0216 { 0217 const auto date = dateOfExpiry(); 0218 if (!Kleo::isValidExpirationDate(date)) { 0219 KMessageBox::error(this, i18nc("@info", "Error: %1", Kleo::validityPeriodHint())); 0220 return; 0221 } 0222 0223 QDialog::accept(); 0224 } 0225 0226 void ExpiryDialog::showEvent(QShowEvent *event) 0227 { 0228 d->setInitialFocus(); 0229 QDialog::showEvent(event); 0230 } 0231 0232 void ExpiryDialog::setPrimaryKey(const GpgME::Key &key) 0233 { 0234 if (!key.subkey(0).neverExpires()) { 0235 d->ui.primaryKeyExpirationDate->setText(i18n("Expiration of primary key: %1", Kleo::Formatting::expirationDateString(key))); 0236 d->ui.onCB->setMaximumDate(Kleo::Formatting::expirationDate(key)); 0237 d->ui.primaryKeyExpirationDate->setVisible(true); 0238 } 0239 } 0240 0241 #include "moc_expirydialog.cpp"