blob: 79ac9d07cf039eea700551adaf1eae63cf182885 [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")));
51
Zhenkai Zhu86df7412012-09-27 16:30:20 -070052 createActions();
53 createTrayIcon();
54 m_timer = new QTimer(this);
55 connect(lineEdit, SIGNAL(returnPressed()), this, SLOT(returnPressed()));
56 connect(setButton, SIGNAL(pressed()), this, SLOT(buttonPressed()));
Zhenkai Zhub60b7e12012-09-28 11:34:21 -070057 connect(treeButton, SIGNAL(pressed()), this, SLOT(treeButtonPressed()));
Zhenkai Zhu7f52e1b2012-10-09 11:45:36 -070058 connect(reapButton, SIGNAL(pressed()), this, SLOT(summonReaper()));
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -070059 connect(refreshButton, SIGNAL(pressed()), this, SLOT(updateLocalPrefix()));
Zhenkai Zhu24ec4722012-10-07 17:56:38 -070060 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 -070061 connect(this, SIGNAL(treeUpdated(const std::vector<Sync::MissingDataInfo>)), this, SLOT(processTreeUpdate(const std::vector<Sync::MissingDataInfo>)));
Zhenkai Zhu86df7412012-09-27 16:30:20 -070062 connect(m_timer, SIGNAL(timeout()), this, SLOT(replot()));
63 connect(m_scene, SIGNAL(replot()), this, SLOT(replot()));
64 connect(trayIcon, SIGNAL(messageClicked()), this, SLOT(showNormal()));
65 connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
Zhenkai Zhu25e33e52012-09-28 13:00:07 -070066 connect(m_scene, SIGNAL(rosterChanged(QStringList)), this, SLOT(updateRosterList(QStringList)));
Zhenkai Zhu86df7412012-09-27 16:30:20 -070067
Zhenkai Zhu82a62752012-06-04 17:11:04 -070068 // create sync socket
69 if(!m_user.getChatroom().isEmpty()) {
70 std::string syncPrefix = BROADCAST_PREFIX_FOR_SYNC_DEMO;
71 syncPrefix += "/";
72 syncPrefix += m_user.getChatroom().toStdString();
Zhenkai Zhua4fb1242012-06-05 20:26:05 -070073 try
74 {
Alexander Afanasyev288edd82012-10-04 17:07:56 -070075 m_sock = new Sync::SyncAppSocket(syncPrefix,
76 bind(&ChatDialog::processTreeUpdateWrapper, this, _1, _2),
77 bind(&ChatDialog::processRemoveWrapper, this, _1));
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -070078 Sync::CcnxWrapperPtr handle = Sync::CcnxWrapper::Create();
79 handle->setInterestFilter(m_user.getPrefix().toStdString(), bind(&ChatDialog::respondHistoryRequest, this, _1));
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -070080 //QTimer::singleShot(100, this, SLOT(getLocalPrefix()));
81 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()));
89 }
90 else
91 {
92 // this socket is going to be destroyed anyway
93 // why bother doing the following steps
Alexander Afanasyevebe118d2012-10-08 08:56:34 -070094
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -070095 // the same steps would be performed for another socket
96 // in settingUpdated
97 }
Zhenkai Zhua4fb1242012-06-05 20:26:05 -070098 }
99 catch (Sync::CcnxOperationException ex)
100 {
Zhenkai Zhu0b3fa332012-09-27 21:58:43 -0700101 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 -0700102 std::exit(1);
103 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700104 }
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700105
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700106}
107
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700108ChatDialog::~ChatDialog()
109{
110 if (m_sock != NULL)
111 {
Zhenkai Zhucf024442012-10-05 10:33:08 -0700112 sendLeave();
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700113 delete m_sock;
114 m_sock = NULL;
115 }
116}
117
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700118void
Zhenkai Zhucf024442012-10-05 10:33:08 -0700119ChatDialog::sendLeave()
120{
121 SyncDemo::ChatMessage msg;
122 formControlMessage(msg, SyncDemo::ChatMessage::LEAVE);
123 sendMsg(msg);
124 usleep(500000);
125 m_sock->remove(m_user.getPrefix().toStdString());
126 usleep(5000);
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700127 m_joined = false;
Zhenkai Zhucf024442012-10-05 10:33:08 -0700128#ifdef __DEBUG
129 std::cout << "Sync REMOVE signal sent" << std::endl;
130#endif
131}
132
133void
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700134ChatDialog::replot()
135{
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700136 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700137 m_scene->plot(m_sock->getRootDigest().c_str());
Zhenkai Zhuc9e4e3c2012-10-02 11:47:31 -0700138 fitView();
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700139}
140
Zhenkai Zhu6082ede2012-09-27 17:28:46 -0700141void
Zhenkai Zhu7f52e1b2012-10-09 11:45:36 -0700142ChatDialog::summonReaper()
143{
144 Sync::SyncLogic &logic = m_sock->getLogic ();
145 std::map<std::string, bool> branches = logic.getBranchPrefixes();
146 QMap<QString, DisplayUserPtr> roster = m_scene->getRosterFull();
147
148 m_zombieList.clear();
149
150 QMapIterator<QString, DisplayUserPtr> it(roster);
151 std::map<std::string, bool>::iterator mapIt;
152 while(it.hasNext())
153 {
154 it.next();
155 DisplayUserPtr p = it.value();
156 if (p != DisplayUserNullPtr)
157 {
158 mapIt = branches.find(p->getPrefix().toStdString());
159 if (mapIt != branches.end())
160 {
161 mapIt->second = true;
162 }
163 }
164 }
165
166 for (mapIt = branches.begin(); mapIt != branches.end(); ++mapIt)
167 {
168 // this is zombie. all active users should have been marked true
169 if (! mapIt->second)
170 {
171 m_zombieList.append(mapIt->first.c_str());
172 }
173 }
174
175 m_zombieIndex = 0;
176
177 // start reaping
178 reap();
179}
180
181void
182ChatDialog::reap()
183{
184 if (m_zombieIndex < m_zombieList.size())
185 {
186 std::string prefix = m_zombieList.at(m_zombieIndex).toStdString();
187 m_sock->remove(prefix);
188 std::cout << "Reaped: prefix = " << prefix << std::endl;
189 m_zombieIndex++;
190 // reap again in 10 seconds
191 QTimer::singleShot(10000, this, SLOT(reap()));
192 }
193}
194
195void
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700196ChatDialog::updateRosterList(QStringList staleUserList)
Zhenkai Zhu6082ede2012-09-27 17:28:46 -0700197{
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700198 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu6082ede2012-09-27 17:28:46 -0700199 QStringList rosterList = m_scene->getRosterList();
200 m_rosterModel->setStringList(rosterList);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700201 QString user;
202 QStringListIterator it(staleUserList);
203 while(it.hasNext())
204 {
Zhenkai Zhu32cbdce2012-10-02 11:09:38 -0700205 std::string nick = it.next().toStdString();
206 if (nick.empty())
207 continue;
208
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700209 SyncDemo::ChatMessage msg;
Zhenkai Zhub5b78462012-09-28 14:10:37 -0700210 formControlMessage(msg, SyncDemo::ChatMessage::LEAVE);
Zhenkai Zhu32cbdce2012-10-02 11:09:38 -0700211 msg.set_from(nick);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700212 appendMessage(msg);
213 }
Zhenkai Zhu6082ede2012-09-27 17:28:46 -0700214}
215
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700216void
217ChatDialog::setVisible(bool visible)
218{
219 minimizeAction->setEnabled(visible);
220 maximizeAction->setEnabled(!isMaximized());
221 restoreAction->setEnabled(isMaximized() || !visible);
222 QDialog::setVisible(visible);
223}
224
225void
226ChatDialog::closeEvent(QCloseEvent *e)
227{
Zhenkai Zhu3974a492012-09-28 14:39:45 -0700228 if (trayIcon->isVisible() && !m_minimaniho)
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700229 {
Zhenkai Zhu0b3fa332012-09-27 21:58:43 -0700230 QMessageBox::information(this, tr("Chronos"),
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700231 tr("The program will keep running in the "
232 "system tray. To terminate the program"
233 "choose <b>Quit</b> in the context memu"
234 "of the system tray entry."));
235 hide();
236 e->ignore();
Zhenkai Zhu3974a492012-09-28 14:39:45 -0700237 m_minimaniho = true;
238 writeSettings();
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700239 }
240}
241
242void
243ChatDialog::changeEvent(QEvent *e)
244{
245 switch(e->type())
246 {
247 case QEvent::ActivationChange:
248 if (isActiveWindow())
249 {
250 trayIcon->setIcon(QIcon(":/images/icon_small.png"));
251 }
252 break;
253 default:
254 break;
255 }
256}
257
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700258void
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700259ChatDialog::appendMessage(const SyncDemo::ChatMessage msg, bool isHistory)
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700260{
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700261 boost::recursive_mutex::scoped_lock lock(m_msgMutex);
Zhenkai Zhub6338822012-05-31 13:27:24 -0700262
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700263 if (msg.type() == SyncDemo::ChatMessage::CHAT)
Zhenkai Zhub98e6022012-09-27 13:48:23 -0700264 {
Zhenkai Zhub98e6022012-09-27 13:48:23 -0700265
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700266 if (!msg.has_data())
Zhenkai Zhub98e6022012-09-27 13:48:23 -0700267 {
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700268 return;
Zhenkai Zhub98e6022012-09-27 13:48:23 -0700269 }
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700270
271 if (msg.from().empty() || msg.data().empty())
272 {
273 return;
274 }
275
276 if (!msg.has_timestamp())
277 {
278 return;
279 }
280
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -0700281 if (m_history.size() == MAX_HISTORY_ENTRY)
282 {
283 m_history.dequeue();
284 }
285
286 m_history.enqueue(msg);
287
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700288 QTextCharFormat nickFormat;
289 nickFormat.setForeground(Qt::darkGreen);
290 nickFormat.setFontWeight(QFont::Bold);
291 nickFormat.setFontUnderline(true);
292 nickFormat.setUnderlineColor(Qt::gray);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700293
294 QTextCursor cursor(textEdit->textCursor());
295 cursor.movePosition(QTextCursor::End);
296 QTextTableFormat tableFormat;
297 tableFormat.setBorder(0);
298 QTextTable *table = cursor.insertTable(1, 2, tableFormat);
299 QString from = QString("%1 ").arg(msg.from().c_str());
300 QTextTableCell fromCell = table->cellAt(0, 0);
301 fromCell.setFormat(nickFormat);
302 fromCell.firstCursorPosition().insertText(from);
Zhenkai Zhu560ef1b2012-09-28 14:23:33 -0700303
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700304 time_t timestamp = msg.timestamp();
Zhenkai Zhu560ef1b2012-09-28 14:23:33 -0700305 printTimeInCell(table, timestamp);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700306
307 QTextCursor nextCursor(textEdit->textCursor());
308 nextCursor.movePosition(QTextCursor::End);
309 table = nextCursor.insertTable(1, 1, tableFormat);
Zhenkai Zhu767eac72012-10-08 11:20:57 -0700310 table->cellAt(0, 0).firstCursorPosition().insertText(QString::fromUtf8(msg.data().c_str()));
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700311 if (!isHistory)
312 {
Zhenkai Zhu767eac72012-10-08 11:20:57 -0700313 showMessage(from, QString::fromUtf8(msg.data().c_str()));
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700314 }
Zhenkai Zhub98e6022012-09-27 13:48:23 -0700315 }
316
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700317 if (msg.type() == SyncDemo::ChatMessage::JOIN || msg.type() == SyncDemo::ChatMessage::LEAVE)
318 {
319 QTextCharFormat nickFormat;
320 nickFormat.setForeground(Qt::gray);
321 nickFormat.setFontWeight(QFont::Bold);
322 nickFormat.setFontUnderline(true);
323 nickFormat.setUnderlineColor(Qt::gray);
Zhenkai Zhub98e6022012-09-27 13:48:23 -0700324
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700325 QTextCursor cursor(textEdit->textCursor());
326 cursor.movePosition(QTextCursor::End);
327 QTextTableFormat tableFormat;
328 tableFormat.setBorder(0);
329 QTextTable *table = cursor.insertTable(1, 2, tableFormat);
330 QString action;
331 if (msg.type() == SyncDemo::ChatMessage::JOIN)
332 {
333 action = "enters room";
334 }
335 else
336 {
337 action = "leaves room";
338 }
339
340 QString from = QString("%1 %2 ").arg(msg.from().c_str()).arg(action);
341 QTextTableCell fromCell = table->cellAt(0, 0);
342 fromCell.setFormat(nickFormat);
343 fromCell.firstCursorPosition().insertText(from);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700344
Zhenkai Zhu560ef1b2012-09-28 14:23:33 -0700345 time_t timestamp = msg.timestamp();
346 printTimeInCell(table, timestamp);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700347 }
348
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700349 QScrollBar *bar = textEdit->verticalScrollBar();
350 bar->setValue(bar->maximum());
351}
352
Zhenkai Zhu560ef1b2012-09-28 14:23:33 -0700353void
354ChatDialog::printTimeInCell(QTextTable *table, time_t timestamp)
355{
356 QTextCharFormat timeFormat;
357 timeFormat.setForeground(Qt::gray);
358 timeFormat.setFontUnderline(true);
359 timeFormat.setUnderlineColor(Qt::gray);
360 QTextTableCell timeCell = table->cellAt(0, 1);
361 timeCell.setFormat(timeFormat);
362 timeCell.firstCursorPosition().insertText(formatTime(timestamp));
363}
364
365QString
366ChatDialog::formatTime(time_t timestamp)
367{
368 struct tm *tm_time = localtime(&timestamp);
369 int hour = tm_time->tm_hour;
370 QString amOrPM;
371 if (hour > 12)
372 {
373 hour -= 12;
374 amOrPM = "PM";
375 }
376 else
377 {
378 amOrPM = "AM";
379 if (hour == 0)
380 {
381 hour = 12;
382 }
383 }
384
385 char textTime[12];
386 sprintf(textTime, "%d:%02d:%02d %s", hour, tm_time->tm_min, tm_time->tm_sec, amOrPM.toStdString().c_str());
387 return QString(textTime);
388}
389
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700390void
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700391ChatDialog::processTreeUpdateWrapper(const std::vector<Sync::MissingDataInfo> v, Sync::SyncAppSocket *sock)
392{
393 emit treeUpdated(v);
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700394#ifdef __DEBUG
395 std::cout << "<<< Tree update signal emitted" << std::endl;
396#endif
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700397}
398
399void
400ChatDialog::processTreeUpdate(const std::vector<Sync::MissingDataInfo> v)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700401{
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700402#ifdef __DEBUG
403 std::cout << "<<< processing Tree Update" << std::endl;
404#endif
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700405 if (v.empty())
406 {
407 return;
408 }
409
410 // reflect the changes on digest tree
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700411 {
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700412 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700413 m_scene->processUpdate(v, m_sock->getRootDigest().c_str());
414 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700415
416 int n = v.size();
417 int totalMissingPackets = 0;
418 for (int i = 0; i < n; i++)
419 {
420 totalMissingPackets += v[i].high.getSeq() - v[i].low.getSeq() + 1;
421 }
422
Zhenkai Zhubb198112012-09-27 11:31:42 -0700423 for (int i = 0; i < n; i++)
424 {
425 if (totalMissingPackets < 4)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700426 {
427 for (Sync::SeqNo seq = v[i].low; seq <= v[i].high; ++seq)
428 {
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700429 m_sock->fetchRaw(v[i].prefix, seq, bind(&ChatDialog::processDataWrapper, this, _1, _2, _3), 2);
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700430#ifdef __DEBUG
431 std::cout << "<<< Fetching " << v[i].prefix << "/" <<seq.getSession() <<"/" << seq.getSeq() << std::endl;
432#endif
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700433 }
434 }
Zhenkai Zhubb198112012-09-27 11:31:42 -0700435 else
436 {
437 m_sock->fetchRaw(v[i].prefix, v[i].high, bind(&ChatDialog::processDataNoShowWrapper, this, _1, _2, _3), 2);
438 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700439 }
440
441 // adjust the view
442 fitView();
443
444}
445
446void
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700447ChatDialog::processDataWrapper(std::string name, const char *buf, size_t len)
448{
Zhenkai Zhuae29f5a2012-10-05 17:28:04 -0700449 char *tempBuf = new char[len];
450 memcpy(tempBuf, buf, len);
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700451 emit dataReceived(name.c_str(), tempBuf, len, true, false);
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700452#ifdef __DEBUG
453 std::cout <<"<<< " << name << " fetched" << std::endl;
454#endif
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700455}
456
457void
Zhenkai Zhubb198112012-09-27 11:31:42 -0700458ChatDialog::processDataNoShowWrapper(std::string name, const char *buf, size_t len)
459{
Zhenkai Zhuae29f5a2012-10-05 17:28:04 -0700460 char *tempBuf = new char[len];
461 memcpy(tempBuf, buf, len);
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700462 emit dataReceived(name.c_str(), tempBuf, len, false, false);
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -0700463
464 if (!m_historyInitialized)
465 {
466 fetchHistory(name);
467 m_historyInitialized = true;
468 }
469}
470
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700471void
472ChatDialog::processDataHistoryWrapper(std::string name, const char *buf, size_t len)
473{
474 char *tempBuf = new char[len];
475 memcpy(tempBuf, buf, len);
476 emit dataReceived(name.c_str(), tempBuf, len, true, true);
477}
478
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -0700479void
480ChatDialog::fetchHistory(std::string name)
481{
482 std::string nameWithoutSeq = name.substr(0, name.find_last_of('/'));
483 std::string prefix = nameWithoutSeq.substr(0, nameWithoutSeq.find_last_of('/'));
484 prefix += "/history";
485 Sync::CcnxWrapperPtr handle = Sync::CcnxWrapper::Create();
486 QString randomString = getRandomString();
487 for (int i = 0; i < MAX_HISTORY_ENTRY; i++)
488 {
489 QString interest = QString("%1/%2/%3").arg(prefix.c_str()).arg(randomString).arg(i);
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700490 handle->sendInterest(interest.toStdString(), bind(&ChatDialog::processDataHistoryWrapper, this, _1, _2, _3));
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -0700491 }
492}
493
494void
495ChatDialog::respondHistoryRequest(std::string interest)
496{
497 std::string seqStr = interest.substr(interest.find_last_of('/') + 1);
498 int seq = boost::lexical_cast<int>(seqStr);
499 if (seq >= 0 && seq < m_history.size())
500 {
501 Sync::CcnxWrapperPtr handle = Sync::CcnxWrapper::Create();
502 SyncDemo::ChatMessage msg = m_history.at(seq);
503 size_t size = msg.ByteSize();
504 char *buf = new char[size];
505 msg.SerializeToArray(buf, size);
506 handle->publishRawData(interest, buf, size, 1);
507 delete buf;
508 }
Zhenkai Zhubb198112012-09-27 11:31:42 -0700509}
510
511void
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700512ChatDialog::processData(QString name, const char *buf, size_t len, bool show, bool isHistory)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700513{
514 SyncDemo::ChatMessage msg;
Zhenkai Zhuef8d0632012-10-05 10:24:55 -0700515 bool corrupted = false;
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700516 if (!msg.ParseFromArray(buf, len))
517 {
Zhenkai Zhubb198112012-09-27 11:31:42 -0700518 std::cerr << "Errrrr.. Can not parse msg with name: " << name.toStdString() << ". what is happening?" << std::endl;
Zhenkai Zhuef8d0632012-10-05 10:24:55 -0700519 // nasty stuff: as a remedy, we'll form some standard msg for inparsable msgs
520 msg.set_from("inconnu");
521 msg.set_type(SyncDemo::ChatMessage::OTHER);
522 corrupted = true;
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700523 }
524
Zhenkai Zhuae29f5a2012-10-05 17:28:04 -0700525 delete [] buf;
526 buf = NULL;
527
Zhenkai Zhu10ccb5a2012-06-04 21:55:14 -0700528 // display msg received from network
529 // we have to do so; this function is called by ccnd thread
530 // so if we call appendMsg directly
531 // Qt crash as "QObject: Cannot create children for a parent that is in a different thread"
532 // the "cannonical" way to is use signal-slot
Zhenkai Zhuef8d0632012-10-05 10:24:55 -0700533 if (show && !corrupted)
Zhenkai Zhubb198112012-09-27 11:31:42 -0700534 {
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700535 appendMessage(msg, isHistory);
Zhenkai Zhubb198112012-09-27 11:31:42 -0700536 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700537
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700538 if (!isHistory)
539 {
540 // update the tree view
541 std::string stdStrName = name.toStdString();
542 std::string stdStrNameWithoutSeq = stdStrName.substr(0, stdStrName.find_last_of('/'));
543 std::string prefix = stdStrNameWithoutSeq.substr(0, stdStrNameWithoutSeq.find_last_of('/'));
Zhenkai Zhu097bfe72012-06-05 14:30:17 -0700544#ifdef __DEBUG
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700545 std::cout <<"<<< updating scene for" << prefix << ": " << msg.from() << std::endl;
Zhenkai Zhu097bfe72012-06-05 14:30:17 -0700546#endif
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700547 if (msg.type() == SyncDemo::ChatMessage::LEAVE)
548 {
549 processRemove(prefix.c_str());
550 }
551 else
552 {
553 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
554 m_scene->msgReceived(prefix.c_str(), msg.from().c_str());
555 }
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700556 }
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700557 fitView();
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700558}
559
560void
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700561ChatDialog::processRemoveWrapper(std::string prefix)
562{
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700563#ifdef __DEBUG
564 std::cout << "Sync REMOVE signal received for prefix: " << prefix << std::endl;
565#endif
566 //emit removeReceived(prefix.c_str());
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700567}
568
569void
570ChatDialog::processRemove(QString prefix)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700571{
Zhenkai Zhu591e8c32012-09-26 11:57:50 -0700572#ifdef __DEBUG
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700573 std::cout << "<<< remove node for prefix" << prefix.toStdString() << std::endl;
Zhenkai Zhu591e8c32012-09-26 11:57:50 -0700574#endif
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700575 bool removed = m_scene->removeNode(prefix);
Zhenkai Zhu591e8c32012-09-26 11:57:50 -0700576 if (removed)
577 {
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700578 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu591e8c32012-09-26 11:57:50 -0700579 m_scene->plot(m_sock->getRootDigest().c_str());
580 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700581}
582
583void
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700584ChatDialog::formChatMessage(const QString &text, SyncDemo::ChatMessage &msg) {
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700585 msg.set_from(m_user.getNick().toStdString());
586 msg.set_to(m_user.getChatroom().toStdString());
Zhenkai Zhu767eac72012-10-08 11:20:57 -0700587 msg.set_data(text.toUtf8().constData());
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700588 time_t seconds = time(NULL);
589 msg.set_timestamp(seconds);
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700590 msg.set_type(SyncDemo::ChatMessage::CHAT);
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700591}
592
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700593void
Zhenkai Zhub5b78462012-09-28 14:10:37 -0700594ChatDialog::formControlMessage(SyncDemo::ChatMessage &msg, SyncDemo::ChatMessage::ChatMessageType type)
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700595{
596 msg.set_from(m_user.getNick().toStdString());
597 msg.set_to(m_user.getChatroom().toStdString());
598 time_t seconds = time(NULL);
599 msg.set_timestamp(seconds);
Zhenkai Zhub5b78462012-09-28 14:10:37 -0700600 msg.set_type(type);
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700601}
602
Zhenkai Zhu59245aa2012-09-26 16:07:04 -0700603static std::string chars("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM0123456789");
604
605QString
606ChatDialog::getRandomString()
607{
608 std::string randStr;
609 boost::random::random_device rng;
610 boost::random::uniform_int_distribution<> index_dist(0, chars.size() - 1);
611 for (int i = 0; i < 10; i ++)
612 {
613 randStr += chars[index_dist(rng)];
614 }
615 return randStr.c_str();
616}
617
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700618bool
Zhenkai Zhu6bda0bd2012-10-06 23:50:39 -0700619ChatDialog::getLocalPrefix()
620{
Zhenkai Zhu86581412012-10-08 16:58:39 -0700621// /*
622// * this method tries to use ccncat
623// * however, it does not work in Mac OS X app bundle
624// * it works well in command line though
625// */
626
627// std::string cmd = CCN_EXEC;
628// cmd += " -c -v ";
629// cmd += LOCAL_PREFIX_QUERY;
630// QString localPrefix;
631// #define MAX_PREFIX_LEN 100
632// FILE *fp = popen(cmd.c_str(), "r");
633// if (fp != NULL)
634// {
635// char prefix[MAX_PREFIX_LEN];
636// if (fgets(prefix, MAX_PREFIX_LEN, fp) != NULL)
637// {
638// localPrefix = prefix;
639// localPrefix.remove('\n');
640// }
641// else
642// {
643// localPrefix = DEFAULT_LOCAL_PREFIX;
644// }
645// pclose(fp);
646// }
647// else
648// {
649// localPrefix = DEFAULT_LOCAL_PREFIX;
650// }
651// return localPrefix;
Alexander Afanasyevebe118d2012-10-08 08:56:34 -0700652 std::cerr << "trying to get local prefix" << std::endl;
653
Zhenkai Zhu86581412012-10-08 16:58:39 -0700654 if (m_sock != NULL)
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700655 {
656 QString originPrefix = QString::fromStdString (m_sock->getLocalPrefix()).trimmed ();
657 std::cerr << "got: " << originPrefix.toStdString () << std::endl;
Zhenkai Zhuba707342012-10-08 16:20:15 -0700658
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700659 if (originPrefix != "" && m_user.getOriginPrefix () != originPrefix)
Zhenkai Zhu86581412012-10-08 16:58:39 -0700660 {
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700661 emit settingUpdated(m_user.getNick (), m_user.getChatroom (), originPrefix);
662 // prefix updated
663 return true;
Zhenkai Zhu86581412012-10-08 16:58:39 -0700664 }
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700665 }
666
667 // prefix not changed
668 return false;
669}
670
671void
672ChatDialog::updateLocalPrefix()
673{
674 getLocalPrefix();
Zhenkai Zhu6bda0bd2012-10-06 23:50:39 -0700675}
676
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700677bool
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700678ChatDialog::readSettings()
679{
680 QSettings s(ORGANIZATION, APPLICATION);
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700681 QString nick = s.value("nick", "").toString();
682 QString chatroom = s.value("chatroom", "").toString();
Zhenkai Zhu86581412012-10-08 16:58:39 -0700683 // QString originPrefix = s.value("originPrefix", "").toString();
Alexander Afanasyev5ddc68b2012-10-08 00:21:40 -0700684
Zhenkai Zhu86581412012-10-08 16:58:39 -0700685 // Sync::CcnxWrapperPtr wrapper = Sync::CcnxWrapper::Create ();
686 // QString originPrefix = QString::fromStdString (wrapper->getLocalPrefix());
687 // Sync::CcnxWrapper::Destroy ();
Alexander Afanasyev5ddc68b2012-10-08 00:21:40 -0700688
Zhenkai Zhu86581412012-10-08 16:58:39 -0700689 QString originPrefix = DEFAULT_LOCAL_PREFIX;
Alexander Afanasyev5ddc68b2012-10-08 00:21:40 -0700690
Zhenkai Zhu3974a492012-09-28 14:39:45 -0700691 m_minimaniho = s.value("minimaniho", false).toBool();
692 if (nick == "" || chatroom == "" || originPrefix == "") {
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700693 QTimer::singleShot(500, this, SLOT(buttonPressed()));
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700694 return false;
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700695 }
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700696 else {
697 m_user.setNick(nick);
698 m_user.setChatroom(chatroom);
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700699 m_user.setOriginPrefix(originPrefix);
Zhenkai Zhu3974a492012-09-28 14:39:45 -0700700 m_user.setPrefix(originPrefix + "/" + chatroom + "/" + getRandomString());
Zhenkai Zhu716fe852012-10-08 18:27:55 -0700701 m_scene->setCurrentPrefix(originPrefix + "/" + chatroom + "/" + getRandomString());
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700702 return true;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700703 }
Zhenkai Zhu3974a492012-09-28 14:39:45 -0700704
705// QTimer::singleShot(500, this, SLOT(buttonPressed()));
706 // return false;
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700707}
708
709void
710ChatDialog::writeSettings()
711{
712 QSettings s(ORGANIZATION, APPLICATION);
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700713 s.setValue("nick", m_user.getNick());
714 s.setValue("chatroom", m_user.getChatroom());
Zhenkai Zhu6bda0bd2012-10-06 23:50:39 -0700715 //s.setValue("originPrefix", m_user.getOriginPrefix());
Zhenkai Zhu3974a492012-09-28 14:39:45 -0700716 s.setValue("minimaniho", m_minimaniho);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700717}
718
719void
720ChatDialog::updateLabels()
721{
Zhenkai Zhu76ff02b2012-09-27 21:11:03 -0700722 QString settingDisp = QString("Chatroom: %1").arg(m_user.getChatroom());
723 infoLabel->setStyleSheet("QLabel {color: #630; font-size: 16px; font: bold \"Verdana\";}");
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700724 infoLabel->setText(settingDisp);
Zhenkai Zhu6bda0bd2012-10-06 23:50:39 -0700725 QString prefixDisp;
726 if (m_user.getPrefix().startsWith(DEFAULT_LOCAL_PREFIX))
727 {
728 prefixDisp = QString("<Warning: Auto config prefix failed.>\n <Prefix = %1>").arg(m_user.getPrefix());
729 prefixLabel->setStyleSheet("QLabel {color: red; font-size: 12px; font: bold \"Verdana\";}");
730 }
731 else
732 {
733 prefixDisp = QString("<Prefix = %1>").arg(m_user.getPrefix());
734 prefixLabel->setStyleSheet("QLabel {color: Green; font-size: 12px; font: bold \"Verdana\";}");
735 }
736 prefixLabel->setText(prefixDisp);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700737}
738
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700739void
740ChatDialog::returnPressed()
741{
742 QString text = lineEdit->text();
743 if (text.isEmpty())
744 return;
745
Zhenkai Zhub6338822012-05-31 13:27:24 -0700746 lineEdit->clear();
747
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700748 SyncDemo::ChatMessage msg;
749 formChatMessage(text, msg);
750
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700751 appendMessage(msg);
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700752
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700753 sendMsg(msg);
754
755 fitView();
756}
757
758void
759ChatDialog::sendMsg(SyncDemo::ChatMessage &msg)
760{
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700761 // send msg
762 size_t size = msg.ByteSize();
763 char *buf = new char[size];
764 msg.SerializeToArray(buf, size);
765 if (!msg.IsInitialized())
766 {
767 std::cerr << "Errrrr.. msg was not probally initialized "<<__FILE__ <<":"<<__LINE__<<". what is happening?" << std::endl;
768 abort();
769 }
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700770 m_sock->publishRaw(m_user.getPrefix().toStdString(), m_session, buf, size, FRESHNESS);
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700771
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700772 delete buf;
773
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700774 m_lastMsgTime = time(NULL);
775
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700776 int nextSequence = m_sock->getNextSeq(m_user.getPrefix().toStdString(), m_session);
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700777 Sync::MissingDataInfo mdi = {m_user.getPrefix().toStdString(), Sync::SeqNo(0), Sync::SeqNo(nextSequence - 1)};
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700778 std::vector<Sync::MissingDataInfo> v;
779 v.push_back(mdi);
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700780 {
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700781 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700782 m_scene->processUpdate(v, m_sock->getRootDigest().c_str());
783 m_scene->msgReceived(m_user.getPrefix(), m_user.getNick());
784 }
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700785}
786
787void
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700788ChatDialog::sendJoin()
789{
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700790 m_joined = true;
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700791 SyncDemo::ChatMessage msg;
Zhenkai Zhub5b78462012-09-28 14:10:37 -0700792 formControlMessage(msg, SyncDemo::ChatMessage::JOIN);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700793 sendMsg(msg);
Zhenkai Zhuc61dbc22012-10-08 11:36:37 -0700794 boost::random::random_device rng;
795 boost::random::uniform_int_distribution<> uniform(1, FRESHNESS / 5 * 1000);
796 m_randomizedInterval = HELLO_INTERVAL * 1000 + uniform(rng);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700797 QTimer::singleShot(m_randomizedInterval, this, SLOT(sendHello()));
798}
799
800void
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700801ChatDialog::sendHello()
802{
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700803 time_t now = time(NULL);
804 int elapsed = now - m_lastMsgTime;
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700805 if (elapsed >= m_randomizedInterval / 1000)
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700806 {
807 SyncDemo::ChatMessage msg;
Zhenkai Zhub5b78462012-09-28 14:10:37 -0700808 formControlMessage(msg, SyncDemo::ChatMessage::HELLO);
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -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 Zhuee5c90f2012-09-27 14:05:41 -0700813 QTimer::singleShot(m_randomizedInterval, this, SLOT(sendHello()));
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700814 }
815 else
816 {
Zhenkai Zhuee5c90f2012-09-27 14:05:41 -0700817 QTimer::singleShot((m_randomizedInterval - elapsed * 1000), this, SLOT(sendHello()));
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700818 }
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700819}
820
821void
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700822ChatDialog::buttonPressed()
823{
Alexander Afanasyev5ddc68b2012-10-08 00:21:40 -0700824 Sync::SyncLogic &logic = m_sock->getLogic ();
825 logic.printState ();
826
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700827 SettingDialog dialog(this, m_user.getNick(), m_user.getChatroom(), m_user.getOriginPrefix());
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700828 connect(&dialog, SIGNAL(updated(QString, QString, QString)), this, SLOT(settingUpdated(QString, QString, QString)));
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700829 dialog.exec();
Zhenkai Zhue837f792012-06-05 20:47:54 -0700830 QTimer::singleShot(100, this, SLOT(checkSetting()));
831}
832
Zhenkai Zhub60b7e12012-09-28 11:34:21 -0700833void ChatDialog::treeButtonPressed()
834{
835 if (treeViewer->isVisible())
836 {
837 treeViewer->hide();
838 treeButton->setText("Show Sync Tree");
839 }
840 else
841 {
842 treeViewer->show();
843 treeButton->setText("Hide Sync Tree");
844 }
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700845
846 fitView();
Zhenkai Zhub60b7e12012-09-28 11:34:21 -0700847}
848
Zhenkai Zhu0e7a9b22012-10-05 17:55:17 -0700849void ChatDialog::enableTreeDisplay()
850{
851 treeButton->setEnabled(true);
852 treeViewer->show();
853 fitView();
854}
855
856void ChatDialog::disableTreeDisplay()
857{
858 treeButton->setEnabled(false);
859 treeViewer->hide();
860 fitView();
861}
862
Zhenkai Zhue837f792012-06-05 20:47:54 -0700863void
864ChatDialog::checkSetting()
865{
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700866 if (m_user.getOriginPrefix().isEmpty() || m_user.getNick().isEmpty() || m_user.getChatroom().isEmpty())
Zhenkai Zhue837f792012-06-05 20:47:54 -0700867 {
868 buttonPressed();
869 }
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -0700870}
Zhenkai Zhue08afe02012-05-31 15:49:07 -0700871
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700872void
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700873ChatDialog::settingUpdated(QString nick, QString chatroom, QString originPrefix)
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700874{
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700875 QString randString = getRandomString();
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700876 bool needWrite = false;
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700877 bool needFresh = false;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700878 if (!nick.isEmpty() && nick != m_user.getNick()) {
879 m_user.setNick(nick);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700880 needWrite = true;
881 }
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -0700882 QString oldPrefix = m_user.getPrefix();
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700883 if (!originPrefix.isEmpty() && originPrefix != m_user.getOriginPrefix()) {
884 m_user.setOriginPrefix(originPrefix);
885 m_user.setPrefix(originPrefix + "/" + m_user.getChatroom() + "/" + randString);
Zhenkai Zhu716fe852012-10-08 18:27:55 -0700886 m_scene->setCurrentPrefix(originPrefix + "/" + m_user.getChatroom() + "/" + randString);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700887 needWrite = true;
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700888 needFresh = true;
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700889 }
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700890 if (!chatroom.isEmpty() && chatroom != m_user.getChatroom()) {
891 m_user.setChatroom(chatroom);
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700892 m_user.setPrefix(m_user.getOriginPrefix() + "/" + chatroom + "/" + randString);
Zhenkai Zhu716fe852012-10-08 18:27:55 -0700893 m_scene->setCurrentPrefix(m_user.getOriginPrefix() + "/" + chatroom + "/" + randString);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700894 needWrite = true;
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700895 needFresh = true;
896 }
897
898 if (needFresh)
899 {
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700900
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700901 {
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700902 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700903 m_scene->clearAll();
904 m_scene->plot("Empty");
905 }
Zhenkai Zhucc4c2c02012-09-27 21:24:37 -0700906
907 textEdit->clear();
908
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700909 if (m_sock != NULL)
910 {
Zhenkai Zhu77fc8f22012-10-08 15:12:56 -0700911 // keep the new prefix
912 QString newPrefix = m_user.getPrefix();
913 // send leave for the old
914 m_user.setPrefix(oldPrefix);
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700915 // there is no point to send leave if we haven't joined yet
916 if (m_joined)
917 {
918 sendLeave();
919 }
Zhenkai Zhu77fc8f22012-10-08 15:12:56 -0700920 // resume new prefix
921 m_user.setPrefix(newPrefix);
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -0700922 Sync::CcnxWrapperPtr handle = Sync::CcnxWrapper::Create();
923 handle->clearInterestFilter(oldPrefix.toStdString());
924 m_history.clear();
925 m_historyInitialized = false;
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700926 delete m_sock;
927 m_sock = NULL;
928 }
929 std::string syncPrefix = BROADCAST_PREFIX_FOR_SYNC_DEMO;
930 syncPrefix += "/";
931 syncPrefix += m_user.getChatroom().toStdString();
Zhenkai Zhua4fb1242012-06-05 20:26:05 -0700932 try
933 {
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700934 m_sock = new Sync::SyncAppSocket(syncPrefix, bind(&ChatDialog::processTreeUpdateWrapper, this, _1, _2), bind(&ChatDialog::processRemoveWrapper, this, _1));
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -0700935 Sync::CcnxWrapperPtr handle = Sync::CcnxWrapper::Create();
936 handle->setInterestFilter(m_user.getPrefix().toStdString(), bind(&ChatDialog::respondHistoryRequest, this, _1));
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700937 QTimer::singleShot(600, this, SLOT(sendJoin()));
Zhenkai Zhu78799ea2012-10-08 11:51:56 -0700938 m_timer->start(FRESHNESS * 1000);
Zhenkai Zhu0e7a9b22012-10-05 17:55:17 -0700939 disableTreeDisplay();
940 QTimer::singleShot(2200, this, SLOT(enableTreeDisplay()));
Zhenkai Zhua4fb1242012-06-05 20:26:05 -0700941 }
942 catch (Sync::CcnxOperationException ex)
943 {
Zhenkai Zhu0b3fa332012-09-27 21:58:43 -0700944 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 -0700945 std::exit(1);
946 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700947
948 fitView();
949
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700950 }
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700951
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700952 if (needWrite) {
953 writeSettings();
954 updateLabels();
955 }
956}
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700957
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700958void
959ChatDialog::iconActivated(QSystemTrayIcon::ActivationReason reason)
960{
961 switch (reason)
962 {
963 case QSystemTrayIcon::Trigger:
964 case QSystemTrayIcon::DoubleClick:
965 break;
966 case QSystemTrayIcon::MiddleClick:
967 // showMessage();
968 break;
969 default:;
970 }
971}
972
973void
974ChatDialog::showMessage(QString from, QString data)
975{
976 // std::cout <<"Showing Message: " << from.toStdString() << ": " << data.toStdString() << std::endl;
977 if (!isActiveWindow())
978 {
979 trayIcon->showMessage(QString("Chatroom %1 has a new message").arg(m_user.getChatroom()), QString("<%1>: %2").arg(from).arg(data), QSystemTrayIcon::Information, 20000);
980 trayIcon->setIcon(QIcon(":/images/note.png"));
981 }
982}
983
984void
985ChatDialog::messageClicked()
986{
987 this->showMaximized();
988}
989
990void
991ChatDialog::createActions()
992{
993 minimizeAction = new QAction(tr("Mi&nimize"), this);
994 connect(minimizeAction, SIGNAL(triggered()), this, SLOT(hide()));
995
996 maximizeAction = new QAction(tr("Ma&ximize"), this);
997 connect(maximizeAction, SIGNAL(triggered()), this, SLOT(showMaximized()));
998
999 restoreAction = new QAction(tr("&Restore"), this);
1000 connect(restoreAction, SIGNAL(triggered()), this, SLOT(showNormal()));
1001
1002 quitAction = new QAction(tr("Quit"), this);
1003 connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
1004}
1005
1006void
1007ChatDialog::createTrayIcon()
1008{
1009 trayIconMenu = new QMenu(this);
1010 trayIconMenu->addAction(minimizeAction);
1011 trayIconMenu->addAction(maximizeAction);
1012 trayIconMenu->addAction(restoreAction);
1013 trayIconMenu->addSeparator();
1014 trayIconMenu->addAction(quitAction);
1015
1016 trayIcon = new QSystemTrayIcon(this);
1017 trayIcon->setContextMenu(trayIconMenu);
1018
1019 QIcon icon(":/images/icon_small.png");
1020 trayIcon->setIcon(icon);
1021 setWindowIcon(icon);
Zhenkai Zhu0b3fa332012-09-27 21:58:43 -07001022 trayIcon->setToolTip("Chronos System Tray Icon");
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -07001023 trayIcon->setVisible(true);
1024}
1025
Zhenkai Zhud13acd02012-06-04 15:25:20 -07001026void
1027ChatDialog::resizeEvent(QResizeEvent *e)
1028{
1029 fitView();
1030}
1031
1032void
1033ChatDialog::showEvent(QShowEvent *e)
1034{
1035 fitView();
1036}
1037
1038void
1039ChatDialog::fitView()
1040{
Zhenkai Zhu9036e032012-09-27 20:59:33 -07001041 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu21d75f92012-06-04 21:23:34 -07001042 QRectF rect = m_scene->itemsBoundingRect();
1043 m_scene->setSceneRect(rect);
Zhenkai Zhu82a62752012-06-04 17:11:04 -07001044 treeViewer->fitInView(m_scene->itemsBoundingRect(), Qt::KeepAspectRatio);
Zhenkai Zhud13acd02012-06-04 15:25:20 -07001045}