blob: fdde9dfc92c6bd891266549faaf9b66d6e4ccac5 [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 Zhu6c4fc112012-10-07 17:07:43 -070011#include <boost/lexical_cast.hpp>
Zhenkai Zhu6bda0bd2012-10-06 23:50:39 -070012#include <stdio.h>
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -070013
Zhenkai Zhu0b3fa332012-09-27 21:58:43 -070014#define BROADCAST_PREFIX_FOR_SYNC_DEMO "/ndn/broadcast/chronos"
Zhenkai Zhu6bda0bd2012-10-06 23:50:39 -070015#define LOCAL_PREFIX_QUERY "/local/ndn/prefix"
16#define DEFAULT_LOCAL_PREFIX "/private/local"
Zhenkai Zhu756666a2012-10-07 00:24:35 -070017#define CCN_EXEC "/usr/local/bin/ccnpeek"
Zhenkai Zhu82a62752012-06-04 17:11:04 -070018
Zhenkai Zhuc61dbc22012-10-08 11:36:37 -070019static const int HELLO_INTERVAL = FRESHNESS * 3 / 4; // seconds
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -070020
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -070021ChatDialog::ChatDialog(QWidget *parent)
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -070022 : QDialog(parent), m_sock(NULL), m_lastMsgTime(0), m_historyInitialized(false), m_joined(false)
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -070023{
Zhenkai Zhu10ccb5a2012-06-04 21:55:14 -070024 // have to register this, otherwise
25 // the signal-slot system won't recognize this type
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -070026 qRegisterMetaType<std::vector<Sync::MissingDataInfo> >("std::vector<Sync::MissingDataInfo>");
27 qRegisterMetaType<size_t>("size_t");
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -070028 setupUi(this);
Zhenkai Zhu82a62752012-06-04 17:11:04 -070029 m_session = time(NULL);
Zhenkai Zhu716fe852012-10-08 18:27:55 -070030 m_scene = new DigestTreeScene(this);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -070031
32 readSettings();
Zhenkai Zhu82a62752012-06-04 17:11:04 -070033
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -070034 updateLabels();
35
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -070036 lineEdit->setFocusPolicy(Qt::StrongFocus);
Zhenkai Zhub45e38a2012-06-01 15:44:36 -070037
Zhenkai Zhu82a62752012-06-04 17:11:04 -070038 treeViewer->setScene(m_scene);
39 m_scene->plot("Empty");
40 QRectF rect = m_scene->itemsBoundingRect();
41 m_scene->setSceneRect(rect);
42
Zhenkai Zhu9036e032012-09-27 20:59:33 -070043 listView->setStyleSheet("QListView { alternate-background-color: white; background: #F0F0F0; color: darkGreen; font: bold large; }");
Zhenkai Zhuf55f4382012-09-28 10:58:54 -070044 listView->setEditTriggers(QAbstractItemView::NoEditTriggers);
45 listView->setDragDropMode(QAbstractItemView::NoDragDrop);
46 listView->setSelectionMode(QAbstractItemView::NoSelection);
Zhenkai Zhu6082ede2012-09-27 17:28:46 -070047 m_rosterModel = new QStringListModel(this);
48 listView->setModel(m_rosterModel);
49
Zhenkai Zhu4b953d92012-10-08 13:09:40 -070050 refreshButton->setIcon(QIcon(QPixmap(":images/refresh.png")));
Zhenkai Zhu22c7d4d2012-10-09 12:29:32 -070051 reapButton->hide();
Zhenkai Zhu4b953d92012-10-08 13:09:40 -070052
Zhenkai Zhu86df7412012-09-27 16:30:20 -070053 createActions();
54 createTrayIcon();
55 m_timer = new QTimer(this);
56 connect(lineEdit, SIGNAL(returnPressed()), this, SLOT(returnPressed()));
57 connect(setButton, SIGNAL(pressed()), this, SLOT(buttonPressed()));
Zhenkai Zhub60b7e12012-09-28 11:34:21 -070058 connect(treeButton, SIGNAL(pressed()), this, SLOT(treeButtonPressed()));
Zhenkai Zhu7f52e1b2012-10-09 11:45:36 -070059 connect(reapButton, SIGNAL(pressed()), this, SLOT(summonReaper()));
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -070060 connect(refreshButton, SIGNAL(pressed()), this, SLOT(updateLocalPrefix()));
Zhenkai Zhu24ec4722012-10-07 17:56:38 -070061 connect(this, SIGNAL(dataReceived(QString, const char *, size_t, bool, bool)), this, SLOT(processData(QString, const char *, size_t, bool, bool)));
Zhenkai Zhu86df7412012-09-27 16:30:20 -070062 connect(this, SIGNAL(treeUpdated(const std::vector<Sync::MissingDataInfo>)), this, SLOT(processTreeUpdate(const std::vector<Sync::MissingDataInfo>)));
Zhenkai Zhu86df7412012-09-27 16:30:20 -070063 connect(m_timer, SIGNAL(timeout()), this, SLOT(replot()));
64 connect(m_scene, SIGNAL(replot()), this, SLOT(replot()));
65 connect(trayIcon, SIGNAL(messageClicked()), this, SLOT(showNormal()));
66 connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
Zhenkai Zhu25e33e52012-09-28 13:00:07 -070067 connect(m_scene, SIGNAL(rosterChanged(QStringList)), this, SLOT(updateRosterList(QStringList)));
Zhenkai Zhud616b582012-10-10 00:04:07 -070068
69 initializeSync();
Zhenkai Zhu86df7412012-09-27 16:30:20 -070070
Zhenkai Zhud616b582012-10-10 00:04:07 -070071}
72
73void
74ChatDialog::initializeSync()
75{
Zhenkai Zhu82a62752012-06-04 17:11:04 -070076 // create sync socket
Zhenkai Zhu8e180ae2012-10-10 14:01:05 -070077 if(!m_user.getChatroom().isEmpty() && !m_user.getNick().isEmpty()) {
Zhenkai Zhu82a62752012-06-04 17:11:04 -070078 std::string syncPrefix = BROADCAST_PREFIX_FOR_SYNC_DEMO;
79 syncPrefix += "/";
80 syncPrefix += m_user.getChatroom().toStdString();
Zhenkai Zhua4fb1242012-06-05 20:26:05 -070081 try
82 {
Alexander Afanasyev288edd82012-10-04 17:07:56 -070083 m_sock = new Sync::SyncAppSocket(syncPrefix,
84 bind(&ChatDialog::processTreeUpdateWrapper, this, _1, _2),
85 bind(&ChatDialog::processRemoveWrapper, this, _1));
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -070086 //QTimer::singleShot(100, this, SLOT(getLocalPrefix()));
Zhenkai Zhu400cc892012-10-09 12:31:51 -070087 usleep(100000);
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -070088 if (!getLocalPrefix())
89 {
90 // if getLocalPrefix indicates no prefix change
91 // this sock is going to be used
92 QTimer::singleShot(600, this, SLOT(sendJoin()));
93 m_timer->start(FRESHNESS * 1000);
94 disableTreeDisplay();
95 QTimer::singleShot(2200, this, SLOT(enableTreeDisplay()));
Zhenkai Zhu5ee10092012-10-09 12:48:52 -070096 Sync::CcnxWrapperPtr handle = Sync::CcnxWrapper::Create();
97 handle->setInterestFilter(m_user.getPrefix().toStdString(), bind(&ChatDialog::respondHistoryRequest, this, _1));
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -070098 }
99 else
100 {
101 // this socket is going to be destroyed anyway
102 // why bother doing the following steps
Alexander Afanasyevebe118d2012-10-08 08:56:34 -0700103
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700104 // the same steps would be performed for another socket
105 // in settingUpdated
106 }
Zhenkai Zhua4fb1242012-06-05 20:26:05 -0700107 }
108 catch (Sync::CcnxOperationException ex)
109 {
Zhenkai Zhu0b3fa332012-09-27 21:58:43 -0700110 QMessageBox::critical(this, tr("Chronos"), tr("Canno connect to ccnd.\n Have you started your ccnd?"), QMessageBox::Ok);
Zhenkai Zhua4fb1242012-06-05 20:26:05 -0700111 std::exit(1);
112 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700113 }
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700114}
115
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700116ChatDialog::~ChatDialog()
117{
118 if (m_sock != NULL)
119 {
Zhenkai Zhucf024442012-10-05 10:33:08 -0700120 sendLeave();
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700121 delete m_sock;
122 m_sock = NULL;
123 }
124}
125
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700126void
Zhenkai Zhucf024442012-10-05 10:33:08 -0700127ChatDialog::sendLeave()
128{
129 SyncDemo::ChatMessage msg;
130 formControlMessage(msg, SyncDemo::ChatMessage::LEAVE);
131 sendMsg(msg);
132 usleep(500000);
133 m_sock->remove(m_user.getPrefix().toStdString());
134 usleep(5000);
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700135 m_joined = false;
Zhenkai Zhucf024442012-10-05 10:33:08 -0700136#ifdef __DEBUG
137 std::cout << "Sync REMOVE signal sent" << std::endl;
138#endif
139}
140
141void
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700142ChatDialog::replot()
143{
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700144 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700145 m_scene->plot(m_sock->getRootDigest().c_str());
Zhenkai Zhuc9e4e3c2012-10-02 11:47:31 -0700146 fitView();
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700147}
148
Zhenkai Zhu6082ede2012-09-27 17:28:46 -0700149void
Zhenkai Zhu7f52e1b2012-10-09 11:45:36 -0700150ChatDialog::summonReaper()
151{
152 Sync::SyncLogic &logic = m_sock->getLogic ();
153 std::map<std::string, bool> branches = logic.getBranchPrefixes();
154 QMap<QString, DisplayUserPtr> roster = m_scene->getRosterFull();
155
156 m_zombieList.clear();
157
158 QMapIterator<QString, DisplayUserPtr> it(roster);
159 std::map<std::string, bool>::iterator mapIt;
160 while(it.hasNext())
161 {
162 it.next();
163 DisplayUserPtr p = it.value();
164 if (p != DisplayUserNullPtr)
165 {
166 mapIt = branches.find(p->getPrefix().toStdString());
167 if (mapIt != branches.end())
168 {
169 mapIt->second = true;
170 }
171 }
172 }
173
174 for (mapIt = branches.begin(); mapIt != branches.end(); ++mapIt)
175 {
176 // this is zombie. all active users should have been marked true
177 if (! mapIt->second)
178 {
179 m_zombieList.append(mapIt->first.c_str());
180 }
181 }
182
183 m_zombieIndex = 0;
184
185 // start reaping
186 reap();
187}
188
189void
190ChatDialog::reap()
191{
192 if (m_zombieIndex < m_zombieList.size())
193 {
194 std::string prefix = m_zombieList.at(m_zombieIndex).toStdString();
195 m_sock->remove(prefix);
196 std::cout << "Reaped: prefix = " << prefix << std::endl;
197 m_zombieIndex++;
198 // reap again in 10 seconds
199 QTimer::singleShot(10000, this, SLOT(reap()));
200 }
201}
202
203void
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700204ChatDialog::updateRosterList(QStringList staleUserList)
Zhenkai Zhu6082ede2012-09-27 17:28:46 -0700205{
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700206 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu6082ede2012-09-27 17:28:46 -0700207 QStringList rosterList = m_scene->getRosterList();
208 m_rosterModel->setStringList(rosterList);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700209 QString user;
210 QStringListIterator it(staleUserList);
211 while(it.hasNext())
212 {
Zhenkai Zhu32cbdce2012-10-02 11:09:38 -0700213 std::string nick = it.next().toStdString();
214 if (nick.empty())
215 continue;
216
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700217 SyncDemo::ChatMessage msg;
Zhenkai Zhub5b78462012-09-28 14:10:37 -0700218 formControlMessage(msg, SyncDemo::ChatMessage::LEAVE);
Zhenkai Zhu32cbdce2012-10-02 11:09:38 -0700219 msg.set_from(nick);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700220 appendMessage(msg);
221 }
Zhenkai Zhu6082ede2012-09-27 17:28:46 -0700222}
223
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700224void
225ChatDialog::setVisible(bool visible)
226{
227 minimizeAction->setEnabled(visible);
228 maximizeAction->setEnabled(!isMaximized());
229 restoreAction->setEnabled(isMaximized() || !visible);
230 QDialog::setVisible(visible);
231}
232
233void
234ChatDialog::closeEvent(QCloseEvent *e)
235{
Zhenkai Zhu3974a492012-09-28 14:39:45 -0700236 if (trayIcon->isVisible() && !m_minimaniho)
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700237 {
Zhenkai Zhu0b3fa332012-09-27 21:58:43 -0700238 QMessageBox::information(this, tr("Chronos"),
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700239 tr("The program will keep running in the "
240 "system tray. To terminate the program"
241 "choose <b>Quit</b> in the context memu"
242 "of the system tray entry."));
243 hide();
244 e->ignore();
Zhenkai Zhu3974a492012-09-28 14:39:45 -0700245 m_minimaniho = true;
246 writeSettings();
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700247 }
248}
249
250void
251ChatDialog::changeEvent(QEvent *e)
252{
253 switch(e->type())
254 {
255 case QEvent::ActivationChange:
256 if (isActiveWindow())
257 {
258 trayIcon->setIcon(QIcon(":/images/icon_small.png"));
259 }
260 break;
261 default:
262 break;
263 }
264}
265
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700266void
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700267ChatDialog::appendMessage(const SyncDemo::ChatMessage msg, bool isHistory)
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700268{
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700269 boost::recursive_mutex::scoped_lock lock(m_msgMutex);
Zhenkai Zhub6338822012-05-31 13:27:24 -0700270
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700271 if (msg.type() == SyncDemo::ChatMessage::CHAT)
Zhenkai Zhub98e6022012-09-27 13:48:23 -0700272 {
Zhenkai Zhub98e6022012-09-27 13:48:23 -0700273
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700274 if (!msg.has_data())
Zhenkai Zhub98e6022012-09-27 13:48:23 -0700275 {
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700276 return;
Zhenkai Zhub98e6022012-09-27 13:48:23 -0700277 }
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700278
279 if (msg.from().empty() || msg.data().empty())
280 {
281 return;
282 }
283
284 if (!msg.has_timestamp())
285 {
286 return;
287 }
288
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -0700289 if (m_history.size() == MAX_HISTORY_ENTRY)
290 {
291 m_history.dequeue();
292 }
293
294 m_history.enqueue(msg);
295
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700296 QTextCharFormat nickFormat;
297 nickFormat.setForeground(Qt::darkGreen);
298 nickFormat.setFontWeight(QFont::Bold);
299 nickFormat.setFontUnderline(true);
300 nickFormat.setUnderlineColor(Qt::gray);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700301
302 QTextCursor cursor(textEdit->textCursor());
303 cursor.movePosition(QTextCursor::End);
304 QTextTableFormat tableFormat;
305 tableFormat.setBorder(0);
306 QTextTable *table = cursor.insertTable(1, 2, tableFormat);
307 QString from = QString("%1 ").arg(msg.from().c_str());
308 QTextTableCell fromCell = table->cellAt(0, 0);
309 fromCell.setFormat(nickFormat);
310 fromCell.firstCursorPosition().insertText(from);
Zhenkai Zhu560ef1b2012-09-28 14:23:33 -0700311
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700312 time_t timestamp = msg.timestamp();
Zhenkai Zhu560ef1b2012-09-28 14:23:33 -0700313 printTimeInCell(table, timestamp);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700314
315 QTextCursor nextCursor(textEdit->textCursor());
316 nextCursor.movePosition(QTextCursor::End);
317 table = nextCursor.insertTable(1, 1, tableFormat);
Zhenkai Zhu767eac72012-10-08 11:20:57 -0700318 table->cellAt(0, 0).firstCursorPosition().insertText(QString::fromUtf8(msg.data().c_str()));
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700319 if (!isHistory)
320 {
Zhenkai Zhu767eac72012-10-08 11:20:57 -0700321 showMessage(from, QString::fromUtf8(msg.data().c_str()));
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700322 }
Zhenkai Zhub98e6022012-09-27 13:48:23 -0700323 }
324
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700325 if (msg.type() == SyncDemo::ChatMessage::JOIN || msg.type() == SyncDemo::ChatMessage::LEAVE)
326 {
327 QTextCharFormat nickFormat;
328 nickFormat.setForeground(Qt::gray);
329 nickFormat.setFontWeight(QFont::Bold);
330 nickFormat.setFontUnderline(true);
331 nickFormat.setUnderlineColor(Qt::gray);
Zhenkai Zhub98e6022012-09-27 13:48:23 -0700332
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700333 QTextCursor cursor(textEdit->textCursor());
334 cursor.movePosition(QTextCursor::End);
335 QTextTableFormat tableFormat;
336 tableFormat.setBorder(0);
337 QTextTable *table = cursor.insertTable(1, 2, tableFormat);
338 QString action;
339 if (msg.type() == SyncDemo::ChatMessage::JOIN)
340 {
341 action = "enters room";
342 }
343 else
344 {
345 action = "leaves room";
346 }
347
348 QString from = QString("%1 %2 ").arg(msg.from().c_str()).arg(action);
349 QTextTableCell fromCell = table->cellAt(0, 0);
350 fromCell.setFormat(nickFormat);
351 fromCell.firstCursorPosition().insertText(from);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700352
Zhenkai Zhu560ef1b2012-09-28 14:23:33 -0700353 time_t timestamp = msg.timestamp();
354 printTimeInCell(table, timestamp);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700355 }
356
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700357 QScrollBar *bar = textEdit->verticalScrollBar();
358 bar->setValue(bar->maximum());
359}
360
Zhenkai Zhu560ef1b2012-09-28 14:23:33 -0700361void
362ChatDialog::printTimeInCell(QTextTable *table, time_t timestamp)
363{
364 QTextCharFormat timeFormat;
365 timeFormat.setForeground(Qt::gray);
366 timeFormat.setFontUnderline(true);
367 timeFormat.setUnderlineColor(Qt::gray);
368 QTextTableCell timeCell = table->cellAt(0, 1);
369 timeCell.setFormat(timeFormat);
370 timeCell.firstCursorPosition().insertText(formatTime(timestamp));
371}
372
373QString
374ChatDialog::formatTime(time_t timestamp)
375{
376 struct tm *tm_time = localtime(&timestamp);
377 int hour = tm_time->tm_hour;
378 QString amOrPM;
379 if (hour > 12)
380 {
381 hour -= 12;
382 amOrPM = "PM";
383 }
384 else
385 {
386 amOrPM = "AM";
387 if (hour == 0)
388 {
389 hour = 12;
390 }
391 }
392
393 char textTime[12];
394 sprintf(textTime, "%d:%02d:%02d %s", hour, tm_time->tm_min, tm_time->tm_sec, amOrPM.toStdString().c_str());
395 return QString(textTime);
396}
397
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700398void
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700399ChatDialog::processTreeUpdateWrapper(const std::vector<Sync::MissingDataInfo> v, Sync::SyncAppSocket *sock)
400{
401 emit treeUpdated(v);
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700402#ifdef __DEBUG
403 std::cout << "<<< Tree update signal emitted" << std::endl;
404#endif
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700405}
406
407void
408ChatDialog::processTreeUpdate(const std::vector<Sync::MissingDataInfo> v)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700409{
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700410#ifdef __DEBUG
411 std::cout << "<<< processing Tree Update" << std::endl;
412#endif
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700413 if (v.empty())
414 {
415 return;
416 }
417
418 // reflect the changes on digest tree
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700419 {
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700420 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700421 m_scene->processUpdate(v, m_sock->getRootDigest().c_str());
422 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700423
424 int n = v.size();
425 int totalMissingPackets = 0;
426 for (int i = 0; i < n; i++)
427 {
428 totalMissingPackets += v[i].high.getSeq() - v[i].low.getSeq() + 1;
429 }
430
Zhenkai Zhubb198112012-09-27 11:31:42 -0700431 for (int i = 0; i < n; i++)
432 {
433 if (totalMissingPackets < 4)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700434 {
435 for (Sync::SeqNo seq = v[i].low; seq <= v[i].high; ++seq)
436 {
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700437 m_sock->fetchRaw(v[i].prefix, seq, bind(&ChatDialog::processDataWrapper, this, _1, _2, _3), 2);
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700438#ifdef __DEBUG
439 std::cout << "<<< Fetching " << v[i].prefix << "/" <<seq.getSession() <<"/" << seq.getSeq() << std::endl;
440#endif
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700441 }
442 }
Zhenkai Zhubb198112012-09-27 11:31:42 -0700443 else
444 {
445 m_sock->fetchRaw(v[i].prefix, v[i].high, bind(&ChatDialog::processDataNoShowWrapper, this, _1, _2, _3), 2);
446 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700447 }
448
449 // adjust the view
450 fitView();
451
452}
453
454void
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700455ChatDialog::processDataWrapper(std::string name, const char *buf, size_t len)
456{
Zhenkai Zhuae29f5a2012-10-05 17:28:04 -0700457 char *tempBuf = new char[len];
458 memcpy(tempBuf, buf, len);
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700459 emit dataReceived(name.c_str(), tempBuf, len, true, false);
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700460#ifdef __DEBUG
461 std::cout <<"<<< " << name << " fetched" << std::endl;
462#endif
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700463}
464
465void
Zhenkai Zhubb198112012-09-27 11:31:42 -0700466ChatDialog::processDataNoShowWrapper(std::string name, const char *buf, size_t len)
467{
Zhenkai Zhuae29f5a2012-10-05 17:28:04 -0700468 char *tempBuf = new char[len];
469 memcpy(tempBuf, buf, len);
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700470 emit dataReceived(name.c_str(), tempBuf, len, false, false);
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -0700471
472 if (!m_historyInitialized)
473 {
474 fetchHistory(name);
475 m_historyInitialized = true;
476 }
477}
478
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700479void
480ChatDialog::processDataHistoryWrapper(std::string name, const char *buf, size_t len)
481{
482 char *tempBuf = new char[len];
483 memcpy(tempBuf, buf, len);
484 emit dataReceived(name.c_str(), tempBuf, len, true, true);
485}
486
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -0700487void
488ChatDialog::fetchHistory(std::string name)
489{
490 std::string nameWithoutSeq = name.substr(0, name.find_last_of('/'));
491 std::string prefix = nameWithoutSeq.substr(0, nameWithoutSeq.find_last_of('/'));
492 prefix += "/history";
493 Sync::CcnxWrapperPtr handle = Sync::CcnxWrapper::Create();
494 QString randomString = getRandomString();
495 for (int i = 0; i < MAX_HISTORY_ENTRY; i++)
496 {
497 QString interest = QString("%1/%2/%3").arg(prefix.c_str()).arg(randomString).arg(i);
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700498 handle->sendInterest(interest.toStdString(), bind(&ChatDialog::processDataHistoryWrapper, this, _1, _2, _3));
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -0700499 }
500}
501
502void
503ChatDialog::respondHistoryRequest(std::string interest)
504{
505 std::string seqStr = interest.substr(interest.find_last_of('/') + 1);
506 int seq = boost::lexical_cast<int>(seqStr);
507 if (seq >= 0 && seq < m_history.size())
508 {
509 Sync::CcnxWrapperPtr handle = Sync::CcnxWrapper::Create();
510 SyncDemo::ChatMessage msg = m_history.at(seq);
511 size_t size = msg.ByteSize();
512 char *buf = new char[size];
513 msg.SerializeToArray(buf, size);
514 handle->publishRawData(interest, buf, size, 1);
515 delete buf;
516 }
Zhenkai Zhubb198112012-09-27 11:31:42 -0700517}
518
519void
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700520ChatDialog::processData(QString name, const char *buf, size_t len, bool show, bool isHistory)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700521{
522 SyncDemo::ChatMessage msg;
Zhenkai Zhuef8d0632012-10-05 10:24:55 -0700523 bool corrupted = false;
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700524 if (!msg.ParseFromArray(buf, len))
525 {
Zhenkai Zhubb198112012-09-27 11:31:42 -0700526 std::cerr << "Errrrr.. Can not parse msg with name: " << name.toStdString() << ". what is happening?" << std::endl;
Zhenkai Zhuef8d0632012-10-05 10:24:55 -0700527 // nasty stuff: as a remedy, we'll form some standard msg for inparsable msgs
528 msg.set_from("inconnu");
529 msg.set_type(SyncDemo::ChatMessage::OTHER);
530 corrupted = true;
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700531 }
532
Zhenkai Zhuae29f5a2012-10-05 17:28:04 -0700533 delete [] buf;
534 buf = NULL;
535
Zhenkai Zhu10ccb5a2012-06-04 21:55:14 -0700536 // display msg received from network
537 // we have to do so; this function is called by ccnd thread
538 // so if we call appendMsg directly
539 // Qt crash as "QObject: Cannot create children for a parent that is in a different thread"
540 // the "cannonical" way to is use signal-slot
Zhenkai Zhuef8d0632012-10-05 10:24:55 -0700541 if (show && !corrupted)
Zhenkai Zhubb198112012-09-27 11:31:42 -0700542 {
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700543 appendMessage(msg, isHistory);
Zhenkai Zhubb198112012-09-27 11:31:42 -0700544 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700545
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700546 if (!isHistory)
547 {
548 // update the tree view
549 std::string stdStrName = name.toStdString();
550 std::string stdStrNameWithoutSeq = stdStrName.substr(0, stdStrName.find_last_of('/'));
551 std::string prefix = stdStrNameWithoutSeq.substr(0, stdStrNameWithoutSeq.find_last_of('/'));
Zhenkai Zhu097bfe72012-06-05 14:30:17 -0700552#ifdef __DEBUG
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700553 std::cout <<"<<< updating scene for" << prefix << ": " << msg.from() << std::endl;
Zhenkai Zhu097bfe72012-06-05 14:30:17 -0700554#endif
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700555 if (msg.type() == SyncDemo::ChatMessage::LEAVE)
556 {
557 processRemove(prefix.c_str());
558 }
559 else
560 {
561 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
562 m_scene->msgReceived(prefix.c_str(), msg.from().c_str());
563 }
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700564 }
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700565 fitView();
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700566}
567
568void
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700569ChatDialog::processRemoveWrapper(std::string prefix)
570{
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700571#ifdef __DEBUG
572 std::cout << "Sync REMOVE signal received for prefix: " << prefix << std::endl;
573#endif
574 //emit removeReceived(prefix.c_str());
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700575}
576
577void
578ChatDialog::processRemove(QString prefix)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700579{
Zhenkai Zhu591e8c32012-09-26 11:57:50 -0700580#ifdef __DEBUG
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700581 std::cout << "<<< remove node for prefix" << prefix.toStdString() << std::endl;
Zhenkai Zhu591e8c32012-09-26 11:57:50 -0700582#endif
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700583 bool removed = m_scene->removeNode(prefix);
Zhenkai Zhu591e8c32012-09-26 11:57:50 -0700584 if (removed)
585 {
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700586 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu591e8c32012-09-26 11:57:50 -0700587 m_scene->plot(m_sock->getRootDigest().c_str());
588 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700589}
590
591void
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700592ChatDialog::formChatMessage(const QString &text, SyncDemo::ChatMessage &msg) {
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700593 msg.set_from(m_user.getNick().toStdString());
594 msg.set_to(m_user.getChatroom().toStdString());
Zhenkai Zhu767eac72012-10-08 11:20:57 -0700595 msg.set_data(text.toUtf8().constData());
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700596 time_t seconds = time(NULL);
597 msg.set_timestamp(seconds);
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700598 msg.set_type(SyncDemo::ChatMessage::CHAT);
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700599}
600
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700601void
Zhenkai Zhub5b78462012-09-28 14:10:37 -0700602ChatDialog::formControlMessage(SyncDemo::ChatMessage &msg, SyncDemo::ChatMessage::ChatMessageType type)
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700603{
604 msg.set_from(m_user.getNick().toStdString());
605 msg.set_to(m_user.getChatroom().toStdString());
606 time_t seconds = time(NULL);
607 msg.set_timestamp(seconds);
Zhenkai Zhub5b78462012-09-28 14:10:37 -0700608 msg.set_type(type);
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700609}
610
Zhenkai Zhu59245aa2012-09-26 16:07:04 -0700611static std::string chars("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM0123456789");
612
613QString
614ChatDialog::getRandomString()
615{
616 std::string randStr;
617 boost::random::random_device rng;
618 boost::random::uniform_int_distribution<> index_dist(0, chars.size() - 1);
619 for (int i = 0; i < 10; i ++)
620 {
621 randStr += chars[index_dist(rng)];
622 }
623 return randStr.c_str();
624}
625
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700626bool
Zhenkai Zhu6bda0bd2012-10-06 23:50:39 -0700627ChatDialog::getLocalPrefix()
628{
Zhenkai Zhu86581412012-10-08 16:58:39 -0700629// /*
630// * this method tries to use ccncat
631// * however, it does not work in Mac OS X app bundle
632// * it works well in command line though
633// */
634
635// std::string cmd = CCN_EXEC;
636// cmd += " -c -v ";
637// cmd += LOCAL_PREFIX_QUERY;
638// QString localPrefix;
639// #define MAX_PREFIX_LEN 100
640// FILE *fp = popen(cmd.c_str(), "r");
641// if (fp != NULL)
642// {
643// char prefix[MAX_PREFIX_LEN];
644// if (fgets(prefix, MAX_PREFIX_LEN, fp) != NULL)
645// {
646// localPrefix = prefix;
647// localPrefix.remove('\n');
648// }
649// else
650// {
651// localPrefix = DEFAULT_LOCAL_PREFIX;
652// }
653// pclose(fp);
654// }
655// else
656// {
657// localPrefix = DEFAULT_LOCAL_PREFIX;
658// }
659// return localPrefix;
Alexander Afanasyevebe118d2012-10-08 08:56:34 -0700660 std::cerr << "trying to get local prefix" << std::endl;
661
Zhenkai Zhu86581412012-10-08 16:58:39 -0700662 if (m_sock != NULL)
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700663 {
664 QString originPrefix = QString::fromStdString (m_sock->getLocalPrefix()).trimmed ();
665 std::cerr << "got: " << originPrefix.toStdString () << std::endl;
Zhenkai Zhuba707342012-10-08 16:20:15 -0700666
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700667 if (originPrefix != "" && m_user.getOriginPrefix () != originPrefix)
Zhenkai Zhu86581412012-10-08 16:58:39 -0700668 {
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700669 emit settingUpdated(m_user.getNick (), m_user.getChatroom (), originPrefix);
670 // prefix updated
671 return true;
Zhenkai Zhu86581412012-10-08 16:58:39 -0700672 }
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700673 }
674
675 // prefix not changed
676 return false;
677}
678
679void
680ChatDialog::updateLocalPrefix()
681{
682 getLocalPrefix();
Zhenkai Zhu6bda0bd2012-10-06 23:50:39 -0700683}
684
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700685bool
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700686ChatDialog::readSettings()
687{
688 QSettings s(ORGANIZATION, APPLICATION);
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700689 QString nick = s.value("nick", "").toString();
690 QString chatroom = s.value("chatroom", "").toString();
Zhenkai Zhu86581412012-10-08 16:58:39 -0700691 // QString originPrefix = s.value("originPrefix", "").toString();
Alexander Afanasyev5ddc68b2012-10-08 00:21:40 -0700692
Zhenkai Zhu86581412012-10-08 16:58:39 -0700693 // Sync::CcnxWrapperPtr wrapper = Sync::CcnxWrapper::Create ();
694 // QString originPrefix = QString::fromStdString (wrapper->getLocalPrefix());
695 // Sync::CcnxWrapper::Destroy ();
Alexander Afanasyev5ddc68b2012-10-08 00:21:40 -0700696
Zhenkai Zhu86581412012-10-08 16:58:39 -0700697 QString originPrefix = DEFAULT_LOCAL_PREFIX;
Alexander Afanasyev5ddc68b2012-10-08 00:21:40 -0700698
Zhenkai Zhu3974a492012-09-28 14:39:45 -0700699 m_minimaniho = s.value("minimaniho", false).toBool();
700 if (nick == "" || chatroom == "" || originPrefix == "") {
Zhenkai Zhud616b582012-10-10 00:04:07 -0700701 m_user.setOriginPrefix(DEFAULT_LOCAL_PREFIX);
Zhenkai Zhu8e180ae2012-10-10 14:01:05 -0700702 m_user.setChatroom("retreat2012");
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700703 QTimer::singleShot(500, this, SLOT(buttonPressed()));
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700704 return false;
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700705 }
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700706 else {
707 m_user.setNick(nick);
708 m_user.setChatroom(chatroom);
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700709 m_user.setOriginPrefix(originPrefix);
Zhenkai Zhu3974a492012-09-28 14:39:45 -0700710 m_user.setPrefix(originPrefix + "/" + chatroom + "/" + getRandomString());
Zhenkai Zhu716fe852012-10-08 18:27:55 -0700711 m_scene->setCurrentPrefix(originPrefix + "/" + chatroom + "/" + getRandomString());
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700712 return true;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700713 }
Zhenkai Zhu3974a492012-09-28 14:39:45 -0700714
715// QTimer::singleShot(500, this, SLOT(buttonPressed()));
716 // return false;
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700717}
718
719void
720ChatDialog::writeSettings()
721{
722 QSettings s(ORGANIZATION, APPLICATION);
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700723 s.setValue("nick", m_user.getNick());
724 s.setValue("chatroom", m_user.getChatroom());
Zhenkai Zhu6bda0bd2012-10-06 23:50:39 -0700725 //s.setValue("originPrefix", m_user.getOriginPrefix());
Zhenkai Zhu3974a492012-09-28 14:39:45 -0700726 s.setValue("minimaniho", m_minimaniho);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700727}
728
729void
730ChatDialog::updateLabels()
731{
Zhenkai Zhu76ff02b2012-09-27 21:11:03 -0700732 QString settingDisp = QString("Chatroom: %1").arg(m_user.getChatroom());
733 infoLabel->setStyleSheet("QLabel {color: #630; font-size: 16px; font: bold \"Verdana\";}");
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700734 infoLabel->setText(settingDisp);
Zhenkai Zhu6bda0bd2012-10-06 23:50:39 -0700735 QString prefixDisp;
736 if (m_user.getPrefix().startsWith(DEFAULT_LOCAL_PREFIX))
737 {
Zhenkai Zhud616b582012-10-10 00:04:07 -0700738 prefixDisp = QString("<Warning: no connection to hub or hub does not support prefix autoconfig.>\n <Prefix = %1>").arg(m_user.getPrefix());
Zhenkai Zhu6bda0bd2012-10-06 23:50:39 -0700739 prefixLabel->setStyleSheet("QLabel {color: red; font-size: 12px; font: bold \"Verdana\";}");
740 }
741 else
742 {
743 prefixDisp = QString("<Prefix = %1>").arg(m_user.getPrefix());
744 prefixLabel->setStyleSheet("QLabel {color: Green; font-size: 12px; font: bold \"Verdana\";}");
745 }
746 prefixLabel->setText(prefixDisp);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700747}
748
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700749void
750ChatDialog::returnPressed()
751{
752 QString text = lineEdit->text();
753 if (text.isEmpty())
754 return;
755
Zhenkai Zhub6338822012-05-31 13:27:24 -0700756 lineEdit->clear();
757
Zhenkai Zhu22c7d4d2012-10-09 12:29:32 -0700758 if (text.startsWith("boruoboluomi"))
759 {
760 reapButton->show();
761 fitView();
762 return;
763 }
764
765 if (text.startsWith("minimanihong"))
766 {
767 reapButton->hide();
768 fitView();
769 return;
770 }
771
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700772 SyncDemo::ChatMessage msg;
773 formChatMessage(text, msg);
774
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700775 appendMessage(msg);
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700776
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700777 sendMsg(msg);
778
779 fitView();
780}
781
782void
783ChatDialog::sendMsg(SyncDemo::ChatMessage &msg)
784{
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700785 // send msg
786 size_t size = msg.ByteSize();
787 char *buf = new char[size];
788 msg.SerializeToArray(buf, size);
789 if (!msg.IsInitialized())
790 {
791 std::cerr << "Errrrr.. msg was not probally initialized "<<__FILE__ <<":"<<__LINE__<<". what is happening?" << std::endl;
792 abort();
793 }
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700794 m_sock->publishRaw(m_user.getPrefix().toStdString(), m_session, buf, size, FRESHNESS);
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700795
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700796 delete buf;
797
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700798 m_lastMsgTime = time(NULL);
799
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700800 int nextSequence = m_sock->getNextSeq(m_user.getPrefix().toStdString(), m_session);
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700801 Sync::MissingDataInfo mdi = {m_user.getPrefix().toStdString(), Sync::SeqNo(0), Sync::SeqNo(nextSequence - 1)};
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700802 std::vector<Sync::MissingDataInfo> v;
803 v.push_back(mdi);
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700804 {
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700805 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700806 m_scene->processUpdate(v, m_sock->getRootDigest().c_str());
807 m_scene->msgReceived(m_user.getPrefix(), m_user.getNick());
808 }
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700809}
810
811void
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700812ChatDialog::sendJoin()
813{
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700814 m_joined = true;
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700815 SyncDemo::ChatMessage msg;
Zhenkai Zhub5b78462012-09-28 14:10:37 -0700816 formControlMessage(msg, SyncDemo::ChatMessage::JOIN);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700817 sendMsg(msg);
Zhenkai Zhuc61dbc22012-10-08 11:36:37 -0700818 boost::random::random_device rng;
819 boost::random::uniform_int_distribution<> uniform(1, FRESHNESS / 5 * 1000);
820 m_randomizedInterval = HELLO_INTERVAL * 1000 + uniform(rng);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700821 QTimer::singleShot(m_randomizedInterval, this, SLOT(sendHello()));
822}
823
824void
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700825ChatDialog::sendHello()
826{
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700827 time_t now = time(NULL);
828 int elapsed = now - m_lastMsgTime;
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700829 if (elapsed >= m_randomizedInterval / 1000)
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700830 {
831 SyncDemo::ChatMessage msg;
Zhenkai Zhub5b78462012-09-28 14:10:37 -0700832 formControlMessage(msg, SyncDemo::ChatMessage::HELLO);
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700833 sendMsg(msg);
Zhenkai Zhuc61dbc22012-10-08 11:36:37 -0700834 boost::random::random_device rng;
835 boost::random::uniform_int_distribution<> uniform(1, FRESHNESS / 5 * 1000);
836 m_randomizedInterval = HELLO_INTERVAL * 1000 + uniform(rng);
Zhenkai Zhuee5c90f2012-09-27 14:05:41 -0700837 QTimer::singleShot(m_randomizedInterval, this, SLOT(sendHello()));
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700838 }
839 else
840 {
Zhenkai Zhuee5c90f2012-09-27 14:05:41 -0700841 QTimer::singleShot((m_randomizedInterval - elapsed * 1000), this, SLOT(sendHello()));
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700842 }
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700843}
844
845void
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700846ChatDialog::buttonPressed()
847{
Zhenkai Zhud616b582012-10-10 00:04:07 -0700848 if (m_sock != NULL)
849 {
850 Sync::SyncLogic &logic = m_sock->getLogic ();
851 logic.printState ();
852 }
Alexander Afanasyev5ddc68b2012-10-08 00:21:40 -0700853
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700854 SettingDialog dialog(this, m_user.getNick(), m_user.getChatroom(), m_user.getOriginPrefix());
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700855 connect(&dialog, SIGNAL(updated(QString, QString, QString)), this, SLOT(settingUpdated(QString, QString, QString)));
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700856 dialog.exec();
Zhenkai Zhue837f792012-06-05 20:47:54 -0700857 QTimer::singleShot(100, this, SLOT(checkSetting()));
858}
859
Zhenkai Zhub60b7e12012-09-28 11:34:21 -0700860void ChatDialog::treeButtonPressed()
861{
862 if (treeViewer->isVisible())
863 {
864 treeViewer->hide();
865 treeButton->setText("Show Sync Tree");
866 }
867 else
868 {
869 treeViewer->show();
870 treeButton->setText("Hide Sync Tree");
871 }
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700872
873 fitView();
Zhenkai Zhub60b7e12012-09-28 11:34:21 -0700874}
875
Zhenkai Zhu0e7a9b22012-10-05 17:55:17 -0700876void ChatDialog::enableTreeDisplay()
877{
878 treeButton->setEnabled(true);
879 treeViewer->show();
880 fitView();
881}
882
883void ChatDialog::disableTreeDisplay()
884{
885 treeButton->setEnabled(false);
886 treeViewer->hide();
887 fitView();
888}
889
Zhenkai Zhue837f792012-06-05 20:47:54 -0700890void
891ChatDialog::checkSetting()
892{
Zhenkai Zhud616b582012-10-10 00:04:07 -0700893 if (m_user.getNick().isEmpty() || m_user.getChatroom().isEmpty() || m_user.getOriginPrefix().isEmpty())
Zhenkai Zhue837f792012-06-05 20:47:54 -0700894 {
895 buttonPressed();
896 }
Zhenkai Zhud616b582012-10-10 00:04:07 -0700897
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -0700898}
Zhenkai Zhue08afe02012-05-31 15:49:07 -0700899
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700900void
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700901ChatDialog::settingUpdated(QString nick, QString chatroom, QString originPrefix)
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700902{
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700903 QString randString = getRandomString();
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700904 bool needWrite = false;
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700905 bool needFresh = false;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700906 if (!nick.isEmpty() && nick != m_user.getNick()) {
907 m_user.setNick(nick);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700908 needWrite = true;
909 }
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -0700910 QString oldPrefix = m_user.getPrefix();
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700911 if (!originPrefix.isEmpty() && originPrefix != m_user.getOriginPrefix()) {
912 m_user.setOriginPrefix(originPrefix);
913 m_user.setPrefix(originPrefix + "/" + m_user.getChatroom() + "/" + randString);
Zhenkai Zhu716fe852012-10-08 18:27:55 -0700914 m_scene->setCurrentPrefix(originPrefix + "/" + m_user.getChatroom() + "/" + randString);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700915 needWrite = true;
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700916 needFresh = true;
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700917 }
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700918 if (!chatroom.isEmpty() && chatroom != m_user.getChatroom()) {
919 m_user.setChatroom(chatroom);
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700920 m_user.setPrefix(m_user.getOriginPrefix() + "/" + chatroom + "/" + randString);
Zhenkai Zhu716fe852012-10-08 18:27:55 -0700921 m_scene->setCurrentPrefix(m_user.getOriginPrefix() + "/" + chatroom + "/" + randString);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700922 needWrite = true;
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700923 needFresh = true;
924 }
925
Zhenkai Zhud616b582012-10-10 00:04:07 -0700926 if (needWrite) {
927 writeSettings();
928 updateLabels();
929 }
930
931 if (needFresh && m_sock != NULL)
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700932 {
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700933
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700934 {
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700935 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700936 m_scene->clearAll();
937 m_scene->plot("Empty");
938 }
Zhenkai Zhucc4c2c02012-09-27 21:24:37 -0700939
940 textEdit->clear();
941
Zhenkai Zhud616b582012-10-10 00:04:07 -0700942 // keep the new prefix
943 QString newPrefix = m_user.getPrefix();
944 // send leave for the old
945 m_user.setPrefix(oldPrefix);
946 // there is no point to send leave if we haven't joined yet
947 if (m_joined)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700948 {
Zhenkai Zhud616b582012-10-10 00:04:07 -0700949 sendLeave();
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700950 }
Zhenkai Zhud616b582012-10-10 00:04:07 -0700951 // resume new prefix
952 m_user.setPrefix(newPrefix);
953 // Sync::CcnxWrapperPtr handle = Sync::CcnxWrapper::Create();
954 // handle->clearInterestFilter(oldPrefix.toStdString());
955 m_history.clear();
956 m_historyInitialized = false;
957 delete m_sock;
958 m_sock = NULL;
959
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700960 std::string syncPrefix = BROADCAST_PREFIX_FOR_SYNC_DEMO;
961 syncPrefix += "/";
962 syncPrefix += m_user.getChatroom().toStdString();
Zhenkai Zhua4fb1242012-06-05 20:26:05 -0700963 try
964 {
Zhenkai Zhud616b582012-10-10 00:04:07 -0700965 usleep(100000);
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700966 m_sock = new Sync::SyncAppSocket(syncPrefix, bind(&ChatDialog::processTreeUpdateWrapper, this, _1, _2), bind(&ChatDialog::processRemoveWrapper, this, _1));
Zhenkai Zhud616b582012-10-10 00:04:07 -0700967 usleep(100000);
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -0700968 Sync::CcnxWrapperPtr handle = Sync::CcnxWrapper::Create();
969 handle->setInterestFilter(m_user.getPrefix().toStdString(), bind(&ChatDialog::respondHistoryRequest, this, _1));
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700970 QTimer::singleShot(600, this, SLOT(sendJoin()));
Zhenkai Zhu78799ea2012-10-08 11:51:56 -0700971 m_timer->start(FRESHNESS * 1000);
Zhenkai Zhu0e7a9b22012-10-05 17:55:17 -0700972 disableTreeDisplay();
973 QTimer::singleShot(2200, this, SLOT(enableTreeDisplay()));
Zhenkai Zhua4fb1242012-06-05 20:26:05 -0700974 }
975 catch (Sync::CcnxOperationException ex)
976 {
Zhenkai Zhu0b3fa332012-09-27 21:58:43 -0700977 QMessageBox::critical(this, tr("Chronos"), tr("Canno connect to ccnd.\n Have you started your ccnd?"), QMessageBox::Ok);
Zhenkai Zhua4fb1242012-06-05 20:26:05 -0700978 std::exit(1);
979 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700980
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700981
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700982 }
Zhenkai Zhu6bb65e92012-10-10 10:34:39 -0700983 else if (needFresh && m_sock == NULL)
984 {
985 m_history.clear();
986 m_historyInitialized = false;
987 initializeSync();
988 }
Zhenkai Zhu8e180ae2012-10-10 14:01:05 -0700989 else if (m_sock == NULL)
990 {
991 initializeSync();
992 }
Zhenkai Zhud616b582012-10-10 00:04:07 -0700993 else
994 {
Zhenkai Zhu6bb65e92012-10-10 10:34:39 -0700995#ifdef __DEBUG
996 std::cout << "Just changing nicks, we're good. " << std::endl;
997#endif
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700998 }
Zhenkai Zhud616b582012-10-10 00:04:07 -0700999
1000 fitView();
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -07001001}
Zhenkai Zhud13acd02012-06-04 15:25:20 -07001002
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -07001003void
1004ChatDialog::iconActivated(QSystemTrayIcon::ActivationReason reason)
1005{
1006 switch (reason)
1007 {
1008 case QSystemTrayIcon::Trigger:
1009 case QSystemTrayIcon::DoubleClick:
1010 break;
1011 case QSystemTrayIcon::MiddleClick:
1012 // showMessage();
1013 break;
1014 default:;
1015 }
1016}
1017
1018void
1019ChatDialog::showMessage(QString from, QString data)
1020{
1021 // std::cout <<"Showing Message: " << from.toStdString() << ": " << data.toStdString() << std::endl;
1022 if (!isActiveWindow())
1023 {
1024 trayIcon->showMessage(QString("Chatroom %1 has a new message").arg(m_user.getChatroom()), QString("<%1>: %2").arg(from).arg(data), QSystemTrayIcon::Information, 20000);
1025 trayIcon->setIcon(QIcon(":/images/note.png"));
1026 }
1027}
1028
1029void
1030ChatDialog::messageClicked()
1031{
1032 this->showMaximized();
1033}
1034
1035void
1036ChatDialog::createActions()
1037{
1038 minimizeAction = new QAction(tr("Mi&nimize"), this);
1039 connect(minimizeAction, SIGNAL(triggered()), this, SLOT(hide()));
1040
1041 maximizeAction = new QAction(tr("Ma&ximize"), this);
1042 connect(maximizeAction, SIGNAL(triggered()), this, SLOT(showMaximized()));
1043
1044 restoreAction = new QAction(tr("&Restore"), this);
1045 connect(restoreAction, SIGNAL(triggered()), this, SLOT(showNormal()));
1046
1047 quitAction = new QAction(tr("Quit"), this);
1048 connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
1049}
1050
1051void
1052ChatDialog::createTrayIcon()
1053{
1054 trayIconMenu = new QMenu(this);
1055 trayIconMenu->addAction(minimizeAction);
1056 trayIconMenu->addAction(maximizeAction);
1057 trayIconMenu->addAction(restoreAction);
1058 trayIconMenu->addSeparator();
1059 trayIconMenu->addAction(quitAction);
1060
1061 trayIcon = new QSystemTrayIcon(this);
1062 trayIcon->setContextMenu(trayIconMenu);
1063
1064 QIcon icon(":/images/icon_small.png");
1065 trayIcon->setIcon(icon);
1066 setWindowIcon(icon);
Zhenkai Zhu0b3fa332012-09-27 21:58:43 -07001067 trayIcon->setToolTip("Chronos System Tray Icon");
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -07001068 trayIcon->setVisible(true);
1069}
1070
Zhenkai Zhud13acd02012-06-04 15:25:20 -07001071void
1072ChatDialog::resizeEvent(QResizeEvent *e)
1073{
1074 fitView();
1075}
1076
1077void
1078ChatDialog::showEvent(QShowEvent *e)
1079{
1080 fitView();
1081}
1082
1083void
1084ChatDialog::fitView()
1085{
Zhenkai Zhu9036e032012-09-27 20:59:33 -07001086 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu21d75f92012-06-04 21:23:34 -07001087 QRectF rect = m_scene->itemsBoundingRect();
1088 m_scene->setSceneRect(rect);
Zhenkai Zhu82a62752012-06-04 17:11:04 -07001089 treeViewer->fitInView(m_scene->itemsBoundingRect(), Qt::KeepAspectRatio);
Zhenkai Zhud13acd02012-06-04 15:25:20 -07001090}