blob: 5527f96f83a8776783e9fc6655ec3fb8a00f8f25 [file] [log] [blame]
Zhenkai Zhufd52ab72012-05-29 17:34:35 -07001#include <QtGui>
2#include "chatdialog.h"
Zhenkai Zhu275ba3a2012-06-01 23:10:43 -07003#include "settingdialog.h"
Zhenkai Zhuc71da772012-05-30 21:25:23 -07004#include <ctime>
Zhenkai Zhu2c55b382012-05-31 13:27:24 -07005#include <iostream>
Zhenkai Zhu3472e3f2012-06-02 00:44:42 -07006#include <QTimer>
Zhenkai Zhue8b9e8e2012-06-04 21:55:14 -07007#include <QMetaType>
Zhenkai Zhufd52ab72012-05-29 17:34:35 -07008
Zhenkai Zhu36c6b782012-06-04 17:11:04 -07009#define BROADCAST_PREFIX_FOR_SYNC_DEMO "/ndn/broadcast/sync-demo"
10
Zhenkai Zhu88380c12012-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 Zhufd52ab72012-05-29 17:34:35 -070033ChatDialog::ChatDialog(QWidget *parent)
Zhenkai Zhu36c6b782012-06-04 17:11:04 -070034 : QDialog(parent), m_sock(NULL)
Zhenkai Zhufd52ab72012-05-29 17:34:35 -070035{
Zhenkai Zhue8b9e8e2012-06-04 21:55:14 -070036 // have to register this, otherwise
37 // the signal-slot system won't recognize this type
38 qRegisterMetaType<SyncDemo::ChatMessage>("SyncDemo::ChatMessage");
Zhenkai Zhufd52ab72012-05-29 17:34:35 -070039 setupUi(this);
Zhenkai Zhu36c6b782012-06-04 17:11:04 -070040 m_session = time(NULL);
Zhenkai Zhu3472e3f2012-06-02 00:44:42 -070041
42 readSettings();
Zhenkai Zhu36c6b782012-06-04 17:11:04 -070043
Zhenkai Zhu3472e3f2012-06-02 00:44:42 -070044 updateLabels();
45
Zhenkai Zhufd52ab72012-05-29 17:34:35 -070046 lineEdit->setFocusPolicy(Qt::StrongFocus);
Zhenkai Zhu36c6b782012-06-04 17:11:04 -070047 m_scene = new DigestTreeScene(this);
Zhenkai Zhu9ec8f412012-06-01 15:44:36 -070048
Zhenkai Zhu36c6b782012-06-04 17:11:04 -070049 treeViewer->setScene(m_scene);
50 m_scene->plot("Empty");
51 QRectF rect = m_scene->itemsBoundingRect();
52 m_scene->setSceneRect(rect);
53
54 // create sync socket
55 if(!m_user.getChatroom().isEmpty()) {
56 std::string syncPrefix = BROADCAST_PREFIX_FOR_SYNC_DEMO;
57 syncPrefix += "/";
58 syncPrefix += m_user.getChatroom().toStdString();
59 m_sock = new Sync::SyncAppSocket(syncPrefix, bind(&ChatDialog::processTreeUpdate, this, _1, _2), bind(&ChatDialog::processRemove, this, _1));
60 }
Zhenkai Zhu9ec8f412012-06-01 15:44:36 -070061
Zhenkai Zhuc71da772012-05-30 21:25:23 -070062 connect(lineEdit, SIGNAL(returnPressed()), this, SLOT(returnPressed()));
Zhenkai Zhu275ba3a2012-06-01 23:10:43 -070063 connect(setButton, SIGNAL(pressed()), this, SLOT(buttonPressed()));
Zhenkai Zhue8b9e8e2012-06-04 21:55:14 -070064 connect(this, SIGNAL(msgReceived(const SyncDemo::ChatMessage)), this, SLOT(appendMessage(const SyncDemo::ChatMessage)));
65 //testDraw();
Zhenkai Zhuc71da772012-05-30 21:25:23 -070066}
67
Zhenkai Zhu36c6b782012-06-04 17:11:04 -070068ChatDialog::~ChatDialog()
69{
70 if (m_sock != NULL)
71 {
72 delete m_sock;
73 m_sock = NULL;
74 }
75}
76
Zhenkai Zhuc71da772012-05-30 21:25:23 -070077void
Zhenkai Zhue8b9e8e2012-06-04 21:55:14 -070078ChatDialog::appendMessage(const SyncDemo::ChatMessage msg)
Zhenkai Zhuc71da772012-05-30 21:25:23 -070079{
Zhenkai Zhu2c55b382012-05-31 13:27:24 -070080
81 if (msg.type() != SyncDemo::ChatMessage::CHAT) {
Zhenkai Zhuc71da772012-05-30 21:25:23 -070082 return;
Zhenkai Zhu2c55b382012-05-31 13:27:24 -070083 }
84
85 if (!msg.has_data()) {
86 return;
87 }
88
89 if (msg.from().empty() || msg.data().empty()) {
90 return;
91 }
Zhenkai Zhuc71da772012-05-30 21:25:23 -070092
Zhenkai Zhue8b9e8e2012-06-04 21:55:14 -070093 std::cout << "<<<< Received Message: " << msg.data() << std::endl;
Zhenkai Zhuc71da772012-05-30 21:25:23 -070094 QTextCursor cursor(textEdit->textCursor());
95 cursor.movePosition(QTextCursor::End);
96 QTextTableFormat tableFormat;
97 tableFormat.setBorder(0);
98 QTextTable *table = cursor.insertTable(1, 2, tableFormat);
Zhenkai Zhu2c55b382012-05-31 13:27:24 -070099 QString from = QString("<%1>: ").arg(msg.from().c_str());
100 table->cellAt(0, 0).firstCursorPosition().insertText(from);
101 table->cellAt(0, 1).firstCursorPosition().insertText(msg.data().c_str());
Zhenkai Zhuc71da772012-05-30 21:25:23 -0700102 QScrollBar *bar = textEdit->verticalScrollBar();
103 bar->setValue(bar->maximum());
Zhenkai Zhue8b9e8e2012-06-04 21:55:14 -0700104 std::cout << "<<<<, Message appended " << std::endl;
Zhenkai Zhuc71da772012-05-30 21:25:23 -0700105}
106
Zhenkai Zhu275ba3a2012-06-01 23:10:43 -0700107void
Zhenkai Zhu36c6b782012-06-04 17:11:04 -0700108ChatDialog::processTreeUpdate(const std::vector<Sync::MissingDataInfo> &v, Sync::SyncAppSocket *)
109{
110 if (v.empty())
111 {
112 return;
113 }
114
115 // reflect the changes on digest tree
116 m_scene->processUpdate(v, m_sock->getRootDigest().c_str());
117
118 int n = v.size();
119 int totalMissingPackets = 0;
120 for (int i = 0; i < n; i++)
121 {
122 totalMissingPackets += v[i].high.getSeq() - v[i].low.getSeq() + 1;
123 }
124
125 if (totalMissingPackets < 10) {
126 for (int i = 0; i < n; i++)
127 {
128 for (Sync::SeqNo seq = v[i].low; seq <= v[i].high; ++seq)
129 {
130 m_sock->fetchRaw(v[i].prefix, seq, bind(&ChatDialog::processData, this, _1, _2, _3), 2);
131 }
132 }
133 }
134 else
135 {
136 // too bad; too many missing packets
137 // we may just join a new chatroom
138 // or some network patition just healed
139 // we don't try to fetch any data in this case (for now)
140 }
141
142 // adjust the view
143 fitView();
144
145}
146
147void
148ChatDialog::processData(std::string name, const char *buf, size_t len)
149{
150 SyncDemo::ChatMessage msg;
151 if (!msg.ParseFromArray(buf, len))
152 {
153 std::cerr << "Errrrr.. Can not parse msg at "<<__FILE__ <<":"<<__LINE__<<". what is happening?" << std::endl;
154 abort();
155 }
156
Zhenkai Zhue8b9e8e2012-06-04 21:55:14 -0700157 // display msg received from network
158 // we have to do so; this function is called by ccnd thread
159 // so if we call appendMsg directly
160 // Qt crash as "QObject: Cannot create children for a parent that is in a different thread"
161 // the "cannonical" way to is use signal-slot
162 emit msgReceived(msg);
Zhenkai Zhu36c6b782012-06-04 17:11:04 -0700163
164 // update the tree view
165 std::string prefix = name.substr(0, name.find_last_of('/'));
166 m_scene->msgReceived(prefix.c_str(), msg.from().c_str());
167}
168
169void
170ChatDialog::processRemove(std::string prefix)
171{
172}
173
174void
Zhenkai Zhu275ba3a2012-06-01 23:10:43 -0700175ChatDialog::formChatMessage(const QString &text, SyncDemo::ChatMessage &msg) {
Zhenkai Zhu56a88592012-06-04 09:42:53 -0700176 msg.set_from(m_user.getNick().toStdString());
177 msg.set_to(m_user.getChatroom().toStdString());
Zhenkai Zhu275ba3a2012-06-01 23:10:43 -0700178 msg.set_data(text.toStdString());
179 time_t seconds = time(NULL);
180 msg.set_timestamp(seconds);
Zhenkai Zhu36c6b782012-06-04 17:11:04 -0700181 msg.set_type(SyncDemo::ChatMessage::CHAT);
Zhenkai Zhuc71da772012-05-30 21:25:23 -0700182}
183
Zhenkai Zhu36c6b782012-06-04 17:11:04 -0700184bool
Zhenkai Zhu3472e3f2012-06-02 00:44:42 -0700185ChatDialog::readSettings()
186{
187 QSettings s(ORGANIZATION, APPLICATION);
Zhenkai Zhu56a88592012-06-04 09:42:53 -0700188 QString nick = s.value("nick", "").toString();
189 QString chatroom = s.value("chatroom", "").toString();
190 QString prefix = s.value("prefix", "").toString();
191 if (nick == "" || chatroom == "" || prefix == "") {
Zhenkai Zhu3472e3f2012-06-02 00:44:42 -0700192 QTimer::singleShot(500, this, SLOT(buttonPressed()));
Zhenkai Zhu36c6b782012-06-04 17:11:04 -0700193 return false;
Zhenkai Zhu3472e3f2012-06-02 00:44:42 -0700194 }
Zhenkai Zhu56a88592012-06-04 09:42:53 -0700195 else {
196 m_user.setNick(nick);
197 m_user.setChatroom(chatroom);
198 m_user.setPrefix(prefix);
Zhenkai Zhu36c6b782012-06-04 17:11:04 -0700199 return true;
Zhenkai Zhu56a88592012-06-04 09:42:53 -0700200 }
Zhenkai Zhu3472e3f2012-06-02 00:44:42 -0700201}
202
203void
204ChatDialog::writeSettings()
205{
206 QSettings s(ORGANIZATION, APPLICATION);
Zhenkai Zhu56a88592012-06-04 09:42:53 -0700207 s.setValue("nick", m_user.getNick());
208 s.setValue("chatroom", m_user.getChatroom());
209 s.setValue("prefix", m_user.getPrefix());
Zhenkai Zhu3472e3f2012-06-02 00:44:42 -0700210}
211
212void
213ChatDialog::updateLabels()
214{
Zhenkai Zhu56a88592012-06-04 09:42:53 -0700215 QString settingDisp = QString("<User: %1>, <Chatroom: %2>").arg(m_user.getNick()).arg(m_user.getChatroom());
Zhenkai Zhu3472e3f2012-06-02 00:44:42 -0700216 infoLabel->setText(settingDisp);
Zhenkai Zhu56a88592012-06-04 09:42:53 -0700217 QString prefixDisp = QString("<Prefix: %1>").arg(m_user.getPrefix());
Zhenkai Zhu3472e3f2012-06-02 00:44:42 -0700218 prefixLabel->setText(prefixDisp);
219}
220
Zhenkai Zhuc71da772012-05-30 21:25:23 -0700221void
222ChatDialog::returnPressed()
223{
224 QString text = lineEdit->text();
225 if (text.isEmpty())
226 return;
227
Zhenkai Zhu2c55b382012-05-31 13:27:24 -0700228 lineEdit->clear();
229
Zhenkai Zhuc71da772012-05-30 21:25:23 -0700230 SyncDemo::ChatMessage msg;
231 formChatMessage(text, msg);
232
Zhenkai Zhuc71da772012-05-30 21:25:23 -0700233 appendMessage(msg);
Zhenkai Zhu36c6b782012-06-04 17:11:04 -0700234
235 // send msg
236 size_t size = msg.ByteSize();
237 char *buf = new char[size];
238 msg.SerializeToArray(buf, size);
239 if (!msg.IsInitialized())
240 {
241 std::cerr << "Errrrr.. msg was not probally initialized "<<__FILE__ <<":"<<__LINE__<<". what is happening?" << std::endl;
242 abort();
243 }
244 m_sock->publishRaw(m_user.getPrefix().toStdString(), m_session, buf, size, 60);
Zhenkai Zhu2c55b382012-05-31 13:27:24 -0700245
Zhenkai Zhuc71da772012-05-30 21:25:23 -0700246}
247
248void
Zhenkai Zhu275ba3a2012-06-01 23:10:43 -0700249ChatDialog::buttonPressed()
250{
Zhenkai Zhu56a88592012-06-04 09:42:53 -0700251 SettingDialog dialog(this, m_user.getNick(), m_user.getChatroom(), m_user.getPrefix());
Zhenkai Zhu3472e3f2012-06-02 00:44:42 -0700252 connect(&dialog, SIGNAL(updated(QString, QString, QString)), this, SLOT(settingUpdated(QString, QString, QString)));
Zhenkai Zhu275ba3a2012-06-01 23:10:43 -0700253 dialog.exec();
Zhenkai Zhufd52ab72012-05-29 17:34:35 -0700254}
Zhenkai Zhu80af0e02012-05-31 15:49:07 -0700255
Zhenkai Zhu3472e3f2012-06-02 00:44:42 -0700256void
257ChatDialog::settingUpdated(QString nick, QString chatroom, QString prefix)
258{
259 bool needWrite = false;
Zhenkai Zhu56a88592012-06-04 09:42:53 -0700260 if (!nick.isEmpty() && nick != m_user.getNick()) {
261 m_user.setNick(nick);
Zhenkai Zhu3472e3f2012-06-02 00:44:42 -0700262 needWrite = true;
263 }
Zhenkai Zhu56a88592012-06-04 09:42:53 -0700264 if (!prefix.isEmpty() && prefix != m_user.getPrefix()) {
265 m_user.setPrefix(prefix);
Zhenkai Zhu3472e3f2012-06-02 00:44:42 -0700266 needWrite = true;
267 // TODO: set the previous prefix as left?
268 }
Zhenkai Zhu56a88592012-06-04 09:42:53 -0700269 if (!chatroom.isEmpty() && chatroom != m_user.getChatroom()) {
270 m_user.setChatroom(chatroom);
Zhenkai Zhu3472e3f2012-06-02 00:44:42 -0700271 needWrite = true;
Zhenkai Zhu36c6b782012-06-04 17:11:04 -0700272
273 m_scene->clearAll();
274 m_scene->plot("Empty");
Zhenkai Zhu3472e3f2012-06-02 00:44:42 -0700275 // TODO: perhaps need to do a lot. e.g. use a new SyncAppSokcet
Zhenkai Zhu36c6b782012-06-04 17:11:04 -0700276 if (m_sock != NULL)
277 {
278 delete m_sock;
279 m_sock = NULL;
280 }
281 std::string syncPrefix = BROADCAST_PREFIX_FOR_SYNC_DEMO;
282 syncPrefix += "/";
283 syncPrefix += m_user.getChatroom().toStdString();
284 m_sock = new Sync::SyncAppSocket(syncPrefix, bind(&ChatDialog::processTreeUpdate, this, _1, _2), bind(&ChatDialog::processRemove, this, _1));
285
286 fitView();
287
Zhenkai Zhu3472e3f2012-06-02 00:44:42 -0700288 }
289 if (needWrite) {
290 writeSettings();
291 updateLabels();
292 }
293}
Zhenkai Zhue5660932012-06-04 15:25:20 -0700294
295void
296ChatDialog::resizeEvent(QResizeEvent *e)
297{
298 fitView();
299}
300
301void
302ChatDialog::showEvent(QShowEvent *e)
303{
304 fitView();
305}
306
307void
308ChatDialog::fitView()
309{
Zhenkai Zhu88380c12012-06-04 21:23:34 -0700310 QRectF rect = m_scene->itemsBoundingRect();
311 m_scene->setSceneRect(rect);
Zhenkai Zhu36c6b782012-06-04 17:11:04 -0700312 treeViewer->fitInView(m_scene->itemsBoundingRect(), Qt::KeepAspectRatio);
Zhenkai Zhue5660932012-06-04 15:25:20 -0700313}