blob: a3137a0e1b39f96ea457b508c06c17b2c7b4d497 [file] [log] [blame]
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -07001#include "chatdialog.h"
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -07002
Zhenkai Zhu85845d22012-06-01 23:10:43 -07003#include "settingdialog.h"
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -07004
5#include <QtGui>
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>
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -07009
10#ifndef Q_MOC_RUN
11#include <ctime>
12#include <iostream>
13
Zhenkai Zhu59245aa2012-09-26 16:07:04 -070014#include <boost/random/random_device.hpp>
15#include <boost/random/uniform_int_distribution.hpp>
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -070016#include <boost/lexical_cast.hpp>
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -070017#include <boost/make_shared.hpp>
18
Zhenkai Zhu6bda0bd2012-10-06 23:50:39 -070019#include <stdio.h>
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -070020#endif
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -070021
Zhenkai Zhu0b3fa332012-09-27 21:58:43 -070022#define BROADCAST_PREFIX_FOR_SYNC_DEMO "/ndn/broadcast/chronos"
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -070023#define LOCAL_PREFIX_QUERY "/local/ndn/prefix"
Zhenkai Zhu6bda0bd2012-10-06 23:50:39 -070024#define DEFAULT_LOCAL_PREFIX "/private/local"
Zhenkai Zhu756666a2012-10-07 00:24:35 -070025#define CCN_EXEC "/usr/local/bin/ccnpeek"
Zhenkai Zhu82a62752012-06-04 17:11:04 -070026
Zhenkai Zhuc61dbc22012-10-08 11:36:37 -070027static const int HELLO_INTERVAL = FRESHNESS * 3 / 4; // seconds
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -070028
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -070029ChatDialog::ChatDialog(QWidget *parent)
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -070030 : QDialog(parent), m_sock(NULL), m_lastMsgTime(0), m_historyInitialized(false), m_joined(false)
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -070031{
Zhenkai Zhu10ccb5a2012-06-04 21:55:14 -070032 // have to register this, otherwise
33 // the signal-slot system won't recognize this type
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -070034 qRegisterMetaType<std::vector<Sync::MissingDataInfo> >("std::vector<Sync::MissingDataInfo>");
35 qRegisterMetaType<size_t>("size_t");
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -070036 setupUi(this);
Zhenkai Zhu82a62752012-06-04 17:11:04 -070037 m_session = time(NULL);
Zhenkai Zhu716fe852012-10-08 18:27:55 -070038 m_scene = new DigestTreeScene(this);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -070039
40 readSettings();
Zhenkai Zhu82a62752012-06-04 17:11:04 -070041
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -070042 updateLabels();
43
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -070044 lineEdit->setFocusPolicy(Qt::StrongFocus);
Zhenkai Zhub45e38a2012-06-01 15:44:36 -070045
Zhenkai Zhu82a62752012-06-04 17:11:04 -070046 treeViewer->setScene(m_scene);
47 m_scene->plot("Empty");
48 QRectF rect = m_scene->itemsBoundingRect();
49 m_scene->setSceneRect(rect);
50
Zhenkai Zhu9036e032012-09-27 20:59:33 -070051 listView->setStyleSheet("QListView { alternate-background-color: white; background: #F0F0F0; color: darkGreen; font: bold large; }");
Zhenkai Zhuf55f4382012-09-28 10:58:54 -070052 listView->setEditTriggers(QAbstractItemView::NoEditTriggers);
53 listView->setDragDropMode(QAbstractItemView::NoDragDrop);
54 listView->setSelectionMode(QAbstractItemView::NoSelection);
Zhenkai Zhu6082ede2012-09-27 17:28:46 -070055 m_rosterModel = new QStringListModel(this);
56 listView->setModel(m_rosterModel);
57
Zhenkai Zhu4b953d92012-10-08 13:09:40 -070058 refreshButton->setIcon(QIcon(QPixmap(":images/refresh.png")));
Zhenkai Zhu22c7d4d2012-10-09 12:29:32 -070059 reapButton->hide();
Zhenkai Zhu4b953d92012-10-08 13:09:40 -070060
Zhenkai Zhu86df7412012-09-27 16:30:20 -070061 createActions();
62 createTrayIcon();
63 m_timer = new QTimer(this);
64 connect(lineEdit, SIGNAL(returnPressed()), this, SLOT(returnPressed()));
65 connect(setButton, SIGNAL(pressed()), this, SLOT(buttonPressed()));
Zhenkai Zhub60b7e12012-09-28 11:34:21 -070066 connect(treeButton, SIGNAL(pressed()), this, SLOT(treeButtonPressed()));
Zhenkai Zhu7f52e1b2012-10-09 11:45:36 -070067 connect(reapButton, SIGNAL(pressed()), this, SLOT(summonReaper()));
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -070068 connect(refreshButton, SIGNAL(pressed()), this, SLOT(updateLocalPrefix()));
Zhenkai Zhu24ec4722012-10-07 17:56:38 -070069 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 -070070 connect(this, SIGNAL(treeUpdated(const std::vector<Sync::MissingDataInfo>)), this, SLOT(processTreeUpdate(const std::vector<Sync::MissingDataInfo>)));
Zhenkai Zhu86df7412012-09-27 16:30:20 -070071 connect(m_timer, SIGNAL(timeout()), this, SLOT(replot()));
72 connect(m_scene, SIGNAL(replot()), this, SLOT(replot()));
73 connect(trayIcon, SIGNAL(messageClicked()), this, SLOT(showNormal()));
74 connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
Zhenkai Zhu25e33e52012-09-28 13:00:07 -070075 connect(m_scene, SIGNAL(rosterChanged(QStringList)), this, SLOT(updateRosterList(QStringList)));
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -070076
Zhenkai Zhud616b582012-10-10 00:04:07 -070077 initializeSync();
Zhenkai Zhu86df7412012-09-27 16:30:20 -070078
Zhenkai Zhud616b582012-10-10 00:04:07 -070079}
80
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -070081void
Zhenkai Zhud616b582012-10-10 00:04:07 -070082ChatDialog::initializeSync()
83{
Zhenkai Zhu82a62752012-06-04 17:11:04 -070084 // create sync socket
Zhenkai Zhu8e180ae2012-10-10 14:01:05 -070085 if(!m_user.getChatroom().isEmpty() && !m_user.getNick().isEmpty()) {
Zhenkai Zhu82a62752012-06-04 17:11:04 -070086 std::string syncPrefix = BROADCAST_PREFIX_FOR_SYNC_DEMO;
87 syncPrefix += "/";
88 syncPrefix += m_user.getChatroom().toStdString();
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -070089 try
Zhenkai Zhua4fb1242012-06-05 20:26:05 -070090 {
Alexander Afanasyev288edd82012-10-04 17:07:56 -070091 m_sock = new Sync::SyncAppSocket(syncPrefix,
92 bind(&ChatDialog::processTreeUpdateWrapper, this, _1, _2),
93 bind(&ChatDialog::processRemoveWrapper, this, _1));
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -070094 //QTimer::singleShot(100, this, SLOT(getLocalPrefix()));
Zhenkai Zhu400cc892012-10-09 12:31:51 -070095 usleep(100000);
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -070096 if (!getLocalPrefix())
97 {
98 // if getLocalPrefix indicates no prefix change
99 // this sock is going to be used
100 QTimer::singleShot(600, this, SLOT(sendJoin()));
101 m_timer->start(FRESHNESS * 1000);
102 disableTreeDisplay();
103 QTimer::singleShot(2200, this, SLOT(enableTreeDisplay()));
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700104 Sync::CcnxWrapperPtr handle = boost::make_shared<Sync::CcnxWrapper> ();
Zhenkai Zhu5ee10092012-10-09 12:48:52 -0700105 handle->setInterestFilter(m_user.getPrefix().toStdString(), bind(&ChatDialog::respondHistoryRequest, this, _1));
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700106 }
107 else
108 {
109 // this socket is going to be destroyed anyway
110 // why bother doing the following steps
Alexander Afanasyevebe118d2012-10-08 08:56:34 -0700111
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700112 // the same steps would be performed for another socket
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700113 // in settingUpdated
114 }
Zhenkai Zhua4fb1242012-06-05 20:26:05 -0700115 }
116 catch (Sync::CcnxOperationException ex)
117 {
Zhenkai Zhu0b3fa332012-09-27 21:58:43 -0700118 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 -0700119 std::exit(1);
120 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700121 }
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700122}
123
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700124ChatDialog::~ChatDialog()
125{
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700126 if (m_sock != NULL)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700127 {
Zhenkai Zhucf024442012-10-05 10:33:08 -0700128 sendLeave();
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700129 delete m_sock;
130 m_sock = NULL;
131 }
132}
133
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700134void
Zhenkai Zhucf024442012-10-05 10:33:08 -0700135ChatDialog::sendLeave()
136{
137 SyncDemo::ChatMessage msg;
138 formControlMessage(msg, SyncDemo::ChatMessage::LEAVE);
139 sendMsg(msg);
140 usleep(500000);
141 m_sock->remove(m_user.getPrefix().toStdString());
142 usleep(5000);
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700143 m_joined = false;
Zhenkai Zhucf024442012-10-05 10:33:08 -0700144#ifdef __DEBUG
145 std::cout << "Sync REMOVE signal sent" << std::endl;
146#endif
147}
148
149void
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700150ChatDialog::replot()
151{
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700152 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700153 m_scene->plot(m_sock->getRootDigest().c_str());
Zhenkai Zhuc9e4e3c2012-10-02 11:47:31 -0700154 fitView();
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700155}
156
Zhenkai Zhu6082ede2012-09-27 17:28:46 -0700157void
Zhenkai Zhu7f52e1b2012-10-09 11:45:36 -0700158ChatDialog::summonReaper()
159{
160 Sync::SyncLogic &logic = m_sock->getLogic ();
161 std::map<std::string, bool> branches = logic.getBranchPrefixes();
162 QMap<QString, DisplayUserPtr> roster = m_scene->getRosterFull();
163
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700164 m_zombieList.clear();
Zhenkai Zhu7f52e1b2012-10-09 11:45:36 -0700165
166 QMapIterator<QString, DisplayUserPtr> it(roster);
167 std::map<std::string, bool>::iterator mapIt;
168 while(it.hasNext())
169 {
170 it.next();
171 DisplayUserPtr p = it.value();
172 if (p != DisplayUserNullPtr)
173 {
174 mapIt = branches.find(p->getPrefix().toStdString());
175 if (mapIt != branches.end())
176 {
177 mapIt->second = true;
178 }
179 }
180 }
181
182 for (mapIt = branches.begin(); mapIt != branches.end(); ++mapIt)
183 {
184 // this is zombie. all active users should have been marked true
185 if (! mapIt->second)
186 {
187 m_zombieList.append(mapIt->first.c_str());
188 }
189 }
190
191 m_zombieIndex = 0;
192
193 // start reaping
194 reap();
195}
196
197void
198ChatDialog::reap()
199{
200 if (m_zombieIndex < m_zombieList.size())
201 {
202 std::string prefix = m_zombieList.at(m_zombieIndex).toStdString();
203 m_sock->remove(prefix);
204 std::cout << "Reaped: prefix = " << prefix << std::endl;
205 m_zombieIndex++;
206 // reap again in 10 seconds
207 QTimer::singleShot(10000, this, SLOT(reap()));
208 }
209}
210
211void
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700212ChatDialog::updateRosterList(QStringList staleUserList)
Zhenkai Zhu6082ede2012-09-27 17:28:46 -0700213{
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700214 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu6082ede2012-09-27 17:28:46 -0700215 QStringList rosterList = m_scene->getRosterList();
216 m_rosterModel->setStringList(rosterList);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700217 QString user;
218 QStringListIterator it(staleUserList);
219 while(it.hasNext())
220 {
Zhenkai Zhu32cbdce2012-10-02 11:09:38 -0700221 std::string nick = it.next().toStdString();
222 if (nick.empty())
223 continue;
224
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700225 SyncDemo::ChatMessage msg;
Zhenkai Zhub5b78462012-09-28 14:10:37 -0700226 formControlMessage(msg, SyncDemo::ChatMessage::LEAVE);
Zhenkai Zhu32cbdce2012-10-02 11:09:38 -0700227 msg.set_from(nick);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700228 appendMessage(msg);
229 }
Zhenkai Zhu6082ede2012-09-27 17:28:46 -0700230}
231
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700232void
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700233ChatDialog::setVisible(bool visible)
234{
235 minimizeAction->setEnabled(visible);
236 maximizeAction->setEnabled(!isMaximized());
237 restoreAction->setEnabled(isMaximized() || !visible);
238 QDialog::setVisible(visible);
239}
240
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700241void
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700242ChatDialog::closeEvent(QCloseEvent *e)
243{
Zhenkai Zhu3974a492012-09-28 14:39:45 -0700244 if (trayIcon->isVisible() && !m_minimaniho)
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700245 {
Zhenkai Zhu0b3fa332012-09-27 21:58:43 -0700246 QMessageBox::information(this, tr("Chronos"),
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700247 tr("The program will keep running in the "
248 "system tray. To terminate the program"
249 "choose <b>Quit</b> in the context memu"
250 "of the system tray entry."));
251 hide();
252 e->ignore();
Zhenkai Zhu3974a492012-09-28 14:39:45 -0700253 m_minimaniho = true;
254 writeSettings();
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700255 }
256}
257
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700258void
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700259ChatDialog::changeEvent(QEvent *e)
260{
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700261 switch(e->type())
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700262 {
263 case QEvent::ActivationChange:
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700264 if (isActiveWindow())
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700265 {
266 trayIcon->setIcon(QIcon(":/images/icon_small.png"));
267 }
268 break;
269 default:
270 break;
271 }
272}
273
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700274void
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700275ChatDialog::appendMessage(const SyncDemo::ChatMessage msg, bool isHistory)
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700276{
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700277 boost::recursive_mutex::scoped_lock lock(m_msgMutex);
Zhenkai Zhub6338822012-05-31 13:27:24 -0700278
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700279 if (msg.type() == SyncDemo::ChatMessage::CHAT)
Zhenkai Zhub98e6022012-09-27 13:48:23 -0700280 {
Zhenkai Zhub98e6022012-09-27 13:48:23 -0700281
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700282 if (!msg.has_data())
Zhenkai Zhub98e6022012-09-27 13:48:23 -0700283 {
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700284 return;
Zhenkai Zhub98e6022012-09-27 13:48:23 -0700285 }
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700286
287 if (msg.from().empty() || msg.data().empty())
288 {
289 return;
290 }
291
292 if (!msg.has_timestamp())
293 {
294 return;
295 }
296
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -0700297 if (m_history.size() == MAX_HISTORY_ENTRY)
298 {
299 m_history.dequeue();
300 }
301
302 m_history.enqueue(msg);
303
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700304 QTextCharFormat nickFormat;
305 nickFormat.setForeground(Qt::darkGreen);
306 nickFormat.setFontWeight(QFont::Bold);
307 nickFormat.setFontUnderline(true);
308 nickFormat.setUnderlineColor(Qt::gray);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700309
310 QTextCursor cursor(textEdit->textCursor());
311 cursor.movePosition(QTextCursor::End);
312 QTextTableFormat tableFormat;
313 tableFormat.setBorder(0);
314 QTextTable *table = cursor.insertTable(1, 2, tableFormat);
315 QString from = QString("%1 ").arg(msg.from().c_str());
316 QTextTableCell fromCell = table->cellAt(0, 0);
317 fromCell.setFormat(nickFormat);
318 fromCell.firstCursorPosition().insertText(from);
Zhenkai Zhu560ef1b2012-09-28 14:23:33 -0700319
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700320 time_t timestamp = msg.timestamp();
Zhenkai Zhu560ef1b2012-09-28 14:23:33 -0700321 printTimeInCell(table, timestamp);
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700322
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700323 QTextCursor nextCursor(textEdit->textCursor());
324 nextCursor.movePosition(QTextCursor::End);
325 table = nextCursor.insertTable(1, 1, tableFormat);
Zhenkai Zhu767eac72012-10-08 11:20:57 -0700326 table->cellAt(0, 0).firstCursorPosition().insertText(QString::fromUtf8(msg.data().c_str()));
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700327 if (!isHistory)
328 {
Zhenkai Zhu767eac72012-10-08 11:20:57 -0700329 showMessage(from, QString::fromUtf8(msg.data().c_str()));
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700330 }
Zhenkai Zhub98e6022012-09-27 13:48:23 -0700331 }
332
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700333 if (msg.type() == SyncDemo::ChatMessage::JOIN || msg.type() == SyncDemo::ChatMessage::LEAVE)
334 {
335 QTextCharFormat nickFormat;
336 nickFormat.setForeground(Qt::gray);
337 nickFormat.setFontWeight(QFont::Bold);
338 nickFormat.setFontUnderline(true);
339 nickFormat.setUnderlineColor(Qt::gray);
Zhenkai Zhub98e6022012-09-27 13:48:23 -0700340
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700341 QTextCursor cursor(textEdit->textCursor());
342 cursor.movePosition(QTextCursor::End);
343 QTextTableFormat tableFormat;
344 tableFormat.setBorder(0);
345 QTextTable *table = cursor.insertTable(1, 2, tableFormat);
346 QString action;
347 if (msg.type() == SyncDemo::ChatMessage::JOIN)
348 {
349 action = "enters room";
350 }
351 else
352 {
353 action = "leaves room";
354 }
355
356 QString from = QString("%1 %2 ").arg(msg.from().c_str()).arg(action);
357 QTextTableCell fromCell = table->cellAt(0, 0);
358 fromCell.setFormat(nickFormat);
359 fromCell.firstCursorPosition().insertText(from);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700360
Zhenkai Zhu560ef1b2012-09-28 14:23:33 -0700361 time_t timestamp = msg.timestamp();
362 printTimeInCell(table, timestamp);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700363 }
364
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700365 QScrollBar *bar = textEdit->verticalScrollBar();
366 bar->setValue(bar->maximum());
367}
368
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700369void
Zhenkai Zhu560ef1b2012-09-28 14:23:33 -0700370ChatDialog::printTimeInCell(QTextTable *table, time_t timestamp)
371{
372 QTextCharFormat timeFormat;
373 timeFormat.setForeground(Qt::gray);
374 timeFormat.setFontUnderline(true);
375 timeFormat.setUnderlineColor(Qt::gray);
376 QTextTableCell timeCell = table->cellAt(0, 1);
377 timeCell.setFormat(timeFormat);
378 timeCell.firstCursorPosition().insertText(formatTime(timestamp));
379}
380
381QString
382ChatDialog::formatTime(time_t timestamp)
383{
384 struct tm *tm_time = localtime(&timestamp);
385 int hour = tm_time->tm_hour;
386 QString amOrPM;
387 if (hour > 12)
388 {
389 hour -= 12;
390 amOrPM = "PM";
391 }
392 else
393 {
394 amOrPM = "AM";
395 if (hour == 0)
396 {
397 hour = 12;
398 }
399 }
400
401 char textTime[12];
402 sprintf(textTime, "%d:%02d:%02d %s", hour, tm_time->tm_min, tm_time->tm_sec, amOrPM.toStdString().c_str());
403 return QString(textTime);
404}
405
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700406void
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700407ChatDialog::processTreeUpdateWrapper(const std::vector<Sync::MissingDataInfo> v, Sync::SyncAppSocket *sock)
408{
409 emit treeUpdated(v);
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700410#ifdef __DEBUG
411 std::cout << "<<< Tree update signal emitted" << std::endl;
412#endif
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700413}
414
415void
416ChatDialog::processTreeUpdate(const std::vector<Sync::MissingDataInfo> v)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700417{
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700418#ifdef __DEBUG
419 std::cout << "<<< processing Tree Update" << std::endl;
420#endif
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700421 if (v.empty())
422 {
423 return;
424 }
425
426 // reflect the changes on digest tree
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700427 {
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700428 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700429 m_scene->processUpdate(v, m_sock->getRootDigest().c_str());
430 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700431
432 int n = v.size();
433 int totalMissingPackets = 0;
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700434 for (int i = 0; i < n; i++)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700435 {
436 totalMissingPackets += v[i].high.getSeq() - v[i].low.getSeq() + 1;
437 }
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700438
439 for (int i = 0; i < n; i++)
Zhenkai Zhubb198112012-09-27 11:31:42 -0700440 {
441 if (totalMissingPackets < 4)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700442 {
443 for (Sync::SeqNo seq = v[i].low; seq <= v[i].high; ++seq)
444 {
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700445 m_sock->fetchRaw(v[i].prefix, seq, bind(&ChatDialog::processDataWrapper, this, _1, _2, _3), 2);
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700446#ifdef __DEBUG
447 std::cout << "<<< Fetching " << v[i].prefix << "/" <<seq.getSession() <<"/" << seq.getSeq() << std::endl;
448#endif
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700449 }
450 }
Zhenkai Zhubb198112012-09-27 11:31:42 -0700451 else
452 {
453 m_sock->fetchRaw(v[i].prefix, v[i].high, bind(&ChatDialog::processDataNoShowWrapper, this, _1, _2, _3), 2);
454 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700455 }
456
457 // adjust the view
458 fitView();
459
460}
461
462void
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700463ChatDialog::processDataWrapper(std::string name, const char *buf, size_t len)
464{
Zhenkai Zhuae29f5a2012-10-05 17:28:04 -0700465 char *tempBuf = new char[len];
466 memcpy(tempBuf, buf, len);
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700467 emit dataReceived(name.c_str(), tempBuf, len, true, false);
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700468#ifdef __DEBUG
469 std::cout <<"<<< " << name << " fetched" << std::endl;
470#endif
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700471}
472
473void
Zhenkai Zhubb198112012-09-27 11:31:42 -0700474ChatDialog::processDataNoShowWrapper(std::string name, const char *buf, size_t len)
475{
Zhenkai Zhuae29f5a2012-10-05 17:28:04 -0700476 char *tempBuf = new char[len];
477 memcpy(tempBuf, buf, len);
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700478 emit dataReceived(name.c_str(), tempBuf, len, false, false);
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700479
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -0700480 if (!m_historyInitialized)
481 {
482 fetchHistory(name);
483 m_historyInitialized = true;
484 }
485}
486
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700487void
488ChatDialog::processDataHistoryWrapper(std::string name, const char *buf, size_t len)
489{
490 char *tempBuf = new char[len];
491 memcpy(tempBuf, buf, len);
492 emit dataReceived(name.c_str(), tempBuf, len, true, true);
493}
494
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700495void
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -0700496ChatDialog::fetchHistory(std::string name)
497{
498 std::string nameWithoutSeq = name.substr(0, name.find_last_of('/'));
499 std::string prefix = nameWithoutSeq.substr(0, nameWithoutSeq.find_last_of('/'));
500 prefix += "/history";
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700501 Sync::CcnxWrapperPtr handle = boost::make_shared<Sync::CcnxWrapper> ();
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -0700502 QString randomString = getRandomString();
503 for (int i = 0; i < MAX_HISTORY_ENTRY; i++)
504 {
505 QString interest = QString("%1/%2/%3").arg(prefix.c_str()).arg(randomString).arg(i);
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700506 handle->sendInterest(interest.toStdString(), bind(&ChatDialog::processDataHistoryWrapper, this, _1, _2, _3));
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -0700507 }
508}
509
510void
511ChatDialog::respondHistoryRequest(std::string interest)
512{
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700513 std::string seqStr = interest.substr(interest.find_last_of('/') + 1);
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -0700514 int seq = boost::lexical_cast<int>(seqStr);
515 if (seq >= 0 && seq < m_history.size())
516 {
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700517 Sync::CcnxWrapperPtr handle = boost::make_shared<Sync::CcnxWrapper> ();
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -0700518 SyncDemo::ChatMessage msg = m_history.at(seq);
519 size_t size = msg.ByteSize();
520 char *buf = new char[size];
521 msg.SerializeToArray(buf, size);
522 handle->publishRawData(interest, buf, size, 1);
523 delete buf;
524 }
Zhenkai Zhubb198112012-09-27 11:31:42 -0700525}
526
527void
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700528ChatDialog::processData(QString name, const char *buf, size_t len, bool show, bool isHistory)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700529{
530 SyncDemo::ChatMessage msg;
Zhenkai Zhuef8d0632012-10-05 10:24:55 -0700531 bool corrupted = false;
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700532 if (!msg.ParseFromArray(buf, len))
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700533 {
Zhenkai Zhubb198112012-09-27 11:31:42 -0700534 std::cerr << "Errrrr.. Can not parse msg with name: " << name.toStdString() << ". what is happening?" << std::endl;
Zhenkai Zhuef8d0632012-10-05 10:24:55 -0700535 // nasty stuff: as a remedy, we'll form some standard msg for inparsable msgs
536 msg.set_from("inconnu");
537 msg.set_type(SyncDemo::ChatMessage::OTHER);
538 corrupted = true;
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700539 }
540
Zhenkai Zhuae29f5a2012-10-05 17:28:04 -0700541 delete [] buf;
542 buf = NULL;
543
Zhenkai Zhu10ccb5a2012-06-04 21:55:14 -0700544 // display msg received from network
545 // we have to do so; this function is called by ccnd thread
546 // so if we call appendMsg directly
547 // Qt crash as "QObject: Cannot create children for a parent that is in a different thread"
548 // the "cannonical" way to is use signal-slot
Zhenkai Zhuef8d0632012-10-05 10:24:55 -0700549 if (show && !corrupted)
Zhenkai Zhubb198112012-09-27 11:31:42 -0700550 {
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700551 appendMessage(msg, isHistory);
Zhenkai Zhubb198112012-09-27 11:31:42 -0700552 }
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700553
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700554 if (!isHistory)
555 {
556 // update the tree view
557 std::string stdStrName = name.toStdString();
558 std::string stdStrNameWithoutSeq = stdStrName.substr(0, stdStrName.find_last_of('/'));
559 std::string prefix = stdStrNameWithoutSeq.substr(0, stdStrNameWithoutSeq.find_last_of('/'));
Zhenkai Zhu097bfe72012-06-05 14:30:17 -0700560#ifdef __DEBUG
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700561 std::cout <<"<<< updating scene for" << prefix << ": " << msg.from() << std::endl;
Zhenkai Zhu097bfe72012-06-05 14:30:17 -0700562#endif
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700563 if (msg.type() == SyncDemo::ChatMessage::LEAVE)
564 {
565 processRemove(prefix.c_str());
566 }
567 else
568 {
569 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
570 m_scene->msgReceived(prefix.c_str(), msg.from().c_str());
571 }
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700572 }
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700573 fitView();
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700574}
575
576void
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700577ChatDialog::processRemoveWrapper(std::string prefix)
578{
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700579#ifdef __DEBUG
580 std::cout << "Sync REMOVE signal received for prefix: " << prefix << std::endl;
581#endif
582 //emit removeReceived(prefix.c_str());
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700583}
584
585void
586ChatDialog::processRemove(QString prefix)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700587{
Zhenkai Zhu591e8c32012-09-26 11:57:50 -0700588#ifdef __DEBUG
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700589 std::cout << "<<< remove node for prefix" << prefix.toStdString() << std::endl;
Zhenkai Zhu591e8c32012-09-26 11:57:50 -0700590#endif
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700591 bool removed = m_scene->removeNode(prefix);
Zhenkai Zhu591e8c32012-09-26 11:57:50 -0700592 if (removed)
593 {
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700594 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu591e8c32012-09-26 11:57:50 -0700595 m_scene->plot(m_sock->getRootDigest().c_str());
596 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700597}
598
599void
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700600ChatDialog::formChatMessage(const QString &text, SyncDemo::ChatMessage &msg) {
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700601 msg.set_from(m_user.getNick().toStdString());
602 msg.set_to(m_user.getChatroom().toStdString());
Zhenkai Zhu767eac72012-10-08 11:20:57 -0700603 msg.set_data(text.toUtf8().constData());
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700604 time_t seconds = time(NULL);
605 msg.set_timestamp(seconds);
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700606 msg.set_type(SyncDemo::ChatMessage::CHAT);
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700607}
608
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700609void
Zhenkai Zhub5b78462012-09-28 14:10:37 -0700610ChatDialog::formControlMessage(SyncDemo::ChatMessage &msg, SyncDemo::ChatMessage::ChatMessageType type)
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700611{
612 msg.set_from(m_user.getNick().toStdString());
613 msg.set_to(m_user.getChatroom().toStdString());
614 time_t seconds = time(NULL);
615 msg.set_timestamp(seconds);
Zhenkai Zhub5b78462012-09-28 14:10:37 -0700616 msg.set_type(type);
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700617}
618
Zhenkai Zhu59245aa2012-09-26 16:07:04 -0700619static std::string chars("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM0123456789");
620
621QString
622ChatDialog::getRandomString()
623{
624 std::string randStr;
625 boost::random::random_device rng;
626 boost::random::uniform_int_distribution<> index_dist(0, chars.size() - 1);
627 for (int i = 0; i < 10; i ++)
628 {
629 randStr += chars[index_dist(rng)];
630 }
631 return randStr.c_str();
632}
633
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700634bool
Zhenkai Zhu6bda0bd2012-10-06 23:50:39 -0700635ChatDialog::getLocalPrefix()
636{
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700637// /*
638// * this method tries to use ccncat
Zhenkai Zhu86581412012-10-08 16:58:39 -0700639// * however, it does not work in Mac OS X app bundle
640// * it works well in command line though
641// */
642
643// std::string cmd = CCN_EXEC;
644// cmd += " -c -v ";
645// cmd += LOCAL_PREFIX_QUERY;
646// QString localPrefix;
647// #define MAX_PREFIX_LEN 100
648// FILE *fp = popen(cmd.c_str(), "r");
649// if (fp != NULL)
650// {
651// char prefix[MAX_PREFIX_LEN];
652// if (fgets(prefix, MAX_PREFIX_LEN, fp) != NULL)
653// {
654// localPrefix = prefix;
655// localPrefix.remove('\n');
656// }
657// else
658// {
659// localPrefix = DEFAULT_LOCAL_PREFIX;
660// }
661// pclose(fp);
662// }
663// else
664// {
665// localPrefix = DEFAULT_LOCAL_PREFIX;
666// }
667// return localPrefix;
Alexander Afanasyevebe118d2012-10-08 08:56:34 -0700668 std::cerr << "trying to get local prefix" << std::endl;
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700669
Zhenkai Zhu86581412012-10-08 16:58:39 -0700670 if (m_sock != NULL)
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700671 {
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700672 QString originPrefix = QString::fromStdString (m_sock->GetLocalPrefix()).trimmed ();
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700673 std::cerr << "got: " << originPrefix.toStdString () << std::endl;
Zhenkai Zhuba707342012-10-08 16:20:15 -0700674
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700675 if (originPrefix != "" && m_user.getOriginPrefix () != originPrefix)
Zhenkai Zhu86581412012-10-08 16:58:39 -0700676 {
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700677 emit settingUpdated(m_user.getNick (), m_user.getChatroom (), originPrefix);
678 // prefix updated
679 return true;
Zhenkai Zhu86581412012-10-08 16:58:39 -0700680 }
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700681 }
682
683 // prefix not changed
684 return false;
685}
686
687void
688ChatDialog::updateLocalPrefix()
689{
690 getLocalPrefix();
Zhenkai Zhu6bda0bd2012-10-06 23:50:39 -0700691}
692
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700693bool
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700694ChatDialog::readSettings()
695{
696 QSettings s(ORGANIZATION, APPLICATION);
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700697 QString nick = s.value("nick", "").toString();
698 QString chatroom = s.value("chatroom", "").toString();
Zhenkai Zhu86581412012-10-08 16:58:39 -0700699 // QString originPrefix = s.value("originPrefix", "").toString();
Alexander Afanasyev5ddc68b2012-10-08 00:21:40 -0700700
Zhenkai Zhu86581412012-10-08 16:58:39 -0700701 // Sync::CcnxWrapperPtr wrapper = Sync::CcnxWrapper::Create ();
702 // QString originPrefix = QString::fromStdString (wrapper->getLocalPrefix());
703 // Sync::CcnxWrapper::Destroy ();
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700704
Zhenkai Zhu86581412012-10-08 16:58:39 -0700705 QString originPrefix = DEFAULT_LOCAL_PREFIX;
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700706
Zhenkai Zhu3974a492012-09-28 14:39:45 -0700707 m_minimaniho = s.value("minimaniho", false).toBool();
708 if (nick == "" || chatroom == "" || originPrefix == "") {
Zhenkai Zhud616b582012-10-10 00:04:07 -0700709 m_user.setOriginPrefix(DEFAULT_LOCAL_PREFIX);
Zhenkai Zhu8e180ae2012-10-10 14:01:05 -0700710 m_user.setChatroom("retreat2012");
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700711 QTimer::singleShot(500, this, SLOT(buttonPressed()));
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700712 return false;
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700713 }
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700714 else {
715 m_user.setNick(nick);
716 m_user.setChatroom(chatroom);
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700717 m_user.setOriginPrefix(originPrefix);
Zhenkai Zhu3974a492012-09-28 14:39:45 -0700718 m_user.setPrefix(originPrefix + "/" + chatroom + "/" + getRandomString());
Zhenkai Zhu716fe852012-10-08 18:27:55 -0700719 m_scene->setCurrentPrefix(originPrefix + "/" + chatroom + "/" + getRandomString());
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700720 return true;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700721 }
Zhenkai Zhu3974a492012-09-28 14:39:45 -0700722
723// QTimer::singleShot(500, this, SLOT(buttonPressed()));
724 // return false;
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700725}
726
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700727void
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700728ChatDialog::writeSettings()
729{
730 QSettings s(ORGANIZATION, APPLICATION);
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700731 s.setValue("nick", m_user.getNick());
732 s.setValue("chatroom", m_user.getChatroom());
Zhenkai Zhu6bda0bd2012-10-06 23:50:39 -0700733 //s.setValue("originPrefix", m_user.getOriginPrefix());
Zhenkai Zhu3974a492012-09-28 14:39:45 -0700734 s.setValue("minimaniho", m_minimaniho);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700735}
736
737void
738ChatDialog::updateLabels()
739{
Zhenkai Zhu76ff02b2012-09-27 21:11:03 -0700740 QString settingDisp = QString("Chatroom: %1").arg(m_user.getChatroom());
741 infoLabel->setStyleSheet("QLabel {color: #630; font-size: 16px; font: bold \"Verdana\";}");
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700742 infoLabel->setText(settingDisp);
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700743 QString prefixDisp;
Zhenkai Zhu6bda0bd2012-10-06 23:50:39 -0700744 if (m_user.getPrefix().startsWith(DEFAULT_LOCAL_PREFIX))
745 {
Zhenkai Zhud616b582012-10-10 00:04:07 -0700746 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 -0700747 prefixLabel->setStyleSheet("QLabel {color: red; font-size: 12px; font: bold \"Verdana\";}");
748 }
749 else
750 {
751 prefixDisp = QString("<Prefix = %1>").arg(m_user.getPrefix());
752 prefixLabel->setStyleSheet("QLabel {color: Green; font-size: 12px; font: bold \"Verdana\";}");
753 }
754 prefixLabel->setText(prefixDisp);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700755}
756
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700757void
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700758ChatDialog::returnPressed()
759{
760 QString text = lineEdit->text();
761 if (text.isEmpty())
762 return;
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700763
Zhenkai Zhub6338822012-05-31 13:27:24 -0700764 lineEdit->clear();
765
Zhenkai Zhu22c7d4d2012-10-09 12:29:32 -0700766 if (text.startsWith("boruoboluomi"))
767 {
768 reapButton->show();
769 fitView();
770 return;
771 }
772
773 if (text.startsWith("minimanihong"))
774 {
775 reapButton->hide();
776 fitView();
777 return;
778 }
779
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700780 SyncDemo::ChatMessage msg;
781 formChatMessage(text, msg);
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700782
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700783 appendMessage(msg);
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700784
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700785 sendMsg(msg);
786
787 fitView();
788}
789
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700790void
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700791ChatDialog::sendMsg(SyncDemo::ChatMessage &msg)
792{
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700793 // send msg
794 size_t size = msg.ByteSize();
795 char *buf = new char[size];
796 msg.SerializeToArray(buf, size);
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700797 if (!msg.IsInitialized())
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700798 {
799 std::cerr << "Errrrr.. msg was not probally initialized "<<__FILE__ <<":"<<__LINE__<<". what is happening?" << std::endl;
800 abort();
801 }
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700802 m_sock->publishRaw(m_user.getPrefix().toStdString(), m_session, buf, size, FRESHNESS);
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700803
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700804 delete buf;
805
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700806 m_lastMsgTime = time(NULL);
807
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700808 int nextSequence = m_sock->getNextSeq(m_user.getPrefix().toStdString(), m_session);
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700809 Sync::MissingDataInfo mdi = {m_user.getPrefix().toStdString(), Sync::SeqNo(0), Sync::SeqNo(nextSequence - 1)};
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700810 std::vector<Sync::MissingDataInfo> v;
811 v.push_back(mdi);
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700812 {
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700813 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700814 m_scene->processUpdate(v, m_sock->getRootDigest().c_str());
815 m_scene->msgReceived(m_user.getPrefix(), m_user.getNick());
816 }
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700817}
818
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700819void
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700820ChatDialog::sendJoin()
821{
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700822 m_joined = true;
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700823 SyncDemo::ChatMessage msg;
Zhenkai Zhub5b78462012-09-28 14:10:37 -0700824 formControlMessage(msg, SyncDemo::ChatMessage::JOIN);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -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 Zhu25e33e52012-09-28 13:00:07 -0700829 QTimer::singleShot(m_randomizedInterval, this, SLOT(sendHello()));
830}
831
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700832void
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700833ChatDialog::sendHello()
834{
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700835 time_t now = time(NULL);
836 int elapsed = now - m_lastMsgTime;
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700837 if (elapsed >= m_randomizedInterval / 1000)
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700838 {
839 SyncDemo::ChatMessage msg;
Zhenkai Zhub5b78462012-09-28 14:10:37 -0700840 formControlMessage(msg, SyncDemo::ChatMessage::HELLO);
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700841 sendMsg(msg);
Zhenkai Zhuc61dbc22012-10-08 11:36:37 -0700842 boost::random::random_device rng;
843 boost::random::uniform_int_distribution<> uniform(1, FRESHNESS / 5 * 1000);
844 m_randomizedInterval = HELLO_INTERVAL * 1000 + uniform(rng);
Zhenkai Zhuee5c90f2012-09-27 14:05:41 -0700845 QTimer::singleShot(m_randomizedInterval, this, SLOT(sendHello()));
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700846 }
847 else
848 {
Zhenkai Zhuee5c90f2012-09-27 14:05:41 -0700849 QTimer::singleShot((m_randomizedInterval - elapsed * 1000), this, SLOT(sendHello()));
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700850 }
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700851}
852
853void
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700854ChatDialog::buttonPressed()
855{
Zhenkai Zhud616b582012-10-10 00:04:07 -0700856 if (m_sock != NULL)
857 {
858 Sync::SyncLogic &logic = m_sock->getLogic ();
859 logic.printState ();
860 }
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700861
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700862 SettingDialog dialog(this, m_user.getNick(), m_user.getChatroom(), m_user.getOriginPrefix());
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700863 connect(&dialog, SIGNAL(updated(QString, QString, QString)), this, SLOT(settingUpdated(QString, QString, QString)));
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700864 dialog.exec();
Zhenkai Zhue837f792012-06-05 20:47:54 -0700865 QTimer::singleShot(100, this, SLOT(checkSetting()));
866}
867
Zhenkai Zhub60b7e12012-09-28 11:34:21 -0700868void ChatDialog::treeButtonPressed()
869{
870 if (treeViewer->isVisible())
871 {
872 treeViewer->hide();
873 treeButton->setText("Show Sync Tree");
874 }
875 else
876 {
877 treeViewer->show();
878 treeButton->setText("Hide Sync Tree");
879 }
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700880
881 fitView();
Zhenkai Zhub60b7e12012-09-28 11:34:21 -0700882}
883
Zhenkai Zhu0e7a9b22012-10-05 17:55:17 -0700884void ChatDialog::enableTreeDisplay()
885{
886 treeButton->setEnabled(true);
887 treeViewer->show();
888 fitView();
889}
890
891void ChatDialog::disableTreeDisplay()
892{
893 treeButton->setEnabled(false);
894 treeViewer->hide();
895 fitView();
896}
897
Zhenkai Zhue837f792012-06-05 20:47:54 -0700898void
899ChatDialog::checkSetting()
900{
Zhenkai Zhud616b582012-10-10 00:04:07 -0700901 if (m_user.getNick().isEmpty() || m_user.getChatroom().isEmpty() || m_user.getOriginPrefix().isEmpty())
Zhenkai Zhue837f792012-06-05 20:47:54 -0700902 {
903 buttonPressed();
904 }
Zhenkai Zhud616b582012-10-10 00:04:07 -0700905
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -0700906}
Zhenkai Zhue08afe02012-05-31 15:49:07 -0700907
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700908void
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700909ChatDialog::settingUpdated(QString nick, QString chatroom, QString originPrefix)
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700910{
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700911 QString randString = getRandomString();
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700912 bool needWrite = false;
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700913 bool needFresh = false;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700914 if (!nick.isEmpty() && nick != m_user.getNick()) {
915 m_user.setNick(nick);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700916 needWrite = true;
917 }
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -0700918 QString oldPrefix = m_user.getPrefix();
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700919 if (!originPrefix.isEmpty() && originPrefix != m_user.getOriginPrefix()) {
920 m_user.setOriginPrefix(originPrefix);
921 m_user.setPrefix(originPrefix + "/" + m_user.getChatroom() + "/" + randString);
Zhenkai Zhu716fe852012-10-08 18:27:55 -0700922 m_scene->setCurrentPrefix(originPrefix + "/" + m_user.getChatroom() + "/" + randString);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700923 needWrite = true;
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700924 needFresh = true;
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700925 }
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700926 if (!chatroom.isEmpty() && chatroom != m_user.getChatroom()) {
927 m_user.setChatroom(chatroom);
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700928 m_user.setPrefix(m_user.getOriginPrefix() + "/" + chatroom + "/" + randString);
Zhenkai Zhu716fe852012-10-08 18:27:55 -0700929 m_scene->setCurrentPrefix(m_user.getOriginPrefix() + "/" + chatroom + "/" + randString);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700930 needWrite = true;
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700931 needFresh = true;
932 }
933
Zhenkai Zhud616b582012-10-10 00:04:07 -0700934 if (needWrite) {
935 writeSettings();
936 updateLabels();
937 }
938
939 if (needFresh && m_sock != NULL)
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700940 {
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700941
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700942 {
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700943 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700944 m_scene->clearAll();
945 m_scene->plot("Empty");
946 }
Zhenkai Zhucc4c2c02012-09-27 21:24:37 -0700947
948 textEdit->clear();
949
Zhenkai Zhud616b582012-10-10 00:04:07 -0700950 // keep the new prefix
951 QString newPrefix = m_user.getPrefix();
952 // send leave for the old
953 m_user.setPrefix(oldPrefix);
954 // there is no point to send leave if we haven't joined yet
955 if (m_joined)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700956 {
Zhenkai Zhud616b582012-10-10 00:04:07 -0700957 sendLeave();
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700958 }
Zhenkai Zhud616b582012-10-10 00:04:07 -0700959 // resume new prefix
960 m_user.setPrefix(newPrefix);
961 // Sync::CcnxWrapperPtr handle = Sync::CcnxWrapper::Create();
962 // handle->clearInterestFilter(oldPrefix.toStdString());
963 m_history.clear();
964 m_historyInitialized = false;
965 delete m_sock;
966 m_sock = NULL;
967
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700968 std::string syncPrefix = BROADCAST_PREFIX_FOR_SYNC_DEMO;
969 syncPrefix += "/";
970 syncPrefix += m_user.getChatroom().toStdString();
Zhenkai Zhua4fb1242012-06-05 20:26:05 -0700971 try
972 {
Zhenkai Zhud616b582012-10-10 00:04:07 -0700973 usleep(100000);
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700974 m_sock = new Sync::SyncAppSocket(syncPrefix, bind(&ChatDialog::processTreeUpdateWrapper, this, _1, _2), bind(&ChatDialog::processRemoveWrapper, this, _1));
Zhenkai Zhud616b582012-10-10 00:04:07 -0700975 usleep(100000);
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700976 Sync::CcnxWrapperPtr handle = boost::make_shared<Sync::CcnxWrapper> ();
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -0700977 handle->setInterestFilter(m_user.getPrefix().toStdString(), bind(&ChatDialog::respondHistoryRequest, this, _1));
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700978 QTimer::singleShot(600, this, SLOT(sendJoin()));
Zhenkai Zhu78799ea2012-10-08 11:51:56 -0700979 m_timer->start(FRESHNESS * 1000);
Zhenkai Zhu0e7a9b22012-10-05 17:55:17 -0700980 disableTreeDisplay();
981 QTimer::singleShot(2200, this, SLOT(enableTreeDisplay()));
Zhenkai Zhua4fb1242012-06-05 20:26:05 -0700982 }
983 catch (Sync::CcnxOperationException ex)
984 {
Zhenkai Zhu0b3fa332012-09-27 21:58:43 -0700985 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 -0700986 std::exit(1);
987 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700988
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700989
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700990 }
Zhenkai Zhu6bb65e92012-10-10 10:34:39 -0700991 else if (needFresh && m_sock == NULL)
992 {
993 m_history.clear();
994 m_historyInitialized = false;
995 initializeSync();
996 }
Zhenkai Zhu8e180ae2012-10-10 14:01:05 -0700997 else if (m_sock == NULL)
998 {
999 initializeSync();
1000 }
Zhenkai Zhud616b582012-10-10 00:04:07 -07001001 else
1002 {
Zhenkai Zhu6bb65e92012-10-10 10:34:39 -07001003#ifdef __DEBUG
1004 std::cout << "Just changing nicks, we're good. " << std::endl;
1005#endif
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -07001006 }
Zhenkai Zhud616b582012-10-10 00:04:07 -07001007
1008 fitView();
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -07001009}
Zhenkai Zhud13acd02012-06-04 15:25:20 -07001010
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -07001011void
1012ChatDialog::iconActivated(QSystemTrayIcon::ActivationReason reason)
1013{
1014 switch (reason)
1015 {
1016 case QSystemTrayIcon::Trigger:
1017 case QSystemTrayIcon::DoubleClick:
1018 break;
1019 case QSystemTrayIcon::MiddleClick:
1020 // showMessage();
1021 break;
1022 default:;
1023 }
1024}
1025
1026void
1027ChatDialog::showMessage(QString from, QString data)
1028{
1029 // std::cout <<"Showing Message: " << from.toStdString() << ": " << data.toStdString() << std::endl;
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -07001030 if (!isActiveWindow())
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -07001031 {
1032 trayIcon->showMessage(QString("Chatroom %1 has a new message").arg(m_user.getChatroom()), QString("<%1>: %2").arg(from).arg(data), QSystemTrayIcon::Information, 20000);
1033 trayIcon->setIcon(QIcon(":/images/note.png"));
1034 }
1035}
1036
1037void
1038ChatDialog::messageClicked()
1039{
1040 this->showMaximized();
1041}
1042
1043void
1044ChatDialog::createActions()
1045{
1046 minimizeAction = new QAction(tr("Mi&nimize"), this);
1047 connect(minimizeAction, SIGNAL(triggered()), this, SLOT(hide()));
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -07001048
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -07001049 maximizeAction = new QAction(tr("Ma&ximize"), this);
1050 connect(maximizeAction, SIGNAL(triggered()), this, SLOT(showMaximized()));
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -07001051
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -07001052 restoreAction = new QAction(tr("&Restore"), this);
1053 connect(restoreAction, SIGNAL(triggered()), this, SLOT(showNormal()));
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -07001054
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -07001055 quitAction = new QAction(tr("Quit"), this);
1056 connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
1057}
1058
1059void
1060ChatDialog::createTrayIcon()
1061{
1062 trayIconMenu = new QMenu(this);
1063 trayIconMenu->addAction(minimizeAction);
1064 trayIconMenu->addAction(maximizeAction);
1065 trayIconMenu->addAction(restoreAction);
1066 trayIconMenu->addSeparator();
1067 trayIconMenu->addAction(quitAction);
1068
1069 trayIcon = new QSystemTrayIcon(this);
1070 trayIcon->setContextMenu(trayIconMenu);
1071
1072 QIcon icon(":/images/icon_small.png");
1073 trayIcon->setIcon(icon);
1074 setWindowIcon(icon);
Zhenkai Zhu0b3fa332012-09-27 21:58:43 -07001075 trayIcon->setToolTip("Chronos System Tray Icon");
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -07001076 trayIcon->setVisible(true);
1077}
1078
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -07001079void
Zhenkai Zhud13acd02012-06-04 15:25:20 -07001080ChatDialog::resizeEvent(QResizeEvent *e)
1081{
1082 fitView();
1083}
1084
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -07001085void
Zhenkai Zhud13acd02012-06-04 15:25:20 -07001086ChatDialog::showEvent(QShowEvent *e)
1087{
1088 fitView();
1089}
1090
1091void
1092ChatDialog::fitView()
1093{
Zhenkai Zhu9036e032012-09-27 20:59:33 -07001094 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu21d75f92012-06-04 21:23:34 -07001095 QRectF rect = m_scene->itemsBoundingRect();
1096 m_scene->setSceneRect(rect);
Zhenkai Zhu82a62752012-06-04 17:11:04 -07001097 treeViewer->fitInView(m_scene->itemsBoundingRect(), Qt::KeepAspectRatio);
Zhenkai Zhud13acd02012-06-04 15:25:20 -07001098}