blob: 2ade4bf4fcc92e77231163a48f3184299385d89c [file] [log] [blame]
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -07001#include <QtGui>
2#include "chatdialog.h"
Zhenkai Zhu85845d22012-06-01 23:10:43 -07003#include "settingdialog.h"
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -07004#include <ctime>
Zhenkai Zhub6338822012-05-31 13:27:24 -07005#include <iostream>
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -07006#include <QTimer>
Zhenkai Zhu10ccb5a2012-06-04 21:55:14 -07007#include <QMetaType>
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -07008#include <QMessageBox>
Zhenkai Zhu59245aa2012-09-26 16:07:04 -07009#include <boost/random/random_device.hpp>
10#include <boost/random/uniform_int_distribution.hpp>
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -070011#include <boost/lexical_cast.hpp>
Zhenkai Zhu6bda0bd2012-10-06 23:50:39 -070012#include <stdio.h>
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -070013
Zhenkai Zhu0b3fa332012-09-27 21:58:43 -070014#define BROADCAST_PREFIX_FOR_SYNC_DEMO "/ndn/broadcast/chronos"
Zhenkai Zhu6bda0bd2012-10-06 23:50:39 -070015#define LOCAL_PREFIX_QUERY "/local/ndn/prefix"
16#define DEFAULT_LOCAL_PREFIX "/private/local"
Zhenkai Zhu756666a2012-10-07 00:24:35 -070017#define CCN_EXEC "/usr/local/bin/ccnpeek"
Zhenkai Zhu82a62752012-06-04 17:11:04 -070018
Zhenkai Zhuc61dbc22012-10-08 11:36:37 -070019static const int HELLO_INTERVAL = FRESHNESS * 3 / 4; // seconds
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -070020
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -070021ChatDialog::ChatDialog(QWidget *parent)
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -070022 : QDialog(parent), m_sock(NULL), m_lastMsgTime(0), m_historyInitialized(false), m_joined(false)
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -070023{
Zhenkai Zhu10ccb5a2012-06-04 21:55:14 -070024 // have to register this, otherwise
25 // the signal-slot system won't recognize this type
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -070026 qRegisterMetaType<std::vector<Sync::MissingDataInfo> >("std::vector<Sync::MissingDataInfo>");
27 qRegisterMetaType<size_t>("size_t");
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -070028 setupUi(this);
Zhenkai Zhu82a62752012-06-04 17:11:04 -070029 m_session = time(NULL);
Zhenkai Zhu716fe852012-10-08 18:27:55 -070030 m_scene = new DigestTreeScene(this);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -070031
32 readSettings();
Zhenkai Zhu82a62752012-06-04 17:11:04 -070033
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -070034 updateLabels();
35
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -070036 lineEdit->setFocusPolicy(Qt::StrongFocus);
Zhenkai Zhub45e38a2012-06-01 15:44:36 -070037
Zhenkai Zhu82a62752012-06-04 17:11:04 -070038 treeViewer->setScene(m_scene);
39 m_scene->plot("Empty");
40 QRectF rect = m_scene->itemsBoundingRect();
41 m_scene->setSceneRect(rect);
42
Zhenkai Zhu9036e032012-09-27 20:59:33 -070043 listView->setStyleSheet("QListView { alternate-background-color: white; background: #F0F0F0; color: darkGreen; font: bold large; }");
Zhenkai Zhuf55f4382012-09-28 10:58:54 -070044 listView->setEditTriggers(QAbstractItemView::NoEditTriggers);
45 listView->setDragDropMode(QAbstractItemView::NoDragDrop);
46 listView->setSelectionMode(QAbstractItemView::NoSelection);
Zhenkai Zhu6082ede2012-09-27 17:28:46 -070047 m_rosterModel = new QStringListModel(this);
48 listView->setModel(m_rosterModel);
49
Zhenkai Zhu4b953d92012-10-08 13:09:40 -070050 refreshButton->setIcon(QIcon(QPixmap(":images/refresh.png")));
51
Zhenkai Zhu86df7412012-09-27 16:30:20 -070052 createActions();
53 createTrayIcon();
54 m_timer = new QTimer(this);
55 connect(lineEdit, SIGNAL(returnPressed()), this, SLOT(returnPressed()));
56 connect(setButton, SIGNAL(pressed()), this, SLOT(buttonPressed()));
Zhenkai Zhub60b7e12012-09-28 11:34:21 -070057 connect(treeButton, SIGNAL(pressed()), this, SLOT(treeButtonPressed()));
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -070058 connect(refreshButton, SIGNAL(pressed()), this, SLOT(updateLocalPrefix()));
Zhenkai Zhu24ec4722012-10-07 17:56:38 -070059 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 -070060 connect(this, SIGNAL(treeUpdated(const std::vector<Sync::MissingDataInfo>)), this, SLOT(processTreeUpdate(const std::vector<Sync::MissingDataInfo>)));
Zhenkai Zhu86df7412012-09-27 16:30:20 -070061 connect(m_timer, SIGNAL(timeout()), this, SLOT(replot()));
62 connect(m_scene, SIGNAL(replot()), this, SLOT(replot()));
63 connect(trayIcon, SIGNAL(messageClicked()), this, SLOT(showNormal()));
64 connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
Zhenkai Zhu25e33e52012-09-28 13:00:07 -070065 connect(m_scene, SIGNAL(rosterChanged(QStringList)), this, SLOT(updateRosterList(QStringList)));
Zhenkai Zhu86df7412012-09-27 16:30:20 -070066
Zhenkai Zhu82a62752012-06-04 17:11:04 -070067 // create sync socket
68 if(!m_user.getChatroom().isEmpty()) {
69 std::string syncPrefix = BROADCAST_PREFIX_FOR_SYNC_DEMO;
70 syncPrefix += "/";
71 syncPrefix += m_user.getChatroom().toStdString();
Zhenkai Zhua4fb1242012-06-05 20:26:05 -070072 try
73 {
Alexander Afanasyev288edd82012-10-04 17:07:56 -070074 m_sock = new Sync::SyncAppSocket(syncPrefix,
75 bind(&ChatDialog::processTreeUpdateWrapper, this, _1, _2),
76 bind(&ChatDialog::processRemoveWrapper, this, _1));
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -070077 Sync::CcnxWrapperPtr handle = Sync::CcnxWrapper::Create();
78 handle->setInterestFilter(m_user.getPrefix().toStdString(), bind(&ChatDialog::respondHistoryRequest, this, _1));
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -070079 //QTimer::singleShot(100, this, SLOT(getLocalPrefix()));
Zhenkai Zhu400cc892012-10-09 12:31:51 -070080 usleep(100000);
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -070081 if (!getLocalPrefix())
82 {
83 // if getLocalPrefix indicates no prefix change
84 // this sock is going to be used
85 QTimer::singleShot(600, this, SLOT(sendJoin()));
86 m_timer->start(FRESHNESS * 1000);
87 disableTreeDisplay();
88 QTimer::singleShot(2200, this, SLOT(enableTreeDisplay()));
89 }
90 else
91 {
92 // this socket is going to be destroyed anyway
93 // why bother doing the following steps
Alexander Afanasyevebe118d2012-10-08 08:56:34 -070094
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -070095 // the same steps would be performed for another socket
96 // in settingUpdated
97 }
Zhenkai Zhua4fb1242012-06-05 20:26:05 -070098 }
99 catch (Sync::CcnxOperationException ex)
100 {
Zhenkai Zhu0b3fa332012-09-27 21:58:43 -0700101 QMessageBox::critical(this, tr("Chronos"), tr("Canno connect to ccnd.\n Have you started your ccnd?"), QMessageBox::Ok);
Zhenkai Zhua4fb1242012-06-05 20:26:05 -0700102 std::exit(1);
103 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700104 }
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700105
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700106}
107
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700108ChatDialog::~ChatDialog()
109{
110 if (m_sock != NULL)
111 {
Zhenkai Zhucf024442012-10-05 10:33:08 -0700112 sendLeave();
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700113 delete m_sock;
114 m_sock = NULL;
115 }
116}
117
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700118void
Zhenkai Zhucf024442012-10-05 10:33:08 -0700119ChatDialog::sendLeave()
120{
121 SyncDemo::ChatMessage msg;
122 formControlMessage(msg, SyncDemo::ChatMessage::LEAVE);
123 sendMsg(msg);
124 usleep(500000);
125 m_sock->remove(m_user.getPrefix().toStdString());
126 usleep(5000);
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700127 m_joined = false;
Zhenkai Zhucf024442012-10-05 10:33:08 -0700128#ifdef __DEBUG
129 std::cout << "Sync REMOVE signal sent" << std::endl;
130#endif
131}
132
133void
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700134ChatDialog::replot()
135{
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700136 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700137 m_scene->plot(m_sock->getRootDigest().c_str());
Zhenkai Zhuc9e4e3c2012-10-02 11:47:31 -0700138 fitView();
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700139}
140
Zhenkai Zhu6082ede2012-09-27 17:28:46 -0700141void
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700142ChatDialog::updateRosterList(QStringList staleUserList)
Zhenkai Zhu6082ede2012-09-27 17:28:46 -0700143{
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700144 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu6082ede2012-09-27 17:28:46 -0700145 QStringList rosterList = m_scene->getRosterList();
146 m_rosterModel->setStringList(rosterList);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700147 QString user;
148 QStringListIterator it(staleUserList);
149 while(it.hasNext())
150 {
Zhenkai Zhu32cbdce2012-10-02 11:09:38 -0700151 std::string nick = it.next().toStdString();
152 if (nick.empty())
153 continue;
154
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700155 SyncDemo::ChatMessage msg;
Zhenkai Zhub5b78462012-09-28 14:10:37 -0700156 formControlMessage(msg, SyncDemo::ChatMessage::LEAVE);
Zhenkai Zhu32cbdce2012-10-02 11:09:38 -0700157 msg.set_from(nick);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700158 appendMessage(msg);
159 }
Zhenkai Zhu6082ede2012-09-27 17:28:46 -0700160}
161
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700162void
163ChatDialog::setVisible(bool visible)
164{
165 minimizeAction->setEnabled(visible);
166 maximizeAction->setEnabled(!isMaximized());
167 restoreAction->setEnabled(isMaximized() || !visible);
168 QDialog::setVisible(visible);
169}
170
171void
172ChatDialog::closeEvent(QCloseEvent *e)
173{
Zhenkai Zhu3974a492012-09-28 14:39:45 -0700174 if (trayIcon->isVisible() && !m_minimaniho)
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700175 {
Zhenkai Zhu0b3fa332012-09-27 21:58:43 -0700176 QMessageBox::information(this, tr("Chronos"),
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700177 tr("The program will keep running in the "
178 "system tray. To terminate the program"
179 "choose <b>Quit</b> in the context memu"
180 "of the system tray entry."));
181 hide();
182 e->ignore();
Zhenkai Zhu3974a492012-09-28 14:39:45 -0700183 m_minimaniho = true;
184 writeSettings();
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700185 }
186}
187
188void
189ChatDialog::changeEvent(QEvent *e)
190{
191 switch(e->type())
192 {
193 case QEvent::ActivationChange:
194 if (isActiveWindow())
195 {
196 trayIcon->setIcon(QIcon(":/images/icon_small.png"));
197 }
198 break;
199 default:
200 break;
201 }
202}
203
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700204void
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700205ChatDialog::appendMessage(const SyncDemo::ChatMessage msg, bool isHistory)
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700206{
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700207 boost::recursive_mutex::scoped_lock lock(m_msgMutex);
Zhenkai Zhub6338822012-05-31 13:27:24 -0700208
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700209 if (msg.type() == SyncDemo::ChatMessage::CHAT)
Zhenkai Zhub98e6022012-09-27 13:48:23 -0700210 {
Zhenkai Zhub98e6022012-09-27 13:48:23 -0700211
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700212 if (!msg.has_data())
Zhenkai Zhub98e6022012-09-27 13:48:23 -0700213 {
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700214 return;
Zhenkai Zhub98e6022012-09-27 13:48:23 -0700215 }
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700216
217 if (msg.from().empty() || msg.data().empty())
218 {
219 return;
220 }
221
222 if (!msg.has_timestamp())
223 {
224 return;
225 }
226
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -0700227 if (m_history.size() == MAX_HISTORY_ENTRY)
228 {
229 m_history.dequeue();
230 }
231
232 m_history.enqueue(msg);
233
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700234 QTextCharFormat nickFormat;
235 nickFormat.setForeground(Qt::darkGreen);
236 nickFormat.setFontWeight(QFont::Bold);
237 nickFormat.setFontUnderline(true);
238 nickFormat.setUnderlineColor(Qt::gray);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700239
240 QTextCursor cursor(textEdit->textCursor());
241 cursor.movePosition(QTextCursor::End);
242 QTextTableFormat tableFormat;
243 tableFormat.setBorder(0);
244 QTextTable *table = cursor.insertTable(1, 2, tableFormat);
245 QString from = QString("%1 ").arg(msg.from().c_str());
246 QTextTableCell fromCell = table->cellAt(0, 0);
247 fromCell.setFormat(nickFormat);
248 fromCell.firstCursorPosition().insertText(from);
Zhenkai Zhu560ef1b2012-09-28 14:23:33 -0700249
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700250 time_t timestamp = msg.timestamp();
Zhenkai Zhu560ef1b2012-09-28 14:23:33 -0700251 printTimeInCell(table, timestamp);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700252
253 QTextCursor nextCursor(textEdit->textCursor());
254 nextCursor.movePosition(QTextCursor::End);
255 table = nextCursor.insertTable(1, 1, tableFormat);
Zhenkai Zhu767eac72012-10-08 11:20:57 -0700256 table->cellAt(0, 0).firstCursorPosition().insertText(QString::fromUtf8(msg.data().c_str()));
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700257 if (!isHistory)
258 {
Zhenkai Zhu767eac72012-10-08 11:20:57 -0700259 showMessage(from, QString::fromUtf8(msg.data().c_str()));
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700260 }
Zhenkai Zhub98e6022012-09-27 13:48:23 -0700261 }
262
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700263 if (msg.type() == SyncDemo::ChatMessage::JOIN || msg.type() == SyncDemo::ChatMessage::LEAVE)
264 {
265 QTextCharFormat nickFormat;
266 nickFormat.setForeground(Qt::gray);
267 nickFormat.setFontWeight(QFont::Bold);
268 nickFormat.setFontUnderline(true);
269 nickFormat.setUnderlineColor(Qt::gray);
Zhenkai Zhub98e6022012-09-27 13:48:23 -0700270
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700271 QTextCursor cursor(textEdit->textCursor());
272 cursor.movePosition(QTextCursor::End);
273 QTextTableFormat tableFormat;
274 tableFormat.setBorder(0);
275 QTextTable *table = cursor.insertTable(1, 2, tableFormat);
276 QString action;
277 if (msg.type() == SyncDemo::ChatMessage::JOIN)
278 {
279 action = "enters room";
280 }
281 else
282 {
283 action = "leaves room";
284 }
285
286 QString from = QString("%1 %2 ").arg(msg.from().c_str()).arg(action);
287 QTextTableCell fromCell = table->cellAt(0, 0);
288 fromCell.setFormat(nickFormat);
289 fromCell.firstCursorPosition().insertText(from);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700290
Zhenkai Zhu560ef1b2012-09-28 14:23:33 -0700291 time_t timestamp = msg.timestamp();
292 printTimeInCell(table, timestamp);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700293 }
294
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700295 QScrollBar *bar = textEdit->verticalScrollBar();
296 bar->setValue(bar->maximum());
297}
298
Zhenkai Zhu560ef1b2012-09-28 14:23:33 -0700299void
300ChatDialog::printTimeInCell(QTextTable *table, time_t timestamp)
301{
302 QTextCharFormat timeFormat;
303 timeFormat.setForeground(Qt::gray);
304 timeFormat.setFontUnderline(true);
305 timeFormat.setUnderlineColor(Qt::gray);
306 QTextTableCell timeCell = table->cellAt(0, 1);
307 timeCell.setFormat(timeFormat);
308 timeCell.firstCursorPosition().insertText(formatTime(timestamp));
309}
310
311QString
312ChatDialog::formatTime(time_t timestamp)
313{
314 struct tm *tm_time = localtime(&timestamp);
315 int hour = tm_time->tm_hour;
316 QString amOrPM;
317 if (hour > 12)
318 {
319 hour -= 12;
320 amOrPM = "PM";
321 }
322 else
323 {
324 amOrPM = "AM";
325 if (hour == 0)
326 {
327 hour = 12;
328 }
329 }
330
331 char textTime[12];
332 sprintf(textTime, "%d:%02d:%02d %s", hour, tm_time->tm_min, tm_time->tm_sec, amOrPM.toStdString().c_str());
333 return QString(textTime);
334}
335
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700336void
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700337ChatDialog::processTreeUpdateWrapper(const std::vector<Sync::MissingDataInfo> v, Sync::SyncAppSocket *sock)
338{
339 emit treeUpdated(v);
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700340#ifdef __DEBUG
341 std::cout << "<<< Tree update signal emitted" << std::endl;
342#endif
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700343}
344
345void
346ChatDialog::processTreeUpdate(const std::vector<Sync::MissingDataInfo> v)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700347{
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700348#ifdef __DEBUG
349 std::cout << "<<< processing Tree Update" << std::endl;
350#endif
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700351 if (v.empty())
352 {
353 return;
354 }
355
356 // reflect the changes on digest tree
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700357 {
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700358 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700359 m_scene->processUpdate(v, m_sock->getRootDigest().c_str());
360 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700361
362 int n = v.size();
363 int totalMissingPackets = 0;
364 for (int i = 0; i < n; i++)
365 {
366 totalMissingPackets += v[i].high.getSeq() - v[i].low.getSeq() + 1;
367 }
368
Zhenkai Zhubb198112012-09-27 11:31:42 -0700369 for (int i = 0; i < n; i++)
370 {
371 if (totalMissingPackets < 4)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700372 {
373 for (Sync::SeqNo seq = v[i].low; seq <= v[i].high; ++seq)
374 {
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700375 m_sock->fetchRaw(v[i].prefix, seq, bind(&ChatDialog::processDataWrapper, this, _1, _2, _3), 2);
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700376#ifdef __DEBUG
377 std::cout << "<<< Fetching " << v[i].prefix << "/" <<seq.getSession() <<"/" << seq.getSeq() << std::endl;
378#endif
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700379 }
380 }
Zhenkai Zhubb198112012-09-27 11:31:42 -0700381 else
382 {
383 m_sock->fetchRaw(v[i].prefix, v[i].high, bind(&ChatDialog::processDataNoShowWrapper, this, _1, _2, _3), 2);
384 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700385 }
386
387 // adjust the view
388 fitView();
389
390}
391
392void
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700393ChatDialog::processDataWrapper(std::string name, const char *buf, size_t len)
394{
Zhenkai Zhuae29f5a2012-10-05 17:28:04 -0700395 char *tempBuf = new char[len];
396 memcpy(tempBuf, buf, len);
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700397 emit dataReceived(name.c_str(), tempBuf, len, true, false);
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700398#ifdef __DEBUG
399 std::cout <<"<<< " << name << " fetched" << std::endl;
400#endif
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700401}
402
403void
Zhenkai Zhubb198112012-09-27 11:31:42 -0700404ChatDialog::processDataNoShowWrapper(std::string name, const char *buf, size_t len)
405{
Zhenkai Zhuae29f5a2012-10-05 17:28:04 -0700406 char *tempBuf = new char[len];
407 memcpy(tempBuf, buf, len);
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700408 emit dataReceived(name.c_str(), tempBuf, len, false, false);
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -0700409
410 if (!m_historyInitialized)
411 {
412 fetchHistory(name);
413 m_historyInitialized = true;
414 }
415}
416
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700417void
418ChatDialog::processDataHistoryWrapper(std::string name, const char *buf, size_t len)
419{
420 char *tempBuf = new char[len];
421 memcpy(tempBuf, buf, len);
422 emit dataReceived(name.c_str(), tempBuf, len, true, true);
423}
424
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -0700425void
426ChatDialog::fetchHistory(std::string name)
427{
428 std::string nameWithoutSeq = name.substr(0, name.find_last_of('/'));
429 std::string prefix = nameWithoutSeq.substr(0, nameWithoutSeq.find_last_of('/'));
430 prefix += "/history";
431 Sync::CcnxWrapperPtr handle = Sync::CcnxWrapper::Create();
432 QString randomString = getRandomString();
433 for (int i = 0; i < MAX_HISTORY_ENTRY; i++)
434 {
435 QString interest = QString("%1/%2/%3").arg(prefix.c_str()).arg(randomString).arg(i);
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700436 handle->sendInterest(interest.toStdString(), bind(&ChatDialog::processDataHistoryWrapper, this, _1, _2, _3));
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -0700437 }
438}
439
440void
441ChatDialog::respondHistoryRequest(std::string interest)
442{
443 std::string seqStr = interest.substr(interest.find_last_of('/') + 1);
444 int seq = boost::lexical_cast<int>(seqStr);
445 if (seq >= 0 && seq < m_history.size())
446 {
447 Sync::CcnxWrapperPtr handle = Sync::CcnxWrapper::Create();
448 SyncDemo::ChatMessage msg = m_history.at(seq);
449 size_t size = msg.ByteSize();
450 char *buf = new char[size];
451 msg.SerializeToArray(buf, size);
452 handle->publishRawData(interest, buf, size, 1);
453 delete buf;
454 }
Zhenkai Zhubb198112012-09-27 11:31:42 -0700455}
456
457void
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700458ChatDialog::processData(QString name, const char *buf, size_t len, bool show, bool isHistory)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700459{
460 SyncDemo::ChatMessage msg;
Zhenkai Zhuef8d0632012-10-05 10:24:55 -0700461 bool corrupted = false;
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700462 if (!msg.ParseFromArray(buf, len))
463 {
Zhenkai Zhubb198112012-09-27 11:31:42 -0700464 std::cerr << "Errrrr.. Can not parse msg with name: " << name.toStdString() << ". what is happening?" << std::endl;
Zhenkai Zhuef8d0632012-10-05 10:24:55 -0700465 // nasty stuff: as a remedy, we'll form some standard msg for inparsable msgs
466 msg.set_from("inconnu");
467 msg.set_type(SyncDemo::ChatMessage::OTHER);
468 corrupted = true;
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700469 }
470
Zhenkai Zhuae29f5a2012-10-05 17:28:04 -0700471 delete [] buf;
472 buf = NULL;
473
Zhenkai Zhu10ccb5a2012-06-04 21:55:14 -0700474 // display msg received from network
475 // we have to do so; this function is called by ccnd thread
476 // so if we call appendMsg directly
477 // Qt crash as "QObject: Cannot create children for a parent that is in a different thread"
478 // the "cannonical" way to is use signal-slot
Zhenkai Zhuef8d0632012-10-05 10:24:55 -0700479 if (show && !corrupted)
Zhenkai Zhubb198112012-09-27 11:31:42 -0700480 {
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700481 appendMessage(msg, isHistory);
Zhenkai Zhubb198112012-09-27 11:31:42 -0700482 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700483
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700484 if (!isHistory)
485 {
486 // update the tree view
487 std::string stdStrName = name.toStdString();
488 std::string stdStrNameWithoutSeq = stdStrName.substr(0, stdStrName.find_last_of('/'));
489 std::string prefix = stdStrNameWithoutSeq.substr(0, stdStrNameWithoutSeq.find_last_of('/'));
Zhenkai Zhu097bfe72012-06-05 14:30:17 -0700490#ifdef __DEBUG
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700491 std::cout <<"<<< updating scene for" << prefix << ": " << msg.from() << std::endl;
Zhenkai Zhu097bfe72012-06-05 14:30:17 -0700492#endif
Zhenkai Zhu24ec4722012-10-07 17:56:38 -0700493 if (msg.type() == SyncDemo::ChatMessage::LEAVE)
494 {
495 processRemove(prefix.c_str());
496 }
497 else
498 {
499 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
500 m_scene->msgReceived(prefix.c_str(), msg.from().c_str());
501 }
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700502 }
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700503 fitView();
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700504}
505
506void
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700507ChatDialog::processRemoveWrapper(std::string prefix)
508{
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700509#ifdef __DEBUG
510 std::cout << "Sync REMOVE signal received for prefix: " << prefix << std::endl;
511#endif
512 //emit removeReceived(prefix.c_str());
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700513}
514
515void
516ChatDialog::processRemove(QString prefix)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700517{
Zhenkai Zhu591e8c32012-09-26 11:57:50 -0700518#ifdef __DEBUG
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700519 std::cout << "<<< remove node for prefix" << prefix.toStdString() << std::endl;
Zhenkai Zhu591e8c32012-09-26 11:57:50 -0700520#endif
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700521 bool removed = m_scene->removeNode(prefix);
Zhenkai Zhu591e8c32012-09-26 11:57:50 -0700522 if (removed)
523 {
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700524 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu591e8c32012-09-26 11:57:50 -0700525 m_scene->plot(m_sock->getRootDigest().c_str());
526 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700527}
528
529void
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700530ChatDialog::formChatMessage(const QString &text, SyncDemo::ChatMessage &msg) {
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700531 msg.set_from(m_user.getNick().toStdString());
532 msg.set_to(m_user.getChatroom().toStdString());
Zhenkai Zhu767eac72012-10-08 11:20:57 -0700533 msg.set_data(text.toUtf8().constData());
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700534 time_t seconds = time(NULL);
535 msg.set_timestamp(seconds);
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700536 msg.set_type(SyncDemo::ChatMessage::CHAT);
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700537}
538
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700539void
Zhenkai Zhub5b78462012-09-28 14:10:37 -0700540ChatDialog::formControlMessage(SyncDemo::ChatMessage &msg, SyncDemo::ChatMessage::ChatMessageType type)
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700541{
542 msg.set_from(m_user.getNick().toStdString());
543 msg.set_to(m_user.getChatroom().toStdString());
544 time_t seconds = time(NULL);
545 msg.set_timestamp(seconds);
Zhenkai Zhub5b78462012-09-28 14:10:37 -0700546 msg.set_type(type);
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700547}
548
Zhenkai Zhu59245aa2012-09-26 16:07:04 -0700549static std::string chars("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM0123456789");
550
551QString
552ChatDialog::getRandomString()
553{
554 std::string randStr;
555 boost::random::random_device rng;
556 boost::random::uniform_int_distribution<> index_dist(0, chars.size() - 1);
557 for (int i = 0; i < 10; i ++)
558 {
559 randStr += chars[index_dist(rng)];
560 }
561 return randStr.c_str();
562}
563
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700564bool
Zhenkai Zhu6bda0bd2012-10-06 23:50:39 -0700565ChatDialog::getLocalPrefix()
566{
Zhenkai Zhu86581412012-10-08 16:58:39 -0700567// /*
568// * this method tries to use ccncat
569// * however, it does not work in Mac OS X app bundle
570// * it works well in command line though
571// */
572
573// std::string cmd = CCN_EXEC;
574// cmd += " -c -v ";
575// cmd += LOCAL_PREFIX_QUERY;
576// QString localPrefix;
577// #define MAX_PREFIX_LEN 100
578// FILE *fp = popen(cmd.c_str(), "r");
579// if (fp != NULL)
580// {
581// char prefix[MAX_PREFIX_LEN];
582// if (fgets(prefix, MAX_PREFIX_LEN, fp) != NULL)
583// {
584// localPrefix = prefix;
585// localPrefix.remove('\n');
586// }
587// else
588// {
589// localPrefix = DEFAULT_LOCAL_PREFIX;
590// }
591// pclose(fp);
592// }
593// else
594// {
595// localPrefix = DEFAULT_LOCAL_PREFIX;
596// }
597// return localPrefix;
Alexander Afanasyevebe118d2012-10-08 08:56:34 -0700598 std::cerr << "trying to get local prefix" << std::endl;
599
Zhenkai Zhu86581412012-10-08 16:58:39 -0700600 if (m_sock != NULL)
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700601 {
602 QString originPrefix = QString::fromStdString (m_sock->getLocalPrefix()).trimmed ();
603 std::cerr << "got: " << originPrefix.toStdString () << std::endl;
Zhenkai Zhuba707342012-10-08 16:20:15 -0700604
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700605 if (originPrefix != "" && m_user.getOriginPrefix () != originPrefix)
Zhenkai Zhu86581412012-10-08 16:58:39 -0700606 {
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700607 emit settingUpdated(m_user.getNick (), m_user.getChatroom (), originPrefix);
608 // prefix updated
609 return true;
Zhenkai Zhu86581412012-10-08 16:58:39 -0700610 }
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700611 }
612
613 // prefix not changed
614 return false;
615}
616
617void
618ChatDialog::updateLocalPrefix()
619{
620 getLocalPrefix();
Zhenkai Zhu6bda0bd2012-10-06 23:50:39 -0700621}
622
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700623bool
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700624ChatDialog::readSettings()
625{
626 QSettings s(ORGANIZATION, APPLICATION);
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700627 QString nick = s.value("nick", "").toString();
628 QString chatroom = s.value("chatroom", "").toString();
Zhenkai Zhu86581412012-10-08 16:58:39 -0700629 // QString originPrefix = s.value("originPrefix", "").toString();
Alexander Afanasyev5ddc68b2012-10-08 00:21:40 -0700630
Zhenkai Zhu86581412012-10-08 16:58:39 -0700631 // Sync::CcnxWrapperPtr wrapper = Sync::CcnxWrapper::Create ();
632 // QString originPrefix = QString::fromStdString (wrapper->getLocalPrefix());
633 // Sync::CcnxWrapper::Destroy ();
Alexander Afanasyev5ddc68b2012-10-08 00:21:40 -0700634
Zhenkai Zhu86581412012-10-08 16:58:39 -0700635 QString originPrefix = DEFAULT_LOCAL_PREFIX;
Alexander Afanasyev5ddc68b2012-10-08 00:21:40 -0700636
Zhenkai Zhu3974a492012-09-28 14:39:45 -0700637 m_minimaniho = s.value("minimaniho", false).toBool();
638 if (nick == "" || chatroom == "" || originPrefix == "") {
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700639 QTimer::singleShot(500, this, SLOT(buttonPressed()));
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700640 return false;
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700641 }
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700642 else {
643 m_user.setNick(nick);
644 m_user.setChatroom(chatroom);
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700645 m_user.setOriginPrefix(originPrefix);
Zhenkai Zhu3974a492012-09-28 14:39:45 -0700646 m_user.setPrefix(originPrefix + "/" + chatroom + "/" + getRandomString());
Zhenkai Zhu716fe852012-10-08 18:27:55 -0700647 m_scene->setCurrentPrefix(originPrefix + "/" + chatroom + "/" + getRandomString());
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700648 return true;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700649 }
Zhenkai Zhu3974a492012-09-28 14:39:45 -0700650
651// QTimer::singleShot(500, this, SLOT(buttonPressed()));
652 // return false;
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700653}
654
655void
656ChatDialog::writeSettings()
657{
658 QSettings s(ORGANIZATION, APPLICATION);
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700659 s.setValue("nick", m_user.getNick());
660 s.setValue("chatroom", m_user.getChatroom());
Zhenkai Zhu6bda0bd2012-10-06 23:50:39 -0700661 //s.setValue("originPrefix", m_user.getOriginPrefix());
Zhenkai Zhu3974a492012-09-28 14:39:45 -0700662 s.setValue("minimaniho", m_minimaniho);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700663}
664
665void
666ChatDialog::updateLabels()
667{
Zhenkai Zhu76ff02b2012-09-27 21:11:03 -0700668 QString settingDisp = QString("Chatroom: %1").arg(m_user.getChatroom());
669 infoLabel->setStyleSheet("QLabel {color: #630; font-size: 16px; font: bold \"Verdana\";}");
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700670 infoLabel->setText(settingDisp);
Zhenkai Zhu6bda0bd2012-10-06 23:50:39 -0700671 QString prefixDisp;
672 if (m_user.getPrefix().startsWith(DEFAULT_LOCAL_PREFIX))
673 {
674 prefixDisp = QString("<Warning: Auto config prefix failed.>\n <Prefix = %1>").arg(m_user.getPrefix());
675 prefixLabel->setStyleSheet("QLabel {color: red; font-size: 12px; font: bold \"Verdana\";}");
676 }
677 else
678 {
679 prefixDisp = QString("<Prefix = %1>").arg(m_user.getPrefix());
680 prefixLabel->setStyleSheet("QLabel {color: Green; font-size: 12px; font: bold \"Verdana\";}");
681 }
682 prefixLabel->setText(prefixDisp);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700683}
684
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700685void
686ChatDialog::returnPressed()
687{
688 QString text = lineEdit->text();
689 if (text.isEmpty())
690 return;
691
Zhenkai Zhub6338822012-05-31 13:27:24 -0700692 lineEdit->clear();
693
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700694 SyncDemo::ChatMessage msg;
695 formChatMessage(text, msg);
696
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700697 appendMessage(msg);
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700698
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700699 sendMsg(msg);
700
701 fitView();
702}
703
704void
705ChatDialog::sendMsg(SyncDemo::ChatMessage &msg)
706{
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700707 // send msg
708 size_t size = msg.ByteSize();
709 char *buf = new char[size];
710 msg.SerializeToArray(buf, size);
711 if (!msg.IsInitialized())
712 {
713 std::cerr << "Errrrr.. msg was not probally initialized "<<__FILE__ <<":"<<__LINE__<<". what is happening?" << std::endl;
714 abort();
715 }
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700716 m_sock->publishRaw(m_user.getPrefix().toStdString(), m_session, buf, size, FRESHNESS);
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700717
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700718 delete buf;
719
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700720 m_lastMsgTime = time(NULL);
721
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700722 int nextSequence = m_sock->getNextSeq(m_user.getPrefix().toStdString(), m_session);
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700723 Sync::MissingDataInfo mdi = {m_user.getPrefix().toStdString(), Sync::SeqNo(0), Sync::SeqNo(nextSequence - 1)};
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700724 std::vector<Sync::MissingDataInfo> v;
725 v.push_back(mdi);
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700726 {
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700727 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700728 m_scene->processUpdate(v, m_sock->getRootDigest().c_str());
729 m_scene->msgReceived(m_user.getPrefix(), m_user.getNick());
730 }
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700731}
732
733void
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700734ChatDialog::sendJoin()
735{
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700736 m_joined = true;
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700737 SyncDemo::ChatMessage msg;
Zhenkai Zhub5b78462012-09-28 14:10:37 -0700738 formControlMessage(msg, SyncDemo::ChatMessage::JOIN);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700739 sendMsg(msg);
Zhenkai Zhuc61dbc22012-10-08 11:36:37 -0700740 boost::random::random_device rng;
741 boost::random::uniform_int_distribution<> uniform(1, FRESHNESS / 5 * 1000);
742 m_randomizedInterval = HELLO_INTERVAL * 1000 + uniform(rng);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700743 QTimer::singleShot(m_randomizedInterval, this, SLOT(sendHello()));
744}
745
746void
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700747ChatDialog::sendHello()
748{
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700749 time_t now = time(NULL);
750 int elapsed = now - m_lastMsgTime;
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700751 if (elapsed >= m_randomizedInterval / 1000)
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700752 {
753 SyncDemo::ChatMessage msg;
Zhenkai Zhub5b78462012-09-28 14:10:37 -0700754 formControlMessage(msg, SyncDemo::ChatMessage::HELLO);
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700755 sendMsg(msg);
Zhenkai Zhuc61dbc22012-10-08 11:36:37 -0700756 boost::random::random_device rng;
757 boost::random::uniform_int_distribution<> uniform(1, FRESHNESS / 5 * 1000);
758 m_randomizedInterval = HELLO_INTERVAL * 1000 + uniform(rng);
Zhenkai Zhuee5c90f2012-09-27 14:05:41 -0700759 QTimer::singleShot(m_randomizedInterval, this, SLOT(sendHello()));
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700760 }
761 else
762 {
Zhenkai Zhuee5c90f2012-09-27 14:05:41 -0700763 QTimer::singleShot((m_randomizedInterval - elapsed * 1000), this, SLOT(sendHello()));
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700764 }
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700765}
766
767void
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700768ChatDialog::buttonPressed()
769{
Alexander Afanasyev5ddc68b2012-10-08 00:21:40 -0700770 Sync::SyncLogic &logic = m_sock->getLogic ();
771 logic.printState ();
772
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700773 SettingDialog dialog(this, m_user.getNick(), m_user.getChatroom(), m_user.getOriginPrefix());
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700774 connect(&dialog, SIGNAL(updated(QString, QString, QString)), this, SLOT(settingUpdated(QString, QString, QString)));
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700775 dialog.exec();
Zhenkai Zhue837f792012-06-05 20:47:54 -0700776 QTimer::singleShot(100, this, SLOT(checkSetting()));
777}
778
Zhenkai Zhub60b7e12012-09-28 11:34:21 -0700779void ChatDialog::treeButtonPressed()
780{
781 if (treeViewer->isVisible())
782 {
783 treeViewer->hide();
784 treeButton->setText("Show Sync Tree");
785 }
786 else
787 {
788 treeViewer->show();
789 treeButton->setText("Hide Sync Tree");
790 }
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700791
792 fitView();
Zhenkai Zhub60b7e12012-09-28 11:34:21 -0700793}
794
Zhenkai Zhu0e7a9b22012-10-05 17:55:17 -0700795void ChatDialog::enableTreeDisplay()
796{
797 treeButton->setEnabled(true);
798 treeViewer->show();
799 fitView();
800}
801
802void ChatDialog::disableTreeDisplay()
803{
804 treeButton->setEnabled(false);
805 treeViewer->hide();
806 fitView();
807}
808
Zhenkai Zhue837f792012-06-05 20:47:54 -0700809void
810ChatDialog::checkSetting()
811{
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700812 if (m_user.getOriginPrefix().isEmpty() || m_user.getNick().isEmpty() || m_user.getChatroom().isEmpty())
Zhenkai Zhue837f792012-06-05 20:47:54 -0700813 {
814 buttonPressed();
815 }
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -0700816}
Zhenkai Zhue08afe02012-05-31 15:49:07 -0700817
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700818void
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700819ChatDialog::settingUpdated(QString nick, QString chatroom, QString originPrefix)
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700820{
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700821 QString randString = getRandomString();
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700822 bool needWrite = false;
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700823 bool needFresh = false;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700824 if (!nick.isEmpty() && nick != m_user.getNick()) {
825 m_user.setNick(nick);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700826 needWrite = true;
827 }
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -0700828 QString oldPrefix = m_user.getPrefix();
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700829 if (!originPrefix.isEmpty() && originPrefix != m_user.getOriginPrefix()) {
830 m_user.setOriginPrefix(originPrefix);
831 m_user.setPrefix(originPrefix + "/" + m_user.getChatroom() + "/" + randString);
Zhenkai Zhu716fe852012-10-08 18:27:55 -0700832 m_scene->setCurrentPrefix(originPrefix + "/" + m_user.getChatroom() + "/" + randString);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700833 needWrite = true;
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700834 needFresh = true;
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700835 }
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700836 if (!chatroom.isEmpty() && chatroom != m_user.getChatroom()) {
837 m_user.setChatroom(chatroom);
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700838 m_user.setPrefix(m_user.getOriginPrefix() + "/" + chatroom + "/" + randString);
Zhenkai Zhu716fe852012-10-08 18:27:55 -0700839 m_scene->setCurrentPrefix(m_user.getOriginPrefix() + "/" + chatroom + "/" + randString);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700840 needWrite = true;
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700841 needFresh = true;
842 }
843
844 if (needFresh)
845 {
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700846
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700847 {
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700848 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700849 m_scene->clearAll();
850 m_scene->plot("Empty");
851 }
Zhenkai Zhucc4c2c02012-09-27 21:24:37 -0700852
853 textEdit->clear();
854
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700855 if (m_sock != NULL)
856 {
Zhenkai Zhu77fc8f22012-10-08 15:12:56 -0700857 // keep the new prefix
858 QString newPrefix = m_user.getPrefix();
859 // send leave for the old
860 m_user.setPrefix(oldPrefix);
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700861 // there is no point to send leave if we haven't joined yet
862 if (m_joined)
863 {
864 sendLeave();
865 }
Zhenkai Zhu77fc8f22012-10-08 15:12:56 -0700866 // resume new prefix
867 m_user.setPrefix(newPrefix);
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -0700868 Sync::CcnxWrapperPtr handle = Sync::CcnxWrapper::Create();
869 handle->clearInterestFilter(oldPrefix.toStdString());
870 m_history.clear();
871 m_historyInitialized = false;
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700872 delete m_sock;
873 m_sock = NULL;
874 }
875 std::string syncPrefix = BROADCAST_PREFIX_FOR_SYNC_DEMO;
876 syncPrefix += "/";
877 syncPrefix += m_user.getChatroom().toStdString();
Zhenkai Zhua4fb1242012-06-05 20:26:05 -0700878 try
879 {
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700880 m_sock = new Sync::SyncAppSocket(syncPrefix, bind(&ChatDialog::processTreeUpdateWrapper, this, _1, _2), bind(&ChatDialog::processRemoveWrapper, this, _1));
Zhenkai Zhu6c4fc112012-10-07 17:07:43 -0700881 Sync::CcnxWrapperPtr handle = Sync::CcnxWrapper::Create();
882 handle->setInterestFilter(m_user.getPrefix().toStdString(), bind(&ChatDialog::respondHistoryRequest, this, _1));
Zhenkai Zhu0fe2b8c2012-10-09 04:49:28 -0700883 QTimer::singleShot(600, this, SLOT(sendJoin()));
Zhenkai Zhu78799ea2012-10-08 11:51:56 -0700884 m_timer->start(FRESHNESS * 1000);
Zhenkai Zhu0e7a9b22012-10-05 17:55:17 -0700885 disableTreeDisplay();
886 QTimer::singleShot(2200, this, SLOT(enableTreeDisplay()));
Zhenkai Zhua4fb1242012-06-05 20:26:05 -0700887 }
888 catch (Sync::CcnxOperationException ex)
889 {
Zhenkai Zhu0b3fa332012-09-27 21:58:43 -0700890 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 -0700891 std::exit(1);
892 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700893
894 fitView();
895
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700896 }
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700897
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700898 if (needWrite) {
899 writeSettings();
900 updateLabels();
901 }
902}
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700903
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700904void
905ChatDialog::iconActivated(QSystemTrayIcon::ActivationReason reason)
906{
907 switch (reason)
908 {
909 case QSystemTrayIcon::Trigger:
910 case QSystemTrayIcon::DoubleClick:
911 break;
912 case QSystemTrayIcon::MiddleClick:
913 // showMessage();
914 break;
915 default:;
916 }
917}
918
919void
920ChatDialog::showMessage(QString from, QString data)
921{
922 // std::cout <<"Showing Message: " << from.toStdString() << ": " << data.toStdString() << std::endl;
923 if (!isActiveWindow())
924 {
925 trayIcon->showMessage(QString("Chatroom %1 has a new message").arg(m_user.getChatroom()), QString("<%1>: %2").arg(from).arg(data), QSystemTrayIcon::Information, 20000);
926 trayIcon->setIcon(QIcon(":/images/note.png"));
927 }
928}
929
930void
931ChatDialog::messageClicked()
932{
933 this->showMaximized();
934}
935
936void
937ChatDialog::createActions()
938{
939 minimizeAction = new QAction(tr("Mi&nimize"), this);
940 connect(minimizeAction, SIGNAL(triggered()), this, SLOT(hide()));
941
942 maximizeAction = new QAction(tr("Ma&ximize"), this);
943 connect(maximizeAction, SIGNAL(triggered()), this, SLOT(showMaximized()));
944
945 restoreAction = new QAction(tr("&Restore"), this);
946 connect(restoreAction, SIGNAL(triggered()), this, SLOT(showNormal()));
947
948 quitAction = new QAction(tr("Quit"), this);
949 connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
950}
951
952void
953ChatDialog::createTrayIcon()
954{
955 trayIconMenu = new QMenu(this);
956 trayIconMenu->addAction(minimizeAction);
957 trayIconMenu->addAction(maximizeAction);
958 trayIconMenu->addAction(restoreAction);
959 trayIconMenu->addSeparator();
960 trayIconMenu->addAction(quitAction);
961
962 trayIcon = new QSystemTrayIcon(this);
963 trayIcon->setContextMenu(trayIconMenu);
964
965 QIcon icon(":/images/icon_small.png");
966 trayIcon->setIcon(icon);
967 setWindowIcon(icon);
Zhenkai Zhu0b3fa332012-09-27 21:58:43 -0700968 trayIcon->setToolTip("Chronos System Tray Icon");
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700969 trayIcon->setVisible(true);
970}
971
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700972void
973ChatDialog::resizeEvent(QResizeEvent *e)
974{
975 fitView();
976}
977
978void
979ChatDialog::showEvent(QShowEvent *e)
980{
981 fitView();
982}
983
984void
985ChatDialog::fitView()
986{
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700987 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700988 QRectF rect = m_scene->itemsBoundingRect();
989 m_scene->setSceneRect(rect);
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700990 treeViewer->fitInView(m_scene->itemsBoundingRect(), Qt::KeepAspectRatio);
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700991}