|
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
51
52
53
54
55
56
57
58
|
if(send == "/disconnect" || send == "/exit")
{
break;
}
}
catch(SocketException& e)
{
cout << e.description() << endl;
}
}
}
|
|
59
|
void recvThread(Socket* s, Chatroom* chat)
|
|
60
61
62
63
64
65
|
{
string recv;
while(true)
{
try
{
|
|
66
67
68
|
*s >> recv;
if(recv[0] == '1')
{
|
|
69
|
chat->relayMsg(recv.substr(1));
|
|
70
71
72
73
74
75
|
continue;
}
else if(recv[0] == '0')
{
recv = recv.substr(1);
}
|
|
76
77
78
|
}
catch(SocketException &e)
{
|
|
79
|
chat->toggleConnected(false);
|
|
80
|
cout << e.description() << endl;
|
|
81
|
msgListNotEmpty.notify_all();
|
|
82
83
|
string msg = "Connection to server lost";
chat->putMsgToPrintQueue(msg,MSG_STATUS);
|
|
84
85
86
87
88
|
break;
}
if(recv == "DISC_OK")
{
cout << "Disconnecting" << endl;
|
|
89
|
chat->toggleConnected(false);
|
|
90
|
msgListNotEmpty.notify_all();
|
|
91
92
93
94
95
|
break;
}
else if(recv == "EXIT_OK")
{
cout << "Exiting" << endl;
|
|
96
|
chat->toggleConnected(false);
|
|
97
|
msgListNotEmpty.notify_all();
|
|
98
|
chat->close();
|
|
99
100
|
break;
}
|
|
101
102
103
|
else if(recv.substr(0,8) == "USERLIST")
{
QString userlist = QString::fromStdString(recv.substr(8));
|
|
104
|
emit chat->newUsers(userlist);
|
|
105
|
}
|
|
106
107
|
else
{
|
|
108
|
chat->putMsgToPrintQueue(recv,MSG_USER);
|
|
109
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
|
}
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()));
|
|
140
141
|
connect(this,SIGNAL(serverMessagesToPrint()),this,SLOT(printServerMsg()));
connect(this,SIGNAL(statusMessagesToPrint()),this,SLOT(printStatusMsg()));
|
|
142
143
|
connect(ui->userList,SIGNAL(doubleClicked(QModelIndex)),this,SLOT(launchChatWindow(QModelIndex)));
connect(this,SIGNAL(createChat(QString)),this,SLOT(newChat(QString)));
|
|
144
|
connect(this,SIGNAL(toggleConnected(bool)),this,SLOT(setConnected(bool)));
|
|
145
|
connect(this,SIGNAL(newUsers(QString)),this,SLOT(updateUserList(QString)));
|
|
146
147
148
149
150
151
152
153
154
155
156
157
158
159
|
}
void Chatroom::closeEvent(QCloseEvent *event)
{
if(recv == NULL && send == NULL)
{
event->accept();
return;
}
sendQueue.clear();
QString exitMsg("/exit");
putMsgToSendQueue(exitMsg);
recv->join();
send->join();
|
|
160
161
|
freeChats(true);
freeChats(false);
|
|
162
|
event->accept();
|
|
163
164
|
}
|
|
165
|
bool Chatroom::getConnected()
|
|
166
|
{
|
|
167
168
169
170
171
172
173
174
175
176
|
myMutex.lock();
bool val = connected;
myMutex.unlock();
return val;
}
void Chatroom::setConnected(bool status)
{
myMutex.lock();
connected = status;
|
|
177
178
179
180
181
182
|
if(status == false)
{
ui->chatText->printServerMsg("Disconnected");
this->ui->inputText->setReadOnly(true);
this->ui->sendButton->setDisabled(true);
this->ui->actionDisconnect->setDisabled(true);
|
|
183
|
this->ui->userList->clear();
|
|
184
185
186
187
188
189
190
191
|
}
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");
}
|
|
192
193
194
|
myMutex.unlock();
}
|
|
195
|
void Chatroom::setNickname(QString nick)
|
|
196
|
{
|
|
197
|
nickname = nick;
|
|
198
199
|
}
|
|
200
|
QString Chatroom::getNickname()
|
|
201
|
{
|
|
202
|
return nickname;
|
|
203
204
|
}
|
|
205
|
void Chatroom::updateUserList(QString userlist)
|
|
206
|
{
|
|
207
208
209
|
ui->userList->clear();
QStringList users = userlist.split('\n',QString::SkipEmptyParts);
for(int i = 0; i < users.size(); i++)
|
|
210
|
{
|
|
211
|
ui->userList->addItem(users[i]);
|
|
212
|
}
|
|
213
214
215
216
217
|
}
void Chatroom::relayMsg(string msg)
{
string sender = getSender(msg);
|
|
218
|
if(!ui->userList->findItems(QString::fromStdString(sender),Qt::MatchExactly | Qt::MatchCaseSensitive).isEmpty())
|
|
219
|
{
|
|
220
|
map<string,void*>::iterator it = activeChats.begin();
|
|
221
|
it = activeChats.find(sender);
|
|
222
223
224
225
226
227
228
229
230
|
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);
|
|
231
232
233
234
235
|
}
}
void Chatroom::newChat(QString peerNick)
{
|
|
236
|
freeChats(false);
|
|
237
238
239
240
241
242
243
244
|
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)
{
|
|
245
|
chatMutex.lock();
|
|
246
247
|
ChatWindow* chat = (ChatWindow*) activeChats.find(nickname.toStdString())->second;
inactiveChats.insert(std::pair<string,ChatWindow*>(nickname.toStdString(),chat));
|
|
248
|
activeChats.erase(nickname.toStdString());
|
|
249
|
chatMutex.unlock();
|
|
250
251
252
253
254
255
256
|
}
void Chatroom::launchChatWindow(QModelIndex index)
{
QString peerNick = ui->userList->model()->data(index).toString();
if(activeChats.find(peerNick.toStdString()) == activeChats.end())
{
|
|
257
|
emit createChat(peerNick);
|
|
258
259
260
|
}
}
|
|
261
|
void Chatroom::putMsgToPrintQueue(string &msg, int type)
|
|
262
263
|
{
printMutex.lock();
|
|
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
|
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;
}
|
|
282
|
}
|
|
283
|
|
|
284
285
286
287
288
289
290
291
|
void Chatroom::printMsg()
{
while(!printQueue.empty())
{
string msg = printQueue.front();
ui->chatText->printMsg(msg);
printQueue.pop_front();
}
|
|
292
|
printMutex.unlock();
|
|
293
294
|
}
|
|
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
|
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();
}
|
|
317
318
319
320
321
322
323
324
|
void Chatroom::putMsgToSendQueue(QString& msg)
{
msgMutex.lock();
sendQueue.push_back(msg);
msgMutex.unlock();
msgListNotEmpty.notify_all();
}
|
|
325
|
void Chatroom::sendMsg()
|
|
326
|
{
|
|
327
328
329
|
QString msg = ui->inputText->toPlainText();
ui->inputText->clear();
if(msg == "/disconnect")
|
|
330
|
{
|
|
331
|
this->disconnectChatroom();
|
|
332
|
}
|
|
333
|
else if(msg == "/exit")
|
|
334
|
{
|
|
335
336
337
338
339
|
this->close();
}
else
{
putMsgToSendQueue(msg);
|
|
340
341
342
|
}
}
|
|
343
|
string Chatroom::getSender(string msg)
|
|
344
|
{
|
|
345
|
if(msg[0] == '@')
|
|
346
|
{
|
|
347
348
349
350
351
|
return msg.substr(1,msg.find(" ")-1);
}
else
{
return msg.substr(0,msg.find(":"));
|
|
352
353
354
355
356
357
358
359
360
361
362
363
|
}
}
void Chatroom::disconnectChatroom()
{
msgMutex.lock();
sendQueue.clear();
sendQueue.push_back("/disconnect");
msgMutex.unlock();
msgListNotEmpty.notify_all();
}
|
|
364
|
void Chatroom::startSession()
|
|
365
|
{
|
|
366
367
368
|
LoginScreen login(&s,this);
login.exec();
int result = login.result();
|
|
369
|
if(result == QDialog::Rejected)
|
|
370
371
|
{
return;
|
|
372
|
}
|
|
373
|
setConnected(true);
|
|
374
375
|
recv = new std::thread(recvThread,&s,this);
send = new std::thread(sendThread,&s,this);
|
|
376
377
|
}
|
|
378
379
|
void Chatroom::freeChats(bool active)
{
|
|
380
|
map<string,void*>::iterator it;
|
|
381
382
|
if(active)
{
|
|
383
|
while(true)
|
|
384
|
{
|
|
385
386
387
388
389
390
391
|
chatMutex.lock();
it = activeChats.begin();
chatMutex.unlock();
if(it == activeChats.end())
{
break;
}
|
|
392
|
ChatWindow* chat = (ChatWindow*) it->second;
|
|
393
|
chat->notifyClose();
|
|
394
395
396
397
|
}
}
else
{
|
|
398
|
for(it = inactiveChats.begin(); it != inactiveChats.end(); it++)
|
|
399
400
401
402
|
{
ChatWindow* chat = (ChatWindow*) it->second;
delete chat;
}
|
|
403
|
inactiveChats.clear();
|
|
404
405
406
|
}
}
|
|
407
408
|
Chatroom::~Chatroom()
{
|
|
409
|
delete msgLock;
|
|
410
|
delete chatLock;
|
|
411
412
|
delete recv;
delete send;
|
|
413
414
|
delete ui;
}
|