1 /*!
2 * \copyright Copyright (c) 2017-2021 Governikus GmbH & Co. KG, Germany
3 */
4
5 #include "ReaderDriverModel.h"
6
7 #include "AppSettings.h"
8 #include "Env.h"
9 #include "GeneralSettings.h"
10 #include "HelpAction.h"
11 #include "LanguageLoader.h"
12 #include "ReaderConfiguration.h"
13 #include "ReaderManager.h"
14
15 #if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
16 #include "ReaderDetector.h"
17 #endif
18
19 using namespace governikus;
20
21
ReaderDriverModel(QObject * pParent)22 ReaderDriverModel::ReaderDriverModel(QObject* pParent)
23 : QAbstractTableModel(pParent)
24 , mKnownDrivers()
25 , mConnectedReaders()
26 , mConnectedReadersUpdateTime()
27 {
28 const GeneralSettings& generalSettings = Env::getSingleton<AppSettings>()->getGeneralSettings();
29 connect(&generalSettings, &GeneralSettings::fireLanguageChanged, this, &ReaderDriverModel::fireLanguageChanged);
30 connect(&generalSettings, &GeneralSettings::fireLanguageChanged, this, &ReaderDriverModel::onUpdateContent);
31
32 const ReaderManager* const readerManager = Env::getSingleton<ReaderManager>();
33
34 connect(readerManager, &ReaderManager::fireReaderAdded, this, &ReaderDriverModel::onUpdateContent);
35 connect(readerManager, &ReaderManager::fireReaderRemoved, this, &ReaderDriverModel::onUpdateContent);
36 connect(Env::getSingleton<ReaderConfiguration>(), &ReaderConfiguration::fireUpdated, this, &ReaderDriverModel::onUpdateContent);
37 connect(Env::getSingleton<AppSettings>(), &AppSettings::fireSettingsChanged, this, &ReaderDriverModel::onUpdateContent);
38
39 #if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
40 connect(Env::getSingleton<ReaderDetector>(), &ReaderDetector::fireReaderChangeDetected, this, &ReaderDriverModel::onUpdateContent);
41 #endif
42
43 onUpdateContent();
44 }
45
46
collectReaderData()47 void ReaderDriverModel::collectReaderData()
48 {
49 mConnectedReaders.clear();
50
51 const QVector<ReaderInfo> installedReaders = Env::getSingleton<ReaderManager>()->getReaderInfos(ReaderFilter({
52 ReaderManagerPlugInType::PCSC, ReaderManagerPlugInType::NFC
53 }));
54
55 for (const auto& installedReader : installedReaders)
56 {
57 const auto& readerSettingsInfo = installedReader.getReaderConfigurationInfo();
58 if (!readerSettingsInfo.getUrl().isEmpty())
59 {
60 mKnownDrivers += readerSettingsInfo;
61 mConnectedReaders += readerSettingsInfo;
62 }
63 }
64
65 #if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
66 QVector<ReaderConfigurationInfo> readersWithoutDriver;
67 const auto& attachedSupportedDevices = Env::getSingleton<ReaderDetector>()->getAttachedSupportedDevices();
68 for (const auto& info : attachedSupportedDevices)
69 {
70 if (!mConnectedReaders.contains(info))
71 {
72 readersWithoutDriver.append(info);
73 }
74 }
75 mConnectedReaders += readersWithoutDriver;
76 #endif
77 }
78
79
indexIsValid(const QModelIndex & pIndex) const80 bool ReaderDriverModel::indexIsValid(const QModelIndex& pIndex) const
81 {
82 if (!pIndex.isValid())
83 {
84 Q_ASSERT(false && "Invoked with an invalid QModelIndex.");
85 return false;
86 }
87
88 if (pIndex.row() >= rowCount() || pIndex.column() >= columnCount())
89 {
90 Q_ASSERT(false && "Invoked with a row or a column which is out of bounds.");
91 return false;
92 }
93
94 return true;
95 }
96
97
getStatus(const ReaderConfigurationInfo & pReaderConfigurationInfo) const98 QString ReaderDriverModel::getStatus(const ReaderConfigurationInfo& pReaderConfigurationInfo) const
99 {
100 if (mConnectedReaders.isEmpty())
101 {
102 //: LABEL ALL_PLATFORMS
103 return tr("Not connected");
104 }
105
106 if (mKnownDrivers.contains(pReaderConfigurationInfo))
107 {
108 //: LABEL ALL_PLATFORMS
109 return tr("Driver installed");
110 }
111
112 //: LABEL ALL_PLATFORMS
113 return tr("No driver installed");
114 }
115
116
onUpdateContent()117 void ReaderDriverModel::onUpdateContent()
118 {
119 beginResetModel();
120
121 collectReaderData();
122 mConnectedReadersUpdateTime = QTime::currentTime();
123
124 endResetModel();
125
126 Q_EMIT fireModelChanged();
127 }
128
129
headerData(int pSection,Qt::Orientation pOrientation,int pRole) const130 QVariant ReaderDriverModel::headerData(int pSection, Qt::Orientation pOrientation, int pRole) const
131 {
132 if (pRole == Qt::DisplayRole && pOrientation == Qt::Horizontal)
133 {
134 switch (pSection)
135 {
136 case ColumnId::ReaderName:
137 //: LABEL ALL_PLATFORMS
138 return tr("Card reader");
139
140 case ColumnId::ReaderStatus:
141 //: LABEL ALL_PLATFORMS
142 return tr("Status");
143
144 default:
145 return QVariant();
146 }
147 }
148 return QVariant();
149 }
150
151
rowCount(const QModelIndex &) const152 int ReaderDriverModel::rowCount(const QModelIndex&) const
153 {
154 return mConnectedReaders.size();
155 }
156
157
columnCount(const QModelIndex &) const158 int ReaderDriverModel::columnCount(const QModelIndex&) const
159 {
160 return NUMBER_OF_COLUMNS;
161 }
162
163
data(const QModelIndex & pIndex,int pRole) const164 QVariant ReaderDriverModel::data(const QModelIndex& pIndex, int pRole) const
165 {
166 if (!indexIsValid(pIndex))
167 {
168 return QVariant();
169 }
170
171 const auto& reader = mConnectedReaders.at(pIndex.row());
172 switch (pRole)
173 {
174 case Qt::DisplayRole:
175 switch (pIndex.column())
176 {
177 case ColumnId::ReaderName:
178 return reader.getName();
179
180 case ColumnId::ReaderStatus:
181 return getStatus(reader);
182
183 default:
184 return QVariant();
185 }
186
187 case READER_NAME:
188 return reader.getName();
189
190 case READER_STATUS:
191 return getStatus(reader);
192
193 case READER_IMAGE_PATH:
194 return getReaderImageUrl(pIndex);
195
196 case READER_HTML_DESCRIPTION:
197 return getHTMLDescription(pIndex);
198
199 case READER_DRIVER_URL:
200 return mConnectedReaders.at(pIndex.row()).getUrl();
201
202 case READER_INSTALLED_AND_SUPPORTED:
203 return isInstalledSupportedReader(pIndex);
204
205 default:
206 return QVariant();
207 }
208 }
209
210
roleNames() const211 QHash<int, QByteArray> ReaderDriverModel::roleNames() const
212 {
213 QHash<int, QByteArray> roles = QAbstractTableModel::roleNames();
214 roles.insert(READER_NAME, "readerName");
215 roles.insert(READER_STATUS, "readerStatus");
216 roles.insert(READER_IMAGE_PATH, "readerImagePath");
217 roles.insert(READER_HTML_DESCRIPTION, "readerHTMLDescription");
218 roles.insert(READER_DRIVER_URL, "readerDriverUrl");
219 roles.insert(READER_INSTALLED_AND_SUPPORTED, "readerInstalledAndSupported");
220 return roles;
221 }
222
223
getNoReaderFoundIconPath() const224 QString ReaderDriverModel::getNoReaderFoundIconPath() const
225 {
226 return ReaderConfiguration::getNoReaderFoundIconPath();
227 }
228
229
getReaderImageUrl(const QModelIndex & pIndex) const230 QUrl ReaderDriverModel::getReaderImageUrl(const QModelIndex& pIndex) const
231 {
232 return mConnectedReaders.at(pIndex.row()).getIcon()->lookupUrl();
233 }
234
235
getReaderImagePath(const QModelIndex & pIndex) const236 QString ReaderDriverModel::getReaderImagePath(const QModelIndex& pIndex) const
237 {
238 if (!indexIsValid(pIndex))
239 {
240 return QString();
241 }
242
243 return mConnectedReaders.at(pIndex.row()).getIcon()->lookupPath();
244 }
245
246
getHTMLDescription(const QModelIndex & pIndex) const247 QString ReaderDriverModel::getHTMLDescription(const QModelIndex& pIndex) const
248 {
249 if (!indexIsValid(pIndex))
250 {
251 return QString();
252 }
253
254 if (mConnectedReaders.isEmpty())
255 {
256 return QString();
257 }
258
259 if (mKnownDrivers.contains(mConnectedReaders.at(pIndex.row())))
260 {
261 //: LABEL ALL_PLATFORMS
262 return tr("Card reader ready for use.");
263 }
264
265 //: INFO ALL_PLATFORMS The driver for card reader needs to be installed, the download link is provided in the message.
266 return tr("Please download and install the driver you can find at: %1").
267 arg(QStringLiteral("<a href=\"%1\">%1</a>").arg(mConnectedReaders.at(pIndex.row()).getUrl()));
268 }
269
270
getEmptyListDescriptionString() const271 QString ReaderDriverModel::getEmptyListDescriptionString() const
272 {
273 const QString& onlineHelpSection = QStringLiteral("settingsPcscReader");
274 const QString& url = HelpAction::getOnlineUrl(onlineHelpSection);
275 //: Is embedded in a sentence.
276 const QString& hyperlink = QStringLiteral("<a href=\"%1\">%2</a>").arg(url, tr("online help"));
277 //: INFO ALL_PLATFORMS No card reader was found, the message contains a link to the installation section of the manual.
278 return tr("No connected card reader found. See %1 for installation of card readers.").arg(hyperlink);
279 }
280
281
isInstalledSupportedReader(const QModelIndex & pIndex) const282 bool ReaderDriverModel::isInstalledSupportedReader(const QModelIndex& pIndex) const
283 {
284 if (!indexIsValid(pIndex))
285 {
286 return false;
287 }
288
289 const auto& readerSettingsInfo = mConnectedReaders.at(pIndex.row());
290 const bool knownDriver = mKnownDrivers.contains(readerSettingsInfo);
291 const bool knownReader = readerSettingsInfo.isKnownReader();
292 return knownDriver && knownReader;
293 }
294
295
getLastUpdatedInformation() const296 QString ReaderDriverModel::getLastUpdatedInformation() const
297 {
298 if (!mConnectedReadersUpdateTime.isValid())
299 {
300 return QString();
301 }
302
303 const auto& updateTime = LanguageLoader::getInstance().getUsedLocale().toString(mConnectedReadersUpdateTime, tr("hh:mm:ss AP"));
304 //: LABEL ALL_PLATFORMS
305 return tr("The list of card readers was last updated at %1.").arg(updateTime);
306 }
307