blob: 89e1710d4ad636482be33f58fb806ded804c91fc [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 Zhu6082ede2012-09-27 17:28:46 -070041 m_rosterModel = new QStringListModel(this);
42 listView->setModel(m_rosterModel);
43
Zhenkai Zhu86df7412012-09-27 16:30:20 -070044 createActions();
45 createTrayIcon();
46 m_timer = new QTimer(this);
47 connect(lineEdit, SIGNAL(returnPressed()), this, SLOT(returnPressed()));
48 connect(setButton, SIGNAL(pressed()), this, SLOT(buttonPressed()));
49 connect(this, SIGNAL(dataReceived(QString, const char *, size_t, bool)), this, SLOT(processData(QString, const char *, size_t, bool)));
50 connect(this, SIGNAL(treeUpdated(const std::vector<Sync::MissingDataInfo>)), this, SLOT(processTreeUpdate(const std::vector<Sync::MissingDataInfo>)));
51 connect(this, SIGNAL(removeReceived(QString)), this, SLOT(processRemove(QString)));
52 connect(m_timer, SIGNAL(timeout()), this, SLOT(replot()));
53 connect(m_scene, SIGNAL(replot()), this, SLOT(replot()));
54 connect(trayIcon, SIGNAL(messageClicked()), this, SLOT(showNormal()));
55 connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
Zhenkai Zhu6082ede2012-09-27 17:28:46 -070056 connect(m_scene, SIGNAL(rosterChanged()), this, SLOT(updateRosterList()));
Zhenkai Zhu86df7412012-09-27 16:30:20 -070057
Zhenkai Zhu82a62752012-06-04 17:11:04 -070058 // create sync socket
59 if(!m_user.getChatroom().isEmpty()) {
60 std::string syncPrefix = BROADCAST_PREFIX_FOR_SYNC_DEMO;
61 syncPrefix += "/";
62 syncPrefix += m_user.getChatroom().toStdString();
Zhenkai Zhua4fb1242012-06-05 20:26:05 -070063 try
64 {
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -070065 m_sock = new Sync::SyncAppSocket(syncPrefix, bind(&ChatDialog::processTreeUpdateWrapper, this, _1, _2), bind(&ChatDialog::processRemoveWrapper, this, _1));
66 sendHello();
Zhenkai Zhu86df7412012-09-27 16:30:20 -070067 m_timer->start(FRESHNESS * 2000);
Zhenkai Zhua4fb1242012-06-05 20:26:05 -070068 }
69 catch (Sync::CcnxOperationException ex)
70 {
71 QMessageBox::critical(this, tr("Sync-Demo"), tr("Canno connect to ccnd.\n Have you started your ccnd?"), QMessageBox::Ok);
72 std::exit(1);
73 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -070074 }
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -070075
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -070076//testDraw();
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -070077}
78
Zhenkai Zhu82a62752012-06-04 17:11:04 -070079ChatDialog::~ChatDialog()
80{
81 if (m_sock != NULL)
82 {
Zhenkai Zhu591e8c32012-09-26 11:57:50 -070083 m_sock->remove(m_user.getPrefix().toStdString());
Zhenkai Zhu82a62752012-06-04 17:11:04 -070084 delete m_sock;
85 m_sock = NULL;
86 }
87}
88
Zhenkai Zhu86df7412012-09-27 16:30:20 -070089void
90ChatDialog::replot()
91{
92 boost::mutex::scoped_lock lock(m_sceneMutex);
93 m_scene->plot(m_sock->getRootDigest().c_str());
94}
95
Zhenkai Zhu6082ede2012-09-27 17:28:46 -070096void
97ChatDialog::updateRosterList()
98{
99 boost::mutex::scoped_lock lock(m_sceneMutex);
100 QStringList rosterList = m_scene->getRosterList();
101 m_rosterModel->setStringList(rosterList);
102}
103
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700104void
105ChatDialog::setVisible(bool visible)
106{
107 minimizeAction->setEnabled(visible);
108 maximizeAction->setEnabled(!isMaximized());
109 restoreAction->setEnabled(isMaximized() || !visible);
110 QDialog::setVisible(visible);
111}
112
113void
114ChatDialog::closeEvent(QCloseEvent *e)
115{
116 if (trayIcon->isVisible())
117 {
118 QMessageBox::information(this, tr("Sync-Demo"),
119 tr("The program will keep running in the "
120 "system tray. To terminate the program"
121 "choose <b>Quit</b> in the context memu"
122 "of the system tray entry."));
123 hide();
124 e->ignore();
125 }
126}
127
128void
129ChatDialog::changeEvent(QEvent *e)
130{
131 switch(e->type())
132 {
133 case QEvent::ActivationChange:
134 if (isActiveWindow())
135 {
136 trayIcon->setIcon(QIcon(":/images/icon_small.png"));
137 }
138 break;
139 default:
140 break;
141 }
142}
143
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700144void
Zhenkai Zhu10ccb5a2012-06-04 21:55:14 -0700145ChatDialog::appendMessage(const SyncDemo::ChatMessage msg)
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700146{
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700147 boost::mutex::scoped_lock lock(m_msgMutex);
Zhenkai Zhub6338822012-05-31 13:27:24 -0700148
149 if (msg.type() != SyncDemo::ChatMessage::CHAT) {
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700150 return;
Zhenkai Zhub6338822012-05-31 13:27:24 -0700151 }
152
153 if (!msg.has_data()) {
154 return;
155 }
156
157 if (msg.from().empty() || msg.data().empty()) {
158 return;
159 }
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700160
Zhenkai Zhub98e6022012-09-27 13:48:23 -0700161 if (!msg.has_timestamp())
162 {
163 return;
164 }
165
166 QTextCharFormat nickFormat;
167 nickFormat.setForeground(Qt::darkGreen);
168 nickFormat.setFontWeight(QFont::Bold);
169 nickFormat.setFontUnderline(true);
170 nickFormat.setUnderlineColor(Qt::gray);
171 QTextCharFormat timeFormat;
172 timeFormat.setForeground(Qt::gray);
173 timeFormat.setFontUnderline(true);
174 timeFormat.setUnderlineColor(Qt::gray);
175
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700176 QTextCursor cursor(textEdit->textCursor());
177 cursor.movePosition(QTextCursor::End);
178 QTextTableFormat tableFormat;
179 tableFormat.setBorder(0);
180 QTextTable *table = cursor.insertTable(1, 2, tableFormat);
Zhenkai Zhub98e6022012-09-27 13:48:23 -0700181 QString from = QString("%1 ").arg(msg.from().c_str());
182 QTextTableCell fromCell = table->cellAt(0, 0);
183 fromCell.setFormat(nickFormat);
184 fromCell.firstCursorPosition().insertText(from);
185 QTextTableCell timeCell = table->cellAt(0, 1);
186 timeCell.setFormat(timeFormat);
187 time_t timestamp = msg.timestamp();
188 struct tm *tm_time = localtime(&timestamp);
189 int hour = tm_time->tm_hour;
190 QString amOrPM;
191 if (hour > 12)
192 {
193 hour -= 12;
194 amOrPM = "PM";
195 }
196 else
197 {
198 amOrPM = "AM";
199 if (hour == 0)
200 {
201 hour = 12;
202 }
203 }
204
205 char textTime[12];
206 sprintf(textTime, "%d:%02d:%02d %s", hour, tm_time->tm_min, tm_time->tm_sec, amOrPM.toStdString().c_str());
207 timeCell.firstCursorPosition().insertText(textTime);
208
209
210 QTextCursor nextCursor(textEdit->textCursor());
211 table = nextCursor.insertTable(1, 1, tableFormat);
212 table->cellAt(0, 0).firstCursorPosition().insertText(msg.data().c_str());
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700213 QScrollBar *bar = textEdit->verticalScrollBar();
214 bar->setValue(bar->maximum());
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700215 showMessage(from, msg.data().c_str());
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700216}
217
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700218void
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700219ChatDialog::processTreeUpdateWrapper(const std::vector<Sync::MissingDataInfo> v, Sync::SyncAppSocket *sock)
220{
221 emit treeUpdated(v);
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700222#ifdef __DEBUG
223 std::cout << "<<< Tree update signal emitted" << std::endl;
224#endif
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700225}
226
227void
228ChatDialog::processTreeUpdate(const std::vector<Sync::MissingDataInfo> v)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700229{
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700230#ifdef __DEBUG
231 std::cout << "<<< processing Tree Update" << std::endl;
232#endif
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700233 if (v.empty())
234 {
235 return;
236 }
237
238 // reflect the changes on digest tree
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700239 {
240 boost::mutex::scoped_lock lock(m_sceneMutex);
241 m_scene->processUpdate(v, m_sock->getRootDigest().c_str());
242 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700243
244 int n = v.size();
245 int totalMissingPackets = 0;
246 for (int i = 0; i < n; i++)
247 {
248 totalMissingPackets += v[i].high.getSeq() - v[i].low.getSeq() + 1;
249 }
250
Zhenkai Zhubb198112012-09-27 11:31:42 -0700251 for (int i = 0; i < n; i++)
252 {
253 if (totalMissingPackets < 4)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700254 {
255 for (Sync::SeqNo seq = v[i].low; seq <= v[i].high; ++seq)
256 {
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700257 m_sock->fetchRaw(v[i].prefix, seq, bind(&ChatDialog::processDataWrapper, this, _1, _2, _3), 2);
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700258#ifdef __DEBUG
259 std::cout << "<<< Fetching " << v[i].prefix << "/" <<seq.getSession() <<"/" << seq.getSeq() << std::endl;
260#endif
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700261 }
262 }
Zhenkai Zhubb198112012-09-27 11:31:42 -0700263 else
264 {
265 m_sock->fetchRaw(v[i].prefix, v[i].high, bind(&ChatDialog::processDataNoShowWrapper, this, _1, _2, _3), 2);
266 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700267 }
268
269 // adjust the view
270 fitView();
271
272}
273
274void
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700275ChatDialog::processDataWrapper(std::string name, const char *buf, size_t len)
276{
Zhenkai Zhubb198112012-09-27 11:31:42 -0700277 emit dataReceived(name.c_str(), buf, len, true);
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700278#ifdef __DEBUG
279 std::cout <<"<<< " << name << " fetched" << std::endl;
280#endif
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700281}
282
283void
Zhenkai Zhubb198112012-09-27 11:31:42 -0700284ChatDialog::processDataNoShowWrapper(std::string name, const char *buf, size_t len)
285{
286 emit dataReceived(name.c_str(), buf, len, false);
287}
288
289void
290ChatDialog::processData(QString name, const char *buf, size_t len, bool show)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700291{
292 SyncDemo::ChatMessage msg;
293 if (!msg.ParseFromArray(buf, len))
294 {
Zhenkai Zhubb198112012-09-27 11:31:42 -0700295 std::cerr << "Errrrr.. Can not parse msg with name: " << name.toStdString() << ". what is happening?" << std::endl;
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700296 }
297
Zhenkai Zhu10ccb5a2012-06-04 21:55:14 -0700298 // display msg received from network
299 // we have to do so; this function is called by ccnd thread
300 // so if we call appendMsg directly
301 // Qt crash as "QObject: Cannot create children for a parent that is in a different thread"
302 // the "cannonical" way to is use signal-slot
Zhenkai Zhubb198112012-09-27 11:31:42 -0700303 if (show)
304 {
305 appendMessage(msg);
306 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700307
308 // update the tree view
Zhenkai Zhu097bfe72012-06-05 14:30:17 -0700309 std::string stdStrName = name.toStdString();
310 std::string stdStrNameWithoutSeq = stdStrName.substr(0, stdStrName.find_last_of('/'));
311 std::string prefix = stdStrNameWithoutSeq.substr(0, stdStrNameWithoutSeq.find_last_of('/'));
312#ifdef __DEBUG
313 std::cout <<"<<< updating scene for" << prefix << ": " << msg.from() << std::endl;
314#endif
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700315 {
316 boost::mutex::scoped_lock lock(m_sceneMutex);
317 m_scene->msgReceived(prefix.c_str(), msg.from().c_str());
318 }
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700319 fitView();
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700320}
321
322void
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700323ChatDialog::processRemoveWrapper(std::string prefix)
324{
325 emit removeReceived(prefix.c_str());
326}
327
328void
329ChatDialog::processRemove(QString prefix)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700330{
Zhenkai Zhu591e8c32012-09-26 11:57:50 -0700331#ifdef __DEBUG
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700332 std::cout << "<<< remove node for prefix" << prefix.toStdString() << std::endl;
Zhenkai Zhu591e8c32012-09-26 11:57:50 -0700333#endif
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700334 bool removed = m_scene->removeNode(prefix);
Zhenkai Zhu591e8c32012-09-26 11:57:50 -0700335 if (removed)
336 {
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700337 boost::mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu591e8c32012-09-26 11:57:50 -0700338 m_scene->plot(m_sock->getRootDigest().c_str());
339 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700340}
341
342void
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700343ChatDialog::formChatMessage(const QString &text, SyncDemo::ChatMessage &msg) {
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700344 msg.set_from(m_user.getNick().toStdString());
345 msg.set_to(m_user.getChatroom().toStdString());
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700346 msg.set_data(text.toStdString());
347 time_t seconds = time(NULL);
348 msg.set_timestamp(seconds);
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700349 msg.set_type(SyncDemo::ChatMessage::CHAT);
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700350}
351
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700352void
353ChatDialog::formHelloMessage(SyncDemo::ChatMessage &msg)
354{
355 msg.set_from(m_user.getNick().toStdString());
356 msg.set_to(m_user.getChatroom().toStdString());
357 time_t seconds = time(NULL);
358 msg.set_timestamp(seconds);
359 msg.set_type(SyncDemo::ChatMessage::HELLO);
360}
361
Zhenkai Zhu59245aa2012-09-26 16:07:04 -0700362static std::string chars("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM0123456789");
363
364QString
365ChatDialog::getRandomString()
366{
367 std::string randStr;
368 boost::random::random_device rng;
369 boost::random::uniform_int_distribution<> index_dist(0, chars.size() - 1);
370 for (int i = 0; i < 10; i ++)
371 {
372 randStr += chars[index_dist(rng)];
373 }
374 return randStr.c_str();
375}
376
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700377bool
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700378ChatDialog::readSettings()
379{
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700380#ifndef __DEBUG
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700381 QSettings s(ORGANIZATION, APPLICATION);
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700382 QString nick = s.value("nick", "").toString();
383 QString chatroom = s.value("chatroom", "").toString();
384 QString prefix = s.value("prefix", "").toString();
385 if (nick == "" || chatroom == "" || prefix == "") {
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700386 QTimer::singleShot(500, this, SLOT(buttonPressed()));
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700387 return false;
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700388 }
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700389 else {
390 m_user.setNick(nick);
391 m_user.setChatroom(chatroom);
392 m_user.setPrefix(prefix);
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700393 return true;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700394 }
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700395#else
396 QTimer::singleShot(500, this, SLOT(buttonPressed()));
397 return false;
398#endif
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700399}
400
401void
402ChatDialog::writeSettings()
403{
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700404#ifndef __DEBUG
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700405 QSettings s(ORGANIZATION, APPLICATION);
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700406 s.setValue("nick", m_user.getNick());
407 s.setValue("chatroom", m_user.getChatroom());
408 s.setValue("prefix", m_user.getPrefix());
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700409#endif
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700410}
411
412void
413ChatDialog::updateLabels()
414{
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700415 QString settingDisp = QString("<User: %1>, <Chatroom: %2>").arg(m_user.getNick()).arg(m_user.getChatroom());
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700416 infoLabel->setText(settingDisp);
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700417 QString prefixDisp = QString("<Prefix: %1>").arg(m_user.getPrefix());
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700418 prefixLabel->setText(prefixDisp);
419}
420
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700421void
422ChatDialog::returnPressed()
423{
424 QString text = lineEdit->text();
425 if (text.isEmpty())
426 return;
427
Zhenkai Zhub6338822012-05-31 13:27:24 -0700428 lineEdit->clear();
429
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700430 SyncDemo::ChatMessage msg;
431 formChatMessage(text, msg);
432
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700433 appendMessage(msg);
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700434
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700435 sendMsg(msg);
436
437 fitView();
438}
439
440void
441ChatDialog::sendMsg(SyncDemo::ChatMessage &msg)
442{
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700443 // send msg
444 size_t size = msg.ByteSize();
445 char *buf = new char[size];
446 msg.SerializeToArray(buf, size);
447 if (!msg.IsInitialized())
448 {
449 std::cerr << "Errrrr.. msg was not probally initialized "<<__FILE__ <<":"<<__LINE__<<". what is happening?" << std::endl;
450 abort();
451 }
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700452 m_sock->publishRaw(m_user.getPrefix().toStdString(), m_session, buf, size, FRESHNESS);
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700453
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700454 delete buf;
455
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700456 m_lastMsgTime = time(NULL);
457
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700458 int nextSequence = m_sock->getNextSeq(m_user.getPrefix().toStdString(), m_session);
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700459 Sync::MissingDataInfo mdi = {m_user.getPrefix().toStdString(), Sync::SeqNo(0), Sync::SeqNo(nextSequence - 1)};
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700460 std::vector<Sync::MissingDataInfo> v;
461 v.push_back(mdi);
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700462 {
463 boost::mutex::scoped_lock lock(m_sceneMutex);
464 m_scene->processUpdate(v, m_sock->getRootDigest().c_str());
465 m_scene->msgReceived(m_user.getPrefix(), m_user.getNick());
466 }
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700467}
468
469void
470ChatDialog::sendHello()
471{
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700472 time_t now = time(NULL);
473 int elapsed = now - m_lastMsgTime;
Zhenkai Zhuee5c90f2012-09-27 14:05:41 -0700474 if (elapsed >= m_randomizedInterval / 1000)
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700475 {
476 SyncDemo::ChatMessage msg;
477 formHelloMessage(msg);
478 sendMsg(msg);
Zhenkai Zhuee5c90f2012-09-27 14:05:41 -0700479 QTimer::singleShot(m_randomizedInterval, this, SLOT(sendHello()));
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700480 }
481 else
482 {
Zhenkai Zhuee5c90f2012-09-27 14:05:41 -0700483 QTimer::singleShot((m_randomizedInterval - elapsed * 1000), this, SLOT(sendHello()));
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700484 }
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700485}
486
487void
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700488ChatDialog::buttonPressed()
489{
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700490 SettingDialog dialog(this, m_user.getNick(), m_user.getChatroom(), m_user.getPrefix());
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700491 connect(&dialog, SIGNAL(updated(QString, QString, QString)), this, SLOT(settingUpdated(QString, QString, QString)));
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700492 dialog.exec();
Zhenkai Zhue837f792012-06-05 20:47:54 -0700493 QTimer::singleShot(100, this, SLOT(checkSetting()));
494}
495
496void
497ChatDialog::checkSetting()
498{
499 if (m_user.getPrefix().isEmpty() || m_user.getNick().isEmpty() || m_user.getChatroom().isEmpty())
500 {
501 buttonPressed();
502 }
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -0700503}
Zhenkai Zhue08afe02012-05-31 15:49:07 -0700504
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700505void
506ChatDialog::settingUpdated(QString nick, QString chatroom, QString prefix)
507{
508 bool needWrite = false;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700509 if (!nick.isEmpty() && nick != m_user.getNick()) {
510 m_user.setNick(nick);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700511 needWrite = true;
512 }
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700513 if (!prefix.isEmpty() && prefix != m_user.getPrefix()) {
Zhenkai Zhu59245aa2012-09-26 16:07:04 -0700514 m_user.setPrefix(prefix + "/" + getRandomString());
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700515 needWrite = true;
516 // TODO: set the previous prefix as left?
517 }
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700518 if (!chatroom.isEmpty() && chatroom != m_user.getChatroom()) {
519 m_user.setChatroom(chatroom);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700520 needWrite = true;
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700521
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700522 {
523 boost::mutex::scoped_lock lock(m_sceneMutex);
524 m_scene->clearAll();
525 m_scene->plot("Empty");
526 }
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700527 // TODO: perhaps need to do a lot. e.g. use a new SyncAppSokcet
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700528 if (m_sock != NULL)
529 {
530 delete m_sock;
531 m_sock = NULL;
532 }
533 std::string syncPrefix = BROADCAST_PREFIX_FOR_SYNC_DEMO;
534 syncPrefix += "/";
535 syncPrefix += m_user.getChatroom().toStdString();
Zhenkai Zhua4fb1242012-06-05 20:26:05 -0700536 try
537 {
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700538 m_sock = new Sync::SyncAppSocket(syncPrefix, bind(&ChatDialog::processTreeUpdateWrapper, this, _1, _2), bind(&ChatDialog::processRemoveWrapper, this, _1));
539 sendHello();
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700540 m_timer->start(FRESHNESS * 2000);
Zhenkai Zhua4fb1242012-06-05 20:26:05 -0700541 }
542 catch (Sync::CcnxOperationException ex)
543 {
544 QMessageBox::critical(this, tr("Sync-Demo"), tr("Canno connect to ccnd.\n Have you started your ccnd?"), QMessageBox::Ok);
545 std::exit(1);
546 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700547
548 fitView();
549
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700550 }
551 if (needWrite) {
552 writeSettings();
553 updateLabels();
554 }
555}
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700556
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700557void
558ChatDialog::iconActivated(QSystemTrayIcon::ActivationReason reason)
559{
560 switch (reason)
561 {
562 case QSystemTrayIcon::Trigger:
563 case QSystemTrayIcon::DoubleClick:
564 break;
565 case QSystemTrayIcon::MiddleClick:
566 // showMessage();
567 break;
568 default:;
569 }
570}
571
572void
573ChatDialog::showMessage(QString from, QString data)
574{
575 // std::cout <<"Showing Message: " << from.toStdString() << ": " << data.toStdString() << std::endl;
576 if (!isActiveWindow())
577 {
578 trayIcon->showMessage(QString("Chatroom %1 has a new message").arg(m_user.getChatroom()), QString("<%1>: %2").arg(from).arg(data), QSystemTrayIcon::Information, 20000);
579 trayIcon->setIcon(QIcon(":/images/note.png"));
580 }
581}
582
583void
584ChatDialog::messageClicked()
585{
586 this->showMaximized();
587}
588
589void
590ChatDialog::createActions()
591{
592 minimizeAction = new QAction(tr("Mi&nimize"), this);
593 connect(minimizeAction, SIGNAL(triggered()), this, SLOT(hide()));
594
595 maximizeAction = new QAction(tr("Ma&ximize"), this);
596 connect(maximizeAction, SIGNAL(triggered()), this, SLOT(showMaximized()));
597
598 restoreAction = new QAction(tr("&Restore"), this);
599 connect(restoreAction, SIGNAL(triggered()), this, SLOT(showNormal()));
600
601 quitAction = new QAction(tr("Quit"), this);
602 connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
603}
604
605void
606ChatDialog::createTrayIcon()
607{
608 trayIconMenu = new QMenu(this);
609 trayIconMenu->addAction(minimizeAction);
610 trayIconMenu->addAction(maximizeAction);
611 trayIconMenu->addAction(restoreAction);
612 trayIconMenu->addSeparator();
613 trayIconMenu->addAction(quitAction);
614
615 trayIcon = new QSystemTrayIcon(this);
616 trayIcon->setContextMenu(trayIconMenu);
617
618 QIcon icon(":/images/icon_small.png");
619 trayIcon->setIcon(icon);
620 setWindowIcon(icon);
621 trayIcon->setToolTip("Sync-Demo System Tray Icon");
622 trayIcon->setVisible(true);
623}
624
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700625void
626ChatDialog::resizeEvent(QResizeEvent *e)
627{
628 fitView();
629}
630
631void
632ChatDialog::showEvent(QShowEvent *e)
633{
634 fitView();
635}
636
637void
638ChatDialog::fitView()
639{
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700640 boost::mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700641 QRectF rect = m_scene->itemsBoundingRect();
642 m_scene->setSceneRect(rect);
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700643 treeViewer->fitInView(m_scene->itemsBoundingRect(), Qt::KeepAspectRatio);
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700644}