- Qt 5.5
- Qt Bluetooth
- Bluetooth File Transfer Example
- remoteselector.cpp Example File
- Qt 5.5.1 Reference Documentation

# remoteselector.cpp Example File

btfiletransfer/remoteselector.cpp

    /****************************************************************************
    **
    ** Copyright (C) 2015 The Qt Company Ltd.
    ** Contact: http://www.qt.io/licensing/
    **
    ** This file is part of the QtBluetooth module of the Qt Toolkit.
    **
    ** $QT_BEGIN_LICENSE:BSD$
    ** 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();
    }