| /**************************************************************************** |
| ** |
| ** Copyright (C) 2017 The Qt Company Ltd. |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** This file is part of the QtNfc module of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:BSD$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** BSD License Usage |
| ** Alternatively, you may use this file under the terms of the BSD license |
| ** as follows: |
| ** |
| ** "Redistribution and use in source and binary forms, with or without |
| ** modification, are permitted provided that the following conditions are |
| ** met: |
| ** * Redistributions of source code must retain the above copyright |
| ** notice, this list of conditions and the following disclaimer. |
| ** * Redistributions in binary form must reproduce the above copyright |
| ** notice, this list of conditions and the following disclaimer in |
| ** the documentation and/or other materials provided with the |
| ** distribution. |
| ** * Neither the name of The Qt Company Ltd nor the names of its |
| ** contributors may be used to endorse or promote products derived |
| ** from this software without specific prior written permission. |
| ** |
| ** |
| ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #include "mainwindow.h" |
| #include "ui_mainwindow.h" |
| |
| #include "textrecordeditor.h" |
| #include "urirecordeditor.h" |
| #include "mimeimagerecordeditor.h" |
| |
| #include <QtNfc/qndefnfcurirecord.h> |
| #include <QtNfc/qndefnfctextrecord.h> |
| #include <QtNfc/qndefrecord.h> |
| #include <QtNfc/qndefmessage.h> |
| #include <QtNfc/qnearfieldmanager.h> |
| #include <QtNfc/qnearfieldtarget.h> |
| |
| #include <QtWidgets/QMenu> |
| #include <QtWidgets/QVBoxLayout> |
| #include <QtWidgets/QFrame> |
| #include <QtWidgets/QLabel> |
| #include <QtWidgets/QFileDialog> |
| |
| class EmptyRecordLabel : public QLabel |
| { |
| Q_OBJECT |
| |
| public: |
| EmptyRecordLabel() : QLabel(tr("Empty Record")) { } |
| ~EmptyRecordLabel() { } |
| |
| void setRecord(const QNdefRecord &record) |
| { |
| Q_UNUSED(record); |
| } |
| |
| QNdefRecord record() const |
| { |
| return QNdefRecord(); |
| } |
| }; |
| |
| class UnknownRecordLabel : public QLabel |
| { |
| Q_OBJECT |
| |
| public: |
| UnknownRecordLabel() : QLabel(tr("Unknown Record Type")) { } |
| ~UnknownRecordLabel() { } |
| |
| void setRecord(const QNdefRecord &record) { m_record = record; } |
| QNdefRecord record() const { return m_record; } |
| |
| private: |
| QNdefRecord m_record; |
| }; |
| |
| template <typename T> |
| void addRecord(Ui::MainWindow *ui, const QNdefRecord &record = QNdefRecord()) |
| { |
| QVBoxLayout *vbox = qobject_cast<QVBoxLayout *>(ui->scrollAreaWidgetContents->layout()); |
| if (!vbox) |
| return; |
| |
| if (!vbox->isEmpty()) { |
| QFrame *hline = new QFrame; |
| hline->setFrameShape(QFrame::HLine); |
| hline->setObjectName(QStringLiteral("line-spacer")); |
| |
| vbox->addWidget(hline); |
| } |
| |
| T *recordEditor = new T; |
| recordEditor->setObjectName(QStringLiteral("record-editor")); |
| |
| if (!record.isEmpty()) |
| recordEditor->setRecord(record); |
| |
| vbox->addWidget(recordEditor); |
| } |
| |
| MainWindow::MainWindow(QWidget *parent) |
| : QMainWindow(parent), ui(new Ui::MainWindow), m_touchAction(NoAction) |
| { |
| ui->setupUi(this); |
| |
| QMenu *addRecordMenu = new QMenu(this); |
| addRecordMenu->addAction(tr("NFC Text Record"), this, SLOT(addNfcTextRecord())); |
| addRecordMenu->addAction(tr("NFC URI Record"), this, SLOT(addNfcUriRecord())); |
| addRecordMenu->addAction(tr("MIME Image Record"), this, SLOT(addMimeImageRecord())); |
| addRecordMenu->addAction(tr("Empty Record"), this, SLOT(addEmptyRecord())); |
| ui->addRecord->setMenu(addRecordMenu); |
| |
| QVBoxLayout *vbox = new QVBoxLayout; |
| ui->scrollAreaWidgetContents->setLayout(vbox); |
| |
| //! [QNearFieldManager init] |
| m_manager = new QNearFieldManager(this); |
| connect(m_manager, &QNearFieldManager::targetDetected, |
| this, &MainWindow::targetDetected); |
| connect(m_manager, &QNearFieldManager::targetLost, |
| this, &MainWindow::targetLost); |
| //! [QNearFieldManager init] |
| } |
| |
| MainWindow::~MainWindow() |
| { |
| delete ui; |
| } |
| |
| void MainWindow::addNfcTextRecord() |
| { |
| addRecord<TextRecordEditor>(ui); |
| } |
| |
| void MainWindow::addNfcUriRecord() |
| { |
| addRecord<UriRecordEditor>(ui); |
| } |
| |
| void MainWindow::addMimeImageRecord() |
| { |
| addRecord<MimeImageRecordEditor>(ui); |
| } |
| |
| void MainWindow::addEmptyRecord() |
| { |
| addRecord<EmptyRecordLabel>(ui); |
| } |
| |
| void MainWindow::loadMessage() |
| { |
| QString filename = QFileDialog::getOpenFileName(this, tr("Select NDEF Message")); |
| if (filename.isEmpty()) |
| return; |
| |
| QFile file(filename); |
| if (!file.open(QIODevice::ReadOnly)) |
| return; |
| |
| QByteArray ndef = file.readAll(); |
| |
| ndefMessageRead(QNdefMessage::fromByteArray(ndef)); |
| |
| file.close(); |
| } |
| |
| void MainWindow::saveMessage() |
| { |
| QString filename = QFileDialog::getSaveFileName(this, tr("Select NDEF Message")); |
| if (filename.isEmpty()) |
| return; |
| |
| QFile file(filename); |
| if (!file.open(QIODevice::WriteOnly)) |
| return; |
| |
| file.write(ndefMessage().toByteArray()); |
| |
| file.close(); |
| } |
| |
| void MainWindow::touchReceive() |
| { |
| ui->status->setStyleSheet(QStringLiteral("background: blue")); |
| |
| m_touchAction = ReadNdef; |
| |
| m_manager->setTargetAccessModes(QNearFieldManager::NdefReadTargetAccess); |
| //! [QNearFieldManager start detection] |
| m_manager->startTargetDetection(); |
| //! [QNearFieldManager start detection] |
| } |
| |
| void MainWindow::touchStore() |
| { |
| ui->status->setStyleSheet(QStringLiteral("background: yellow")); |
| |
| m_touchAction = WriteNdef; |
| |
| m_manager->setTargetAccessModes(QNearFieldManager::NdefWriteTargetAccess); |
| m_manager->startTargetDetection(); |
| } |
| |
| //! [QNearFieldTarget detected] |
| void MainWindow::targetDetected(QNearFieldTarget *target) |
| { |
| switch (m_touchAction) { |
| case NoAction: |
| break; |
| case ReadNdef: |
| connect(target, &QNearFieldTarget::ndefMessageRead, this, &MainWindow::ndefMessageRead); |
| connect(target, &QNearFieldTarget::error, this, &MainWindow::targetError); |
| |
| m_request = target->readNdefMessages(); |
| if (!m_request.isValid()) // cannot read messages |
| targetError(QNearFieldTarget::NdefReadError, m_request); |
| break; |
| case WriteNdef: |
| connect(target, &QNearFieldTarget::ndefMessagesWritten, this, &MainWindow::ndefMessageWritten); |
| connect(target, &QNearFieldTarget::error, this, &MainWindow::targetError); |
| |
| m_request = target->writeNdefMessages(QList<QNdefMessage>() << ndefMessage()); |
| if (!m_request.isValid()) // cannot write messages |
| targetError(QNearFieldTarget::NdefWriteError, m_request); |
| break; |
| } |
| } |
| //! [QNearFieldTarget detected] |
| |
| //! [QNearFieldTarget lost] |
| void MainWindow::targetLost(QNearFieldTarget *target) |
| { |
| target->deleteLater(); |
| } |
| //! [QNearFieldTarget lost] |
| |
| void MainWindow::ndefMessageRead(const QNdefMessage &message) |
| { |
| clearMessage(); |
| |
| for (const QNdefRecord &record : message) { |
| if (record.isRecordType<QNdefNfcTextRecord>()) { |
| addRecord<TextRecordEditor>(ui, record); |
| } else if (record.isRecordType<QNdefNfcUriRecord>()) { |
| addRecord<UriRecordEditor>(ui, record); |
| } else if (record.typeNameFormat() == QNdefRecord::Mime && |
| record.type().startsWith("image/")) { |
| addRecord<MimeImageRecordEditor>(ui, record); |
| } else if (record.isEmpty()) { |
| addRecord<EmptyRecordLabel>(ui); |
| } else { |
| addRecord<UnknownRecordLabel>(ui, record); |
| } |
| } |
| |
| ui->status->setStyleSheet(QString()); |
| m_manager->setTargetAccessModes(QNearFieldManager::NoTargetAccess); |
| //! [QNearFieldManager stop detection] |
| m_manager->stopTargetDetection(); |
| //! [QNearFieldManager stop detection] |
| m_request = QNearFieldTarget::RequestId(); |
| ui->statusBar->clearMessage(); |
| } |
| |
| void MainWindow::ndefMessageWritten() |
| { |
| ui->status->setStyleSheet(QString()); |
| m_manager->setTargetAccessModes(QNearFieldManager::NoTargetAccess); |
| m_manager->stopTargetDetection(); |
| m_request = QNearFieldTarget::RequestId(); |
| ui->statusBar->clearMessage(); |
| } |
| |
| void MainWindow::targetError(QNearFieldTarget::Error error, const QNearFieldTarget::RequestId &id) |
| { |
| Q_UNUSED(error); |
| Q_UNUSED(id); |
| |
| if (m_request == id) { |
| switch (error) { |
| case QNearFieldTarget::NoError: |
| ui->statusBar->clearMessage(); |
| break; |
| case QNearFieldTarget::UnsupportedError: |
| ui->statusBar->showMessage(tr("Unsupported tag")); |
| break; |
| case QNearFieldTarget::TargetOutOfRangeError: |
| ui->statusBar->showMessage(tr("Tag removed from field")); |
| break; |
| case QNearFieldTarget::NoResponseError: |
| ui->statusBar->showMessage(tr("No response from tag")); |
| break; |
| case QNearFieldTarget::ChecksumMismatchError: |
| ui->statusBar->showMessage(tr("Checksum mismatch")); |
| break; |
| case QNearFieldTarget::InvalidParametersError: |
| ui->statusBar->showMessage(tr("Invalid parameters")); |
| break; |
| case QNearFieldTarget::NdefReadError: |
| ui->statusBar->showMessage(tr("NDEF read error")); |
| break; |
| case QNearFieldTarget::NdefWriteError: |
| ui->statusBar->showMessage(tr("NDEF write error")); |
| break; |
| default: |
| ui->statusBar->showMessage(tr("Unknown error")); |
| } |
| |
| ui->status->setStyleSheet(QString()); |
| m_manager->setTargetAccessModes(QNearFieldManager::NoTargetAccess); |
| m_manager->stopTargetDetection(); |
| m_request = QNearFieldTarget::RequestId(); |
| } |
| } |
| |
| void MainWindow::clearMessage() |
| { |
| QWidget *scrollArea = ui->scrollAreaWidgetContents; |
| |
| qDeleteAll(scrollArea->findChildren<QWidget *>(QStringLiteral("line-spacer"))); |
| qDeleteAll(scrollArea->findChildren<QWidget *>(QStringLiteral("record-editor"))); |
| } |
| |
| QNdefMessage MainWindow::ndefMessage() const |
| { |
| QVBoxLayout *vbox = qobject_cast<QVBoxLayout *>(ui->scrollAreaWidgetContents->layout()); |
| if (!vbox) |
| return QNdefMessage(); |
| |
| QNdefMessage message; |
| |
| for (int i = 0; i < vbox->count(); ++i) { |
| QWidget *widget = vbox->itemAt(i)->widget(); |
| |
| if (TextRecordEditor *editor = qobject_cast<TextRecordEditor *>(widget)) { |
| message.append(editor->record()); |
| } else if (UriRecordEditor *editor = qobject_cast<UriRecordEditor *>(widget)) { |
| message.append(editor->record()); |
| } else if (MimeImageRecordEditor *editor = qobject_cast<MimeImageRecordEditor *>(widget)) { |
| message.append(editor->record()); |
| } else if (qobject_cast<EmptyRecordLabel *>(widget)) { |
| message.append(QNdefRecord()); |
| } else if (UnknownRecordLabel *label = qobject_cast<UnknownRecordLabel *>(widget)) { |
| message.append(label->record()); |
| } |
| } |
| |
| return message; |
| } |
| |
| #include "mainwindow.moc" |