|
1
2
3
|
#include "chatroom.h"
#include "ui_chatroom.h"
|
|
4
5
6
|
list<QString> sendQueue;
std::mutex myMutex;
std::mutex msgMutex;
|
|
7
|
std::mutex printMutex;
|
|
8
9
10
11
|
unique_lock<std::mutex>* msgLock;
std::condition_variable msgListNotEmpty;
void sendThread(Socket* s, Chatroom* chat)
|
|
12
13
|
{
string send;
|
|
14
|
while(chat->getConnected())
|
|
15
|
{
|
|
16
|
while(sendQueue.empty())
|
|
17
|
{
|
|
18
19
|
msgLock->lock();
msgListNotEmpty.wait(*msgLock);
|
|
20
|
msgLock->unlock();
|
|
21
22
23
24
|
if(!chat->getConnected())
{
return;
}
|
|
25
|
}
|
|
26
27
28
|
msgLock->lock();
send = sendQueue.front().toStdString();
sendQueue.pop_front();
|
|
29
30
|
try
{
|
|
31
32
|
if(send[0] == '@')
{
|
|
33
|
chat->relayMsg(send);
|
|
34
35
36
37
38
|
send = '1' + send;
}
else
{
send = '0' + send;
|
|
39
40
|
if(send.substr(1) != "/exit" && send.substr(1) != "/disconnect")
{
|
|
41
|
chat->putMsgToPrintQueue(chat->getNickname().toStdString().append(": ").append(send.substr(1)),MSG_USER);
|
|
42
|
}
|
|
43
44
|
}
msgLock->unlock();
|
|
45
|
*s << send;
|
|
46
|
send = send.substr(1);
|
|
47
48
49
50
|
if(send == "/disconnect" || send == "/exit")
{
break;
}
|
|
51
|
|
|
52
53
54
55
56
57
58
59
|
}
catch(SocketException& e)
{
cout << e.description() << endl;
}
}
}
|
|
60
|
void recvThread(Socket* s, Chatroom* chat)
|
|
61
62
63
64
65
66
|
{
string recv;
while(true)
{
try
{
|
|
67
68
69
|
*s >> recv;
if(recv[0] == '1')
{
|
|
70
|
chat->relayMsg(recv.substr(1));
|
|
71
72
73
74
75
76
|
continue;
}
else if(recv[0] == '0')
{
recv = recv.substr(1);
}
|
|
77
78
79
|
}
catch(SocketException &e)
{
|
|
80
|
chat->toggleConnected(false);
|
|
81
|
cout << e.description() << endl;
|
|
82
|
msgListNotEmpty.notify_all();
|
|
83
84
|
string msg = "Connection to server lost";
chat->putMsgToPrintQueue(msg,MSG_STATUS);
|
|
85
86
87
88
89
|
break;
}
if(recv == "DISC_OK")
{
cout << "Disconnecting" << endl;
|
|
90
|
chat->toggleConnected(false);
|
|
91
|
msgListNotEmpty.notify_all();
|
|
92
93
94
95
96
|
break;
}
else if(recv == "EXIT_OK")
{
cout << "Exiting" << endl;
|
|
97
|
chat->toggleConnected(true);
|
|
98
|
msgListNotEmpty.notify_all();
|
|
99
|
chat->close();
|
|
100
101
|
break;
}
|
|
102
103
104
105
106
|
else if(recv.substr(0,8) == "USERLIST")
{
QString userlist = QString::fromStdString(recv.substr(8));
chat->updateUserList(userlist);
}
|
|
107
108
|
else
{
|
|
109
|
chat->putMsgToPrintQueue(recv,MSG_USER);
|
|
110
111
|
}
}
|
|
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
|
}
Chatroom::Chatroom(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::Chatroom)
{
ui->setupUi(this);
QList<int> chatSizes;
QList<int> splitSizes;
chatSizes.push_front(ui->chatText->height());
chatSizes.push_front(100);
splitSizes.push_front(ui->chatWindow->width());
splitSizes.push_front(200);
ui->chatSplitter->setSizes(chatSizes);
ui->windowSplitter->setSizes(splitSizes);
connected = false;
msgLock = new unique_lock<std::mutex>(msgMutex,std::defer_lock);
chatLock = new unique_lock<std::mutex>(chatMutex,std::defer_lock);
send = NULL;
recv = NULL;
connect(ui->actionConnect,SIGNAL(triggered()),this,SLOT(startSession()));
connect(ui->actionExit,SIGNAL(triggered()),this,SLOT(close()));
connect(ui->actionDisconnect,SIGNAL(triggered()),this,SLOT(disconnectChatroom()));
connect(ui->actionSave_chat,SIGNAL(triggered()),ui->chatText,SLOT(saveChatToFile()));
connect(ui->inputText,SIGNAL(msgReady()),this,SLOT(sendMsg()));
connect(ui->sendButton,SIGNAL(clicked()),this,SLOT(sendMsg()));
connect(this,SIGNAL(messagesToPrint()),this,SLOT(printMsg()));
|
|
141
142
|
connect(this,SIGNAL(serverMessagesToPrint()),this,SLOT(printServerMsg()));
connect(this,SIGNAL(statusMessagesToPrint()),this,SLOT(printStatusMsg()));
|
|
143
144
|
connect(ui->userList,SIGNAL(doubleClicked(QModelIndex)),this,SLOT(launchChatWindow(QModelIndex)));
connect(this,SIGNAL(createChat(QString)),this,SLOT(newChat(QString)));
|
|
145
|
connect(this,SIGNAL(toggleConnected(bool)),this,SLOT(setConnected(bool)));
|
|
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
|
}
void Chatroom::closeEvent(QCloseEvent *event)
{
if(recv == NULL && send == NULL)
{
ui->inputText->setReadOnly(true);
ui->chatText->printServerMsg("Disconnected");
event->accept();
return;
}
sendQueue.clear();
QString exitMsg("/exit");
putMsgToSendQueue(exitMsg);
ui->inputText->setReadOnly(true);
recv->join();
send->join();
|
|
163
164
165
166
167
168
|
map<string,void*>::iterator it;
for(it = activeChats.begin(); it != activeChats.end(); it++)
{
ChatWindow* chat = (ChatWindow*) it->second;
chat->close();
}
|
|
169
170
171
172
|
ui->chatText->printServerMsg("Disconnected");
send = NULL;
recv = NULL;
event->accept();
|
|
173
174
|
}
|
|
175
|
bool Chatroom::getConnected()
|
|
176
|
{
|
|
177
178
179
180
181
182
183
184
185
186
|
myMutex.lock();
bool val = connected;
myMutex.unlock();
return val;
}
void Chatroom::setConnected(bool status)
{
myMutex.lock();
connected = status;
|
|
187
188
189
190
191
192
193
194
195
196
197
198
199
200
|
if(status == false)
{
ui->chatText->printServerMsg("Disconnected");
this->ui->inputText->setReadOnly(true);
this->ui->sendButton->setDisabled(true);
this->ui->actionDisconnect->setDisabled(true);
}
else if(status == true)
{
this->ui->inputText->setReadOnly(false);
this->ui->sendButton->setDisabled(false);
this->ui->actionDisconnect->setDisabled(false);
ui->chatText->printServerMsg("Connected to chatroom");
}
|
|
201
202
203
|
myMutex.unlock();
}
|
|
204
|
void Chatroom::setNickname(QString nick)
|
|
205
|
{
|
|
206
|
nickname = nick;
|
|
207
208
|
}
|
|
209
|
QString Chatroom::getNickname()
|
|
210
|
{
|
|
211
|
return nickname;
|
|
212
213
|
}
|
|
214
|
void Chatroom::updateUserList(QString userlist)
|
|
215
|
{
|
|
216
217
218
|
ui->userList->clear();
QStringList users = userlist.split('\n',QString::SkipEmptyParts);
for(int i = 0; i < users.size(); i++)
|
|
219
|
{
|
|
220
|
ui->userList->addItem(users[i]);
|
|
221
|
}
|
|
222
223
224
225
226
|
}
void Chatroom::relayMsg(string msg)
{
string sender = getSender(msg);
|
|
227
|
if(!ui->userList->findItems(QString::fromStdString(sender),Qt::MatchExactly | Qt::MatchCaseSensitive).isEmpty())
|
|
228
|
{
|
|
229
|
map<string,void*>::iterator it = activeChats.begin();
|
|
230
|
it = activeChats.find(sender);
|
|
231
232
233
234
235
236
237
238
239
|
if(it == activeChats.end())
{
chatLock->lock();
emit createChat(QString::fromStdString(sender));
chatCreated.wait(*chatLock);
chatLock->unlock();
it = activeChats.find(sender);
}
((ChatWindow*)it->second)->notifyPrint(msg);
|
|
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
|
}
}
void Chatroom::newChat(QString peerNick)
{
ChatWindow* newchat = new ChatWindow(peerNick,this);
activeChats.insert(std::pair<string,ChatWindow*>(peerNick.toStdString(),newchat));
newchat->show();
chatCreated.notify_all();
}
void Chatroom::removeChat(QString &nickname)
{
ChatWindow* chat = (ChatWindow*)activeChats.find(nickname.toStdString())->second;
delete chat;
activeChats.erase(nickname.toStdString());
}
void Chatroom::launchChatWindow(QModelIndex index)
{
QString peerNick = ui->userList->model()->data(index).toString();
if(activeChats.find(peerNick.toStdString()) == activeChats.end())
{
emit newChat(peerNick);
}
}
|
|
267
|
void Chatroom::putMsgToPrintQueue(string &msg, int type)
|
|
268
269
|
{
printMutex.lock();
|
|
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
|
if(type == MSG_USER)
{
printQueue.push_back(msg);
emit messagesToPrint();
return;
}
else if(type == MSG_SERVER)
{
printServerQueue.push_back(msg);
emit serverMessagesToPrint();
return;
}
else if(type == MSG_STATUS)
{
printStatusQueue.push_back(msg);
emit statusMessagesToPrint();
return;
}
|
|
288
|
}
|
|
289
|
|
|
290
291
292
293
294
295
296
297
|
void Chatroom::printMsg()
{
while(!printQueue.empty())
{
string msg = printQueue.front();
ui->chatText->printMsg(msg);
printQueue.pop_front();
}
|
|
298
|
printMutex.unlock();
|
|
299
300
|
}
|
|
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
|
void Chatroom::printServerMsg()
{
while(!printServerQueue.empty())
{
string msg = printServerQueue.front();
ui->chatText->printServerMsg(msg);
printServerQueue.pop_front();
}
printMutex.unlock();
}
void Chatroom::printStatusMsg()
{
while(!printStatusQueue.empty())
{
string msg = printStatusQueue.front();
ui->chatText->printStatusMsg(msg);
printStatusQueue.pop_front();
}
printMutex.unlock();
}
|
|
323
324
325
326
327
328
329
330
|
void Chatroom::putMsgToSendQueue(QString& msg)
{
msgMutex.lock();
sendQueue.push_back(msg);
msgMutex.unlock();
msgListNotEmpty.notify_all();
}
|
|
331
|
void Chatroom::sendMsg()
|
|
332
|
{
|
|
333
334
335
|
QString msg = ui->inputText->toPlainText();
ui->inputText->clear();
if(msg == "/disconnect")
|
|
336
|
{
|
|
337
|
this->disconnectChatroom();
|
|
338
|
}
|
|
339
|
else if(msg == "/exit")
|
|
340
|
{
|
|
341
342
343
344
345
|
this->close();
}
else
{
putMsgToSendQueue(msg);
|
|
346
347
348
|
}
}
|
|
349
|
string Chatroom::getSender(string msg)
|
|
350
|
{
|
|
351
352
|
cout << msg << endl;
if(msg[0] == '@')
|
|
353
|
{
|
|
354
355
356
357
358
|
return msg.substr(1,msg.find(" ")-1);
}
else
{
return msg.substr(0,msg.find(":"));
|
|
359
360
361
362
363
364
365
366
367
368
369
370
|
}
}
void Chatroom::disconnectChatroom()
{
msgMutex.lock();
sendQueue.clear();
sendQueue.push_back("/disconnect");
msgMutex.unlock();
msgListNotEmpty.notify_all();
}
|
|
371
|
void Chatroom::startSession()
|
|
372
|
{
|
|
373
374
375
376
|
LoginScreen login(&s,this);
login.exec();
int result = login.result();
if(result == QDialog::Accepted)
|
|
377
|
{
|
|
378
379
380
381
382
|
ui->inputText->setReadOnly(false);
}
else if(result == QDialog::Rejected)
{
return;
|
|
383
|
}
|
|
384
|
setConnected(true);
|
|
385
386
|
recv = new std::thread(recvThread,&s,this);
send = new std::thread(sendThread,&s,this);
|
|
387
388
389
390
|
}
Chatroom::~Chatroom()
{
|
|
391
392
393
|
delete msgLock;
delete recv;
delete send;
|
|
394
395
396
397
398
399
|
map<string,void*>::iterator it;
for(it = activeChats.begin(); it != activeChats.end(); it++)
{
ChatWindow* chat = (ChatWindow*) it->second;
delete chat;
}
|
|
400
401
|
delete ui;
}
|
|
402
403
|
|