blob: abf60057ef17002a9be6b0fe4d72e5068c16b927 [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 Zhu3a008fc2012-06-08 17:36:39 -07008#include <QMessageBox>
Zhenkai Zhu59245aa2012-09-26 16:07:04 -07009#include <boost/random/random_device.hpp>
10#include <boost/random/uniform_int_distribution.hpp>
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -070011
Zhenkai Zhu82a62752012-06-04 17:11:04 -070012#define BROADCAST_PREFIX_FOR_SYNC_DEMO "/ndn/broadcast/sync-demo"
13
Zhenkai Zhuee5c90f2012-09-27 14:05:41 -070014static const int HELLO_INTERVAL = 90; // seconds
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -070015
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -070016ChatDialog::ChatDialog(QWidget *parent)
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -070017 : QDialog(parent), m_sock(NULL), m_lastMsgTime(0)
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -070018{
Zhenkai Zhu10ccb5a2012-06-04 21:55:14 -070019 // have to register this, otherwise
20 // the signal-slot system won't recognize this type
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -070021 qRegisterMetaType<std::vector<Sync::MissingDataInfo> >("std::vector<Sync::MissingDataInfo>");
22 qRegisterMetaType<size_t>("size_t");
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -070023 setupUi(this);
Zhenkai Zhu82a62752012-06-04 17:11:04 -070024 m_session = time(NULL);
Zhenkai Zhuee5c90f2012-09-27 14:05:41 -070025 boost::random::random_device rng;
26 boost::random::uniform_int_distribution<> uniform(1, 29000);
27 m_randomizedInterval = HELLO_INTERVAL * 1000 + uniform(rng);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -070028
29 readSettings();
Zhenkai Zhu82a62752012-06-04 17:11:04 -070030
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -070031 updateLabels();
32
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -070033 lineEdit->setFocusPolicy(Qt::StrongFocus);
Zhenkai Zhu82a62752012-06-04 17:11:04 -070034 m_scene = new DigestTreeScene(this);
Zhenkai Zhub45e38a2012-06-01 15:44:36 -070035
Zhenkai Zhu82a62752012-06-04 17:11:04 -070036 treeViewer->setScene(m_scene);
37 m_scene->plot("Empty");
38 QRectF rect = m_scene->itemsBoundingRect();
39 m_scene->setSceneRect(rect);
40
Zhenkai Zhu86df7412012-09-27 16:30:20 -070041 createActions();
42 createTrayIcon();
43 m_timer = new QTimer(this);
44 connect(lineEdit, SIGNAL(returnPressed()), this, SLOT(returnPressed()));
45 connect(setButton, SIGNAL(pressed()), this, SLOT(buttonPressed()));
46 connect(this, SIGNAL(dataReceived(QString, const char *, size_t, bool)), this, SLOT(processData(QString, const char *, size_t, bool)));
47 connect(this, SIGNAL(treeUpdated(const std::vector<Sync::MissingDataInfo>)), this, SLOT(processTreeUpdate(const std::vector<Sync::MissingDataInfo>)));
48 connect(this, SIGNAL(removeReceived(QString)), this, SLOT(processRemove(QString)));
49 connect(m_timer, SIGNAL(timeout()), this, SLOT(replot()));
50 connect(m_scene, SIGNAL(replot()), this, SLOT(replot()));
51 connect(trayIcon, SIGNAL(messageClicked()), this, SLOT(showNormal()));
52 connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
53
Zhenkai Zhu82a62752012-06-04 17:11:04 -070054 // create sync socket
55 if(!m_user.getChatroom().isEmpty()) {
56 std::string syncPrefix = BROADCAST_PREFIX_FOR_SYNC_DEMO;
57 syncPrefix += "/";
58 syncPrefix += m_user.getChatroom().toStdString();
Zhenkai Zhua4fb1242012-06-05 20:26:05 -070059 try
60 {
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -070061 m_sock = new Sync::SyncAppSocket(syncPrefix, bind(&ChatDialog::processTreeUpdateWrapper, this, _1, _2), bind(&ChatDialog::processRemoveWrapper, this, _1));
62 sendHello();
Zhenkai Zhu86df7412012-09-27 16:30:20 -070063 m_timer->start(FRESHNESS * 2000);
Zhenkai Zhua4fb1242012-06-05 20:26:05 -070064 }
65 catch (Sync::CcnxOperationException ex)
66 {
67 QMessageBox::critical(this, tr("Sync-Demo"), tr("Canno connect to ccnd.\n Have you started your ccnd?"), QMessageBox::Ok);
68 std::exit(1);
69 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -070070 }
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -070071
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -070072//testDraw();
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -070073}
74
Zhenkai Zhu82a62752012-06-04 17:11:04 -070075ChatDialog::~ChatDialog()
76{
77 if (m_sock != NULL)
78 {
Zhenkai Zhu591e8c32012-09-26 11:57:50 -070079 m_sock->remove(m_user.getPrefix().toStdString());
Zhenkai Zhu82a62752012-06-04 17:11:04 -070080 delete m_sock;
81 m_sock = NULL;
82 }
83}
84
Zhenkai Zhu86df7412012-09-27 16:30:20 -070085void
86ChatDialog::replot()
87{
88 boost::mutex::scoped_lock lock(m_sceneMutex);
89 m_scene->plot(m_sock->getRootDigest().c_str());
90}
91
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -070092void
93ChatDialog::setVisible(bool visible)
94{
95 minimizeAction->setEnabled(visible);
96 maximizeAction->setEnabled(!isMaximized());
97 restoreAction->setEnabled(isMaximized() || !visible);
98 QDialog::setVisible(visible);
99}
100
101void
102ChatDialog::closeEvent(QCloseEvent *e)
103{
104 if (trayIcon->isVisible())
105 {
106 QMessageBox::information(this, tr("Sync-Demo"),
107 tr("The program will keep running in the "
108 "system tray. To terminate the program"
109 "choose <b>Quit</b> in the context memu"
110 "of the system tray entry."));
111 hide();
112 e->ignore();
113 }
114}
115
116void
117ChatDialog::changeEvent(QEvent *e)
118{
119 switch(e->type())
120 {
121 case QEvent::ActivationChange:
122 if (isActiveWindow())
123 {
124 trayIcon->setIcon(QIcon(":/images/icon_small.png"));
125 }
126 break;
127 default:
128 break;
129 }
130}
131
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700132void
Zhenkai Zhu10ccb5a2012-06-04 21:55:14 -0700133ChatDialog::appendMessage(const SyncDemo::ChatMessage msg)
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700134{
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700135 boost::mutex::scoped_lock lock(m_msgMutex);
Zhenkai Zhub6338822012-05-31 13:27:24 -0700136
137 if (msg.type() != SyncDemo::ChatMessage::CHAT) {
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700138 return;
Zhenkai Zhub6338822012-05-31 13:27:24 -0700139 }
140
141 if (!msg.has_data()) {
142 return;
143 }
144
145 if (msg.from().empty() || msg.data().empty()) {
146 return;
147 }
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700148
Zhenkai Zhub98e6022012-09-27 13:48:23 -0700149 if (!msg.has_timestamp())
150 {
151 return;
152 }
153
154 QTextCharFormat nickFormat;
155 nickFormat.setForeground(Qt::darkGreen);
156 nickFormat.setFontWeight(QFont::Bold);
157 nickFormat.setFontUnderline(true);
158 nickFormat.setUnderlineColor(Qt::gray);
159 QTextCharFormat timeFormat;
160 timeFormat.setForeground(Qt::gray);
161 timeFormat.setFontUnderline(true);
162 timeFormat.setUnderlineColor(Qt::gray);
163
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700164 QTextCursor cursor(textEdit->textCursor());
165 cursor.movePosition(QTextCursor::End);
166 QTextTableFormat tableFormat;
167 tableFormat.setBorder(0);
168 QTextTable *table = cursor.insertTable(1, 2, tableFormat);
Zhenkai Zhub98e6022012-09-27 13:48:23 -0700169 QString from = QString("%1 ").arg(msg.from().c_str());
170 QTextTableCell fromCell = table->cellAt(0, 0);
171 fromCell.setFormat(nickFormat);
172 fromCell.firstCursorPosition().insertText(from);
173 QTextTableCell timeCell = table->cellAt(0, 1);
174 timeCell.setFormat(timeFormat);
175 time_t timestamp = msg.timestamp();
176 struct tm *tm_time = localtime(&timestamp);
177 int hour = tm_time->tm_hour;
178 QString amOrPM;
179 if (hour > 12)
180 {
181 hour -= 12;
182 amOrPM = "PM";
183 }
184 else
185 {
186 amOrPM = "AM";
187 if (hour == 0)
188 {
189 hour = 12;
190 }
191 }
192
193 char textTime[12];
194 sprintf(textTime, "%d:%02d:%02d %s", hour, tm_time->tm_min, tm_time->tm_sec, amOrPM.toStdString().c_str());
195 timeCell.firstCursorPosition().insertText(textTime);
196
197
198 QTextCursor nextCursor(textEdit->textCursor());
199 table = nextCursor.insertTable(1, 1, tableFormat);
200 table->cellAt(0, 0).firstCursorPosition().insertText(msg.data().c_str());
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700201 QScrollBar *bar = textEdit->verticalScrollBar();
202 bar->setValue(bar->maximum());
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700203 showMessage(from, msg.data().c_str());
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700204}
205
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700206void
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700207ChatDialog::processTreeUpdateWrapper(const std::vector<Sync::MissingDataInfo> v, Sync::SyncAppSocket *sock)
208{
209 emit treeUpdated(v);
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700210#ifdef __DEBUG
211 std::cout << "<<< Tree update signal emitted" << std::endl;
212#endif
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700213}
214
215void
216ChatDialog::processTreeUpdate(const std::vector<Sync::MissingDataInfo> v)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700217{
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700218#ifdef __DEBUG
219 std::cout << "<<< processing Tree Update" << std::endl;
220#endif
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700221 if (v.empty())
222 {
223 return;
224 }
225
226 // reflect the changes on digest tree
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700227 {
228 boost::mutex::scoped_lock lock(m_sceneMutex);
229 m_scene->processUpdate(v, m_sock->getRootDigest().c_str());
230 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700231
232 int n = v.size();
233 int totalMissingPackets = 0;
234 for (int i = 0; i < n; i++)
235 {
236 totalMissingPackets += v[i].high.getSeq() - v[i].low.getSeq() + 1;
237 }
238
Zhenkai Zhubb198112012-09-27 11:31:42 -0700239 for (int i = 0; i < n; i++)
240 {
241 if (totalMissingPackets < 4)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700242 {
243 for (Sync::SeqNo seq = v[i].low; seq <= v[i].high; ++seq)
244 {
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700245 m_sock->fetchRaw(v[i].prefix, seq, bind(&ChatDialog::processDataWrapper, this, _1, _2, _3), 2);
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700246#ifdef __DEBUG
247 std::cout << "<<< Fetching " << v[i].prefix << "/" <<seq.getSession() <<"/" << seq.getSeq() << std::endl;
248#endif
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700249 }
250 }
Zhenkai Zhubb198112012-09-27 11:31:42 -0700251 else
252 {
253 m_sock->fetchRaw(v[i].prefix, v[i].high, bind(&ChatDialog::processDataNoShowWrapper, this, _1, _2, _3), 2);
254 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700255 }
256
257 // adjust the view
258 fitView();
259
260}
261
262void
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700263ChatDialog::processDataWrapper(std::string name, const char *buf, size_t len)
264{
Zhenkai Zhubb198112012-09-27 11:31:42 -0700265 emit dataReceived(name.c_str(), buf, len, true);
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700266#ifdef __DEBUG
267 std::cout <<"<<< " << name << " fetched" << std::endl;
268#endif
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700269}
270
271void
Zhenkai Zhubb198112012-09-27 11:31:42 -0700272ChatDialog::processDataNoShowWrapper(std::string name, const char *buf, size_t len)
273{
274 emit dataReceived(name.c_str(), buf, len, false);
275}
276
277void
278ChatDialog::processData(QString name, const char *buf, size_t len, bool show)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700279{
280 SyncDemo::ChatMessage msg;
281 if (!msg.ParseFromArray(buf, len))
282 {
Zhenkai Zhubb198112012-09-27 11:31:42 -0700283 std::cerr << "Errrrr.. Can not parse msg with name: " << name.toStdString() << ". what is happening?" << std::endl;
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700284 }
285
Zhenkai Zhu10ccb5a2012-06-04 21:55:14 -0700286 // display msg received from network
287 // we have to do so; this function is called by ccnd thread
288 // so if we call appendMsg directly
289 // Qt crash as "QObject: Cannot create children for a parent that is in a different thread"
290 // the "cannonical" way to is use signal-slot
Zhenkai Zhubb198112012-09-27 11:31:42 -0700291 if (show)
292 {
293 appendMessage(msg);
294 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700295
296 // update the tree view
Zhenkai Zhu097bfe72012-06-05 14:30:17 -0700297 std::string stdStrName = name.toStdString();
298 std::string stdStrNameWithoutSeq = stdStrName.substr(0, stdStrName.find_last_of('/'));
299 std::string prefix = stdStrNameWithoutSeq.substr(0, stdStrNameWithoutSeq.find_last_of('/'));
300#ifdef __DEBUG
301 std::cout <<"<<< updating scene for" << prefix << ": " << msg.from() << std::endl;
302#endif
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700303 {
304 boost::mutex::scoped_lock lock(m_sceneMutex);
305 m_scene->msgReceived(prefix.c_str(), msg.from().c_str());
306 }
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700307 fitView();
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700308}
309
310void
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700311ChatDialog::processRemoveWrapper(std::string prefix)
312{
313 emit removeReceived(prefix.c_str());
314}
315
316void
317ChatDialog::processRemove(QString prefix)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700318{
Zhenkai Zhu591e8c32012-09-26 11:57:50 -0700319#ifdef __DEBUG
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700320 std::cout << "<<< remove node for prefix" << prefix.toStdString() << std::endl;
Zhenkai Zhu591e8c32012-09-26 11:57:50 -0700321#endif
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700322 bool removed = m_scene->removeNode(prefix);
Zhenkai Zhu591e8c32012-09-26 11:57:50 -0700323 if (removed)
324 {
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700325 boost::mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu591e8c32012-09-26 11:57:50 -0700326 m_scene->plot(m_sock->getRootDigest().c_str());
327 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700328}
329
330void
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700331ChatDialog::formChatMessage(const QString &text, SyncDemo::ChatMessage &msg) {
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700332 msg.set_from(m_user.getNick().toStdString());
333 msg.set_to(m_user.getChatroom().toStdString());
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700334 msg.set_data(text.toStdString());
335 time_t seconds = time(NULL);
336 msg.set_timestamp(seconds);
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700337 msg.set_type(SyncDemo::ChatMessage::CHAT);
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700338}
339
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700340void
341ChatDialog::formHelloMessage(SyncDemo::ChatMessage &msg)
342{
343 msg.set_from(m_user.getNick().toStdString());
344 msg.set_to(m_user.getChatroom().toStdString());
345 time_t seconds = time(NULL);
346 msg.set_timestamp(seconds);
347 msg.set_type(SyncDemo::ChatMessage::HELLO);
348}
349
Zhenkai Zhu59245aa2012-09-26 16:07:04 -0700350static std::string chars("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM0123456789");
351
352QString
353ChatDialog::getRandomString()
354{
355 std::string randStr;
356 boost::random::random_device rng;
357 boost::random::uniform_int_distribution<> index_dist(0, chars.size() - 1);
358 for (int i = 0; i < 10; i ++)
359 {
360 randStr += chars[index_dist(rng)];
361 }
362 return randStr.c_str();
363}
364
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700365bool
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700366ChatDialog::readSettings()
367{
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700368#ifndef __DEBUG
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700369 QSettings s(ORGANIZATION, APPLICATION);
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700370 QString nick = s.value("nick", "").toString();
371 QString chatroom = s.value("chatroom", "").toString();
372 QString prefix = s.value("prefix", "").toString();
373 if (nick == "" || chatroom == "" || prefix == "") {
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700374 QTimer::singleShot(500, this, SLOT(buttonPressed()));
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700375 return false;
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700376 }
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700377 else {
378 m_user.setNick(nick);
379 m_user.setChatroom(chatroom);
380 m_user.setPrefix(prefix);
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700381 return true;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700382 }
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700383#else
384 QTimer::singleShot(500, this, SLOT(buttonPressed()));
385 return false;
386#endif
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700387}
388
389void
390ChatDialog::writeSettings()
391{
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700392#ifndef __DEBUG
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700393 QSettings s(ORGANIZATION, APPLICATION);
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700394 s.setValue("nick", m_user.getNick());
395 s.setValue("chatroom", m_user.getChatroom());
396 s.setValue("prefix", m_user.getPrefix());
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700397#endif
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700398}
399
400void
401ChatDialog::updateLabels()
402{
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700403 QString settingDisp = QString("<User: %1>, <Chatroom: %2>").arg(m_user.getNick()).arg(m_user.getChatroom());
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700404 infoLabel->setText(settingDisp);
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700405 QString prefixDisp = QString("<Prefix: %1>").arg(m_user.getPrefix());
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700406 prefixLabel->setText(prefixDisp);
407}
408
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700409void
410ChatDialog::returnPressed()
411{
412 QString text = lineEdit->text();
413 if (text.isEmpty())
414 return;
415
Zhenkai Zhub6338822012-05-31 13:27:24 -0700416 lineEdit->clear();
417
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700418 SyncDemo::ChatMessage msg;
419 formChatMessage(text, msg);
420
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700421 appendMessage(msg);
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700422
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700423 sendMsg(msg);
424
425 fitView();
426}
427
428void
429ChatDialog::sendMsg(SyncDemo::ChatMessage &msg)
430{
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700431 // send msg
432 size_t size = msg.ByteSize();
433 char *buf = new char[size];
434 msg.SerializeToArray(buf, size);
435 if (!msg.IsInitialized())
436 {
437 std::cerr << "Errrrr.. msg was not probally initialized "<<__FILE__ <<":"<<__LINE__<<". what is happening?" << std::endl;
438 abort();
439 }
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700440 m_sock->publishRaw(m_user.getPrefix().toStdString(), m_session, buf, size, FRESHNESS);
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700441
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700442 delete buf;
443
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700444 m_lastMsgTime = time(NULL);
445
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700446 int nextSequence = m_sock->getNextSeq(m_user.getPrefix().toStdString(), m_session);
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700447 Sync::MissingDataInfo mdi = {m_user.getPrefix().toStdString(), Sync::SeqNo(0), Sync::SeqNo(nextSequence - 1)};
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700448 std::vector<Sync::MissingDataInfo> v;
449 v.push_back(mdi);
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700450 {
451 boost::mutex::scoped_lock lock(m_sceneMutex);
452 m_scene->processUpdate(v, m_sock->getRootDigest().c_str());
453 m_scene->msgReceived(m_user.getPrefix(), m_user.getNick());
454 }
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700455}
456
457void
458ChatDialog::sendHello()
459{
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700460 time_t now = time(NULL);
461 int elapsed = now - m_lastMsgTime;
Zhenkai Zhuee5c90f2012-09-27 14:05:41 -0700462 if (elapsed >= m_randomizedInterval / 1000)
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700463 {
464 SyncDemo::ChatMessage msg;
465 formHelloMessage(msg);
466 sendMsg(msg);
Zhenkai Zhuee5c90f2012-09-27 14:05:41 -0700467 QTimer::singleShot(m_randomizedInterval, this, SLOT(sendHello()));
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700468 }
469 else
470 {
Zhenkai Zhuee5c90f2012-09-27 14:05:41 -0700471 QTimer::singleShot((m_randomizedInterval - elapsed * 1000), this, SLOT(sendHello()));
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700472 }
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700473}
474
475void
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700476ChatDialog::buttonPressed()
477{
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700478 SettingDialog dialog(this, m_user.getNick(), m_user.getChatroom(), m_user.getPrefix());
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700479 connect(&dialog, SIGNAL(updated(QString, QString, QString)), this, SLOT(settingUpdated(QString, QString, QString)));
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700480 dialog.exec();
Zhenkai Zhue837f792012-06-05 20:47:54 -0700481 QTimer::singleShot(100, this, SLOT(checkSetting()));
482}
483
484void
485ChatDialog::checkSetting()
486{
487 if (m_user.getPrefix().isEmpty() || m_user.getNick().isEmpty() || m_user.getChatroom().isEmpty())
488 {
489 buttonPressed();
490 }
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -0700491}
Zhenkai Zhue08afe02012-05-31 15:49:07 -0700492
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700493void
494ChatDialog::settingUpdated(QString nick, QString chatroom, QString prefix)
495{
496 bool needWrite = false;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700497 if (!nick.isEmpty() && nick != m_user.getNick()) {
498 m_user.setNick(nick);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700499 needWrite = true;
500 }
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700501 if (!prefix.isEmpty() && prefix != m_user.getPrefix()) {
Zhenkai Zhu59245aa2012-09-26 16:07:04 -0700502 m_user.setPrefix(prefix + "/" + getRandomString());
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700503 needWrite = true;
504 // TODO: set the previous prefix as left?
505 }
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700506 if (!chatroom.isEmpty() && chatroom != m_user.getChatroom()) {
507 m_user.setChatroom(chatroom);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700508 needWrite = true;
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700509
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700510 {
511 boost::mutex::scoped_lock lock(m_sceneMutex);
512 m_scene->clearAll();
513 m_scene->plot("Empty");
514 }
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700515 // TODO: perhaps need to do a lot. e.g. use a new SyncAppSokcet
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700516 if (m_sock != NULL)
517 {
518 delete m_sock;
519 m_sock = NULL;
520 }
521 std::string syncPrefix = BROADCAST_PREFIX_FOR_SYNC_DEMO;
522 syncPrefix += "/";
523 syncPrefix += m_user.getChatroom().toStdString();
Zhenkai Zhua4fb1242012-06-05 20:26:05 -0700524 try
525 {
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700526 m_sock = new Sync::SyncAppSocket(syncPrefix, bind(&ChatDialog::processTreeUpdateWrapper, this, _1, _2), bind(&ChatDialog::processRemoveWrapper, this, _1));
527 sendHello();
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700528 m_timer->start(FRESHNESS * 2000);
Zhenkai Zhua4fb1242012-06-05 20:26:05 -0700529 }
530 catch (Sync::CcnxOperationException ex)
531 {
532 QMessageBox::critical(this, tr("Sync-Demo"), tr("Canno connect to ccnd.\n Have you started your ccnd?"), QMessageBox::Ok);
533 std::exit(1);
534 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700535
536 fitView();
537
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700538 }
539 if (needWrite) {
540 writeSettings();
541 updateLabels();
542 }
543}
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700544
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700545void
546ChatDialog::iconActivated(QSystemTrayIcon::ActivationReason reason)
547{
548 switch (reason)
549 {
550 case QSystemTrayIcon::Trigger:
551 case QSystemTrayIcon::DoubleClick:
552 break;
553 case QSystemTrayIcon::MiddleClick:
554 // showMessage();
555 break;
556 default:;
557 }
558}
559
560void
561ChatDialog::showMessage(QString from, QString data)
562{
563 // std::cout <<"Showing Message: " << from.toStdString() << ": " << data.toStdString() << std::endl;
564 if (!isActiveWindow())
565 {
566 trayIcon->showMessage(QString("Chatroom %1 has a new message").arg(m_user.getChatroom()), QString("<%1>: %2").arg(from).arg(data), QSystemTrayIcon::Information, 20000);
567 trayIcon->setIcon(QIcon(":/images/note.png"));
568 }
569}
570
571void
572ChatDialog::messageClicked()
573{
574 this->showMaximized();
575}
576
577void
578ChatDialog::createActions()
579{
580 minimizeAction = new QAction(tr("Mi&nimize"), this);
581 connect(minimizeAction, SIGNAL(triggered()), this, SLOT(hide()));
582
583 maximizeAction = new QAction(tr("Ma&ximize"), this);
584 connect(maximizeAction, SIGNAL(triggered()), this, SLOT(showMaximized()));
585
586 restoreAction = new QAction(tr("&Restore"), this);
587 connect(restoreAction, SIGNAL(triggered()), this, SLOT(showNormal()));
588
589 quitAction = new QAction(tr("Quit"), this);
590 connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
591}
592
593void
594ChatDialog::createTrayIcon()
595{
596 trayIconMenu = new QMenu(this);
597 trayIconMenu->addAction(minimizeAction);
598 trayIconMenu->addAction(maximizeAction);
599 trayIconMenu->addAction(restoreAction);
600 trayIconMenu->addSeparator();
601 trayIconMenu->addAction(quitAction);
602
603 trayIcon = new QSystemTrayIcon(this);
604 trayIcon->setContextMenu(trayIconMenu);
605
606 QIcon icon(":/images/icon_small.png");
607 trayIcon->setIcon(icon);
608 setWindowIcon(icon);
609 trayIcon->setToolTip("Sync-Demo System Tray Icon");
610 trayIcon->setVisible(true);
611}
612
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700613void
614ChatDialog::resizeEvent(QResizeEvent *e)
615{
616 fitView();
617}
618
619void
620ChatDialog::showEvent(QShowEvent *e)
621{
622 fitView();
623}
624
625void
626ChatDialog::fitView()
627{
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700628 boost::mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700629 QRectF rect = m_scene->itemsBoundingRect();
630 m_scene->setSceneRect(rect);
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700631 treeViewer->fitInView(m_scene->itemsBoundingRect(), Qt::KeepAspectRatio);
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700632}