Qt 5.9 | Qt Bluetooth | Bluetooth File Transfer Example | remoteselector.cpp Example File

Qt 5.9.9 Reference Documentation

# remoteselector.cpp Example File

btfiletransfer/remoteselector.cpp

      /****************************************************************************
      **
      ** Copyright (C) 2017 The Qt Company Ltd.
      ** Contact: https://www.qt.io/licensing/
      **
      ** This file is part of the QtBluetooth 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 "remoteselector.h"
      #include "ui_remoteselector.h"

      #include <qbluetoothdeviceinfo.h>
      #include <qbluetoothaddress.h>
      #include <qbluetoothtransferrequest.h>
      #include <qbluetoothtransferreply.h>
      #include <qbluetoothlocaldevice.h>

      #include <QMovie>
      #include <QMessageBox>
      #include <QFileDialog>
      #include <QCheckBox>

      #include "progress.h"
      #include "pindisplay.h"

      QT_USE_NAMESPACE

      RemoteSelector::RemoteSelector(QWidget *parent)
      :   QDialog(parent), ui(new Ui::RemoteSelector),
          m_localDevice(new QBluetoothLocalDevice), m_pindisplay(0),
          m_pairingError(false)
      {
          ui->setupUi(this);

          //Using default Bluetooth adapter
          QBluetoothAddress adapterAddress = m_localDevice->address();

          /*
           * In case of multiple Bluetooth adapters it is possible to
           * set which adapter will be used by providing MAC Address.
           * Example code:
           *
           * QBluetoothAddress adapterAddress("XX:XX:XX:XX:XX:XX");
           * m_discoveryAgent = new QBluetoothServiceDiscoveryAgent(adapterAddress);
           */

          m_discoveryAgent = new QBluetoothServiceDiscoveryAgent(adapterAddress);

          connect(m_discoveryAgent, SIGNAL(serviceDiscovered(QBluetoothServiceInfo)),
                  this, SLOT(serviceDiscovered(QBluetoothServiceInfo)));
          connect(m_discoveryAgent, SIGNAL(finished()), this, SLOT(discoveryFinished()));
          connect(m_discoveryAgent, SIGNAL(canceled()), this, SLOT(discoveryFinished()));

          ui->remoteDevices->setColumnWidth(3, 75);
          ui->remoteDevices->setColumnWidth(4, 100);

          connect(m_localDevice, SIGNAL(pairingDisplayPinCode(QBluetoothAddress,QString)),
                  this, SLOT(displayPin(QBluetoothAddress,QString)));
          connect(m_localDevice, SIGNAL(pairingDisplayConfirmation(QBluetoothAddress,QString)),
                  this, SLOT(displayConfirmation(QBluetoothAddress,QString)));
          connect(m_localDevice, SIGNAL(pairingFinished(QBluetoothAddress,QBluetoothLocalDevice::Pairing)),
                  this, SLOT(pairingFinished(QBluetoothAddress,QBluetoothLocalDevice::Pairing)));
          connect(m_localDevice, SIGNAL(error(QBluetoothLocalDevice::Error)),
                  this, SLOT(pairingError(QBluetoothLocalDevice::Error)));

          ui->busyWidget->setMovie(new QMovie(":/icons/busy.gif"));
          ui->busyWidget->movie()->start();

          ui->pairingBusy->setMovie(new QMovie(":/icons/pairing.gif"));
          ui->pairingBusy->hide();

          ui->remoteDevices->clearContents();
          ui->remoteDevices->setRowCount(0);
      }

      RemoteSelector::~RemoteSelector()
      {
          delete ui;
          delete m_discoveryAgent;
          delete m_localDevice;
      }

      void RemoteSelector::startDiscovery(const QBluetoothUuid &uuid)
      {
          ui->stopButton->setDisabled(false);
          if (m_discoveryAgent->isActive())
              m_discoveryAgent->stop();

          m_discoveryAgent->setUuidFilter(uuid);
          m_discoveryAgent->start();

          if (!m_discoveryAgent->isActive() ||
                  m_discoveryAgent->error() != QBluetoothServiceDiscoveryAgent::NoError) {
              ui->status->setText(tr("Cannot find remote services."));
          } else {
              ui->status->setText(tr("Scanning..."));
              ui->busyWidget->show();
              ui->busyWidget->movie()->start();
          }
      }

      QBluetoothServiceInfo RemoteSelector::service() const
      {
          return m_service;
      }

      void RemoteSelector::serviceDiscovered(const QBluetoothServiceInfo &serviceInfo)
      {
      #if 0
          qDebug() << "Discovered service on"
                   << serviceInfo.device().name() << serviceInfo.device().address().toString();
          qDebug() << "\tService name:" << serviceInfo.serviceName();
          qDebug() << "\tDescription:"
                   << serviceInfo.attribute(QBluetoothServiceInfo::ServiceDescription).toString();
          qDebug() << "\tProvider:"
                   << serviceInfo.attribute(QBluetoothServiceInfo::ServiceProvider).toString();
          qDebug() << "\tL2CAP protocol service multiplexer:"
                   << serviceInfo.protocolServiceMultiplexer();
          qDebug() << "\tRFCOMM server channel:" << serviceInfo.serverChannel();
      #endif

          QString remoteName;
          if (serviceInfo.device().name().isEmpty())
              remoteName = serviceInfo.device().address().toString();
          else
              remoteName = serviceInfo.device().name();

      //    QListWidgetItem *item =
      //        new QListWidgetItem(QString::fromLatin1("%1\t%2\t%3").arg(serviceInfo.device().address().toString(),
      //                                                             serviceInfo.device().name(), serviceInfo.serviceName()));

          QMutableMapIterator<int, QBluetoothServiceInfo> i(m_discoveredServices);
          while (i.hasNext()){
              i.next();
              if (serviceInfo.device().address() == i.value().device().address()){
                  i.setValue(serviceInfo);
                  return;
              }
          }

          int row = ui->remoteDevices->rowCount();
          ui->remoteDevices->insertRow(row);
          QTableWidgetItem *item = new QTableWidgetItem(serviceInfo.device().address().toString());
          ui->remoteDevices->setItem(row, 0, item);
          item = new QTableWidgetItem(serviceInfo.device().name());
          ui->remoteDevices->setItem(row, 1, item);
          item = new QTableWidgetItem(serviceInfo.serviceName());

          ui->remoteDevices->setItem(row, 2, item);

          QBluetoothLocalDevice::Pairing p;

          p = m_localDevice->pairingStatus(serviceInfo.device().address());

          ui->remoteDevices->blockSignals(true);

          item = new QTableWidgetItem();
          if ((p&QBluetoothLocalDevice::Paired) || (p&QBluetoothLocalDevice::AuthorizedPaired))
              item->setCheckState(Qt::Checked);
          else
              item->setCheckState(Qt::Unchecked);
          ui->remoteDevices->setItem(row, 3, item);

          item = new QTableWidgetItem();
          if (p&QBluetoothLocalDevice::AuthorizedPaired)
              item->setCheckState(Qt::Checked);
          else
              item->setCheckState(Qt::Unchecked);

          ui->remoteDevices->setItem(row, 4, item);

          ui->remoteDevices->blockSignals(false);

          m_discoveredServices.insert(row, serviceInfo);
      }

      void RemoteSelector::discoveryFinished()
      {
          ui->status->setText(tr("Select the device to send to."));
          ui->stopButton->setDisabled(true);
          ui->busyWidget->movie()->stop();
          ui->busyWidget->hide();
      }

      void RemoteSelector::startDiscovery()
      {
          startDiscovery(QBluetoothUuid(QBluetoothUuid::ObexObjectPush));
      }

      void RemoteSelector::on_refreshPB_clicked()
      {
          startDiscovery();
          ui->stopButton->setDisabled(false);
      }

      void RemoteSelector::on_fileSelectPB_clicked()
      {
          ui->fileName->setText(QFileDialog::getOpenFileName());
          if (m_service.isValid())
              ui->sendButton->setDisabled(false);
      }

      void RemoteSelector::on_sendButton_clicked()
      {
          QBluetoothTransferManager mgr;
          QBluetoothTransferRequest req(m_service.device().address());

          m_file = new QFile(ui->fileName->text());

          Progress *p = new Progress;
          p->setStatus("Sending to: " + m_service.device().name(), "Waiting for start");
          p->show();

          QBluetoothTransferReply *reply = mgr.put(req, m_file);
          //mgr is default parent
          //ensure that mgr doesn't take reply down when leaving scope
          reply->setParent(this);
          if (reply->error()){
              qDebug() << "Failed to send file";
              p->finished(reply);
              reply->deleteLater();
              return;
          }

          connect(reply, SIGNAL(transferProgress(qint64,qint64)), p, SLOT(uploadProgress(qint64,qint64)));
          connect(reply, SIGNAL(finished(QBluetoothTransferReply*)), p, SLOT(finished(QBluetoothTransferReply*)));
          connect(p, SIGNAL(rejected()), reply, SLOT(abort()));
      }

      void RemoteSelector::on_stopButton_clicked()
      {
          m_discoveryAgent->stop();
      }

      QString RemoteSelector::addressToName(const QBluetoothAddress &address)
      {
          QMapIterator<int, QBluetoothServiceInfo> i(m_discoveredServices);
          while (i.hasNext()){
              i.next();
              if (i.value().device().address() == address)
                  return i.value().device().name();
          }
          return address.toString();
      }

      void RemoteSelector::displayPin(const QBluetoothAddress &address, QString pin)
      {
          if (m_pindisplay)
              m_pindisplay->deleteLater();
          m_pindisplay = new pinDisplay(QString("Enter pairing pin on: %1").arg(addressToName(address)), pin, this);
          m_pindisplay->show();
      }

      void RemoteSelector::displayConfirmation(const QBluetoothAddress &address, QString pin)
      {
          Q_UNUSED(address);

          if (m_pindisplay)
              m_pindisplay->deleteLater();
          m_pindisplay = new pinDisplay(QString("Confirm this pin is the same"), pin, this);
          connect(m_pindisplay, SIGNAL(accepted()), this, SLOT(displayConfAccepted()));
          connect(m_pindisplay, SIGNAL(rejected()), this, SLOT(displayConfReject()));
          m_pindisplay->setOkCancel();
          m_pindisplay->show();
      }

      void RemoteSelector::displayConfAccepted()
      {
          m_localDevice->pairingConfirmation(true);
      }
      void RemoteSelector::displayConfReject()
      {
          m_localDevice->pairingConfirmation(false);
      }

      void RemoteSelector::pairingFinished(const QBluetoothAddress &address, QBluetoothLocalDevice::Pairing status)
      {
          QBluetoothServiceInfo service;
          int row = 0;

          ui->pairingBusy->hide();
          ui->pairingBusy->movie()->stop();

          ui->remoteDevices->blockSignals(true);

          for (int i = 0; i < m_discoveredServices.count(); i++){
              if (m_discoveredServices.value(i).device().address() == address){
                  service = m_discoveredServices.value(i);
                  row = i;
                  break;
              }
          }

          if (m_pindisplay)
              delete m_pindisplay;

          QMessageBox msgBox;
          if (m_pairingError) {
              msgBox.setText("Pairing failed with " + address.toString());
          } else if (status == QBluetoothLocalDevice::Paired
                     || status == QBluetoothLocalDevice::AuthorizedPaired) {
              msgBox.setText("Paired successfully with " + address.toString());
          } else {
              msgBox.setText("Pairing released with " + address.toString());
          }

          if (service.isValid()){
              if (status == QBluetoothLocalDevice::AuthorizedPaired){
                  ui->remoteDevices->item(row, 3)->setCheckState(Qt::Checked);
                  ui->remoteDevices->item(row, 4)->setCheckState(Qt::Checked);
              }
              else if (status == QBluetoothLocalDevice::Paired){
                  ui->remoteDevices->item(row, 3)->setCheckState(Qt::Checked);
                  ui->remoteDevices->item(row, 4)->setCheckState(Qt::Unchecked);
              }
              else {
                  ui->remoteDevices->item(row, 3)->setCheckState(Qt::Unchecked);
                  ui->remoteDevices->item(row, 4)->setCheckState(Qt::Unchecked);
              }
          }

          m_pairingError = false;
          msgBox.exec();

          ui->remoteDevices->blockSignals(false);
      }

      void RemoteSelector::pairingError(QBluetoothLocalDevice::Error error)
      {
          if (error != QBluetoothLocalDevice::PairingError)
              return;

          m_pairingError = true;
          pairingFinished(m_service.device().address(), QBluetoothLocalDevice::Unpaired);
      }

      void RemoteSelector::on_remoteDevices_cellClicked(int row, int column)
      {
          Q_UNUSED(column);

          m_service = m_discoveredServices.value(row);
          if (!ui->fileName->text().isEmpty()) {
              ui->sendButton->setDisabled(false);
          }
      }

      void RemoteSelector::on_remoteDevices_itemChanged(QTableWidgetItem* item)
      {
          int row = item->row();
          int column = item->column();
          m_service = m_discoveredServices.value(row);

          if (column < 3)
              return;

          if (item->checkState() == Qt::Unchecked && column == 3){
              m_localDevice->requestPairing(m_service.device().address(), QBluetoothLocalDevice::Unpaired);
              return; // don't continue and start movie
          }
          else if ((item->checkState() == Qt::Checked && column == 3) ||
                  (item->checkState() == Qt::Unchecked && column == 4)){
              m_localDevice->requestPairing(m_service.device().address(), QBluetoothLocalDevice::Paired);
              ui->remoteDevices->blockSignals(true);
              ui->remoteDevices->item(row, column)->setCheckState(Qt::PartiallyChecked);
              ui->remoteDevices->blockSignals(false);
          }
          else if (item->checkState() == Qt::Checked && column == 4){
              m_localDevice->requestPairing(m_service.device().address(), QBluetoothLocalDevice::AuthorizedPaired);
              ui->remoteDevices->blockSignals(true);
              ui->remoteDevices->item(row, column)->setCheckState(Qt::PartiallyChecked);
              ui->remoteDevices->blockSignals(false);
          }
          ui->pairingBusy->show();
          ui->pairingBusy->movie()->start();
      }