diff --git a/src/view/smartcardwidget.cpp b/src/view/smartcardwidget.cpp index e471ee93e..6f3c4859b 100644 --- a/src/view/smartcardwidget.cpp +++ b/src/view/smartcardwidget.cpp @@ -1,226 +1,242 @@ /* view/smartcardwidget.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-FileCopyrightText: 2020 g10 Code GmbH SPDX-FileContributor: Ingo Klöcker SPDX-License-Identifier: GPL-2.0-or-later */ #include "smartcardwidget.h" #include "smartcard/readerstatus.h" #include "smartcard/openpgpcard.h" #include "smartcard/netkeycard.h" #include "smartcard/p15card.h" #include "smartcard/pivcard.h" #include "smartcard/utils.h" #include "view/pgpcardwidget.h" #include "view/netkeywidget.h" #include "view/pivcardwidget.h" #include "view/p15cardwidget.h" #include "kleopatra_debug.h" #include #include #include #include #include #include #include #include using namespace Kleo; using namespace Kleo::SmartCard; namespace { class PlaceHolderWidget: public QWidget { Q_OBJECT public: explicit PlaceHolderWidget(QWidget *parent = nullptr) : QWidget{parent} { auto lay = new QVBoxLayout; lay->addStretch(-1); const QStringList supported = QStringList() << i18nc("OpenPGP refers to a smartcard protocol", "OpenPGP v2.0 - v3.3") << i18nc("Gnuk is a cryptographic token for GnuPG", "Gnuk") << i18nc("NetKey refers to a smartcard protocol", "NetKey v3") << i18nc("PIV refers to a smartcard protocol", "PIV (requires GnuPG 2.3 or later)") << i18nc("CardOS is a smartcard operating system", "CardOS 5 (various apps)"); lay->addWidget(new QLabel(QStringLiteral("\t\t

") + i18n("Please insert a compatible smartcard.") + QStringLiteral("

"), this)); lay->addSpacing(10); lay->addWidget(new QLabel(QStringLiteral("\t\t") + i18n("Kleopatra currently supports the following card types:") + QStringLiteral("
  • ") + supported.join(QLatin1String("
  • ")) + QStringLiteral("
"), this)); lay->addSpacing(10); - lay->addWidget(new QLabel(i18n("Refresh the view (F5) to update the smartcard status."), this)); + { + auto hbox = new QHBoxLayout; + hbox->addStretch(1); + mReloadButton = new QPushButton{i18n("Reload"), this}; + hbox->addWidget(mReloadButton); + hbox->addStretch(1); + lay->addLayout(hbox); + } lay->addStretch(-1); auto hLay = new QHBoxLayout(this); hLay->addStretch(-1); hLay->addLayout(lay); hLay->addStretch(-1); lay->addStretch(-1); + + connect(mReloadButton, &QPushButton::clicked, this, &PlaceHolderWidget::reload); } + +Q_SIGNALS: + void reload(); + +private: + QPushButton *mReloadButton = nullptr; }; } // namespace class SmartCardWidget::Private { friend class ::Kleo::SmartCardWidget; public: Private(SmartCardWidget *qq); void cardAddedOrChanged(const std::string &serialNumber, const std::string &appName); void cardRemoved(const std::string &serialNumber, const std::string &appName); private: template void cardAddedOrChanged(const std::string &serialNumber); private: SmartCardWidget *const q; QMap, QPointer> mCardWidgets; PlaceHolderWidget *mPlaceHolderWidget; QStackedWidget *mStack; QTabWidget *mTabWidget; }; SmartCardWidget::Private::Private(SmartCardWidget *qq) : q{qq} { auto vLay = new QVBoxLayout(q); vLay->addWidget(new QLabel(QStringLiteral("

") + i18n("Smartcard Management") + QStringLiteral("

"))); mStack = new QStackedWidget; vLay->addWidget(mStack); mPlaceHolderWidget = new PlaceHolderWidget; mStack->addWidget(mPlaceHolderWidget); mTabWidget = new QTabWidget; mStack->addWidget(mTabWidget); mStack->setCurrentWidget(mPlaceHolderWidget); + connect(mPlaceHolderWidget, &PlaceHolderWidget::reload, q, &SmartCardWidget::reload); connect(ReaderStatus::instance(), &ReaderStatus::cardAdded, q, [this] (const std::string &serialNumber, const std::string &appName) { cardAddedOrChanged(serialNumber, appName); }); connect(ReaderStatus::instance(), &ReaderStatus::cardChanged, q, [this] (const std::string &serialNumber, const std::string &appName) { cardAddedOrChanged(serialNumber, appName); }); connect(ReaderStatus::instance(), &ReaderStatus::cardRemoved, q, [this] (const std::string &serialNumber, const std::string &appName) { cardRemoved(serialNumber, appName); }); } void SmartCardWidget::Private::cardAddedOrChanged(const std::string &serialNumber, const std::string &appName) { if (appName == SmartCard::NetKeyCard::AppName) { cardAddedOrChanged(serialNumber); } else if (appName == SmartCard::OpenPGPCard::AppName) { cardAddedOrChanged(serialNumber); } else if (appName == SmartCard::PIVCard::AppName) { cardAddedOrChanged(serialNumber); } else if (appName == SmartCard::P15Card::AppName) { cardAddedOrChanged(serialNumber); } else { qCWarning(KLEOPATRA_LOG) << "SmartCardWidget::Private::cardAddedOrChanged:" << "App" << appName.c_str() << "is not supported"; } } namespace { static QString getCardLabel(const std::shared_ptr &card) { if (!card->cardHolder().isEmpty()) { return i18nc("@title:tab smartcard application - name of card holder - serial number of smartcard", "%1 - %2 - %3", displayAppName(card->appName()), card->cardHolder(), card->displaySerialNumber()); } else { return i18nc("@title:tab smartcard application - serial number of smartcard", "%1 - %2", displayAppName(card->appName()), card->displaySerialNumber()); } } } template void SmartCardWidget::Private::cardAddedOrChanged(const std::string &serialNumber) { const auto card = ReaderStatus::instance()->getCard(serialNumber); if (!card) { qCWarning(KLEOPATRA_LOG) << "SmartCardWidget::Private::cardAddedOrChanged:" << "New or changed card" << serialNumber.c_str() << "with app" << C::AppName.c_str() << "not found"; return; } W *cardWidget = dynamic_cast(mCardWidgets.value({serialNumber, C::AppName}).data()); if (!cardWidget) { cardWidget = new W; mCardWidgets.insert({serialNumber, C::AppName}, cardWidget); mTabWidget->addTab(cardWidget, getCardLabel(card)); if (mCardWidgets.size() == 1) { mStack->setCurrentWidget(mTabWidget); } } cardWidget->setCard(card.get()); } void SmartCardWidget::Private::cardRemoved(const std::string &serialNumber, const std::string &appName) { QWidget * cardWidget = mCardWidgets.take({serialNumber, appName}); if (cardWidget) { const int index = mTabWidget->indexOf(cardWidget); if (index != -1) { mTabWidget->removeTab(index); } delete cardWidget; } if (mCardWidgets.empty()) { mStack->setCurrentWidget(mPlaceHolderWidget); } } SmartCardWidget::SmartCardWidget(QWidget *parent) : QWidget{parent} , d{std::make_unique(this)} { } Kleo::SmartCardWidget::~SmartCardWidget() = default; QWidget *getFirstEnabledFocusWidget(QWidget *parent) { for (auto w = parent->nextInFocusChain(); w != parent; w = w->nextInFocusChain()) { if (w->isEnabled() && (w->focusPolicy() != Qt::NoFocus)) { return w; } } return nullptr; } void SmartCardWidget::focusFirstChild(Qt::FocusReason reason) { if (d->mStack->currentWidget() == d->mPlaceHolderWidget) { if (auto w = getFirstEnabledFocusWidget(d->mPlaceHolderWidget)) { w->setFocus(reason); } } else if (auto cardWidget = d->mTabWidget->currentWidget()) { if (auto w = getFirstEnabledFocusWidget(cardWidget)) { w->setFocus(reason); } } } void SmartCardWidget::reload() { ReaderStatus::mutableInstance()->updateStatus(); } #include "smartcardwidget.moc"