blob: 90ba598f275e1e4f96a49e05aa26e85a830002d6 [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 Zhu6d589aa2012-05-29 17:34:35 -070011
Zhenkai Zhu0b3fa332012-09-27 21:58:43 -070012#define BROADCAST_PREFIX_FOR_SYNC_DEMO "/ndn/broadcast/chronos"
Zhenkai Zhu82a62752012-06-04 17:11:04 -070013
Zhenkai Zhuee5c90f2012-09-27 14:05:41 -070014static const int HELLO_INTERVAL = 90; // seconds
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -070015
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -070016ChatDialog::ChatDialog(QWidget *parent)
Zhenkai Zhu25e33e52012-09-28 13:00:07 -070017 : QDialog(parent), m_sock(NULL), m_lastMsgTime(0)
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -070018{
Zhenkai Zhu10ccb5a2012-06-04 21:55:14 -070019 // have to register this, otherwise
20 // the signal-slot system won't recognize this type
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -070021 qRegisterMetaType<std::vector<Sync::MissingDataInfo> >("std::vector<Sync::MissingDataInfo>");
22 qRegisterMetaType<size_t>("size_t");
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -070023 setupUi(this);
Zhenkai Zhu82a62752012-06-04 17:11:04 -070024 m_session = time(NULL);
Zhenkai Zhuee5c90f2012-09-27 14:05:41 -070025 boost::random::random_device rng;
26 boost::random::uniform_int_distribution<> uniform(1, 29000);
27 m_randomizedInterval = HELLO_INTERVAL * 1000 + uniform(rng);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -070028
29 readSettings();
Zhenkai Zhu82a62752012-06-04 17:11:04 -070030
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -070031 updateLabels();
32
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -070033 lineEdit->setFocusPolicy(Qt::StrongFocus);
Zhenkai Zhu82a62752012-06-04 17:11:04 -070034 m_scene = new DigestTreeScene(this);
Zhenkai Zhub45e38a2012-06-01 15:44:36 -070035
Zhenkai Zhu82a62752012-06-04 17:11:04 -070036 treeViewer->setScene(m_scene);
37 m_scene->plot("Empty");
38 QRectF rect = m_scene->itemsBoundingRect();
39 m_scene->setSceneRect(rect);
40
Zhenkai Zhu9036e032012-09-27 20:59:33 -070041 listView->setStyleSheet("QListView { alternate-background-color: white; background: #F0F0F0; color: darkGreen; font: bold large; }");
Zhenkai Zhuf55f4382012-09-28 10:58:54 -070042 listView->setEditTriggers(QAbstractItemView::NoEditTriggers);
43 listView->setDragDropMode(QAbstractItemView::NoDragDrop);
44 listView->setSelectionMode(QAbstractItemView::NoSelection);
Zhenkai Zhu6082ede2012-09-27 17:28:46 -070045 m_rosterModel = new QStringListModel(this);
46 listView->setModel(m_rosterModel);
47
Zhenkai Zhu86df7412012-09-27 16:30:20 -070048 createActions();
49 createTrayIcon();
50 m_timer = new QTimer(this);
51 connect(lineEdit, SIGNAL(returnPressed()), this, SLOT(returnPressed()));
52 connect(setButton, SIGNAL(pressed()), this, SLOT(buttonPressed()));
Zhenkai Zhub60b7e12012-09-28 11:34:21 -070053 connect(treeButton, SIGNAL(pressed()), this, SLOT(treeButtonPressed()));
Zhenkai Zhu86df7412012-09-27 16:30:20 -070054 connect(this, SIGNAL(dataReceived(QString, const char *, size_t, bool)), this, SLOT(processData(QString, const char *, size_t, bool)));
55 connect(this, SIGNAL(treeUpdated(const std::vector<Sync::MissingDataInfo>)), this, SLOT(processTreeUpdate(const std::vector<Sync::MissingDataInfo>)));
Zhenkai Zhu86df7412012-09-27 16:30:20 -070056 connect(m_timer, SIGNAL(timeout()), this, SLOT(replot()));
57 connect(m_scene, SIGNAL(replot()), this, SLOT(replot()));
58 connect(trayIcon, SIGNAL(messageClicked()), this, SLOT(showNormal()));
59 connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
Zhenkai Zhu25e33e52012-09-28 13:00:07 -070060 connect(m_scene, SIGNAL(rosterChanged(QStringList)), this, SLOT(updateRosterList(QStringList)));
Zhenkai Zhu86df7412012-09-27 16:30:20 -070061
Zhenkai Zhu82a62752012-06-04 17:11:04 -070062 // create sync socket
63 if(!m_user.getChatroom().isEmpty()) {
64 std::string syncPrefix = BROADCAST_PREFIX_FOR_SYNC_DEMO;
65 syncPrefix += "/";
66 syncPrefix += m_user.getChatroom().toStdString();
Zhenkai Zhua4fb1242012-06-05 20:26:05 -070067 try
68 {
Alexander Afanasyev288edd82012-10-04 17:07:56 -070069 m_sock = new Sync::SyncAppSocket(syncPrefix,
70 bind(&ChatDialog::processTreeUpdateWrapper, this, _1, _2),
71 bind(&ChatDialog::processRemoveWrapper, this, _1));
72 QTimer::singleShot(1000, this, SLOT(sendJoin()));
Zhenkai Zhu86df7412012-09-27 16:30:20 -070073 m_timer->start(FRESHNESS * 2000);
Zhenkai Zhua4fb1242012-06-05 20:26:05 -070074 }
75 catch (Sync::CcnxOperationException ex)
76 {
Zhenkai Zhu0b3fa332012-09-27 21:58:43 -070077 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 -070078 std::exit(1);
79 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -070080 }
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -070081
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -070082}
83
Zhenkai Zhu82a62752012-06-04 17:11:04 -070084ChatDialog::~ChatDialog()
85{
86 if (m_sock != NULL)
87 {
Zhenkai Zhu25e33e52012-09-28 13:00:07 -070088 SyncDemo::ChatMessage msg;
Zhenkai Zhub5b78462012-09-28 14:10:37 -070089 formControlMessage(msg, SyncDemo::ChatMessage::LEAVE);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -070090 sendMsg(msg);
Zhenkai Zhu3974a492012-09-28 14:39:45 -070091 usleep(500000);
Zhenkai Zhu591e8c32012-09-26 11:57:50 -070092 m_sock->remove(m_user.getPrefix().toStdString());
Zhenkai Zhu3974a492012-09-28 14:39:45 -070093 usleep(5000);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -070094#ifdef __DEBUG
95 std::cout << "Sync REMOVE signal sent" << std::endl;
96#endif
Zhenkai Zhu82a62752012-06-04 17:11:04 -070097 delete m_sock;
98 m_sock = NULL;
99 }
100}
101
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700102void
103ChatDialog::replot()
104{
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700105 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700106 m_scene->plot(m_sock->getRootDigest().c_str());
Zhenkai Zhuc9e4e3c2012-10-02 11:47:31 -0700107 fitView();
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700108}
109
Zhenkai Zhu6082ede2012-09-27 17:28:46 -0700110void
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700111ChatDialog::updateRosterList(QStringList staleUserList)
Zhenkai Zhu6082ede2012-09-27 17:28:46 -0700112{
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700113 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu6082ede2012-09-27 17:28:46 -0700114 QStringList rosterList = m_scene->getRosterList();
115 m_rosterModel->setStringList(rosterList);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700116 QString user;
117 QStringListIterator it(staleUserList);
118 while(it.hasNext())
119 {
Zhenkai Zhu32cbdce2012-10-02 11:09:38 -0700120 std::string nick = it.next().toStdString();
121 if (nick.empty())
122 continue;
123
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700124 SyncDemo::ChatMessage msg;
Zhenkai Zhub5b78462012-09-28 14:10:37 -0700125 formControlMessage(msg, SyncDemo::ChatMessage::LEAVE);
Zhenkai Zhu32cbdce2012-10-02 11:09:38 -0700126 msg.set_from(nick);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700127 appendMessage(msg);
128 }
Zhenkai Zhu6082ede2012-09-27 17:28:46 -0700129}
130
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700131void
132ChatDialog::setVisible(bool visible)
133{
134 minimizeAction->setEnabled(visible);
135 maximizeAction->setEnabled(!isMaximized());
136 restoreAction->setEnabled(isMaximized() || !visible);
137 QDialog::setVisible(visible);
138}
139
140void
141ChatDialog::closeEvent(QCloseEvent *e)
142{
Zhenkai Zhu3974a492012-09-28 14:39:45 -0700143 if (trayIcon->isVisible() && !m_minimaniho)
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700144 {
Zhenkai Zhu0b3fa332012-09-27 21:58:43 -0700145 QMessageBox::information(this, tr("Chronos"),
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700146 tr("The program will keep running in the "
147 "system tray. To terminate the program"
148 "choose <b>Quit</b> in the context memu"
149 "of the system tray entry."));
150 hide();
151 e->ignore();
Zhenkai Zhu3974a492012-09-28 14:39:45 -0700152 m_minimaniho = true;
153 writeSettings();
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700154 }
155}
156
157void
158ChatDialog::changeEvent(QEvent *e)
159{
160 switch(e->type())
161 {
162 case QEvent::ActivationChange:
163 if (isActiveWindow())
164 {
165 trayIcon->setIcon(QIcon(":/images/icon_small.png"));
166 }
167 break;
168 default:
169 break;
170 }
171}
172
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700173void
Zhenkai Zhu10ccb5a2012-06-04 21:55:14 -0700174ChatDialog::appendMessage(const SyncDemo::ChatMessage msg)
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700175{
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700176 boost::recursive_mutex::scoped_lock lock(m_msgMutex);
Zhenkai Zhub6338822012-05-31 13:27:24 -0700177
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700178 if (msg.type() == SyncDemo::ChatMessage::CHAT)
Zhenkai Zhub98e6022012-09-27 13:48:23 -0700179 {
Zhenkai Zhub98e6022012-09-27 13:48:23 -0700180
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700181 if (!msg.has_data())
Zhenkai Zhub98e6022012-09-27 13:48:23 -0700182 {
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700183 return;
Zhenkai Zhub98e6022012-09-27 13:48:23 -0700184 }
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700185
186 if (msg.from().empty() || msg.data().empty())
187 {
188 return;
189 }
190
191 if (!msg.has_timestamp())
192 {
193 return;
194 }
195
196 QTextCharFormat nickFormat;
197 nickFormat.setForeground(Qt::darkGreen);
198 nickFormat.setFontWeight(QFont::Bold);
199 nickFormat.setFontUnderline(true);
200 nickFormat.setUnderlineColor(Qt::gray);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700201
202 QTextCursor cursor(textEdit->textCursor());
203 cursor.movePosition(QTextCursor::End);
204 QTextTableFormat tableFormat;
205 tableFormat.setBorder(0);
206 QTextTable *table = cursor.insertTable(1, 2, tableFormat);
207 QString from = QString("%1 ").arg(msg.from().c_str());
208 QTextTableCell fromCell = table->cellAt(0, 0);
209 fromCell.setFormat(nickFormat);
210 fromCell.firstCursorPosition().insertText(from);
Zhenkai Zhu560ef1b2012-09-28 14:23:33 -0700211
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700212 time_t timestamp = msg.timestamp();
Zhenkai Zhu560ef1b2012-09-28 14:23:33 -0700213 printTimeInCell(table, timestamp);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700214
215 QTextCursor nextCursor(textEdit->textCursor());
216 nextCursor.movePosition(QTextCursor::End);
217 table = nextCursor.insertTable(1, 1, tableFormat);
218 table->cellAt(0, 0).firstCursorPosition().insertText(msg.data().c_str());
219 showMessage(from, msg.data().c_str());
Zhenkai Zhub98e6022012-09-27 13:48:23 -0700220 }
221
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700222 if (msg.type() == SyncDemo::ChatMessage::JOIN || msg.type() == SyncDemo::ChatMessage::LEAVE)
223 {
224 QTextCharFormat nickFormat;
225 nickFormat.setForeground(Qt::gray);
226 nickFormat.setFontWeight(QFont::Bold);
227 nickFormat.setFontUnderline(true);
228 nickFormat.setUnderlineColor(Qt::gray);
Zhenkai Zhub98e6022012-09-27 13:48:23 -0700229
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700230 QTextCursor cursor(textEdit->textCursor());
231 cursor.movePosition(QTextCursor::End);
232 QTextTableFormat tableFormat;
233 tableFormat.setBorder(0);
234 QTextTable *table = cursor.insertTable(1, 2, tableFormat);
235 QString action;
236 if (msg.type() == SyncDemo::ChatMessage::JOIN)
237 {
238 action = "enters room";
239 }
240 else
241 {
242 action = "leaves room";
243 }
244
245 QString from = QString("%1 %2 ").arg(msg.from().c_str()).arg(action);
246 QTextTableCell fromCell = table->cellAt(0, 0);
247 fromCell.setFormat(nickFormat);
248 fromCell.firstCursorPosition().insertText(from);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700249
Zhenkai Zhu560ef1b2012-09-28 14:23:33 -0700250 time_t timestamp = msg.timestamp();
251 printTimeInCell(table, timestamp);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700252 }
253
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700254 QScrollBar *bar = textEdit->verticalScrollBar();
255 bar->setValue(bar->maximum());
256}
257
Zhenkai Zhu560ef1b2012-09-28 14:23:33 -0700258void
259ChatDialog::printTimeInCell(QTextTable *table, time_t timestamp)
260{
261 QTextCharFormat timeFormat;
262 timeFormat.setForeground(Qt::gray);
263 timeFormat.setFontUnderline(true);
264 timeFormat.setUnderlineColor(Qt::gray);
265 QTextTableCell timeCell = table->cellAt(0, 1);
266 timeCell.setFormat(timeFormat);
267 timeCell.firstCursorPosition().insertText(formatTime(timestamp));
268}
269
270QString
271ChatDialog::formatTime(time_t timestamp)
272{
273 struct tm *tm_time = localtime(&timestamp);
274 int hour = tm_time->tm_hour;
275 QString amOrPM;
276 if (hour > 12)
277 {
278 hour -= 12;
279 amOrPM = "PM";
280 }
281 else
282 {
283 amOrPM = "AM";
284 if (hour == 0)
285 {
286 hour = 12;
287 }
288 }
289
290 char textTime[12];
291 sprintf(textTime, "%d:%02d:%02d %s", hour, tm_time->tm_min, tm_time->tm_sec, amOrPM.toStdString().c_str());
292 return QString(textTime);
293}
294
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700295void
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700296ChatDialog::processTreeUpdateWrapper(const std::vector<Sync::MissingDataInfo> v, Sync::SyncAppSocket *sock)
297{
298 emit treeUpdated(v);
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700299#ifdef __DEBUG
300 std::cout << "<<< Tree update signal emitted" << std::endl;
301#endif
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700302}
303
304void
305ChatDialog::processTreeUpdate(const std::vector<Sync::MissingDataInfo> v)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700306{
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700307#ifdef __DEBUG
308 std::cout << "<<< processing Tree Update" << std::endl;
309#endif
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700310 if (v.empty())
311 {
312 return;
313 }
314
315 // reflect the changes on digest tree
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700316 {
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700317 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700318 m_scene->processUpdate(v, m_sock->getRootDigest().c_str());
319 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700320
321 int n = v.size();
322 int totalMissingPackets = 0;
323 for (int i = 0; i < n; i++)
324 {
325 totalMissingPackets += v[i].high.getSeq() - v[i].low.getSeq() + 1;
326 }
327
Zhenkai Zhubb198112012-09-27 11:31:42 -0700328 for (int i = 0; i < n; i++)
329 {
330 if (totalMissingPackets < 4)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700331 {
332 for (Sync::SeqNo seq = v[i].low; seq <= v[i].high; ++seq)
333 {
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700334 m_sock->fetchRaw(v[i].prefix, seq, bind(&ChatDialog::processDataWrapper, this, _1, _2, _3), 2);
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700335#ifdef __DEBUG
336 std::cout << "<<< Fetching " << v[i].prefix << "/" <<seq.getSession() <<"/" << seq.getSeq() << std::endl;
337#endif
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700338 }
339 }
Zhenkai Zhubb198112012-09-27 11:31:42 -0700340 else
341 {
342 m_sock->fetchRaw(v[i].prefix, v[i].high, bind(&ChatDialog::processDataNoShowWrapper, this, _1, _2, _3), 2);
343 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700344 }
345
346 // adjust the view
347 fitView();
348
349}
350
351void
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700352ChatDialog::processDataWrapper(std::string name, const char *buf, size_t len)
353{
Zhenkai Zhubb198112012-09-27 11:31:42 -0700354 emit dataReceived(name.c_str(), buf, len, true);
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700355#ifdef __DEBUG
356 std::cout <<"<<< " << name << " fetched" << std::endl;
357#endif
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700358}
359
360void
Zhenkai Zhubb198112012-09-27 11:31:42 -0700361ChatDialog::processDataNoShowWrapper(std::string name, const char *buf, size_t len)
362{
363 emit dataReceived(name.c_str(), buf, len, false);
364}
365
366void
367ChatDialog::processData(QString name, const char *buf, size_t len, bool show)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700368{
369 SyncDemo::ChatMessage msg;
Zhenkai Zhuef8d0632012-10-05 10:24:55 -0700370 bool corrupted = false;
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700371 if (!msg.ParseFromArray(buf, len))
372 {
Zhenkai Zhubb198112012-09-27 11:31:42 -0700373 std::cerr << "Errrrr.. Can not parse msg with name: " << name.toStdString() << ". what is happening?" << std::endl;
Zhenkai Zhuef8d0632012-10-05 10:24:55 -0700374 // nasty stuff: as a remedy, we'll form some standard msg for inparsable msgs
375 msg.set_from("inconnu");
376 msg.set_type(SyncDemo::ChatMessage::OTHER);
377 corrupted = true;
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700378 }
379
Zhenkai Zhu10ccb5a2012-06-04 21:55:14 -0700380 // display msg received from network
381 // we have to do so; this function is called by ccnd thread
382 // so if we call appendMsg directly
383 // Qt crash as "QObject: Cannot create children for a parent that is in a different thread"
384 // the "cannonical" way to is use signal-slot
Zhenkai Zhuef8d0632012-10-05 10:24:55 -0700385 if (show && !corrupted)
Zhenkai Zhubb198112012-09-27 11:31:42 -0700386 {
387 appendMessage(msg);
388 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700389
390 // update the tree view
Zhenkai Zhu097bfe72012-06-05 14:30:17 -0700391 std::string stdStrName = name.toStdString();
392 std::string stdStrNameWithoutSeq = stdStrName.substr(0, stdStrName.find_last_of('/'));
393 std::string prefix = stdStrNameWithoutSeq.substr(0, stdStrNameWithoutSeq.find_last_of('/'));
394#ifdef __DEBUG
395 std::cout <<"<<< updating scene for" << prefix << ": " << msg.from() << std::endl;
396#endif
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700397 if (msg.type() == SyncDemo::ChatMessage::LEAVE)
398 {
399 processRemove(prefix.c_str());
400 }
401 else
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700402 {
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700403 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700404 m_scene->msgReceived(prefix.c_str(), msg.from().c_str());
405 }
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700406 fitView();
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700407}
408
409void
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700410ChatDialog::processRemoveWrapper(std::string prefix)
411{
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700412#ifdef __DEBUG
413 std::cout << "Sync REMOVE signal received for prefix: " << prefix << std::endl;
414#endif
415 //emit removeReceived(prefix.c_str());
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700416}
417
418void
419ChatDialog::processRemove(QString prefix)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700420{
Zhenkai Zhu591e8c32012-09-26 11:57:50 -0700421#ifdef __DEBUG
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700422 std::cout << "<<< remove node for prefix" << prefix.toStdString() << std::endl;
Zhenkai Zhu591e8c32012-09-26 11:57:50 -0700423#endif
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700424 bool removed = m_scene->removeNode(prefix);
Zhenkai Zhu591e8c32012-09-26 11:57:50 -0700425 if (removed)
426 {
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700427 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu591e8c32012-09-26 11:57:50 -0700428 m_scene->plot(m_sock->getRootDigest().c_str());
429 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700430}
431
432void
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700433ChatDialog::formChatMessage(const QString &text, SyncDemo::ChatMessage &msg) {
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700434 msg.set_from(m_user.getNick().toStdString());
435 msg.set_to(m_user.getChatroom().toStdString());
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700436 msg.set_data(text.toStdString());
437 time_t seconds = time(NULL);
438 msg.set_timestamp(seconds);
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700439 msg.set_type(SyncDemo::ChatMessage::CHAT);
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700440}
441
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700442void
Zhenkai Zhub5b78462012-09-28 14:10:37 -0700443ChatDialog::formControlMessage(SyncDemo::ChatMessage &msg, SyncDemo::ChatMessage::ChatMessageType type)
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700444{
445 msg.set_from(m_user.getNick().toStdString());
446 msg.set_to(m_user.getChatroom().toStdString());
447 time_t seconds = time(NULL);
448 msg.set_timestamp(seconds);
Zhenkai Zhub5b78462012-09-28 14:10:37 -0700449 msg.set_type(type);
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700450}
451
Zhenkai Zhu59245aa2012-09-26 16:07:04 -0700452static std::string chars("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM0123456789");
453
454QString
455ChatDialog::getRandomString()
456{
457 std::string randStr;
458 boost::random::random_device rng;
459 boost::random::uniform_int_distribution<> index_dist(0, chars.size() - 1);
460 for (int i = 0; i < 10; i ++)
461 {
462 randStr += chars[index_dist(rng)];
463 }
464 return randStr.c_str();
465}
466
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700467bool
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700468ChatDialog::readSettings()
469{
470 QSettings s(ORGANIZATION, APPLICATION);
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700471 QString nick = s.value("nick", "").toString();
472 QString chatroom = s.value("chatroom", "").toString();
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700473 QString originPrefix = s.value("originPrefix", "").toString();
Zhenkai Zhu3974a492012-09-28 14:39:45 -0700474 m_minimaniho = s.value("minimaniho", false).toBool();
475 if (nick == "" || chatroom == "" || originPrefix == "") {
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700476 QTimer::singleShot(500, this, SLOT(buttonPressed()));
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700477 return false;
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700478 }
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700479 else {
480 m_user.setNick(nick);
481 m_user.setChatroom(chatroom);
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700482 m_user.setOriginPrefix(originPrefix);
Zhenkai Zhu3974a492012-09-28 14:39:45 -0700483 m_user.setPrefix(originPrefix + "/" + chatroom + "/" + getRandomString());
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700484 return true;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700485 }
Zhenkai Zhu3974a492012-09-28 14:39:45 -0700486
487// QTimer::singleShot(500, this, SLOT(buttonPressed()));
488 // return false;
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700489}
490
491void
492ChatDialog::writeSettings()
493{
494 QSettings s(ORGANIZATION, APPLICATION);
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700495 s.setValue("nick", m_user.getNick());
496 s.setValue("chatroom", m_user.getChatroom());
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700497 s.setValue("originPrefix", m_user.getOriginPrefix());
Zhenkai Zhu3974a492012-09-28 14:39:45 -0700498 s.setValue("minimaniho", m_minimaniho);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700499}
500
501void
502ChatDialog::updateLabels()
503{
Zhenkai Zhu76ff02b2012-09-27 21:11:03 -0700504 QString settingDisp = QString("Chatroom: %1").arg(m_user.getChatroom());
505 infoLabel->setStyleSheet("QLabel {color: #630; font-size: 16px; font: bold \"Verdana\";}");
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700506 infoLabel->setText(settingDisp);
Zhenkai Zhub60b7e12012-09-28 11:34:21 -0700507 //QString prefixDisp = QString("<Prefix: %1>").arg(m_user.getPrefix());
508 //prefixLabel->setText(prefixDisp);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700509}
510
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700511void
512ChatDialog::returnPressed()
513{
514 QString text = lineEdit->text();
515 if (text.isEmpty())
516 return;
517
Zhenkai Zhub6338822012-05-31 13:27:24 -0700518 lineEdit->clear();
519
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700520 SyncDemo::ChatMessage msg;
521 formChatMessage(text, msg);
522
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700523 appendMessage(msg);
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700524
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700525 sendMsg(msg);
526
527 fitView();
528}
529
530void
531ChatDialog::sendMsg(SyncDemo::ChatMessage &msg)
532{
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700533 // send msg
534 size_t size = msg.ByteSize();
535 char *buf = new char[size];
536 msg.SerializeToArray(buf, size);
537 if (!msg.IsInitialized())
538 {
539 std::cerr << "Errrrr.. msg was not probally initialized "<<__FILE__ <<":"<<__LINE__<<". what is happening?" << std::endl;
540 abort();
541 }
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700542 m_sock->publishRaw(m_user.getPrefix().toStdString(), m_session, buf, size, FRESHNESS);
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700543
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700544 delete buf;
545
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700546 m_lastMsgTime = time(NULL);
547
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700548 int nextSequence = m_sock->getNextSeq(m_user.getPrefix().toStdString(), m_session);
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700549 Sync::MissingDataInfo mdi = {m_user.getPrefix().toStdString(), Sync::SeqNo(0), Sync::SeqNo(nextSequence - 1)};
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700550 std::vector<Sync::MissingDataInfo> v;
551 v.push_back(mdi);
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700552 {
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700553 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700554 m_scene->processUpdate(v, m_sock->getRootDigest().c_str());
555 m_scene->msgReceived(m_user.getPrefix(), m_user.getNick());
556 }
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700557}
558
559void
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700560ChatDialog::sendJoin()
561{
562 SyncDemo::ChatMessage msg;
Zhenkai Zhub5b78462012-09-28 14:10:37 -0700563 formControlMessage(msg, SyncDemo::ChatMessage::JOIN);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700564 sendMsg(msg);
565 QTimer::singleShot(m_randomizedInterval, this, SLOT(sendHello()));
566}
567
568void
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700569ChatDialog::sendHello()
570{
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700571 time_t now = time(NULL);
572 int elapsed = now - m_lastMsgTime;
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700573 if (elapsed >= m_randomizedInterval / 1000)
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700574 {
575 SyncDemo::ChatMessage msg;
Zhenkai Zhub5b78462012-09-28 14:10:37 -0700576 formControlMessage(msg, SyncDemo::ChatMessage::HELLO);
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700577 sendMsg(msg);
Zhenkai Zhuee5c90f2012-09-27 14:05:41 -0700578 QTimer::singleShot(m_randomizedInterval, this, SLOT(sendHello()));
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700579 }
580 else
581 {
Zhenkai Zhuee5c90f2012-09-27 14:05:41 -0700582 QTimer::singleShot((m_randomizedInterval - elapsed * 1000), this, SLOT(sendHello()));
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700583 }
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700584}
585
586void
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700587ChatDialog::buttonPressed()
588{
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700589 SettingDialog dialog(this, m_user.getNick(), m_user.getChatroom(), m_user.getOriginPrefix());
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700590 connect(&dialog, SIGNAL(updated(QString, QString, QString)), this, SLOT(settingUpdated(QString, QString, QString)));
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700591 dialog.exec();
Zhenkai Zhue837f792012-06-05 20:47:54 -0700592 QTimer::singleShot(100, this, SLOT(checkSetting()));
593}
594
Zhenkai Zhub60b7e12012-09-28 11:34:21 -0700595void ChatDialog::treeButtonPressed()
596{
597 if (treeViewer->isVisible())
598 {
599 treeViewer->hide();
600 treeButton->setText("Show Sync Tree");
601 }
602 else
603 {
604 treeViewer->show();
605 treeButton->setText("Hide Sync Tree");
606 }
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700607
608 fitView();
Zhenkai Zhub60b7e12012-09-28 11:34:21 -0700609}
610
Zhenkai Zhue837f792012-06-05 20:47:54 -0700611void
612ChatDialog::checkSetting()
613{
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700614 if (m_user.getOriginPrefix().isEmpty() || m_user.getNick().isEmpty() || m_user.getChatroom().isEmpty())
Zhenkai Zhue837f792012-06-05 20:47:54 -0700615 {
616 buttonPressed();
617 }
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -0700618}
Zhenkai Zhue08afe02012-05-31 15:49:07 -0700619
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700620void
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700621ChatDialog::settingUpdated(QString nick, QString chatroom, QString originPrefix)
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700622{
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700623 QString randString = getRandomString();
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700624 bool needWrite = false;
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700625 bool needFresh = false;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700626 if (!nick.isEmpty() && nick != m_user.getNick()) {
627 m_user.setNick(nick);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700628 needWrite = true;
629 }
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700630 if (!originPrefix.isEmpty() && originPrefix != m_user.getOriginPrefix()) {
631 m_user.setOriginPrefix(originPrefix);
632 m_user.setPrefix(originPrefix + "/" + m_user.getChatroom() + "/" + randString);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700633 needWrite = true;
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700634 needFresh = true;
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700635 }
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700636 if (!chatroom.isEmpty() && chatroom != m_user.getChatroom()) {
637 m_user.setChatroom(chatroom);
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700638 m_user.setPrefix(m_user.getOriginPrefix() + "/" + chatroom + "/" + randString);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700639 needWrite = true;
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700640 needFresh = true;
641 }
642
643 if (needFresh)
644 {
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700645
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700646 {
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700647 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700648 m_scene->clearAll();
649 m_scene->plot("Empty");
650 }
Zhenkai Zhucc4c2c02012-09-27 21:24:37 -0700651
652 textEdit->clear();
653
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700654 // TODO: perhaps need to do a lot. e.g. use a new SyncAppSokcet
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700655 if (m_sock != NULL)
656 {
657 delete m_sock;
658 m_sock = NULL;
659 }
660 std::string syncPrefix = BROADCAST_PREFIX_FOR_SYNC_DEMO;
661 syncPrefix += "/";
662 syncPrefix += m_user.getChatroom().toStdString();
Zhenkai Zhua4fb1242012-06-05 20:26:05 -0700663 try
664 {
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700665 m_sock = new Sync::SyncAppSocket(syncPrefix, bind(&ChatDialog::processTreeUpdateWrapper, this, _1, _2), bind(&ChatDialog::processRemoveWrapper, this, _1));
Alexander Afanasyev288edd82012-10-04 17:07:56 -0700666 QTimer::singleShot(1000, this, SLOT(sendJoin()));
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700667 m_timer->start(FRESHNESS * 2000);
Zhenkai Zhua4fb1242012-06-05 20:26:05 -0700668 }
669 catch (Sync::CcnxOperationException ex)
670 {
Zhenkai Zhu0b3fa332012-09-27 21:58:43 -0700671 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 -0700672 std::exit(1);
673 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700674
675 fitView();
676
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700677 }
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700678
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700679 if (needWrite) {
680 writeSettings();
681 updateLabels();
682 }
683}
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700684
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700685void
686ChatDialog::iconActivated(QSystemTrayIcon::ActivationReason reason)
687{
688 switch (reason)
689 {
690 case QSystemTrayIcon::Trigger:
691 case QSystemTrayIcon::DoubleClick:
692 break;
693 case QSystemTrayIcon::MiddleClick:
694 // showMessage();
695 break;
696 default:;
697 }
698}
699
700void
701ChatDialog::showMessage(QString from, QString data)
702{
703 // std::cout <<"Showing Message: " << from.toStdString() << ": " << data.toStdString() << std::endl;
704 if (!isActiveWindow())
705 {
706 trayIcon->showMessage(QString("Chatroom %1 has a new message").arg(m_user.getChatroom()), QString("<%1>: %2").arg(from).arg(data), QSystemTrayIcon::Information, 20000);
707 trayIcon->setIcon(QIcon(":/images/note.png"));
708 }
709}
710
711void
712ChatDialog::messageClicked()
713{
714 this->showMaximized();
715}
716
717void
718ChatDialog::createActions()
719{
720 minimizeAction = new QAction(tr("Mi&nimize"), this);
721 connect(minimizeAction, SIGNAL(triggered()), this, SLOT(hide()));
722
723 maximizeAction = new QAction(tr("Ma&ximize"), this);
724 connect(maximizeAction, SIGNAL(triggered()), this, SLOT(showMaximized()));
725
726 restoreAction = new QAction(tr("&Restore"), this);
727 connect(restoreAction, SIGNAL(triggered()), this, SLOT(showNormal()));
728
729 quitAction = new QAction(tr("Quit"), this);
730 connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
731}
732
733void
734ChatDialog::createTrayIcon()
735{
736 trayIconMenu = new QMenu(this);
737 trayIconMenu->addAction(minimizeAction);
738 trayIconMenu->addAction(maximizeAction);
739 trayIconMenu->addAction(restoreAction);
740 trayIconMenu->addSeparator();
741 trayIconMenu->addAction(quitAction);
742
743 trayIcon = new QSystemTrayIcon(this);
744 trayIcon->setContextMenu(trayIconMenu);
745
746 QIcon icon(":/images/icon_small.png");
747 trayIcon->setIcon(icon);
748 setWindowIcon(icon);
Zhenkai Zhu0b3fa332012-09-27 21:58:43 -0700749 trayIcon->setToolTip("Chronos System Tray Icon");
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700750 trayIcon->setVisible(true);
751}
752
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700753void
754ChatDialog::resizeEvent(QResizeEvent *e)
755{
756 fitView();
757}
758
759void
760ChatDialog::showEvent(QShowEvent *e)
761{
762 fitView();
763}
764
765void
766ChatDialog::fitView()
767{
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700768 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700769 QRectF rect = m_scene->itemsBoundingRect();
770 m_scene->setSceneRect(rect);
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700771 treeViewer->fitInView(m_scene->itemsBoundingRect(), Qt::KeepAspectRatio);
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700772}