1/****************************************************************************
2**
3** Copyright (C) 2017 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtNfc module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:BSD$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** BSD License Usage
18** Alternatively, you may use this file under the terms of the BSD license
19** as follows:
20**
21** "Redistribution and use in source and binary forms, with or without
22** modification, are permitted provided that the following conditions are
23** met:
24** * Redistributions of source code must retain the above copyright
25** notice, this list of conditions and the following disclaimer.
26** * Redistributions in binary form must reproduce the above copyright
27** notice, this list of conditions and the following disclaimer in
28** the documentation and/or other materials provided with the
29** distribution.
30** * Neither the name of The Qt Company Ltd nor the names of its
31** contributors may be used to endorse or promote products derived
32** from this software without specific prior written permission.
33**
34**
35** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
36** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
38** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
39** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
43** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
45** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
46**
47** $QT_END_LICENSE$
48**
49****************************************************************************/
50
51#include "mainwindow.h"
52#include "ui_mainwindow.h"
53
54#include "textrecordeditor.h"
55#include "urirecordeditor.h"
56#include "mimeimagerecordeditor.h"
57
58#include <QtNfc/qndefnfcurirecord.h>
59#include <QtNfc/qndefnfctextrecord.h>
60#include <QtNfc/qndefrecord.h>
61#include <QtNfc/qndefmessage.h>
62#include <QtNfc/qnearfieldmanager.h>
63#include <QtNfc/qnearfieldtarget.h>
64
65#include <QtWidgets/QMenu>
66#include <QtWidgets/QVBoxLayout>
67#include <QtWidgets/QFrame>
68#include <QtWidgets/QLabel>
69#include <QtWidgets/QFileDialog>
70
71class EmptyRecordLabel : public QLabel
72{
73 Q_OBJECT
74
75public:
76 EmptyRecordLabel() : QLabel(tr(s: "Empty Record")) { }
77 ~EmptyRecordLabel() { }
78
79 void setRecord(const QNdefRecord &record)
80 {
81 Q_UNUSED(record);
82 }
83
84 QNdefRecord record() const
85 {
86 return QNdefRecord();
87 }
88};
89
90class UnknownRecordLabel : public QLabel
91{
92 Q_OBJECT
93
94public:
95 UnknownRecordLabel() : QLabel(tr(s: "Unknown Record Type")) { }
96 ~UnknownRecordLabel() { }
97
98 void setRecord(const QNdefRecord &record) { m_record = record; }
99 QNdefRecord record() const { return m_record; }
100
101private:
102 QNdefRecord m_record;
103};
104
105template <typename T>
106void addRecord(Ui::MainWindow *ui, const QNdefRecord &record = QNdefRecord())
107{
108 QVBoxLayout *vbox = qobject_cast<QVBoxLayout *>(object: ui->scrollAreaWidgetContents->layout());
109 if (!vbox)
110 return;
111
112 if (!vbox->isEmpty()) {
113 QFrame *hline = new QFrame;
114 hline->setFrameShape(QFrame::HLine);
115 hline->setObjectName(QStringLiteral("line-spacer"));
116
117 vbox->addWidget(hline);
118 }
119
120 T *recordEditor = new T;
121 recordEditor->setObjectName(QStringLiteral("record-editor"));
122
123 if (!record.isEmpty())
124 recordEditor->setRecord(record);
125
126 vbox->addWidget(recordEditor);
127}
128
129MainWindow::MainWindow(QWidget *parent)
130: QMainWindow(parent), ui(new Ui::MainWindow), m_touchAction(NoAction)
131{
132 ui->setupUi(this);
133
134 QMenu *addRecordMenu = new QMenu(this);
135 addRecordMenu->addAction(text: tr(s: "NFC Text Record"), receiver: this, SLOT(addNfcTextRecord()));
136 addRecordMenu->addAction(text: tr(s: "NFC URI Record"), receiver: this, SLOT(addNfcUriRecord()));
137 addRecordMenu->addAction(text: tr(s: "MIME Image Record"), receiver: this, SLOT(addMimeImageRecord()));
138 addRecordMenu->addAction(text: tr(s: "Empty Record"), receiver: this, SLOT(addEmptyRecord()));
139 ui->addRecord->setMenu(addRecordMenu);
140
141 QVBoxLayout *vbox = new QVBoxLayout;
142 ui->scrollAreaWidgetContents->setLayout(vbox);
143
144 //! [QNearFieldManager init]
145 m_manager = new QNearFieldManager(this);
146 connect(sender: m_manager, signal: &QNearFieldManager::targetDetected,
147 receiver: this, slot: &MainWindow::targetDetected);
148 connect(sender: m_manager, signal: &QNearFieldManager::targetLost,
149 receiver: this, slot: &MainWindow::targetLost);
150 //! [QNearFieldManager init]
151}
152
153MainWindow::~MainWindow()
154{
155 delete ui;
156}
157
158void MainWindow::addNfcTextRecord()
159{
160 addRecord<TextRecordEditor>(ui);
161}
162
163void MainWindow::addNfcUriRecord()
164{
165 addRecord<UriRecordEditor>(ui);
166}
167
168void MainWindow::addMimeImageRecord()
169{
170 addRecord<MimeImageRecordEditor>(ui);
171}
172
173void MainWindow::addEmptyRecord()
174{
175 addRecord<EmptyRecordLabel>(ui);
176}
177
178void MainWindow::loadMessage()
179{
180 QString filename = QFileDialog::getOpenFileName(parent: this, caption: tr(s: "Select NDEF Message"));
181 if (filename.isEmpty())
182 return;
183
184 QFile file(filename);
185 if (!file.open(flags: QIODevice::ReadOnly))
186 return;
187
188 QByteArray ndef = file.readAll();
189
190 ndefMessageRead(message: QNdefMessage::fromByteArray(message: ndef));
191
192 file.close();
193}
194
195void MainWindow::saveMessage()
196{
197 QString filename = QFileDialog::getSaveFileName(parent: this, caption: tr(s: "Select NDEF Message"));
198 if (filename.isEmpty())
199 return;
200
201 QFile file(filename);
202 if (!file.open(flags: QIODevice::WriteOnly))
203 return;
204
205 file.write(data: ndefMessage().toByteArray());
206
207 file.close();
208}
209
210void MainWindow::touchReceive()
211{
212 ui->status->setStyleSheet(QStringLiteral("background: blue"));
213
214 m_touchAction = ReadNdef;
215
216 m_manager->setTargetAccessModes(QNearFieldManager::NdefReadTargetAccess);
217 //! [QNearFieldManager start detection]
218 m_manager->startTargetDetection();
219 //! [QNearFieldManager start detection]
220}
221
222void MainWindow::touchStore()
223{
224 ui->status->setStyleSheet(QStringLiteral("background: yellow"));
225
226 m_touchAction = WriteNdef;
227
228 m_manager->setTargetAccessModes(QNearFieldManager::NdefWriteTargetAccess);
229 m_manager->startTargetDetection();
230}
231
232//! [QNearFieldTarget detected]
233void MainWindow::targetDetected(QNearFieldTarget *target)
234{
235 switch (m_touchAction) {
236 case NoAction:
237 break;
238 case ReadNdef:
239 connect(sender: target, signal: &QNearFieldTarget::ndefMessageRead, receiver: this, slot: &MainWindow::ndefMessageRead);
240 connect(sender: target, signal: &QNearFieldTarget::error, receiver: this, slot: &MainWindow::targetError);
241
242 m_request = target->readNdefMessages();
243 if (!m_request.isValid()) // cannot read messages
244 targetError(error: QNearFieldTarget::NdefReadError, id: m_request);
245 break;
246 case WriteNdef:
247 connect(sender: target, signal: &QNearFieldTarget::ndefMessagesWritten, receiver: this, slot: &MainWindow::ndefMessageWritten);
248 connect(sender: target, signal: &QNearFieldTarget::error, receiver: this, slot: &MainWindow::targetError);
249
250 m_request = target->writeNdefMessages(messages: QList<QNdefMessage>() << ndefMessage());
251 if (!m_request.isValid()) // cannot write messages
252 targetError(error: QNearFieldTarget::NdefWriteError, id: m_request);
253 break;
254 }
255}
256//! [QNearFieldTarget detected]
257
258//! [QNearFieldTarget lost]
259void MainWindow::targetLost(QNearFieldTarget *target)
260{
261 target->deleteLater();
262}
263//! [QNearFieldTarget lost]
264
265void MainWindow::ndefMessageRead(const QNdefMessage &message)
266{
267 clearMessage();
268
269 for (const QNdefRecord &record : message) {
270 if (record.isRecordType<QNdefNfcTextRecord>()) {
271 addRecord<TextRecordEditor>(ui, record);
272 } else if (record.isRecordType<QNdefNfcUriRecord>()) {
273 addRecord<UriRecordEditor>(ui, record);
274 } else if (record.typeNameFormat() == QNdefRecord::Mime &&
275 record.type().startsWith(c: "image/")) {
276 addRecord<MimeImageRecordEditor>(ui, record);
277 } else if (record.isEmpty()) {
278 addRecord<EmptyRecordLabel>(ui);
279 } else {
280 addRecord<UnknownRecordLabel>(ui, record);
281 }
282 }
283
284 ui->status->setStyleSheet(QString());
285 m_manager->setTargetAccessModes(QNearFieldManager::NoTargetAccess);
286 //! [QNearFieldManager stop detection]
287 m_manager->stopTargetDetection();
288 //! [QNearFieldManager stop detection]
289 m_request = QNearFieldTarget::RequestId();
290 ui->statusBar->clearMessage();
291}
292
293void MainWindow::ndefMessageWritten()
294{
295 ui->status->setStyleSheet(QString());
296 m_manager->setTargetAccessModes(QNearFieldManager::NoTargetAccess);
297 m_manager->stopTargetDetection();
298 m_request = QNearFieldTarget::RequestId();
299 ui->statusBar->clearMessage();
300}
301
302void MainWindow::targetError(QNearFieldTarget::Error error, const QNearFieldTarget::RequestId &id)
303{
304 Q_UNUSED(error);
305 Q_UNUSED(id);
306
307 if (m_request == id) {
308 switch (error) {
309 case QNearFieldTarget::NoError:
310 ui->statusBar->clearMessage();
311 break;
312 case QNearFieldTarget::UnsupportedError:
313 ui->statusBar->showMessage(text: tr(s: "Unsupported tag"));
314 break;
315 case QNearFieldTarget::TargetOutOfRangeError:
316 ui->statusBar->showMessage(text: tr(s: "Tag removed from field"));
317 break;
318 case QNearFieldTarget::NoResponseError:
319 ui->statusBar->showMessage(text: tr(s: "No response from tag"));
320 break;
321 case QNearFieldTarget::ChecksumMismatchError:
322 ui->statusBar->showMessage(text: tr(s: "Checksum mismatch"));
323 break;
324 case QNearFieldTarget::InvalidParametersError:
325 ui->statusBar->showMessage(text: tr(s: "Invalid parameters"));
326 break;
327 case QNearFieldTarget::NdefReadError:
328 ui->statusBar->showMessage(text: tr(s: "NDEF read error"));
329 break;
330 case QNearFieldTarget::NdefWriteError:
331 ui->statusBar->showMessage(text: tr(s: "NDEF write error"));
332 break;
333 default:
334 ui->statusBar->showMessage(text: tr(s: "Unknown error"));
335 }
336
337 ui->status->setStyleSheet(QString());
338 m_manager->setTargetAccessModes(QNearFieldManager::NoTargetAccess);
339 m_manager->stopTargetDetection();
340 m_request = QNearFieldTarget::RequestId();
341 }
342}
343
344void MainWindow::clearMessage()
345{
346 QWidget *scrollArea = ui->scrollAreaWidgetContents;
347
348 qDeleteAll(c: scrollArea->findChildren<QWidget *>(QStringLiteral("line-spacer")));
349 qDeleteAll(c: scrollArea->findChildren<QWidget *>(QStringLiteral("record-editor")));
350}
351
352QNdefMessage MainWindow::ndefMessage() const
353{
354 QVBoxLayout *vbox = qobject_cast<QVBoxLayout *>(object: ui->scrollAreaWidgetContents->layout());
355 if (!vbox)
356 return QNdefMessage();
357
358 QNdefMessage message;
359
360 for (int i = 0; i < vbox->count(); ++i) {
361 QWidget *widget = vbox->itemAt(i)->widget();
362
363 if (TextRecordEditor *editor = qobject_cast<TextRecordEditor *>(object: widget)) {
364 message.append(t: editor->record());
365 } else if (UriRecordEditor *editor = qobject_cast<UriRecordEditor *>(object: widget)) {
366 message.append(t: editor->record());
367 } else if (MimeImageRecordEditor *editor = qobject_cast<MimeImageRecordEditor *>(object: widget)) {
368 message.append(t: editor->record());
369 } else if (qobject_cast<EmptyRecordLabel *>(object: widget)) {
370 message.append(t: QNdefRecord());
371 } else if (UnknownRecordLabel *label = qobject_cast<UnknownRecordLabel *>(object: widget)) {
372 message.append(t: label->record());
373 }
374 }
375
376 return message;
377}
378
379#include "mainwindow.moc"
380

source code of qtconnectivity/examples/nfc/ndefeditor/mainwindow.cpp