Commit 762726ce authored by Ingo Klöcker's avatar Ingo Klöcker
Browse files

Show UI for all inserted cards in tabs

ReaderStatus:
* Use more specific signals cardAdded, cardChanged, cardRemoved instead
  of just cardChanged.
* Send serial number and app name (which uniquely identify an application
  on a smartcard) with the signals

NetKeyWidget, PGPCardWidget, PIVCardWidget:
* Remove double margins around the widgets; this also avoids an ugly
  lightgray border around the widgets

SmartCardWidget:
* Use a QTabWidget with tabs for each application on the inserted
  smartcards

GnuPG-bug-id: 5066
parent 523d95da
......@@ -644,7 +644,9 @@ public:
Q_SIGNALS:
void firstCardWithNullPinChanged(const std::string &serialNumber);
void anyCardCanLearnKeysChanged(bool);
void cardChanged(unsigned int);
void cardAdded(const std::string &serialNumber, const std::string &appName);
void cardChanged(const std::string &serialNumber, const std::string &appName);
void cardRemoved(const std::string &serialNumber, const std::string &appName);
void oneTransactionFinished(const GpgME::Error &err);
public Q_SLOTS:
......@@ -730,39 +732,39 @@ private:
KDAB_SYNCHRONIZED(m_mutex)
m_cardInfos = newCards;
std::vector<std::shared_ptr<Card> >::const_iterator
nit = newCards.begin(), nend = newCards.end(),
oit = oldCards.begin(), oend = oldCards.end();
unsigned int idx = 0;
bool anyLC = false;
std::string firstCardWithNullPin;
bool anyError = false;
while (nit != nend || oit != oend) {
const Card *optr = oit != oend ? (*oit).get() : nullptr;
const Card *nptr = nit != nend ? (*nit).get() : nullptr;
if ((optr && !nptr) || (!optr && nptr) || (optr && nptr && *optr != *nptr)) {
qCDebug(KLEOPATRA_LOG) << "ReaderStatusThread[2nd]: slot" << idx << ": card Changed";
Q_EMIT cardChanged(idx);
}
if (nptr) {
if (nptr->canLearnKeys()) {
anyLC = true;
}
if (nptr->hasNullPin() && firstCardWithNullPin.empty()) {
firstCardWithNullPin = (*nit)->serialNumber();
}
if (nptr->status() == Card::CardError) {
anyError = true;
for (const auto &newCard: newCards) {
const auto serialNumber = newCard->serialNumber();
const auto appName = newCard->appName();
const auto matchingOldCard = std::find_if(oldCards.cbegin(), oldCards.cend(),
[serialNumber, appName] (const std::shared_ptr<Card> &card) {
return card->serialNumber() == serialNumber && card->appName() == appName;
});
if (matchingOldCard == oldCards.cend()) {
qCDebug(KLEOPATRA_LOG) << "ReaderStatusThread: Card" << serialNumber << "with app" << appName << "was added";
Q_EMIT cardAdded(serialNumber, appName);
} else {
if (*newCard != **matchingOldCard) {
qCDebug(KLEOPATRA_LOG) << "ReaderStatusThread: Card" << serialNumber << "with app" << appName << "changed";
Q_EMIT cardChanged(serialNumber, appName);
}
oldCards.erase(matchingOldCard);
}
if (newCard->canLearnKeys()) {
anyLC = true;
}
if (nit != nend) {
++nit;
if (newCard->hasNullPin() && firstCardWithNullPin.empty()) {
firstCardWithNullPin = newCard->serialNumber();
}
if (oit != oend) {
++oit;
if (newCard->status() == Card::CardError) {
anyError = true;
}
++idx;
}
for (const auto &oldCard: oldCards) {
qCDebug(KLEOPATRA_LOG) << "ReaderStatusThread: Card" << oldCard->serialNumber() << "with app" << oldCard->appName() << "was removed";
Q_EMIT cardRemoved(oldCard->serialNumber(), oldCard->appName());
}
Q_EMIT firstCardWithNullPinChanged(firstCardWithNullPin);
......@@ -824,8 +826,12 @@ public:
watcher.addPath(Kleo::gnupgHomeDirectory());
watcher.setDelay(100);
connect(this, &::ReaderStatusThread::cardAdded,
q, &ReaderStatus::cardAdded);
connect(this, &::ReaderStatusThread::cardChanged,
q, &ReaderStatus::cardChanged);
connect(this, &::ReaderStatusThread::cardRemoved,
q, &ReaderStatus::cardRemoved);
connect(this, &::ReaderStatusThread::firstCardWithNullPinChanged,
q, &ReaderStatus::firstCardWithNullPinChanged);
connect(this, &::ReaderStatusThread::anyCardCanLearnKeysChanged,
......
......@@ -65,7 +65,9 @@ public Q_SLOTS:
Q_SIGNALS:
void firstCardWithNullPinChanged(const std::string &serialNumber);
void anyCardCanLearnKeysChanged(bool);
void cardChanged(unsigned int slot);
void cardAdded(const std::string &serialNumber, const std::string &appName);
void cardChanged(const std::string &serialNumber, const std::string &appName);
void cardRemoved(const std::string &serialNumber, const std::string &appName);
private:
class Private;
......
......@@ -56,6 +56,7 @@ NetKeyWidget::NetKeyWidget(QWidget *parent) :
mAreaWidget->setLayout(vLay);
mArea->setWidget(mAreaWidget);
auto scrollLay = new QVBoxLayout(this);
scrollLay->setContentsMargins(0, 0, 0, 0);
scrollLay->addWidget(mArea);
// Add general widgets
......
......@@ -120,6 +120,7 @@ PGPCardWidget::PGPCardWidget(QWidget *parent):
areaVLay->addStretch(1);
area->setWidget(areaWidget);
auto myLayout = new QVBoxLayout(this);
myLayout->setContentsMargins(0, 0, 0, 0);
myLayout->addWidget(area);
// Version and Serialnumber
......
......@@ -81,6 +81,7 @@ PIVCardWidget::PIVCardWidget(QWidget *parent):
{
// Set up the scroll area
auto myLayout = new QVBoxLayout(this);
myLayout->setContentsMargins(0, 0, 0, 0);
auto area = new QScrollArea;
area->setFrameShape(QFrame::NoFrame);
......
......@@ -3,29 +3,35 @@
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 <dev@ingo-kloecker.de>
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/pivcard.h"
#include "view/pgpcardwidget.h"
#include "view/netkeywidget.h"
#include "view/pivcardwidget.h"
#include "kleopatra_debug.h"
#include <KLocalizedString>
#include <QHBoxLayout>
#include <QLabel>
#include <QPointer>
#include <QPushButton>
#include <QTabWidget>
#include <QVBoxLayout>
#include <QStackedWidget>
#include <KLocalizedString>
using namespace Kleo;
using namespace Kleo::SmartCard;
......@@ -69,15 +75,19 @@ class SmartCardWidget::Private
public:
Private(SmartCardWidget *qq);
void setCard(std::shared_ptr<Card> card);
void cardAddedOrChanged(const std::string &serialNumber, const std::string &appName);
void cardRemoved(const std::string &serialNumber, const std::string &appName);
private:
template <typename C, typename W>
void cardAddedOrChanged(const std::string &serialNumber);
private:
SmartCardWidget *const q;
NetKeyWidget *mNetKeyWidget;
PGPCardWidget *mPGPCardWidget;
PIVCardWidget *mPIVCardWidget;
QMap<std::pair<std::string, std::string>, QPointer<QWidget> > mCardWidgets;
PlaceHolderWidget *mPlaceHolderWidget;
QStackedWidget *mStack;
QTabWidget *mTabWidget;
};
SmartCardWidget::Private::Private(SmartCardWidget *qq)
......@@ -100,46 +110,70 @@ SmartCardWidget::Private::Private(SmartCardWidget *qq)
mStack = new QStackedWidget;
vLay->addWidget(mStack);
mPGPCardWidget = new PGPCardWidget(q);
mStack->addWidget(mPGPCardWidget);
mNetKeyWidget = new NetKeyWidget(q);
mStack->addWidget(mNetKeyWidget);
mPIVCardWidget = new PIVCardWidget(q);
mStack->addWidget(mPIVCardWidget);
mPlaceHolderWidget = new PlaceHolderWidget(q);
mPlaceHolderWidget = new PlaceHolderWidget;
mStack->addWidget(mPlaceHolderWidget);
mTabWidget = new QTabWidget;
mStack->addWidget(mTabWidget);
mStack->setCurrentWidget(mPlaceHolderWidget);
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] (unsigned int slot) {
if (slot == 0) {
const auto cards = ReaderStatus::instance()->getCards();
if (!cards.size()) {
setCard(std::shared_ptr<Card>(new Card()));
} else {
// No support for multiple reader / cards currently
setCard(cards[0]);
}
}
});
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::setCard(std::shared_ptr<Card> card)
void SmartCardWidget::Private::cardAddedOrChanged(const std::string &serialNumber, const std::string &appName)
{
if (card->appName() == SmartCard::OpenPGPCard::AppName) {
mPGPCardWidget->setCard(static_cast<OpenPGPCard *> (card.get()));
mStack->setCurrentWidget(mPGPCardWidget);
} else if (card->appName() == SmartCard::NetKeyCard::AppName) {
mNetKeyWidget->setCard(static_cast<NetKeyCard *> (card.get()));
mStack->setCurrentWidget(mNetKeyWidget);
} else if (card->appName() == SmartCard::PIVCard::AppName) {
mPIVCardWidget->setCard(static_cast<PIVCard *> (card.get()));
mStack->setCurrentWidget(mPIVCardWidget);
if (appName == SmartCard::NetKeyCard::AppName) {
cardAddedOrChanged<NetKeyCard, NetKeyWidget>(serialNumber);
} else if (appName == SmartCard::OpenPGPCard::AppName) {
cardAddedOrChanged<OpenPGPCard, PGPCardWidget>(serialNumber);
} else if (appName == SmartCard::PIVCard::AppName) {
cardAddedOrChanged<PIVCard, PIVCardWidget>(serialNumber);
} else {
qCWarning(KLEOPATRA_LOG) << "SmartCardWidget::Private::cardAddedOrChanged:"
<< "App" << appName.c_str() << "is not supported";
}
}
template <typename C, typename W>
void SmartCardWidget::Private::cardAddedOrChanged(const std::string &serialNumber)
{
const auto card = ReaderStatus::instance()->getCard<C>(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<W *>(mCardWidgets.value({serialNumber, C::AppName}).data());
if (!cardWidget) {
cardWidget = new W;
mCardWidgets.insert({serialNumber, C::AppName}, cardWidget);
const QString cardLabel = i18nc("@title:tab serial number of smartcard - smartcard application", "%1 - %2",
QString::fromStdString(serialNumber), QString::fromStdString(C::AppName));
mTabWidget->addTab(cardWidget, cardLabel);
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);
}
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment