diff --git a/src/conf/appearanceconfigwidget.cpp b/src/conf/appearanceconfigwidget.cpp index c17213b83..b2050dd3a 100644 --- a/src/conf/appearanceconfigwidget.cpp +++ b/src/conf/appearanceconfigwidget.cpp @@ -1,927 +1,927 @@ /* appearanceconfigwidget.cpp This file is part of kleopatra, the KDE key manager SPDX-FileCopyrightText: 2002, 2004, 2008 Klarälvdalens Datakonsult AB SPDX-FileCopyrightText: 2002, 2003 Marc Mutz SPDX-License-Identifier: GPL-2.0-or-later */ #include #include "appearanceconfigwidget.h" #include "pluralhandlingspinbox.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Kleo; using namespace Kleo::Config; enum { HasNameRole = Qt::UserRole + 0x1234, /*!< Records that the user has assigned a name (to avoid comparing with i18n-strings) */ HasFontRole, /*!< Records that the user has chosen completely different font (as opposed to italic/bold/strikeout) */ IconNameRole, /*!< Records the name of the icon (since QIcon won't give it out again, once set) */ MayChangeNameRole, MayChangeForegroundRole, MayChangeBackgroundRole, MayChangeFontRole, MayChangeItalicRole, MayChangeBoldRole, MayChangeStrikeOutRole, MayChangeIconRole, StoredForegroundRole, /*!< Stores the actual configured foreground color */ StoredBackgroundRole, /*!< Stores the actual configured background color */ EndDummy, }; static QFont tryToFindFontFor(const QListWidgetItem *item) { if (item) if (const QListWidget *const lw = item->listWidget()) { return lw->font(); } return QApplication::font("QListWidget"); } static bool is(const QListWidgetItem *item, bool (QFont::*func)() const) { if (!item) { return false; } const QVariant v = item->data(Qt::FontRole); #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) if (!v.isValid() || v.type() != QVariant::Font) { #else if (!v.isValid() || v.userType() != QMetaType::QFont) { #endif return false; } return (v.value().*func)(); } static bool is_italic(const QListWidgetItem *item) { return is(item, &QFont::italic); } static bool is_bold(const QListWidgetItem *item) { return is(item, &QFont::bold); } static bool is_strikeout(const QListWidgetItem *item) { return is(item, &QFont::strikeOut); } static void set(QListWidgetItem *item, bool on, void (QFont::*func)(bool)) { if (!item) { return; } const QVariant v = item->data(Qt::FontRole); #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) QFont font = v.isValid() && v.type() == QVariant::Font ? v.value() : tryToFindFontFor(item); #else QFont font = v.isValid() && v.userType() == QMetaType::QFont ? v.value() : tryToFindFontFor(item); #endif (font.*func)(on); item->setData(Qt::FontRole, font); } static void set_italic(QListWidgetItem *item, bool on) { set(item, on, &QFont::setItalic); } static void set_bold(QListWidgetItem *item, bool on) { set(item, on, &QFont::setBold); } static void set_strikeout(QListWidgetItem *item, bool on) { set(item, on, &QFont::setStrikeOut); } static void apply_config(const KConfigGroup &group, QListWidgetItem *item) { if (!item) { return; } const QString name = group.readEntry("Name"); item->setText(name.isEmpty() ? i18nc("Key filter without user-assigned name", "") : name); item->setData(HasNameRole, !name.isEmpty()); item->setData(MayChangeNameRole, !group.isEntryImmutable("Name")); const QColor fg = group.readEntry("foreground-color", QColor()); item->setData(StoredForegroundRole, fg.isValid() ? QBrush(fg) : QVariant()); if (!SystemInfo::isHighContrastModeActive()) { item->setData(Qt::ForegroundRole, fg.isValid() ? QBrush(fg) : QVariant()); } item->setData(MayChangeForegroundRole, !group.isEntryImmutable("foreground-color")); const QColor bg = group.readEntry("background-color", QColor()); item->setData(StoredBackgroundRole, bg.isValid() ? QBrush(bg) : QVariant()); if (!SystemInfo::isHighContrastModeActive()) { item->setData(Qt::BackgroundRole, bg.isValid() ? QBrush(bg) : QVariant()); } item->setData(MayChangeBackgroundRole, !group.isEntryImmutable("background-color")); const QFont defaultFont = tryToFindFontFor(item); if (group.hasKey("font")) { const QFont font = group.readEntry("font", defaultFont); item->setData(Qt::FontRole, font != defaultFont ? font : QVariant()); item->setData(HasFontRole, font != defaultFont); } else { QFont font = defaultFont; font.setStrikeOut(group.readEntry("font-strikeout", false)); font.setItalic(group.readEntry("font-italic", false)); font.setBold(group.readEntry("font-bold", false)); item->setData(Qt::FontRole, font); item->setData(HasFontRole, false); } item->setData(MayChangeFontRole, !group.isEntryImmutable("font")); item->setData(MayChangeItalicRole, !group.isEntryImmutable("font-italic")); item->setData(MayChangeBoldRole, !group.isEntryImmutable("font-bold")); item->setData(MayChangeStrikeOutRole, !group.isEntryImmutable("font-strikeout")); const QString iconName = group.readEntry("icon"); item->setData(Qt::DecorationRole, iconName.isEmpty() ? QVariant() : QIcon::fromTheme(iconName)); item->setData(IconNameRole, iconName.isEmpty() ? QVariant() : iconName); item->setData(MayChangeIconRole, !group.isEntryImmutable("icon")); } static void erase_if_allowed(QListWidgetItem *item, int role, int allowRole) { if (item && item->data(allowRole).toBool()) { item->setData(role, QVariant()); } } #if 0 static void erase_if_allowed(QListWidgetItem *item, const int role[], size_t numRoles, int allowRole) { if (item && item->data(allowRole).toBool()) for (unsigned int i = 0; i < numRoles; ++i) { item->setData(role[i], QVariant()); } } static void erase_if_allowed(QListWidgetItem *item, int role, const int allowRole[], size_t numAllowRoles) { if (!item) { return; } for (unsigned int i = 0; i < numAllowRoles; ++i) if (!item->data(allowRole[i]).toBool()) { return; } item->setData(role, QVariant()); } #endif static void erase_if_allowed(QListWidgetItem *item, const int role[], size_t numRoles, const int allowRole[], size_t numAllowRoles) { if (!item) { return; } for (unsigned int i = 0; i < numAllowRoles; ++i) if (!item->data(allowRole[i]).toBool()) { return; } for (unsigned int i = 0; i < numRoles; ++i) { item->setData(role[i], QVariant()); } } static void set_default_appearance(QListWidgetItem *item) { if (!item) { return; } erase_if_allowed(item, StoredForegroundRole, MayChangeForegroundRole); erase_if_allowed(item, Qt::ForegroundRole, MayChangeForegroundRole); erase_if_allowed(item, StoredBackgroundRole, MayChangeBackgroundRole); erase_if_allowed(item, Qt::BackgroundRole, MayChangeBackgroundRole); erase_if_allowed(item, Qt::DecorationRole, MayChangeIconRole); static const int fontRoles[] = { Qt::FontRole, HasFontRole }; static const int fontAllowRoles[] = { MayChangeFontRole, MayChangeItalicRole, MayChangeBoldRole, MayChangeStrikeOutRole, }; erase_if_allowed(item, fontRoles, sizeof(fontRoles) / sizeof(int), fontAllowRoles, sizeof(fontAllowRoles) / sizeof(int)); } static void writeOrDelete(KConfigGroup &group, const char *key, const QVariant &value) { if (value.isValid()) { group.writeEntry(key, value); } else { group.deleteEntry(key); } } static QVariant brush2color(const QVariant &v) { if (v.isValid()) { #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) if (v.type() == QVariant::Color) { #else if (v.userType() == QMetaType::QColor) { #endif return v; #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) } else if (v.type() == QVariant::Brush) { #else } else if (v.userType() == QMetaType::QBrush) { #endif return v.value().color(); } } return QVariant(); } static void save_to_config(const QListWidgetItem *item, KConfigGroup &group) { if (!item) { return; } writeOrDelete(group, "Name", item->data(HasNameRole).toBool() ? item->text() : QVariant()); writeOrDelete(group, "foreground-color", brush2color(item->data(StoredForegroundRole))); writeOrDelete(group, "background-color", brush2color(item->data(StoredBackgroundRole))); writeOrDelete(group, "icon", item->data(IconNameRole)); group.deleteEntry("font"); group.deleteEntry("font-strikeout"); group.deleteEntry("font-italic"); group.deleteEntry("font-bold"); if (item->data(HasFontRole).toBool()) { writeOrDelete(group, "font", item->data(Qt::FontRole)); return; } if (is_strikeout(item)) { group.writeEntry("font-strikeout", true); } if (is_italic(item)) { group.writeEntry("font-italic", true); } if (is_bold(item)) { group.writeEntry("font-bold", true); } } static void kiosk_enable(QWidget *w, const QListWidgetItem *item, int allowRole) { if (!w) { return; } if (item && !item->data(allowRole).toBool()) { w->setEnabled(false); w->setToolTip(i18n("This parameter has been locked down by the system administrator.")); } else { w->setEnabled(item); w->setToolTip(QString()); } } class Ui_AppearanceConfigWidget { public: QTabWidget *tabWidget; KMessageWidget *highContrastMsg; QListWidget *categoriesLV; QPushButton *iconButton; QPushButton *foregroundButton; QPushButton *backgroundButton; QPushButton *fontButton; QCheckBox *italicCB; QCheckBox *boldCB; QCheckBox *strikeoutCB; QPushButton *defaultLookPB; QCheckBox *tooltipValidityCheckBox; QCheckBox *tooltipOwnerCheckBox; QCheckBox *tooltipDetailsCheckBox; QCheckBox *useTagsCheckBox; QCheckBox *showExpirationCheckBox; PluralHandlingSpinBox *ownCertificateThresholdSpinBox; PluralHandlingSpinBox *otherCertificateThresholdSpinBox; void setupUi(QWidget *parent) { if (parent->objectName().isEmpty()) parent->setObjectName(QString::fromUtf8("AppearanceConfigWidget")); auto mainLayout = new QVBoxLayout{parent}; tabWidget = new QTabWidget(parent); tabWidget->setObjectName(QString::fromUtf8("tabWidget")); { auto tab = new QWidget{parent}; auto tabLayout = new QVBoxLayout{tab}; useTagsCheckBox = new QCheckBox{i18nc("@option:check", "Show tags attached to certificates"), tab}; useTagsCheckBox->setToolTip(i18nc("@info:tooltip", "Enable display and usage of tags attached to certificates.")); tabLayout->addWidget(useTagsCheckBox); tabLayout->addWidget(new KSeparator{tab}); auto label = new QLabel{tab}; label->setText(i18nc("@info", "Show the following information in certificate list tooltips:")); tabLayout->addWidget(label); tooltipValidityCheckBox = new QCheckBox{i18nc("@option:check", "Show validity"), tab}; tabLayout->addWidget(tooltipValidityCheckBox); tooltipOwnerCheckBox = new QCheckBox{i18nc("@option:check", "Show owner information"), tab}; tabLayout->addWidget(tooltipOwnerCheckBox); tooltipDetailsCheckBox = new QCheckBox{i18nc("@option:check", "Show technical details"), tab}; tabLayout->addWidget(tooltipDetailsCheckBox); tabLayout->addWidget(new KSeparator{tab}); showExpirationCheckBox = new QCheckBox{i18nc("@option:check", "Show upcoming certificate expiration"), tab}; tabLayout->addWidget(showExpirationCheckBox); { auto gridLayout = new QGridLayout; const ExpiryCheckerConfig expiryConfig; { auto label = new QLabel{i18nc("@label:spinbox", "Threshold for own certificates:"), tab}; ownCertificateThresholdSpinBox = new PluralHandlingSpinBox{tab}; label->setBuddy(ownCertificateThresholdSpinBox); const auto configItem = expiryConfig.ownKeyThresholdInDaysItem(); ownCertificateThresholdSpinBox->setMinimum(configItem->minValue().toInt()); ownCertificateThresholdSpinBox->setMaximum(configItem->maxValue().toInt()); ownCertificateThresholdSpinBox->setSpecialValueText(i18nc("@item never show expiry notification", "never")); ownCertificateThresholdSpinBox->setSuffix(ki18ncp("@item:valuesuffix", " day", " days")); ownCertificateThresholdSpinBox->setToolTip(i18nc("@info:tooltip", "Select the number of days you want to be warned in advance, if your own certificate is about to expire soon.")); gridLayout->addWidget(label, 0, 0); gridLayout->addWidget(ownCertificateThresholdSpinBox, 0, 1); } { auto label = new QLabel{i18nc("@label:spinbox", "Threshold for other certificates:"), tab}; otherCertificateThresholdSpinBox = new PluralHandlingSpinBox{tab}; label->setBuddy(otherCertificateThresholdSpinBox); const auto configItem = expiryConfig.otherKeyThresholdInDaysItem(); otherCertificateThresholdSpinBox->setMinimum(configItem->minValue().toInt()); otherCertificateThresholdSpinBox->setMaximum(configItem->maxValue().toInt()); otherCertificateThresholdSpinBox->setSpecialValueText(i18nc("@item never show expiry notification", "never")); otherCertificateThresholdSpinBox->setSuffix(ki18ncp("@item:valuesuffix", " day", " days")); otherCertificateThresholdSpinBox->setToolTip(i18nc("@info:tooltip", "Select the number of days you want to be warned in advance, if another person's certificate is about to expire soon.")); gridLayout->addWidget(label, 1, 0); gridLayout->addWidget(otherCertificateThresholdSpinBox, 1, 1); } gridLayout->setColumnStretch(2, 1); tabLayout->addLayout(gridLayout); } tabLayout->addStretch(1); tabWidget->addTab(tab, i18nc("@title:tab", "General")); } auto tab_2 = new QWidget(); tab_2->setObjectName(QString::fromUtf8("tab_2")); auto gridLayout = new QGridLayout(tab_2); gridLayout->setObjectName(QString::fromUtf8("gridLayout")); highContrastMsg = new KMessageWidget(tab_2); highContrastMsg->setObjectName(QString::fromUtf8("highContrastMsg")); gridLayout->addWidget(highContrastMsg, 0, 0, 1, 2); categoriesLV = new QListWidget(tab_2); categoriesLV->setObjectName(QString::fromUtf8("categoriesLV")); gridLayout->addWidget(categoriesLV, 1, 0, 1, 1); auto vboxLayout = new QVBoxLayout(); vboxLayout->setObjectName(QString::fromUtf8("vboxLayout")); iconButton = new QPushButton(tab_2); iconButton->setText(i18nc("@action:button", "Set Icon...")); iconButton->setObjectName(QString::fromUtf8("iconButton")); iconButton->setEnabled(false); vboxLayout->addWidget(iconButton); foregroundButton = new QPushButton(tab_2); foregroundButton->setText(i18nc("@action:button", "Set Text Color...")); foregroundButton->setObjectName(QString::fromUtf8("foregroundButton")); foregroundButton->setEnabled(false); vboxLayout->addWidget(foregroundButton); backgroundButton = new QPushButton(tab_2); backgroundButton->setText(i18nc("@action:button", "Set Background Color...")); backgroundButton->setObjectName(QString::fromUtf8("backgroundButton")); backgroundButton->setEnabled(false); vboxLayout->addWidget(backgroundButton); fontButton = new QPushButton(tab_2); fontButton->setText(i18nc("@action:button", "Set Font...")); fontButton->setObjectName(QString::fromUtf8("fontButton")); fontButton->setEnabled(false); vboxLayout->addWidget(fontButton); italicCB = new QCheckBox(tab_2); italicCB->setText(i18nc("@option:check", "Italic")); italicCB->setObjectName(QString::fromUtf8("italicCB")); italicCB->setEnabled(false); vboxLayout->addWidget(italicCB); boldCB = new QCheckBox(tab_2); boldCB->setText(i18nc("@option:check", "Bold")); boldCB->setObjectName(QString::fromUtf8("boldCB")); boldCB->setEnabled(false); vboxLayout->addWidget(boldCB); strikeoutCB = new QCheckBox(tab_2); strikeoutCB->setText(i18nc("@option:check", "Strikeout")); strikeoutCB->setObjectName(QString::fromUtf8("strikeoutCB")); strikeoutCB->setEnabled(false); vboxLayout->addWidget(strikeoutCB); vboxLayout->addStretch(1); defaultLookPB = new QPushButton(tab_2); defaultLookPB->setText(i18nc("@action:button", "Default Appearance")); defaultLookPB->setObjectName(QString::fromUtf8("defaultLookPB")); defaultLookPB->setEnabled(false); vboxLayout->addWidget(defaultLookPB); gridLayout->addLayout(vboxLayout, 1, 1, 1, 1); tabWidget->addTab(tab_2, i18nc("@title:tab", "Certificate Categories")); mainLayout->addWidget(tabWidget); } }; class AppearanceConfigWidget::Private : public Ui_AppearanceConfigWidget { friend class ::Kleo::Config::AppearanceConfigWidget; AppearanceConfigWidget *const q; public: explicit Private(AppearanceConfigWidget *qq) : Ui_AppearanceConfigWidget() , q(qq) { setupUi(q); if (QLayout *const l = q->layout()) { l->setContentsMargins(0, 0, 0, 0); } highContrastMsg->setVisible(SystemInfo::isHighContrastModeActive()); highContrastMsg->setMessageType(KMessageWidget::Warning); highContrastMsg->setIcon(q->style()->standardIcon(QStyle::SP_MessageBoxWarning, nullptr, q)); highContrastMsg->setText(i18n("The preview of colors is disabled because high-contrast mode is active.")); highContrastMsg->setCloseButtonVisible(false); if (Kleo::Settings{}.cmsEnabled()) { auto w = new QWidget; dnOrderWidget = new DNAttributeOrderConfigWidget{w}; dnOrderWidget->setObjectName(QStringLiteral("dnOrderWidget")); (new QVBoxLayout(w))->addWidget(dnOrderWidget); tabWidget->addTab(w, i18n("DN-Attribute Order")); connect(dnOrderWidget, &DNAttributeOrderConfigWidget::changed, q, &AppearanceConfigWidget::changed); } connect(iconButton, SIGNAL(clicked()), q, SLOT(slotIconClicked())); #ifndef QT_NO_COLORDIALOG connect(foregroundButton, SIGNAL(clicked()), q, SLOT(slotForegroundClicked())); connect(backgroundButton, SIGNAL(clicked()), q, SLOT(slotBackgroundClicked())); #else foregroundButton->hide(); backgroundButton->hide(); #endif #ifndef QT_NO_FONTDIALOG connect(fontButton, SIGNAL(clicked()), q, SLOT(slotFontClicked())); #else fontButton->hide(); #endif auto emitChanged = [this]() { Q_EMIT q->changed(); }; connect(categoriesLV, SIGNAL(itemSelectionChanged()), q, SLOT(slotSelectionChanged())); connect(defaultLookPB, SIGNAL(clicked()), q, SLOT(slotDefaultClicked())); connect(italicCB, SIGNAL(toggled(bool)), q, SLOT(slotItalicToggled(bool))); connect(boldCB, SIGNAL(toggled(bool)), q, SLOT(slotBoldToggled(bool))); connect(strikeoutCB, SIGNAL(toggled(bool)), q, SLOT(slotStrikeOutToggled(bool))); connect(tooltipValidityCheckBox, SIGNAL(toggled(bool)), q, SLOT(slotTooltipValidityChanged(bool))); connect(tooltipOwnerCheckBox, SIGNAL(toggled(bool)), q, SLOT(slotTooltipOwnerChanged(bool))); connect(tooltipDetailsCheckBox, SIGNAL(toggled(bool)), q, SLOT(slotTooltipDetailsChanged(bool))); connect(useTagsCheckBox, SIGNAL(toggled(bool)), q, SLOT(slotUseTagsChanged(bool))); connect(showExpirationCheckBox, &QCheckBox::toggled, q, emitChanged); - connect(ownCertificateThresholdSpinBox, &QSpinBox::valueChanged, q, emitChanged); - connect(otherCertificateThresholdSpinBox, &QSpinBox::valueChanged, q, emitChanged); + connect(ownCertificateThresholdSpinBox, qOverload(&QSpinBox::valueChanged), q, emitChanged); + connect(otherCertificateThresholdSpinBox, qOverload(&QSpinBox::valueChanged), q, emitChanged); } private: void enableDisableActions(QListWidgetItem *item); QListWidgetItem *selectedItem() const; private: void slotIconClicked(); #ifndef QT_NO_COLORDIALOG void slotForegroundClicked(); void slotBackgroundClicked(); #endif #ifndef QT_NO_FONTDIALOG void slotFontClicked(); #endif void slotSelectionChanged(); void slotDefaultClicked(); void slotItalicToggled(bool); void slotBoldToggled(bool); void slotStrikeOutToggled(bool); void slotTooltipValidityChanged(bool); void slotTooltipOwnerChanged(bool); void slotTooltipDetailsChanged(bool); void slotUseTagsChanged(bool); private: Kleo::DNAttributeOrderConfigWidget *dnOrderWidget = nullptr; }; AppearanceConfigWidget::AppearanceConfigWidget(QWidget *p, Qt::WindowFlags f) : QWidget(p, f), d(new Private(this)) { // load(); } AppearanceConfigWidget::~AppearanceConfigWidget() {} void AppearanceConfigWidget::Private::slotSelectionChanged() { enableDisableActions(selectedItem()); } QListWidgetItem *AppearanceConfigWidget::Private::selectedItem() const { const QList items = categoriesLV->selectedItems(); return items.empty() ? nullptr : items.front(); } void AppearanceConfigWidget::Private::enableDisableActions(QListWidgetItem *item) { kiosk_enable(iconButton, item, MayChangeIconRole); #ifndef QT_NO_COLORDIALOG kiosk_enable(foregroundButton, item, MayChangeForegroundRole); kiosk_enable(backgroundButton, item, MayChangeBackgroundRole); #endif #ifndef QT_NO_FONTDIALOG kiosk_enable(fontButton, item, MayChangeFontRole); #endif kiosk_enable(italicCB, item, MayChangeItalicRole); kiosk_enable(boldCB, item, MayChangeBoldRole); kiosk_enable(strikeoutCB, item, MayChangeStrikeOutRole); defaultLookPB->setEnabled(item); italicCB->setChecked(is_italic(item)); boldCB->setChecked(is_bold(item)); strikeoutCB->setChecked(is_strikeout(item)); } void AppearanceConfigWidget::Private::slotDefaultClicked() { QListWidgetItem *const item = selectedItem(); if (!item) { return; } set_default_appearance(item); enableDisableActions(item); Q_EMIT q->changed(); } void AppearanceConfigWidget::defaults() { // use temporary KConfigSkeleton instances for (re)setting the values to the defaults; // the setters respect the immutability of the individual settings, so that we don't have // to check this ourselves Settings settings; settings.setShowExpiryNotifications(settings.findItem(QStringLiteral("ShowExpiryNotifications"))->getDefault().toBool()); d->showExpirationCheckBox->setChecked(settings.showExpiryNotifications()); { ExpiryCheckerConfig expiryConfig; expiryConfig.setOwnKeyThresholdInDays(expiryConfig.ownKeyThresholdInDaysItem()->getDefault().toInt()); d->ownCertificateThresholdSpinBox->setValue(expiryConfig.ownKeyThresholdInDays()); expiryConfig.setOtherKeyThresholdInDays(expiryConfig.otherKeyThresholdInDaysItem()->getDefault().toInt()); d->otherCertificateThresholdSpinBox->setValue(expiryConfig.otherKeyThresholdInDays()); } // This simply means "default look for every category" for (int i = 0, end = d->categoriesLV->count(); i != end; ++i) { set_default_appearance(d->categoriesLV->item(i)); } TooltipPreferences tooltipPrefs; tooltipPrefs.setShowValidity(tooltipPrefs.findItem(QStringLiteral("ShowValidity"))->getDefault().toBool()); d->tooltipValidityCheckBox->setChecked(tooltipPrefs.showValidity()); tooltipPrefs.setShowOwnerInformation(tooltipPrefs.findItem(QStringLiteral("ShowOwnerInformation"))->getDefault().toBool()); d->tooltipOwnerCheckBox->setChecked(tooltipPrefs.showOwnerInformation()); tooltipPrefs.setShowCertificateDetails(tooltipPrefs.findItem(QStringLiteral("ShowCertificateDetails"))->getDefault().toBool()); d->tooltipDetailsCheckBox->setChecked(tooltipPrefs.showCertificateDetails()); if (d->dnOrderWidget) { if (!settings.isImmutable(QStringLiteral("AttributeOrder"))) { d->dnOrderWidget->setAttributeOrder(DN::defaultAttributeOrder()); } } Q_EMIT changed(); } void AppearanceConfigWidget::load() { const Settings settings; d->showExpirationCheckBox->setChecked(settings.showExpiryNotifications()); d->showExpirationCheckBox->setEnabled(!settings.isImmutable(QStringLiteral("ShowExpiryNotifications"))); { const ExpiryCheckerConfig expiryConfig; d->ownCertificateThresholdSpinBox->setValue(expiryConfig.ownKeyThresholdInDays()); d->ownCertificateThresholdSpinBox->setEnabled(!expiryConfig.ownKeyThresholdInDaysItem()->isImmutable()); d->otherCertificateThresholdSpinBox->setValue(expiryConfig.otherKeyThresholdInDays()); d->otherCertificateThresholdSpinBox->setEnabled(!expiryConfig.otherKeyThresholdInDaysItem()->isImmutable()); } if (d->dnOrderWidget) { d->dnOrderWidget->setAttributeOrder(DN::attributeOrder()); d->dnOrderWidget->setEnabled(!settings.isImmutable(QStringLiteral("AttributeOrder"))); } d->categoriesLV->clear(); KSharedConfigPtr config = KSharedConfig::openConfig(QStringLiteral("libkleopatrarc")); if (!config) { return; } const QStringList groups = config->groupList().filter(QRegularExpression(QStringLiteral("^Key Filter #\\d+$"))); for (const QString &group : groups) { const KConfigGroup configGroup{config, group}; const bool isCmsSpecificKeyFilter = !configGroup.readEntry("is-openpgp-key", true); auto item = new QListWidgetItem{d->categoriesLV}; // hide CMS-specific filters if CMS is disabled; we hide those filters // instead of skipping them, so that they are not removed on save item->setHidden(isCmsSpecificKeyFilter && !Kleo::Settings{}.cmsEnabled()); apply_config(configGroup, item); } const TooltipPreferences prefs; d->tooltipValidityCheckBox->setChecked(prefs.showValidity()); d->tooltipValidityCheckBox->setEnabled(!prefs.isImmutable(QStringLiteral("ShowValidity"))); d->tooltipOwnerCheckBox->setChecked(prefs.showOwnerInformation()); d->tooltipOwnerCheckBox->setEnabled(!prefs.isImmutable(QStringLiteral("ShowOwnerInformation"))); d->tooltipDetailsCheckBox->setChecked(prefs.showCertificateDetails()); d->tooltipDetailsCheckBox->setEnabled(!prefs.isImmutable(QStringLiteral("ShowCertificateDetails"))); const TagsPreferences tagsPrefs; d->useTagsCheckBox->setChecked(tagsPrefs.useTags()); d->useTagsCheckBox->setEnabled(!tagsPrefs.isImmutable(QStringLiteral("UseTags"))); } void AppearanceConfigWidget::save() { Settings settings; settings.setShowExpiryNotifications(d->showExpirationCheckBox->isChecked()); if (d->dnOrderWidget) { settings.setAttributeOrder(d->dnOrderWidget->attributeOrder()); DN::setAttributeOrder(settings.attributeOrder()); } settings.save(); { ExpiryCheckerConfig expiryConfig; expiryConfig.setOwnKeyThresholdInDays(d->ownCertificateThresholdSpinBox->value()); expiryConfig.setOtherKeyThresholdInDays(d->otherCertificateThresholdSpinBox->value()); expiryConfig.save(); } TooltipPreferences prefs; prefs.setShowValidity(d->tooltipValidityCheckBox->isChecked()); prefs.setShowOwnerInformation(d->tooltipOwnerCheckBox->isChecked()); prefs.setShowCertificateDetails(d->tooltipDetailsCheckBox->isChecked()); prefs.save(); KSharedConfigPtr config = KSharedConfig::openConfig(QStringLiteral("libkleopatrarc")); if (!config) { return; } // We know (assume) that the groups in the config object haven't changed, // so we just iterate over them and over the listviewitems, and map one-to-one. const QStringList groups = config->groupList().filter(QRegularExpression(QStringLiteral("^Key Filter #\\d+$"))); #if 0 if (groups.isEmpty()) { // If we created the default categories ourselves just now, then we need to make up their list Q3ListViewItemIterator lvit(categoriesLV); for (; lvit.current(); ++lvit) { groups << lvit.current()->text(0); } } #endif for (int i = 0, end = std::min(groups.size(), d->categoriesLV->count()); i != end; ++i) { const QListWidgetItem *const item = d->categoriesLV->item(i); Q_ASSERT(item); KConfigGroup group(config, groups[i]); save_to_config(item, group); } TagsPreferences tagsPrefs; tagsPrefs.setUseTags(d->useTagsCheckBox->isChecked()); tagsPrefs.save(); config->sync(); KeyFilterManager::instance()->reload(); } void AppearanceConfigWidget::Private::slotIconClicked() { QListWidgetItem *const item = selectedItem(); if (!item) { return; } const QString iconName = KIconDialog::getIcon( /* repeating default arguments begin */ KIconLoader::Desktop, KIconLoader::Application, false, 0, false, /* repeating default arguments end */ q); if (iconName.isEmpty()) { return; } item->setIcon(QIcon::fromTheme(iconName)); item->setData(IconNameRole, iconName); Q_EMIT q->changed(); } #ifndef QT_NO_COLORDIALOG void AppearanceConfigWidget::Private::slotForegroundClicked() { QListWidgetItem *const item = selectedItem(); if (!item) { return; } const QVariant v = brush2color(item->data(StoredForegroundRole)); const QColor initial = v.isValid() ? v.value() : categoriesLV->palette().color(QPalette::Normal, QPalette::Text); const QColor c = QColorDialog::getColor(initial, q); if (c.isValid()) { item->setData(StoredForegroundRole, QBrush(c)); if (!SystemInfo::isHighContrastModeActive()) { item->setData(Qt::ForegroundRole, QBrush(c)); } Q_EMIT q->changed(); } } void AppearanceConfigWidget::Private::slotBackgroundClicked() { QListWidgetItem *const item = selectedItem(); if (!item) { return; } const QVariant v = brush2color(item->data(StoredBackgroundRole)); const QColor initial = v.isValid() ? v.value() : categoriesLV->palette().color(QPalette::Normal, QPalette::Base); const QColor c = QColorDialog::getColor(initial, q); if (c.isValid()) { item->setData(StoredBackgroundRole, QBrush(c)); if (!SystemInfo::isHighContrastModeActive()) { item->setData(Qt::BackgroundRole, QBrush(c)); } Q_EMIT q->changed(); } } #endif // QT_NO_COLORDIALOG #ifndef QT_NO_FONTDIALOG void AppearanceConfigWidget::Private::slotFontClicked() { QListWidgetItem *const item = selectedItem(); if (!item) { return; } const QVariant v = item->data(Qt::FontRole); bool ok = false; const QFont defaultFont = tryToFindFontFor(item); #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) const QFont initial = v.isValid() && v.type() == QVariant::Font ? v.value() : defaultFont; #else const QFont initial = v.isValid() && v.userType() == QMetaType::QFont ? v.value() : defaultFont; #endif QFont f = QFontDialog::getFont(&ok, initial, q); if (!ok) { return; } // disallow circumventing KIOSK: if (!item->data(MayChangeItalicRole).toBool()) { f.setItalic(initial.italic()); } if (!item->data(MayChangeBoldRole).toBool()) { f.setBold(initial.bold()); } if (!item->data(MayChangeStrikeOutRole).toBool()) { f.setStrikeOut(initial.strikeOut()); } item->setData(Qt::FontRole, f != defaultFont ? f : QVariant()); item->setData(HasFontRole, true); Q_EMIT q->changed(); } #endif // QT_NO_FONTDIALOG void AppearanceConfigWidget::Private::slotItalicToggled(bool on) { set_italic(selectedItem(), on); Q_EMIT q->changed(); } void AppearanceConfigWidget::Private::slotBoldToggled(bool on) { set_bold(selectedItem(), on); Q_EMIT q->changed(); } void AppearanceConfigWidget::Private::slotStrikeOutToggled(bool on) { set_strikeout(selectedItem(), on); Q_EMIT q->changed(); } void AppearanceConfigWidget::Private::slotTooltipValidityChanged(bool) { Q_EMIT q->changed(); } void AppearanceConfigWidget::Private::slotTooltipOwnerChanged(bool) { Q_EMIT q->changed(); } void AppearanceConfigWidget::Private::slotTooltipDetailsChanged(bool) { Q_EMIT q->changed(); } void AppearanceConfigWidget::Private::slotUseTagsChanged(bool) { Q_EMIT q->changed(); } #include "moc_appearanceconfigwidget.cpp" diff --git a/src/conf/pluralhandlingspinbox.cpp b/src/conf/pluralhandlingspinbox.cpp index 7f306b21a..ef4db8800 100644 --- a/src/conf/pluralhandlingspinbox.cpp +++ b/src/conf/pluralhandlingspinbox.cpp @@ -1,52 +1,52 @@ /* SPDX-FileCopyrightText: 2014 Laurent Montel SPDX-License-Identifier: LGPL-2.1-or-later This is a copy of KPluralHandlingSpinBox from KTextWidgets. */ #include "pluralhandlingspinbox.h" class PluralHandlingSpinBoxPrivate { public: PluralHandlingSpinBoxPrivate(QSpinBox *q) : q(q) { - QObject::connect(q, &QSpinBox::valueChanged, q, [this](int value) { + QObject::connect(q, qOverload(&QSpinBox::valueChanged), q, [this](int value) { updateSuffix(value); }); } void updateSuffix(int value) { if (!pluralSuffix.isEmpty()) { KLocalizedString s = pluralSuffix; q->setSuffix(s.subs(value).toString()); } } QSpinBox *const q; KLocalizedString pluralSuffix; }; PluralHandlingSpinBox::PluralHandlingSpinBox(QWidget *parent) : QSpinBox(parent) , d(new PluralHandlingSpinBoxPrivate(this)) { } PluralHandlingSpinBox::~PluralHandlingSpinBox() = default; void PluralHandlingSpinBox::setSuffix(const KLocalizedString &suffix) { d->pluralSuffix = suffix; if (suffix.isEmpty()) { QSpinBox::setSuffix(QString()); } else { d->updateSuffix(value()); } } #include "moc_pluralhandlingspinbox.cpp" diff --git a/src/dialogs/updatenotification.cpp b/src/dialogs/updatenotification.cpp index 0f99d639c..59d149580 100644 --- a/src/dialogs/updatenotification.cpp +++ b/src/dialogs/updatenotification.cpp @@ -1,228 +1,229 @@ /* dialogs/updatenotification.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2017 Bundesamt für Sicherheit in der Informationstechnik SPDX-FileContributor: Intevation GmbH SPDX-License-Identifier: GPL-2.0-or-later */ #include "updatenotification.h" #include #include #include +#include #include "kleopatra_debug.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Kleo; namespace { static void gpgconf_set_update_check(bool value) { auto conf = QGpgME::cryptoConfig(); auto entry = getCryptoConfigEntry(conf, "dirmngr", "allow-version-check"); if (!entry) { qCDebug(KLEOPATRA_LOG) << "allow-version-check entry not found"; return; } if (entry->boolValue() != value) { entry->setBoolValue(value); conf->sync(true); } } } // namespace void UpdateNotification::forceUpdateCheck(QWidget *parent) { auto proc = new QProcess; proc->setProgram(gnupgInstallPath() + QStringLiteral("/gpg-connect-agent.exe")); proc->setArguments({ QStringLiteral("--dirmngr"), QStringLiteral("loadswdb --force"), QStringLiteral("/bye"), }); auto progress = new QProgressDialog(i18n("Searching for updates..."), i18n("Cancel"), 0, 0, parent); progress->setMinimumDuration(0); progress->show(); connect(progress, &QProgressDialog::canceled, [ proc] () { proc->kill(); qCDebug(KLEOPATRA_LOG) << "Update force canceled. Output:" << QString::fromLocal8Bit(proc->readAllStandardOutput()) << "stderr:" << QString::fromLocal8Bit(proc->readAllStandardError()); }); #if QT_DEPRECATED_SINCE(5, 13) connect(proc, qOverload(&QProcess::finished), #else connect(proc, &QProcess::finished, #endif [parent, progress, proc](int exitCode, QProcess::ExitStatus exitStatus) { qCDebug(KLEOPATRA_LOG) << "Update force exited with status:" << exitStatus << "code:" << exitCode; delete progress; proc->deleteLater(); UpdateNotification::checkUpdate(parent, exitStatus == QProcess::NormalExit); }); qCDebug(KLEOPATRA_LOG) << "Starting:" << proc->program() << "args" << proc->arguments(); proc->start(); } void UpdateNotification::checkUpdate(QWidget *parent, bool force) { #ifdef Q_OS_WIN KConfigGroup updatecfg(KSharedConfig::openConfig(), "UpdateNotification"); if (updatecfg.readEntry("NeverShow", false) && !force) { return; } // Gpg defaults to no update check. For Gpg4win we want this // enabled if the user does not explicitly disable update // checks neverShow would be true in that case or // we would have set AllowVersionCheck once and the user // explicitly removed that. if (force || updatecfg.readEntry("AllowVersionCheckSetOnce", false)) { gpgconf_set_update_check (true); updatecfg.writeEntry("AllowVersionCheckSetOnce", true); } const auto current = gpg4winVersionNumber(); GpgME::Error err; const auto lastshown = updatecfg.readEntry("LastShown", QDateTime()); if (!force && lastshown.isValid() && lastshown.addSecs(20 * 60 * 60) > QDateTime::currentDateTime()) { qDebug() << QDateTime::currentDateTime().addSecs(20 * 60 * 60); return; } const auto results = GpgME::SwdbResult::query("gpg4win", current.toUtf8().constData(), &err); if (err) { qCDebug(KLEOPATRA_LOG) << "update check failed: " << Formatting::errorAsString(err); return; } if (results.size() != 1) { /* Should not happen */ qCDebug(KLEOPATRA_LOG) << "more then one result"; return; } const auto result = results[0]; if (result.update()) { const QString newVersion = QStringLiteral("%1.%2.%3").arg(result.version().major) .arg(result.version().minor) .arg(result.version().patch); qCDebug(KLEOPATRA_LOG) << "Have update to version:" << newVersion; UpdateNotification notifier(parent, newVersion); notifier.exec(); updatecfg.writeEntry("LastShown", QDateTime::currentDateTime()); updatecfg.sync(); } else { qCDebug(KLEOPATRA_LOG) << "No update for:" << current; if (force) { KMessageBox::information(parent, i18nc("@info", "No update found in the available version database."), i18nc("@title", "Up to date")); } } #else Q_UNUSED(parent) Q_UNUSED(force) #endif } UpdateNotification::UpdateNotification(QWidget *parent, const QString &version) : QDialog(parent) { resize(400, 200); auto lay = new QGridLayout(this); auto logo = new QLabel; logo->setMaximumWidth(110); setAttribute(Qt::WA_QuitOnClose, false); KIconLoader *const il = KIconLoader::global(); const QString iconPath = il->iconPath(QStringLiteral("gpg4win"), KIconLoader::User); logo->setPixmap(QIcon(iconPath).pixmap(100, 100)); auto label = new HtmlLabel; const QString boldVersion = QStringLiteral("%1").arg(version); label->setHtml(i18nc("%1 is the version number", "Version %1 is available.", boldVersion) + QStringLiteral("

") + i18nc("Link to NEWS style changelog", "See the new features.")); label->setOpenExternalLinks(true); label->setTextInteractionFlags(Qt::TextBrowserInteraction); label->setWordWrap(true); setWindowTitle(i18nc("@title:window", "Update Available")); setWindowIcon(QIcon(QLatin1String("gpg4win"))); lay->addWidget(logo, 0, 0); lay->addWidget(label, 0, 1); const auto chk = new QCheckBox (i18n("Show this notification for future updates.")); lay->addWidget(chk, 1, 0, 1, -1); KConfigGroup updatecfg(KSharedConfig::openConfig(), "UpdateNotification"); chk->setChecked(!updatecfg.readEntry("NeverShow", false)); const auto bb = new QDialogButtonBox(); const auto b = bb->addButton(i18n("&Get update"), QDialogButtonBox::AcceptRole); b->setDefault(true); b->setIcon(QIcon::fromTheme(QStringLiteral("arrow-down"))); bb->addButton(QDialogButtonBox::Cancel); lay->addWidget(bb, 2, 0, 1, -1); connect (bb, &QDialogButtonBox::accepted, this, [this, chk]() { QDesktopServices::openUrl(QUrl(QStringLiteral("https://www.gpg4win.org/download.html"))); KConfigGroup updatecfg(KSharedConfig::openConfig(), "UpdateNotification"); updatecfg.writeEntry("NeverShow", !chk->isChecked()); gpgconf_set_update_check (chk->isChecked()); QDialog::accept(); }); connect (bb, &QDialogButtonBox::rejected, this, [this, chk]() { KConfigGroup updatecfg(KSharedConfig::openConfig(), "UpdateNotification"); updatecfg.writeEntry("NeverShow", !chk->isChecked()); gpgconf_set_update_check (chk->isChecked()); QDialog::reject(); }); }