blob: 43d48608c842b060494abc6b6de182ea1574f204 [file] [log] [blame]
Alexander Afanasyevb4b92292013-07-09 13:54:59 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2/*
3 * Copyright (c) 2013, Regents of the University of California
4 * Alexander Afanasyev
5 * Zhenkai Zhu
6 *
7 * GNU v3.0 license, See the LICENSE file for more information
8 *
9 * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
10 * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
11 */
12
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -070013#include "chatdialog.h"
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -070014
Zhenkai Zhu85845d22012-06-01 23:10:43 -070015#include "settingdialog.h"
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -070016
17#include <QtGui>
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -070018#include <QTimer>
Zhenkai Zhu10ccb5a2012-06-04 21:55:14 -070019#include <QMetaType>
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -070020#include <QMessageBox>
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -070021
22#ifndef Q_MOC_RUN
23#include <ctime>
24#include <iostream>
25
Zhenkai Zhu59245aa2012-09-26 16:07:04 -070026#include <boost/random/random_device.hpp>
27#include <boost/random/uniform_int_distribution.hpp>
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -070028#include <boost/lexical_cast.hpp>
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -070029#include <boost/make_shared.hpp>
30
Zhenkai Zhu6bda0bd2012-10-06 23:50:39 -070031#include <stdio.h>
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -070032#endif
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -070033
Alexander Afanasyevb4b92292013-07-09 13:54:59 -070034#define BROADCAST_PREFIX_FOR_SYNC_DEMO "/ndn/broadcast/ChronoChat-0.3"
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -070035#define LOCAL_PREFIX_QUERY "/local/ndn/prefix"
Zhenkai Zhu6bda0bd2012-10-06 23:50:39 -070036#define DEFAULT_LOCAL_PREFIX "/private/local"
Alexander Afanasyevb4b92292013-07-09 13:54:59 -070037// #define CCN_EXEC "/usr/local/bin/ccnpeek"
Zhenkai Zhu82a62752012-06-04 17:11:04 -070038
Zhenkai Zhuc61dbc22012-10-08 11:36:37 -070039static const int HELLO_INTERVAL = FRESHNESS * 3 / 4; // seconds
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -070040
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -070041ChatDialog::ChatDialog(QWidget *parent)
Alexander Afanasyevb4b92292013-07-09 13:54:59 -070042 : QDialog(parent)
43 , m_sock(NULL)
44 , m_lastMsgTime(0)
45 , m_historyInitialized(false)
46 , m_joined(false)
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -070047{
Zhenkai Zhu10ccb5a2012-06-04 21:55:14 -070048 // have to register this, otherwise
49 // the signal-slot system won't recognize this type
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -070050 qRegisterMetaType<std::vector<Sync::MissingDataInfo> >("std::vector<Sync::MissingDataInfo>");
51 qRegisterMetaType<size_t>("size_t");
Alexander Afanasyevb4b92292013-07-09 13:54:59 -070052
53 setupUi (this);
54
Zhenkai Zhu82a62752012-06-04 17:11:04 -070055 m_session = time(NULL);
Zhenkai Zhu716fe852012-10-08 18:27:55 -070056 m_scene = new DigestTreeScene(this);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -070057
58 readSettings();
Zhenkai Zhu82a62752012-06-04 17:11:04 -070059
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -070060 updateLabels();
61
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -070062 lineEdit->setFocusPolicy(Qt::StrongFocus);
Zhenkai Zhub45e38a2012-06-01 15:44:36 -070063
Zhenkai Zhu82a62752012-06-04 17:11:04 -070064 treeViewer->setScene(m_scene);
Alexander Afanasyevb4b92292013-07-09 13:54:59 -070065 treeViewer->hide ();
Zhenkai Zhu82a62752012-06-04 17:11:04 -070066 m_scene->plot("Empty");
67 QRectF rect = m_scene->itemsBoundingRect();
68 m_scene->setSceneRect(rect);
69
Alexander Afanasyevb4b92292013-07-09 13:54:59 -070070 // listView->setStyleSheet("QListView { alternate-background-color: white; background: #F0F0F0; color: darkGreen; font: bold large; }");
71 // listView->setEditTriggers(QAbstractItemView::NoEditTriggers);
72 // listView->setDragDropMode(QAbstractItemView::NoDragDrop);
73 // listView->setSelectionMode(QAbstractItemView::NoSelection);
74
Zhenkai Zhu6082ede2012-09-27 17:28:46 -070075 m_rosterModel = new QStringListModel(this);
76 listView->setModel(m_rosterModel);
77
Alexander Afanasyevb4b92292013-07-09 13:54:59 -070078 // refreshButton->setIcon(QIcon(QPixmap(":images/refresh.png")));
79 // reapButton->hide();
Zhenkai Zhu4b953d92012-10-08 13:09:40 -070080
Zhenkai Zhu86df7412012-09-27 16:30:20 -070081 createActions();
82 createTrayIcon();
83 m_timer = new QTimer(this);
84 connect(lineEdit, SIGNAL(returnPressed()), this, SLOT(returnPressed()));
Alexander Afanasyevb4b92292013-07-09 13:54:59 -070085 // connect(setButton, SIGNAL(pressed()), this, SLOT(buttonPressed()));
Zhenkai Zhub60b7e12012-09-28 11:34:21 -070086 connect(treeButton, SIGNAL(pressed()), this, SLOT(treeButtonPressed()));
Alexander Afanasyevb4b92292013-07-09 13:54:59 -070087 // connect(reapButton, SIGNAL(pressed()), this, SLOT(summonReaper()));
88 // connect(refreshButton, SIGNAL(pressed()), this, SLOT(updateLocalPrefix()));
89
Zhenkai Zhu24ec4722012-10-07 17:56:38 -070090 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 -070091 connect(this, SIGNAL(treeUpdated(const std::vector<Sync::MissingDataInfo>)), this, SLOT(processTreeUpdate(const std::vector<Sync::MissingDataInfo>)));
Zhenkai Zhu86df7412012-09-27 16:30:20 -070092 connect(m_timer, SIGNAL(timeout()), this, SLOT(replot()));
93 connect(m_scene, SIGNAL(replot()), this, SLOT(replot()));
94 connect(trayIcon, SIGNAL(messageClicked()), this, SLOT(showNormal()));
95 connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
Zhenkai Zhu25e33e52012-09-28 13:00:07 -070096 connect(m_scene, SIGNAL(rosterChanged(QStringList)), this, SLOT(updateRosterList(QStringList)));
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -070097
Zhenkai Zhud616b582012-10-10 00:04:07 -070098 initializeSync();
Zhenkai Zhud616b582012-10-10 00:04:07 -070099}
100
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700101void
Zhenkai Zhud616b582012-10-10 00:04:07 -0700102ChatDialog::initializeSync()
103{
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700104 // create sync socket
Zhenkai Zhu8e180ae2012-10-10 14:01:05 -0700105 if(!m_user.getChatroom().isEmpty() && !m_user.getNick().isEmpty()) {
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700106 std::string syncPrefix = BROADCAST_PREFIX_FOR_SYNC_DEMO;
107 syncPrefix += "/";
108 syncPrefix += m_user.getChatroom().toStdString();
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700109 try
Zhenkai Zhua4fb1242012-06-05 20:26:05 -0700110 {
Alexander Afanasyev288edd82012-10-04 17:07:56 -0700111 m_sock = new Sync::SyncAppSocket(syncPrefix,
112 bind(&ChatDialog::processTreeUpdateWrapper, this, _1, _2),
113 bind(&ChatDialog::processRemoveWrapper, this, _1));
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700114 //QTimer::singleShot(100, this, SLOT(getLocalPrefix()));
Zhenkai Zhu400cc892012-10-09 12:31:51 -0700115 usleep(100000);
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700116 if (!getLocalPrefix())
117 {
118 // if getLocalPrefix indicates no prefix change
119 // this sock is going to be used
120 QTimer::singleShot(600, this, SLOT(sendJoin()));
121 m_timer->start(FRESHNESS * 1000);
122 disableTreeDisplay();
123 QTimer::singleShot(2200, this, SLOT(enableTreeDisplay()));
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700124 Sync::CcnxWrapperPtr handle = boost::make_shared<Sync::CcnxWrapper> ();
Zhenkai Zhu5ee10092012-10-09 12:48:52 -0700125 handle->setInterestFilter(m_user.getPrefix().toStdString(), bind(&ChatDialog::respondHistoryRequest, this, _1));
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700126 }
127 else
128 {
129 // this socket is going to be destroyed anyway
130 // why bother doing the following steps
Alexander Afanasyevebe118d2012-10-08 08:56:34 -0700131
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700132 // the same steps would be performed for another socket
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700133 // in settingUpdated
134 }
Zhenkai Zhua4fb1242012-06-05 20:26:05 -0700135 }
136 catch (Sync::CcnxOperationException ex)
137 {
Zhenkai Zhu0b3fa332012-09-27 21:58:43 -0700138 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 -0700139 std::exit(1);
140 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700141 }
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700142}
143
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700144ChatDialog::~ChatDialog()
145{
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700146 if (m_sock != NULL)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700147 {
Zhenkai Zhucf024442012-10-05 10:33:08 -0700148 sendLeave();
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700149 delete m_sock;
150 m_sock = NULL;
151 }
152}
153
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700154void
Zhenkai Zhucf024442012-10-05 10:33:08 -0700155ChatDialog::sendLeave()
156{
157 SyncDemo::ChatMessage msg;
158 formControlMessage(msg, SyncDemo::ChatMessage::LEAVE);
159 sendMsg(msg);
160 usleep(500000);
161 m_sock->remove(m_user.getPrefix().toStdString());
162 usleep(5000);
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700163 m_joined = false;
Zhenkai Zhucf024442012-10-05 10:33:08 -0700164#ifdef __DEBUG
165 std::cout << "Sync REMOVE signal sent" << std::endl;
166#endif
167}
168
169void
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700170ChatDialog::replot()
171{
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700172 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700173 m_scene->plot(m_sock->getRootDigest().c_str());
Zhenkai Zhuc9e4e3c2012-10-02 11:47:31 -0700174 fitView();
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700175}
176
Zhenkai Zhu6082ede2012-09-27 17:28:46 -0700177void
Zhenkai Zhu7f52e1b2012-10-09 11:45:36 -0700178ChatDialog::summonReaper()
179{
180 Sync::SyncLogic &logic = m_sock->getLogic ();
181 std::map<std::string, bool> branches = logic.getBranchPrefixes();
182 QMap<QString, DisplayUserPtr> roster = m_scene->getRosterFull();
183
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700184 m_zombieList.clear();
Zhenkai Zhu7f52e1b2012-10-09 11:45:36 -0700185
186 QMapIterator<QString, DisplayUserPtr> it(roster);
187 std::map<std::string, bool>::iterator mapIt;
188 while(it.hasNext())
189 {
190 it.next();
191 DisplayUserPtr p = it.value();
192 if (p != DisplayUserNullPtr)
193 {
194 mapIt = branches.find(p->getPrefix().toStdString());
195 if (mapIt != branches.end())
196 {
197 mapIt->second = true;
198 }
199 }
200 }
201
202 for (mapIt = branches.begin(); mapIt != branches.end(); ++mapIt)
203 {
204 // this is zombie. all active users should have been marked true
205 if (! mapIt->second)
206 {
207 m_zombieList.append(mapIt->first.c_str());
208 }
209 }
210
211 m_zombieIndex = 0;
212
213 // start reaping
214 reap();
215}
216
217void
218ChatDialog::reap()
219{
220 if (m_zombieIndex < m_zombieList.size())
221 {
222 std::string prefix = m_zombieList.at(m_zombieIndex).toStdString();
223 m_sock->remove(prefix);
224 std::cout << "Reaped: prefix = " << prefix << std::endl;
225 m_zombieIndex++;
226 // reap again in 10 seconds
227 QTimer::singleShot(10000, this, SLOT(reap()));
228 }
229}
230
231void
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700232ChatDialog::updateRosterList(QStringList staleUserList)
Zhenkai Zhu6082ede2012-09-27 17:28:46 -0700233{
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700234 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu6082ede2012-09-27 17:28:46 -0700235 QStringList rosterList = m_scene->getRosterList();
236 m_rosterModel->setStringList(rosterList);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700237 QString user;
238 QStringListIterator it(staleUserList);
239 while(it.hasNext())
240 {
Zhenkai Zhu32cbdce2012-10-02 11:09:38 -0700241 std::string nick = it.next().toStdString();
242 if (nick.empty())
243 continue;
244
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700245 SyncDemo::ChatMessage msg;
Zhenkai Zhub5b78462012-09-28 14:10:37 -0700246 formControlMessage(msg, SyncDemo::ChatMessage::LEAVE);
Zhenkai Zhu32cbdce2012-10-02 11:09:38 -0700247 msg.set_from(nick);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700248 appendMessage(msg);
249 }
Zhenkai Zhu6082ede2012-09-27 17:28:46 -0700250}
251
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700252void
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700253ChatDialog::setVisible(bool visible)
254{
255 minimizeAction->setEnabled(visible);
256 maximizeAction->setEnabled(!isMaximized());
Alexander Afanasyevd6d12f12013-07-13 15:07:08 -0700257 // restoreAction->setEnabled(isMaximized() || !visible);
Alexander Afanasyevb4b92292013-07-09 13:54:59 -0700258
259 raise(); // for MacOS
260 activateWindow(); // for Windows
261
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700262 QDialog::setVisible(visible);
263}
264
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700265void
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700266ChatDialog::closeEvent(QCloseEvent *e)
267{
Zhenkai Zhu3974a492012-09-28 14:39:45 -0700268 if (trayIcon->isVisible() && !m_minimaniho)
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700269 {
Zhenkai Zhu0b3fa332012-09-27 21:58:43 -0700270 QMessageBox::information(this, tr("Chronos"),
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700271 tr("The program will keep running in the "
272 "system tray. To terminate the program"
273 "choose <b>Quit</b> in the context memu"
274 "of the system tray entry."));
275 hide();
276 e->ignore();
Zhenkai Zhu3974a492012-09-28 14:39:45 -0700277 m_minimaniho = true;
278 writeSettings();
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700279 }
280}
281
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700282void
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700283ChatDialog::changeEvent(QEvent *e)
284{
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700285 switch(e->type())
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700286 {
287 case QEvent::ActivationChange:
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700288 if (isActiveWindow())
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700289 {
290 trayIcon->setIcon(QIcon(":/images/icon_small.png"));
291 }
292 break;
293 default:
294 break;
295 }
296}
297
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700298void
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700299ChatDialog::appendMessage(const SyncDemo::ChatMessage msg, bool isHistory)
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700300{
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700301 boost::recursive_mutex::scoped_lock lock(m_msgMutex);
Zhenkai Zhub6338822012-05-31 13:27:24 -0700302
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700303 if (msg.type() == SyncDemo::ChatMessage::CHAT)
Zhenkai Zhub98e6022012-09-27 13:48:23 -0700304 {
Zhenkai Zhub98e6022012-09-27 13:48:23 -0700305
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700306 if (!msg.has_data())
Zhenkai Zhub98e6022012-09-27 13:48:23 -0700307 {
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700308 return;
Zhenkai Zhub98e6022012-09-27 13:48:23 -0700309 }
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700310
311 if (msg.from().empty() || msg.data().empty())
312 {
313 return;
314 }
315
316 if (!msg.has_timestamp())
317 {
318 return;
319 }
320
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -0700321 if (m_history.size() == MAX_HISTORY_ENTRY)
322 {
323 m_history.dequeue();
324 }
325
326 m_history.enqueue(msg);
327
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700328 QTextCharFormat nickFormat;
329 nickFormat.setForeground(Qt::darkGreen);
330 nickFormat.setFontWeight(QFont::Bold);
331 nickFormat.setFontUnderline(true);
332 nickFormat.setUnderlineColor(Qt::gray);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700333
334 QTextCursor cursor(textEdit->textCursor());
335 cursor.movePosition(QTextCursor::End);
336 QTextTableFormat tableFormat;
337 tableFormat.setBorder(0);
338 QTextTable *table = cursor.insertTable(1, 2, tableFormat);
339 QString from = QString("%1 ").arg(msg.from().c_str());
340 QTextTableCell fromCell = table->cellAt(0, 0);
341 fromCell.setFormat(nickFormat);
342 fromCell.firstCursorPosition().insertText(from);
Zhenkai Zhu560ef1b2012-09-28 14:23:33 -0700343
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700344 time_t timestamp = msg.timestamp();
Zhenkai Zhu560ef1b2012-09-28 14:23:33 -0700345 printTimeInCell(table, timestamp);
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700346
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700347 QTextCursor nextCursor(textEdit->textCursor());
348 nextCursor.movePosition(QTextCursor::End);
349 table = nextCursor.insertTable(1, 1, tableFormat);
Zhenkai Zhu767eac72012-10-08 11:20:57 -0700350 table->cellAt(0, 0).firstCursorPosition().insertText(QString::fromUtf8(msg.data().c_str()));
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700351 if (!isHistory)
352 {
Zhenkai Zhu767eac72012-10-08 11:20:57 -0700353 showMessage(from, QString::fromUtf8(msg.data().c_str()));
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700354 }
Zhenkai Zhub98e6022012-09-27 13:48:23 -0700355 }
356
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700357 if (msg.type() == SyncDemo::ChatMessage::JOIN || msg.type() == SyncDemo::ChatMessage::LEAVE)
358 {
359 QTextCharFormat nickFormat;
360 nickFormat.setForeground(Qt::gray);
361 nickFormat.setFontWeight(QFont::Bold);
362 nickFormat.setFontUnderline(true);
363 nickFormat.setUnderlineColor(Qt::gray);
Zhenkai Zhub98e6022012-09-27 13:48:23 -0700364
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700365 QTextCursor cursor(textEdit->textCursor());
366 cursor.movePosition(QTextCursor::End);
367 QTextTableFormat tableFormat;
368 tableFormat.setBorder(0);
369 QTextTable *table = cursor.insertTable(1, 2, tableFormat);
370 QString action;
371 if (msg.type() == SyncDemo::ChatMessage::JOIN)
372 {
373 action = "enters room";
374 }
375 else
376 {
377 action = "leaves room";
378 }
379
380 QString from = QString("%1 %2 ").arg(msg.from().c_str()).arg(action);
381 QTextTableCell fromCell = table->cellAt(0, 0);
382 fromCell.setFormat(nickFormat);
383 fromCell.firstCursorPosition().insertText(from);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700384
Zhenkai Zhu560ef1b2012-09-28 14:23:33 -0700385 time_t timestamp = msg.timestamp();
386 printTimeInCell(table, timestamp);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700387 }
388
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700389 QScrollBar *bar = textEdit->verticalScrollBar();
390 bar->setValue(bar->maximum());
391}
392
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700393void
Zhenkai Zhu560ef1b2012-09-28 14:23:33 -0700394ChatDialog::printTimeInCell(QTextTable *table, time_t timestamp)
395{
396 QTextCharFormat timeFormat;
397 timeFormat.setForeground(Qt::gray);
398 timeFormat.setFontUnderline(true);
399 timeFormat.setUnderlineColor(Qt::gray);
400 QTextTableCell timeCell = table->cellAt(0, 1);
401 timeCell.setFormat(timeFormat);
402 timeCell.firstCursorPosition().insertText(formatTime(timestamp));
403}
404
405QString
406ChatDialog::formatTime(time_t timestamp)
407{
408 struct tm *tm_time = localtime(&timestamp);
409 int hour = tm_time->tm_hour;
410 QString amOrPM;
411 if (hour > 12)
412 {
413 hour -= 12;
414 amOrPM = "PM";
415 }
416 else
417 {
418 amOrPM = "AM";
419 if (hour == 0)
420 {
421 hour = 12;
422 }
423 }
424
425 char textTime[12];
426 sprintf(textTime, "%d:%02d:%02d %s", hour, tm_time->tm_min, tm_time->tm_sec, amOrPM.toStdString().c_str());
427 return QString(textTime);
428}
429
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700430void
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700431ChatDialog::processTreeUpdateWrapper(const std::vector<Sync::MissingDataInfo> v, Sync::SyncAppSocket *sock)
432{
433 emit treeUpdated(v);
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700434#ifdef __DEBUG
435 std::cout << "<<< Tree update signal emitted" << std::endl;
436#endif
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700437}
438
439void
440ChatDialog::processTreeUpdate(const std::vector<Sync::MissingDataInfo> v)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700441{
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700442#ifdef __DEBUG
443 std::cout << "<<< processing Tree Update" << std::endl;
444#endif
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700445 if (v.empty())
446 {
447 return;
448 }
449
450 // reflect the changes on digest tree
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700451 {
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700452 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700453 m_scene->processUpdate(v, m_sock->getRootDigest().c_str());
454 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700455
456 int n = v.size();
457 int totalMissingPackets = 0;
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700458 for (int i = 0; i < n; i++)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700459 {
460 totalMissingPackets += v[i].high.getSeq() - v[i].low.getSeq() + 1;
461 }
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700462
463 for (int i = 0; i < n; i++)
Zhenkai Zhubb198112012-09-27 11:31:42 -0700464 {
465 if (totalMissingPackets < 4)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700466 {
467 for (Sync::SeqNo seq = v[i].low; seq <= v[i].high; ++seq)
468 {
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700469 m_sock->fetchRaw(v[i].prefix, seq, bind(&ChatDialog::processDataWrapper, this, _1, _2, _3), 2);
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700470#ifdef __DEBUG
471 std::cout << "<<< Fetching " << v[i].prefix << "/" <<seq.getSession() <<"/" << seq.getSeq() << std::endl;
472#endif
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700473 }
474 }
Zhenkai Zhubb198112012-09-27 11:31:42 -0700475 else
476 {
477 m_sock->fetchRaw(v[i].prefix, v[i].high, bind(&ChatDialog::processDataNoShowWrapper, this, _1, _2, _3), 2);
478 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700479 }
480
481 // adjust the view
482 fitView();
483
484}
485
486void
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700487ChatDialog::processDataWrapper(std::string name, const char *buf, size_t len)
488{
Zhenkai Zhuae29f5a2012-10-05 17:28:04 -0700489 char *tempBuf = new char[len];
490 memcpy(tempBuf, buf, len);
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700491 emit dataReceived(name.c_str(), tempBuf, len, true, false);
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700492#ifdef __DEBUG
493 std::cout <<"<<< " << name << " fetched" << std::endl;
494#endif
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700495}
496
497void
Zhenkai Zhubb198112012-09-27 11:31:42 -0700498ChatDialog::processDataNoShowWrapper(std::string name, const char *buf, size_t len)
499{
Zhenkai Zhuae29f5a2012-10-05 17:28:04 -0700500 char *tempBuf = new char[len];
501 memcpy(tempBuf, buf, len);
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700502 emit dataReceived(name.c_str(), tempBuf, len, false, false);
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700503
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -0700504 if (!m_historyInitialized)
505 {
506 fetchHistory(name);
507 m_historyInitialized = true;
508 }
509}
510
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700511void
512ChatDialog::processDataHistoryWrapper(std::string name, const char *buf, size_t len)
513{
514 char *tempBuf = new char[len];
515 memcpy(tempBuf, buf, len);
516 emit dataReceived(name.c_str(), tempBuf, len, true, true);
517}
518
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700519void
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -0700520ChatDialog::fetchHistory(std::string name)
521{
522 std::string nameWithoutSeq = name.substr(0, name.find_last_of('/'));
523 std::string prefix = nameWithoutSeq.substr(0, nameWithoutSeq.find_last_of('/'));
524 prefix += "/history";
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700525 Sync::CcnxWrapperPtr handle = boost::make_shared<Sync::CcnxWrapper> ();
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -0700526 QString randomString = getRandomString();
527 for (int i = 0; i < MAX_HISTORY_ENTRY; i++)
528 {
529 QString interest = QString("%1/%2/%3").arg(prefix.c_str()).arg(randomString).arg(i);
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700530 handle->sendInterest(interest.toStdString(), bind(&ChatDialog::processDataHistoryWrapper, this, _1, _2, _3));
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -0700531 }
532}
533
534void
535ChatDialog::respondHistoryRequest(std::string interest)
536{
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700537 std::string seqStr = interest.substr(interest.find_last_of('/') + 1);
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -0700538 int seq = boost::lexical_cast<int>(seqStr);
539 if (seq >= 0 && seq < m_history.size())
540 {
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700541 Sync::CcnxWrapperPtr handle = boost::make_shared<Sync::CcnxWrapper> ();
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -0700542 SyncDemo::ChatMessage msg = m_history.at(seq);
543 size_t size = msg.ByteSize();
544 char *buf = new char[size];
545 msg.SerializeToArray(buf, size);
546 handle->publishRawData(interest, buf, size, 1);
547 delete buf;
548 }
Zhenkai Zhubb198112012-09-27 11:31:42 -0700549}
550
551void
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700552ChatDialog::processData(QString name, const char *buf, size_t len, bool show, bool isHistory)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700553{
554 SyncDemo::ChatMessage msg;
Zhenkai Zhuef8d0632012-10-05 10:24:55 -0700555 bool corrupted = false;
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700556 if (!msg.ParseFromArray(buf, len))
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700557 {
Zhenkai Zhubb198112012-09-27 11:31:42 -0700558 std::cerr << "Errrrr.. Can not parse msg with name: " << name.toStdString() << ". what is happening?" << std::endl;
Zhenkai Zhuef8d0632012-10-05 10:24:55 -0700559 // nasty stuff: as a remedy, we'll form some standard msg for inparsable msgs
560 msg.set_from("inconnu");
561 msg.set_type(SyncDemo::ChatMessage::OTHER);
562 corrupted = true;
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700563 }
564
Zhenkai Zhuae29f5a2012-10-05 17:28:04 -0700565 delete [] buf;
566 buf = NULL;
567
Zhenkai Zhu10ccb5a2012-06-04 21:55:14 -0700568 // display msg received from network
569 // we have to do so; this function is called by ccnd thread
570 // so if we call appendMsg directly
571 // Qt crash as "QObject: Cannot create children for a parent that is in a different thread"
572 // the "cannonical" way to is use signal-slot
Zhenkai Zhuef8d0632012-10-05 10:24:55 -0700573 if (show && !corrupted)
Zhenkai Zhubb198112012-09-27 11:31:42 -0700574 {
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700575 appendMessage(msg, isHistory);
Zhenkai Zhubb198112012-09-27 11:31:42 -0700576 }
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700577
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700578 if (!isHistory)
579 {
580 // update the tree view
581 std::string stdStrName = name.toStdString();
582 std::string stdStrNameWithoutSeq = stdStrName.substr(0, stdStrName.find_last_of('/'));
583 std::string prefix = stdStrNameWithoutSeq.substr(0, stdStrNameWithoutSeq.find_last_of('/'));
Zhenkai Zhu097bfe72012-06-05 14:30:17 -0700584#ifdef __DEBUG
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700585 std::cout <<"<<< updating scene for" << prefix << ": " << msg.from() << std::endl;
Zhenkai Zhu097bfe72012-06-05 14:30:17 -0700586#endif
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700587 if (msg.type() == SyncDemo::ChatMessage::LEAVE)
588 {
589 processRemove(prefix.c_str());
590 }
591 else
592 {
593 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
594 m_scene->msgReceived(prefix.c_str(), msg.from().c_str());
595 }
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700596 }
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700597 fitView();
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700598}
599
600void
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700601ChatDialog::processRemoveWrapper(std::string prefix)
602{
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700603#ifdef __DEBUG
604 std::cout << "Sync REMOVE signal received for prefix: " << prefix << std::endl;
605#endif
606 //emit removeReceived(prefix.c_str());
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700607}
608
609void
610ChatDialog::processRemove(QString prefix)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700611{
Zhenkai Zhu591e8c32012-09-26 11:57:50 -0700612#ifdef __DEBUG
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700613 std::cout << "<<< remove node for prefix" << prefix.toStdString() << std::endl;
Zhenkai Zhu591e8c32012-09-26 11:57:50 -0700614#endif
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700615 bool removed = m_scene->removeNode(prefix);
Zhenkai Zhu591e8c32012-09-26 11:57:50 -0700616 if (removed)
617 {
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700618 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu591e8c32012-09-26 11:57:50 -0700619 m_scene->plot(m_sock->getRootDigest().c_str());
620 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700621}
622
623void
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700624ChatDialog::formChatMessage(const QString &text, SyncDemo::ChatMessage &msg) {
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700625 msg.set_from(m_user.getNick().toStdString());
626 msg.set_to(m_user.getChatroom().toStdString());
Zhenkai Zhu767eac72012-10-08 11:20:57 -0700627 msg.set_data(text.toUtf8().constData());
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700628 time_t seconds = time(NULL);
629 msg.set_timestamp(seconds);
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700630 msg.set_type(SyncDemo::ChatMessage::CHAT);
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700631}
632
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700633void
Zhenkai Zhub5b78462012-09-28 14:10:37 -0700634ChatDialog::formControlMessage(SyncDemo::ChatMessage &msg, SyncDemo::ChatMessage::ChatMessageType type)
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700635{
636 msg.set_from(m_user.getNick().toStdString());
637 msg.set_to(m_user.getChatroom().toStdString());
638 time_t seconds = time(NULL);
639 msg.set_timestamp(seconds);
Zhenkai Zhub5b78462012-09-28 14:10:37 -0700640 msg.set_type(type);
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700641}
642
Zhenkai Zhu59245aa2012-09-26 16:07:04 -0700643static std::string chars("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM0123456789");
644
645QString
646ChatDialog::getRandomString()
647{
648 std::string randStr;
649 boost::random::random_device rng;
650 boost::random::uniform_int_distribution<> index_dist(0, chars.size() - 1);
651 for (int i = 0; i < 10; i ++)
652 {
653 randStr += chars[index_dist(rng)];
654 }
655 return randStr.c_str();
656}
657
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700658bool
Zhenkai Zhu6bda0bd2012-10-06 23:50:39 -0700659ChatDialog::getLocalPrefix()
660{
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700661// /*
662// * this method tries to use ccncat
Zhenkai Zhu86581412012-10-08 16:58:39 -0700663// * however, it does not work in Mac OS X app bundle
664// * it works well in command line though
665// */
666
667// std::string cmd = CCN_EXEC;
668// cmd += " -c -v ";
669// cmd += LOCAL_PREFIX_QUERY;
670// QString localPrefix;
671// #define MAX_PREFIX_LEN 100
672// FILE *fp = popen(cmd.c_str(), "r");
673// if (fp != NULL)
674// {
675// char prefix[MAX_PREFIX_LEN];
676// if (fgets(prefix, MAX_PREFIX_LEN, fp) != NULL)
677// {
678// localPrefix = prefix;
679// localPrefix.remove('\n');
680// }
681// else
682// {
683// localPrefix = DEFAULT_LOCAL_PREFIX;
684// }
685// pclose(fp);
686// }
687// else
688// {
689// localPrefix = DEFAULT_LOCAL_PREFIX;
690// }
691// return localPrefix;
Alexander Afanasyevebe118d2012-10-08 08:56:34 -0700692 std::cerr << "trying to get local prefix" << std::endl;
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700693
Zhenkai Zhu86581412012-10-08 16:58:39 -0700694 if (m_sock != NULL)
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700695 {
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700696 QString originPrefix = QString::fromStdString (m_sock->GetLocalPrefix()).trimmed ();
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700697 std::cerr << "got: " << originPrefix.toStdString () << std::endl;
Zhenkai Zhuba707342012-10-08 16:20:15 -0700698
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700699 if (originPrefix != "" && m_user.getOriginPrefix () != originPrefix)
Zhenkai Zhu86581412012-10-08 16:58:39 -0700700 {
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700701 emit settingUpdated(m_user.getNick (), m_user.getChatroom (), originPrefix);
702 // prefix updated
703 return true;
Zhenkai Zhu86581412012-10-08 16:58:39 -0700704 }
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700705 }
706
707 // prefix not changed
708 return false;
709}
710
711void
712ChatDialog::updateLocalPrefix()
713{
714 getLocalPrefix();
Zhenkai Zhu6bda0bd2012-10-06 23:50:39 -0700715}
716
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700717bool
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700718ChatDialog::readSettings()
719{
Alexander Afanasyevb4b92292013-07-09 13:54:59 -0700720 QSettings settings (QSettings::NativeFormat, QSettings::UserScope, ORGANIZATION, APPLICATION);
721
722 QString nick = settings.value("nick", "").toString();
723 QString chatroom = settings.value("chatroom", "").toString();
724 // QString originPrefix = settings.value("originPrefix", "").toString();
Alexander Afanasyev5ddc68b2012-10-08 00:21:40 -0700725
Zhenkai Zhu86581412012-10-08 16:58:39 -0700726 // Sync::CcnxWrapperPtr wrapper = Sync::CcnxWrapper::Create ();
727 // QString originPrefix = QString::fromStdString (wrapper->getLocalPrefix());
728 // Sync::CcnxWrapper::Destroy ();
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700729
Zhenkai Zhu86581412012-10-08 16:58:39 -0700730 QString originPrefix = DEFAULT_LOCAL_PREFIX;
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700731
Alexander Afanasyevb4b92292013-07-09 13:54:59 -0700732 m_minimaniho = settings.value("minimaniho", false).toBool();
Zhenkai Zhu3974a492012-09-28 14:39:45 -0700733 if (nick == "" || chatroom == "" || originPrefix == "") {
Zhenkai Zhud616b582012-10-10 00:04:07 -0700734 m_user.setOriginPrefix(DEFAULT_LOCAL_PREFIX);
Alexander Afanasyev721c8b92013-07-14 11:49:33 -0700735 m_user.setChatroom("clue");
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700736 QTimer::singleShot(500, this, SLOT(buttonPressed()));
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700737 return false;
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700738 }
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700739 else {
740 m_user.setNick(nick);
741 m_user.setChatroom(chatroom);
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700742 m_user.setOriginPrefix(originPrefix);
Zhenkai Zhu3974a492012-09-28 14:39:45 -0700743 m_user.setPrefix(originPrefix + "/" + chatroom + "/" + getRandomString());
Zhenkai Zhu716fe852012-10-08 18:27:55 -0700744 m_scene->setCurrentPrefix(originPrefix + "/" + chatroom + "/" + getRandomString());
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700745 return true;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700746 }
Zhenkai Zhu3974a492012-09-28 14:39:45 -0700747
748// QTimer::singleShot(500, this, SLOT(buttonPressed()));
749 // return false;
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700750}
751
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700752void
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700753ChatDialog::writeSettings()
754{
Alexander Afanasyevb4b92292013-07-09 13:54:59 -0700755 QSettings settings (QSettings::NativeFormat, QSettings::UserScope, ORGANIZATION, APPLICATION);
756
757 settings.setValue("nick", m_user.getNick());
758 settings.setValue("chatroom", m_user.getChatroom());
759 //settings.setValue("originPrefix", m_user.getOriginPrefix());
760 settings.setValue("minimaniho", m_minimaniho);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700761}
762
763void
764ChatDialog::updateLabels()
765{
Zhenkai Zhu76ff02b2012-09-27 21:11:03 -0700766 QString settingDisp = QString("Chatroom: %1").arg(m_user.getChatroom());
767 infoLabel->setStyleSheet("QLabel {color: #630; font-size: 16px; font: bold \"Verdana\";}");
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700768 infoLabel->setText(settingDisp);
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700769 QString prefixDisp;
Zhenkai Zhu6bda0bd2012-10-06 23:50:39 -0700770 if (m_user.getPrefix().startsWith(DEFAULT_LOCAL_PREFIX))
771 {
Zhenkai Zhud616b582012-10-10 00:04:07 -0700772 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 -0700773 prefixLabel->setStyleSheet("QLabel {color: red; font-size: 12px; font: bold \"Verdana\";}");
774 }
775 else
776 {
777 prefixDisp = QString("<Prefix = %1>").arg(m_user.getPrefix());
778 prefixLabel->setStyleSheet("QLabel {color: Green; font-size: 12px; font: bold \"Verdana\";}");
779 }
780 prefixLabel->setText(prefixDisp);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700781}
782
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700783void
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700784ChatDialog::returnPressed()
785{
786 QString text = lineEdit->text();
787 if (text.isEmpty())
788 return;
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700789
Zhenkai Zhub6338822012-05-31 13:27:24 -0700790 lineEdit->clear();
791
Zhenkai Zhu22c7d4d2012-10-09 12:29:32 -0700792 if (text.startsWith("boruoboluomi"))
793 {
Alexander Afanasyevb4b92292013-07-09 13:54:59 -0700794 summonReaper ();
795 // reapButton->show();
Zhenkai Zhu22c7d4d2012-10-09 12:29:32 -0700796 fitView();
797 return;
798 }
799
800 if (text.startsWith("minimanihong"))
801 {
Alexander Afanasyevb4b92292013-07-09 13:54:59 -0700802 // reapButton->hide();
Zhenkai Zhu22c7d4d2012-10-09 12:29:32 -0700803 fitView();
804 return;
805 }
806
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700807 SyncDemo::ChatMessage msg;
808 formChatMessage(text, msg);
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700809
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700810 appendMessage(msg);
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700811
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700812 sendMsg(msg);
813
814 fitView();
815}
816
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700817void
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700818ChatDialog::sendMsg(SyncDemo::ChatMessage &msg)
819{
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700820 // send msg
821 size_t size = msg.ByteSize();
822 char *buf = new char[size];
823 msg.SerializeToArray(buf, size);
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700824 if (!msg.IsInitialized())
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700825 {
826 std::cerr << "Errrrr.. msg was not probally initialized "<<__FILE__ <<":"<<__LINE__<<". what is happening?" << std::endl;
827 abort();
828 }
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700829 m_sock->publishRaw(m_user.getPrefix().toStdString(), m_session, buf, size, FRESHNESS);
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700830
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700831 delete buf;
832
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700833 m_lastMsgTime = time(NULL);
834
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700835 int nextSequence = m_sock->getNextSeq(m_user.getPrefix().toStdString(), m_session);
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700836 Sync::MissingDataInfo mdi = {m_user.getPrefix().toStdString(), Sync::SeqNo(0), Sync::SeqNo(nextSequence - 1)};
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700837 std::vector<Sync::MissingDataInfo> v;
838 v.push_back(mdi);
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700839 {
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700840 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700841 m_scene->processUpdate(v, m_sock->getRootDigest().c_str());
842 m_scene->msgReceived(m_user.getPrefix(), m_user.getNick());
843 }
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700844}
845
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700846void
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700847ChatDialog::sendJoin()
848{
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700849 m_joined = true;
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700850 SyncDemo::ChatMessage msg;
Zhenkai Zhub5b78462012-09-28 14:10:37 -0700851 formControlMessage(msg, SyncDemo::ChatMessage::JOIN);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700852 sendMsg(msg);
Zhenkai Zhuc61dbc22012-10-08 11:36:37 -0700853 boost::random::random_device rng;
854 boost::random::uniform_int_distribution<> uniform(1, FRESHNESS / 5 * 1000);
855 m_randomizedInterval = HELLO_INTERVAL * 1000 + uniform(rng);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700856 QTimer::singleShot(m_randomizedInterval, this, SLOT(sendHello()));
857}
858
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700859void
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700860ChatDialog::sendHello()
861{
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700862 time_t now = time(NULL);
863 int elapsed = now - m_lastMsgTime;
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700864 if (elapsed >= m_randomizedInterval / 1000)
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700865 {
866 SyncDemo::ChatMessage msg;
Zhenkai Zhub5b78462012-09-28 14:10:37 -0700867 formControlMessage(msg, SyncDemo::ChatMessage::HELLO);
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700868 sendMsg(msg);
Zhenkai Zhuc61dbc22012-10-08 11:36:37 -0700869 boost::random::random_device rng;
870 boost::random::uniform_int_distribution<> uniform(1, FRESHNESS / 5 * 1000);
871 m_randomizedInterval = HELLO_INTERVAL * 1000 + uniform(rng);
Zhenkai Zhuee5c90f2012-09-27 14:05:41 -0700872 QTimer::singleShot(m_randomizedInterval, this, SLOT(sendHello()));
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700873 }
874 else
875 {
Zhenkai Zhuee5c90f2012-09-27 14:05:41 -0700876 QTimer::singleShot((m_randomizedInterval - elapsed * 1000), this, SLOT(sendHello()));
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700877 }
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700878}
879
880void
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700881ChatDialog::buttonPressed()
882{
Zhenkai Zhud616b582012-10-10 00:04:07 -0700883 if (m_sock != NULL)
884 {
885 Sync::SyncLogic &logic = m_sock->getLogic ();
886 logic.printState ();
887 }
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -0700888
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700889 SettingDialog dialog(this, m_user.getNick(), m_user.getChatroom(), m_user.getOriginPrefix());
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700890 connect(&dialog, SIGNAL(updated(QString, QString, QString)), this, SLOT(settingUpdated(QString, QString, QString)));
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700891 dialog.exec();
Zhenkai Zhue837f792012-06-05 20:47:54 -0700892 QTimer::singleShot(100, this, SLOT(checkSetting()));
893}
894
Zhenkai Zhub60b7e12012-09-28 11:34:21 -0700895void ChatDialog::treeButtonPressed()
896{
897 if (treeViewer->isVisible())
898 {
899 treeViewer->hide();
Alexander Afanasyevb4b92292013-07-09 13:54:59 -0700900 treeButton->setText("Show ChronoSync Tree");
Zhenkai Zhub60b7e12012-09-28 11:34:21 -0700901 }
902 else
903 {
904 treeViewer->show();
Alexander Afanasyevb4b92292013-07-09 13:54:59 -0700905 treeButton->setText("Hide ChronoSync Tree");
Zhenkai Zhub60b7e12012-09-28 11:34:21 -0700906 }
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700907
908 fitView();
Zhenkai Zhub60b7e12012-09-28 11:34:21 -0700909}
910
Zhenkai Zhu0e7a9b22012-10-05 17:55:17 -0700911void ChatDialog::enableTreeDisplay()
912{
913 treeButton->setEnabled(true);
Alexander Afanasyevb4b92292013-07-09 13:54:59 -0700914 // treeViewer->show();
915 // fitView();
Zhenkai Zhu0e7a9b22012-10-05 17:55:17 -0700916}
917
918void ChatDialog::disableTreeDisplay()
919{
920 treeButton->setEnabled(false);
921 treeViewer->hide();
922 fitView();
923}
924
Zhenkai Zhue837f792012-06-05 20:47:54 -0700925void
926ChatDialog::checkSetting()
927{
Zhenkai Zhud616b582012-10-10 00:04:07 -0700928 if (m_user.getNick().isEmpty() || m_user.getChatroom().isEmpty() || m_user.getOriginPrefix().isEmpty())
Zhenkai Zhue837f792012-06-05 20:47:54 -0700929 {
930 buttonPressed();
931 }
Zhenkai Zhud616b582012-10-10 00:04:07 -0700932
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -0700933}
Zhenkai Zhue08afe02012-05-31 15:49:07 -0700934
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700935void
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700936ChatDialog::settingUpdated(QString nick, QString chatroom, QString originPrefix)
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700937{
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700938 QString randString = getRandomString();
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700939 bool needWrite = false;
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700940 bool needFresh = false;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700941 if (!nick.isEmpty() && nick != m_user.getNick()) {
942 m_user.setNick(nick);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700943 needWrite = true;
944 }
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -0700945 QString oldPrefix = m_user.getPrefix();
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700946 if (!originPrefix.isEmpty() && originPrefix != m_user.getOriginPrefix()) {
947 m_user.setOriginPrefix(originPrefix);
948 m_user.setPrefix(originPrefix + "/" + m_user.getChatroom() + "/" + randString);
Zhenkai Zhu716fe852012-10-08 18:27:55 -0700949 m_scene->setCurrentPrefix(originPrefix + "/" + m_user.getChatroom() + "/" + randString);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700950 needWrite = true;
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700951 needFresh = true;
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700952 }
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700953 if (!chatroom.isEmpty() && chatroom != m_user.getChatroom()) {
954 m_user.setChatroom(chatroom);
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700955 m_user.setPrefix(m_user.getOriginPrefix() + "/" + chatroom + "/" + randString);
Zhenkai Zhu716fe852012-10-08 18:27:55 -0700956 m_scene->setCurrentPrefix(m_user.getOriginPrefix() + "/" + chatroom + "/" + randString);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700957 needWrite = true;
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700958 needFresh = true;
959 }
960
Zhenkai Zhud616b582012-10-10 00:04:07 -0700961 if (needWrite) {
962 writeSettings();
963 updateLabels();
964 }
965
966 if (needFresh && m_sock != NULL)
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700967 {
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700968
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700969 {
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700970 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700971 m_scene->clearAll();
972 m_scene->plot("Empty");
973 }
Zhenkai Zhucc4c2c02012-09-27 21:24:37 -0700974
975 textEdit->clear();
976
Zhenkai Zhud616b582012-10-10 00:04:07 -0700977 // keep the new prefix
978 QString newPrefix = m_user.getPrefix();
979 // send leave for the old
980 m_user.setPrefix(oldPrefix);
981 // there is no point to send leave if we haven't joined yet
982 if (m_joined)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700983 {
Zhenkai Zhud616b582012-10-10 00:04:07 -0700984 sendLeave();
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700985 }
Zhenkai Zhud616b582012-10-10 00:04:07 -0700986 // resume new prefix
987 m_user.setPrefix(newPrefix);
988 // Sync::CcnxWrapperPtr handle = Sync::CcnxWrapper::Create();
989 // handle->clearInterestFilter(oldPrefix.toStdString());
990 m_history.clear();
991 m_historyInitialized = false;
992 delete m_sock;
993 m_sock = NULL;
994
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700995 std::string syncPrefix = BROADCAST_PREFIX_FOR_SYNC_DEMO;
996 syncPrefix += "/";
997 syncPrefix += m_user.getChatroom().toStdString();
Zhenkai Zhua4fb1242012-06-05 20:26:05 -0700998 try
999 {
Zhenkai Zhud616b582012-10-10 00:04:07 -07001000 usleep(100000);
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -07001001 m_sock = new Sync::SyncAppSocket(syncPrefix, bind(&ChatDialog::processTreeUpdateWrapper, this, _1, _2), bind(&ChatDialog::processRemoveWrapper, this, _1));
Zhenkai Zhud616b582012-10-10 00:04:07 -07001002 usleep(100000);
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -07001003 Sync::CcnxWrapperPtr handle = boost::make_shared<Sync::CcnxWrapper> ();
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -07001004 handle->setInterestFilter(m_user.getPrefix().toStdString(), bind(&ChatDialog::respondHistoryRequest, this, _1));
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -07001005 QTimer::singleShot(600, this, SLOT(sendJoin()));
Zhenkai Zhu78799ea2012-10-08 11:51:56 -07001006 m_timer->start(FRESHNESS * 1000);
Zhenkai Zhu0e7a9b22012-10-05 17:55:17 -07001007 disableTreeDisplay();
1008 QTimer::singleShot(2200, this, SLOT(enableTreeDisplay()));
Zhenkai Zhua4fb1242012-06-05 20:26:05 -07001009 }
1010 catch (Sync::CcnxOperationException ex)
1011 {
Zhenkai Zhu0b3fa332012-09-27 21:58:43 -07001012 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 -07001013 std::exit(1);
1014 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -07001015
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -07001016
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -07001017 }
Zhenkai Zhu6bb65e92012-10-10 10:34:39 -07001018 else if (needFresh && m_sock == NULL)
1019 {
1020 m_history.clear();
1021 m_historyInitialized = false;
1022 initializeSync();
1023 }
Zhenkai Zhu8e180ae2012-10-10 14:01:05 -07001024 else if (m_sock == NULL)
1025 {
1026 initializeSync();
1027 }
Zhenkai Zhud616b582012-10-10 00:04:07 -07001028 else
1029 {
Zhenkai Zhu6bb65e92012-10-10 10:34:39 -07001030#ifdef __DEBUG
1031 std::cout << "Just changing nicks, we're good. " << std::endl;
1032#endif
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -07001033 }
Zhenkai Zhud616b582012-10-10 00:04:07 -07001034
1035 fitView();
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -07001036}
Zhenkai Zhud13acd02012-06-04 15:25:20 -07001037
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -07001038void
1039ChatDialog::iconActivated(QSystemTrayIcon::ActivationReason reason)
1040{
1041 switch (reason)
1042 {
1043 case QSystemTrayIcon::Trigger:
1044 case QSystemTrayIcon::DoubleClick:
1045 break;
1046 case QSystemTrayIcon::MiddleClick:
1047 // showMessage();
1048 break;
1049 default:;
1050 }
1051}
1052
1053void
1054ChatDialog::showMessage(QString from, QString data)
1055{
1056 // std::cout <<"Showing Message: " << from.toStdString() << ": " << data.toStdString() << std::endl;
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -07001057 if (!isActiveWindow())
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -07001058 {
1059 trayIcon->showMessage(QString("Chatroom %1 has a new message").arg(m_user.getChatroom()), QString("<%1>: %2").arg(from).arg(data), QSystemTrayIcon::Information, 20000);
1060 trayIcon->setIcon(QIcon(":/images/note.png"));
1061 }
1062}
1063
1064void
1065ChatDialog::messageClicked()
1066{
1067 this->showMaximized();
1068}
1069
1070void
1071ChatDialog::createActions()
1072{
1073 minimizeAction = new QAction(tr("Mi&nimize"), this);
1074 connect(minimizeAction, SIGNAL(triggered()), this, SLOT(hide()));
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -07001075
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -07001076 maximizeAction = new QAction(tr("Ma&ximize"), this);
1077 connect(maximizeAction, SIGNAL(triggered()), this, SLOT(showMaximized()));
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -07001078
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -07001079 restoreAction = new QAction(tr("&Restore"), this);
1080 connect(restoreAction, SIGNAL(triggered()), this, SLOT(showNormal()));
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -07001081
Alexander Afanasyevb4b92292013-07-09 13:54:59 -07001082 settingsAction = new QAction(tr("Settings"), this);
1083 connect (settingsAction, SIGNAL(triggered()), this, SLOT(buttonPressed()));
1084
1085 settingsAction->setMenuRole (QAction::PreferencesRole);
1086
1087 updateLocalPrefixAction = new QAction(tr("Update local prefix"), this);
1088 connect (updateLocalPrefixAction, SIGNAL(triggered()), this, SLOT(updateLocalPrefix()));
1089
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -07001090 quitAction = new QAction(tr("Quit"), this);
1091 connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
1092}
1093
1094void
1095ChatDialog::createTrayIcon()
1096{
1097 trayIconMenu = new QMenu(this);
1098 trayIconMenu->addAction(minimizeAction);
1099 trayIconMenu->addAction(maximizeAction);
1100 trayIconMenu->addAction(restoreAction);
1101 trayIconMenu->addSeparator();
Alexander Afanasyevb4b92292013-07-09 13:54:59 -07001102 trayIconMenu->addAction(settingsAction);
1103 trayIconMenu->addSeparator();
1104 trayIconMenu->addAction(updateLocalPrefixAction);
1105 trayIconMenu->addSeparator();
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -07001106 trayIconMenu->addAction(quitAction);
1107
1108 trayIcon = new QSystemTrayIcon(this);
1109 trayIcon->setContextMenu(trayIconMenu);
1110
1111 QIcon icon(":/images/icon_small.png");
1112 trayIcon->setIcon(icon);
1113 setWindowIcon(icon);
Zhenkai Zhu0b3fa332012-09-27 21:58:43 -07001114 trayIcon->setToolTip("Chronos System Tray Icon");
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -07001115 trayIcon->setVisible(true);
Alexander Afanasyevb4b92292013-07-09 13:54:59 -07001116
1117 // // QApplication::getMenu ()->addMenu (trayIconMenu);
1118 // QMenuBar *bar = new QMenuBar ();
1119 // bar->setMenu (trayIconMenu);
1120 // setMenuBar (bar);
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -07001121}
1122
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -07001123void
Zhenkai Zhud13acd02012-06-04 15:25:20 -07001124ChatDialog::resizeEvent(QResizeEvent *e)
1125{
1126 fitView();
1127}
1128
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -07001129void
Zhenkai Zhud13acd02012-06-04 15:25:20 -07001130ChatDialog::showEvent(QShowEvent *e)
1131{
1132 fitView();
1133}
1134
1135void
1136ChatDialog::fitView()
1137{
Zhenkai Zhu9036e032012-09-27 20:59:33 -07001138 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu21d75f92012-06-04 21:23:34 -07001139 QRectF rect = m_scene->itemsBoundingRect();
1140 m_scene->setSceneRect(rect);
Zhenkai Zhu82a62752012-06-04 17:11:04 -07001141 treeViewer->fitInView(m_scene->itemsBoundingRect(), Qt::KeepAspectRatio);
Zhenkai Zhud13acd02012-06-04 15:25:20 -07001142}
Alexander Afanasyevb4b92292013-07-09 13:54:59 -07001143
1144#if WAF
1145#include "chatdialog.moc"
1146#include "chatdialog.cpp.moc"
1147#endif