blob: 0f6e8060443268e7b1c61c0d14f8c3b7a1f6f8ea [file] [log] [blame]
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -07001#include <QtGui>
2#include "chatdialog.h"
Zhenkai Zhu85845d22012-06-01 23:10:43 -07003#include "settingdialog.h"
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -07004#include <ctime>
Zhenkai Zhub6338822012-05-31 13:27:24 -07005#include <iostream>
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -07006#include <QTimer>
Zhenkai Zhu10ccb5a2012-06-04 21:55:14 -07007#include <QMetaType>
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -07008
Zhenkai Zhu82a62752012-06-04 17:11:04 -07009#define BROADCAST_PREFIX_FOR_SYNC_DEMO "/ndn/broadcast/sync-demo"
10
Zhenkai Zhu21d75f92012-06-04 21:23:34 -070011void
12ChatDialog::testDraw()
13{
14 std::string prefix[5] = {"/ndn/1", "/ndn/2", "/ndn/3", "/ndn/4", "/ndn/5"};
15 std::string nick[5] = {"tom", "jerry", "jason", "michael", "hurry"};
16 std::vector<Sync::MissingDataInfo> v;
17 for (int i = 0; i < 5; i++)
18 {
19 Sync::MissingDataInfo mdi = {prefix[i], Sync::SeqNo(0), Sync::SeqNo(i * (2 << i) )};
20 v.push_back(mdi);
21 }
22
23 m_scene->processUpdate(v, "12341234@!#%!@");
24
25 for (int i = 0; i < 5; i++)
26 {
27 m_scene-> msgReceived(prefix[i].c_str(), nick[i].c_str());
28 }
29
30 fitView();
31}
32
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -070033ChatDialog::ChatDialog(QWidget *parent)
Zhenkai Zhu82a62752012-06-04 17:11:04 -070034 : QDialog(parent), m_sock(NULL)
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -070035{
Zhenkai Zhu10ccb5a2012-06-04 21:55:14 -070036 // have to register this, otherwise
37 // the signal-slot system won't recognize this type
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -070038 qRegisterMetaType<std::vector<Sync::MissingDataInfo> >("std::vector<Sync::MissingDataInfo>");
39 qRegisterMetaType<size_t>("size_t");
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -070040 setupUi(this);
Zhenkai Zhu82a62752012-06-04 17:11:04 -070041 m_session = time(NULL);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -070042
43 readSettings();
Zhenkai Zhu82a62752012-06-04 17:11:04 -070044
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -070045 updateLabels();
46
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -070047 lineEdit->setFocusPolicy(Qt::StrongFocus);
Zhenkai Zhu82a62752012-06-04 17:11:04 -070048 m_scene = new DigestTreeScene(this);
Zhenkai Zhub45e38a2012-06-01 15:44:36 -070049
Zhenkai Zhu82a62752012-06-04 17:11:04 -070050 treeViewer->setScene(m_scene);
51 m_scene->plot("Empty");
52 QRectF rect = m_scene->itemsBoundingRect();
53 m_scene->setSceneRect(rect);
54
55 // create sync socket
56 if(!m_user.getChatroom().isEmpty()) {
57 std::string syncPrefix = BROADCAST_PREFIX_FOR_SYNC_DEMO;
58 syncPrefix += "/";
59 syncPrefix += m_user.getChatroom().toStdString();
Zhenkai Zhua4fb1242012-06-05 20:26:05 -070060 try
61 {
62 m_sock = new Sync::SyncAppSocket(syncPrefix, bind(&ChatDialog::processTreeUpdateWrapper, this, _1, _2), bind(&ChatDialog::processRemove, this, _1));
63 }
64 catch (Sync::CcnxOperationException ex)
65 {
66 QMessageBox::critical(this, tr("Sync-Demo"), tr("Canno connect to ccnd.\n Have you started your ccnd?"), QMessageBox::Ok);
67 std::exit(1);
68 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -070069 }
Zhenkai Zhub45e38a2012-06-01 15:44:36 -070070
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -070071 connect(lineEdit, SIGNAL(returnPressed()), this, SLOT(returnPressed()));
Zhenkai Zhu85845d22012-06-01 23:10:43 -070072 connect(setButton, SIGNAL(pressed()), this, SLOT(buttonPressed()));
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -070073 connect(this, SIGNAL(dataReceived(QString, const char *, size_t)), this, SLOT(processData(QString, const char *, size_t)));
74 connect(this, SIGNAL(treeUpdated(const std::vector<Sync::MissingDataInfo>)), this, SLOT(processTreeUpdate(const std::vector<Sync::MissingDataInfo>)));
Zhenkai Zhu10ccb5a2012-06-04 21:55:14 -070075 //testDraw();
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -070076}
77
Zhenkai Zhu82a62752012-06-04 17:11:04 -070078ChatDialog::~ChatDialog()
79{
80 if (m_sock != NULL)
81 {
82 delete m_sock;
83 m_sock = NULL;
84 }
85}
86
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -070087void
Zhenkai Zhu10ccb5a2012-06-04 21:55:14 -070088ChatDialog::appendMessage(const SyncDemo::ChatMessage msg)
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -070089{
Zhenkai Zhu44b43752012-06-05 21:18:37 -070090 boost::mutex::scoped_lock lock(m_msgMutex);
Zhenkai Zhub6338822012-05-31 13:27:24 -070091
92 if (msg.type() != SyncDemo::ChatMessage::CHAT) {
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -070093 return;
Zhenkai Zhub6338822012-05-31 13:27:24 -070094 }
95
96 if (!msg.has_data()) {
97 return;
98 }
99
100 if (msg.from().empty() || msg.data().empty()) {
101 return;
102 }
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700103
104 QTextCursor cursor(textEdit->textCursor());
105 cursor.movePosition(QTextCursor::End);
106 QTextTableFormat tableFormat;
107 tableFormat.setBorder(0);
108 QTextTable *table = cursor.insertTable(1, 2, tableFormat);
Zhenkai Zhub6338822012-05-31 13:27:24 -0700109 QString from = QString("<%1>: ").arg(msg.from().c_str());
110 table->cellAt(0, 0).firstCursorPosition().insertText(from);
111 table->cellAt(0, 1).firstCursorPosition().insertText(msg.data().c_str());
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700112 QScrollBar *bar = textEdit->verticalScrollBar();
113 bar->setValue(bar->maximum());
114}
115
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700116void
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700117ChatDialog::processTreeUpdateWrapper(const std::vector<Sync::MissingDataInfo> v, Sync::SyncAppSocket *sock)
118{
119 emit treeUpdated(v);
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700120#ifdef __DEBUG
121 std::cout << "<<< Tree update signal emitted" << std::endl;
122#endif
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700123}
124
125void
126ChatDialog::processTreeUpdate(const std::vector<Sync::MissingDataInfo> v)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700127{
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700128#ifdef __DEBUG
129 std::cout << "<<< processing Tree Update" << std::endl;
130#endif
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700131 if (v.empty())
132 {
133 return;
134 }
135
136 // reflect the changes on digest tree
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700137 {
138 boost::mutex::scoped_lock lock(m_sceneMutex);
139 m_scene->processUpdate(v, m_sock->getRootDigest().c_str());
140 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700141
142 int n = v.size();
143 int totalMissingPackets = 0;
144 for (int i = 0; i < n; i++)
145 {
146 totalMissingPackets += v[i].high.getSeq() - v[i].low.getSeq() + 1;
147 }
148
149 if (totalMissingPackets < 10) {
150 for (int i = 0; i < n; i++)
151 {
152 for (Sync::SeqNo seq = v[i].low; seq <= v[i].high; ++seq)
153 {
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700154 m_sock->fetchRaw(v[i].prefix, seq, bind(&ChatDialog::processDataWrapper, this, _1, _2, _3), 2);
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700155#ifdef __DEBUG
156 std::cout << "<<< Fetching " << v[i].prefix << "/" <<seq.getSession() <<"/" << seq.getSeq() << std::endl;
157#endif
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700158 }
159 }
160 }
161 else
162 {
163 // too bad; too many missing packets
164 // we may just join a new chatroom
165 // or some network patition just healed
166 // we don't try to fetch any data in this case (for now)
167 }
168
169 // adjust the view
170 fitView();
171
172}
173
174void
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700175ChatDialog::processDataWrapper(std::string name, const char *buf, size_t len)
176{
177 emit dataReceived(name.c_str(), buf, len);
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700178#ifdef __DEBUG
179 std::cout <<"<<< " << name << " fetched" << std::endl;
180#endif
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700181}
182
183void
184ChatDialog::processData(QString name, const char *buf, size_t len)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700185{
186 SyncDemo::ChatMessage msg;
187 if (!msg.ParseFromArray(buf, len))
188 {
189 std::cerr << "Errrrr.. Can not parse msg at "<<__FILE__ <<":"<<__LINE__<<". what is happening?" << std::endl;
190 abort();
191 }
192
Zhenkai Zhu10ccb5a2012-06-04 21:55:14 -0700193 // display msg received from network
194 // we have to do so; this function is called by ccnd thread
195 // so if we call appendMsg directly
196 // Qt crash as "QObject: Cannot create children for a parent that is in a different thread"
197 // the "cannonical" way to is use signal-slot
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700198 appendMessage(msg);
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700199
200 // update the tree view
Zhenkai Zhu097bfe72012-06-05 14:30:17 -0700201 std::string stdStrName = name.toStdString();
202 std::string stdStrNameWithoutSeq = stdStrName.substr(0, stdStrName.find_last_of('/'));
203 std::string prefix = stdStrNameWithoutSeq.substr(0, stdStrNameWithoutSeq.find_last_of('/'));
204#ifdef __DEBUG
205 std::cout <<"<<< updating scene for" << prefix << ": " << msg.from() << std::endl;
206#endif
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700207 {
208 boost::mutex::scoped_lock lock(m_sceneMutex);
209 m_scene->msgReceived(prefix.c_str(), msg.from().c_str());
210 }
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700211 fitView();
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700212}
213
214void
215ChatDialog::processRemove(std::string prefix)
216{
217}
218
219void
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700220ChatDialog::formChatMessage(const QString &text, SyncDemo::ChatMessage &msg) {
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700221 msg.set_from(m_user.getNick().toStdString());
222 msg.set_to(m_user.getChatroom().toStdString());
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700223 msg.set_data(text.toStdString());
224 time_t seconds = time(NULL);
225 msg.set_timestamp(seconds);
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700226 msg.set_type(SyncDemo::ChatMessage::CHAT);
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700227}
228
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700229bool
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700230ChatDialog::readSettings()
231{
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700232#ifndef __DEBUG
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700233 QSettings s(ORGANIZATION, APPLICATION);
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700234 QString nick = s.value("nick", "").toString();
235 QString chatroom = s.value("chatroom", "").toString();
236 QString prefix = s.value("prefix", "").toString();
237 if (nick == "" || chatroom == "" || prefix == "") {
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700238 QTimer::singleShot(500, this, SLOT(buttonPressed()));
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700239 return false;
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700240 }
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700241 else {
242 m_user.setNick(nick);
243 m_user.setChatroom(chatroom);
244 m_user.setPrefix(prefix);
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700245 return true;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700246 }
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700247#else
248 QTimer::singleShot(500, this, SLOT(buttonPressed()));
249 return false;
250#endif
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700251}
252
253void
254ChatDialog::writeSettings()
255{
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700256#ifndef __DEBUG
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700257 QSettings s(ORGANIZATION, APPLICATION);
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700258 s.setValue("nick", m_user.getNick());
259 s.setValue("chatroom", m_user.getChatroom());
260 s.setValue("prefix", m_user.getPrefix());
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700261#endif
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700262}
263
264void
265ChatDialog::updateLabels()
266{
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700267 QString settingDisp = QString("<User: %1>, <Chatroom: %2>").arg(m_user.getNick()).arg(m_user.getChatroom());
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700268 infoLabel->setText(settingDisp);
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700269 QString prefixDisp = QString("<Prefix: %1>").arg(m_user.getPrefix());
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700270 prefixLabel->setText(prefixDisp);
271}
272
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700273void
274ChatDialog::returnPressed()
275{
276 QString text = lineEdit->text();
277 if (text.isEmpty())
278 return;
279
Zhenkai Zhub6338822012-05-31 13:27:24 -0700280 lineEdit->clear();
281
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700282 SyncDemo::ChatMessage msg;
283 formChatMessage(text, msg);
284
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700285 appendMessage(msg);
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700286
287 // send msg
288 size_t size = msg.ByteSize();
289 char *buf = new char[size];
290 msg.SerializeToArray(buf, size);
291 if (!msg.IsInitialized())
292 {
293 std::cerr << "Errrrr.. msg was not probally initialized "<<__FILE__ <<":"<<__LINE__<<". what is happening?" << std::endl;
294 abort();
295 }
296 m_sock->publishRaw(m_user.getPrefix().toStdString(), m_session, buf, size, 60);
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700297
298 int nextSequence = m_sock->getNextSeq(m_user.getPrefix().toStdString(), m_session);
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700299 Sync::MissingDataInfo mdi = {m_user.getPrefix().toStdString(), Sync::SeqNo(0), Sync::SeqNo(nextSequence - 1)};
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700300 std::vector<Sync::MissingDataInfo> v;
301 v.push_back(mdi);
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700302 {
303 boost::mutex::scoped_lock lock(m_sceneMutex);
304 m_scene->processUpdate(v, m_sock->getRootDigest().c_str());
305 m_scene->msgReceived(m_user.getPrefix(), m_user.getNick());
306 }
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700307 fitView();
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700308}
309
310void
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700311ChatDialog::buttonPressed()
312{
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700313 SettingDialog dialog(this, m_user.getNick(), m_user.getChatroom(), m_user.getPrefix());
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700314 connect(&dialog, SIGNAL(updated(QString, QString, QString)), this, SLOT(settingUpdated(QString, QString, QString)));
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700315 dialog.exec();
Zhenkai Zhue837f792012-06-05 20:47:54 -0700316 QTimer::singleShot(100, this, SLOT(checkSetting()));
317}
318
319void
320ChatDialog::checkSetting()
321{
322 if (m_user.getPrefix().isEmpty() || m_user.getNick().isEmpty() || m_user.getChatroom().isEmpty())
323 {
324 buttonPressed();
325 }
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -0700326}
Zhenkai Zhue08afe02012-05-31 15:49:07 -0700327
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700328void
329ChatDialog::settingUpdated(QString nick, QString chatroom, QString prefix)
330{
331 bool needWrite = false;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700332 if (!nick.isEmpty() && nick != m_user.getNick()) {
333 m_user.setNick(nick);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700334 needWrite = true;
335 }
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700336 if (!prefix.isEmpty() && prefix != m_user.getPrefix()) {
337 m_user.setPrefix(prefix);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700338 needWrite = true;
339 // TODO: set the previous prefix as left?
340 }
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700341 if (!chatroom.isEmpty() && chatroom != m_user.getChatroom()) {
342 m_user.setChatroom(chatroom);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700343 needWrite = true;
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700344
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700345 {
346 boost::mutex::scoped_lock lock(m_sceneMutex);
347 m_scene->clearAll();
348 m_scene->plot("Empty");
349 }
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700350 // TODO: perhaps need to do a lot. e.g. use a new SyncAppSokcet
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700351 if (m_sock != NULL)
352 {
353 delete m_sock;
354 m_sock = NULL;
355 }
356 std::string syncPrefix = BROADCAST_PREFIX_FOR_SYNC_DEMO;
357 syncPrefix += "/";
358 syncPrefix += m_user.getChatroom().toStdString();
Zhenkai Zhua4fb1242012-06-05 20:26:05 -0700359 try
360 {
361 m_sock = new Sync::SyncAppSocket(syncPrefix, bind(&ChatDialog::processTreeUpdateWrapper, this, _1, _2), bind(&ChatDialog::processRemove, this, _1));
362 }
363 catch (Sync::CcnxOperationException ex)
364 {
365 QMessageBox::critical(this, tr("Sync-Demo"), tr("Canno connect to ccnd.\n Have you started your ccnd?"), QMessageBox::Ok);
366 std::exit(1);
367 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700368
369 fitView();
370
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700371 }
372 if (needWrite) {
373 writeSettings();
374 updateLabels();
375 }
376}
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700377
378void
379ChatDialog::resizeEvent(QResizeEvent *e)
380{
381 fitView();
382}
383
384void
385ChatDialog::showEvent(QShowEvent *e)
386{
387 fitView();
388}
389
390void
391ChatDialog::fitView()
392{
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700393 boost::mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700394 QRectF rect = m_scene->itemsBoundingRect();
395 m_scene->setSceneRect(rect);
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700396 treeViewer->fitInView(m_scene->itemsBoundingRect(), Qt::KeepAspectRatio);
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700397}