commit 2debcf4c7df16da344222090c8f6d64a61e1b2c9 Author: Jaro Date: Mon Oct 26 20:25:50 2020 +0100 Initial MQTT bell app based on systray diff --git a/doc/images/systemtray-editor.png b/doc/images/systemtray-editor.png new file mode 100644 index 0000000..f7c23db Binary files /dev/null and b/doc/images/systemtray-editor.png differ diff --git a/doc/images/systemtray-example.png b/doc/images/systemtray-example.png new file mode 100644 index 0000000..98b5c81 Binary files /dev/null and b/doc/images/systemtray-example.png differ diff --git a/doc/src/systray.qdoc b/doc/src/systray.qdoc new file mode 100644 index 0000000..ae7e925 --- /dev/null +++ b/doc/src/systray.qdoc @@ -0,0 +1,187 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** 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: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example desktop/systray + \title System Tray Icon Example + \ingroup examples-widgets + \brief The System Tray Icon example shows how to add an icon with a menu + and popup messages to a desktop environment's system tray. + + \borderedimage systemtray-example.png + \caption Screenshot of the System Tray Icon + + Modern operating systems usually provide a special area on the + desktop, called the system tray or notification area, where + long-running applications can display icons and short messages. + + This example consists of one single class, \c Window, providing + the main application window (i.e., an editor for the system tray + icon) and the associated icon. + + \borderedimage systemtray-editor.png + + The editor allows the user to choose the preferred icon as well as + set the balloon message's type and duration. The user can also + edit the message's title and body. Finally, the editor provides a + checkbox controlling whether the icon is actually shown in the + system tray, or not. + + \section1 Window Class Definition + + The \c Window class inherits QWidget: + + \snippet desktop/systray/window.h 0 + + We implement several private slots to respond to user + interaction. The other private functions are only convenience + functions provided to simplify the constructor. + + The tray icon is an instance of the QSystemTrayIcon class. To + check whether a system tray is present on the user's desktop, call + the static QSystemTrayIcon::isSystemTrayAvailable() + function. Associated with the icon, we provide a menu containing + the typical \uicontrol minimize, \uicontrol maximize, \uicontrol restore and + \uicontrol quit actions. We reimplement the QWidget::setVisible() function to + update the tray icon's menu whenever the editor's appearance + changes, e.g., when maximizing or minimizing the main application + window. + + Finally, we reimplement QWidget's \l {QWidget::}{closeEvent()} + function to be able to inform the user (when closing the editor + window) that the program will keep running in the system tray + until the user chooses the \uicontrol Quit entry in the icon's context + menu. + + \section1 Window Class Implementation + + When constructing the editor widget, we first create the various + editor elements before we create the actual system tray icon: + + \snippet desktop/systray/window.cpp 0 + + We ensure that the application responds to user input by + connecting most of the editor's input widgets (including the + system tray icon) to the application's private slots. But note the + visibility checkbox; its \l {QCheckBox::}{toggled()} signal is + connected to the \e {icon}'s \l {QSystemTrayIcon::}{setVisible()} + function instead. + + \snippet desktop/systray/window.cpp 3 + + The \c setIcon() slot is triggered whenever the current index in + the icon combobox changes, i.e., whenever the user chooses another + icon in the editor. Note that it is also called when the user + activates the tray icon with the left mouse button, triggering the + icon's \l {QSystemTrayIcon::}{activated()} signal. We will come + back to this signal shortly. + + The QSystemTrayIcon::setIcon() function sets the \l + {QSystemTrayIcon::}{icon} property that holds the actual system + tray icon. On Windows, the system tray icon size is 16x16; on X11, + the preferred size is 22x22. The icon will be scaled to the + appropriate size as necessary. + + Note that on X11, due to a limitation in the system tray + specification, mouse clicks on transparent areas in the icon are + propagated to the system tray. If this behavior is unacceptable, + we suggest using an icon with no transparency. + + \snippet desktop/systray/window.cpp 4 + + Whenever the user activates the system tray icon, it emits its \l + {QSystemTrayIcon::}{activated()} signal passing the triggering + reason as parameter. QSystemTrayIcon provides the \l + {QSystemTrayIcon::}{ActivationReason} enum to describe how the + icon was activated. + + In the constructor, we connected our icon's \l + {QSystemTrayIcon::}{activated()} signal to our custom \c + iconActivated() slot: If the user has clicked the icon using the + left mouse button, this function changes the icon image by + incrementing the icon combobox's current index, triggering the \c + setIcon() slot as mentioned above. If the user activates the icon + using the middle mouse button, it calls the custom \c + showMessage() slot: + + \snippet desktop/systray/window.cpp 5 + + When the \e showMessage() slot is triggered, we first retrieve the + message icon depending on the currently chosen message type. The + QSystemTrayIcon::MessageIcon enum describes the icon that is shown + when a balloon message is displayed. Then we call + QSystemTrayIcon's \l {QSystemTrayIcon::}{showMessage()} function + to show the message with the title, body, and icon for the time + specified in milliseconds. + + \macos users note: The Growl notification system must be + installed for QSystemTrayIcon::showMessage() to display messages. + + QSystemTrayIcon also has the corresponding, \l {QSystemTrayIcon::} + {messageClicked()} signal, which is emitted when the user clicks a + message displayed by \l {QSystemTrayIcon::}{showMessage()}. + + \snippet desktop/systray/window.cpp 6 + + In the constructor, we connected the \l + {QSystemTrayIcon::}{messageClicked()} signal to our custom \c + messageClicked() slot that simply displays a message using the + QMessageBox class. + + QMessageBox provides a modal dialog with a short message, an icon, + and buttons laid out depending on the current style. It supports + four severity levels: "Question", "Information", "Warning" and + "Critical". The easiest way to pop up a message box in Qt is to + call one of the associated static functions, e.g., + QMessageBox::information(). + + As we mentioned earlier, we reimplement a couple of QWidget's + virtual functions: + + \snippet desktop/systray/window.cpp 1 + + Our reimplementation of the QWidget::setVisible() function updates + the tray icon's menu whenever the editor's appearance changes, + e.g., when maximizing or minimizing the main application window, + before calling the base class implementation. + + \snippet desktop/systray/window.cpp 2 + + We have reimplemented the QWidget::closeEvent() event handler to + receive widget close events, showing the above message to the + users when they are closing the editor window. On \macos we need to + avoid showing the message and accepting the close event when the + user really intends to quit the application, that is, when the + user has triggered "Quit" in the menu bar or pressed the Command+Q + shortcut. + + In addition to the functions and slots discussed above, we have + also implemented several convenience functions to simplify the + constructor: \c createIconGroupBox(), \c createMessageGroupBox(), + \c createActions() and \c createTrayIcon(). See the \c + {desktop/systray/window.cpp} file for details. +*/ diff --git a/images/bad.png b/images/bad.png new file mode 100644 index 0000000..c8701a2 Binary files /dev/null and b/images/bad.png differ diff --git a/images/bell-icon.png b/images/bell-icon.png new file mode 100644 index 0000000..f8f90c3 Binary files /dev/null and b/images/bell-icon.png differ diff --git a/images/heart.png b/images/heart.png new file mode 100644 index 0000000..cee1302 Binary files /dev/null and b/images/heart.png differ diff --git a/images/trash.png b/images/trash.png new file mode 100644 index 0000000..4c24db9 Binary files /dev/null and b/images/trash.png differ diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..ecae1fc --- /dev/null +++ b/main.cpp @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#ifndef QT_NO_SYSTEMTRAYICON + +#include +#include "window.h" +#include "subscriber.h" + +int main(int argc, char *argv[]) +{ + Q_INIT_RESOURCE(systray); + + qDebug() << "Starting UP1..."; + + QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); + + QApplication app(argc, argv); + + if (!QSystemTrayIcon::isSystemTrayAvailable()) { + QMessageBox::critical(nullptr, QObject::tr("Systray"), + QObject::tr("I couldn't detect any system tray " + "on this system.")); + return 1; + } + QApplication::setQuitOnLastWindowClosed(false); + + Subscriber subscriber; + subscriber.connectToHost(); + + Window window; + window.show(); + + QObject::connect(&subscriber,&Subscriber::packetArrived,&window,&Window::packetArrived); + QObject::connect(&window,&Window::settingsChanged,&subscriber,&Subscriber::onSettingsChanged); + + window.hide(); + return app.exec(); +} + +#else + +#include +#include + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + QString text("QSystemTrayIcon is not supported on this platform"); + + QLabel *label = new QLabel(text); + label->setWordWrap(true); + + label->show(); + qDebug() << text; + + app.exec(); +} + +#endif diff --git a/myudp.cpp b/myudp.cpp new file mode 100644 index 0000000..ed5b322 --- /dev/null +++ b/myudp.cpp @@ -0,0 +1,104 @@ +// myudp.cpp + +#include "myudp.h" +#include +#include + +MyUDP::MyUDP(QObject *parent) : + QObject(parent) +{ + // create a QUDP socket + socket = new QUdpSocket(this); + + // The most common way to use QUdpSocket class is + // to bind to an address and port using bind() + // bool QAbstractSocket::bind(const QHostAddress & address, + // quint16 port = 0, BindMode mode = DefaultForPlatform) + socket->bind(QHostAddress::AnyIPv4, 1234,QUdpSocket::ShareAddress); + + connect(socket,SIGNAL(readyRead()),this,SLOT(readyRead())); + + QTimer::singleShot(200, this, &MyUDP::join); + +} + +void MyUDP::join() +{ + setMulticast(QHostAddress("224.1.2.3")); +} + +void MyUDP::setMulticast(QHostAddress address) +{ + if (listen_address != address) { + + QList mListIfaces = QNetworkInterface::allInterfaces(); + + for (int i = 0; i < mListIfaces.length(); ++i) { + if (socket && socket->state() == QAbstractSocket::BoundState) + socket->leaveMulticastGroup(listen_address, mListIfaces.at(i)); + } + + listen_address = address; + + for (int i = 0; i < mListIfaces.length(); ++i) { + qDebug() << socket->joinMulticastGroup(address,mListIfaces.at(i)); + } + + + qDebug() << "EMIT MULTICAST CHANGED"; + emit multicastChanged(address); + } +} + +void MyUDP::HelloUDP() +{ + QByteArray Data; + Data.append("Hello from UDP"); + qDebug() << "Sending message"; + + // Sends the datagram datagram + // to the host address and at port. + // qint64 QUdpSocket::writeDatagram(const QByteArray & datagram, + // const QHostAddress & host, quint16 port) + socket->writeDatagram(Data, QHostAddress::LocalHost, 1234); +} + +void MyUDP::readyRead() +{ + // when data comes in + QByteArray buffer; + buffer.resize(socket->pendingDatagramSize()); + + QHostAddress sender; + quint16 senderPort; + int bellNumber; + QString header; + QString msg; + + // qint64 QUdpSocket::readDatagram(char * data, qint64 maxSize, + // QHostAddress * address = 0, quint16 * port = 0) + // Receives a datagram no larger than maxSize bytes and stores it in data. + // The sender's host address and port is stored in *address and *port + // (unless the pointers are 0). + + socket->readDatagram(buffer.data(), buffer.size(), + &sender, &senderPort); + + + msg = QString::fromLatin1(buffer); + QStringList list1 = msg.split(QLatin1Char(':')); + qDebug() << msg; + qDebug() << "List Size: " << list1.size(); + if (list1.size() >= 2) { + header = list1.at(0); + qDebug() << "H: " << header; + if (header == "BELL") { + bellNumber = list1.at(1).toInt(); + emit packetArrived(bellNumber); + } + } + + qDebug() << "Message from: " << sender.toString(); + qDebug() << "Message port: " << senderPort; + qDebug() << "Message: " << buffer; +} diff --git a/myudp.h b/myudp.h new file mode 100644 index 0000000..dbd5c8b --- /dev/null +++ b/myudp.h @@ -0,0 +1,30 @@ +#ifndef MYUDP_H +#define MYUDP_H + +#include +#include + + +class MyUDP : public QObject +{ + Q_OBJECT +public: + explicit MyUDP(QObject *parent = 0); + void HelloUDP(); + void join(); +signals: + void multicastChanged(QHostAddress address); + void packetArrived(int bellNumber); + +public slots: + void readyRead(); + void setMulticast(QHostAddress address); + +public: + QUdpSocket *socket; +private: + QHostAddress listen_address; + +}; + +#endif // MYUDP_H diff --git a/publisher.cpp b/publisher.cpp new file mode 100644 index 0000000..cff6a3b --- /dev/null +++ b/publisher.cpp @@ -0,0 +1,165 @@ +Skip to content +Why GitHub? +Team +Enterprise +Explore +Marketplace +Pricing +Search + +Sign in +Sign up +emqx +/ +qmqtt +60388208 +Code +Issues +4 +Pull requests +Actions +Projects +Security +Insights +Join GitHub today +GitHub is home to over 50 million developers working together to host and review code, manage projects, and build software together. + +qmqtt/examples/qmqtt/client/example.cpp +@KonstantinRitt +KonstantinRitt Rename module to qmqtt +… +Latest commit ada0692 on Aug 21, 2018 + History + 1 contributor +132 lines (119 sloc) 4.14 KB + +/* + * example.cpp - qmqtt example + * + * Copyright (c) 2013 Ery Lee + * All rights reserved. + * + * 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 mqttc 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. + * + */ +#include +#include +#include + +const QHostAddress EXAMPLE_HOST = QHostAddress("172.16.1.254"); +const quint16 EXAMPLE_PORT = 1883; +const QString EXAMPLE_TOPIC = "home/bell/ring"; + +class Publisher : public QMQTT::Client +{ + Q_OBJECT +public: + explicit Publisher(const QHostAddress& host = EXAMPLE_HOST, + const quint16 port = EXAMPLE_PORT, + QObject* parent = NULL) + : QMQTT::Client(host, port, parent) + , _number(0) + { + connect(this, &Publisher::connected, this, &Publisher::onConnected); + connect(&_timer, &QTimer::timeout, this, &Publisher::onTimeout); + connect(this, &Publisher::disconnected, this, &Publisher::onDisconnected); + } + virtual ~Publisher() {} + + QTimer _timer; + quint16 _number; + +public slots: + void onConnected() + { + subscribe(EXAMPLE_TOPIC, 0); + _timer.start(1000); + } + + void onTimeout() + { + QMQTT::Message message(_number, EXAMPLE_TOPIC, + QString("Number is %1").arg(_number).toUtf8()); + publish(message); + _number++; + if(_number >= 10) + { + _timer.stop(); + disconnectFromHost(); + } + } + + void onDisconnected() + { + QTimer::singleShot(0, qApp, &QCoreApplication::quit); + } +}; + +class Subscriber : public QMQTT::Client +{ + Q_OBJECT +public: + explicit Subscriber(const QHostAddress& host = EXAMPLE_HOST, + const quint16 port = EXAMPLE_PORT, + QObject* parent = NULL) + : QMQTT::Client(host, port, parent) + , _qout(stdout) + { + connect(this, &Subscriber::connected, this, &Subscriber::onConnected); + connect(this, &Subscriber::subscribed, this, &Subscriber::onSubscribed); + connect(this, &Subscriber::received, this, &Subscriber::onReceived); + } + virtual ~Subscriber() {} + + QTextStream _qout; + +public slots: + void onConnected() + { + _qout << "connected" << endl; + subscribe(EXAMPLE_TOPIC, 0); + } + + void onSubscribed(const QString& topic) + { + _qout << "subscribed " << topic << endl; + } + + void onReceived(const QMQTT::Message& message) + { + _qout << "publish received: \"" << QString::fromUtf8(message.payload()) + << "\"" << endl; + } +}; + +int main(int argc, char** argv) +{ + QCoreApplication app(argc, argv); + Subscriber subscriber; + subscriber.connectToHost(); + Publisher publisher; + publisher.connectToHost(); + return app.exec(); +} diff --git a/publisher.h b/publisher.h new file mode 100644 index 0000000..280c63f --- /dev/null +++ b/publisher.h @@ -0,0 +1,12 @@ +#ifndef PUBLISHER_H +#define PUBLISHER_H + +#include + +class Publisher +{ +public: + Publisher(); +}; + +#endif // PUBLISHER_H diff --git a/sounds/bell_large_gong_like_single.wav b/sounds/bell_large_gong_like_single.wav new file mode 100644 index 0000000..d0bc91f Binary files /dev/null and b/sounds/bell_large_gong_like_single.wav differ diff --git a/sounds/bells_buddhist_chime.mp3 b/sounds/bells_buddhist_chime.mp3 new file mode 100644 index 0000000..c07fa50 Binary files /dev/null and b/sounds/bells_buddhist_chime.mp3 differ diff --git a/sounds/bells_buddhist_chime.wav b/sounds/bells_buddhist_chime.wav new file mode 100644 index 0000000..b3a91a0 Binary files /dev/null and b/sounds/bells_buddhist_chime.wav differ diff --git a/sounds/default_bell.wav b/sounds/default_bell.wav new file mode 100644 index 0000000..4e9c4b0 Binary files /dev/null and b/sounds/default_bell.wav differ diff --git a/sounds/zapsplat_bell_medium_strike_mallet_hand_49165.mp3 b/sounds/zapsplat_bell_medium_strike_mallet_hand_49165.mp3 new file mode 100644 index 0000000..3d8a6cb Binary files /dev/null and b/sounds/zapsplat_bell_medium_strike_mallet_hand_49165.mp3 differ diff --git a/sounds/zapsplat_bell_small_hand_ring_short_weak_002_49173.mp3 b/sounds/zapsplat_bell_small_hand_ring_short_weak_002_49173.mp3 new file mode 100644 index 0000000..3569437 Binary files /dev/null and b/sounds/zapsplat_bell_small_hand_ring_short_weak_002_49173.mp3 differ diff --git a/sounds/zapsplat_bell_small_ring_close_clean_shop_door_bell_010_50046.mp3 b/sounds/zapsplat_bell_small_ring_close_clean_shop_door_bell_010_50046.mp3 new file mode 100644 index 0000000..782c594 Binary files /dev/null and b/sounds/zapsplat_bell_small_ring_close_clean_shop_door_bell_010_50046.mp3 differ diff --git a/sounds/zapsplat_bell_very_large_strike_mallet_gong_like_49177.mp3 b/sounds/zapsplat_bell_very_large_strike_mallet_gong_like_49177.mp3 new file mode 100644 index 0000000..46f1479 Binary files /dev/null and b/sounds/zapsplat_bell_very_large_strike_mallet_gong_like_49177.mp3 differ diff --git a/subscriber.cpp b/subscriber.cpp new file mode 100644 index 0000000..a646b5c --- /dev/null +++ b/subscriber.cpp @@ -0,0 +1,50 @@ +#include "subscriber.h" + + +void Subscriber::onSettingsChanged(QHostAddress _host) +{ + qDebug() << "Setting host:" << _host; + if (_host != host()) { + disconnect(); + setHost(_host); + } +} + +void Subscriber::onConnected() +{ + QSettings settings(QSettings::IniFormat, QSettings::UserScope,"BAD Soft", "Bell"); + + settings.beginGroup("Subscriber"); + + qDebug() << "connected"; + subscribe(settings.value("topic",EXAMPLE_TOPIC).toString(), 0); + + settings.endGroup(); +} + +void Subscriber::onSubscribed(const QString& topic) +{ + qDebug() << "subscribed " << topic; +} + +void Subscriber::onReceived(const QMQTT::Message& message) +{ + int bellNumber; + QString header; + QString msg; + + qDebug() << "publish received: " << QString::fromUtf8(message.payload()); + + msg = QString::fromLatin1(message.payload()); + QStringList list1 = msg.split(QLatin1Char(':')); + qDebug() << msg; + qDebug() << "List Size: " << list1.size(); + if (list1.size() >= 2) { + header = list1.at(0); + qDebug() << "H: " << header; + if (header == "BELL") { + bellNumber = list1.at(1).toInt(); + emit packetArrived(bellNumber); + } + } +} diff --git a/subscriber.h b/subscriber.h new file mode 100644 index 0000000..9aa7f8c --- /dev/null +++ b/subscriber.h @@ -0,0 +1,47 @@ +#ifndef SUBSCRIBER_H +#define SUBSCRIBER_H + + +#include +#include +#include + +const QHostAddress EXAMPLE_HOST = QHostAddress("172.16.1.254"); +const quint16 EXAMPLE_PORT = 1883; +const QString EXAMPLE_TOPIC = "home/bell/ring"; + +class Subscriber : public QMQTT::Client +{ + Q_OBJECT +public: + explicit Subscriber(const QHostAddress& host = EXAMPLE_HOST, + const quint16 port = EXAMPLE_PORT, + QObject* parent = NULL) + : QMQTT::Client(host, port, parent) + { + QSettings settings(QSettings::IniFormat, QSettings::UserScope,"BAD Soft", "Bell"); + + settings.beginGroup("Subscriber"); + setHost(QHostAddress(settings.value("address", EXAMPLE_HOST.toString()).toString())); + setPort(settings.value("port", EXAMPLE_PORT).toString().toInt()); + settings.endGroup(); + + connect(this, &Subscriber::connected, this, &Subscriber::onConnected); + connect(this, &Subscriber::subscribed, this, &Subscriber::onSubscribed); + connect(this, &Subscriber::received, this, &Subscriber::onReceived); + } + virtual ~Subscriber() {} + +public slots: + void onConnected(); + void onSubscribed(const QString& topic); + void onReceived(const QMQTT::Message& message); + void onSettingsChanged(QHostAddress address); + +signals: + void addressChanged(QHostAddress address); + void packetArrived(int bellNumber); + +}; + +#endif diff --git a/systray.pro b/systray.pro new file mode 100644 index 0000000..8906823 --- /dev/null +++ b/systray.pro @@ -0,0 +1,20 @@ +HEADERS = window.h \ + subscriber.h +SOURCES = main.cpp \ + subscriber.cpp \ + window.cpp +RESOURCES = systray.qrc + +QT += widgets core multimedia +requires(qtConfig(combobox)) + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/widgets/desktop/systray +INSTALLS += target + + +win32:CONFIG(release, debug|release): LIBS += -L$$PWD/../../../../../Devel/build-qmqtt-Desktop_Qt_5_15_0_MinGW_32_bit-Debug/lib/ -lQt5Qmqtt +else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/../../../../../Devel/build-qmqtt-Desktop_Qt_5_15_0_MinGW_32_bit-Debug/lib/ -lQt5Qmqttd + +INCLUDEPATH += $$PWD/../../../../../Devel/qmqtt-master/src/mqtt/ +DEPENDPATH += $$PWD/../../../../../Devel/build-qmqtt-Desktop_Qt_5_15_0_MinGW_32_bit-Debug/include diff --git a/systray.pro.user b/systray.pro.user new file mode 100644 index 0000000..49bb4ce --- /dev/null +++ b/systray.pro.user @@ -0,0 +1,616 @@ + + + + + + EnvironmentId + {4c84ef17-ae0f-4036-8820-1a5c5a7da43e} + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + true + false + true + + Cpp + + CppGlobal + + + + QmlJS + + QmlJSGlobal + + + 2 + UTF-8 + false + 4 + false + 80 + true + true + 1 + true + false + 0 + true + true + 0 + 8 + true + 1 + true + true + true + *.md, *.MD, Makefile + false + true + + + + ProjectExplorer.Project.PluginSettings + + + true + true + true + true + true + + + 0 + true + + -fno-delayed-template-parsing + + true + Builtin.Questionable + + true + Builtin.DefaultTidyAndClazy + 2 + + + + true + + + + + ProjectExplorer.Project.Target.0 + + Desktop + Desktop Qt 5.15.0 MinGW 32-bit + Desktop Qt 5.15.0 MinGW 32-bit + qt.qt5.5150.win32_mingw81_kit + 1 + 0 + 0 + + true + 0 + C:\Devel\Qt\Examples\Qt-5.15.0\widgets\desktop\build-systray-Desktop_Qt_5_15_0_MinGW_32_bit-Debug + C:/Devel/Qt/Examples/Qt-5.15.0/widgets/desktop/build-systray-Desktop_Qt_5_15_0_MinGW_32_bit-Debug + + + true + QtProjectManager.QMakeBuildStep + + true + + + + true + Qt4ProjectManager.MakeStep + + false + + + false + + 2 + Build + Build + ProjectExplorer.BuildSteps.Build + + + + true + Qt4ProjectManager.MakeStep + + true + clean + + false + + 1 + Clean + Clean + ProjectExplorer.BuildSteps.Clean + + 2 + false + + + Debug + Qt4ProjectManager.Qt4BuildConfiguration + 2 + 2 + 2 + + + true + 2 + C:\Users\Jaro\Documents\qt-systray\build\release + C:/Users/Jaro/Documents/qt-systray/build/release + + + true + QtProjectManager.QMakeBuildStep + + false + + + + true + Qt4ProjectManager.MakeStep + + false + + + false + + 2 + Build + Build + ProjectExplorer.BuildSteps.Build + + + + true + Qt4ProjectManager.MakeStep + + true + clean + + false + + 1 + Clean + Clean + ProjectExplorer.BuildSteps.Clean + + 2 + false + + + Release + Qt4ProjectManager.Qt4BuildConfiguration + 0 + 0 + 2 + + + true + 0 + C:\Devel\Qt\Examples\Qt-5.15.0\widgets\desktop\build-systray-Desktop_Qt_5_15_0_MinGW_32_bit-Profile + C:/Devel/Qt/Examples/Qt-5.15.0/widgets/desktop/build-systray-Desktop_Qt_5_15_0_MinGW_32_bit-Profile + + + true + QtProjectManager.QMakeBuildStep + + true + + + + true + Qt4ProjectManager.MakeStep + + false + + + false + + 2 + Build + Build + ProjectExplorer.BuildSteps.Build + + + + true + Qt4ProjectManager.MakeStep + + true + clean + + false + + 1 + Clean + Clean + ProjectExplorer.BuildSteps.Clean + + 2 + false + + + Profile + Qt4ProjectManager.Qt4BuildConfiguration + 0 + 0 + 0 + + 3 + + + 0 + Deploy + Deploy + ProjectExplorer.BuildSteps.Deploy + + 1 + + false + ProjectExplorer.DefaultDeployConfiguration + + 1 + + + dwarf + + cpu-cycles + + + 250 + + -e + cpu-cycles + --call-graph + dwarf,4096 + -F + 250 + + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + + 2 + + Qt4ProjectManager.Qt4RunConfiguration:C:/Users/Jaro/Documents/qt-systray/bell-mqtt/systray.pro + C:/Users/Jaro/Documents/qt-systray/bell-mqtt/systray.pro + + false + + false + true + true + false + false + true + + C:/Users/Jaro/Documents/qt-systray/build/release + + 1 + + + + ProjectExplorer.Project.Target.1 + + Desktop + Desktop Qt 5.15.0 MinGW 64-bit + Desktop Qt 5.15.0 MinGW 64-bit + qt.qt5.5150.win64_mingw81_kit + 0 + 0 + 0 + + true + 0 + C:\Devel\Qt\Examples\Qt-5.15.0\widgets\desktop\build-systray-Desktop_Qt_5_15_0_MinGW_64_bit-Debug + C:/Devel/Qt/Examples/Qt-5.15.0/widgets/desktop/build-systray-Desktop_Qt_5_15_0_MinGW_64_bit-Debug + + + true + QtProjectManager.QMakeBuildStep + + true + + + + true + Qt4ProjectManager.MakeStep + + false + + + false + + 2 + Build + Build + ProjectExplorer.BuildSteps.Build + + + + true + Qt4ProjectManager.MakeStep + + true + clean + + false + + 1 + Clean + Clean + ProjectExplorer.BuildSteps.Clean + + 2 + false + + + Debug + Qt4ProjectManager.Qt4BuildConfiguration + 2 + 2 + 2 + + + true + 2 + C:\Devel\Qt\Examples\Qt-5.15.0\widgets\desktop\build-systray-Desktop_Qt_5_15_0_MinGW_64_bit-Release + C:/Devel/Qt/Examples/Qt-5.15.0/widgets/desktop/build-systray-Desktop_Qt_5_15_0_MinGW_64_bit-Release + + + true + QtProjectManager.QMakeBuildStep + + true + + + + true + Qt4ProjectManager.MakeStep + + false + + + false + + 2 + Build + Build + ProjectExplorer.BuildSteps.Build + + + + true + Qt4ProjectManager.MakeStep + + true + clean + + false + + 1 + Clean + Clean + ProjectExplorer.BuildSteps.Clean + + 2 + false + + + Release + Qt4ProjectManager.Qt4BuildConfiguration + 0 + 0 + 2 + + + true + 0 + C:\Devel\Qt\Examples\Qt-5.15.0\widgets\desktop\build-systray-Desktop_Qt_5_15_0_MinGW_64_bit-Profile + C:/Devel/Qt/Examples/Qt-5.15.0/widgets/desktop/build-systray-Desktop_Qt_5_15_0_MinGW_64_bit-Profile + + + true + QtProjectManager.QMakeBuildStep + + true + + + + true + Qt4ProjectManager.MakeStep + + false + + + false + + 2 + Build + Build + ProjectExplorer.BuildSteps.Build + + + + true + Qt4ProjectManager.MakeStep + + true + clean + + false + + 1 + Clean + Clean + ProjectExplorer.BuildSteps.Clean + + 2 + false + + + Profile + Qt4ProjectManager.Qt4BuildConfiguration + 0 + 0 + 0 + + 3 + + + 0 + Deploy + Deploy + ProjectExplorer.BuildSteps.Deploy + + 1 + + false + ProjectExplorer.DefaultDeployConfiguration + + 1 + + + dwarf + + cpu-cycles + + + 250 + + -e + cpu-cycles + --call-graph + dwarf,4096 + -F + 250 + + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + + 2 + + Qt4ProjectManager.Qt4RunConfiguration:C:/Users/Jaro/Documents/qt-systray/systray/systray.pro + C:/Users/Jaro/Documents/qt-systray/systray/systray.pro + + false + + false + true + true + false + false + true + + + + 1 + + + + ProjectExplorer.Project.TargetCount + 2 + + + ProjectExplorer.Project.Updater.FileVersion + 22 + + + Version + 22 + + diff --git a/systray.qrc b/systray.qrc new file mode 100644 index 0000000..c4036eb --- /dev/null +++ b/systray.qrc @@ -0,0 +1,11 @@ + + + images/bad.png + images/heart.png + images/trash.png + sounds/default_bell.wav + sounds/bell_large_gong_like_single.wav + sounds/bells_buddhist_chime.wav + images/bell-icon.png + + diff --git a/window.cpp b/window.cpp new file mode 100644 index 0000000..97bb83f --- /dev/null +++ b/window.cpp @@ -0,0 +1,422 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "window.h" + +#ifndef QT_NO_SYSTEMTRAYICON + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +//! [0] +Window::Window() +{ + createIconGroupBox(); + createSoundGroupBox(); + createIpGroupBox(); + createIconGroupBox(); + createMessageGroupBox(); + + iconLabel->setMinimumWidth(durationLabel->sizeHint().width()); + + createActions(); + createTrayIcon(); + + connect(showMessageButton, &QAbstractButton::clicked, this, &Window::showMessage); + connect(saveSettingsButton, &QAbstractButton::clicked, this, &Window::writeSettings); + connect(showIconCheckBox, &QAbstractButton::toggled, trayIcon, &QSystemTrayIcon::setVisible); + connect(iconComboBox, QOverload::of(&QComboBox::currentIndexChanged), + this, &Window::setIcon); + connect(soundComboBox, QOverload::of(&QComboBox::currentIndexChanged), + this, &Window::playSound); + + connect(trayIcon, &QSystemTrayIcon::messageClicked, this, &Window::messageClicked); + connect(trayIcon, &QSystemTrayIcon::activated, this, &Window::iconActivated); + + QVBoxLayout *mainLayout = new QVBoxLayout; + mainLayout->addWidget(iconGroupBox); + mainLayout->addWidget(soundGroupBox); + mainLayout->addWidget(ipGroupBox); + mainLayout->addWidget(messageGroupBox); + setLayout(mainLayout); + + iconComboBox->setCurrentIndex(1); + trayIcon->show(); + + setWindowTitle(tr("Systray")); + readSettings(); + + +} +//! [0] + +void Window::writeSettings() +{ + qDebug() << "Write Settings"; + + QSettings settings(QSettings::IniFormat, QSettings::UserScope,"BAD Soft", "Bell"); + + settings.beginGroup("Window"); + settings.setValue("size", size()); + settings.setValue("pos", pos()); + settings.setValue("sound",soundComboBox->currentIndex()); + settings.setValue("icon",iconComboBox->currentIndex()); + settings.setValue("type",typeComboBox->currentIndex()); + settings.setValue("check",showIconCheckBox->checkState()); + settings.setValue("title",titleEdit->text()); + settings.setValue("body",bodyEdit->toPlainText()); + settings.setValue("duration",durationSpinBox->value()); + settings.endGroup(); + + settings.beginGroup("Subscriber"); + settings.setValue("address", ipEdit->text()); + settings.endGroup(); +} + +void Window::readSettings() +{ + QSettings settings(QSettings::IniFormat, QSettings::UserScope,"BAD Soft", "Bell"); + + settings.beginGroup("Window"); + resize(settings.value("size", QSize(400, 300)).toSize()); + move(settings.value("pos", QPoint(200, 200)).toPoint()); + soundComboBox->setCurrentIndex(settings.value("sound",0).toUInt()); + iconComboBox->setCurrentIndex(settings.value("icon",1).toUInt()); + typeComboBox->setCurrentIndex(settings.value("type",0).toUInt()); + if (settings.value("check",1).toUInt()) + showIconCheckBox->setCheckState(Qt::Checked); + else + showIconCheckBox->setCheckState(Qt::Unchecked); + + titleEdit->setText(settings.value("title",tr("Bell ringing")).toString()); + bodyEdit->setPlainText(settings.value("body",tr("Detected Bell ringing.\nClick this balloon for details.")).toString()); + durationSpinBox->setValue(settings.value("duration",15).toUInt()); + settings.endGroup(); +} + +void Window::playSound(int index) +{ + QSound::play(bellResourceNames.at(index)); +} + +void Window::setMulticast(QHostAddress address) +{ + + qDebug() << "Signal Mulitcast = " << address.toString(); + ipEdit->setText(address.toString()); +} + +void Window::packetArrived(int bellNumber) +{ + showMessage(); +} + +//! [1] +void Window::setVisible(bool visible) +{ + minimizeAction->setEnabled(visible); + maximizeAction->setEnabled(!isMaximized()); + restoreAction->setEnabled(isMaximized() || !visible); + QDialog::setVisible(visible); +} +//! [1] + +//! [2] +void Window::closeEvent(QCloseEvent *event) +{ +#ifdef Q_OS_MACOS + if (!event->spontaneous() || !isVisible()) { + return; + } +#endif + if (trayIcon->isVisible()) { + QMessageBox::information(this, tr("Systray"), + tr("The program will keep running in the " + "system tray. To terminate the program, " + "choose Quit in the context menu " + "of the system tray entry.")); + hide(); + event->ignore(); + } +} +//! [2] + +//! [3] +void Window::setIcon(int index) +{ + QIcon icon = iconComboBox->itemIcon(index); + trayIcon->setIcon(icon); + setWindowIcon(icon); + + trayIcon->setToolTip(iconComboBox->itemText(index)); +} +//! [3] + + +//! [4] +void Window::iconActivated(QSystemTrayIcon::ActivationReason reason) +{ + switch (reason) { + case QSystemTrayIcon::Trigger: + case QSystemTrayIcon::DoubleClick: + iconComboBox->setCurrentIndex((iconComboBox->currentIndex() + 1) % iconComboBox->count()); + break; + case QSystemTrayIcon::MiddleClick: + showMessage(); + break; + default: + ; + } +} +//! [4] + +//! [5] +void Window::showMessage() +{ + qDebug() << "SHOW MESSAGE"; + showIconCheckBox->setChecked(true); + int selectedIcon = typeComboBox->itemData(typeComboBox->currentIndex()).toInt(); + QSystemTrayIcon::MessageIcon msgIcon = QSystemTrayIcon::MessageIcon(selectedIcon); + + QSound::play(bellResourceNames.at(soundComboBox->currentIndex())); + + if (selectedIcon == -1) { // custom icon + QIcon icon(iconComboBox->itemIcon(iconComboBox->currentIndex())); + trayIcon->showMessage(titleEdit->text(), bodyEdit->toPlainText(), icon, + durationSpinBox->value() * 1000); + } else { + trayIcon->showMessage(titleEdit->text(), bodyEdit->toPlainText(), msgIcon, + durationSpinBox->value() * 1000); + } + + emit settingsChanged(QHostAddress(ipEdit->text())); +} +//! [5] + +//! [6] +void Window::messageClicked() +{ + QMessageBox::information(nullptr, tr("Systray"), + tr("Sorry, I already gave what help I could.\n" + "Maybe you should try asking a human?")); +} +//! [6] + +void Window::createIconGroupBox() +{ + iconGroupBox = new QGroupBox(tr("Tray Icon")); + + iconLabel = new QLabel("Icon:"); + + iconComboBox = new QComboBox; + iconComboBox->addItem(QIcon(":/images/bad.png"), tr("Bad")); + iconComboBox->addItem(QIcon(":/images/bell-icon.png"), tr("Bell")); + iconComboBox->addItem(QIcon(":/images/heart.png"), tr("Heart")); + iconComboBox->addItem(QIcon(":/images/trash.png"), tr("Trash")); + + showIconCheckBox = new QCheckBox(tr("Show icon")); + showIconCheckBox->setChecked(true); + + QHBoxLayout *iconLayout = new QHBoxLayout; + iconLayout->addWidget(iconLabel); + iconLayout->addWidget(iconComboBox); + iconLayout->addStretch(); + iconLayout->addWidget(showIconCheckBox); + iconGroupBox->setLayout(iconLayout); +} + +void Window::createSoundGroupBox() +{ + soundGroupBox = new QGroupBox(tr("Playing sound")); + + soundLabel = new QLabel("Sound:"); + + soundComboBox = new QComboBox; + foreach (QString str, bellNames) { + soundComboBox->addItem(str); + } + + QHBoxLayout *soundLayout = new QHBoxLayout; + soundLayout->addWidget(soundLabel); + soundLayout->addWidget(soundComboBox); + soundLayout->addStretch(); + soundGroupBox->setLayout(soundLayout); + +} +void Window::createIpGroupBox() +{ + ipGroupBox = new QGroupBox(tr("Adress of Mqtt server")); + + ipLabel = new QLabel(tr("Address:")); + ipEdit = new QLineEdit("172.16.1.254"); + + QHBoxLayout *ipLayout = new QHBoxLayout; + ipLayout->addWidget(ipLabel); + ipLayout->addWidget(ipEdit); + ipLayout->addStretch(); + ipGroupBox->setLayout(ipLayout); + +} + +QString Window::getIpAddress() +{ + return ipEdit->text(); +} + +void Window::createMessageGroupBox() +{ + messageGroupBox = new QGroupBox(tr("Balloon Message")); + + typeLabel = new QLabel(tr("Type:")); + + typeComboBox = new QComboBox; + typeComboBox->addItem(tr("None"), QSystemTrayIcon::NoIcon); + typeComboBox->addItem(style()->standardIcon( + QStyle::SP_MessageBoxInformation), tr("Information"), + QSystemTrayIcon::Information); + typeComboBox->addItem(style()->standardIcon( + QStyle::SP_MessageBoxWarning), tr("Warning"), + QSystemTrayIcon::Warning); + typeComboBox->addItem(style()->standardIcon( + QStyle::SP_MessageBoxCritical), tr("Critical"), + QSystemTrayIcon::Critical); + typeComboBox->addItem(QIcon(), tr("Custom icon"), + -1); + typeComboBox->setCurrentIndex(1); + + durationLabel = new QLabel(tr("Duration:")); + + durationSpinBox = new QSpinBox; + durationSpinBox->setRange(5, 60); + durationSpinBox->setSuffix(" s"); + durationSpinBox->setValue(15); + + durationWarningLabel = new QLabel(tr("(some systems might ignore this " + "hint)")); + durationWarningLabel->setIndent(10); + + titleLabel = new QLabel(tr("Title:")); + + titleEdit = new QLineEdit(); + + bodyLabel = new QLabel(tr("Body:")); + + bodyEdit = new QTextEdit; + bodyEdit->setPlainText(""); + + saveSettingsButton = new QPushButton(tr("Save Settings")); + + showMessageButton = new QPushButton(tr("Show Message")); + showMessageButton->setDefault(true); + + QGridLayout *messageLayout = new QGridLayout; + messageLayout->addWidget(typeLabel, 0, 0); + messageLayout->addWidget(typeComboBox, 0, 1, 1, 2); + messageLayout->addWidget(durationLabel, 1, 0); + messageLayout->addWidget(durationSpinBox, 1, 1); + messageLayout->addWidget(durationWarningLabel, 1, 2, 1, 3); + messageLayout->addWidget(titleLabel, 2, 0); + messageLayout->addWidget(titleEdit, 2, 1, 1, 4); + messageLayout->addWidget(bodyLabel, 3, 0); + messageLayout->addWidget(bodyEdit, 3, 1, 2, 4); + messageLayout->addWidget(saveSettingsButton, 5, 3, Qt::AlignRight); + messageLayout->addWidget(showMessageButton, 5, 4); + messageLayout->setColumnStretch(3, 1); + messageLayout->setRowStretch(4, 1); + messageGroupBox->setLayout(messageLayout); +} + +void Window::createActions() +{ + minimizeAction = new QAction(tr("Mi&nimize"), this); + connect(minimizeAction, &QAction::triggered, this, &QWidget::hide); + + maximizeAction = new QAction(tr("Ma&ximize"), this); + connect(maximizeAction, &QAction::triggered, this, &QWidget::showMaximized); + + restoreAction = new QAction(tr("&Restore"), this); + connect(restoreAction, &QAction::triggered, this, &QWidget::showNormal); + + quitAction = new QAction(tr("&Quit"), this); + connect(quitAction, &QAction::triggered, qApp, &QCoreApplication::quit); +} + +void Window::createTrayIcon() +{ + trayIconMenu = new QMenu(this); + trayIconMenu->addAction(minimizeAction); + trayIconMenu->addAction(maximizeAction); + trayIconMenu->addAction(restoreAction); + trayIconMenu->addSeparator(); + trayIconMenu->addAction(quitAction); + + trayIcon = new QSystemTrayIcon(this); + trayIcon->setContextMenu(trayIconMenu); +} + +#endif diff --git a/window.h b/window.h new file mode 100644 index 0000000..da56484 --- /dev/null +++ b/window.h @@ -0,0 +1,153 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef WINDOW_H +#define WINDOW_H + +#include + +#ifndef QT_NO_SYSTEMTRAYICON + +#include +#include +#include + +QT_BEGIN_NAMESPACE +class QAction; +class QCheckBox; +class QComboBox; +class QGroupBox; +class QLabel; +class QLineEdit; +class QMenu; +class QPushButton; +class QSpinBox; +class QTextEdit; +QT_END_NAMESPACE + +//! [0] +class Window : public QDialog +{ + Q_OBJECT + +public: + Window(); + + void setVisible(bool visible) override; + QString getIpAddress(); +signals: + void settingsChanged(QHostAddress address); + +protected: + void closeEvent(QCloseEvent *event) override; + +private slots: + void setIcon(int index); + void iconActivated(QSystemTrayIcon::ActivationReason reason); + void showMessage(); + void messageClicked(); + void playSound(int index); + +public slots: + void setMulticast(QHostAddress address); + void packetArrived(int bellNumber); + +private: + void createIconGroupBox(); + void createSoundGroupBox(); + void createIpGroupBox(); + void createMessageGroupBox(); + void createActions(); + void createTrayIcon(); + void readSettings(); + void writeSettings(); + + QGroupBox *iconGroupBox; + QLabel *iconLabel; + QComboBox *iconComboBox; + QCheckBox *showIconCheckBox; + + QGroupBox *soundGroupBox; + QLabel *soundLabel; + QComboBox *soundComboBox; + + QGroupBox *ipGroupBox; + QLabel *ipLabel; + QLineEdit *ipEdit; + + QGroupBox *messageGroupBox; + QLabel *typeLabel; + QLabel *durationLabel; + QLabel *durationWarningLabel; + QLabel *titleLabel; + QLabel *bodyLabel; + QComboBox *typeComboBox; + QSpinBox *durationSpinBox; + QLineEdit *titleEdit; + QTextEdit *bodyEdit; + QPushButton *saveSettingsButton; + QPushButton *showMessageButton; + + QAction *minimizeAction; + QAction *maximizeAction; + QAction *restoreAction; + QAction *quitAction; + + QSystemTrayIcon *trayIcon; + QMenu *trayIconMenu; + + QList bellNames{ tr("Default Bell"), tr("Buddhist Bell"), tr("Large Gong")}; + QList bellResourceNames{":/sounds/default_bell.wav",":/sounds/bells_buddhist_chime.wav",":/sounds/bell_large_gong_like_single.wav"}; +}; +//! [0] + +#endif // QT_NO_SYSTEMTRAYICON + +#endif