/**************************************************************************** ** ** 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 "chat.h" #include "remoteselector.h" #include "chatserver.h" #include "chatclient.h" #include #include #include #include #include #ifdef Q_OS_ANDROID #include #endif #include #include static const QLatin1String serviceUuid("e8e10f95-1a70-4b27-9ccf-02010264e9c8"); #ifdef Q_OS_ANDROID static const QLatin1String reverseUuid("c8e96402-0102-cf9c-274b-701a950fe1e8"); #endif Chat::Chat(QWidget *parent) : QDialog(parent), currentAdapterIndex(0), ui(new Ui_Chat) { //! [Construct UI] ui->setupUi(this); connect(ui->quitButton, SIGNAL(clicked()), this, SLOT(accept())); connect(ui->connectButton, SIGNAL(clicked()), this, SLOT(connectClicked())); connect(ui->sendButton, SIGNAL(clicked()), this, SLOT(sendClicked())); //! [Construct UI] localAdapters = QBluetoothLocalDevice::allDevices(); if (localAdapters.count() < 2) { ui->localAdapterBox->setVisible(false); } else { //we ignore more than two adapters ui->localAdapterBox->setVisible(true); ui->firstAdapter->setText(tr("Default (%1)", "%1 = Bluetooth address"). arg(localAdapters.at(0).address().toString())); ui->secondAdapter->setText(localAdapters.at(1).address().toString()); ui->firstAdapter->setChecked(true); connect(ui->firstAdapter, SIGNAL(clicked()), this, SLOT(newAdapterSelected())); connect(ui->secondAdapter, SIGNAL(clicked()), this, SLOT(newAdapterSelected())); QBluetoothLocalDevice adapter(localAdapters.at(0).address()); adapter.setHostMode(QBluetoothLocalDevice::HostDiscoverable); } //! [Create Chat Server] server = new ChatServer(this); connect(server, SIGNAL(clientConnected(QString)), this, SLOT(clientConnected(QString))); connect(server, SIGNAL(clientDisconnected(QString)), this, SLOT(clientDisconnected(QString))); connect(server, SIGNAL(messageReceived(QString,QString)), this, SLOT(showMessage(QString,QString))); connect(this, SIGNAL(sendMessage(QString)), server, SLOT(sendMessage(QString))); server->startServer(); //! [Create Chat Server] //! [Get local device name] localName = QBluetoothLocalDevice().name(); //! [Get local device name] } Chat::~Chat() { qDeleteAll(clients); delete server; } //! [clientConnected clientDisconnected] void Chat::clientConnected(const QString &name) { ui->chat->insertPlainText(QString::fromLatin1("%1 has joined chat.\n").arg(name)); } void Chat::clientDisconnected(const QString &name) { ui->chat->insertPlainText(QString::fromLatin1("%1 has left.\n").arg(name)); } //! [clientConnected clientDisconnected] //! [connected] void Chat::connected(const QString &name) { ui->chat->insertPlainText(QString::fromLatin1("Joined chat with %1.\n").arg(name)); } void Chat::newAdapterSelected() { const int newAdapterIndex = adapterFromUserSelection(); if (currentAdapterIndex != newAdapterIndex) { server->stopServer(); currentAdapterIndex = newAdapterIndex; const QBluetoothHostInfo info = localAdapters.at(currentAdapterIndex); QBluetoothLocalDevice adapter(info.address()); adapter.setHostMode(QBluetoothLocalDevice::HostDiscoverable); server->startServer(info.address()); localName = info.name(); } } int Chat::adapterFromUserSelection() const { int result = 0; QBluetoothAddress newAdapter = localAdapters.at(0).address(); if (ui->secondAdapter->isChecked()) { newAdapter = localAdapters.at(1).address(); result = 1; } return result; } //! [connected] //! [clientDisconnected] void Chat::clientDisconnected() { ChatClient *client = qobject_cast(sender()); if (client) { clients.removeOne(client); client->deleteLater(); } } //! [clientDisconnected] //! [Connect to remote service] void Chat::connectClicked() { ui->connectButton->setEnabled(false); // scan for services const QBluetoothAddress adapter = localAdapters.isEmpty() ? QBluetoothAddress() : localAdapters.at(currentAdapterIndex).address(); RemoteSelector remoteSelector(adapter); #ifdef Q_OS_ANDROID if (QtAndroid::androidSdkVersion() >= 23) remoteSelector.startDiscovery(QBluetoothUuid(reverseUuid)); else remoteSelector.startDiscovery(QBluetoothUuid(serviceUuid)); #else remoteSelector.startDiscovery(QBluetoothUuid(serviceUuid)); #endif if (remoteSelector.exec() == QDialog::Accepted) { QBluetoothServiceInfo service = remoteSelector.service(); qDebug() << "Connecting to service 2" << service.serviceName() << "on" << service.device().name(); // Create client qDebug() << "Going to create client"; ChatClient *client = new ChatClient(this); qDebug() << "Connecting..."; connect(client, SIGNAL(messageReceived(QString,QString)), this, SLOT(showMessage(QString,QString))); connect(client, SIGNAL(disconnected()), this, SLOT(clientDisconnected())); connect(client, SIGNAL(connected(QString)), this, SLOT(connected(QString))); connect(this, SIGNAL(sendMessage(QString)), client, SLOT(sendMessage(QString))); qDebug() << "Start client"; client->startClient(service); clients.append(client); } ui->connectButton->setEnabled(true); } //! [Connect to remote service] //! [sendClicked] void Chat::sendClicked() { ui->sendButton->setEnabled(false); ui->sendText->setEnabled(false); showMessage(localName, ui->sendText->text()); emit sendMessage(ui->sendText->text()); ui->sendText->clear(); ui->sendText->setEnabled(true); ui->sendButton->setEnabled(true); } //! [sendClicked] //! [showMessage] void Chat::showMessage(const QString &sender, const QString &message) { ui->chat->insertPlainText(QString::fromLatin1("%1: %2\n").arg(sender, message)); ui->chat->ensureCursorVisible(); } //! [showMessage]