blob: b7c6043bc5675d57f336b415e5cbc6b1dbf10d7b [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 Zhu86df7412012-09-27 16:30:20 -070068
Zhenkai Zhu82a62752012-06-04 17:11:04 -070069 // create sync socket
70 if(!m_user.getChatroom().isEmpty()) {
71 std::string syncPrefix = BROADCAST_PREFIX_FOR_SYNC_DEMO;
72 syncPrefix += "/";
73 syncPrefix += m_user.getChatroom().toStdString();
Zhenkai Zhua4fb1242012-06-05 20:26:05 -070074 try
75 {
Alexander Afanasyev288edd82012-10-04 17:07:56 -070076 m_sock = new Sync::SyncAppSocket(syncPrefix,
77 bind(&ChatDialog::processTreeUpdateWrapper, this, _1, _2),
78 bind(&ChatDialog::processRemoveWrapper, this, _1));
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -070079 //QTimer::singleShot(100, this, SLOT(getLocalPrefix()));
Zhenkai Zhu400cc892012-10-09 12:31:51 -070080 usleep(100000);
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -070081 if (!getLocalPrefix())
82 {
83 // if getLocalPrefix indicates no prefix change
84 // this sock is going to be used
85 QTimer::singleShot(600, this, SLOT(sendJoin()));
86 m_timer->start(FRESHNESS * 1000);
87 disableTreeDisplay();
88 QTimer::singleShot(2200, this, SLOT(enableTreeDisplay()));
Zhenkai Zhu5ee10092012-10-09 12:48:52 -070089 Sync::CcnxWrapperPtr handle = Sync::CcnxWrapper::Create();
90 handle->setInterestFilter(m_user.getPrefix().toStdString(), bind(&ChatDialog::respondHistoryRequest, this, _1));
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -070091 }
92 else
93 {
94 // this socket is going to be destroyed anyway
95 // why bother doing the following steps
Alexander Afanasyevebe118d2012-10-08 08:56:34 -070096
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -070097 // the same steps would be performed for another socket
98 // in settingUpdated
99 }
Zhenkai Zhua4fb1242012-06-05 20:26:05 -0700100 }
101 catch (Sync::CcnxOperationException ex)
102 {
Zhenkai Zhu0b3fa332012-09-27 21:58:43 -0700103 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 -0700104 std::exit(1);
105 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700106 }
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700107
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700108}
109
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700110ChatDialog::~ChatDialog()
111{
112 if (m_sock != NULL)
113 {
Zhenkai Zhucf024442012-10-05 10:33:08 -0700114 sendLeave();
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700115 delete m_sock;
116 m_sock = NULL;
117 }
118}
119
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700120void
Zhenkai Zhucf024442012-10-05 10:33:08 -0700121ChatDialog::sendLeave()
122{
123 SyncDemo::ChatMessage msg;
124 formControlMessage(msg, SyncDemo::ChatMessage::LEAVE);
125 sendMsg(msg);
126 usleep(500000);
127 m_sock->remove(m_user.getPrefix().toStdString());
128 usleep(5000);
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700129 m_joined = false;
Zhenkai Zhucf024442012-10-05 10:33:08 -0700130#ifdef __DEBUG
131 std::cout << "Sync REMOVE signal sent" << std::endl;
132#endif
133}
134
135void
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700136ChatDialog::replot()
137{
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700138 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700139 m_scene->plot(m_sock->getRootDigest().c_str());
Zhenkai Zhuc9e4e3c2012-10-02 11:47:31 -0700140 fitView();
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700141}
142
Zhenkai Zhu6082ede2012-09-27 17:28:46 -0700143void
Zhenkai Zhu7f52e1b2012-10-09 11:45:36 -0700144ChatDialog::summonReaper()
145{
146 Sync::SyncLogic &logic = m_sock->getLogic ();
147 std::map<std::string, bool> branches = logic.getBranchPrefixes();
148 QMap<QString, DisplayUserPtr> roster = m_scene->getRosterFull();
149
150 m_zombieList.clear();
151
152 QMapIterator<QString, DisplayUserPtr> it(roster);
153 std::map<std::string, bool>::iterator mapIt;
154 while(it.hasNext())
155 {
156 it.next();
157 DisplayUserPtr p = it.value();
158 if (p != DisplayUserNullPtr)
159 {
160 mapIt = branches.find(p->getPrefix().toStdString());
161 if (mapIt != branches.end())
162 {
163 mapIt->second = true;
164 }
165 }
166 }
167
168 for (mapIt = branches.begin(); mapIt != branches.end(); ++mapIt)
169 {
170 // this is zombie. all active users should have been marked true
171 if (! mapIt->second)
172 {
173 m_zombieList.append(mapIt->first.c_str());
174 }
175 }
176
177 m_zombieIndex = 0;
178
179 // start reaping
180 reap();
181}
182
183void
184ChatDialog::reap()
185{
186 if (m_zombieIndex < m_zombieList.size())
187 {
188 std::string prefix = m_zombieList.at(m_zombieIndex).toStdString();
189 m_sock->remove(prefix);
190 std::cout << "Reaped: prefix = " << prefix << std::endl;
191 m_zombieIndex++;
192 // reap again in 10 seconds
193 QTimer::singleShot(10000, this, SLOT(reap()));
194 }
195}
196
197void
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700198ChatDialog::updateRosterList(QStringList staleUserList)
Zhenkai Zhu6082ede2012-09-27 17:28:46 -0700199{
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700200 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu6082ede2012-09-27 17:28:46 -0700201 QStringList rosterList = m_scene->getRosterList();
202 m_rosterModel->setStringList(rosterList);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700203 QString user;
204 QStringListIterator it(staleUserList);
205 while(it.hasNext())
206 {
Zhenkai Zhu32cbdce2012-10-02 11:09:38 -0700207 std::string nick = it.next().toStdString();
208 if (nick.empty())
209 continue;
210
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700211 SyncDemo::ChatMessage msg;
Zhenkai Zhub5b78462012-09-28 14:10:37 -0700212 formControlMessage(msg, SyncDemo::ChatMessage::LEAVE);
Zhenkai Zhu32cbdce2012-10-02 11:09:38 -0700213 msg.set_from(nick);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700214 appendMessage(msg);
215 }
Zhenkai Zhu6082ede2012-09-27 17:28:46 -0700216}
217
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700218void
219ChatDialog::setVisible(bool visible)
220{
221 minimizeAction->setEnabled(visible);
222 maximizeAction->setEnabled(!isMaximized());
223 restoreAction->setEnabled(isMaximized() || !visible);
224 QDialog::setVisible(visible);
225}
226
227void
228ChatDialog::closeEvent(QCloseEvent *e)
229{
Zhenkai Zhu3974a492012-09-28 14:39:45 -0700230 if (trayIcon->isVisible() && !m_minimaniho)
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700231 {
Zhenkai Zhu0b3fa332012-09-27 21:58:43 -0700232 QMessageBox::information(this, tr("Chronos"),
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700233 tr("The program will keep running in the "
234 "system tray. To terminate the program"
235 "choose <b>Quit</b> in the context memu"
236 "of the system tray entry."));
237 hide();
238 e->ignore();
Zhenkai Zhu3974a492012-09-28 14:39:45 -0700239 m_minimaniho = true;
240 writeSettings();
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700241 }
242}
243
244void
245ChatDialog::changeEvent(QEvent *e)
246{
247 switch(e->type())
248 {
249 case QEvent::ActivationChange:
250 if (isActiveWindow())
251 {
252 trayIcon->setIcon(QIcon(":/images/icon_small.png"));
253 }
254 break;
255 default:
256 break;
257 }
258}
259
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700260void
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700261ChatDialog::appendMessage(const SyncDemo::ChatMessage msg, bool isHistory)
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700262{
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700263 boost::recursive_mutex::scoped_lock lock(m_msgMutex);
Zhenkai Zhub6338822012-05-31 13:27:24 -0700264
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700265 if (msg.type() == SyncDemo::ChatMessage::CHAT)
Zhenkai Zhub98e6022012-09-27 13:48:23 -0700266 {
Zhenkai Zhub98e6022012-09-27 13:48:23 -0700267
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700268 if (!msg.has_data())
Zhenkai Zhub98e6022012-09-27 13:48:23 -0700269 {
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700270 return;
Zhenkai Zhub98e6022012-09-27 13:48:23 -0700271 }
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700272
273 if (msg.from().empty() || msg.data().empty())
274 {
275 return;
276 }
277
278 if (!msg.has_timestamp())
279 {
280 return;
281 }
282
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -0700283 if (m_history.size() == MAX_HISTORY_ENTRY)
284 {
285 m_history.dequeue();
286 }
287
288 m_history.enqueue(msg);
289
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700290 QTextCharFormat nickFormat;
291 nickFormat.setForeground(Qt::darkGreen);
292 nickFormat.setFontWeight(QFont::Bold);
293 nickFormat.setFontUnderline(true);
294 nickFormat.setUnderlineColor(Qt::gray);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700295
296 QTextCursor cursor(textEdit->textCursor());
297 cursor.movePosition(QTextCursor::End);
298 QTextTableFormat tableFormat;
299 tableFormat.setBorder(0);
300 QTextTable *table = cursor.insertTable(1, 2, tableFormat);
301 QString from = QString("%1 ").arg(msg.from().c_str());
302 QTextTableCell fromCell = table->cellAt(0, 0);
303 fromCell.setFormat(nickFormat);
304 fromCell.firstCursorPosition().insertText(from);
Zhenkai Zhu560ef1b2012-09-28 14:23:33 -0700305
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700306 time_t timestamp = msg.timestamp();
Zhenkai Zhu560ef1b2012-09-28 14:23:33 -0700307 printTimeInCell(table, timestamp);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700308
309 QTextCursor nextCursor(textEdit->textCursor());
310 nextCursor.movePosition(QTextCursor::End);
311 table = nextCursor.insertTable(1, 1, tableFormat);
Zhenkai Zhu767eac72012-10-08 11:20:57 -0700312 table->cellAt(0, 0).firstCursorPosition().insertText(QString::fromUtf8(msg.data().c_str()));
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700313 if (!isHistory)
314 {
Zhenkai Zhu767eac72012-10-08 11:20:57 -0700315 showMessage(from, QString::fromUtf8(msg.data().c_str()));
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700316 }
Zhenkai Zhub98e6022012-09-27 13:48:23 -0700317 }
318
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700319 if (msg.type() == SyncDemo::ChatMessage::JOIN || msg.type() == SyncDemo::ChatMessage::LEAVE)
320 {
321 QTextCharFormat nickFormat;
322 nickFormat.setForeground(Qt::gray);
323 nickFormat.setFontWeight(QFont::Bold);
324 nickFormat.setFontUnderline(true);
325 nickFormat.setUnderlineColor(Qt::gray);
Zhenkai Zhub98e6022012-09-27 13:48:23 -0700326
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700327 QTextCursor cursor(textEdit->textCursor());
328 cursor.movePosition(QTextCursor::End);
329 QTextTableFormat tableFormat;
330 tableFormat.setBorder(0);
331 QTextTable *table = cursor.insertTable(1, 2, tableFormat);
332 QString action;
333 if (msg.type() == SyncDemo::ChatMessage::JOIN)
334 {
335 action = "enters room";
336 }
337 else
338 {
339 action = "leaves room";
340 }
341
342 QString from = QString("%1 %2 ").arg(msg.from().c_str()).arg(action);
343 QTextTableCell fromCell = table->cellAt(0, 0);
344 fromCell.setFormat(nickFormat);
345 fromCell.firstCursorPosition().insertText(from);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700346
Zhenkai Zhu560ef1b2012-09-28 14:23:33 -0700347 time_t timestamp = msg.timestamp();
348 printTimeInCell(table, timestamp);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700349 }
350
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700351 QScrollBar *bar = textEdit->verticalScrollBar();
352 bar->setValue(bar->maximum());
353}
354
Zhenkai Zhu560ef1b2012-09-28 14:23:33 -0700355void
356ChatDialog::printTimeInCell(QTextTable *table, time_t timestamp)
357{
358 QTextCharFormat timeFormat;
359 timeFormat.setForeground(Qt::gray);
360 timeFormat.setFontUnderline(true);
361 timeFormat.setUnderlineColor(Qt::gray);
362 QTextTableCell timeCell = table->cellAt(0, 1);
363 timeCell.setFormat(timeFormat);
364 timeCell.firstCursorPosition().insertText(formatTime(timestamp));
365}
366
367QString
368ChatDialog::formatTime(time_t timestamp)
369{
370 struct tm *tm_time = localtime(&timestamp);
371 int hour = tm_time->tm_hour;
372 QString amOrPM;
373 if (hour > 12)
374 {
375 hour -= 12;
376 amOrPM = "PM";
377 }
378 else
379 {
380 amOrPM = "AM";
381 if (hour == 0)
382 {
383 hour = 12;
384 }
385 }
386
387 char textTime[12];
388 sprintf(textTime, "%d:%02d:%02d %s", hour, tm_time->tm_min, tm_time->tm_sec, amOrPM.toStdString().c_str());
389 return QString(textTime);
390}
391
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700392void
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700393ChatDialog::processTreeUpdateWrapper(const std::vector<Sync::MissingDataInfo> v, Sync::SyncAppSocket *sock)
394{
395 emit treeUpdated(v);
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700396#ifdef __DEBUG
397 std::cout << "<<< Tree update signal emitted" << std::endl;
398#endif
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700399}
400
401void
402ChatDialog::processTreeUpdate(const std::vector<Sync::MissingDataInfo> v)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700403{
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700404#ifdef __DEBUG
405 std::cout << "<<< processing Tree Update" << std::endl;
406#endif
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700407 if (v.empty())
408 {
409 return;
410 }
411
412 // reflect the changes on digest tree
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700413 {
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700414 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700415 m_scene->processUpdate(v, m_sock->getRootDigest().c_str());
416 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700417
418 int n = v.size();
419 int totalMissingPackets = 0;
420 for (int i = 0; i < n; i++)
421 {
422 totalMissingPackets += v[i].high.getSeq() - v[i].low.getSeq() + 1;
423 }
424
Zhenkai Zhubb198112012-09-27 11:31:42 -0700425 for (int i = 0; i < n; i++)
426 {
427 if (totalMissingPackets < 4)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700428 {
429 for (Sync::SeqNo seq = v[i].low; seq <= v[i].high; ++seq)
430 {
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700431 m_sock->fetchRaw(v[i].prefix, seq, bind(&ChatDialog::processDataWrapper, this, _1, _2, _3), 2);
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700432#ifdef __DEBUG
433 std::cout << "<<< Fetching " << v[i].prefix << "/" <<seq.getSession() <<"/" << seq.getSeq() << std::endl;
434#endif
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700435 }
436 }
Zhenkai Zhubb198112012-09-27 11:31:42 -0700437 else
438 {
439 m_sock->fetchRaw(v[i].prefix, v[i].high, bind(&ChatDialog::processDataNoShowWrapper, this, _1, _2, _3), 2);
440 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700441 }
442
443 // adjust the view
444 fitView();
445
446}
447
448void
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700449ChatDialog::processDataWrapper(std::string name, const char *buf, size_t len)
450{
Zhenkai Zhuae29f5a2012-10-05 17:28:04 -0700451 char *tempBuf = new char[len];
452 memcpy(tempBuf, buf, len);
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700453 emit dataReceived(name.c_str(), tempBuf, len, true, false);
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700454#ifdef __DEBUG
455 std::cout <<"<<< " << name << " fetched" << std::endl;
456#endif
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700457}
458
459void
Zhenkai Zhubb198112012-09-27 11:31:42 -0700460ChatDialog::processDataNoShowWrapper(std::string name, const char *buf, size_t len)
461{
Zhenkai Zhuae29f5a2012-10-05 17:28:04 -0700462 char *tempBuf = new char[len];
463 memcpy(tempBuf, buf, len);
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700464 emit dataReceived(name.c_str(), tempBuf, len, false, false);
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -0700465
466 if (!m_historyInitialized)
467 {
468 fetchHistory(name);
469 m_historyInitialized = true;
470 }
471}
472
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700473void
474ChatDialog::processDataHistoryWrapper(std::string name, const char *buf, size_t len)
475{
476 char *tempBuf = new char[len];
477 memcpy(tempBuf, buf, len);
478 emit dataReceived(name.c_str(), tempBuf, len, true, true);
479}
480
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -0700481void
482ChatDialog::fetchHistory(std::string name)
483{
484 std::string nameWithoutSeq = name.substr(0, name.find_last_of('/'));
485 std::string prefix = nameWithoutSeq.substr(0, nameWithoutSeq.find_last_of('/'));
486 prefix += "/history";
487 Sync::CcnxWrapperPtr handle = Sync::CcnxWrapper::Create();
488 QString randomString = getRandomString();
489 for (int i = 0; i < MAX_HISTORY_ENTRY; i++)
490 {
491 QString interest = QString("%1/%2/%3").arg(prefix.c_str()).arg(randomString).arg(i);
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700492 handle->sendInterest(interest.toStdString(), bind(&ChatDialog::processDataHistoryWrapper, this, _1, _2, _3));
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -0700493 }
494}
495
496void
497ChatDialog::respondHistoryRequest(std::string interest)
498{
499 std::string seqStr = interest.substr(interest.find_last_of('/') + 1);
500 int seq = boost::lexical_cast<int>(seqStr);
501 if (seq >= 0 && seq < m_history.size())
502 {
503 Sync::CcnxWrapperPtr handle = Sync::CcnxWrapper::Create();
504 SyncDemo::ChatMessage msg = m_history.at(seq);
505 size_t size = msg.ByteSize();
506 char *buf = new char[size];
507 msg.SerializeToArray(buf, size);
508 handle->publishRawData(interest, buf, size, 1);
509 delete buf;
510 }
Zhenkai Zhubb198112012-09-27 11:31:42 -0700511}
512
513void
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700514ChatDialog::processData(QString name, const char *buf, size_t len, bool show, bool isHistory)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700515{
516 SyncDemo::ChatMessage msg;
Zhenkai Zhuef8d0632012-10-05 10:24:55 -0700517 bool corrupted = false;
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700518 if (!msg.ParseFromArray(buf, len))
519 {
Zhenkai Zhubb198112012-09-27 11:31:42 -0700520 std::cerr << "Errrrr.. Can not parse msg with name: " << name.toStdString() << ". what is happening?" << std::endl;
Zhenkai Zhuef8d0632012-10-05 10:24:55 -0700521 // nasty stuff: as a remedy, we'll form some standard msg for inparsable msgs
522 msg.set_from("inconnu");
523 msg.set_type(SyncDemo::ChatMessage::OTHER);
524 corrupted = true;
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700525 }
526
Zhenkai Zhuae29f5a2012-10-05 17:28:04 -0700527 delete [] buf;
528 buf = NULL;
529
Zhenkai Zhu10ccb5a2012-06-04 21:55:14 -0700530 // display msg received from network
531 // we have to do so; this function is called by ccnd thread
532 // so if we call appendMsg directly
533 // Qt crash as "QObject: Cannot create children for a parent that is in a different thread"
534 // the "cannonical" way to is use signal-slot
Zhenkai Zhuef8d0632012-10-05 10:24:55 -0700535 if (show && !corrupted)
Zhenkai Zhubb198112012-09-27 11:31:42 -0700536 {
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700537 appendMessage(msg, isHistory);
Zhenkai Zhubb198112012-09-27 11:31:42 -0700538 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700539
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700540 if (!isHistory)
541 {
542 // update the tree view
543 std::string stdStrName = name.toStdString();
544 std::string stdStrNameWithoutSeq = stdStrName.substr(0, stdStrName.find_last_of('/'));
545 std::string prefix = stdStrNameWithoutSeq.substr(0, stdStrNameWithoutSeq.find_last_of('/'));
Zhenkai Zhu097bfe72012-06-05 14:30:17 -0700546#ifdef __DEBUG
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700547 std::cout <<"<<< updating scene for" << prefix << ": " << msg.from() << std::endl;
Zhenkai Zhu097bfe72012-06-05 14:30:17 -0700548#endif
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700549 if (msg.type() == SyncDemo::ChatMessage::LEAVE)
550 {
551 processRemove(prefix.c_str());
552 }
553 else
554 {
555 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
556 m_scene->msgReceived(prefix.c_str(), msg.from().c_str());
557 }
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700558 }
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700559 fitView();
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700560}
561
562void
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700563ChatDialog::processRemoveWrapper(std::string prefix)
564{
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700565#ifdef __DEBUG
566 std::cout << "Sync REMOVE signal received for prefix: " << prefix << std::endl;
567#endif
568 //emit removeReceived(prefix.c_str());
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700569}
570
571void
572ChatDialog::processRemove(QString prefix)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700573{
Zhenkai Zhu591e8c32012-09-26 11:57:50 -0700574#ifdef __DEBUG
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700575 std::cout << "<<< remove node for prefix" << prefix.toStdString() << std::endl;
Zhenkai Zhu591e8c32012-09-26 11:57:50 -0700576#endif
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700577 bool removed = m_scene->removeNode(prefix);
Zhenkai Zhu591e8c32012-09-26 11:57:50 -0700578 if (removed)
579 {
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700580 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu591e8c32012-09-26 11:57:50 -0700581 m_scene->plot(m_sock->getRootDigest().c_str());
582 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700583}
584
585void
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700586ChatDialog::formChatMessage(const QString &text, SyncDemo::ChatMessage &msg) {
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700587 msg.set_from(m_user.getNick().toStdString());
588 msg.set_to(m_user.getChatroom().toStdString());
Zhenkai Zhu767eac72012-10-08 11:20:57 -0700589 msg.set_data(text.toUtf8().constData());
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700590 time_t seconds = time(NULL);
591 msg.set_timestamp(seconds);
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700592 msg.set_type(SyncDemo::ChatMessage::CHAT);
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700593}
594
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700595void
Zhenkai Zhub5b78462012-09-28 14:10:37 -0700596ChatDialog::formControlMessage(SyncDemo::ChatMessage &msg, SyncDemo::ChatMessage::ChatMessageType type)
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700597{
598 msg.set_from(m_user.getNick().toStdString());
599 msg.set_to(m_user.getChatroom().toStdString());
600 time_t seconds = time(NULL);
601 msg.set_timestamp(seconds);
Zhenkai Zhub5b78462012-09-28 14:10:37 -0700602 msg.set_type(type);
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700603}
604
Zhenkai Zhu59245aa2012-09-26 16:07:04 -0700605static std::string chars("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM0123456789");
606
607QString
608ChatDialog::getRandomString()
609{
610 std::string randStr;
611 boost::random::random_device rng;
612 boost::random::uniform_int_distribution<> index_dist(0, chars.size() - 1);
613 for (int i = 0; i < 10; i ++)
614 {
615 randStr += chars[index_dist(rng)];
616 }
617 return randStr.c_str();
618}
619
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700620bool
Zhenkai Zhu6bda0bd2012-10-06 23:50:39 -0700621ChatDialog::getLocalPrefix()
622{
Zhenkai Zhu86581412012-10-08 16:58:39 -0700623// /*
624// * this method tries to use ccncat
625// * however, it does not work in Mac OS X app bundle
626// * it works well in command line though
627// */
628
629// std::string cmd = CCN_EXEC;
630// cmd += " -c -v ";
631// cmd += LOCAL_PREFIX_QUERY;
632// QString localPrefix;
633// #define MAX_PREFIX_LEN 100
634// FILE *fp = popen(cmd.c_str(), "r");
635// if (fp != NULL)
636// {
637// char prefix[MAX_PREFIX_LEN];
638// if (fgets(prefix, MAX_PREFIX_LEN, fp) != NULL)
639// {
640// localPrefix = prefix;
641// localPrefix.remove('\n');
642// }
643// else
644// {
645// localPrefix = DEFAULT_LOCAL_PREFIX;
646// }
647// pclose(fp);
648// }
649// else
650// {
651// localPrefix = DEFAULT_LOCAL_PREFIX;
652// }
653// return localPrefix;
Alexander Afanasyevebe118d2012-10-08 08:56:34 -0700654 std::cerr << "trying to get local prefix" << std::endl;
655
Zhenkai Zhu86581412012-10-08 16:58:39 -0700656 if (m_sock != NULL)
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700657 {
658 QString originPrefix = QString::fromStdString (m_sock->getLocalPrefix()).trimmed ();
659 std::cerr << "got: " << originPrefix.toStdString () << std::endl;
Zhenkai Zhuba707342012-10-08 16:20:15 -0700660
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700661 if (originPrefix != "" && m_user.getOriginPrefix () != originPrefix)
Zhenkai Zhu86581412012-10-08 16:58:39 -0700662 {
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700663 emit settingUpdated(m_user.getNick (), m_user.getChatroom (), originPrefix);
664 // prefix updated
665 return true;
Zhenkai Zhu86581412012-10-08 16:58:39 -0700666 }
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700667 }
668
669 // prefix not changed
670 return false;
671}
672
673void
674ChatDialog::updateLocalPrefix()
675{
676 getLocalPrefix();
Zhenkai Zhu6bda0bd2012-10-06 23:50:39 -0700677}
678
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700679bool
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700680ChatDialog::readSettings()
681{
682 QSettings s(ORGANIZATION, APPLICATION);
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700683 QString nick = s.value("nick", "").toString();
684 QString chatroom = s.value("chatroom", "").toString();
Zhenkai Zhu86581412012-10-08 16:58:39 -0700685 // QString originPrefix = s.value("originPrefix", "").toString();
Alexander Afanasyev5ddc68b2012-10-08 00:21:40 -0700686
Zhenkai Zhu86581412012-10-08 16:58:39 -0700687 // Sync::CcnxWrapperPtr wrapper = Sync::CcnxWrapper::Create ();
688 // QString originPrefix = QString::fromStdString (wrapper->getLocalPrefix());
689 // Sync::CcnxWrapper::Destroy ();
Alexander Afanasyev5ddc68b2012-10-08 00:21:40 -0700690
Zhenkai Zhu86581412012-10-08 16:58:39 -0700691 QString originPrefix = DEFAULT_LOCAL_PREFIX;
Alexander Afanasyev5ddc68b2012-10-08 00:21:40 -0700692
Zhenkai Zhu3974a492012-09-28 14:39:45 -0700693 m_minimaniho = s.value("minimaniho", false).toBool();
694 if (nick == "" || chatroom == "" || originPrefix == "") {
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700695 QTimer::singleShot(500, this, SLOT(buttonPressed()));
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700696 return false;
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700697 }
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700698 else {
699 m_user.setNick(nick);
700 m_user.setChatroom(chatroom);
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700701 m_user.setOriginPrefix(originPrefix);
Zhenkai Zhu3974a492012-09-28 14:39:45 -0700702 m_user.setPrefix(originPrefix + "/" + chatroom + "/" + getRandomString());
Zhenkai Zhu716fe852012-10-08 18:27:55 -0700703 m_scene->setCurrentPrefix(originPrefix + "/" + chatroom + "/" + getRandomString());
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700704 return true;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700705 }
Zhenkai Zhu3974a492012-09-28 14:39:45 -0700706
707// QTimer::singleShot(500, this, SLOT(buttonPressed()));
708 // return false;
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700709}
710
711void
712ChatDialog::writeSettings()
713{
714 QSettings s(ORGANIZATION, APPLICATION);
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700715 s.setValue("nick", m_user.getNick());
716 s.setValue("chatroom", m_user.getChatroom());
Zhenkai Zhu6bda0bd2012-10-06 23:50:39 -0700717 //s.setValue("originPrefix", m_user.getOriginPrefix());
Zhenkai Zhu3974a492012-09-28 14:39:45 -0700718 s.setValue("minimaniho", m_minimaniho);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700719}
720
721void
722ChatDialog::updateLabels()
723{
Zhenkai Zhu76ff02b2012-09-27 21:11:03 -0700724 QString settingDisp = QString("Chatroom: %1").arg(m_user.getChatroom());
725 infoLabel->setStyleSheet("QLabel {color: #630; font-size: 16px; font: bold \"Verdana\";}");
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700726 infoLabel->setText(settingDisp);
Zhenkai Zhu6bda0bd2012-10-06 23:50:39 -0700727 QString prefixDisp;
728 if (m_user.getPrefix().startsWith(DEFAULT_LOCAL_PREFIX))
729 {
730 prefixDisp = QString("<Warning: Auto config prefix failed.>\n <Prefix = %1>").arg(m_user.getPrefix());
731 prefixLabel->setStyleSheet("QLabel {color: red; font-size: 12px; font: bold \"Verdana\";}");
732 }
733 else
734 {
735 prefixDisp = QString("<Prefix = %1>").arg(m_user.getPrefix());
736 prefixLabel->setStyleSheet("QLabel {color: Green; font-size: 12px; font: bold \"Verdana\";}");
737 }
738 prefixLabel->setText(prefixDisp);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700739}
740
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700741void
742ChatDialog::returnPressed()
743{
744 QString text = lineEdit->text();
745 if (text.isEmpty())
746 return;
747
Zhenkai Zhub6338822012-05-31 13:27:24 -0700748 lineEdit->clear();
749
Zhenkai Zhu22c7d4d2012-10-09 12:29:32 -0700750 if (text.startsWith("boruoboluomi"))
751 {
752 reapButton->show();
753 fitView();
754 return;
755 }
756
757 if (text.startsWith("minimanihong"))
758 {
759 reapButton->hide();
760 fitView();
761 return;
762 }
763
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700764 SyncDemo::ChatMessage msg;
765 formChatMessage(text, msg);
766
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700767 appendMessage(msg);
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700768
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700769 sendMsg(msg);
770
771 fitView();
772}
773
774void
775ChatDialog::sendMsg(SyncDemo::ChatMessage &msg)
776{
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700777 // send msg
778 size_t size = msg.ByteSize();
779 char *buf = new char[size];
780 msg.SerializeToArray(buf, size);
781 if (!msg.IsInitialized())
782 {
783 std::cerr << "Errrrr.. msg was not probally initialized "<<__FILE__ <<":"<<__LINE__<<". what is happening?" << std::endl;
784 abort();
785 }
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700786 m_sock->publishRaw(m_user.getPrefix().toStdString(), m_session, buf, size, FRESHNESS);
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700787
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700788 delete buf;
789
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700790 m_lastMsgTime = time(NULL);
791
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700792 int nextSequence = m_sock->getNextSeq(m_user.getPrefix().toStdString(), m_session);
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700793 Sync::MissingDataInfo mdi = {m_user.getPrefix().toStdString(), Sync::SeqNo(0), Sync::SeqNo(nextSequence - 1)};
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700794 std::vector<Sync::MissingDataInfo> v;
795 v.push_back(mdi);
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700796 {
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700797 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700798 m_scene->processUpdate(v, m_sock->getRootDigest().c_str());
799 m_scene->msgReceived(m_user.getPrefix(), m_user.getNick());
800 }
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700801}
802
803void
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700804ChatDialog::sendJoin()
805{
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700806 m_joined = true;
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700807 SyncDemo::ChatMessage msg;
Zhenkai Zhub5b78462012-09-28 14:10:37 -0700808 formControlMessage(msg, SyncDemo::ChatMessage::JOIN);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700809 sendMsg(msg);
Zhenkai Zhuc61dbc22012-10-08 11:36:37 -0700810 boost::random::random_device rng;
811 boost::random::uniform_int_distribution<> uniform(1, FRESHNESS / 5 * 1000);
812 m_randomizedInterval = HELLO_INTERVAL * 1000 + uniform(rng);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700813 QTimer::singleShot(m_randomizedInterval, this, SLOT(sendHello()));
814}
815
816void
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700817ChatDialog::sendHello()
818{
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700819 time_t now = time(NULL);
820 int elapsed = now - m_lastMsgTime;
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700821 if (elapsed >= m_randomizedInterval / 1000)
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700822 {
823 SyncDemo::ChatMessage msg;
Zhenkai Zhub5b78462012-09-28 14:10:37 -0700824 formControlMessage(msg, SyncDemo::ChatMessage::HELLO);
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700825 sendMsg(msg);
Zhenkai Zhuc61dbc22012-10-08 11:36:37 -0700826 boost::random::random_device rng;
827 boost::random::uniform_int_distribution<> uniform(1, FRESHNESS / 5 * 1000);
828 m_randomizedInterval = HELLO_INTERVAL * 1000 + uniform(rng);
Zhenkai Zhuee5c90f2012-09-27 14:05:41 -0700829 QTimer::singleShot(m_randomizedInterval, this, SLOT(sendHello()));
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700830 }
831 else
832 {
Zhenkai Zhuee5c90f2012-09-27 14:05:41 -0700833 QTimer::singleShot((m_randomizedInterval - elapsed * 1000), this, SLOT(sendHello()));
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700834 }
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700835}
836
837void
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700838ChatDialog::buttonPressed()
839{
Alexander Afanasyev5ddc68b2012-10-08 00:21:40 -0700840 Sync::SyncLogic &logic = m_sock->getLogic ();
841 logic.printState ();
842
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700843 SettingDialog dialog(this, m_user.getNick(), m_user.getChatroom(), m_user.getOriginPrefix());
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700844 connect(&dialog, SIGNAL(updated(QString, QString, QString)), this, SLOT(settingUpdated(QString, QString, QString)));
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700845 dialog.exec();
Zhenkai Zhue837f792012-06-05 20:47:54 -0700846 QTimer::singleShot(100, this, SLOT(checkSetting()));
847}
848
Zhenkai Zhub60b7e12012-09-28 11:34:21 -0700849void ChatDialog::treeButtonPressed()
850{
851 if (treeViewer->isVisible())
852 {
853 treeViewer->hide();
854 treeButton->setText("Show Sync Tree");
855 }
856 else
857 {
858 treeViewer->show();
859 treeButton->setText("Hide Sync Tree");
860 }
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700861
862 fitView();
Zhenkai Zhub60b7e12012-09-28 11:34:21 -0700863}
864
Zhenkai Zhu0e7a9b22012-10-05 17:55:17 -0700865void ChatDialog::enableTreeDisplay()
866{
867 treeButton->setEnabled(true);
868 treeViewer->show();
869 fitView();
870}
871
872void ChatDialog::disableTreeDisplay()
873{
874 treeButton->setEnabled(false);
875 treeViewer->hide();
876 fitView();
877}
878
Zhenkai Zhue837f792012-06-05 20:47:54 -0700879void
880ChatDialog::checkSetting()
881{
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700882 if (m_user.getOriginPrefix().isEmpty() || m_user.getNick().isEmpty() || m_user.getChatroom().isEmpty())
Zhenkai Zhue837f792012-06-05 20:47:54 -0700883 {
884 buttonPressed();
885 }
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -0700886}
Zhenkai Zhue08afe02012-05-31 15:49:07 -0700887
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700888void
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700889ChatDialog::settingUpdated(QString nick, QString chatroom, QString originPrefix)
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700890{
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700891 QString randString = getRandomString();
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700892 bool needWrite = false;
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700893 bool needFresh = false;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700894 if (!nick.isEmpty() && nick != m_user.getNick()) {
895 m_user.setNick(nick);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700896 needWrite = true;
897 }
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -0700898 QString oldPrefix = m_user.getPrefix();
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700899 if (!originPrefix.isEmpty() && originPrefix != m_user.getOriginPrefix()) {
900 m_user.setOriginPrefix(originPrefix);
901 m_user.setPrefix(originPrefix + "/" + m_user.getChatroom() + "/" + randString);
Zhenkai Zhu716fe852012-10-08 18:27:55 -0700902 m_scene->setCurrentPrefix(originPrefix + "/" + m_user.getChatroom() + "/" + randString);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700903 needWrite = true;
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700904 needFresh = true;
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700905 }
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700906 if (!chatroom.isEmpty() && chatroom != m_user.getChatroom()) {
907 m_user.setChatroom(chatroom);
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700908 m_user.setPrefix(m_user.getOriginPrefix() + "/" + chatroom + "/" + randString);
Zhenkai Zhu716fe852012-10-08 18:27:55 -0700909 m_scene->setCurrentPrefix(m_user.getOriginPrefix() + "/" + chatroom + "/" + randString);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700910 needWrite = true;
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700911 needFresh = true;
912 }
913
914 if (needFresh)
915 {
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700916
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700917 {
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700918 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700919 m_scene->clearAll();
920 m_scene->plot("Empty");
921 }
Zhenkai Zhucc4c2c02012-09-27 21:24:37 -0700922
923 textEdit->clear();
924
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700925 if (m_sock != NULL)
926 {
Zhenkai Zhu77fc8f22012-10-08 15:12:56 -0700927 // keep the new prefix
928 QString newPrefix = m_user.getPrefix();
929 // send leave for the old
930 m_user.setPrefix(oldPrefix);
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700931 // there is no point to send leave if we haven't joined yet
932 if (m_joined)
933 {
934 sendLeave();
935 }
Zhenkai Zhu77fc8f22012-10-08 15:12:56 -0700936 // resume new prefix
937 m_user.setPrefix(newPrefix);
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -0700938 Sync::CcnxWrapperPtr handle = Sync::CcnxWrapper::Create();
Zhenkai Zhu5ee10092012-10-09 12:48:52 -0700939 // handle->clearInterestFilter(oldPrefix.toStdString());
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -0700940 m_history.clear();
941 m_historyInitialized = false;
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700942 delete m_sock;
943 m_sock = NULL;
944 }
945 std::string syncPrefix = BROADCAST_PREFIX_FOR_SYNC_DEMO;
946 syncPrefix += "/";
947 syncPrefix += m_user.getChatroom().toStdString();
Zhenkai Zhua4fb1242012-06-05 20:26:05 -0700948 try
949 {
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700950 m_sock = new Sync::SyncAppSocket(syncPrefix, bind(&ChatDialog::processTreeUpdateWrapper, this, _1, _2), bind(&ChatDialog::processRemoveWrapper, this, _1));
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -0700951 Sync::CcnxWrapperPtr handle = Sync::CcnxWrapper::Create();
952 handle->setInterestFilter(m_user.getPrefix().toStdString(), bind(&ChatDialog::respondHistoryRequest, this, _1));
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700953 QTimer::singleShot(600, this, SLOT(sendJoin()));
Zhenkai Zhu78799ea2012-10-08 11:51:56 -0700954 m_timer->start(FRESHNESS * 1000);
Zhenkai Zhu0e7a9b22012-10-05 17:55:17 -0700955 disableTreeDisplay();
956 QTimer::singleShot(2200, this, SLOT(enableTreeDisplay()));
Zhenkai Zhua4fb1242012-06-05 20:26:05 -0700957 }
958 catch (Sync::CcnxOperationException ex)
959 {
Zhenkai Zhu0b3fa332012-09-27 21:58:43 -0700960 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 -0700961 std::exit(1);
962 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700963
964 fitView();
965
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700966 }
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700967
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700968 if (needWrite) {
969 writeSettings();
970 updateLabels();
971 }
972}
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700973
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700974void
975ChatDialog::iconActivated(QSystemTrayIcon::ActivationReason reason)
976{
977 switch (reason)
978 {
979 case QSystemTrayIcon::Trigger:
980 case QSystemTrayIcon::DoubleClick:
981 break;
982 case QSystemTrayIcon::MiddleClick:
983 // showMessage();
984 break;
985 default:;
986 }
987}
988
989void
990ChatDialog::showMessage(QString from, QString data)
991{
992 // std::cout <<"Showing Message: " << from.toStdString() << ": " << data.toStdString() << std::endl;
993 if (!isActiveWindow())
994 {
995 trayIcon->showMessage(QString("Chatroom %1 has a new message").arg(m_user.getChatroom()), QString("<%1>: %2").arg(from).arg(data), QSystemTrayIcon::Information, 20000);
996 trayIcon->setIcon(QIcon(":/images/note.png"));
997 }
998}
999
1000void
1001ChatDialog::messageClicked()
1002{
1003 this->showMaximized();
1004}
1005
1006void
1007ChatDialog::createActions()
1008{
1009 minimizeAction = new QAction(tr("Mi&nimize"), this);
1010 connect(minimizeAction, SIGNAL(triggered()), this, SLOT(hide()));
1011
1012 maximizeAction = new QAction(tr("Ma&ximize"), this);
1013 connect(maximizeAction, SIGNAL(triggered()), this, SLOT(showMaximized()));
1014
1015 restoreAction = new QAction(tr("&Restore"), this);
1016 connect(restoreAction, SIGNAL(triggered()), this, SLOT(showNormal()));
1017
1018 quitAction = new QAction(tr("Quit"), this);
1019 connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
1020}
1021
1022void
1023ChatDialog::createTrayIcon()
1024{
1025 trayIconMenu = new QMenu(this);
1026 trayIconMenu->addAction(minimizeAction);
1027 trayIconMenu->addAction(maximizeAction);
1028 trayIconMenu->addAction(restoreAction);
1029 trayIconMenu->addSeparator();
1030 trayIconMenu->addAction(quitAction);
1031
1032 trayIcon = new QSystemTrayIcon(this);
1033 trayIcon->setContextMenu(trayIconMenu);
1034
1035 QIcon icon(":/images/icon_small.png");
1036 trayIcon->setIcon(icon);
1037 setWindowIcon(icon);
Zhenkai Zhu0b3fa332012-09-27 21:58:43 -07001038 trayIcon->setToolTip("Chronos System Tray Icon");
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -07001039 trayIcon->setVisible(true);
1040}
1041
Zhenkai Zhud13acd02012-06-04 15:25:20 -07001042void
1043ChatDialog::resizeEvent(QResizeEvent *e)
1044{
1045 fitView();
1046}
1047
1048void
1049ChatDialog::showEvent(QShowEvent *e)
1050{
1051 fitView();
1052}
1053
1054void
1055ChatDialog::fitView()
1056{
Zhenkai Zhu9036e032012-09-27 20:59:33 -07001057 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu21d75f92012-06-04 21:23:34 -07001058 QRectF rect = m_scene->itemsBoundingRect();
1059 m_scene->setSceneRect(rect);
Zhenkai Zhu82a62752012-06-04 17:11:04 -07001060 treeViewer->fitInView(m_scene->itemsBoundingRect(), Qt::KeepAspectRatio);
Zhenkai Zhud13acd02012-06-04 15:25:20 -07001061}