Added the ability to correspond, performed a small optimization (fixed the memory leak), changed the structure of all the code (in particular, changed the names of many variables, etc.)

Also translated all into English.
This commit is contained in:
Denis Davydov 2018-07-26 11:33:47 +03:00
parent 9475414ecd
commit 630f739538
10 changed files with 350 additions and 53 deletions

View File

@ -1,14 +1,67 @@
#include "chatwindow.hpp" #include "chatwindow.hpp"
#include "ui_chatwindow.h" #include "ui_chatwindow.h"
ChatWindow::ChatWindow(QWidget *parent) : ChatWindow::ChatWindow(QString pID, QString cUUID, Handler *h, Network *n, QWidget *parent) :
QWidget(parent), QWidget(parent),
ui(new Ui::Form) ui(new Ui::ChatWindow)
{ {
ui->setupUi(this); ui->setupUi(this);
this->setAttribute(Qt::WA_DeleteOnClose);
chatID = cUUID;
peerID = pID;
handler = h;
network = n;
ui->peerIDLabel->setText(ui->peerIDLabel->text() + pID);
connect(ui->sendMsgButton, &QAbstractButton::clicked, this, &ChatWindow::sendMsgButtonClicked);
} }
ChatWindow::~ChatWindow() ChatWindow::~ChatWindow()
{ {
leftFromChat();
emit deleteChat(chatID);
delete ui; delete ui;
this->deleteLater();
}
void ChatWindow::sendMessage(QString msgText)
{
QJsonObject jSend;
jSend["action"] = "msgSend";
jSend["peerID"] = *network->myIPv6;
jSend["chatID"] = chatID;
jSend["msgText"] = msgText;
network->sendDatagram(jSend, peerID);
ui->chatEdit->append(tr("You: ") + msgText);
}
void ChatWindow::sendMsgButtonClicked()
{
QString msg = ui->msgEdit->text();
sendMessage(msg);
ui->msgEdit->setText("");
}
void ChatWindow::displayMsg(QString msgText)
{
ui->chatEdit->append(peerID + ": " + msgText);
}
void ChatWindow::leftFromChat()
{
QJsonObject json;
json["action"] = "leftChat";
json["peerID"] = *network->myIPv6;
json["chatID"] = chatID;
network->sendDatagram(json, peerID);
}
void ChatWindow::peerReceiverLeftFromChat()
{
QString msg;
msg += tr("Peer ");
msg += peerID;
msg += tr(" left from this chat.");
QMessageBox::warning(this, tr("Peer receiver left from chat!"), msg, QMessageBox::Ok);
ui->chatEdit->append(peerID + tr("left from this chat."));
ui->msgEdit->setEnabled(false);
ui->sendMsgButton->setEnabled(false);
} }

View File

@ -1,9 +1,12 @@
#pragma once #pragma once
#include <QWidget> #include <QWidget>
#include <QJsonObject>
#include "kernel/handler.hpp"
#include "kernel/network.hpp"
namespace Ui { namespace Ui {
class Form; class ChatWindow;
} }
class ChatWindow : public QWidget class ChatWindow : public QWidget
@ -11,9 +14,20 @@ class ChatWindow : public QWidget
Q_OBJECT Q_OBJECT
public: public:
explicit ChatWindow(QWidget *parent = 0); explicit ChatWindow(QString pID, QString cUUID, Handler *h, Network *n, QWidget *parent = 0);
~ChatWindow(); ~ChatWindow();
QString chatID;
QString peerID;
Handler *handler;
Network *network;
void displayMsg(QString msgText);
void peerReceiverLeftFromChat();
private: private:
Ui::ChatWindow *ui; Ui::ChatWindow *ui;
void sendMessage(QString msgText);
void leftFromChat();
signals:
void deleteChat(QString cID);
private slots:
void sendMsgButtonClicked();
}; };

View File

@ -1,21 +1,71 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0"> <ui version="4.0">
<author/> <class>ChatWindow</class>
<comment/> <widget class="QWidget" name="ChatWindow">
<exportmacro/>
<class>Form</class>
<widget class="QWidget" name="Form">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>400</width> <width>807</width>
<height>300</height> <height>519</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>Form</string> <string/>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="2" column="0" colspan="2">
<widget class="QLineEdit" name="msgEdit"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="peerIDLabel">
<property name="minimumSize">
<size>
<width>697</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Contact PeerID: </string>
</property> </property>
</widget> </widget>
<pixmapfunction/> </item>
<connections/> <item row="2" column="2">
<widget class="QPushButton" name="sendMsgButton">
<property name="locale">
<locale language="English" country="UnitedStates"/>
</property>
<property name="text">
<string>Send</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="3">
<widget class="QTextEdit" name="chatEdit">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>msgEdit</sender>
<signal>returnPressed()</signal>
<receiver>sendMsgButton</receiver>
<slot>click()</slot>
<hints>
<hint type="sourcelabel">
<x>360</x>
<y>497</y>
</hint>
<hint type="destinationlabel">
<x>757</x>
<y>497</y>
</hint>
</hints>
</connection>
</connections>
</ui> </ui>

View File

@ -5,30 +5,97 @@ Handler::Handler()
using namespace std::placeholders; using namespace std::placeholders;
handlers = { handlers = {
{"checkPeer", std::bind(&Handler::createSession, this, _1)}, {"checkPeer", std::bind(&Handler::checkPeer, this, _1)},
{"checkPeerSuccess", std::bind(&Handler::checkPeerSuccessMethod, this, _1)} {"checkPeerSuccess", std::bind(&Handler::checkPeerSuccessMethod, this, _1)},
{"createChat", std::bind(&Handler::createChatMethod, this, _1)},
{"createChatSuccess", std::bind(&Handler::createChatSuccessMethod, this, _1)},
{"createChatFailed", std::bind(&Handler::createChatFailedMethod, this, _1)},
{"msgSend", std::bind(&Handler::msgReceiveMethod, this, _1)},
{"leftChat", std::bind(&Handler::peerReceiverLeftFromChatMethod, this, _1)}
}; };
peerReceiver = new QString();
network = new Network(); network = new Network();
connect(network, &Network::json_received, this, &Handler::handle); connect(network, &Network::jsonReceived, this, &Handler::handle);
} }
void Handler::handle(QJsonObject jsonReceived) void Handler::handle(QJsonObject jsonReceived)
{ {
QString action = jsonReceived["action"].toString(); QString action = jsonReceived["action"].toString();
*peerReceiver = jsonReceived["peerID"].toString();
handlers[action](jsonReceived); handlers[action](jsonReceived);
} }
void Handler::createSession(QJsonObject jsonReceived) void Handler::checkPeer(QJsonObject jsonReceived)
{ {
QJsonObject jsonSend; QJsonObject jsonSend;
jsonSend["peerID"] = my_ipv6; jsonSend["peerID"] = *network->myIPv6;
jsonSend["action"] = "checkPeerSuccess"; jsonSend["action"] = "checkPeerSuccess";
QString peerReceiver = jsonReceived["peerID"].toString(); network->sendDatagram(jsonSend, *peerReceiver);
network->sendDatagram(jsonSend, peerReceiver);
} }
void Handler::createSessionSuccessMethod(QJsonObject jsonReceived) void Handler::checkPeerSuccessMethod(QJsonObject jsonReceived)
{ {
emit checkPeerSuccess(); emit checkPeerSuccess();
} }
Handler::~Handler()
{
delete peerReceiver;
delete network;
//delete handlers;
}
void Handler::createChatMethod(QJsonObject jsonReceived)
{
QWidget *parent = 0;
QString msgTitle;
QString msg;
msgTitle += "Create chat";
msg += tr("Peer ");
msg += *peerReceiver;
msg += tr(" want to create chat with you.\n");
msg += tr("Do you want to create chat?");
int ret = QMessageBox::warning(parent, msgTitle, msg, QMessageBox::Yes | QMessageBox::No);
if(ret == QMessageBox::Yes)
{
QJsonObject jsonSend;
jsonSend["peerID"] = *network->myIPv6;
jsonSend["action"] = "createChatSuccess";
jsonSend["chatID"] = jsonReceived["chatUUID"].toString();
network->sendDatagram(jsonSend, *peerReceiver);
}
else
{
QJsonObject jsonSend;
jsonSend["peerID"] = *network->myIPv6;
jsonSend["action"] = "createChatFailed";
network->sendDatagram(jsonSend, *peerReceiver);
}
}
void Handler::createChatFailedMethod(QJsonObject jsonReceived)
{
QString msg;
msg += tr("Peer ");
msg += *peerReceiver;
msg += tr(" refused to create a chat with you");
QWidget *parent = 0;
QMessageBox::critical(parent, tr("Create chat failed!"), msg, QMessageBox::Ok);
emit createChatFailed();
}
void Handler::createChatSuccessMethod(QJsonObject jsonReceived)
{
emit createChatSuccess(jsonReceived["peerID"].toString(), jsonReceived["chatID"].toString());
}
void Handler::msgReceiveMethod(QJsonObject jsonReceived)
{
emit msgReceived(jsonReceived["peerID"].toString(), jsonReceived["chatID"].toString(), jsonReceived["msgText"].toString());
}
void Handler::peerReceiverLeftFromChatMethod(QJsonObject jsonReceived)
{
emit peerReceiverLeftFromChat(jsonReceived["peerID"].toString(), jsonReceived["chatID"].toString());
}

View File

@ -2,22 +2,32 @@
#include "network.hpp" #include "network.hpp"
#include <QJsonObject> #include <QJsonObject>
#include <QMessageBox>
class Handler : public QObject class Handler : public QObject
{ {
Q_OBJECT Q_OBJECT
const QString my_ipv6 = Network::local_ipv6();
public: public:
Handler(); Handler();
signals: ~Handler();
void checkPeerSuccess(); QString *peerReceiver;
private: private:
Network *network; Network *network;
void createSession(QJsonObject jsonReceived); void checkPeer(QJsonObject jsonReceived);
std::map<QString, std::function<void(QJsonObject)>> handlers; std::map<QString, std::function<void(QJsonObject)>> handlers;
void checkPeerSuccessMethod(QJsonObject jsonReceived); void checkPeerSuccessMethod(QJsonObject jsonReceived);
void createChatMethod(QJsonObject jsonReceived);
void createChatSuccessMethod(QJsonObject jsonReceived);
void createChatFailedMethod(QJsonObject jsonReceived);
void msgReceiveMethod(QJsonObject jsonReceived);
void peerReceiverLeftFromChatMethod(QJsonObject jsonReceived);
signals:
void checkPeerSuccess();
void createChatSuccess(QString peerID, QString chatID);
void createChatFailed();
void msgReceived(QString peerID, QString chatID, QString msgText);
void peerReceiverLeftFromChat(QString peerID, QString chatID);
private slots: private slots:
void handle(QJsonObject jsonReceived); void handle(QJsonObject jsonReceived);
}; };

View File

@ -1,4 +1,5 @@
#include "network.hpp" #include "network.hpp"
Network::Network(bool is_server) Network::Network(bool is_server)
{ {
udpSocket = new QUdpSocket(this); udpSocket = new QUdpSocket(this);
@ -7,6 +8,7 @@ Network::Network(bool is_server)
udpSocket->bind(QHostAddress::AnyIPv6, 6552); udpSocket->bind(QHostAddress::AnyIPv6, 6552);
connect(udpSocket, SIGNAL(readyRead()), this, SLOT(processTheDatagram())); connect(udpSocket, SIGNAL(readyRead()), this, SLOT(processTheDatagram()));
} }
myIPv6 = new QString(localIPv6());
} }
void Network::sendDatagram(QJsonObject j, QString s) void Network::sendDatagram(QJsonObject j, QString s)
@ -29,10 +31,10 @@ void Network::processTheDatagram()
QJsonDocument jbuff = QJsonDocument::fromJson(baDatagram); QJsonDocument jbuff = QJsonDocument::fromJson(baDatagram);
QJsonObject j = QJsonObject(jbuff.object()); QJsonObject j = QJsonObject(jbuff.object());
emit json_received(j); emit jsonReceived(j);
} }
QString Network::local_ipv6() QString Network::localIPv6()
{ {
QHostAddress address; QHostAddress address;
foreach (address, QNetworkInterface::allAddresses()) { foreach (address, QNetworkInterface::allAddresses()) {
@ -45,4 +47,5 @@ QString Network::local_ipv6()
Network::~Network() Network::~Network()
{ {
delete udpSocket; delete udpSocket;
delete myIPv6;
} }

View File

@ -9,15 +9,18 @@ class Network : public QObject
{ {
Q_OBJECT Q_OBJECT
private:
QUdpSocket* udpSocket;
public: public:
Network(bool is_server = true); Network(bool is_server = true);
static QString local_ipv6(); ~Network();
static QString localIPv6();
const QString *myIPv6;
private:
QUdpSocket* udpSocket;
public slots: public slots:
void sendDatagram(QJsonObject j, QString s); void sendDatagram(QJsonObject j, QString s);
signals: signals:
void json_received(QJsonObject &jsonReceived); void jsonReceived(QJsonObject &jsonReceived);
private slots: private slots:
void processTheDatagram(); void processTheDatagram();
}; };

View File

@ -10,21 +10,28 @@ MainWindow::MainWindow(QWidget *parent) :
handler = new Handler(); handler = new Handler();
timer = new QTimer(); timer = new QTimer();
connect(timer, SIGNAL(timeout()), this, SLOT(slotTimerAlarm())); connect(timer, SIGNAL(timeout()), this, SLOT(slotTimerAlarm()));
connect(handler, &Handler::checkPeerSuccessSuccess, this, &MainWindow::peerReceiverAvailable); connect(handler, &Handler::checkPeerSuccess, this, &MainWindow::peerReceiverAvailable);
ui->myIP->setText(my_ipv6); connect(handler, &Handler::createChatSuccess, this, &MainWindow::createChat);
connect(handler, &Handler::createChatFailed, this, &MainWindow::createChatFailedMethod);
connect(handler, &Handler::msgReceived, this, &MainWindow::msgReceivedMethod);
connect(handler, &Handler::peerReceiverLeftFromChat, this, &MainWindow::peerReceiverLeftFromChatMethod);
ui->myIP->setText(*network->myIPv6);
} }
MainWindow::~MainWindow() MainWindow::~MainWindow()
{ {
delete ui; delete ui;
delete network;
delete handler;
delete timer;
} }
void MainWindow::on_connectToPeer_clicked() void MainWindow::on_connectToPeer_clicked()
{ {
ui->connectToPeer->setEnabled(false); setButtonToWaiting();
ui->connectToPeer->setText("Ожидание...");
QJsonObject j; QJsonObject j;
j["peerID"] = my_ipv6; j["peerID"] = *network->myIPv6;
j["action"] = "checkPeer"; j["action"] = "checkPeer";
QString s = ui->peerID->text(); QString s = ui->peerID->text();
network->sendDatagram(j, s); network->sendDatagram(j, s);
@ -40,10 +47,9 @@ void MainWindow::slotTimerAlarm()
} }
else else
{ {
int ret = QMessageBox::critical(this,QObject::tr("Error"),tr("Timeout Error")); QMessageBox::critical(this, tr("Error"), tr("Timeout Error"));
timer->stop(); timer->stop();
ui->connectToPeer->setEnabled(true); setButtonToConnect();
ui->connectToPeer->setText("Подключиться");
} }
} }
@ -51,7 +57,83 @@ void MainWindow::slotTimerAlarm()
void MainWindow::peerReceiverAvailable() void MainWindow::peerReceiverAvailable()
{ {
receive = true; receive = true;
int ret = QMessageBox::information(this,QObject::tr("Info"),tr("Peer Available!")); int ret = QMessageBox::information(this, tr("Peer Available!"),
ui->connectToPeer->setEnabled(true); tr("Peer Available!\n Do you want to create chat?"), QMessageBox::Yes | QMessageBox::No);
ui->connectToPeer->setText("Подключиться"); if(ret == QMessageBox::Yes)
{
createChatSendDatagram(*handler->peerReceiver);
}
else
{
setButtonToConnect();
}
}
void MainWindow::setButtonToWaiting() // Function, which sets button "connectToPeer" in status "Waiting..."
{
ui->connectToPeer->setEnabled(false);
ui->connectToPeer->setText(tr("Waiting..."));
}
void MainWindow::setButtonToConnect() // Function, which sets button "connectToPeer" in status "Connect"
{
ui->connectToPeer->setEnabled(true);
ui->connectToPeer->setText(tr("Connect"));
}
void MainWindow::createChatSendDatagram(QString peerReceiver)
{
QUuid chatID = QUuid::createUuid();
QJsonObject jSend;
jSend["action"] = "createChat";
jSend["peerID"] = *network->myIPv6;
jSend["chatUUID"] = chatID.toString();
network->sendDatagram(jSend, peerReceiver);
}
void MainWindow::createChat(QString peerID, QString chatID)
{
pChatWindows.push_back(new ChatWindow(peerID, chatID, handler, network));
connect(pChatWindows.back(), &ChatWindow::deleteChat, this, &MainWindow::deleteChatMethod);
pChatWindows.back()->show();
setButtonToConnect();
}
void MainWindow::createChatFailedMethod()
{
setButtonToConnect();
}
void MainWindow::deleteChatMethod(QString cID)
{
for(int i = 0; i < pChatWindows.size(); i++)
{
if(pChatWindows.at(i)->chatID == cID)
{
pChatWindows.remove(i);
break;
}
}
}
void MainWindow::msgReceivedMethod(QString peerID, QString chatID, QString msgText)
{
for(int i = 0; i < pChatWindows.size(); i++)
{
if(pChatWindows.at(i)->peerID == peerID && pChatWindows.at(i)->chatID == chatID)
{
pChatWindows.at(i)->displayMsg(msgText);
}
}
}
void MainWindow::peerReceiverLeftFromChatMethod(QString peerID, QString chatID)
{
for(int i = 0; i < pChatWindows.size(); i++)
{
if(pChatWindows.at(i)->peerID == peerID && pChatWindows.at(i)->chatID == chatID)
{
pChatWindows.at(i)->peerReceiverLeftFromChat();
}
}
} }

View File

@ -3,9 +3,12 @@
#include <QMainWindow> #include <QMainWindow>
#include "kernel/network.hpp" #include "kernel/network.hpp"
#include "kernel/handler.hpp" #include "kernel/handler.hpp"
#include "chatwindow.hpp"
#include <QUuid>
#include <QMessageBox> #include <QMessageBox>
#include <QJsonObject> #include <QJsonObject>
#include <QJsonDocument> #include <QJsonDocument>
#include <QObject>
namespace Ui { namespace Ui {
@ -19,18 +22,24 @@ class MainWindow : public QMainWindow
public: public:
explicit MainWindow(QWidget *parent = 0); explicit MainWindow(QWidget *parent = 0);
~MainWindow(); ~MainWindow();
QVector<ChatWindow*> pChatWindows;
void setButtonToWaiting();
void setButtonToConnect();
public slots: public slots:
void peerReceiverAvailable(); void peerReceiverAvailable();
private slots: private slots:
void on_connectToPeer_clicked(); void on_connectToPeer_clicked();
void slotTimerAlarm(); void slotTimerAlarm();
void createChatFailedMethod();
void createChat(QString peerID, QString chatID);
void deleteChatMethod(QString cID);
void msgReceivedMethod(QString peerID, QString chatID, QString msgText);
void peerReceiverLeftFromChatMethod(QString peerID, QString chatID);
private: private:
void createChatSendDatagram(QString peerReceiver);
Ui::MainWindow *ui; Ui::MainWindow *ui;
QTimer *timer; QTimer *timer;
Network *network; Network *network;
Handler *handler; Handler *handler;
bool receive = false; bool receive = false;
const QString my_ipv6 = Network::local_ipv6();
}; };

View File

@ -39,15 +39,21 @@
</item> </item>
<item row="0" column="0"> <item row="0" column="0">
<widget class="QLabel" name="label"> <widget class="QLabel" name="label">
<property name="locale">
<locale language="English" country="UnitedStates"/>
</property>
<property name="text"> <property name="text">
<string>Мой IP:</string> <string>My IPv6:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="4"> <item row="1" column="4">
<widget class="QPushButton" name="connectToPeer"> <widget class="QPushButton" name="connectToPeer">
<property name="locale">
<locale language="English" country="UnitedStates"/>
</property>
<property name="text"> <property name="text">
<string>Подключиться</string> <string>Connect</string>
</property> </property>
</widget> </widget>
</item> </item>