blob: e325d6b6c2bb872299c2e5b11ea5edc14860624d [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 Zhu6d589aa2012-05-29 17:34:35 -07008
Zhenkai Zhu82a62752012-06-04 17:11:04 -07009#define BROADCAST_PREFIX_FOR_SYNC_DEMO "/ndn/broadcast/sync-demo"
10
Zhenkai Zhu21d75f92012-06-04 21:23:34 -070011void
12ChatDialog::testDraw()
13{
14 std::string prefix[5] = {"/ndn/1", "/ndn/2", "/ndn/3", "/ndn/4", "/ndn/5"};
15 std::string nick[5] = {"tom", "jerry", "jason", "michael", "hurry"};
16 std::vector<Sync::MissingDataInfo> v;
17 for (int i = 0; i < 5; i++)
18 {
19 Sync::MissingDataInfo mdi = {prefix[i], Sync::SeqNo(0), Sync::SeqNo(i * (2 << i) )};
20 v.push_back(mdi);
21 }
22
23 m_scene->processUpdate(v, "12341234@!#%!@");
24
25 for (int i = 0; i < 5; i++)
26 {
27 m_scene-> msgReceived(prefix[i].c_str(), nick[i].c_str());
28 }
29
30 fitView();
31}
32
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -070033ChatDialog::ChatDialog(QWidget *parent)
Zhenkai Zhu82a62752012-06-04 17:11:04 -070034 : QDialog(parent), m_sock(NULL)
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -070035{
Zhenkai Zhu10ccb5a2012-06-04 21:55:14 -070036 // have to register this, otherwise
37 // the signal-slot system won't recognize this type
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -070038 qRegisterMetaType<std::vector<Sync::MissingDataInfo> >("std::vector<Sync::MissingDataInfo>");
39 qRegisterMetaType<size_t>("size_t");
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -070040 setupUi(this);
Zhenkai Zhu82a62752012-06-04 17:11:04 -070041 m_session = time(NULL);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -070042
43 readSettings();
Zhenkai Zhu82a62752012-06-04 17:11:04 -070044
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -070045 updateLabels();
46
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -070047 lineEdit->setFocusPolicy(Qt::StrongFocus);
Zhenkai Zhu82a62752012-06-04 17:11:04 -070048 m_scene = new DigestTreeScene(this);
Zhenkai Zhub45e38a2012-06-01 15:44:36 -070049
Zhenkai Zhu82a62752012-06-04 17:11:04 -070050 treeViewer->setScene(m_scene);
51 m_scene->plot("Empty");
52 QRectF rect = m_scene->itemsBoundingRect();
53 m_scene->setSceneRect(rect);
54
55 // create sync socket
56 if(!m_user.getChatroom().isEmpty()) {
57 std::string syncPrefix = BROADCAST_PREFIX_FOR_SYNC_DEMO;
58 syncPrefix += "/";
59 syncPrefix += m_user.getChatroom().toStdString();
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -070060 m_sock = new Sync::SyncAppSocket(syncPrefix, bind(&ChatDialog::processTreeUpdateWrapper, this, _1, _2), bind(&ChatDialog::processRemove, this, _1));
Zhenkai Zhu82a62752012-06-04 17:11:04 -070061 }
Zhenkai Zhub45e38a2012-06-01 15:44:36 -070062
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -070063 connect(lineEdit, SIGNAL(returnPressed()), this, SLOT(returnPressed()));
Zhenkai Zhu85845d22012-06-01 23:10:43 -070064 connect(setButton, SIGNAL(pressed()), this, SLOT(buttonPressed()));
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -070065 connect(this, SIGNAL(dataReceived(QString, const char *, size_t)), this, SLOT(processData(QString, const char *, size_t)));
66 connect(this, SIGNAL(treeUpdated(const std::vector<Sync::MissingDataInfo>)), this, SLOT(processTreeUpdate(const std::vector<Sync::MissingDataInfo>)));
Zhenkai Zhu10ccb5a2012-06-04 21:55:14 -070067 //testDraw();
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -070068}
69
Zhenkai Zhu82a62752012-06-04 17:11:04 -070070ChatDialog::~ChatDialog()
71{
72 if (m_sock != NULL)
73 {
74 delete m_sock;
75 m_sock = NULL;
76 }
77}
78
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -070079void
Zhenkai Zhu10ccb5a2012-06-04 21:55:14 -070080ChatDialog::appendMessage(const SyncDemo::ChatMessage msg)
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -070081{
Zhenkai Zhub6338822012-05-31 13:27:24 -070082
83 if (msg.type() != SyncDemo::ChatMessage::CHAT) {
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -070084 return;
Zhenkai Zhub6338822012-05-31 13:27:24 -070085 }
86
87 if (!msg.has_data()) {
88 return;
89 }
90
91 if (msg.from().empty() || msg.data().empty()) {
92 return;
93 }
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -070094
Zhenkai Zhu10ccb5a2012-06-04 21:55:14 -070095 std::cout << "<<<< Received Message: " << msg.data() << std::endl;
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -070096 QTextCursor cursor(textEdit->textCursor());
97 cursor.movePosition(QTextCursor::End);
98 QTextTableFormat tableFormat;
99 tableFormat.setBorder(0);
100 QTextTable *table = cursor.insertTable(1, 2, tableFormat);
Zhenkai Zhub6338822012-05-31 13:27:24 -0700101 QString from = QString("<%1>: ").arg(msg.from().c_str());
102 table->cellAt(0, 0).firstCursorPosition().insertText(from);
103 table->cellAt(0, 1).firstCursorPosition().insertText(msg.data().c_str());
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700104 QScrollBar *bar = textEdit->verticalScrollBar();
105 bar->setValue(bar->maximum());
Zhenkai Zhu10ccb5a2012-06-04 21:55:14 -0700106 std::cout << "<<<<, Message appended " << std::endl;
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700107}
108
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700109void
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700110ChatDialog::processTreeUpdateWrapper(const std::vector<Sync::MissingDataInfo> v, Sync::SyncAppSocket *sock)
111{
112 emit treeUpdated(v);
113}
114
115void
116ChatDialog::processTreeUpdate(const std::vector<Sync::MissingDataInfo> v)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700117{
118 if (v.empty())
119 {
120 return;
121 }
122
123 // reflect the changes on digest tree
124 m_scene->processUpdate(v, m_sock->getRootDigest().c_str());
125
126 int n = v.size();
127 int totalMissingPackets = 0;
128 for (int i = 0; i < n; i++)
129 {
130 totalMissingPackets += v[i].high.getSeq() - v[i].low.getSeq() + 1;
131 }
132
133 if (totalMissingPackets < 10) {
134 for (int i = 0; i < n; i++)
135 {
136 for (Sync::SeqNo seq = v[i].low; seq <= v[i].high; ++seq)
137 {
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700138 m_sock->fetchRaw(v[i].prefix, seq, bind(&ChatDialog::processDataWrapper, this, _1, _2, _3), 2);
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700139 }
140 }
141 }
142 else
143 {
144 // too bad; too many missing packets
145 // we may just join a new chatroom
146 // or some network patition just healed
147 // we don't try to fetch any data in this case (for now)
148 }
149
150 // adjust the view
151 fitView();
152
153}
154
155void
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700156ChatDialog::processDataWrapper(std::string name, const char *buf, size_t len)
157{
158 emit dataReceived(name.c_str(), buf, len);
159}
160
161void
162ChatDialog::processData(QString name, const char *buf, size_t len)
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700163{
164 SyncDemo::ChatMessage msg;
165 if (!msg.ParseFromArray(buf, len))
166 {
167 std::cerr << "Errrrr.. Can not parse msg at "<<__FILE__ <<":"<<__LINE__<<". what is happening?" << std::endl;
168 abort();
169 }
170
Zhenkai Zhu10ccb5a2012-06-04 21:55:14 -0700171 // display msg received from network
172 // we have to do so; this function is called by ccnd thread
173 // so if we call appendMsg directly
174 // Qt crash as "QObject: Cannot create children for a parent that is in a different thread"
175 // the "cannonical" way to is use signal-slot
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700176 appendMessage(msg);
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700177
178 // update the tree view
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700179 std::string prefix = name.toStdString().substr(0, name.toStdString().find_last_of('/'));
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700180 m_scene->msgReceived(prefix.c_str(), msg.from().c_str());
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700181 fitView();
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700182}
183
184void
185ChatDialog::processRemove(std::string prefix)
186{
187}
188
189void
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700190ChatDialog::formChatMessage(const QString &text, SyncDemo::ChatMessage &msg) {
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700191 msg.set_from(m_user.getNick().toStdString());
192 msg.set_to(m_user.getChatroom().toStdString());
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700193 msg.set_data(text.toStdString());
194 time_t seconds = time(NULL);
195 msg.set_timestamp(seconds);
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700196 msg.set_type(SyncDemo::ChatMessage::CHAT);
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700197}
198
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700199bool
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700200ChatDialog::readSettings()
201{
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700202#ifndef __DEBUG
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700203 QSettings s(ORGANIZATION, APPLICATION);
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700204 QString nick = s.value("nick", "").toString();
205 QString chatroom = s.value("chatroom", "").toString();
206 QString prefix = s.value("prefix", "").toString();
207 if (nick == "" || chatroom == "" || prefix == "") {
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700208 QTimer::singleShot(500, this, SLOT(buttonPressed()));
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700209 return false;
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700210 }
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700211 else {
212 m_user.setNick(nick);
213 m_user.setChatroom(chatroom);
214 m_user.setPrefix(prefix);
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700215 return true;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700216 }
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700217#else
218 QTimer::singleShot(500, this, SLOT(buttonPressed()));
219 return false;
220#endif
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700221}
222
223void
224ChatDialog::writeSettings()
225{
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700226#ifndef __DEBUG
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700227 QSettings s(ORGANIZATION, APPLICATION);
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700228 s.setValue("nick", m_user.getNick());
229 s.setValue("chatroom", m_user.getChatroom());
230 s.setValue("prefix", m_user.getPrefix());
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700231#endif
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700232}
233
234void
235ChatDialog::updateLabels()
236{
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700237 QString settingDisp = QString("<User: %1>, <Chatroom: %2>").arg(m_user.getNick()).arg(m_user.getChatroom());
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700238 infoLabel->setText(settingDisp);
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700239 QString prefixDisp = QString("<Prefix: %1>").arg(m_user.getPrefix());
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700240 prefixLabel->setText(prefixDisp);
241}
242
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700243void
244ChatDialog::returnPressed()
245{
246 QString text = lineEdit->text();
247 if (text.isEmpty())
248 return;
249
Zhenkai Zhub6338822012-05-31 13:27:24 -0700250 lineEdit->clear();
251
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700252 SyncDemo::ChatMessage msg;
253 formChatMessage(text, msg);
254
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700255 appendMessage(msg);
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700256
257 // send msg
258 size_t size = msg.ByteSize();
259 char *buf = new char[size];
260 msg.SerializeToArray(buf, size);
261 if (!msg.IsInitialized())
262 {
263 std::cerr << "Errrrr.. msg was not probally initialized "<<__FILE__ <<":"<<__LINE__<<". what is happening?" << std::endl;
264 abort();
265 }
266 m_sock->publishRaw(m_user.getPrefix().toStdString(), m_session, buf, size, 60);
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700267
268 int nextSequence = m_sock->getNextSeq(m_user.getPrefix().toStdString(), m_session);
269 Sync::MissingDataInfo mdi = {m_user.getPrefix().toStdString(), Sync::SeqNo(0), Sync::SeqNo(nextSequence)};
270 std::vector<Sync::MissingDataInfo> v;
271 v.push_back(mdi);
272 m_scene->processUpdate(v, m_sock->getRootDigest().c_str());
273 m_scene->msgReceived(m_user.getPrefix(), m_user.getNick());
274 fitView();
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700275}
276
277void
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700278ChatDialog::buttonPressed()
279{
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700280 SettingDialog dialog(this, m_user.getNick(), m_user.getChatroom(), m_user.getPrefix());
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700281 connect(&dialog, SIGNAL(updated(QString, QString, QString)), this, SLOT(settingUpdated(QString, QString, QString)));
Zhenkai Zhu85845d22012-06-01 23:10:43 -0700282 dialog.exec();
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -0700283}
Zhenkai Zhue08afe02012-05-31 15:49:07 -0700284
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700285void
286ChatDialog::settingUpdated(QString nick, QString chatroom, QString prefix)
287{
288 bool needWrite = false;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700289 if (!nick.isEmpty() && nick != m_user.getNick()) {
290 m_user.setNick(nick);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700291 needWrite = true;
292 }
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700293 if (!prefix.isEmpty() && prefix != m_user.getPrefix()) {
294 m_user.setPrefix(prefix);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700295 needWrite = true;
296 // TODO: set the previous prefix as left?
297 }
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700298 if (!chatroom.isEmpty() && chatroom != m_user.getChatroom()) {
299 m_user.setChatroom(chatroom);
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700300 needWrite = true;
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700301
302 m_scene->clearAll();
303 m_scene->plot("Empty");
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700304 // TODO: perhaps need to do a lot. e.g. use a new SyncAppSokcet
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700305 if (m_sock != NULL)
306 {
307 delete m_sock;
308 m_sock = NULL;
309 }
310 std::string syncPrefix = BROADCAST_PREFIX_FOR_SYNC_DEMO;
311 syncPrefix += "/";
312 syncPrefix += m_user.getChatroom().toStdString();
Zhenkai Zhu64f9ede2012-06-05 11:32:00 -0700313 m_sock = new Sync::SyncAppSocket(syncPrefix, bind(&ChatDialog::processTreeUpdateWrapper, this, _1, _2), bind(&ChatDialog::processRemove, this, _1));
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700314
315 fitView();
316
Zhenkai Zhu7e9b06d2012-06-02 00:44:42 -0700317 }
318 if (needWrite) {
319 writeSettings();
320 updateLabels();
321 }
322}
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700323
324void
325ChatDialog::resizeEvent(QResizeEvent *e)
326{
327 fitView();
328}
329
330void
331ChatDialog::showEvent(QShowEvent *e)
332{
333 fitView();
334}
335
336void
337ChatDialog::fitView()
338{
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700339 QRectF rect = m_scene->itemsBoundingRect();
340 m_scene->setSceneRect(rect);
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700341 treeViewer->fitInView(m_scene->itemsBoundingRect(), Qt::KeepAspectRatio);
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700342}