blob: b8857143c7238e303754fa7bd0b39e8a3e928b39 [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
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -070012#include "digest-tree-scene.h"
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -070013
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 Yu348f5ea2014-03-01 14:47:25 -080028DigestTreeScene::DigestTreeScene(QWidget *parent)
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -070029 : QGraphicsScene(parent)
30{
Zhenkai Zhud13acd02012-06-04 15:25:20 -070031 previouslyUpdatedUser = DisplayUserNullPtr;
Zhenkai Zhu6fcdee42012-05-30 17:02:49 -070032}
33
34void
Zhenkai Zhu82a62752012-06-04 17:11:04 -070035DigestTreeScene::processUpdate(const std::vector<Sync::MissingDataInfo> &v, QString digest)
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -070036{
37 int n = v.size();
38 bool rePlot = false;
39 for (int i = 0; i < n; i++)
40 {
Yingdi Yu5a5ff202014-03-17 10:03:02 -070041 QString routablePrefix(v[i].prefix.c_str());
42 QString prefix = trimRoutablePrefix(routablePrefix);
43
44 Roster_iterator it = m_roster.find(prefix);
Zhenkai Zhud1c5a972012-06-05 14:07:41 -070045 if (it == m_roster.end())
46 {
Yingdi Yu5a5ff202014-03-17 10:03:02 -070047 // std::cout << "processUpdate v[" << i << "]: " << prefix.toStdString() << std::endl;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -070048 rePlot = true;
49 DisplayUserPtr p(new DisplayUser());
Zhenkai Zhuc61dbc22012-10-08 11:36:37 -070050 time_t tempTime = time(NULL) - FRESHNESS + 1;
Zhenkai Zhu86df7412012-09-27 16:30:20 -070051 p->setReceived(tempTime);
Yingdi Yu5a5ff202014-03-17 10:03:02 -070052 p->setPrefix(prefix);
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -070053 p->setSeq(v[i].high);
54 m_roster.insert(p->getPrefix(), p);
55 }
Zhenkai Zhud1c5a972012-06-05 14:07:41 -070056 else
57 {
58 it.value()->setSeq(v[i].high);
59 }
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -070060 }
61
62 if (rePlot)
63 {
64 plot(digest);
Yingdi Yu348f5ea2014-03-01 14:47:25 -080065 QTimer::singleShot(2100, this, SLOT(emitReplot()));
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -070066 }
67 else
68 {
69 for (int i = 0; i < n; i++)
70 {
Yingdi Yu5a5ff202014-03-17 10:03:02 -070071 QString routablePrefix(v[i].prefix.c_str());
72 QString prefix = trimRoutablePrefix(routablePrefix);
73
74 Roster_iterator it = m_roster.find(prefix);
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -070075 if (it != m_roster.end()) {
76 DisplayUserPtr p = it.value();
77 QGraphicsTextItem *item = p->getSeqTextItem();
Zhenkai Zhud13acd02012-06-04 15:25:20 -070078 QGraphicsRectItem *rectItem = p->getInnerRectItem();
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -070079 std::string s = boost::lexical_cast<std::string>(p->getSeqNo().getSeq());
80 item->setPlainText(s.c_str());
Zhenkai Zhud13acd02012-06-04 15:25:20 -070081 QRectF textBR = item->boundingRect();
82 QRectF rectBR = rectItem->boundingRect();
83 item->setPos(rectBR.x() + (rectBR.width() - textBR.width())/2, rectBR.y() + (rectBR.height() - textBR.height())/2);
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -070084 }
85 }
86 m_rootDigest->setPlainText(digest);
87 }
88}
89
90void
Zhenkai Zhu86df7412012-09-27 16:30:20 -070091DigestTreeScene::emitReplot()
92{
93 emit replot();
94}
95
Zhenkai Zhu9036e032012-09-27 20:59:33 -070096QStringList
Zhenkai Zhu6082ede2012-09-27 17:28:46 -070097DigestTreeScene::getRosterList()
98{
Zhenkai Zhu9036e032012-09-27 20:59:33 -070099 QStringList rosterList;
100 RosterIterator it(m_roster);
101 while(it.hasNext())
102 {
103 it.next();
104 DisplayUserPtr p = it.value();
105 if (p != DisplayUserNullPtr)
106 {
107 rosterList << "- " + p->getNick();
108 }
109 }
110 return rosterList;
Zhenkai Zhu6082ede2012-09-27 17:28:46 -0700111}
112
113void
Yingdi Yu5a5ff202014-03-17 10:03:02 -0700114DigestTreeScene::msgReceived(QString routablePrefix, QString nick)
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700115{
Yingdi Yu5a5ff202014-03-17 10:03:02 -0700116 QString prefix = trimRoutablePrefix(routablePrefix);
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700117 Roster_iterator it = m_roster.find(prefix);
Yingdi Yu5a5ff202014-03-17 10:03:02 -0700118 // std::cout << "msgReceived prefix: " << prefix.toStdString() << std::endl;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700119 if (it != m_roster.end())
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700120 {
Yingdi Yu5a5ff202014-03-17 10:03:02 -0700121 // std::cout << "Updating for prefix = " << prefix.toStdString() << " nick = " << nick.toStdString() << std::endl;
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -0700122 DisplayUserPtr p = it.value();
123 p->setReceived(time(NULL));
124 if (nick != p->getNick())
125 {
Yingdi Yu5a5ff202014-03-17 10:03:02 -0700126 // std::cout << "old nick = " << p->getNick().toStdString() << std::endl;
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -0700127 p->setNick(nick);
128 QGraphicsTextItem *nickItem = p->getNickTextItem();
129 QGraphicsRectItem *nickRectItem = p->getNickRectItem();
130 nickItem->setPlainText(p->getNick());
131 QRectF rectBR = nickRectItem->boundingRect();
132 QRectF nickBR = nickItem->boundingRect();
133 nickItem->setPos(rectBR.x() + (rectBR.width() - nickBR.width())/2, rectBR.y() + 5);
134 emit rosterChanged(QStringList());
135 }
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700136
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -0700137 reDrawNode(p, Qt::red);
138
139 if (previouslyUpdatedUser != DisplayUserNullPtr && previouslyUpdatedUser != p)
140 {
141 reDrawNode(previouslyUpdatedUser, Qt::darkBlue);
142 }
143
144 previouslyUpdatedUser = p;
145 }
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700146}
147
148void
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700149DigestTreeScene::clearAll()
150{
151 clear();
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700152 m_roster.clear();
153}
154
Zhenkai Zhu591e8c32012-09-26 11:57:50 -0700155bool
156DigestTreeScene::removeNode(const QString prefix)
157{
158 int removedCount = m_roster.remove(prefix);
159 return (removedCount > 0);
160}
161
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700162void
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700163DigestTreeScene::plot(QString digest)
164{
Yingdi Yufa4ce792014-02-06 18:09:22 -0800165#ifdef _DEBUG
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700166 std::cout << "Plotting at time: " << time(NULL) << std::endl;
167#endif
Zhenkai Zhu6fcdee42012-05-30 17:02:49 -0700168 clear();
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700169
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700170 int nodeSize = 40;
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700171
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700172 int siblingDistance = 100, levelDistance = 100;
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700173 std::auto_ptr<TreeLayout> layout(new OneLevelTreeLayout());
174 layout->setSiblingDistance(siblingDistance);
175 layout->setLevelDistance(levelDistance);
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -0700176
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700177 // do some cleaning, get rid of stale member info
178 Roster_iterator it = m_roster.begin();
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700179 QStringList staleUserList;
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700180 while (it != m_roster.end())
181 {
182 DisplayUserPtr p = it.value();
183 if (p != DisplayUserNullPtr)
184 {
185 time_t now = time(NULL);
Zhenkai Zhuc61dbc22012-10-08 11:36:37 -0700186 if (now - p->getReceived() >= FRESHNESS)
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700187 {
Yingdi Yufa4ce792014-02-06 18:09:22 -0800188#ifdef _DEBUG
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700189 std::cout << "Removing user: " << p->getNick().toStdString() << std::endl;
190 std::cout << "now - last = " << now - p->getReceived() << std::endl;
191#endif
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700192 staleUserList << p->getNick();
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700193 p = DisplayUserNullPtr;
194 it = m_roster.erase(it);
195 }
196 else
197 {
Zhenkai Zhu716fe852012-10-08 18:27:55 -0700198 if (!m_currentPrefix.startsWith("/private/local") && p->getPrefix().startsWith("/private/local"))
199 {
Yingdi Yufa4ce792014-02-06 18:09:22 -0800200#ifdef _DEBUG
Zhenkai Zhu716fe852012-10-08 18:27:55 -0700201 std::cout << "erasing: " << p->getPrefix().toStdString() << std::endl;
202#endif
203 staleUserList << p->getNick();
204 p = DisplayUserNullPtr;
205 it = m_roster.erase(it);
206 continue;
207 }
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700208 ++it;
209 }
210 }
211 else
212 {
213 it = m_roster.erase(it);
214 }
215 }
216
Zhenkai Zhu6082ede2012-09-27 17:28:46 -0700217 // for simpicity here, whenever we replot, we also redo the roster list
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700218 emit rosterChanged(staleUserList);
Zhenkai Zhu6082ede2012-09-27 17:28:46 -0700219
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700220 int n = m_roster.size();
Zhenkai Zhu716fe852012-10-08 18:27:55 -0700221
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700222 std::vector<TreeLayout::Coordinate> childNodesCo(n);
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -0700223
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700224 layout->setOneLevelLayout(childNodesCo);
225
226 plotEdge(childNodesCo, nodeSize);
227 plotNode(childNodesCo, digest, nodeSize);
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700228
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700229 previouslyUpdatedUser = DisplayUserNullPtr;
230
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700231}
232
233void
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700234DigestTreeScene::plotEdge(const std::vector<TreeLayout::Coordinate> &childNodesCo, int nodeSize)
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700235{
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700236 int n = childNodesCo.size();
237 for (int i = 0; i < n; i++) {
238 double x1 = 0.0, y1 = 0.0;
239 double x2 = childNodesCo[i].x, y2 = childNodesCo[i].y;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700240 QPointF src(x1 + nodeSize/2, y1 + nodeSize/2);
241 QPointF dest(x2 + nodeSize/2, y2 + nodeSize/2);
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -0700242 QLineF line(src, dest);
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -0700243 double angle = ::acos(line.dx() / line.length());
244
245 double arrowSize = 10;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700246 QPointF sourceArrowP0 = src + QPointF((nodeSize/2 + 10) * line.dx() / line.length(), (nodeSize/2 +10) * line.dy() / line.length());
247 QPointF sourceArrowP1 = sourceArrowP0 + QPointF(cos(angle + Pi / 3 - Pi/2) * arrowSize,
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -0700248 sin(angle + Pi / 3 - Pi/2) * arrowSize);
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700249 QPointF sourceArrowP2 = sourceArrowP0 + QPointF(cos(angle + Pi - Pi / 3 - Pi/2) * arrowSize,
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -0700250 sin(angle + Pi - Pi / 3 - Pi/2) * arrowSize);
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -0700251
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700252 addLine(QLineF(sourceArrowP0, dest), QPen(Qt::black));
253 addPolygon(QPolygonF() << sourceArrowP0<< sourceArrowP1 << sourceArrowP2, QPen(Qt::black), QBrush(Qt::black));
254 }
255}
256
257void
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700258DigestTreeScene::plotNode(const std::vector<TreeLayout::Coordinate> &childNodesCo, QString digest, int nodeSize)
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700259{
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700260 RosterIterator it(m_roster);
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700261 int n = childNodesCo.size();
262 int rim = 3;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700263
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700264 // plot root node
265 QRectF rootBoundingRect(0, 0, nodeSize, nodeSize);
266 QRectF rootInnerBoundingRect(rim, rim, nodeSize - rim * 2, nodeSize - rim * 2);
267 addRect(rootBoundingRect, QPen(Qt::black), QBrush(Qt::darkRed));
268 addRect(rootInnerBoundingRect, QPen(Qt::black), QBrush(Qt::lightGray));
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700269 QRectF digestRect(- 5.5 * nodeSize , - nodeSize, 12 * nodeSize, 30);
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700270 addRect(digestRect, QPen(Qt::darkCyan), QBrush(Qt::darkCyan));
Zhenkai Zhu27df8d42012-06-05 12:04:04 -0700271
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700272 QGraphicsTextItem *digestItem = addText(digest);
273 QRectF digestBoundingRect = digestItem->boundingRect();
Zhenkai Zhu27df8d42012-06-05 12:04:04 -0700274 digestItem->setDefaultTextColor(Qt::black);
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700275 digestItem->setFont(QFont("Cursive", 12, QFont::Bold));
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700276 digestItem->setPos(- 4.5 * nodeSize + (12 * nodeSize - digestBoundingRect.width()) / 2, - nodeSize + 5);
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700277 m_rootDigest = digestItem;
278
279 // plot child nodes
280 for (int i = 0; i < n; i++)
281 {
282 if (it.hasNext())
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700283 {
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700284 it.next();
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700285 }
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700286 else
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700287 {
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700288 abort();
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700289 }
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700290
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700291 double x = childNodesCo[i].x;
292 double y = childNodesCo[i].y;
293 QRectF boundingRect(x, y, nodeSize, nodeSize);
294 QRectF innerBoundingRect(x + rim, y + rim, nodeSize - rim * 2, nodeSize - rim * 2);
295 DisplayUserPtr p = it.value();
296 QGraphicsRectItem *rectItem = addRect(boundingRect, QPen(Qt::black), QBrush(Qt::darkBlue));
297 p->setRimRectItem(rectItem);
298
299 QGraphicsRectItem *innerRectItem = addRect(innerBoundingRect, QPen(Qt::black), QBrush(Qt::lightGray));
300 p->setInnerRectItem(innerRectItem);
301
302 std::string s = boost::lexical_cast<std::string>(p->getSeqNo().getSeq());
303 QGraphicsTextItem *seqItem = addText(s.c_str());
304 seqItem->setFont(QFont("Cursive", 12, QFont::Bold));
305 QRectF seqBoundingRect = seqItem->boundingRect();
306 seqItem->setPos(x + nodeSize / 2 - seqBoundingRect.width() / 2, y + nodeSize / 2 - seqBoundingRect.height() / 2);
307 p->setSeqTextItem(seqItem);
308
309 QRectF textRect(x - nodeSize / 2, y + nodeSize, 2 * nodeSize, 30);
310 QGraphicsRectItem *nickRectItem = addRect(textRect, QPen(Qt::darkCyan), QBrush(Qt::darkCyan));
311 p->setNickRectItem(nickRectItem);
312 QGraphicsTextItem *nickItem = addText(p->getNick());
313 QRectF textBoundingRect = nickItem->boundingRect();
314 nickItem->setDefaultTextColor(Qt::white);
315 nickItem->setFont(QFont("Cursive", 12, QFont::Bold));
316 nickItem->setPos(x + nodeSize / 2 - textBoundingRect.width() / 2, y + nodeSize + 5);
317 p->setNickTextItem(nickItem);
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -0700318 }
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700319
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -0700320}
321
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700322void
323DigestTreeScene::reDrawNode(DisplayUserPtr p, QColor rimColor)
324{
325 QGraphicsRectItem *rimItem = p->getRimRectItem();
326 rimItem->setBrush(QBrush(rimColor));
327 QGraphicsRectItem *innerItem = p->getInnerRectItem();
328 innerItem->setBrush(QBrush(Qt::lightGray));
329 QGraphicsTextItem *seqTextItem = p->getSeqTextItem();
330 std::string s = boost::lexical_cast<std::string>(p->getSeqNo().getSeq());
331 seqTextItem->setPlainText(s.c_str());
332 QRectF textBR = seqTextItem->boundingRect();
333 QRectF innerBR = innerItem->boundingRect();
334 seqTextItem->setPos(innerBR.x() + (innerBR.width() - textBR.width())/2, innerBR.y() + (innerBR.height() - textBR.height())/2);
335}
336
Yingdi Yu5a5ff202014-03-17 10:03:02 -0700337QString
338DigestTreeScene::trimRoutablePrefix(QString prefix)
339{
340 bool encaped = false;
341 ndn::Name prefixName(prefix.toStdString());
342
343 ndn::Name::const_iterator it = prefixName.begin();
344 ndn::Name::const_iterator end = prefixName.end();
345 size_t offset = 0;
346
347 for(; it != end; it++, offset++)
348 {
349 if(it->toEscapedString() == "%F0.")
350 {
351 encaped = true;
352 break;
353 }
354 }
355
356 if(!encaped)
357 return prefix;
358 else
359 {
360 return QString(prefixName.getSubName(offset+1).toUri().c_str());
361 }
362}
363
Alexander Afanasyevb4b92292013-07-09 13:54:59 -0700364#if WAF
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -0700365#include "digest-tree-scene.moc"
366#include "digest-tree-scene.cpp.moc"
Alexander Afanasyevb4b92292013-07-09 13:54:59 -0700367#endif