blob: d692d4e5a3d90c5f67dfa8070523f63b756fea9a [file] [log] [blame]
Yingdi Yu7989eb22013-10-31 17:38:22 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2/*
3 * Copyright (c) 2013, Regents of the University of California
4 * Yingdi Yu
5 *
6 * BSD license, See the LICENSE file for more information
7 *
8 * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
9 * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
10 */
11
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -070012#include "digesttreescene.h"
13
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -070014#include <QtGui>
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -070015
16#ifndef Q_MOC_RUN
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -070017#include <vector>
18#include <iostream>
19#include <assert.h>
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -070020#include <boost/lexical_cast.hpp>
Zhenkai Zhu21d75f92012-06-04 21:23:34 -070021#include <memory>
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -070022#endif
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -070023
24static const double Pi = 3.14159265358979323846264338327950288419717;
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -070025
Zhenkai Zhu7f52e1b2012-10-09 11:45:36 -070026//DisplayUserPtr DisplayUserNullPtr;
Zhenkai Zhud13acd02012-06-04 15:25:20 -070027
Yingdi Yu3a014852014-02-11 22:54:11 -080028DigestTreeScene::DigestTreeScene(ndn::shared_ptr<boost::asio::io_service> ioService,
29 QWidget *parent)
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -070030 : QGraphicsScene(parent)
Yingdi Yu3a014852014-02-11 22:54:11 -080031 , m_scheduler(*ioService)
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -070032{
Zhenkai Zhud13acd02012-06-04 15:25:20 -070033 previouslyUpdatedUser = DisplayUserNullPtr;
Zhenkai Zhu6fcdee42012-05-30 17:02:49 -070034}
35
36void
Zhenkai Zhu82a62752012-06-04 17:11:04 -070037DigestTreeScene::processUpdate(const std::vector<Sync::MissingDataInfo> &v, QString digest)
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -070038{
39 int n = v.size();
40 bool rePlot = false;
41 for (int i = 0; i < n; i++)
42 {
43 Roster_iterator it = m_roster.find(v[i].prefix.c_str());
Zhenkai Zhud1c5a972012-06-05 14:07:41 -070044 if (it == m_roster.end())
45 {
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -070046 rePlot = true;
47 DisplayUserPtr p(new DisplayUser());
Zhenkai Zhuc61dbc22012-10-08 11:36:37 -070048 time_t tempTime = time(NULL) - FRESHNESS + 1;
Zhenkai Zhu86df7412012-09-27 16:30:20 -070049 p->setReceived(tempTime);
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -070050 p->setPrefix(v[i].prefix.c_str());
51 p->setSeq(v[i].high);
52 m_roster.insert(p->getPrefix(), p);
53 }
Zhenkai Zhud1c5a972012-06-05 14:07:41 -070054 else
55 {
56 it.value()->setSeq(v[i].high);
57 }
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -070058 }
59
60 if (rePlot)
61 {
62 plot(digest);
Yingdi Yu3a014852014-02-11 22:54:11 -080063 m_scheduler.scheduleEvent(ndn::time::milliseconds(600), ndn::bind(&DigestTreeScene::emitReplot, this));
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -070064 }
65 else
66 {
67 for (int i = 0; i < n; i++)
68 {
69 Roster_iterator it = m_roster.find(v[i].prefix.c_str());
70 if (it != m_roster.end()) {
71 DisplayUserPtr p = it.value();
72 QGraphicsTextItem *item = p->getSeqTextItem();
Zhenkai Zhud13acd02012-06-04 15:25:20 -070073 QGraphicsRectItem *rectItem = p->getInnerRectItem();
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -070074 std::string s = boost::lexical_cast<std::string>(p->getSeqNo().getSeq());
75 item->setPlainText(s.c_str());
Zhenkai Zhud13acd02012-06-04 15:25:20 -070076 QRectF textBR = item->boundingRect();
77 QRectF rectBR = rectItem->boundingRect();
78 item->setPos(rectBR.x() + (rectBR.width() - textBR.width())/2, rectBR.y() + (rectBR.height() - textBR.height())/2);
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -070079 }
80 }
81 m_rootDigest->setPlainText(digest);
82 }
83}
84
85void
Zhenkai Zhu86df7412012-09-27 16:30:20 -070086DigestTreeScene::emitReplot()
87{
88 emit replot();
89}
90
Zhenkai Zhu9036e032012-09-27 20:59:33 -070091QStringList
Zhenkai Zhu6082ede2012-09-27 17:28:46 -070092DigestTreeScene::getRosterList()
93{
Zhenkai Zhu9036e032012-09-27 20:59:33 -070094 QStringList rosterList;
95 RosterIterator it(m_roster);
96 while(it.hasNext())
97 {
98 it.next();
99 DisplayUserPtr p = it.value();
100 if (p != DisplayUserNullPtr)
101 {
102 rosterList << "- " + p->getNick();
103 }
104 }
105 return rosterList;
Zhenkai Zhu6082ede2012-09-27 17:28:46 -0700106}
107
108void
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700109DigestTreeScene::msgReceived(QString prefix, QString nick)
110{
111 Roster_iterator it = m_roster.find(prefix);
112 if (it != m_roster.end())
113 {
Zhenkai Zhu716fe852012-10-08 18:27:55 -0700114 std::cout << "Updating for prefix = " << prefix.toStdString() << " nick = " << nick.toStdString() << std::endl;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700115 DisplayUserPtr p = it.value();
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700116 p->setReceived(time(NULL));
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700117 if (nick != p->getNick()) {
Zhenkai Zhu716fe852012-10-08 18:27:55 -0700118 std::cout << "old nick = " << p->getNick().toStdString() << std::endl;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700119 p->setNick(nick);
120 QGraphicsTextItem *nickItem = p->getNickTextItem();
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700121 QGraphicsRectItem *nickRectItem = p->getNickRectItem();
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700122 nickItem->setPlainText(p->getNick());
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700123 QRectF rectBR = nickRectItem->boundingRect();
124 QRectF nickBR = nickItem->boundingRect();
125 nickItem->setPos(rectBR.x() + (rectBR.width() - nickBR.width())/2, rectBR.y() + 5);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700126 emit rosterChanged(QStringList());
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700127 }
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700128
129 reDrawNode(p, Qt::red);
130
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700131 if (previouslyUpdatedUser != DisplayUserNullPtr && previouslyUpdatedUser != p)
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700132 {
133 reDrawNode(previouslyUpdatedUser, Qt::darkBlue);
134 }
135
136 previouslyUpdatedUser = p;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700137 }
138}
139
140void
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700141DigestTreeScene::clearAll()
142{
143 clear();
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700144 m_roster.clear();
145}
146
Zhenkai Zhu591e8c32012-09-26 11:57:50 -0700147bool
148DigestTreeScene::removeNode(const QString prefix)
149{
150 int removedCount = m_roster.remove(prefix);
151 return (removedCount > 0);
152}
153
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700154void
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700155DigestTreeScene::plot(QString digest)
156{
Yingdi Yufa4ce792014-02-06 18:09:22 -0800157#ifdef _DEBUG
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700158 std::cout << "Plotting at time: " << time(NULL) << std::endl;
159#endif
Zhenkai Zhu6fcdee42012-05-30 17:02:49 -0700160 clear();
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700161
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700162 int nodeSize = 40;
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700163
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700164 int siblingDistance = 100, levelDistance = 100;
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700165 std::auto_ptr<TreeLayout> layout(new OneLevelTreeLayout());
166 layout->setSiblingDistance(siblingDistance);
167 layout->setLevelDistance(levelDistance);
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -0700168
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700169 // do some cleaning, get rid of stale member info
170 Roster_iterator it = m_roster.begin();
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700171 QStringList staleUserList;
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700172 while (it != m_roster.end())
173 {
174 DisplayUserPtr p = it.value();
175 if (p != DisplayUserNullPtr)
176 {
177 time_t now = time(NULL);
Zhenkai Zhuc61dbc22012-10-08 11:36:37 -0700178 if (now - p->getReceived() >= FRESHNESS)
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700179 {
Yingdi Yufa4ce792014-02-06 18:09:22 -0800180#ifdef _DEBUG
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700181 std::cout << "Removing user: " << p->getNick().toStdString() << std::endl;
182 std::cout << "now - last = " << now - p->getReceived() << std::endl;
183#endif
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700184 staleUserList << p->getNick();
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700185 p = DisplayUserNullPtr;
186 it = m_roster.erase(it);
187 }
188 else
189 {
Zhenkai Zhu716fe852012-10-08 18:27:55 -0700190 if (!m_currentPrefix.startsWith("/private/local") && p->getPrefix().startsWith("/private/local"))
191 {
Yingdi Yufa4ce792014-02-06 18:09:22 -0800192#ifdef _DEBUG
Zhenkai Zhu716fe852012-10-08 18:27:55 -0700193 std::cout << "erasing: " << p->getPrefix().toStdString() << std::endl;
194#endif
195 staleUserList << p->getNick();
196 p = DisplayUserNullPtr;
197 it = m_roster.erase(it);
198 continue;
199 }
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700200 ++it;
201 }
202 }
203 else
204 {
205 it = m_roster.erase(it);
206 }
207 }
208
Zhenkai Zhu6082ede2012-09-27 17:28:46 -0700209 // for simpicity here, whenever we replot, we also redo the roster list
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700210 emit rosterChanged(staleUserList);
Zhenkai Zhu6082ede2012-09-27 17:28:46 -0700211
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700212 int n = m_roster.size();
Zhenkai Zhu716fe852012-10-08 18:27:55 -0700213
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700214 std::vector<TreeLayout::Coordinate> childNodesCo(n);
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -0700215
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700216 layout->setOneLevelLayout(childNodesCo);
217
218 plotEdge(childNodesCo, nodeSize);
219 plotNode(childNodesCo, digest, nodeSize);
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700220
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700221 previouslyUpdatedUser = DisplayUserNullPtr;
222
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700223}
224
225void
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700226DigestTreeScene::plotEdge(const std::vector<TreeLayout::Coordinate> &childNodesCo, int nodeSize)
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700227{
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700228 int n = childNodesCo.size();
229 for (int i = 0; i < n; i++) {
230 double x1 = 0.0, y1 = 0.0;
231 double x2 = childNodesCo[i].x, y2 = childNodesCo[i].y;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700232 QPointF src(x1 + nodeSize/2, y1 + nodeSize/2);
233 QPointF dest(x2 + nodeSize/2, y2 + nodeSize/2);
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -0700234 QLineF line(src, dest);
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -0700235 double angle = ::acos(line.dx() / line.length());
236
237 double arrowSize = 10;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700238 QPointF sourceArrowP0 = src + QPointF((nodeSize/2 + 10) * line.dx() / line.length(), (nodeSize/2 +10) * line.dy() / line.length());
239 QPointF sourceArrowP1 = sourceArrowP0 + QPointF(cos(angle + Pi / 3 - Pi/2) * arrowSize,
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -0700240 sin(angle + Pi / 3 - Pi/2) * arrowSize);
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700241 QPointF sourceArrowP2 = sourceArrowP0 + QPointF(cos(angle + Pi - Pi / 3 - Pi/2) * arrowSize,
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -0700242 sin(angle + Pi - Pi / 3 - Pi/2) * arrowSize);
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -0700243
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700244 addLine(QLineF(sourceArrowP0, dest), QPen(Qt::black));
245 addPolygon(QPolygonF() << sourceArrowP0<< sourceArrowP1 << sourceArrowP2, QPen(Qt::black), QBrush(Qt::black));
246 }
247}
248
249void
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700250DigestTreeScene::plotNode(const std::vector<TreeLayout::Coordinate> &childNodesCo, QString digest, int nodeSize)
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700251{
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700252 RosterIterator it(m_roster);
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700253 int n = childNodesCo.size();
254 int rim = 3;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700255
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700256 // plot root node
257 QRectF rootBoundingRect(0, 0, nodeSize, nodeSize);
258 QRectF rootInnerBoundingRect(rim, rim, nodeSize - rim * 2, nodeSize - rim * 2);
259 addRect(rootBoundingRect, QPen(Qt::black), QBrush(Qt::darkRed));
260 addRect(rootInnerBoundingRect, QPen(Qt::black), QBrush(Qt::lightGray));
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700261 QRectF digestRect(- 5.5 * nodeSize , - nodeSize, 12 * nodeSize, 30);
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700262 addRect(digestRect, QPen(Qt::darkCyan), QBrush(Qt::darkCyan));
Zhenkai Zhu27df8d42012-06-05 12:04:04 -0700263
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700264 QGraphicsTextItem *digestItem = addText(digest);
265 QRectF digestBoundingRect = digestItem->boundingRect();
Zhenkai Zhu27df8d42012-06-05 12:04:04 -0700266 digestItem->setDefaultTextColor(Qt::black);
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700267 digestItem->setFont(QFont("Cursive", 12, QFont::Bold));
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700268 digestItem->setPos(- 4.5 * nodeSize + (12 * nodeSize - digestBoundingRect.width()) / 2, - nodeSize + 5);
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700269 m_rootDigest = digestItem;
270
271 // plot child nodes
272 for (int i = 0; i < n; i++)
273 {
274 if (it.hasNext())
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700275 {
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700276 it.next();
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700277 }
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700278 else
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700279 {
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700280 abort();
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700281 }
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700282
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700283 double x = childNodesCo[i].x;
284 double y = childNodesCo[i].y;
285 QRectF boundingRect(x, y, nodeSize, nodeSize);
286 QRectF innerBoundingRect(x + rim, y + rim, nodeSize - rim * 2, nodeSize - rim * 2);
287 DisplayUserPtr p = it.value();
288 QGraphicsRectItem *rectItem = addRect(boundingRect, QPen(Qt::black), QBrush(Qt::darkBlue));
289 p->setRimRectItem(rectItem);
290
291 QGraphicsRectItem *innerRectItem = addRect(innerBoundingRect, QPen(Qt::black), QBrush(Qt::lightGray));
292 p->setInnerRectItem(innerRectItem);
293
294 std::string s = boost::lexical_cast<std::string>(p->getSeqNo().getSeq());
295 QGraphicsTextItem *seqItem = addText(s.c_str());
296 seqItem->setFont(QFont("Cursive", 12, QFont::Bold));
297 QRectF seqBoundingRect = seqItem->boundingRect();
298 seqItem->setPos(x + nodeSize / 2 - seqBoundingRect.width() / 2, y + nodeSize / 2 - seqBoundingRect.height() / 2);
299 p->setSeqTextItem(seqItem);
300
301 QRectF textRect(x - nodeSize / 2, y + nodeSize, 2 * nodeSize, 30);
302 QGraphicsRectItem *nickRectItem = addRect(textRect, QPen(Qt::darkCyan), QBrush(Qt::darkCyan));
303 p->setNickRectItem(nickRectItem);
304 QGraphicsTextItem *nickItem = addText(p->getNick());
305 QRectF textBoundingRect = nickItem->boundingRect();
306 nickItem->setDefaultTextColor(Qt::white);
307 nickItem->setFont(QFont("Cursive", 12, QFont::Bold));
308 nickItem->setPos(x + nodeSize / 2 - textBoundingRect.width() / 2, y + nodeSize + 5);
309 p->setNickTextItem(nickItem);
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -0700310 }
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700311
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -0700312}
313
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700314void
315DigestTreeScene::reDrawNode(DisplayUserPtr p, QColor rimColor)
316{
317 QGraphicsRectItem *rimItem = p->getRimRectItem();
318 rimItem->setBrush(QBrush(rimColor));
319 QGraphicsRectItem *innerItem = p->getInnerRectItem();
320 innerItem->setBrush(QBrush(Qt::lightGray));
321 QGraphicsTextItem *seqTextItem = p->getSeqTextItem();
322 std::string s = boost::lexical_cast<std::string>(p->getSeqNo().getSeq());
323 seqTextItem->setPlainText(s.c_str());
324 QRectF textBR = seqTextItem->boundingRect();
325 QRectF innerBR = innerItem->boundingRect();
326 seqTextItem->setPos(innerBR.x() + (innerBR.width() - textBR.width())/2, innerBR.y() + (innerBR.height() - textBR.height())/2);
327}
328
Alexander Afanasyevb4b92292013-07-09 13:54:59 -0700329#if WAF
330#include "digesttreescene.moc"
331#include "digesttreescene.cpp.moc"
332#endif