blob: 72e960067c9742ac432969dbc7f0ff8d6e9e8653 [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 Zhucc4c2c02012-09-27 21:24:37 -070017 : QDialog(parent), m_sock(NULL), m_lastMsgTime(0), m_sendJoin(true)
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 Zhu6082ede2012-09-27 17:28:46 -070042 m_rosterModel = new QStringListModel(this);
43 listView->setModel(m_rosterModel);
44
Zhenkai Zhu86df7412012-09-27 16:30:20 -070045 createActions();
46 createTrayIcon();
47 m_timer = new QTimer(this);
48 connect(lineEdit, SIGNAL(returnPressed()), this, SLOT(returnPressed()));
49 connect(setButton, SIGNAL(pressed()), this, SLOT(buttonPressed()));
50 connect(this, SIGNAL(dataReceived(QString, const char *, size_t, bool)), this, SLOT(processData(QString, const char *, size_t, bool)));
51 connect(this, SIGNAL(treeUpdated(const std::vector<Sync::MissingDataInfo>)), this, SLOT(processTreeUpdate(const std::vector<Sync::MissingDataInfo>)));
52 connect(this, SIGNAL(removeReceived(QString)), this, SLOT(processRemove(QString)));
53 connect(m_timer, SIGNAL(timeout()), this, SLOT(replot()));
54 connect(m_scene, SIGNAL(replot()), this, SLOT(replot()));
55 connect(trayIcon, SIGNAL(messageClicked()), this, SLOT(showNormal()));
56 connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
Zhenkai Zhu6082ede2012-09-27 17:28:46 -070057 connect(m_scene, SIGNAL(rosterChanged()), this, SLOT(updateRosterList()));
Zhenkai Zhu86df7412012-09-27 16:30:20 -070058
Zhenkai Zhu82a62752012-06-04 17:11:04 -070059 // create sync socket
60 if(!m_user.getChatroom().isEmpty()) {
61 std::string syncPrefix = BROADCAST_PREFIX_FOR_SYNC_DEMO;
62 syncPrefix += "/";
63 syncPrefix += m_user.getChatroom().toStdString();
Zhenkai Zhua4fb1242012-06-05 20:26:05 -070064 try
65 {
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -070066 m_sock = new Sync::SyncAppSocket(syncPrefix, bind(&ChatDialog::processTreeUpdateWrapper, this, _1, _2), bind(&ChatDialog::processRemoveWrapper, this, _1));
67 sendHello();
Zhenkai Zhu86df7412012-09-27 16:30:20 -070068 m_timer->start(FRESHNESS * 2000);
Zhenkai Zhua4fb1242012-06-05 20:26:05 -070069 }
70 catch (Sync::CcnxOperationException ex)
71 {
Zhenkai Zhu0b3fa332012-09-27 21:58:43 -070072 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 -070073 std::exit(1);
74 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -070075 }
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -070076
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -070077//testDraw();
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -070078}
79
Zhenkai Zhu82a62752012-06-04 17:11:04 -070080ChatDialog::~ChatDialog()
81{
82 if (m_sock != NULL)
83 {
Zhenkai Zhu591e8c32012-09-26 11:57:50 -070084 m_sock->remove(m_user.getPrefix().toStdString());
Zhenkai Zhu82a62752012-06-04 17:11:04 -070085 delete m_sock;
86 m_sock = NULL;
87 }
88}
89
Zhenkai Zhu86df7412012-09-27 16:30:20 -070090void
91ChatDialog::replot()
92{
Zhenkai Zhu9036e032012-09-27 20:59:33 -070093 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu86df7412012-09-27 16:30:20 -070094 m_scene->plot(m_sock->getRootDigest().c_str());
95}
96
Zhenkai Zhu6082ede2012-09-27 17:28:46 -070097void
98ChatDialog::updateRosterList()
99{
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700100 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu6082ede2012-09-27 17:28:46 -0700101 QStringList rosterList = m_scene->getRosterList();
102 m_rosterModel->setStringList(rosterList);
103}
104
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700105void
106ChatDialog::setVisible(bool visible)
107{
108 minimizeAction->setEnabled(visible);
109 maximizeAction->setEnabled(!isMaximized());
110 restoreAction->setEnabled(isMaximized() || !visible);
111 QDialog::setVisible(visible);
112}
113
114void
115ChatDialog::closeEvent(QCloseEvent *e)
116{
117 if (trayIcon->isVisible())
118 {
Zhenkai Zhu0b3fa332012-09-27 21:58:43 -0700119 QMessageBox::information(this, tr("Chronos"),
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700120 tr("The program will keep running in the "
121 "system tray. To terminate the program"
122 "choose <b>Quit</b> in the context memu"
123 "of the system tray entry."));
124 hide();
125 e->ignore();
126 }
127}
128
129void
130ChatDialog::changeEvent(QEvent *e)
131{
132 switch(e->type())
133 {
134 case QEvent::ActivationChange:
135 if (isActiveWindow())
136 {
137 trayIcon->setIcon(QIcon(":/images/icon_small.png"));
138 }
139 break;
140 default:
141 break;
142 }
143}
144
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700145void
Zhenkai Zhu10ccb5a2012-06-04 21:55:14 -0700146ChatDialog::appendMessage(const SyncDemo::ChatMessage msg)
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700147{
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700148 boost::recursive_mutex::scoped_lock lock(m_msgMutex);
Zhenkai Zhub6338822012-05-31 13:27:24 -0700149
150 if (msg.type() != SyncDemo::ChatMessage::CHAT) {
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700151 return;
Zhenkai Zhub6338822012-05-31 13:27:24 -0700152 }
153
154 if (!msg.has_data()) {
155 return;
156 }
157
158 if (msg.from().empty() || msg.data().empty()) {
159 return;
160 }
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700161
Zhenkai Zhub98e6022012-09-27 13:48:23 -0700162 if (!msg.has_timestamp())
163 {
164 return;
165 }
166
167 QTextCharFormat nickFormat;
168 nickFormat.setForeground(Qt::darkGreen);
169 nickFormat.setFontWeight(QFont::Bold);
170 nickFormat.setFontUnderline(true);
171 nickFormat.setUnderlineColor(Qt::gray);
172 QTextCharFormat timeFormat;
173 timeFormat.setForeground(Qt::gray);
174 timeFormat.setFontUnderline(true);
175 timeFormat.setUnderlineColor(Qt::gray);
176
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700177 QTextCursor cursor(textEdit->textCursor());
178 cursor.movePosition(QTextCursor::End);
179 QTextTableFormat tableFormat;
180 tableFormat.setBorder(0);
181 QTextTable *table = cursor.insertTable(1, 2, tableFormat);
Zhenkai Zhub98e6022012-09-27 13:48:23 -0700182 QString from = QString("%1 ").arg(msg.from().c_str());
183 QTextTableCell fromCell = table->cellAt(0, 0);
184 fromCell.setFormat(nickFormat);
185 fromCell.firstCursorPosition().insertText(from);
186 QTextTableCell timeCell = table->cellAt(0, 1);
187 timeCell.setFormat(timeFormat);
188 time_t timestamp = msg.timestamp();
189 struct tm *tm_time = localtime(&timestamp);
190 int hour = tm_time->tm_hour;
191 QString amOrPM;
192 if (hour > 12)
193 {
194 hour -= 12;
195 amOrPM = "PM";
196 }
197 else
198 {
199 amOrPM = "AM";
200 if (hour == 0)
201 {
202 hour = 12;
203 }
204 }
205
206 char textTime[12];
207 sprintf(textTime, "%d:%02d:%02d %s", hour, tm_time->tm_min, tm_time->tm_sec, amOrPM.toStdString().c_str());
208 timeCell.firstCursorPosition().insertText(textTime);
209
210
211 QTextCursor nextCursor(textEdit->textCursor());
212 table = nextCursor.insertTable(1, 1, tableFormat);
213 table->cellAt(0, 0).firstCursorPosition().insertText(msg.data().c_str());
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700214 QScrollBar *bar = textEdit->verticalScrollBar();
215 bar->setValue(bar->maximum());
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700216 showMessage(from, msg.data().c_str());
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700217}
218
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700219void
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700220ChatDialog::processTreeUpdateWrapper(const std::vector<Sync::MissingDataInfo> v, Sync::SyncAppSocket *sock)
221{
222 emit treeUpdated(v);
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700223#ifdef __DEBUG
224 std::cout << "<<< Tree update signal emitted" << std::endl;
225#endif
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700226}
227
228void
229ChatDialog::processTreeUpdate(const std::vector<Sync::MissingDataInfo> v)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700230{
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700231#ifdef __DEBUG
232 std::cout << "<<< processing Tree Update" << std::endl;
233#endif
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700234 if (v.empty())
235 {
236 return;
237 }
238
239 // reflect the changes on digest tree
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700240 {
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700241 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700242 m_scene->processUpdate(v, m_sock->getRootDigest().c_str());
243 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700244
245 int n = v.size();
246 int totalMissingPackets = 0;
247 for (int i = 0; i < n; i++)
248 {
249 totalMissingPackets += v[i].high.getSeq() - v[i].low.getSeq() + 1;
250 }
251
Zhenkai Zhubb198112012-09-27 11:31:42 -0700252 for (int i = 0; i < n; i++)
253 {
254 if (totalMissingPackets < 4)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700255 {
256 for (Sync::SeqNo seq = v[i].low; seq <= v[i].high; ++seq)
257 {
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700258 m_sock->fetchRaw(v[i].prefix, seq, bind(&ChatDialog::processDataWrapper, this, _1, _2, _3), 2);
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700259#ifdef __DEBUG
260 std::cout << "<<< Fetching " << v[i].prefix << "/" <<seq.getSession() <<"/" << seq.getSeq() << std::endl;
261#endif
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700262 }
263 }
Zhenkai Zhubb198112012-09-27 11:31:42 -0700264 else
265 {
266 m_sock->fetchRaw(v[i].prefix, v[i].high, bind(&ChatDialog::processDataNoShowWrapper, this, _1, _2, _3), 2);
267 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700268 }
269
270 // adjust the view
271 fitView();
272
273}
274
275void
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700276ChatDialog::processDataWrapper(std::string name, const char *buf, size_t len)
277{
Zhenkai Zhubb198112012-09-27 11:31:42 -0700278 emit dataReceived(name.c_str(), buf, len, true);
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700279#ifdef __DEBUG
280 std::cout <<"<<< " << name << " fetched" << std::endl;
281#endif
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700282}
283
284void
Zhenkai Zhubb198112012-09-27 11:31:42 -0700285ChatDialog::processDataNoShowWrapper(std::string name, const char *buf, size_t len)
286{
287 emit dataReceived(name.c_str(), buf, len, false);
288}
289
290void
291ChatDialog::processData(QString name, const char *buf, size_t len, bool show)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700292{
293 SyncDemo::ChatMessage msg;
294 if (!msg.ParseFromArray(buf, len))
295 {
Zhenkai Zhubb198112012-09-27 11:31:42 -0700296 std::cerr << "Errrrr.. Can not parse msg with name: " << name.toStdString() << ". what is happening?" << std::endl;
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700297 }
298
Zhenkai Zhu10ccb5a2012-06-04 21:55:14 -0700299 // display msg received from network
300 // we have to do so; this function is called by ccnd thread
301 // so if we call appendMsg directly
302 // Qt crash as "QObject: Cannot create children for a parent that is in a different thread"
303 // the "cannonical" way to is use signal-slot
Zhenkai Zhubb198112012-09-27 11:31:42 -0700304 if (show)
305 {
306 appendMessage(msg);
307 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700308
309 // update the tree view
Zhenkai Zhu097bfe72012-06-05 14:30:17 -0700310 std::string stdStrName = name.toStdString();
311 std::string stdStrNameWithoutSeq = stdStrName.substr(0, stdStrName.find_last_of('/'));
312 std::string prefix = stdStrNameWithoutSeq.substr(0, stdStrNameWithoutSeq.find_last_of('/'));
313#ifdef __DEBUG
314 std::cout <<"<<< updating scene for" << prefix << ": " << msg.from() << std::endl;
315#endif
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->msgReceived(prefix.c_str(), msg.from().c_str());
319 }
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700320 fitView();
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700321}
322
323void
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700324ChatDialog::processRemoveWrapper(std::string prefix)
325{
326 emit removeReceived(prefix.c_str());
327}
328
329void
330ChatDialog::processRemove(QString prefix)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700331{
Zhenkai Zhu591e8c32012-09-26 11:57:50 -0700332#ifdef __DEBUG
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700333 std::cout << "<<< remove node for prefix" << prefix.toStdString() << std::endl;
Zhenkai Zhu591e8c32012-09-26 11:57:50 -0700334#endif
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700335 bool removed = m_scene->removeNode(prefix);
Zhenkai Zhu591e8c32012-09-26 11:57:50 -0700336 if (removed)
337 {
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700338 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu591e8c32012-09-26 11:57:50 -0700339 m_scene->plot(m_sock->getRootDigest().c_str());
340 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700341}
342
343void
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700344ChatDialog::formChatMessage(const QString &text, SyncDemo::ChatMessage &msg) {
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700345 msg.set_from(m_user.getNick().toStdString());
346 msg.set_to(m_user.getChatroom().toStdString());
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700347 msg.set_data(text.toStdString());
348 time_t seconds = time(NULL);
349 msg.set_timestamp(seconds);
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700350 msg.set_type(SyncDemo::ChatMessage::CHAT);
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700351}
352
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700353void
354ChatDialog::formHelloMessage(SyncDemo::ChatMessage &msg)
355{
356 msg.set_from(m_user.getNick().toStdString());
357 msg.set_to(m_user.getChatroom().toStdString());
358 time_t seconds = time(NULL);
359 msg.set_timestamp(seconds);
360 msg.set_type(SyncDemo::ChatMessage::HELLO);
361}
362
Zhenkai Zhu59245aa2012-09-26 16:07:04 -0700363static std::string chars("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM0123456789");
364
365QString
366ChatDialog::getRandomString()
367{
368 std::string randStr;
369 boost::random::random_device rng;
370 boost::random::uniform_int_distribution<> index_dist(0, chars.size() - 1);
371 for (int i = 0; i < 10; i ++)
372 {
373 randStr += chars[index_dist(rng)];
374 }
375 return randStr.c_str();
376}
377
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700378bool
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700379ChatDialog::readSettings()
380{
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700381#ifndef __DEBUG
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700382 QSettings s(ORGANIZATION, APPLICATION);
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700383 QString nick = s.value("nick", "").toString();
384 QString chatroom = s.value("chatroom", "").toString();
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700385 QString originPrefix = s.value("originPrefix", "").toString();
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700386 if (nick == "" || chatroom == "" || prefix == "") {
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700387 QTimer::singleShot(500, this, SLOT(buttonPressed()));
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700388 return false;
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700389 }
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700390 else {
391 m_user.setNick(nick);
392 m_user.setChatroom(chatroom);
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700393 m_user.setOriginPrefix(originPrefix);
394 m_user.setPrefix(origin_prefix + "/" + chatroom + "/" + getRandomString());
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700395 return true;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700396 }
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700397#else
398 QTimer::singleShot(500, this, SLOT(buttonPressed()));
399 return false;
400#endif
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700401}
402
403void
404ChatDialog::writeSettings()
405{
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700406#ifndef __DEBUG
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700407 QSettings s(ORGANIZATION, APPLICATION);
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700408 s.setValue("nick", m_user.getNick());
409 s.setValue("chatroom", m_user.getChatroom());
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700410 s.setValue("originPrefix", m_user.getOriginPrefix());
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700411#endif
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700412}
413
414void
415ChatDialog::updateLabels()
416{
Zhenkai Zhu76ff02b2012-09-27 21:11:03 -0700417 QString settingDisp = QString("Chatroom: %1").arg(m_user.getChatroom());
418 infoLabel->setStyleSheet("QLabel {color: #630; font-size: 16px; font: bold \"Verdana\";}");
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700419 infoLabel->setText(settingDisp);
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700420 QString prefixDisp = QString("<Prefix: %1>").arg(m_user.getPrefix());
421 prefixLabel->setText(prefixDisp);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700422}
423
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700424void
425ChatDialog::returnPressed()
426{
427 QString text = lineEdit->text();
428 if (text.isEmpty())
429 return;
430
Zhenkai Zhub6338822012-05-31 13:27:24 -0700431 lineEdit->clear();
432
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700433 SyncDemo::ChatMessage msg;
434 formChatMessage(text, msg);
435
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700436 appendMessage(msg);
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700437
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700438 sendMsg(msg);
439
440 fitView();
441}
442
443void
444ChatDialog::sendMsg(SyncDemo::ChatMessage &msg)
445{
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700446 // send msg
447 size_t size = msg.ByteSize();
448 char *buf = new char[size];
449 msg.SerializeToArray(buf, size);
450 if (!msg.IsInitialized())
451 {
452 std::cerr << "Errrrr.. msg was not probally initialized "<<__FILE__ <<":"<<__LINE__<<". what is happening?" << std::endl;
453 abort();
454 }
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700455 m_sock->publishRaw(m_user.getPrefix().toStdString(), m_session, buf, size, FRESHNESS);
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700456
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700457 delete buf;
458
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700459 m_lastMsgTime = time(NULL);
460
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700461 int nextSequence = m_sock->getNextSeq(m_user.getPrefix().toStdString(), m_session);
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700462 Sync::MissingDataInfo mdi = {m_user.getPrefix().toStdString(), Sync::SeqNo(0), Sync::SeqNo(nextSequence - 1)};
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700463 std::vector<Sync::MissingDataInfo> v;
464 v.push_back(mdi);
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700465 {
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700466 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700467 m_scene->processUpdate(v, m_sock->getRootDigest().c_str());
468 m_scene->msgReceived(m_user.getPrefix(), m_user.getNick());
469 }
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700470}
471
472void
473ChatDialog::sendHello()
474{
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700475 time_t now = time(NULL);
476 int elapsed = now - m_lastMsgTime;
Zhenkai Zhucc4c2c02012-09-27 21:24:37 -0700477 if (elapsed >= m_randomizedInterval / 1000 || m_sendJoin)
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700478 {
479 SyncDemo::ChatMessage msg;
480 formHelloMessage(msg);
481 sendMsg(msg);
Zhenkai Zhucc4c2c02012-09-27 21:24:37 -0700482 m_sendJoin = false;
Zhenkai Zhuee5c90f2012-09-27 14:05:41 -0700483 QTimer::singleShot(m_randomizedInterval, this, SLOT(sendHello()));
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700484 }
485 else
486 {
Zhenkai Zhuee5c90f2012-09-27 14:05:41 -0700487 QTimer::singleShot((m_randomizedInterval - elapsed * 1000), this, SLOT(sendHello()));
Zhenkai Zhu3e26bb42012-09-27 11:04:09 -0700488 }
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700489}
490
491void
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700492ChatDialog::buttonPressed()
493{
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700494 SettingDialog dialog(this, m_user.getNick(), m_user.getChatroom(), m_user.getOriginPrefix());
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700495 connect(&dialog, SIGNAL(updated(QString, QString, QString)), this, SLOT(settingUpdated(QString, QString, QString)));
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700496 dialog.exec();
Zhenkai Zhue837f792012-06-05 20:47:54 -0700497 QTimer::singleShot(100, this, SLOT(checkSetting()));
498}
499
500void
501ChatDialog::checkSetting()
502{
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700503 if (m_user.getOriginPrefix().isEmpty() || m_user.getNick().isEmpty() || m_user.getChatroom().isEmpty())
Zhenkai Zhue837f792012-06-05 20:47:54 -0700504 {
505 buttonPressed();
506 }
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -0700507}
Zhenkai Zhue08afe02012-05-31 15:49:07 -0700508
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700509void
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700510ChatDialog::settingUpdated(QString nick, QString chatroom, QString originPrefix)
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700511{
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700512 QString randString = getRandomString();
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700513 bool needWrite = false;
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700514 bool needFresh = false;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700515 if (!nick.isEmpty() && nick != m_user.getNick()) {
516 m_user.setNick(nick);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700517 needWrite = true;
518 }
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700519 if (!originPrefix.isEmpty() && originPrefix != m_user.getOriginPrefix()) {
520 m_user.setOriginPrefix(originPrefix);
521 m_user.setPrefix(originPrefix + "/" + m_user.getChatroom() + "/" + randString);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700522 needWrite = true;
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700523 needFresh = true;
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700524 }
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700525 if (!chatroom.isEmpty() && chatroom != m_user.getChatroom()) {
526 m_user.setChatroom(chatroom);
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700527 m_user.setPrefix(m_user.getOriginPrefix() + "/" + chatroom + "/" + randString);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700528 needWrite = true;
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700529 needFresh = true;
530 }
531
532 if (needFresh)
533 {
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700534
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700535 {
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700536 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu44b43752012-06-05 21:18:37 -0700537 m_scene->clearAll();
538 m_scene->plot("Empty");
539 }
Zhenkai Zhucc4c2c02012-09-27 21:24:37 -0700540
541 textEdit->clear();
542
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700543 // TODO: perhaps need to do a lot. e.g. use a new SyncAppSokcet
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700544 if (m_sock != NULL)
545 {
546 delete m_sock;
547 m_sock = NULL;
548 }
549 std::string syncPrefix = BROADCAST_PREFIX_FOR_SYNC_DEMO;
550 syncPrefix += "/";
551 syncPrefix += m_user.getChatroom().toStdString();
Zhenkai Zhua4fb1242012-06-05 20:26:05 -0700552 try
553 {
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700554 m_sock = new Sync::SyncAppSocket(syncPrefix, bind(&ChatDialog::processTreeUpdateWrapper, this, _1, _2), bind(&ChatDialog::processRemoveWrapper, this, _1));
Zhenkai Zhucc4c2c02012-09-27 21:24:37 -0700555 m_sendJoin = true;
Zhenkai Zhu2425b6a2012-09-26 17:11:44 -0700556 sendHello();
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700557 m_timer->start(FRESHNESS * 2000);
Zhenkai Zhua4fb1242012-06-05 20:26:05 -0700558 }
559 catch (Sync::CcnxOperationException ex)
560 {
Zhenkai Zhu0b3fa332012-09-27 21:58:43 -0700561 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 -0700562 std::exit(1);
563 }
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700564
565 fitView();
566
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700567 }
Zhenkai Zhue95c64a2012-09-27 21:46:44 -0700568
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700569 if (needWrite) {
570 writeSettings();
571 updateLabels();
572 }
573}
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700574
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700575void
576ChatDialog::iconActivated(QSystemTrayIcon::ActivationReason reason)
577{
578 switch (reason)
579 {
580 case QSystemTrayIcon::Trigger:
581 case QSystemTrayIcon::DoubleClick:
582 break;
583 case QSystemTrayIcon::MiddleClick:
584 // showMessage();
585 break;
586 default:;
587 }
588}
589
590void
591ChatDialog::showMessage(QString from, QString data)
592{
593 // std::cout <<"Showing Message: " << from.toStdString() << ": " << data.toStdString() << std::endl;
594 if (!isActiveWindow())
595 {
596 trayIcon->showMessage(QString("Chatroom %1 has a new message").arg(m_user.getChatroom()), QString("<%1>: %2").arg(from).arg(data), QSystemTrayIcon::Information, 20000);
597 trayIcon->setIcon(QIcon(":/images/note.png"));
598 }
599}
600
601void
602ChatDialog::messageClicked()
603{
604 this->showMaximized();
605}
606
607void
608ChatDialog::createActions()
609{
610 minimizeAction = new QAction(tr("Mi&nimize"), this);
611 connect(minimizeAction, SIGNAL(triggered()), this, SLOT(hide()));
612
613 maximizeAction = new QAction(tr("Ma&ximize"), this);
614 connect(maximizeAction, SIGNAL(triggered()), this, SLOT(showMaximized()));
615
616 restoreAction = new QAction(tr("&Restore"), this);
617 connect(restoreAction, SIGNAL(triggered()), this, SLOT(showNormal()));
618
619 quitAction = new QAction(tr("Quit"), this);
620 connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
621}
622
623void
624ChatDialog::createTrayIcon()
625{
626 trayIconMenu = new QMenu(this);
627 trayIconMenu->addAction(minimizeAction);
628 trayIconMenu->addAction(maximizeAction);
629 trayIconMenu->addAction(restoreAction);
630 trayIconMenu->addSeparator();
631 trayIconMenu->addAction(quitAction);
632
633 trayIcon = new QSystemTrayIcon(this);
634 trayIcon->setContextMenu(trayIconMenu);
635
636 QIcon icon(":/images/icon_small.png");
637 trayIcon->setIcon(icon);
638 setWindowIcon(icon);
Zhenkai Zhu0b3fa332012-09-27 21:58:43 -0700639 trayIcon->setToolTip("Chronos System Tray Icon");
Zhenkai Zhu3a008fc2012-06-08 17:36:39 -0700640 trayIcon->setVisible(true);
641}
642
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700643void
644ChatDialog::resizeEvent(QResizeEvent *e)
645{
646 fitView();
647}
648
649void
650ChatDialog::showEvent(QShowEvent *e)
651{
652 fitView();
653}
654
655void
656ChatDialog::fitView()
657{
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700658 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700659 QRectF rect = m_scene->itemsBoundingRect();
660 m_scene->setSceneRect(rect);
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700661 treeViewer->fitInView(m_scene->itemsBoundingRect(), Qt::KeepAspectRatio);
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700662}