diff options
author | Jerome Pasion <jerome.pasion@digia.com> | 2012-09-25 15:20:41 +0200 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2012-09-27 14:43:52 +0200 |
commit | d8a179128c0fa8e9cc482df58b9334c696602be6 (patch) | |
tree | dd5032440aa87dfd63c973265adc9947db0918f6 /examples/bluetooth | |
parent | 9d89c661395347bdda9362a77d38c86ad60f486b (diff) |
Qt Bluetooth: Modularized documentation
-moved documentation to src/bluetooth/doc
-added a qdocconf file for Qt Bluetooth
-fixed relative paths for snippets
-moved examples to examples/bluetooth
Change-Id: Id41bac50dca628400568d191f1c3ccfbaac790a1
Reviewed-by: Alex <ablasche@gmail.com>
Diffstat (limited to 'examples/bluetooth')
66 files changed, 6305 insertions, 0 deletions
diff --git a/examples/bluetooth/bluetooth.pro b/examples/bluetooth/bluetooth.pro new file mode 100644 index 00000000..20bf6c6d --- /dev/null +++ b/examples/bluetooth/bluetooth.pro @@ -0,0 +1,9 @@ +TEMPLATE = subdirs +!contains(QT_CONFIG, no-widgets) { + SUBDIRS += btchat \ + btscanner \ + btfiletransfer \ + bttennis +} + +SUBDIRS += scanner diff --git a/examples/bluetooth/btchat/btchat.pro b/examples/bluetooth/btchat/btchat.pro new file mode 100644 index 00000000..f215cb87 --- /dev/null +++ b/examples/bluetooth/btchat/btchat.pro @@ -0,0 +1,21 @@ +TEMPLATE = app +TARGET = btchat + +QT += concurrent bluetooth widgets + +SOURCES = \ + main.cpp \ + chat.cpp \ + remoteselector.cpp \ + chatserver.cpp \ + chatclient.cpp + +HEADERS = \ + chat.h \ + remoteselector.h \ + chatserver.h \ + chatclient.h + +FORMS = \ + chat.ui \ + remoteselector.ui diff --git a/examples/bluetooth/btchat/chat.cpp b/examples/bluetooth/btchat/chat.cpp new file mode 100644 index 00000000..7047cbdd --- /dev/null +++ b/examples/bluetooth/btchat/chat.cpp @@ -0,0 +1,179 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia Plc and its Subsidiary(-ies) 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 <qbluetoothuuid.h> +#include <qrfcommserver.h> +#include <qbluetoothservicediscoveryagent.h> +#include <qbluetoothdeviceinfo.h> +#include <qbluetoothlocaldevice.h> + +#include <QTimer> + +#include <QDebug> + +static const QLatin1String serviceUuid("e8e10f95-1a70-4b27-9ccf-02010264e9c8"); + +Chat::Chat(QWidget *parent) +: QDialog(parent), ui(new Ui_Chat) +{ + //! [Construct UI] + ui->setupUi(this); + +#if defined(Q_OS_WINCE) || defined(Q_WS_MAEMO_6) + setWindowState(Qt::WindowFullScreen); +#endif + + 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] + + //! [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)); +} +//! [connected] + +//! [clientDisconnected] +void Chat::clientDisconnected() +{ + ChatClient *client = qobject_cast<ChatClient *>(sender()); + if (client) { + clients.removeOne(client); + client->deleteLater(); + } +} +//! [clientDisconnected] + +//! [Connect to remote service] +void Chat::connectClicked() +{ + ui->connectButton->setEnabled(false); + + // scan for services + RemoteSelector remoteSelector; + remoteSelector.startDiscovery(QBluetoothUuid(serviceUuid)); + 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)); +} +//! [showMessage] diff --git a/examples/bluetooth/btchat/chat.h b/examples/bluetooth/btchat/chat.h new file mode 100644 index 00000000..740999d0 --- /dev/null +++ b/examples/bluetooth/btchat/chat.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia Plc and its Subsidiary(-ies) 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 "ui_chat.h" + +#include <QDialog> + +#include <qbluetoothserviceinfo.h> +#include <qbluetoothsocket.h> + +#include <QDebug> + +QTBLUETOOTH_BEGIN_NAMESPACE +class QRfcommServer; +QTBLUETOOTH_END_NAMESPACE + +QTBLUETOOTH_USE_NAMESPACE + +class ChatServer; +class ChatClient; + +//! [declaration] +class Chat : public QDialog +{ + Q_OBJECT + +public: + Chat(QWidget *parent = 0); + ~Chat(); + +signals: + void sendMessage(const QString &message); + +private slots: + void connectClicked(); + void sendClicked(); + + void showMessage(const QString &sender, const QString &message); + + void clientConnected(const QString &name); + void clientDisconnected(const QString &name); + void clientDisconnected(); + void connected(const QString &name); + +private: + Ui_Chat *ui; + + ChatServer *server; + QList<ChatClient *> clients; + + QString localName; +}; +//! [declaration] diff --git a/examples/bluetooth/btchat/chat.ui b/examples/bluetooth/btchat/chat.ui new file mode 100644 index 00000000..acebc937 --- /dev/null +++ b/examples/bluetooth/btchat/chat.ui @@ -0,0 +1,76 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>Chat</class> + <widget class="QDialog" name="Chat"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>300</height> + </rect> + </property> + <property name="windowTitle"> + <string>Bluetooth Chat</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QTextEdit" name="chat"> + <property name="focusPolicy"> + <enum>Qt::NoFocus</enum> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QLineEdit" name="sendText"/> + </item> + <item> + <widget class="QPushButton" name="sendButton"> + <property name="text"> + <string>Send</string> + </property> + <property name="default"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="connectButton"> + <property name="text"> + <string>Connect</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QPushButton" name="quitButton"> + <property name="text"> + <string>Quit</string> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/examples/bluetooth/btchat/chatclient.cpp b/examples/bluetooth/btchat/chatclient.cpp new file mode 100644 index 00000000..8ea66e51 --- /dev/null +++ b/examples/bluetooth/btchat/chatclient.cpp @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia Plc and its Subsidiary(-ies) 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 "chatclient.h" + +#include <qbluetoothsocket.h> + +ChatClient::ChatClient(QObject *parent) +: QObject(parent), socket(0) +{ +} + +ChatClient::~ChatClient() +{ + stopClient(); +} + +//! [startClient] +void ChatClient::startClient(const QBluetoothServiceInfo &remoteService) +{ + if (socket) + return; + + // Connect to service + socket = new QBluetoothSocket(QBluetoothSocket::RfcommSocket); + qDebug() << "Create socket"; + socket->connectToService(remoteService); + qDebug() << "ConnecttoService done"; + + connect(socket, SIGNAL(readyRead()), this, SLOT(readSocket())); + connect(socket, SIGNAL(connected()), this, SLOT(connected())); + connect(socket, SIGNAL(disconnected()), this, SIGNAL(disconnected())); +} +//! [startClient] + +//! [stopClient] +void ChatClient::stopClient() +{ + delete socket; + socket = 0; +} +//! [stopClient] + +//! [readSocket] +void ChatClient::readSocket() +{ + if (!socket) + return; + + while (socket->canReadLine()) { + QByteArray line = socket->readLine(); + emit messageReceived(socket->peerName(), + QString::fromUtf8(line.constData(), line.length())); + } +} +//! [readSocket] + +//! [sendMessage] +void ChatClient::sendMessage(const QString &message) +{ + QByteArray text = message.toUtf8() + '\n'; + socket->write(text); +} +//! [sendMessage] + +//! [connected] +void ChatClient::connected() +{ + emit connected(socket->peerName()); +} +//! [connected] diff --git a/examples/bluetooth/btchat/chatclient.h b/examples/bluetooth/btchat/chatclient.h new file mode 100644 index 00000000..710634e5 --- /dev/null +++ b/examples/bluetooth/btchat/chatclient.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia Plc and its Subsidiary(-ies) 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$ +** +****************************************************************************/ + +#ifndef CHATCLIENT_H +#define CHATCLIENT_H + +#include <qbluetoothserviceinfo.h> + +#include <QtCore/QObject> + +QTBLUETOOTH_BEGIN_NAMESPACE +class QBluetoothSocket; +QTBLUETOOTH_END_NAMESPACE + +QTBLUETOOTH_USE_NAMESPACE + +//! [declaration] +class ChatClient : public QObject +{ + Q_OBJECT + +public: + explicit ChatClient(QObject *parent = 0); + ~ChatClient(); + + void startClient(const QBluetoothServiceInfo &remoteService); + void stopClient(); + +public slots: + void sendMessage(const QString &message); + +signals: + void messageReceived(const QString &sender, const QString &message); + void connected(const QString &name); + void disconnected(); + +private slots: + void readSocket(); + void connected(); + +private: + QBluetoothSocket *socket; +}; +//! [declaration] + +#endif // CHATCLIENT_H diff --git a/examples/bluetooth/btchat/chatserver.cpp b/examples/bluetooth/btchat/chatserver.cpp new file mode 100644 index 00000000..545a0b03 --- /dev/null +++ b/examples/bluetooth/btchat/chatserver.cpp @@ -0,0 +1,182 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia Plc and its Subsidiary(-ies) 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 "chatserver.h" + +#include <qrfcommserver.h> +#include <qbluetoothsocket.h> + +//! [Service UUID] +static const QLatin1String serviceUuid("e8e10f95-1a70-4b27-9ccf-02010264e9c8"); +//! [Service UUID] + +ChatServer::ChatServer(QObject *parent) +: QObject(parent), rfcommServer(0) +{ +} + +ChatServer::~ChatServer() +{ + stopServer(); +} + +void ChatServer::startServer() +{ + if (rfcommServer) + return; + + //! [Create the server] + rfcommServer = new QRfcommServer(this); + connect(rfcommServer, SIGNAL(newConnection()), this, SLOT(clientConnected())); + rfcommServer->listen(); + //! [Create the server] + + serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceRecordHandle, (uint)0x00010010); + + //! [Class Uuuid must contain at least 1 entry] + QBluetoothServiceInfo::Sequence classId; + classId << QVariant::fromValue(QBluetoothUuid(serviceUuid)); + serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceClassIds, classId); + //! [Class Uuuid must contain at least 1 entry] + + + //! [Service name, description and provider] + serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceName, tr("Bt Chat Server")); + serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceDescription, + tr("Example bluetooth chat server")); + serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceProvider, tr("Nokia, QtDF")); + //! [Service name, description and provider] + + //! [Service UUID set] + serviceInfo.setServiceUuid(QBluetoothUuid(serviceUuid)); + //! [Service UUID set] + + //! [Service Discoverability] + serviceInfo.setAttribute(QBluetoothServiceInfo::BrowseGroupList, + QBluetoothUuid(QBluetoothUuid::PublicBrowseGroup)); + //! [Service Discoverability] + + //! [Protocol descriptor list] + QBluetoothServiceInfo::Sequence protocolDescriptorList; + QBluetoothServiceInfo::Sequence protocol; + protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::L2cap)); + protocolDescriptorList.append(QVariant::fromValue(protocol)); + protocol.clear(); + protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::Rfcomm)) + << QVariant::fromValue(quint8(rfcommServer->serverPort())); + protocolDescriptorList.append(QVariant::fromValue(protocol)); + serviceInfo.setAttribute(QBluetoothServiceInfo::ProtocolDescriptorList, + protocolDescriptorList); + //! [Protocol descriptor list] + + //! [Register service] + serviceInfo.registerService(); + //! [Register service] +} + +//! [stopServer] +void ChatServer::stopServer() +{ + // Unregister service + serviceInfo.unregisterService(); + + // Close sockets + qDeleteAll(clientSockets); + + // Close server + delete rfcommServer; + rfcommServer = 0; +} +//! [stopServer] + +//! [sendMessage] +void ChatServer::sendMessage(const QString &message) +{ + QByteArray text = message.toUtf8() + '\n'; + + foreach (QBluetoothSocket *socket, clientSockets) + socket->write(text); +} +//! [sendMessage] + +//! [clientConnected] +void ChatServer::clientConnected() +{ + QBluetoothSocket *socket = rfcommServer->nextPendingConnection(); + if (!socket) + return; + + connect(socket, SIGNAL(readyRead()), this, SLOT(readSocket())); + connect(socket, SIGNAL(disconnected()), this, SLOT(clientDisconnected())); + clientSockets.append(socket); + + emit clientConnected(socket->peerName()); +} +//! [clientConnected] + +//! [clientDisconnected] +void ChatServer::clientDisconnected() +{ + QBluetoothSocket *socket = qobject_cast<QBluetoothSocket *>(sender()); + if (!socket) + return; + + emit clientDisconnected(socket->peerName()); + + clientSockets.removeOne(socket); + + socket->deleteLater(); +} +//! [clientDisconnected] + +//! [readSocket] +void ChatServer::readSocket() +{ + QBluetoothSocket *socket = qobject_cast<QBluetoothSocket *>(sender()); + if (!socket) + return; + + while (socket->canReadLine()) { + QByteArray line = socket->readLine().trimmed(); + emit messageReceived(socket->peerName(), + QString::fromUtf8(line.constData(), line.length())); + } +} +//! [readSocket] diff --git a/examples/bluetooth/btchat/chatserver.h b/examples/bluetooth/btchat/chatserver.h new file mode 100644 index 00000000..ee4728a9 --- /dev/null +++ b/examples/bluetooth/btchat/chatserver.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia Plc and its Subsidiary(-ies) 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$ +** +****************************************************************************/ + +#ifndef CHATSERVER_H +#define CHATSERVER_H + +#include <qbluetoothserviceinfo.h> + +#include <QtCore/QObject> +#include <QtCore/QList> + +QTBLUETOOTH_BEGIN_NAMESPACE +class QRfcommServer; +class QBluetoothSocket; +QTBLUETOOTH_END_NAMESPACE + +QTBLUETOOTH_USE_NAMESPACE + +//! [declaration] +class ChatServer : public QObject +{ + Q_OBJECT + +public: + explicit ChatServer(QObject *parent = 0); + ~ChatServer(); + + void startServer(); + void stopServer(); + +public slots: + void sendMessage(const QString &message); + +signals: + void messageReceived(const QString &sender, const QString &message); + void clientConnected(const QString &name); + void clientDisconnected(const QString &name); + +private slots: + void clientConnected(); + void clientDisconnected(); + void readSocket(); + +private: + QRfcommServer *rfcommServer; + QBluetoothServiceInfo serviceInfo; + QList<QBluetoothSocket *> clientSockets; +}; +//! [declaration] + +#endif // CHATSERVER_H diff --git a/examples/bluetooth/btchat/doc/images/btchat-example.png b/examples/bluetooth/btchat/doc/images/btchat-example.png Binary files differnew file mode 100644 index 00000000..762d49cb --- /dev/null +++ b/examples/bluetooth/btchat/doc/images/btchat-example.png diff --git a/examples/bluetooth/btchat/doc/src/btchat.qdoc b/examples/bluetooth/btchat/doc/src/btchat.qdoc new file mode 100644 index 00000000..20f1ad93 --- /dev/null +++ b/examples/bluetooth/btchat/doc/src/btchat.qdoc @@ -0,0 +1,191 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt local connectivty modules. +** +** $QT_BEGIN_LICENSE:FDL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: http://www.gnu.org/copyleft/fdl.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example btchat + \title Bluetooth Chat Example + + The Bluetooth Chat example shows how to use the Qt Connectivity Bluetooth API to communicate + with another application on a remote device using Bluetooth. + + \image btchat-example.png + + The Bluetooth Chat example implements a simple chat program between multiple parties. The + application always acts as both a server and a client eliminating the need to determine who + should connect to whom. + + \section1 Chat Server + + The chat server is implemented by the ChatServer class. The ChatServer class is declared as: + + \snippet btchat/chatserver.h declaration + + The first thing the chat server needs to do is create an instance of QRfcommServer to listen + for incoming Bluetooth connections. Our clientConnected() slot will be called whenever a new + connection is created. + + \snippet btchat/chatserver.cpp Create the server + + The chat server is only useful if others know that it is there. To enable other devices to + discover it a record describing the service needs to be published in the systems SDP (Service + Discovery Protocol) database. The QBluetoothServiceInfo class encapsulates a service record. + + We will publish a service record that contains some textural descriptions of the services, a + UUID that uniquely identifies the service, the discoverability attribute and connection + parameters. + + The textural description of the service is stored in the ServiceName, ServiceDescription and + ServiceProvider attributes. + + \snippet btchat/chatserver.cpp Service name, description and provider + + Bluetooth uses UUIDs as unique identifiers. Our chat service is uses a randomly generated + UUID. + + \snippet btchat/chatserver.cpp Service UUID + \snippet btchat/chatserver.cpp Service UUID set + + A Bluetooth service is only discoverable if it is in the PublicBrowseGroup. + + \snippet btchat/chatserver.cpp Service Discoverability + + The ProtocolDescriptorList attribute is used to publish the connection parameters that the + remote device requires to connect to our service. Here we specify that the Rfcomm protocol is + used and set the port number to port that our rfcommServer instance is listening to. + + \snippet btchat/chatserver.cpp Protocol descriptor list + + Finally we register the service record with the system. + + \snippet btchat/chatserver.cpp Register service + + As mentioned earlier incoming connections are handled in the clientConnected() slot. In this + slot we get a pointer a QBluetoothSocket representing the next pending connection connect up + slots to the readyRead() and disconnected() signals and emit a signal to notify others that a + new client has connected. + + \snippet btchat/chatserver.cpp clientConnected + + The readSocket() slot is called whenever data is ready to be read from a client socket. The + slot reads individual lines from the socket converts them from UTF-8 and emits the + messageReceived() signal. + + \snippet btchat/chatserver.cpp readSocket + + The clientDisconnected() slot is called whenever a client disconnects from the service. The + slot emits a signal to notify others that a client has disconnected and deletes the socket. + + \snippet btchat/chatserver.cpp clientDisconnected + + The sendMessage() slot is used to send a message to all connected clients. The message is + converted into UTF-8 and appended with a newline before being sent to all clients. + + \snippet btchat/chatserver.cpp sendMessage + + When the chat server is stop the service record is removed from the system SDP database, all + connected client sockets are deleted and the QRfcommServer instance is deleted. + + \snippet btchat/chatserver.cpp stopServer + + \section1 Chat Client + + The chat client is implemented by the ChatClient class. The ChatClient class is declared as: + + \snippet btchat/chatclient.h declaration + + The client creates a new QBluetoothSocket and connects to the remote service described by the + \e remoteService parameter. Slots are connected to the sockets readyRead(), connected() and + disconnected() signals. + + \snippet btchat/chatclient.cpp startClient + + On sucessfull socket connection we emit a signal to notify other. + + \snippet btchat/chatclient.cpp connected + + Similarily to the chat server the readSocket() slot is called when data is available from the + socket. Lines are read individually and converted from UTF-8. The messageReceived() signal + is emitted. + + \snippet btchat/chatclient.cpp readSocket + + The sendMessage() slot is used to send a message to the remote device. The message is + converted to UTF-8 and a newline appended. + + \snippet btchat/chatclient.cpp sendMessage + + To disconnect from the remote chat service the QBluetoothSocket instance is deleted. + + \snippet btchat/chatclient.cpp stopClient + + \section1 Chat Dialog + + The main window of this example is the chat dialog, implemented in the Chat class. This class + displays a chat session between a single ChatServer and zero or more ChatClients. The Chat + class is declared as: + + \snippet btchat/chat.h declaration + + First we construct the user interface + + \snippet btchat/chat.cpp Construct UI + + We create an instance of the ChatServer and respond to its clientConnected(), + clientDiconnected() and messageReceived() signals. + + \snippet btchat/chat.cpp Create Chat Server + + In response to the clientConnected() and clientDisconnected() signals of the ChatServer we + display the typical "foo has joined chat." and "foo has left." messages in the chat session. + + \snippet btchat/chat.cpp clientConnected clientDisconnected + + Incoming messages from clients connected to the ChatServer are handled in the showMessage() + slot. The message text tagged with the remote device name is displayed in the chat session. + + \snippet btchat/chat.cpp showMessage + + In response to the connect button being clicked the application starts service discovery and + presents a list of discovered chat services on remote devices. A ChatClient for the service + selected by the user. + + \snippet btchat/chat.cpp Connect to remote service + + In reponse to connected() signals from ChatClient we display the a "Joined chat with foo." + message in the chat session. + + \snippet btchat/chat.cpp connected + + Messages are sent to all remote devices via the ChatServer and ChatClient instances by emitting + the sendMessage() signal. + + \snippet btchat/chat.cpp sendClicked + + We need to clean up ChatClient instances when the remote device forces a disconnect. + + \snippet btchat/chat.cpp clientDisconnected +*/ diff --git a/examples/bluetooth/btchat/main.cpp b/examples/bluetooth/btchat/main.cpp new file mode 100644 index 00000000..cb32f448 --- /dev/null +++ b/examples/bluetooth/btchat/main.cpp @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia Plc and its Subsidiary(-ies) 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 <QApplication> + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + + Chat d; + QObject::connect(&d, SIGNAL(accepted()), &app, SLOT(quit())); + +#if defined(Q_WS_MAEMO_6) + d.showFullScreen(); +#else + d.show(); +#endif + + app.exec(); + + return 0; +} + diff --git a/examples/bluetooth/btchat/remoteselector.cpp b/examples/bluetooth/btchat/remoteselector.cpp new file mode 100644 index 00000000..a63c81c2 --- /dev/null +++ b/examples/bluetooth/btchat/remoteselector.cpp @@ -0,0 +1,146 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia Plc and its Subsidiary(-ies) 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> + +QTBLUETOOTH_USE_NAMESPACE + +RemoteSelector::RemoteSelector(QWidget *parent) +: QDialog(parent), ui(new Ui::RemoteSelector), + m_discoveryAgent(new QBluetoothServiceDiscoveryAgent) +{ + ui->setupUi(this); + +#if defined(Q_OS_WINCE) || defined(Q_WS_MAEMO_6) + setWindowState(Qt::WindowFullScreen); +#endif + + connect(m_discoveryAgent, SIGNAL(serviceDiscovered(QBluetoothServiceInfo)), + this, SLOT(serviceDiscovered(QBluetoothServiceInfo))); + connect(m_discoveryAgent, SIGNAL(finished()), this, SLOT(discoveryFinished())); +} + +RemoteSelector::~RemoteSelector() +{ + delete ui; +} + +void RemoteSelector::startDiscovery(const QBluetoothUuid &uuid) +{ + if (m_discoveryAgent->isActive()) + m_discoveryAgent->stop(); + + ui->remoteDevices->clear(); + + m_discoveryAgent->setUuidFilter(uuid); + m_discoveryAgent->start(); + + ui->status->setText(tr("Scanning...")); +} + +void RemoteSelector::stopDiscovery() +{ + if (m_discoveryAgent){ + m_discoveryAgent->stop(); + } +} + +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 + QMapIterator<QListWidgetItem *, QBluetoothServiceInfo> i(m_discoveredServices); + while (i.hasNext()){ + i.next(); + if (serviceInfo.device().address() == i.value().device().address()){ + return; + } + } + + QString remoteName; + if (serviceInfo.device().name().isEmpty()) + remoteName = serviceInfo.device().address().toString(); + else + remoteName = serviceInfo.device().name(); + + QListWidgetItem *item = + new QListWidgetItem(QString::fromLatin1("%1 %2").arg(remoteName, + serviceInfo.serviceName())); + + m_discoveredServices.insert(item, serviceInfo); + ui->remoteDevices->addItem(item); +} + +void RemoteSelector::discoveryFinished() +{ + ui->status->setText(tr("Select the chat service to connect to.")); +} + +void RemoteSelector::on_remoteDevices_itemActivated(QListWidgetItem *item) +{ + qDebug() << "got click" << item->text(); + m_service = m_discoveredServices.value(item); + + accept(); +} + +void RemoteSelector::on_cancelButton_clicked() +{ + reject(); +} diff --git a/examples/bluetooth/btchat/remoteselector.h b/examples/bluetooth/btchat/remoteselector.h new file mode 100644 index 00000000..eff94895 --- /dev/null +++ b/examples/bluetooth/btchat/remoteselector.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia Plc and its Subsidiary(-ies) 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$ +** +****************************************************************************/ + +#ifndef REMOTESELECTOR_H +#define REMOTESELECTOR_H + +#include <QDialog> + +#include <qbluetoothuuid.h> +#include <qbluetoothserviceinfo.h> +#include <qbluetoothservicediscoveryagent.h> + +QT_FORWARD_DECLARE_CLASS(QModelIndex) +QT_FORWARD_DECLARE_CLASS(QListWidgetItem) + +QTBLUETOOTH_USE_NAMESPACE + +QT_BEGIN_NAMESPACE +namespace Ui { + class RemoteSelector; +} +QT_END_NAMESPACE + +class RemoteSelector : public QDialog +{ + Q_OBJECT + +public: + explicit RemoteSelector(QWidget *parent = 0); + ~RemoteSelector(); + + void startDiscovery(const QBluetoothUuid &uuid); + void stopDiscovery(); + QBluetoothServiceInfo service() const; + +private: + Ui::RemoteSelector *ui; + + QBluetoothServiceDiscoveryAgent *m_discoveryAgent; + QBluetoothServiceInfo m_service; + QMap<QListWidgetItem *, QBluetoothServiceInfo> m_discoveredServices; + +private slots: + void serviceDiscovered(const QBluetoothServiceInfo &serviceInfo); + void discoveryFinished(); + void on_remoteDevices_itemActivated(QListWidgetItem *item); + void on_cancelButton_clicked(); +}; + +#endif // REMOTESELECTOR_H diff --git a/examples/bluetooth/btchat/remoteselector.ui b/examples/bluetooth/btchat/remoteselector.ui new file mode 100644 index 00000000..d415f416 --- /dev/null +++ b/examples/bluetooth/btchat/remoteselector.ui @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>RemoteSelector</class> + <widget class="QDialog" name="RemoteSelector"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>300</height> + </rect> + </property> + <property name="windowTitle"> + <string>Available chat services</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QLabel" name="status"> + <property name="text"> + <string>Scanning...</string> + </property> + </widget> + </item> + <item> + <widget class="QListWidget" name="remoteDevices"/> + </item> + <item> + <widget class="QPushButton" name="cancelButton"> + <property name="text"> + <string>Cancel</string> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/examples/bluetooth/btfiletransfer/btfiletransfer.pro b/examples/bluetooth/btfiletransfer/btfiletransfer.pro new file mode 100644 index 00000000..bc634193 --- /dev/null +++ b/examples/bluetooth/btfiletransfer/btfiletransfer.pro @@ -0,0 +1,27 @@ +TEMPLATE = app +TARGET = btfiletransfer + +QT += concurrent bluetooth widgets + +SOURCES = \ + main.cpp \ + remoteselector.cpp \ + progress.cpp \ + pindisplay.cpp + +HEADERS = \ + remoteselector.h \ + progress.h \ + pindisplay.h + +FORMS = \ + remoteselector.ui \ + progress.ui \ + pindisplay.ui + +OTHER_FILES += \ + busy.gif \ + pairing.gif + +RESOURCES += \ + btfiletransfer.qrc diff --git a/examples/bluetooth/btfiletransfer/btfiletransfer.qrc b/examples/bluetooth/btfiletransfer/btfiletransfer.qrc new file mode 100644 index 00000000..10697d5b --- /dev/null +++ b/examples/bluetooth/btfiletransfer/btfiletransfer.qrc @@ -0,0 +1,6 @@ +<RCC> + <qresource prefix="/icons"> + <file>busy.gif</file> + <file>pairing.gif</file> + </qresource> +</RCC> diff --git a/examples/bluetooth/btfiletransfer/busy.gif b/examples/bluetooth/btfiletransfer/busy.gif Binary files differnew file mode 100644 index 00000000..e192ca89 --- /dev/null +++ b/examples/bluetooth/btfiletransfer/busy.gif diff --git a/examples/bluetooth/btfiletransfer/doc/images/btfiletransfer-example.png b/examples/bluetooth/btfiletransfer/doc/images/btfiletransfer-example.png Binary files differnew file mode 100644 index 00000000..f98241d6 --- /dev/null +++ b/examples/bluetooth/btfiletransfer/doc/images/btfiletransfer-example.png diff --git a/examples/bluetooth/btfiletransfer/doc/src/btfiletransfer.qdoc b/examples/bluetooth/btfiletransfer/doc/src/btfiletransfer.qdoc new file mode 100644 index 00000000..200b3d6f --- /dev/null +++ b/examples/bluetooth/btfiletransfer/doc/src/btfiletransfer.qdoc @@ -0,0 +1,37 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt local connectivty modules. +** +** $QT_BEGIN_LICENSE:FDL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: http://www.gnu.org/copyleft/fdl.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example btfiletransfer + \title Bluetooth File Transfer Example + + The Bluetooth File Transfer example is an application to transfer files + via a bluetooth connection. + + \image btfiletransfer-example.png + +*/ diff --git a/examples/bluetooth/btfiletransfer/main.cpp b/examples/bluetooth/btfiletransfer/main.cpp new file mode 100644 index 00000000..4362c023 --- /dev/null +++ b/examples/bluetooth/btfiletransfer/main.cpp @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia Plc and its Subsidiary(-ies) 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 <QApplication> + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + + RemoteSelector d; + QObject::connect(&d, SIGNAL(accepted()), &app, SLOT(quit())); + d.startDiscovery(); + d.show(); + + app.exec(); + + return 0; +} + diff --git a/examples/bluetooth/btfiletransfer/pairing.gif b/examples/bluetooth/btfiletransfer/pairing.gif Binary files differnew file mode 100644 index 00000000..e147f3ec --- /dev/null +++ b/examples/bluetooth/btfiletransfer/pairing.gif diff --git a/examples/bluetooth/btfiletransfer/pindisplay.cpp b/examples/bluetooth/btfiletransfer/pindisplay.cpp new file mode 100644 index 00000000..bdef6b36 --- /dev/null +++ b/examples/bluetooth/btfiletransfer/pindisplay.cpp @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia Plc and its Subsidiary(-ies) 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 "pindisplay.h" +#include "ui_pindisplay.h" + +pinDisplay::pinDisplay(QString title, QString pin, QWidget *parent) : + QDialog(parent), + ui(new Ui::pinDisplay) +{ + ui->setupUi(this); + ui->label->setText(title); + ui->pin->setText(pin); + + connect(ui->buttonBox, SIGNAL(accepted()), this, SIGNAL(accepted())); + connect(ui->buttonBox, SIGNAL(rejected()), this, SIGNAL(rejected())); +} + +pinDisplay::~pinDisplay() +{ + delete ui; +} + +void pinDisplay::on_buttonBox_accepted() +{ + deleteLater(); +} + +void pinDisplay::setOkCancel() +{ + ui->buttonBox->addButton(QDialogButtonBox::Cancel); +} diff --git a/examples/bluetooth/btfiletransfer/pindisplay.h b/examples/bluetooth/btfiletransfer/pindisplay.h new file mode 100644 index 00000000..fd1b50aa --- /dev/null +++ b/examples/bluetooth/btfiletransfer/pindisplay.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia Plc and its Subsidiary(-ies) 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$ +** +****************************************************************************/ + +#ifndef PINDISPLAY_H +#define PINDISPLAY_H + +#include <QDialog> + +QT_BEGIN_NAMESPACE +namespace Ui { + class pinDisplay; +} +QT_END_NAMESPACE + +class pinDisplay : public QDialog +{ + Q_OBJECT + +public: + explicit pinDisplay(QString title, QString pin, QWidget *parent = 0); + ~pinDisplay(); + + void setOkCancel(); + +private Q_SLOTS: + void on_buttonBox_accepted(); + +private: + Ui::pinDisplay *ui; +}; + +#endif // PINDISPLAY_H diff --git a/examples/bluetooth/btfiletransfer/pindisplay.ui b/examples/bluetooth/btfiletransfer/pindisplay.ui new file mode 100644 index 00000000..02bf7d50 --- /dev/null +++ b/examples/bluetooth/btfiletransfer/pindisplay.ui @@ -0,0 +1,89 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>pinDisplay</class> + <widget class="QDialog" name="pinDisplay"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>240</width> + <height>153</height> + </rect> + </property> + <property name="windowTitle"> + <string>Enter Pin Code</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QLabel" name="pin"> + <property name="font"> + <font> + <family>Monospace</family> + <pointsize>24</pointsize> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="text"> + <string>012345</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string>TextLabel</string> + </property> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>pinDisplay</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>pinDisplay</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/examples/bluetooth/btfiletransfer/progress.cpp b/examples/bluetooth/btfiletransfer/progress.cpp new file mode 100644 index 00000000..d589e9b5 --- /dev/null +++ b/examples/bluetooth/btfiletransfer/progress.cpp @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia Plc and its Subsidiary(-ies) 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 "progress.h" +#include "ui_progress.h" + +#include <qbluetoothdeviceinfo.h> +#include <qbluetoothaddress.h> +#include <qbluetoothtransferrequest.h> +#include <qbluetoothtransferreply.h> + +QTBLUETOOTH_USE_NAMESPACE + +Progress::Progress(QWidget *parent) : + QDialog(parent), + ui(new Ui::Progress) +{ + ui->setupUi(this); + ui->progressBar->setRange(0, 1); + connect(ui->cancelButton, SIGNAL(clicked()), this, SLOT(close())); +} + +Progress::~Progress() +{ + delete ui; +} + +void Progress::setStatus(QString title, QString filename) { + ui->titleLabel->setText(title); + ui->statusLabel->setText(filename); +} + +void Progress::finished(QBluetoothTransferReply *reply){ + if (reply->error() != QBluetoothTransferReply::NoError){ + ui->progressBar->setDisabled(true); + ui->statusLabel->setText(tr("Failed: %1").arg(reply->errorString())); + } + else { + ui->statusLabel->setText(tr("Transfer complete")); + } + ui->cancelButton->setText(tr("Dismiss")); +} + +void Progress::uploadProgress(qint64 bytesSent, qint64 bytesTotal) +{ + if (bytesSent == 0){ + start.start(); + } + + ui->progressBar->setMaximum(bytesTotal); + ui->progressBar->setValue(bytesSent); + if (bytesSent && bytesTotal && + (start.elapsed() > 1000) && + (bytesSent > start.elapsed()/1000)) { + + ui->statusLabel->setText(tr("Transferring...ETA: %1s") + .arg(((bytesTotal-bytesSent)/(bytesSent/(start.elapsed()/1000))))); + } +} + diff --git a/examples/bluetooth/btfiletransfer/progress.h b/examples/bluetooth/btfiletransfer/progress.h new file mode 100644 index 00000000..400c9b70 --- /dev/null +++ b/examples/bluetooth/btfiletransfer/progress.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia Plc and its Subsidiary(-ies) 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$ +** +****************************************************************************/ + +#ifndef PROGRESS_H +#define PROGRESS_H + +#include <QDialog> +#include <qbluetoothglobal.h> +#include <QTime> + +QTBLUETOOTH_BEGIN_NAMESPACE +class QBluetoothTransferReply; +QTBLUETOOTH_END_NAMESPACE + +QTBLUETOOTH_USE_NAMESPACE + +QT_BEGIN_NAMESPACE +namespace Ui { + class Progress; +} +QT_END_NAMESPACE + +class Progress : public QDialog +{ + Q_OBJECT + +public: + explicit Progress(QWidget *parent = 0); + ~Progress(); + + void setStatus(QString title, QString filename); + +public Q_SLOTS: + void finished(QBluetoothTransferReply *); + void uploadProgress(qint64 bytesSent, qint64 bytesTotal); + +private: + Ui::Progress *ui; + + QTime start; +}; + +#endif // PROGRESS_H diff --git a/examples/bluetooth/btfiletransfer/progress.ui b/examples/bluetooth/btfiletransfer/progress.ui new file mode 100644 index 00000000..3b151f06 --- /dev/null +++ b/examples/bluetooth/btfiletransfer/progress.ui @@ -0,0 +1,55 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>Progress</class> + <widget class="QDialog" name="Progress"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>408</width> + <height>115</height> + </rect> + </property> + <property name="windowTitle"> + <string>Transfer Progress</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QLabel" name="titleLabel"> + <property name="text"> + <string>Filename</string> + </property> + </widget> + </item> + <item> + <widget class="QProgressBar" name="progressBar"> + <property name="minimumSize"> + <size> + <width>390</width> + <height>0</height> + </size> + </property> + <property name="value"> + <number>24</number> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="statusLabel"> + <property name="text"> + <string>Status</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="cancelButton"> + <property name="text"> + <string>Cancel</string> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/examples/bluetooth/btfiletransfer/remoteselector.cpp b/examples/bluetooth/btfiletransfer/remoteselector.cpp new file mode 100644 index 00000000..80d8761e --- /dev/null +++ b/examples/bluetooth/btfiletransfer/remoteselector.cpp @@ -0,0 +1,372 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia Plc and its Subsidiary(-ies) 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" + +QTBLUETOOTH_USE_NAMESPACE + +RemoteSelector::RemoteSelector(QWidget *parent) +: QDialog(parent), ui(new Ui::RemoteSelector), + m_discoveryAgent(new QBluetoothServiceDiscoveryAgent), m_localDevice(new QBluetoothLocalDevice), m_pindisplay(0) +{ + ui->setupUi(this); + + connect(m_discoveryAgent, SIGNAL(serviceDiscovered(QBluetoothServiceInfo)), + this, SLOT(serviceDiscovered(QBluetoothServiceInfo))); + connect(m_discoveryAgent, SIGNAL(finished()), this, SLOT(discoveryFinished())); + + ui->remoteDevices->setColumnWidth(3, 75); + ui->remoteDevices->setColumnWidth(4, 100); + + connect(m_localDevice, SIGNAL(pairingDisplayPinCode(const QBluetoothAddress &,QString)), this, SLOT(displayPin(const 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))); + + 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(); + + 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); + if (reply->error()){ + qDebug() << "Failed to send file"; + delete reply; + p->finished(reply); + return; + } + + connect(reply, SIGNAL(uploadProgress(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 (status == QBluetoothLocalDevice::Paired || + status == QBluetoothLocalDevice::AuthorizedPaired){ + msgBox.setText("Paired successfully with" + address.toString()); + } + else { + msgBox.setText("Pairing failed 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); + } + } + + msgBox.exec(); + + ui->remoteDevices->blockSignals(false); + + +} + +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(); +} diff --git a/examples/bluetooth/btfiletransfer/remoteselector.h b/examples/bluetooth/btfiletransfer/remoteselector.h new file mode 100644 index 00000000..d3300c9a --- /dev/null +++ b/examples/bluetooth/btfiletransfer/remoteselector.h @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia Plc and its Subsidiary(-ies) 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$ +** +****************************************************************************/ + +#ifndef REMOTESELECTOR_H +#define REMOTESELECTOR_H + +#include <QDialog> +#include <QPointer> + +#include <qbluetoothuuid.h> +#include <qbluetoothserviceinfo.h> +#include <qbluetoothservicediscoveryagent.h> +#include <qbluetoothlocaldevice.h> + +QT_FORWARD_DECLARE_CLASS(QModelIndex) +QT_FORWARD_DECLARE_CLASS(QTableWidgetItem) +QT_FORWARD_DECLARE_CLASS(QFile) + +class pinDisplay; + +QTBLUETOOTH_USE_NAMESPACE + +QT_BEGIN_NAMESPACE +namespace Ui { + class RemoteSelector; +} +QT_END_NAMESPACE + +class RemoteSelector : public QDialog +{ + Q_OBJECT + +public: + explicit RemoteSelector(QWidget *parent = 0); + ~RemoteSelector(); + + void startDiscovery(const QBluetoothUuid &uuid); + QBluetoothServiceInfo service() const; + +private: + Ui::RemoteSelector *ui; + + QBluetoothServiceDiscoveryAgent *m_discoveryAgent; + QBluetoothServiceInfo m_service; + QMap<int, QBluetoothServiceInfo> m_discoveredServices; + QFile *m_file; + QBluetoothLocalDevice *m_localDevice; + QPointer<pinDisplay> m_pindisplay; + + QString addressToName(const QBluetoothAddress &address); + +public Q_SLOTS: + void startDiscovery(); + +private slots: + void serviceDiscovered(const QBluetoothServiceInfo &serviceInfo); + void discoveryFinished(); + void on_refreshPB_clicked(); + void on_fileSelectPB_clicked(); + void on_sendButton_clicked(); + void on_stopButton_clicked(); + + void pairingFinished(const QBluetoothAddress &address,QBluetoothLocalDevice::Pairing pairing); + void displayPin(const QBluetoothAddress &address, QString pin); + void displayConfirmation(const QBluetoothAddress &address, QString pin); + void displayConfReject(); + void displayConfAccepted(); + + void on_remoteDevices_cellClicked(int row, int column); + void on_remoteDevices_itemChanged(QTableWidgetItem* item); +}; + +#endif // REMOTESELECTOR_H diff --git a/examples/bluetooth/btfiletransfer/remoteselector.ui b/examples/bluetooth/btfiletransfer/remoteselector.ui new file mode 100644 index 00000000..f99deaa7 --- /dev/null +++ b/examples/bluetooth/btfiletransfer/remoteselector.ui @@ -0,0 +1,214 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>RemoteSelector</class> + <widget class="QDialog" name="RemoteSelector"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>681</width> + <height>394</height> + </rect> + </property> + <property name="windowTitle"> + <string>Available file transfer services</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QGridLayout" name="gridLayout"> + <property name="horizontalSpacing"> + <number>6</number> + </property> + <item row="7" column="0" colspan="2"> + <widget class="QLineEdit" name="fileName"/> + </item> + <item row="7" column="2"> + <widget class="QPushButton" name="fileSelectPB"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Select File</string> + </property> + </widget> + </item> + <item row="8" column="0" colspan="3"> + <widget class="QPushButton" name="sendButton"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Send</string> + </property> + </widget> + </item> + <item row="0" column="0" colspan="3"> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QLabel" name="busyWidget"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>16</width> + <height>16</height> + </size> + </property> + <property name="baseSize"> + <size> + <width>16</width> + <height>16</height> + </size> + </property> + <property name="text"> + <string>TextLabel</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="status"> + <property name="text"> + <string>Scanning...</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="pairingBusy"> + <property name="text"> + <string>TextLabel</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="stopButton"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Stop</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="refreshPB"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Refresh</string> + </property> + </widget> + </item> + </layout> + </item> + <item row="6" column="0" colspan="3"> + <widget class="QTableWidget" name="remoteDevices"> + <property name="horizontalScrollBarPolicy"> + <enum>Qt::ScrollBarAsNeeded</enum> + </property> + <property name="editTriggers"> + <set>QAbstractItemView::NoEditTriggers</set> + </property> + <property name="showDropIndicator" stdset="0"> + <bool>false</bool> + </property> + <property name="alternatingRowColors"> + <bool>true</bool> + </property> + <property name="selectionMode"> + <enum>QAbstractItemView::SingleSelection</enum> + </property> + <property name="selectionBehavior"> + <enum>QAbstractItemView::SelectRows</enum> + </property> + <property name="showGrid"> + <bool>false</bool> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + <property name="rowCount"> + <number>1</number> + </property> + <attribute name="horizontalHeaderCascadingSectionResizes"> + <bool>true</bool> + </attribute> + <attribute name="horizontalHeaderDefaultSectionSize"> + <number>150</number> + </attribute> + <attribute name="horizontalHeaderStretchLastSection"> + <bool>true</bool> + </attribute> + <attribute name="verticalHeaderVisible"> + <bool>false</bool> + </attribute> + <attribute name="verticalHeaderCascadingSectionResizes"> + <bool>false</bool> + </attribute> + <row> + <property name="text"> + <string>Test</string> + </property> + </row> + <column> + <property name="text"> + <string>MAC Address</string> + </property> + </column> + <column> + <property name="text"> + <string>Device Name</string> + </property> + </column> + <column> + <property name="text"> + <string>Device Service</string> + </property> + </column> + <column> + <property name="text"> + <string>Paired</string> + </property> + <property name="toolTip"> + <string comment="Paired" extracomment="Paired"/> + </property> + <property name="whatsThis"> + <string comment="Paired" extracomment="Paired"/> + </property> + <property name="textAlignment"> + <set>AlignHCenter|AlignVCenter|AlignCenter</set> + </property> + </column> + <column> + <property name="text"> + <string>Authorized</string> + </property> + <property name="textAlignment"> + <set>AlignHCenter|AlignVCenter|AlignCenter</set> + </property> + </column> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/examples/bluetooth/btscanner/btscanner.pro b/examples/bluetooth/btscanner/btscanner.pro new file mode 100644 index 00000000..cc4675b2 --- /dev/null +++ b/examples/bluetooth/btscanner/btscanner.pro @@ -0,0 +1,18 @@ +TARGET = btscanner + +QT += concurrent bluetooth widgets +TEMPLATE = app + +SOURCES = \ + main.cpp \ + device.cpp \ + service.cpp + +HEADERS = \ + device.h \ + service.h + +FORMS = \ + device.ui \ + service.ui + diff --git a/examples/bluetooth/btscanner/device.cpp b/examples/bluetooth/btscanner/device.cpp new file mode 100644 index 00000000..33b96dc3 --- /dev/null +++ b/examples/bluetooth/btscanner/device.cpp @@ -0,0 +1,211 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia Plc and its Subsidiary(-ies) 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 "device.h" +#include "service.h" + +#include <qbluetoothaddress.h> +#include <qbluetoothdevicediscoveryagent.h> +#include <qbluetoothlocaldevice.h> +#include <QMenu> +#include <QDebug> + +DeviceDiscoveryDialog::DeviceDiscoveryDialog(QWidget *parent) +: QDialog(parent), discoveryAgent(new QBluetoothDeviceDiscoveryAgent), + localDevice(new QBluetoothLocalDevice), + ui(new Ui_DeviceDiscovery) +{ + ui->setupUi(this); + +#if defined(Q_OS_WINCE) || defined(Q_WS_MAEMO_6) + setWindowState(Qt::WindowFullScreen); +#endif + + connect(ui->inquiryType, SIGNAL(toggled(bool)), this, SLOT(setGeneralUnlimited(bool))); + connect(ui->scan, SIGNAL(clicked()), this, SLOT(startScan())); + + connect(discoveryAgent, SIGNAL(deviceDiscovered(const QBluetoothDeviceInfo&)), + this, SLOT(addDevice(const QBluetoothDeviceInfo&))); + connect(discoveryAgent, SIGNAL(finished()), this, SLOT(scanFinished())); + + connect(ui->list, SIGNAL(itemActivated(QListWidgetItem*)), + this, SLOT(itemActivated(QListWidgetItem*))); + + connect(localDevice, SIGNAL(hostModeStateChanged(QBluetoothLocalDevice::HostMode)), + this, SLOT(hostModeStateChanged(QBluetoothLocalDevice::HostMode))); + + hostModeStateChanged(localDevice->hostMode()); + // add context menu for devices to be able to pair device + ui->list->setContextMenuPolicy(Qt::CustomContextMenu); + connect(ui->list, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(displayPairingMenu(QPoint))); + connect(localDevice, SIGNAL(pairingFinished(const QBluetoothAddress&, QBluetoothLocalDevice::Pairing)) + , this, SLOT(pairingDone(const QBluetoothAddress&, QBluetoothLocalDevice::Pairing))); + +} + +DeviceDiscoveryDialog::~DeviceDiscoveryDialog() +{ + delete discoveryAgent; +} + +void DeviceDiscoveryDialog::addDevice(const QBluetoothDeviceInfo &info) +{ + QString label = QString("%1 %2").arg(info.address().toString()).arg(info.name()); + QList<QListWidgetItem *> items = ui->list->findItems(label, Qt::MatchExactly); + if (items.empty()) { + QListWidgetItem *item = new QListWidgetItem(label); + QBluetoothLocalDevice::Pairing pairingStatus = localDevice->pairingStatus(info.address()); + if (pairingStatus == QBluetoothLocalDevice::Paired || pairingStatus == QBluetoothLocalDevice::AuthorizedPaired ) + item->setTextColor(QColor(Qt::green)); + else + item->setTextColor(QColor(Qt::black)); + + ui->list->addItem(item); + } + +} + +void DeviceDiscoveryDialog::startScan() +{ + discoveryAgent->start(); + ui->scan->setEnabled(false); + ui->inquiryType->setEnabled(false); +} + +void DeviceDiscoveryDialog::scanFinished() +{ + ui->scan->setEnabled(true); + ui->inquiryType->setEnabled(true); +} + +void DeviceDiscoveryDialog::setGeneralUnlimited(bool unlimited) +{ + if (unlimited) + discoveryAgent->setInquiryType(QBluetoothDeviceDiscoveryAgent::GeneralUnlimitedInquiry); + else + discoveryAgent->setInquiryType(QBluetoothDeviceDiscoveryAgent::LimitedInquiry); +} + +void DeviceDiscoveryDialog::itemActivated(QListWidgetItem *item) +{ + QString text = item->text(); + + int index = text.indexOf(' '); + + if (index == -1) + return; + + QBluetoothAddress address(text.left(index)); + QString name(text.mid(index + 1)); + + ServiceDiscoveryDialog d(name, address); + d.exec(); +} + +void DeviceDiscoveryDialog::on_discoverable_clicked(bool clicked) +{ + if (clicked) + localDevice->setHostMode(QBluetoothLocalDevice::HostDiscoverable); + else + localDevice->setHostMode(QBluetoothLocalDevice::HostConnectable); +} + +void DeviceDiscoveryDialog::on_power_clicked(bool clicked) +{ + if (clicked) + localDevice->powerOn(); + else + localDevice->setHostMode(QBluetoothLocalDevice::HostPoweredOff); +} + +void DeviceDiscoveryDialog::hostModeStateChanged(QBluetoothLocalDevice::HostMode mode) +{ + if (mode != QBluetoothLocalDevice::HostPoweredOff) + ui->power->setChecked(true); + else + ui->power->setChecked( false); + + if (mode == QBluetoothLocalDevice::HostDiscoverable) + ui->discoverable->setChecked(true); + else + ui->discoverable->setChecked(false); + + bool on = !(mode == QBluetoothLocalDevice::HostPoweredOff); + + + ui->scan->setEnabled(on); + ui->discoverable->setEnabled(on); +} +void DeviceDiscoveryDialog::displayPairingMenu(const QPoint &pos) +{ + QMenu menu(this); + QAction *pairAction = menu.addAction("Pair"); + QAction *removePairAction = menu.addAction("Remove Pairing"); + QAction *chosenAction = menu.exec(ui->list->viewport()->mapToGlobal(pos)); + QListWidgetItem *currentItem = ui->list->currentItem(); + + QString text = currentItem->text(); + int index = text.indexOf(' '); + if (index == -1) + return; + + QBluetoothAddress address (text.left(index)); + if (chosenAction == pairAction) { + localDevice->requestPairing(address, QBluetoothLocalDevice::Paired); + } else if (chosenAction == removePairAction) { + localDevice->requestPairing(address, QBluetoothLocalDevice::Unpaired); + } +} +void DeviceDiscoveryDialog::pairingDone(const QBluetoothAddress &address, QBluetoothLocalDevice::Pairing pairing) +{ + QList<QListWidgetItem *> items = ui->list->findItems(address.toString(), Qt::MatchContains); + + if (pairing == QBluetoothLocalDevice::Paired || pairing == QBluetoothLocalDevice::AuthorizedPaired ) { + for (int var = 0; var < items.count(); ++var) { + QListWidgetItem *item = items.at(var); + item->setTextColor(QColor(Qt::green)); + } + } else { + for (int var = 0; var < items.count(); ++var) { + QListWidgetItem *item = items.at(var); + item->setTextColor(QColor(Qt::red)); + } + } +} diff --git a/examples/bluetooth/btscanner/device.h b/examples/bluetooth/btscanner/device.h new file mode 100644 index 00000000..af2d9a7f --- /dev/null +++ b/examples/bluetooth/btscanner/device.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia Plc and its Subsidiary(-ies) 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$ +** +****************************************************************************/ + +#ifndef DEVICE_H +#define DEVICE_H + +#include "ui_device.h" + +#include <qbluetoothglobal.h> +#include <qbluetoothlocaldevice.h> + +#include <QDialog> + +QTBLUETOOTH_BEGIN_NAMESPACE +class QBluetoothDeviceDiscoveryAgent; +class QBluetoothDeviceInfo; +QTBLUETOOTH_END_NAMESPACE + +QTBLUETOOTH_USE_NAMESPACE + +class DeviceDiscoveryDialog : public QDialog +{ + Q_OBJECT + +public: + DeviceDiscoveryDialog(QWidget *parent = 0); + ~DeviceDiscoveryDialog(); + +public slots: + void addDevice(const QBluetoothDeviceInfo&); + void on_power_clicked(bool clicked); + void on_discoverable_clicked(bool clicked); + void displayPairingMenu(const QPoint &pos); + void pairingDone(const QBluetoothAddress&, QBluetoothLocalDevice::Pairing); +private slots: + void startScan(); + void scanFinished(); + void setGeneralUnlimited(bool unlimited); + void itemActivated(QListWidgetItem *item); + void hostModeStateChanged(QBluetoothLocalDevice::HostMode); + +private: + QBluetoothDeviceDiscoveryAgent *discoveryAgent; + QBluetoothLocalDevice *localDevice; + Ui_DeviceDiscovery *ui; +}; + +#endif diff --git a/examples/bluetooth/btscanner/device.ui b/examples/bluetooth/btscanner/device.ui new file mode 100644 index 00000000..1f62dd96 --- /dev/null +++ b/examples/bluetooth/btscanner/device.ui @@ -0,0 +1,121 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>DeviceDiscovery</class> + <widget class="QDialog" name="DeviceDiscovery"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>411</height> + </rect> + </property> + <property name="windowTitle"> + <string>Bluetooth Scanner</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QListWidget" name="list"/> + </item> + <item> + <widget class="QGroupBox" name="groupBox"> + <property name="title"> + <string>Local Device</string> + </property> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QCheckBox" name="power"> + <property name="text"> + <string>Bluetooth Powered On</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="discoverable"> + <property name="text"> + <string>Discoverable</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QCheckBox" name="inquiryType"> + <property name="text"> + <string>General Unlimited Inquiry</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QPushButton" name="scan"> + <property name="text"> + <string>Scan</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="clear"> + <property name="text"> + <string>Clear</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="quit"> + <property name="text"> + <string>Quit</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>quit</sender> + <signal>clicked()</signal> + <receiver>DeviceDiscovery</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>323</x> + <y>275</y> + </hint> + <hint type="destinationlabel"> + <x>396</x> + <y>268</y> + </hint> + </hints> + </connection> + <connection> + <sender>clear</sender> + <signal>clicked()</signal> + <receiver>list</receiver> + <slot>clear()</slot> + <hints> + <hint type="sourcelabel"> + <x>188</x> + <y>276</y> + </hint> + <hint type="destinationlabel"> + <x>209</x> + <y>172</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/examples/bluetooth/btscanner/doc/images/btscanner-example.png b/examples/bluetooth/btscanner/doc/images/btscanner-example.png Binary files differnew file mode 100644 index 00000000..04fe9f3c --- /dev/null +++ b/examples/bluetooth/btscanner/doc/images/btscanner-example.png diff --git a/examples/bluetooth/btscanner/doc/src/btscanner.qdoc b/examples/bluetooth/btscanner/doc/src/btscanner.qdoc new file mode 100644 index 00000000..f5ee3e3a --- /dev/null +++ b/examples/bluetooth/btscanner/doc/src/btscanner.qdoc @@ -0,0 +1,36 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt local connectivty modules. +** +** $QT_BEGIN_LICENSE:FDL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: http://www.gnu.org/copyleft/fdl.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example btscanner + \title Bluetooth Scanner Example + + An example of how to locate Bluetooth devices. + + \image btscanner-example.png + +*/ diff --git a/examples/bluetooth/btscanner/main.cpp b/examples/bluetooth/btscanner/main.cpp new file mode 100644 index 00000000..e185ffca --- /dev/null +++ b/examples/bluetooth/btscanner/main.cpp @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia Plc and its Subsidiary(-ies) 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 "device.h" + +#include <QApplication> + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + + DeviceDiscoveryDialog d; + QObject::connect(&d, SIGNAL(accepted()), &app, SLOT(quit())); + d.show(); + + app.exec(); + + return 0; +} + diff --git a/examples/bluetooth/btscanner/service.cpp b/examples/bluetooth/btscanner/service.cpp new file mode 100644 index 00000000..daadb2b2 --- /dev/null +++ b/examples/bluetooth/btscanner/service.cpp @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia Plc and its Subsidiary(-ies) 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 "service.h" + +#include <qbluetoothaddress.h> +#include <qbluetoothservicediscoveryagent.h> +#include <qbluetoothserviceinfo.h> + + +ServiceDiscoveryDialog::ServiceDiscoveryDialog(const QString &name, + const QBluetoothAddress &address, QWidget *parent) +: QDialog(parent), discoveryAgent(new QBluetoothServiceDiscoveryAgent(address)), + ui(new Ui_ServiceDiscovery) +{ + ui->setupUi(this); + +#if defined(Q_OS_WINCE) || defined(Q_WS_MAEMO_6) + setWindowState(Qt::WindowMaximized); +#endif + + setWindowTitle(name); + + connect(discoveryAgent, SIGNAL(serviceDiscovered(const QBluetoothServiceInfo&)), + this, SLOT(addService(const QBluetoothServiceInfo&))); + connect(discoveryAgent, SIGNAL(finished()), ui->status, SLOT(hide())); + + discoveryAgent->start(); +} + +ServiceDiscoveryDialog::~ServiceDiscoveryDialog() +{ + delete discoveryAgent; + delete ui; +} + +void ServiceDiscoveryDialog::addService(const QBluetoothServiceInfo &info) +{ + if (info.serviceName().isEmpty()) + return; + + QString line = info.serviceName(); + if (!info.serviceDescription().isEmpty()) + line.append("\n\t" + info.serviceDescription()); + if (!info.serviceProvider().isEmpty()) + line.append("\n\t" + info.serviceProvider()); + + ui->list->addItem(line); +} + diff --git a/examples/bluetooth/btscanner/service.h b/examples/bluetooth/btscanner/service.h new file mode 100644 index 00000000..0e17aa14 --- /dev/null +++ b/examples/bluetooth/btscanner/service.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia Plc and its Subsidiary(-ies) 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$ +** +****************************************************************************/ + +#ifndef SERVICE_H +#define SERVICE_H + +#include "ui_service.h" + +#include <qbluetoothglobal.h> + +#include <QDialog> + +QTBLUETOOTH_BEGIN_NAMESPACE +class QBluetoothServiceDiscoveryAgent; +class QBluetoothServiceInfo; +class QBluetoothAddress; +QTBLUETOOTH_END_NAMESPACE + +QTBLUETOOTH_USE_NAMESPACE + +class ServiceDiscoveryDialog : public QDialog +{ + Q_OBJECT + +public: + ServiceDiscoveryDialog(const QString &name, const QBluetoothAddress &address, QWidget *parent = 0); + ~ServiceDiscoveryDialog(); + +public slots: + void addService(const QBluetoothServiceInfo&); + +private: + QBluetoothServiceDiscoveryAgent *discoveryAgent; + Ui_ServiceDiscovery *ui; +}; + +#endif diff --git a/examples/bluetooth/btscanner/service.ui b/examples/bluetooth/btscanner/service.ui new file mode 100644 index 00000000..68ebc5dc --- /dev/null +++ b/examples/bluetooth/btscanner/service.ui @@ -0,0 +1,76 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ServiceDiscovery</class> + <widget class="QDialog" name="ServiceDiscovery"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>300</height> + </rect> + </property> + <property name="windowTitle"> + <string>Available Services</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QListWidget" name="list"/> + </item> + <item> + <widget class="QLabel" name="status"> + <property name="text"> + <string>Querying...</string> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="close"> + <property name="text"> + <string>Close</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <tabstops> + <tabstop>list</tabstop> + <tabstop>close</tabstop> + </tabstops> + <resources/> + <connections> + <connection> + <sender>close</sender> + <signal>clicked()</signal> + <receiver>ServiceDiscovery</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>350</x> + <y>277</y> + </hint> + <hint type="destinationlabel"> + <x>237</x> + <y>269</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/examples/bluetooth/bttennis/board.cpp b/examples/bluetooth/bttennis/board.cpp new file mode 100644 index 00000000..d1aab939 --- /dev/null +++ b/examples/bluetooth/bttennis/board.cpp @@ -0,0 +1,250 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "board.h" + +#include <QGraphicsItem> +#include <QGraphicsScene> +#include <QDebug> +#include <QTextDocument> +#include <QFontMetrics> +#include <QPropertyAnimation> + +const QColor fg = Qt::white; +const QColor bg = Qt::black; + +Board::Board(QWidget *parent) : + QGraphicsView(parent) +{ + scene = new QGraphicsScene(QRect(0, 0, 640, 360), this); + + scene->setBackgroundBrush(QBrush(bg)); + + ball = scene->addRect(-6, -6, 12, 12, QPen(Qt::SolidLine), QBrush(fg)); + ball->setPos(Width/2-6, Height/2-6); + + // why is y -1...otherwise we have a gap... + topWall = scene->addRect(0, -1, Width, 12, QPen(Qt::SolidLine), QBrush(fg)); + bottomWall = scene->addRect(0, Height-12, Width, 12, QPen(Qt::SolidLine), QBrush(fg)); + + leftPaddle = scene->addRect(0, 12, 12, Paddle, QPen(Qt::SolidLine), QBrush(fg)); + rightPaddle = scene->addRect(Width-12, 12, 12, Paddle, QPen(Qt::SolidLine), QBrush(fg)); + + QPen p; + p.setWidth(2); + p.setStyle(Qt::DotLine); + p.setBrush(QBrush(fg)); + scene->addLine(Width/2, 0, Width/2, Height, p); + + QFont f; + f.setStyleHint(QFont::OldEnglish); + f.setPixelSize(50); + f.setBold(true); + leftScore = scene->addText(QString("0"), f); + leftScore->setDefaultTextColor(fg); +// leftScore->setPos(120, 50); + + rightScore = scene->addText(QString("0"), f); +// rightScore->setPos(Width-140, 50); + rightScore->setDefaultTextColor(fg); + setScore(0, 0); + + f.setPixelSize(25); + status = scene->addText(QString(), f); + status->setDefaultTextColor(fg); + + ball->setCacheMode(QGraphicsItem::DeviceCoordinateCache); + leftPaddle->setCacheMode(QGraphicsItem::DeviceCoordinateCache); + rightPaddle->setCacheMode(QGraphicsItem::DeviceCoordinateCache); + + icon.load(QString(":/icons/connect.png")); + icon = icon.scaled(100, 100, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + qDebug() << "icon" << icon.isNull(); + connectIcon = scene->addPixmap(icon); + connectIcon->setPos(440,200); + connectIcon->setAcceptTouchEvents(true); + connectIcon->setTransformOriginPoint(50,50); + connectIcon->setTransformationMode(Qt::SmoothTransformation); + + connectAnimation = new QPropertyAnimation(this, "connectRotation"); + connectAnimation->setDuration(1000); + connectAnimation->setLoopCount(-1); + connectAnimation->setStartValue(0); + connectAnimation->setEndValue(360); + + setCacheMode(QGraphicsView::CacheBackground); + setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate); + +// connect(scene, SIGNAL(changed(QList<QRectF>)), this, SLOT(sceneChanged(QList<QRectF>))); + +} +void Board::setBall(int x, int y) +{ + ball->setPos(x, y); + checkBall(x, y); +} + +void Board::setLeftPaddle(int y) +{ + leftPaddle->setPos(0, y); +} + +void Board::setRightPaddle(int y) +{ + rightPaddle->setPos(0, y); +} + +void Board::sceneChanged(const QList<QRectF> ®ion) +{ + Q_UNUSED(region); + + QList<QGraphicsItem *>items = scene->collidingItems(ball); + while (!items.empty()) { + QGraphicsItem *i = items.takeFirst(); + if (i == topWall) + emit ballCollision(Top); + if (i == bottomWall) + emit ballCollision(Bottom); + if (i == leftPaddle) + emit ballCollision(Left); + if (i == rightPaddle) + emit ballCollision(Right); + } + +} + +void Board::checkBall(int x, int y) +{ + int ly = leftPaddle->y(); + int ry = rightPaddle->y(); + + if (x > 646) + emit scored(Right); + else if (x < -6) + emit scored(Left); + + if (y < 18) + emit ballCollision(Top); + else if (y > 360-18) + emit ballCollision(Bottom); + + if ((x < 18) && + (y > ly-6) && + (y < ly+Paddle+6)) + emit ballCollision(Left); + + if ((x > 640-18) && + (y > ry-6) && + (y < ry+Paddle+6)) + emit ballCollision(Right); +} + +void Board::setScore(int l, int r) +{ + QString left = QString("%1").arg(l); + QString right = QString("%1").arg(r); + leftScore->document()->setPlainText(left); + rightScore->document()->setPlainText(right); + QFontMetrics fm(leftScore->font()); + leftScore->setPos(Width/4 - fm.width(left)/2, 50); + rightScore->setPos(3*Width/4 - fm.width(right)/2, 50); + +} + +void Board::setStatus(QString text, int opacity_start, int opacity_end) +{ + + status->document()->setPlainText(text); + status->setPos(24, Height-25-25); + QPropertyAnimation *a = new QPropertyAnimation(status, "opacity"); + a->setDuration(2000); + a->setStartValue(opacity_start/100.0); + a->setEndValue(opacity_end/100.0); + a->start(QAbstractAnimation::DeleteWhenStopped); +} + +void Board::setConnectRotation(int rot) +{ + connectIcon->setRotation(rot); +// QTransform t; +// t.rotate(rot); +// connectIcon->setPixmap(icon.scaled(100, 100).transformed(t, Qt::SmoothTransformation)); +} + +void Board::setConnectOpacity(qreal op) +{ + connectIcon->setOpacity(op); +} + +void Board::animateConnect(bool start) +{ + if (start) { + connectAnimation->start(); + } + else { + connectAnimation->stop(); + QPropertyAnimation *a = new QPropertyAnimation(this, "connectRotation"); +// qDebug() << "currentTime" << connectAnimation->currentLoopTime() << "rotation" << connectAnimation->currentValue(); + a->setDuration(connectAnimation->currentLoopTime()/2); + a->setStartValue(connectAnimation->currentValue().toInt( )); + a->setEndValue(0); +// a->setDirection(QAbstractAnimation::Backward); + a->start(QAbstractAnimation::DeleteWhenStopped); + } +} + + +void Board::fadeConnect(bool out) +{ + qreal start = 100.0; + qreal end = 0.0; + + if (!out) { + start = 0.0; + end = 100.0; + } + + QPropertyAnimation *a = new QPropertyAnimation(this, "connectOpacity"); + a->setDuration(2000); + a->setStartValue(start); + a->setEndValue(end); + a->start(QAbstractAnimation::DeleteWhenStopped); +} diff --git a/examples/bluetooth/bttennis/board.h b/examples/bluetooth/bttennis/board.h new file mode 100644 index 00000000..7b0f279b --- /dev/null +++ b/examples/bluetooth/bttennis/board.h @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef BOARD_H +#define BOARD_H + +#include <QObject> +#include <QGraphicsScene> +#include <QGraphicsView> +#include <QGraphicsPixmapItem> +#include <QPixmap> +#include <QPropertyAnimation> + +class Board : public QGraphicsView +{ + Q_OBJECT + Q_PROPERTY(int connectRotation READ connectRotation WRITE setConnectRotation) + Q_PROPERTY(qreal connectOpacity READ connectOpacity WRITE setConnectOpacity) +public: + explicit Board(QWidget *parent = 0); + + enum Edge { + Top = 1, + Bottom, + Left, + Right + }; + + enum BoardSize { + Width = 640, + Height = 360, + Paddle = 50 + }; + + + QGraphicsScene *getScene() { + return scene; + } + + int connectRotation(){ + return connectIcon->rotation(); + } + + qreal connectOpacity(){ + return connectIcon->opacity(); + } + + void setConnectRotation(int rot); + void setConnectOpacity(qreal op); + +signals: + void ballCollision(Board::Edge pos); + void scored(Board::Edge pos); + +public slots: + void setBall(int x, int y); + void setLeftPaddle(int y); + void setRightPaddle(int y); + void setScore(int l, int r); + + void setStatus(QString text, int opacity_start, int opacity_end); + + void sceneChanged(const QList<QRectF> ®ion); + + void animateConnect(bool start = true); + void fadeConnect(bool out = true); + +private: + QGraphicsScene *scene; + QGraphicsRectItem *ball; + QGraphicsRectItem *topWall; + QGraphicsRectItem *bottomWall; + QGraphicsRectItem *leftPaddle; + QGraphicsRectItem *rightPaddle; + + QGraphicsTextItem *leftScore; + QGraphicsTextItem *rightScore; + + QGraphicsTextItem *status; + + QPixmap icon; + QGraphicsPixmapItem *connectIcon; + QPropertyAnimation *connectAnimation; + + void checkBall(int x, int y); +}; + +#endif // BOARD_H diff --git a/examples/bluetooth/bttennis/bttennis.pro b/examples/bluetooth/bttennis/bttennis.pro new file mode 100644 index 00000000..39e33dcf --- /dev/null +++ b/examples/bluetooth/bttennis/bttennis.pro @@ -0,0 +1,30 @@ +TEMPLATE = app +TARGET = bttennis + +QT += concurrent bluetooth widgets +#QT += nfc + +SOURCES = \ + main.cpp \ + board.cpp \ + tennis.cpp \ + controller.cpp \ + tennisserver.cpp \ + tennisclient.cpp \ + tennisview.cpp +# handover.cpp + +HEADERS = \ + board.h \ + tennis.h \ + controller.h \ + tennisserver.h \ + tennisclient.h \ + tennisview.h +# handover.h + +FORMS = \ + tennis.ui + +RESOURCES += \ + tennis.qrc diff --git a/examples/bluetooth/bttennis/connect.png b/examples/bluetooth/bttennis/connect.png Binary files differnew file mode 100644 index 00000000..70b64c6c --- /dev/null +++ b/examples/bluetooth/bttennis/connect.png diff --git a/examples/bluetooth/bttennis/controller.cpp b/examples/bluetooth/bttennis/controller.cpp new file mode 100644 index 00000000..c137060a --- /dev/null +++ b/examples/bluetooth/bttennis/controller.cpp @@ -0,0 +1,263 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "controller.h" + +#include <QDateTime> +#include <QDebug> + +#define FRAME_RATE 60 + +Controller::Controller(QObject *parent) : + QObject(parent), timer(new QTimer), elapsed(new QTime), score_left(0), score_right(0), + col_x(0), col_y(0), + rightPaddleForce(0), leftPaddleForce(0), + rightPaddleLast(0), leftPaddleLast(0), + rightPowerUp(0), leftPowerUp(0) +{ + + qsrand(QDateTime::currentDateTime().time().msec()); + + + timer->setInterval(1000/FRAME_RATE); +// timer->setInterval(0); + connect(timer, SIGNAL(timeout()), SLOT(tick())); + srand(QDateTime::currentDateTime().time().msec()); + + fpscntr = new QTime; + frames = 0; + + timer->start(); + restart_ball(); +} + +void Controller::tick() +{ + if (col_x) + col_x--; + if (col_y) + col_y--; + +// frames++; +// if (fpscntr->elapsed() > 1000){ +// int f = frames/(fpscntr->elapsed()/1000.0); +// emit fps(QString("FPS %1").arg(f)); +// frames = 0; +// fpscntr->restart(); +// } + + int msec = elapsed->elapsed(); + elapsed->restart(); + + ball_x += speed_x*msec/1000; + ball_y += speed_y*msec/1000; + + + const int decay = 5; + + if (leftPaddleForce > decay) + leftPaddleForce-=decay; + else if (leftPaddleForce < -decay) + leftPaddleForce+=decay; + if (rightPaddleForce > decay) + rightPaddleForce-=decay; + else if (rightPaddleForce < -decay) + rightPaddleForce+=decay; + + if (rightPaddleForce <= decay) + rightPowerUp++; + + if (leftPaddleForce <= decay) + leftPowerUp++; + + +// ttf++; +// if (msec > 1000/FRAME_RATE+2 || msec < 1000/FRAME_RATE-2) +// dev++; + +// if (!(i++%120)) { +// qDebug() << "powerUp: " << leftPowerUp << rightPowerUp << leftPaddleForce << rightPaddleForce << speed_x*msec/1000 << speed_y*msec/1000 << msec << dev; +// ttf = dev =0; +// } + + emit moveBall(ball_x, ball_y); +} + + +static inline int paddle_boost(int force){ + if (force > 30) + return -3*FRAME_RATE; + else if (force > 20) + return -2*FRAME_RATE; + else if (force > 6) + return -1*FRAME_RATE; + else if (force < -30) + return 3*FRAME_RATE; + else if (force < -20) + return 2*FRAME_RATE; + else if (force < -6) + return 1*FRAME_RATE; + return 0; +} + +void Controller::ballCollision(Board::Edge pos) +{ + + if ((pos == Board::Top || pos == Board::Bottom) && !col_y) { + speed_y *= -1; + col_y = 10; + } + + if (pos == Board::Left && !col_x) { + speed_x *= -1; + speed_y += paddle_boost(leftPaddleForce); + col_x = 10; + + if (leftPowerUp > 75 && speed_x < 8*FRAME_RATE){ + speed_x *= 2; + leftPowerUp = 0; + } + } + else if (pos == Board::Right && !col_x) { + speed_x *= -1; + speed_y += paddle_boost(rightPaddleForce); + col_x = 10; + + if (rightPowerUp > 75 && speed_x > -8*FRAME_RATE){ + speed_x *= 2; + rightPowerUp = 0; + } + + } +// tick(); +// QMetaObject::invokeMethod(this, "moveBall", Qt::QueuedConnection, Q_ARG(int, ball_x), Q_ARG(int, ball_y)); +// emit moveBall(ball_x, ball_y); + +} + +void Controller::scored(Board::Edge pos) +{ + if (!timer->isActive()) + return; + + if (pos == Board::Left) + emit score(score_left, ++score_right); + else if (pos == Board::Right) + emit score(++score_left, score_right); + + restart_ball(); +} + +void Controller::restart_ball() +{ + if (!timer->isActive()) + return; + + elapsed->start(); + + ball_x = Board::Width/2; + ball_y = Board::Height/2; + +// ball_y = (qrand()%(Board::Height/2))+Board::Height/4; + ball_y = (qrand()%(Board::Height-48))+24; + + // Speed in in pixels/second + + const int max = 4*FRAME_RATE; + const int min_x = 2*FRAME_RATE; + const int min_y = 1.5*FRAME_RATE; + + + speed_y = min_y+qrand()%(max-min_y); + if (speed_y%2) + speed_y *= -1; + + + speed_x = min_x+qrand()%(max-min_y); + if (speed_x%2) + speed_x *= -1; + + leftPowerUp = rightPowerUp = 0; + + emit moveBall(ball_x, ball_y); +} + + +void Controller::resetBoard() +{ + if (!timer->isActive()) + return; + + score_left = score_right = 0; + restart_ball(); +} + +void Controller::stop() +{ + timer->stop(); +} + +void Controller::start() +{ + timer->start(); + fpscntr->restart(); + frames = 0; +} + +void Controller::moveLeftPaddle(int y) +{ + leftPaddleForce += leftPaddleLast-y; + leftPaddleLast = y; + leftPowerUp = 0; +} + +void Controller::moveRightPaddle(int y) +{ + rightPaddleForce += rightPaddleLast-y; + rightPaddleLast =y; + rightPowerUp = 0; +} + +void Controller::refresh() +{ + emit moveBall(ball_x, ball_y); + emit score(score_left, score_right); +} diff --git a/examples/bluetooth/bttennis/controller.h b/examples/bluetooth/bttennis/controller.h new file mode 100644 index 00000000..492f094b --- /dev/null +++ b/examples/bluetooth/bttennis/controller.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CONTROLLER_H +#define CONTROLLER_H + +#include <QObject> +#include <QTimer> +#include <QTime> +#include "board.h" + +class Controller : public QObject +{ + Q_OBJECT +public: + explicit Controller(QObject *parent = 0); + +signals: + void moveBall(int x, int y); + void score(int left, int right); + void fps(const QString &str); + +public slots: + void ballCollision(Board::Edge pos); + void scored(Board::Edge pos); + void resetBoard(); + void refresh(); + + void moveLeftPaddle(int y); + void moveRightPaddle(int y); + + void tick(); + + void start(); + void stop(); + +private: + QTimer *timer; + QTime *elapsed; + QTime *fpscntr; + int frames; + int ball_x; + int speed_x; + int ball_y; + int speed_y; + int score_left; + int score_right; + int col_x; + int col_y; + + int rightPaddleForce; + int leftPaddleForce; + int rightPaddleLast; + int leftPaddleLast; + int rightPowerUp; + int leftPowerUp; + + void restart_ball(); + +}; + +#endif // CONTROLLER_H diff --git a/examples/bluetooth/bttennis/doc/images/bttennis-example.png b/examples/bluetooth/bttennis/doc/images/bttennis-example.png Binary files differnew file mode 100644 index 00000000..53a5486b --- /dev/null +++ b/examples/bluetooth/bttennis/doc/images/bttennis-example.png diff --git a/examples/bluetooth/bttennis/doc/src/bttennis.qdoc b/examples/bluetooth/bttennis/doc/src/bttennis.qdoc new file mode 100644 index 00000000..094dbaa3 --- /dev/null +++ b/examples/bluetooth/bttennis/doc/src/bttennis.qdoc @@ -0,0 +1,37 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt local connectivty modules. +** +** $QT_BEGIN_LICENSE:FDL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: http://www.gnu.org/copyleft/fdl.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example bttennis + \title Bluetooth Tennis Example + + The Bluetooth Tennis example shows how to use the Qt Connectivity Bluetooth API + to implement real-time data transfer for interactive applications. + + \image bttennis-example.png + +*/ diff --git a/examples/bluetooth/bttennis/handover.cpp b/examples/bluetooth/bttennis/handover.cpp new file mode 100644 index 00000000..03ec169b --- /dev/null +++ b/examples/bluetooth/bttennis/handover.cpp @@ -0,0 +1,130 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "handover.h" + +#include <qnearfieldmanager.h> +#include <qllcpserver.h> +#include <qllcpsocket.h> +#include <qbluetoothlocaldevice.h> + +#include <QtCore/QStringList> + +static const QLatin1String tennisUri("urn:nfc:sn:com.nokia.qtnfc.tennis"); + +Handover::Handover(quint16 serverPort, QObject *parent) +: QObject(parent), m_server(new QLlcpServer(this)), + m_client(new QLlcpSocket(this)), m_remote(0), m_serverPort(0), m_localServerPort(serverPort) +{ + connect(m_server, SIGNAL(newConnection()), this, SLOT(handleNewConnection())); + m_server->listen(tennisUri); + + connect(m_client, SIGNAL(disconnected()), this, SLOT(clientDisconnected())); + connect(m_client, SIGNAL(readyRead()), this, SLOT(readBluetoothService())); + + m_client->connectToService(0, tennisUri); +} + +Handover::~Handover() +{ +} + +QBluetoothAddress Handover::bluetoothAddress() const +{ + return m_address; +} + +quint16 Handover::serverPort() const +{ + return m_serverPort; +} + +void Handover::handleNewConnection() +{ + if (m_remote) + m_remote->deleteLater(); + + m_remote = m_server->nextPendingConnection(); + + connect(m_remote, SIGNAL(disconnected()), this, SLOT(remoteDisconnected())); + + sendBluetoothService(); +} + +void Handover::remoteDisconnected() +{ + m_remote->deleteLater(); + m_remote = 0; +} + +void Handover::clientDisconnected() +{ + m_client->connectToService(0, tennisUri); +} + +void Handover::readBluetoothService() +{ + QByteArray rawData = m_client->readAll(); + QString data = QString::fromUtf8(rawData.constData(), rawData.size()); + QStringList split = data.split(QLatin1Char(' ')); + + QBluetoothAddress address = QBluetoothAddress(split.at(0)); + quint16 port = split.at(1).toUInt(); + + QBluetoothLocalDevice localDevice; + QBluetoothAddress localAddress = localDevice.address(); + + if (localAddress < address) { + m_address = address; + m_serverPort = port; + emit bluetoothServiceChanged(); + } +} + +void Handover::sendBluetoothService() +{ + QBluetoothLocalDevice localDevice; + const QString data = localDevice.address().toString() + QLatin1Char(' ') + + QString::number(m_localServerPort); + + m_remote->write(data.toUtf8()); +} + diff --git a/examples/bluetooth/bttennis/handover.h b/examples/bluetooth/bttennis/handover.h new file mode 100644 index 00000000..0e932267 --- /dev/null +++ b/examples/bluetooth/bttennis/handover.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef HANDOVER_H +#define HANDOVER_H + +#include <QtCore/QObject> + +#include <qbluetoothaddress.h> +#include <qbluetoothuuid.h> +#include <qnfcglobal.h> + +QTNFC_BEGIN_NAMESPACE +class QNearFieldManager; +class QNearFieldTarget; +class QLlcpServer; +class QLlcpSocket; +QTNFC_END_NAMESPACE + +QTNFC_USE_NAMESPACE +QTBLUETOOTH_USE_NAMESPACE + +class Handover : public QObject +{ + Q_OBJECT + +public: + explicit Handover(quint16 serverPort, QObject *parent = 0); + ~Handover(); + + QBluetoothAddress bluetoothAddress() const; + quint16 serverPort() const; + +private slots: + void handleNewConnection(); + void remoteDisconnected(); + + void clientDisconnected(); + + void readBluetoothService(); + void sendBluetoothService(); + +signals: + void bluetoothServiceChanged(); + +private: + QLlcpServer *m_server; + QLlcpSocket *m_client; + QLlcpSocket *m_remote; + + QBluetoothAddress m_address; + quint16 m_serverPort; + quint16 m_localServerPort; +}; + +#endif // HANDOVER_H diff --git a/examples/bluetooth/bttennis/main.cpp b/examples/bluetooth/bttennis/main.cpp new file mode 100644 index 00000000..d30632f7 --- /dev/null +++ b/examples/bluetooth/bttennis/main.cpp @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "tennis.h" + +#include <QApplication> + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + + Tennis d; + QObject::connect(&d, SIGNAL(accepted()), &app, SLOT(quit())); + +#if defined(Q_WS_MAEMO_6) + d.showFullScreen(); +#else + d.show(); +#endif + + app.exec(); + + return 0; +} + diff --git a/examples/bluetooth/bttennis/tennis.cpp b/examples/bluetooth/bttennis/tennis.cpp new file mode 100644 index 00000000..54fe026f --- /dev/null +++ b/examples/bluetooth/bttennis/tennis.cpp @@ -0,0 +1,424 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "tennis.h" + +#include <QTimer> +#include <QKeyEvent> +#include <QMouseEvent> + +#include <QDebug> + +#include <QSettings> +#include <QEvent> +#include <QResizeEvent> + +#include "tennisserver.h" +#include "tennisclient.h" +//#include "handover.h" + +#include <qbluetooth.h> +#include <qbluetoothdeviceinfo.h> +#include <qbluetoothsocket.h> +#include <qbluetoothservicediscoveryagent.h> +#include <qbluetoothlocaldevice.h> + +//#include <qnearfieldmanager.h> +//#include <qllcpserver.h> +//#include <qllcpsocket.h> + +Tennis::Tennis(QWidget *parent) +: QDialog(parent), ui(new Ui_Tennis), board(new Board), controller(new Controller), socket(0), + m_discoveryAgent(new QBluetoothServiceDiscoveryAgent)//, m_handover(0) +{ + // start Bluetooth if not started + QBluetoothLocalDevice *device = new QBluetoothLocalDevice(); + device->powerOn(); + delete device; + device = 0; + + //! [Construct UI] + ui->setupUi(this); + + isClient = false; + isConnected = false; + quickDiscovery = true; + +#if defined(Q_OS_WINCE) || defined(Q_WS_MAEMO_6) + setWindowState(Qt::WindowMaximized); +#endif + + ui->pongView->setScene(board->getScene()); + + connect(ui->pongView, SIGNAL(mouseMove(int, int)), this, SLOT(mouseMove(int, int))); + ui->pongView->setMouseTracking(false); + + connect(board, SIGNAL(ballCollision(Board::Edge)), controller, SLOT(ballCollision(Board::Edge))); + connect(board, SIGNAL(scored(Board::Edge)), controller, SLOT(scored(Board::Edge))); + connect(controller, SIGNAL(moveBall(int,int)), board, SLOT(setBall(int,int))); + connect(this, SIGNAL(moveLeftPaddle(int)), board, SLOT(setLeftPaddle(int))); + connect(this, SIGNAL(moveRightPaddle(int)), board, SLOT(setRightPaddle(int))); + connect(controller, SIGNAL(score(int,int)), board, SLOT(setScore(int,int))); + connect(controller, SIGNAL(fps(const QString&)), this, SLOT(fps(const QString&))); + + setFocusPolicy(Qt::WheelFocus); + + paddle_pos = (Board::Height-12)/2-Board::Paddle/2; + endPaddlePos = paddle_pos; + + emit moveLeftPaddle(paddle_pos); + board->setRightPaddle(paddle_pos); + + server = new TennisServer(this); + + connect(controller, SIGNAL(moveBall(int,int)), server, SLOT(moveBall(int,int))); + connect(controller, SIGNAL(score(int,int)), server, SLOT(score(int,int))); + connect(this, SIGNAL(moveLeftPaddle(int)), server, SLOT(moveLeftPaddle(int))); + connect(server, SIGNAL(clientConnected(QString)), this, SLOT(serverConnected(QString))); + connect(server, SIGNAL(clientDisconnected(QString)), this, SLOT(serverDisconnected())); + connect(server, SIGNAL(moveRightPaddle(int)), board, SLOT(setRightPaddle(int))); + connect(server, SIGNAL(lag(int)), this, SLOT(lagReport(int))); + + connect(server, SIGNAL(clientConnected(QString)), controller, SLOT(refresh())); + + server->startServer(); + + client = new TennisClient(this); + + connect(client, SIGNAL(moveBall(int,int)), board, SLOT(setBall(int,int))); + connect(client, SIGNAL(moveLeftPaddle(int)), board, SLOT(setLeftPaddle(int))); + connect(client, SIGNAL(connected(QString)), this, SLOT(clientConnected(QString))); + connect(client, SIGNAL(disconnected()), this, SLOT(clientDisconnected())); + connect(this, SIGNAL(moveRightPaddle(int)), client, SLOT(moveRightPaddle(int))); + connect(client, SIGNAL(score(int,int)), board, SLOT(setScore(int,int))); + connect(client, SIGNAL(lag(int)), this, SLOT(lagReport(int))); + + connect(this, SIGNAL(moveLeftPaddle(int)), controller, SLOT(moveLeftPaddle(int))); + connect(this, SIGNAL(moveRightPaddle(int)), controller, SLOT(moveRightPaddle(int))); + connect(server, SIGNAL(moveRightPaddle(int)), controller, SLOT(moveRightPaddle(int))); + + +// ui->pongView->setBackgroundBrush(QBrush(Qt::white)); + ui->pongView->setCacheMode(QGraphicsView::CacheBackground); + +/* QNearFieldManager nearFieldManager; + if (nearFieldManager.isAvailable()) { + m_handover = new Handover(server->serverPort(), this); + connect(m_handover, SIGNAL(bluetoothServiceChanged()), this, SLOT(nearFieldHandover())); + + connect(m_discoveryAgent, SIGNAL(serviceDiscovered(QBluetoothServiceInfo)), + this, SLOT(serviceDiscovered(QBluetoothServiceInfo))); + connect(m_discoveryAgent, SIGNAL(finished()), this, SLOT(discoveryFinished())); + }*/ + + + m_discoveryAgent->setUuidFilter(QBluetoothUuid(serviceUuid)); + + + QString address; + QString port; + QStringList args = QCoreApplication::arguments(); + if (args.length() >= 2){ + address = args.at(1); + if (args.length() >= 3){ + port = args.at(2); + } + } + + if (address.isEmpty()){ + QSettings settings("QtDF", "bttennis"); + address = settings.value("lastclient").toString(); + } + + if (!address.isEmpty()){ + qDebug() << "Connect to" << address << port; + QBluetoothDeviceInfo device = QBluetoothDeviceInfo(QBluetoothAddress(address), "", QBluetoothDeviceInfo::ComputerDevice); + QBluetoothServiceInfo service; + if (!port.isEmpty()) { + QBluetoothServiceInfo::Sequence protocolDescriptorList; + QBluetoothServiceInfo::Sequence protocol; + protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::L2cap)) + << QVariant::fromValue(port.toUShort()); + protocolDescriptorList.append(QVariant::fromValue(protocol)); + service.setAttribute(QBluetoothServiceInfo::ProtocolDescriptorList, + protocolDescriptorList); + qDebug() << "port" << port.toUShort() << service.protocolServiceMultiplexer(); + } + else { + service.setServiceUuid(QBluetoothUuid(serviceUuid)); + } + service.setDevice(device); + client->startClient(service); + board->setStatus("Connecting", 100, 25); + } /*else if (nearFieldManager.isAvailable()) { + board->setStatus(tr("Touch to play"), 100, 25); + }*/ + + setEnabled(true); + + paddleAnimation = new QPropertyAnimation(this, "paddlePos", this); + paddleAnimation->setEasingCurve(QEasingCurve::InOutQuad); + + ui->pongView->installEventFilter(this); + +} + +Tennis::~Tennis() +{ +} + +void Tennis::keyPressEvent(QKeyEvent *event) +{ + if (event->matches(QKeySequence::MoveToNextLine)) { + moveDown(); + } + else if (event->matches(QKeySequence::MoveToPreviousLine)){ + moveUp(); + } +} + +void Tennis::wheelEvent(QWheelEvent *event) +{ + if (event->delta() > 0){ + moveUp(); + } + else { + moveDown(); + } +} + +void Tennis::moveUp(int px) +{ + endPaddlePos -= px; + if (endPaddlePos <= 0) + endPaddlePos = 0; + move(endPaddlePos); +} + +void Tennis::moveDown(int px) +{ + endPaddlePos += px; + if (endPaddlePos > Board::Height-Board::Paddle-24) + endPaddlePos = Board::Height-Board::Paddle-24; + move(endPaddlePos); + +} + +void Tennis::move(int px) +{ + int distance = abs(paddle_pos - endPaddlePos); + + paddleAnimation->stop(); + paddleAnimation->setStartValue(paddle_pos); + paddleAnimation->setEndValue(px); + paddleAnimation->setDuration((1000*distance)/350); + paddleAnimation->start(); +} + +void Tennis::setPaddlePos(int p) +{ + paddle_pos = p; + if (isClient) + emit moveRightPaddle(paddle_pos); + else + emit moveLeftPaddle(paddle_pos); +} + + +void Tennis::mouseMove(int x, int y) +{ + if (isConnected == false){ + // look for clicks in the bt connect icon + if (x > 440 && x < 540 && y > 200 && y < 300) { + qDebug() << "Got connect click!"; + if (m_discoveryAgent->isActive()) { + qDebug() << "stopping!"; + m_discoveryAgent->stop(); + board->animateConnect(false); + } + else { + qDebug() << "starting!"; + startDiscovery(); + } + } + + } + y-=12+Board::Paddle/2; + if (y <= 0) + y = 0; + else if (y > Board::Height-Board::Paddle-24) + y = Board::Height-Board::Paddle-24; + + endPaddlePos = y; + move(y); +} + +void Tennis::clientConnected(const QString &name) +{ + board->setStatus("Connected to " + name, 100, 0); + controller->stop(); + server->stopServer(); + isClient = true; + isConnected = true; + board->animateConnect(false); + board->fadeConnect(true); + emit moveRightPaddle(paddle_pos); +} + +void Tennis::clientDisconnected() +{ + board->setStatus("Disconnect", 100, 25); + controller->start(); + server->startServer(); + client->stopClient(); + isClient = false; + isConnected = false; + discoveryFinished(); +} + +void Tennis::serverConnected(const QString &name) +{ + board->setStatus("Server for " + name, 100, 0); + m_discoveryAgent->stop(); + isConnected = true; + board->animateConnect(false); + board->fadeConnect(true); + emit moveLeftPaddle(paddle_pos); +} + +void Tennis::serverDisconnected() +{ + board->setStatus("Disconnected", 100, 25); + isConnected = false; + discoveryFinished(); +} + +void Tennis::serviceDiscovered(const QBluetoothServiceInfo &serviceInfo) +{ + qDebug() << "***** Discovered! " << serviceInfo.device().name() << serviceInfo.serviceName() << serviceInfo.serviceUuid(); + qDebug() << "Found one!" << serviceInfo.protocolServiceMultiplexer(); + m_discoveryAgent->stop(); + client->startClient(serviceInfo); + QSettings settings("QtDF", "bttennis"); + settings.setValue("lastclient", serviceInfo.device().address().toString()); +} + +void Tennis::discoveryFinished() +{ + if (!m_discoveryAgent->isActive()) { + if (!isConnected) { + board->setStatus("Waiting", 100, 25); + // QTimer::singleShot(60000, this, SLOT(startDiscovery())); + board->animateConnect(false); + board->fadeConnect(false); + } + } +} + +void Tennis::startDiscovery() +{ + qDebug() << "startDiscovery() called"; + if (!isConnected) { + qDebug() << "Scanning!"; + board->setStatus("Scanning", 100, 25); + board->fadeConnect(false); + board->animateConnect(true); + m_discoveryAgent->start(QBluetoothServiceDiscoveryAgent::MinimalDiscovery); +// if (quickDiscovery) +// m_discoveryAgent->start(QBluetoothServiceDiscoveryAgent::MinimalDiscovery); +// else +// m_discoveryAgent->start(QBluetoothServiceDiscoveryAgent::FullDiscovery); +// quickDiscovery = !quickDiscovery; + } + else { + qDebug() << "Stop scanning!"; + board->setStatus("", 0, 0); + board->animateConnect(false); + board->fadeConnect(true); + } +} + +void Tennis::resizeEvent(QResizeEvent *re) +{ + if (re->oldSize().height() > 0){ + qreal x, y; + x = (re->size().width())/qreal(re->oldSize().width()); + y = (re->size().height())/qreal(re->oldSize().height()); + ui->pongView->scale(x, y); + } + ui->pongView->resize(re->size()); +} + +void Tennis::lagReport(int ms) +{ + if (ms > 250){ + board->setStatus(QString("Caution Lag %1ms").arg(ms), 100, 0); + } +} + +/*void Tennis::nearFieldHandover() +{ + qDebug() << "Connecting to NFC provided address" << m_handover->bluetoothAddress().toString(); + + QBluetoothDeviceInfo device = QBluetoothDeviceInfo(m_handover->bluetoothAddress(), QString(), + QBluetoothDeviceInfo::ComputerDevice); + + QBluetoothServiceInfo service; + service.setServiceUuid(QBluetoothUuid(serviceUuid)); + service.setDevice(device); + + QBluetoothServiceInfo::Sequence protocolDescriptorList; + QBluetoothServiceInfo::Sequence protocol; + protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::L2cap)) + << QVariant::fromValue(m_handover->serverPort()); + protocolDescriptorList.append(QVariant::fromValue(protocol)); + service.setAttribute(QBluetoothServiceInfo::ProtocolDescriptorList, + protocolDescriptorList); + + client->startClient(service); + board->setStatus(tr("Connecting: %1 %2").arg(m_handover->bluetoothAddress().toString()).arg(m_handover->serverPort()), 100, 25); +}*/ + +void Tennis::fps(const QString &f) +{ + board->setStatus(f, 100, 100); +} + diff --git a/examples/bluetooth/bttennis/tennis.h b/examples/bluetooth/bttennis/tennis.h new file mode 100644 index 00000000..92b5f0fa --- /dev/null +++ b/examples/bluetooth/bttennis/tennis.h @@ -0,0 +1,140 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "ui_tennis.h" + +#include <QDialog> + +#include <QResizeEvent> +#include <QMoveEvent> +#include <QPropertyAnimation> +#include <qbluetoothserviceinfo.h> +#include <qbluetoothsocket.h> +#include <qbluetoothdevicediscoveryagent.h> + +#include "board.h" +#include "controller.h" + +#include <QDebug> + +QTBLUETOOTH_BEGIN_NAMESPACE +class QBluetoothServiceDiscoveryAgent; +QTBLUETOOTH_END_NAMESPACE + +QTBLUETOOTH_USE_NAMESPACE + +static const QLatin1String serviceUuid("e8e10f95-1a70-4b27-9ccf-02010264e9c9"); + +class TennisServer; +class TennisClient; +//class Handover; + +//! [declaration] +class Tennis : public QDialog +{ + Q_OBJECT + Q_PROPERTY(int paddlePos READ paddlePos WRITE setPaddlePos) + +public: + Tennis(QWidget *parent = 0); + ~Tennis(); + + int paddlePos() { return paddle_pos; } + void setPaddlePos(int p); + +signals: + void moveLeftPaddle(int y); + void moveRightPaddle(int y); + +protected: + void wheelEvent ( QWheelEvent * event ); + void keyPressEvent ( QKeyEvent * event ); + void resizeEvent(QResizeEvent *); + +private slots: + void serverConnected(const QString &name); + void serverDisconnected(); + + void clientConnected(const QString &name); + void clientDisconnected(); + + void serviceDiscovered(const QBluetoothServiceInfo &serviceInfo); + void discoveryFinished(); + + void startDiscovery(); + + void mouseMove(int x, int y); + + void lagReport(int ms); + +// void nearFieldHandover(); + + void fps(const QString &f); + +private: + + void moveUp(int px = 10); + void moveDown(int px = 10); + + void move(int px); + + Ui_Tennis *ui; + + Board *board; + Controller *controller; + + int paddle_pos; + int endPaddlePos; + + bool isClient; + bool isConnected; + bool quickDiscovery; + + QBluetoothSocket *socket; + TennisServer *server; + TennisClient *client; + + QPropertyAnimation *paddleAnimation; + + QBluetoothServiceDiscoveryAgent *m_discoveryAgent; +// Handover *m_handover; +}; +//! [declaration] diff --git a/examples/bluetooth/bttennis/tennis.qrc b/examples/bluetooth/bttennis/tennis.qrc new file mode 100644 index 00000000..12aa7464 --- /dev/null +++ b/examples/bluetooth/bttennis/tennis.qrc @@ -0,0 +1,5 @@ +<RCC> + <qresource prefix="/icons"> + <file>connect.png</file> + </qresource> +</RCC> diff --git a/examples/bluetooth/bttennis/tennis.ui b/examples/bluetooth/bttennis/tennis.ui new file mode 100644 index 00000000..d6625fa8 --- /dev/null +++ b/examples/bluetooth/bttennis/tennis.ui @@ -0,0 +1,57 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>Tennis</class> + <widget class="QDialog" name="Tennis"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>640</width> + <height>360</height> + </rect> + </property> + <property name="windowTitle"> + <string>Bluetooth Tennis</string> + </property> + <widget class="TennisView" name="pongView"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>640</width> + <height>366</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Plain</enum> + </property> + <property name="lineWidth"> + <number>0</number> + </property> + <property name="verticalScrollBarPolicy"> + <enum>Qt::ScrollBarAlwaysOff</enum> + </property> + <property name="horizontalScrollBarPolicy"> + <enum>Qt::ScrollBarAlwaysOff</enum> + </property> + </widget> + </widget> + <customwidgets> + <customwidget> + <class>TennisView</class> + <extends>QGraphicsView</extends> + <header>tennisview.h</header> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> diff --git a/examples/bluetooth/bttennis/tennisclient.cpp b/examples/bluetooth/bttennis/tennisclient.cpp new file mode 100644 index 00000000..c5487f02 --- /dev/null +++ b/examples/bluetooth/bttennis/tennisclient.cpp @@ -0,0 +1,200 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "tennisclient.h" + +#include <qbluetoothsocket.h> + +#include <QtCore/QDataStream> +#include <QtCore/QByteArray> + +#include <QtCore/QStringList> + +TennisClient::TennisClient(QObject *parent) +: QObject(parent), socket(0), stream(0), elapsed(new QTime), lagTimeout(0) +{ + lagTimer.setInterval(1000); + connect(&lagTimer, SIGNAL(timeout()), this, SLOT(sendEcho())); +} + +TennisClient::~TennisClient() +{ + stopClient(); +} + +//! [startClient] +void TennisClient::startClient(const QBluetoothServiceInfo &remoteService) +{ + if (socket) + return; + + serviceInfo = remoteService; + + // Connect to service + socket = new QBluetoothSocket(QBluetoothSocket::L2capSocket); + qDebug() << "Create socket"; + socket->connectToService(remoteService); + qDebug() << "ConnecttoService done"; + + connect(socket, SIGNAL(readyRead()), this, SLOT(readSocket())); + connect(socket, SIGNAL(connected()), this, SLOT(connected())); + connect(socket, SIGNAL(disconnected()), this, SIGNAL(disconnected())); + connect(socket, SIGNAL(disconnected()), this, SLOT(socketDisconnected())); + connect(socket, SIGNAL(error(QBluetoothSocket::SocketError)), this, SLOT(error(QBluetoothSocket::SocketError))); + + lagTimer.start(); +} +//! [startClient] + +//! [stopClient] +void TennisClient::stopClient() +{ + if (socket == 0) // already stopped + return; + + qDebug() << Q_FUNC_INFO << "closing client!"; + + lagTimer.stop(); + + delete stream; + stream = 0; + + socket->deleteLater(); + socket = 0; +} +//! [stopClient] + +//! [socketDisconnected] +void TennisClient::socketDisconnected() +{ + qDebug() << "Got socketDisconnected"; + stopClient(); +} +//! [socketDisconnected] + +//! [readSocket] +void TennisClient::readSocket() +{ + if (!socket) + return; + + while (socket->bytesAvailable()) { + QString str; + + *stream >> str; + + QStringList args = str.split(QChar(' ')); + QString s = args.takeFirst(); + + if (s == "m" && args.count() == 2) { + emit moveBall(args.at(0).toInt(), args.at(1).toInt()); + } + else if (s == "s" && args.count() == 2){ + emit score(args.at(0).toInt(), args.at(1).toInt()); + } + else if (s == "l" && args.count() == 1){ + emit moveLeftPaddle(args.at(0).toInt()); + } + else if (s == "e"){ // echo + QByteArray b; + QDataStream s(&b, QIODevice::WriteOnly); + s << str; + socket->write(b); + } + else if (s == "E"){ + lagTimeout = 0; + QTime then = QTime::fromString(args.at(0), "hh:mm:ss.zzz"); + if (then.isValid()) { + emit lag(then.msecsTo(QTime::currentTime())); +// qDebug() << "RTT: " << then.msecsTo(QTime::currentTime()) << "ms"; + } + } + else { + qDebug() << Q_FUNC_INFO << "Unknown command" << str; + } + } +} +//! [readSocket] + +//! [moveRightPaddle] +void TennisClient::moveRightPaddle(int y) +{ + int msec = elapsed->elapsed(); + + if (stream && msec > 50) { + QByteArray b; + QDataStream s(&b, QIODevice::WriteOnly); + s << QString("r %1").arg(y); + socket->write(b); + elapsed->restart(); + } +} +//! [moveRightPaddle] + +//! [connected] +void TennisClient::connected() +{ + stream = new QDataStream(socket); + emit connected(socket->peerName()); +} +//! [connected] + +void TennisClient::error(QBluetoothSocket::SocketError err) +{ + qDebug() << "Got socket error" <<Q_FUNC_INFO << "error" << err; + emit disconnected(); +} + +void TennisClient::sendEcho() +{ + if (lagTimeout) { + lagTimeout--; + return; + } + + if (stream) { + QByteArray b; + QDataStream s(&b, QIODevice::WriteOnly); + s << QString("E %1").arg(QTime::currentTime().toString("hh:mm:ss.zzz")); + socket->write(b); + lagTimeout = 10; + } +} diff --git a/examples/bluetooth/bttennis/tennisclient.h b/examples/bluetooth/bttennis/tennisclient.h new file mode 100644 index 00000000..aeccfca1 --- /dev/null +++ b/examples/bluetooth/bttennis/tennisclient.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CHATCLIENT_H +#define CHATCLIENT_H + +#include <qbluetoothserviceinfo.h> +#include <qbluetoothsocket.h> + +#include <QtCore/QObject> +#include <QtCore/QTime> +#include <QtCore/QTimer> + +QTBLUETOOTH_BEGIN_NAMESPACE +class QBluetoothSocket; +QTBLUETOOTH_END_NAMESPACE + +QT_BEGIN_NAMESPACE +class QDataStream; +QT_END_NAMESPACE + +QTBLUETOOTH_USE_NAMESPACE + +//! [declaration] +class TennisClient : public QObject +{ + Q_OBJECT + +public: + explicit TennisClient(QObject *parent = 0); + ~TennisClient(); + + void startClient(const QBluetoothServiceInfo &remoteService); + void stopClient(); + +public slots: + void moveRightPaddle(int y); + void error(QBluetoothSocket::SocketError); + +signals: + void moveBall(int x, int y); + void score(int left, int right); + void moveLeftPaddle(int y); + + void connected(const QString &name); + void disconnected(); + + void lag(int ms); + +private slots: + void readSocket(); + void connected(); + void sendEcho(); + void socketDisconnected(); + +private: + QBluetoothSocket *socket; + QDataStream *stream; + QBluetoothServiceInfo serviceInfo; + QTime *elapsed; + QTimer lagTimer; + int lagTimeout; +}; +//! [declaration] + +#endif // CHATCLIENT_H diff --git a/examples/bluetooth/bttennis/tennisserver.cpp b/examples/bluetooth/bttennis/tennisserver.cpp new file mode 100644 index 00000000..21af2975 --- /dev/null +++ b/examples/bluetooth/bttennis/tennisserver.cpp @@ -0,0 +1,306 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "tennisserver.h" +#include "tennis.h" + +#include <ql2capserver.h> +#include <qbluetoothsocket.h> + +#include <QDebug> + +TennisServer::TennisServer(QObject *parent) +: QObject(parent), l2capServer(0), clientSocket(0), stream(0), lagReplyTimeout(0) +{ + elapsed.start(); + ballElapsed.start(); + lagTimer.setInterval(1000); + connect(&lagTimer, SIGNAL(timeout()), this, SLOT(sendEcho())); +} + +TennisServer::~TennisServer() +{ + if (stream){ + QByteArray b; + QDataStream s(&b, QIODevice::WriteOnly); + s << QString("D"); + clientSocket->write(b); + } + + stopServer(); +} + +void TennisServer::startServer() +{ + if (l2capServer) + return; + + //! [Create the server] + l2capServer = new QL2capServer(this); + connect(l2capServer, SIGNAL(newConnection()), this, SLOT(clientConnected())); + l2capServer->listen(); + //! [Create the server] + + serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceRecordHandle, (uint)0x00010010); + + //! [Class ServiceClass must contain at least 1 entry] + QBluetoothServiceInfo::Sequence classId; +// classId << QVariant::fromValue(QBluetoothUuid(serviceUuid)); + classId << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::SerialPort)); + serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceClassIds, classId); + //! [Class ServiceClass must contain at least 1 entry] + + + //! [Service name, description and provider] + serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceName, tr("Example Tennis Server")); + serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceDescription, + tr("Example bluetooth tennis server")); + serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceProvider, tr("Nokia, QtDF")); + //! [Service name, description and provider] + + //! [Service UUID set] + serviceInfo.setServiceUuid(QBluetoothUuid(serviceUuid)); + //! [Service UUID set] + + //! [Service Discoverability] + serviceInfo.setAttribute(QBluetoothServiceInfo::BrowseGroupList, + QBluetoothUuid(QBluetoothUuid::PublicBrowseGroup)); + //! [Service Discoverability] + + + //! [Protocol descriptor list] + QBluetoothServiceInfo::Sequence protocolDescriptorList; + QBluetoothServiceInfo::Sequence protocol; + protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::L2cap)) + << QVariant::fromValue(quint16(l2capServer->serverPort())); + protocolDescriptorList.append(QVariant::fromValue(protocol)); + serviceInfo.setAttribute(QBluetoothServiceInfo::ProtocolDescriptorList, + protocolDescriptorList); + //! [Protocol descriptor list] + + //! [Register service] + serviceInfo.registerService(); + //! [Register service] + +} + +//! [stopServer] +void TennisServer::stopServer() +{ + qDebug() <<Q_FUNC_INFO; + // Unregister service + serviceInfo.unregisterService(); + + delete stream; + stream = 0; + + // Close sockets + delete clientSocket; + clientSocket = 0; + + // Close server + delete l2capServer; + l2capServer = 0; +} +//! [stopServer] + +quint16 TennisServer::serverPort() const +{ + return l2capServer->serverPort(); +} + +//! [moveBall] +void TennisServer::moveBall(int x, int y) +{ + int msec = ballElapsed.elapsed(); + + if (stream && msec > 30){ + QByteArray b; + QDataStream s(&b, QIODevice::WriteOnly); + s << QString("m %1 %2").arg(x).arg(y); + //s << QLatin1String("m") << x << y; + clientSocket->write(b); + ballElapsed.restart(); + } +} +//! [moveBall] + +void TennisServer::score(int left, int right) +{ + if (stream){ + QByteArray b; + QDataStream s(&b, QIODevice::WriteOnly); + s << QString("s %1 %2").arg(left).arg(right); +// s << QChar('s') << left << right; + clientSocket->write(b); + } +} + +void TennisServer::moveLeftPaddle(int y) +{ + + int msec = elapsed.elapsed(); + + if (stream && msec > 50) { + QByteArray b; + QDataStream s(&b, QIODevice::WriteOnly); + s << QString("l %1").arg(y); +// s << QChar('l') << y; + clientSocket->write(b); + elapsed.restart(); + } +} + +void TennisServer::readSocket() +{ + if (!clientSocket) + return; + + while (clientSocket->bytesAvailable()) { + + QString str; + *stream >> str; + QStringList args = str.split(QChar(' ')); + QString s = args.takeFirst(); + + if (s == "r" && args.count() == 1){ + emit moveRightPaddle(args.at(0).toInt()); + } + else if (s == "e" && args.count() == 1){ + lagReplyTimeout = 0; + QTime then = QTime::fromString(args.at(0), "hh:mm:ss.zzz"); + if (then.isValid()) { + emit lag(then.msecsTo(QTime::currentTime())); +// qDebug() << "RTT: " << then.msecsTo(QTime::currentTime()) << "ms"; + } + } + else if (s == "E"){ + QByteArray b; + QDataStream st(&b, QIODevice::WriteOnly); + st << str; + clientSocket->write(b); + } + else if (s == "D"){ + qDebug() << Q_FUNC_INFO << "closing!"; + clientSocket->deleteLater(); + clientSocket = 0; + } + else { + qDebug() << Q_FUNC_INFO << "Unknown command" << str; + } + } +} + +//! [clientConnected] +void TennisServer::clientConnected() +{ + qDebug() << Q_FUNC_INFO << "connect"; + + QBluetoothSocket *socket = l2capServer->nextPendingConnection(); + if (!socket) + return; + + if (clientSocket){ + qDebug() << Q_FUNC_INFO << "Closing socket!"; + delete socket; + return; + } + + connect(socket, SIGNAL(readyRead()), this, SLOT(readSocket())); + connect(socket, SIGNAL(disconnected()), this, SLOT(clientDisconnected())); + connect(socket, SIGNAL(error(QBluetoothSocket::SocketError)), this, SLOT(socketError(QBluetoothSocket::SocketError))); + + stream = new QDataStream(socket); + + clientSocket = socket; + + qDebug() << Q_FUNC_INFO << "started"; + + emit clientConnected(clientSocket->peerName()); + lagTimer.start(); +} +//! [clientConnected] + +void TennisServer::socketError(QBluetoothSocket::SocketError err) +{ + qDebug() << Q_FUNC_INFO << err; +} + +//! [sendEcho] +void TennisServer::sendEcho() +{ + if (lagReplyTimeout) { + lagReplyTimeout--; + return; + } + + if (stream) { + QByteArray b; + QDataStream s(&b, QIODevice::WriteOnly); + s << QString("e %1").arg(QTime::currentTime().toString("hh:mm:ss.zzz")); + clientSocket->write(b); + lagReplyTimeout = 10; + } +} +//! [sendEcho] + +//! [clientDisconnected] +void TennisServer::clientDisconnected() +{ + qDebug() << Q_FUNC_INFO << "client closing!"; + + lagTimer.stop(); + lagReplyTimeout = 0; + QBluetoothSocket *socket = qobject_cast<QBluetoothSocket *>(sender()); + if (!socket) + return; + + emit clientDisconnected(socket->peerName()); + + clientSocket->deleteLater(); + clientSocket = 0; + delete stream; + stream = 0; + +// socket->deleteLater(); +} +//! [clientDisconnected] + diff --git a/examples/bluetooth/bttennis/tennisserver.h b/examples/bluetooth/bttennis/tennisserver.h new file mode 100644 index 00000000..bfce30ae --- /dev/null +++ b/examples/bluetooth/bttennis/tennisserver.h @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TENNISSERVER_H +#define TENNISSERVER_H + +#include <qbluetoothserviceinfo.h> +#include <qbluetoothsocket.h> + +#include <QtCore/QObject> +#include <QtCore/QList> +#include <QtCore/QDataStream> +#include <QtCore/QTime> +#include <QtCore/QTimer> + +QTBLUETOOTH_BEGIN_NAMESPACE +class QL2capServer; +class QBluetoothSocket; +class QBluetoothServiceInfo; +QTBLUETOOTH_END_NAMESPACE + +QTBLUETOOTH_USE_NAMESPACE + +//! [declaration] +class TennisServer : public QObject +{ + Q_OBJECT + +public: + explicit TennisServer(QObject *parent = 0); + ~TennisServer(); + + void startServer(); + void stopServer(); + + quint16 serverPort() const; + +public slots: + void moveBall(int x, int y); + void score(int left, int right); + void moveLeftPaddle(int y); + +signals: + void moveRightPaddle(int y); + void clientDisconnected(const QString &name); + void clientConnected(const QString &name); + void lag(int ms); + +private slots: + void clientConnected(); + void clientDisconnected(); + void readSocket(); + void sendEcho(); + void socketError(QBluetoothSocket::SocketError err); + +private: + QL2capServer *l2capServer; + QBluetoothServiceInfo serviceInfo; + QBluetoothSocket *clientSocket; + QDataStream *stream; + QTime elapsed; + QTime ballElapsed; + QTimer lagTimer; + int lagReplyTimeout; +}; +//! [declaration] + +#endif // CHATSERVER_H diff --git a/examples/bluetooth/bttennis/tennisview.cpp b/examples/bluetooth/bttennis/tennisview.cpp new file mode 100644 index 00000000..74a43354 --- /dev/null +++ b/examples/bluetooth/bttennis/tennisview.cpp @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include "tennisview.h" + +#include <QMouseEvent> + +TennisView::TennisView(QWidget *parent) : + QGraphicsView(parent) +{ +} + +void TennisView::mousePressEvent(QMouseEvent *event) +{ + QPointF p = mapToScene(event->x(), event->y()); + emit mousePress(p.x(), p.y()); + emit mouseMove(p.x(), p.y()); + last_y = p.y(); +} + +void TennisView::mouseMoveEvent(QMouseEvent *event) +{ + if (event->buttons()) { + QPointF p = mapToScene(event->x(), event->y()); + if (10 < abs(last_y - event->y())) { +// emit mouseMove(p.x(), p.y()); + last_y = p.y(); + } + } +} diff --git a/examples/bluetooth/bttennis/tennisview.h b/examples/bluetooth/bttennis/tennisview.h new file mode 100644 index 00000000..f6bb767e --- /dev/null +++ b/examples/bluetooth/bttennis/tennisview.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef TENNISVIEW_H +#define TENNISVIEW_H + +#include <QGraphicsView> + +class TennisView : public QGraphicsView +{ + Q_OBJECT +public: + explicit TennisView(QWidget *parent = 0); + +signals: + void mouseMove(int x, int y); + void mousePress(int x, int y); + +public slots: + +protected: + void mousePressEvent(QMouseEvent *event); + void mouseMoveEvent(QMouseEvent *ev); + +private: + int last_y; + +}; + +#endif // TENNISVIEW_H diff --git a/examples/bluetooth/scanner/qmlscanner.cpp b/examples/bluetooth/scanner/qmlscanner.cpp new file mode 100644 index 00000000..b86ed72f --- /dev/null +++ b/examples/bluetooth/scanner/qmlscanner.cpp @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the examples of the QtBluetooth module. +** +** $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 Digia Plc and its Subsidiary(-ies) 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 <QtGui/QGuiApplication> +#include <QtQuick/QQuickView> +#include <QtQml/QQmlEngine> + +int main(int argc, char *argv[]) +{ + QGuiApplication application(argc, argv); + const QString mainQmlApp = QLatin1String("qrc:/scanner.qml"); + QQuickView view; + view.setSource(QUrl(mainQmlApp)); + view.setResizeMode(QQuickView::SizeRootObjectToView); + // Qt.quit() called in embedded .qml by default only emits + // quit() signal, so do this (optionally use Qt.exit()). + QObject::connect(view.engine(), SIGNAL(quit()), qApp, SLOT(quit())); +#if defined(Q_WS_MAEMO_6) + view.showFullScreen(); +#else + view.setGeometry(QRect(100, 100, 360, 640)); + view.show(); +#endif + return application.exec(); +} diff --git a/examples/bluetooth/scanner/scanner.pro b/examples/bluetooth/scanner/scanner.pro new file mode 100644 index 00000000..ff046a96 --- /dev/null +++ b/examples/bluetooth/scanner/scanner.pro @@ -0,0 +1,11 @@ +QT += concurrent network bluetooth quick +SOURCES += qmlscanner.cpp + +TARGET = qml_scanner +TEMPLATE = app + +RESOURCES += \ + scanner.qrc + +OTHER_FILES += \ + scanner.qml diff --git a/examples/bluetooth/scanner/scanner.qml b/examples/bluetooth/scanner/scanner.qml new file mode 100644 index 00000000..e83b0a03 --- /dev/null +++ b/examples/bluetooth/scanner/scanner.qml @@ -0,0 +1,246 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the examples of the QtBluetooth module. +** +** $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 Digia Plc and its Subsidiary(-ies) 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$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtBluetooth 5.0 + +Item { + id: top + + property BluetoothService currentService + property alias minimalDiscovery: myModel.minimalDiscovery + + BluetoothDiscoveryModel { + id: myModel + minimalDiscovery: true + onDiscoveryChanged: busy.running = discovery; + onNewServiceDiscovered: console.log("Found new service " + service.deviceAddress + " " + service.deviceName + " " + service.serviceName); + } + + Rectangle { + id: busy + property bool running: true + + width: top.width/1.2; + x: top.width/2-width/2 + anchors.top: top.top; + height: 20; + radius: 5 + color: "#1c56f3" + + Text { + id: text + text: "<b>Scanning</b>" + x: busy.width/2-paintedWidth/2 + y: busy.height/2-paintedHeight/2 + } + + SequentialAnimation on color { + id: busyThrobber + ColorAnimation { easing.type: Easing.InOutSine; from: "#1c56f3"; to: "white"; duration: 1000; } + ColorAnimation { easing.type: Easing.InOutSine; to: "#1c56f3"; from: "white"; duration: 1000 } + loops: Animation.Infinite + } + states: [ + State { + name: "stopped" + when: !busy.running + PropertyChanges { target: busy; height: 0; } + PropertyChanges { target: busyThrobber; running: false } + PropertyChanges { target: text; visible: false } + } + ] + transitions: [ + Transition { + from: "*" + to: "stopped" + reversible: true + NumberAnimation { target: busy; property: "height"; to: 0; duration: 200 } + } + ] + } + + Component { + id: del; + + Item { + id: item + + function item_clicked(service) { + console.log("Clicked " + service.deviceName + service.deviceAddress); + top.currentService = service; + } + + property int text_height: 5+(bticon.height > bttext.height ? bticon.height : bttext.height) + + height: text_height + width: parent.width + + Column { + anchors.fill: item + Row { + width: parent.width + Image { + id: bticon + source: icon; + width: del.height; + } + Text { + id: bttext + text: name; + font.family: "FreeSerif" + font.pointSize: 12 + } + } + Text { + function get_details(s) { + var str = "Address: " + s.deviceAddress; + if (s.serviceName) { str += "<br>Service: " + s.serviceName; } + if (s.serviceDescription) { str += "<br>Description: " + s.serviceDescription; } + if (s.serviceProtocol) { str += "<br>Port: " + s.serviceProtocol; } + if (s.servicePort) { str += "<br>Port: " + s.servicePort; } + return str; + } + + id: details + opacity: 0.0 + text: get_details(service) + font: bttext.font + x: bticon.width + } + } + + MouseArea { + anchors.fill: parent + onClicked: item.state = ((item.state == "details") ? "" : "details") + } + + states: [ + State { + name: "details" + PropertyChanges { target: item; height: item.text_height+details.height; } + PropertyChanges { target: details; opacity: 1.0 } + } + ] + transitions: [ + Transition { + from: "*" + to: "details" + reversible: true + NumberAnimation { target: item; property: "height"; duration: 200 } + NumberAnimation { target: details; property: "lopacity"; duration: 200 } + } + ] + } + } + + Component { + id: highlightBox + + Rectangle { + id: background + anchors.fill: del + border.color: "#34ca57" + radius: 5 + border.width: 2 + } + + } + + ListView { + id: mainList + width: top.width + anchors.top: busy.bottom + anchors.bottom: fullbutton.top + + model: myModel + highlight: highlightBox + delegate: del + focus: true + } + + Rectangle { + id: fullbutton + + function button_clicked() { + myModel.minimalDiscovery = !myModel.minimalDiscovery; + fullbutton.state = fullbutton.state == "clicked" ? "" : "clicked"; + myModel.setDiscovery(true); + } + + anchors.bottom: top.bottom + anchors.margins: 3 + + width: top.width-6 + x: 3 + height: 20 + + radius: 5 + border.width: 1 + color: "white" + + Text { + id: label + text: "Full Discovery" + x: parent.width/2-paintedWidth/2; + y: parent.height/2-paintedHeight/2; + } + + MouseArea { + anchors.fill: parent + onClicked: fullbutton.button_clicked(); + } + + states: [ + State { + name: "clicked" + PropertyChanges { target: fullbutton; color: "#1c56f3" } + } + ] + transitions: [ + Transition { + from: "*" + to: "details" + reversible: true + ColorAnimation { duration: 200 } + } + ] + } +} diff --git a/examples/bluetooth/scanner/scanner.qrc b/examples/bluetooth/scanner/scanner.qrc new file mode 100644 index 00000000..93e9ce08 --- /dev/null +++ b/examples/bluetooth/scanner/scanner.qrc @@ -0,0 +1,5 @@ +<RCC> + <qresource prefix="/"> + <file>scanner.qml</file> + </qresource> +</RCC> |