blob: c2aa865bf1ddc312ea2c19b9e0924abfcf9457fd [file] [log] [blame]
Yingdi Yu42f66462013-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
12#include "digesttreescene.h"
13
14#include <QtGui>
15
16#ifndef Q_MOC_RUN
17#include <vector>
18#include <iostream>
19#include <assert.h>
20#include <boost/lexical_cast.hpp>
21#include <memory>
22#endif
23
24static const double Pi = 3.14159265358979323846264338327950288419717;
25
26//DisplayUserPtr DisplayUserNullPtr;
27
28DigestTreeScene::DigestTreeScene(QWidget *parent)
29 : QGraphicsScene(parent)
30{
31 previouslyUpdatedUser = DisplayUserNullPtr;
32}
33
34void
35DigestTreeScene::processUpdate(const std::vector<Sync::MissingDataInfo> &v, QString digest)
36{
37 int n = v.size();
38 bool rePlot = false;
39 for (int i = 0; i < n; i++)
40 {
41 Roster_iterator it = m_roster.find(v[i].prefix.c_str());
42 if (it == m_roster.end())
43 {
44 rePlot = true;
45 DisplayUserPtr p(new DisplayUser());
46 time_t tempTime = time(NULL) - FRESHNESS + 1;
47 p->setReceived(tempTime);
48 p->setPrefix(v[i].prefix.c_str());
49 p->setSeq(v[i].high);
50 m_roster.insert(p->getPrefix(), p);
51 }
52 else
53 {
54 it.value()->setSeq(v[i].high);
55 }
56 }
57
58 if (rePlot)
59 {
60 plot(digest);
61 QTimer::singleShot(2100, this, SLOT(emitReplot()));
62 }
63 else
64 {
65 for (int i = 0; i < n; i++)
66 {
67 Roster_iterator it = m_roster.find(v[i].prefix.c_str());
68 if (it != m_roster.end()) {
69 DisplayUserPtr p = it.value();
70 QGraphicsTextItem *item = p->getSeqTextItem();
71 QGraphicsRectItem *rectItem = p->getInnerRectItem();
72 std::string s = boost::lexical_cast<std::string>(p->getSeqNo().getSeq());
73 item->setPlainText(s.c_str());
74 QRectF textBR = item->boundingRect();
75 QRectF rectBR = rectItem->boundingRect();
76 item->setPos(rectBR.x() + (rectBR.width() - textBR.width())/2, rectBR.y() + (rectBR.height() - textBR.height())/2);
77 }
78 }
79 m_rootDigest->setPlainText(digest);
80 }
81}
82
83void
84DigestTreeScene::emitReplot()
85{
86 emit replot();
87}
88
89QStringList
90DigestTreeScene::getRosterList()
91{
92 QStringList rosterList;
93 RosterIterator it(m_roster);
94 while(it.hasNext())
95 {
96 it.next();
97 DisplayUserPtr p = it.value();
98 if (p != DisplayUserNullPtr)
99 {
100 rosterList << "- " + p->getNick();
101 }
102 }
103 return rosterList;
104}
105
106void
107DigestTreeScene::msgReceived(QString prefix, QString nick)
108{
109 Roster_iterator it = m_roster.find(prefix);
110 if (it != m_roster.end())
111 {
112 std::cout << "Updating for prefix = " << prefix.toStdString() << " nick = " << nick.toStdString() << std::endl;
113 DisplayUserPtr p = it.value();
114 p->setReceived(time(NULL));
115 if (nick != p->getNick()) {
116 std::cout << "old nick = " << p->getNick().toStdString() << std::endl;
117 p->setNick(nick);
118 QGraphicsTextItem *nickItem = p->getNickTextItem();
119 QGraphicsRectItem *nickRectItem = p->getNickRectItem();
120 nickItem->setPlainText(p->getNick());
121 QRectF rectBR = nickRectItem->boundingRect();
122 QRectF nickBR = nickItem->boundingRect();
123 nickItem->setPos(rectBR.x() + (rectBR.width() - nickBR.width())/2, rectBR.y() + 5);
124 emit rosterChanged(QStringList());
125 }
126
127 reDrawNode(p, Qt::red);
128
129 if (previouslyUpdatedUser != DisplayUserNullPtr && previouslyUpdatedUser != p)
130 {
131 reDrawNode(previouslyUpdatedUser, Qt::darkBlue);
132 }
133
134 previouslyUpdatedUser = p;
135 }
136}
137
138void
139DigestTreeScene::clearAll()
140{
141 clear();
142 m_roster.clear();
143}
144
145bool
146DigestTreeScene::removeNode(const QString prefix)
147{
148 int removedCount = m_roster.remove(prefix);
149 return (removedCount > 0);
150}
151
152void
153DigestTreeScene::plot(QString digest)
154{
Yingdi Yua1a688f2014-02-06 18:09:22 -0800155#ifdef _DEBUG
Yingdi Yu42f66462013-10-31 17:38:22 -0700156 std::cout << "Plotting at time: " << time(NULL) << std::endl;
157#endif
158 clear();
159
160 int nodeSize = 40;
161
162 int siblingDistance = 100, levelDistance = 100;
163 std::auto_ptr<TreeLayout> layout(new OneLevelTreeLayout());
164 layout->setSiblingDistance(siblingDistance);
165 layout->setLevelDistance(levelDistance);
166
167 // do some cleaning, get rid of stale member info
168 Roster_iterator it = m_roster.begin();
169 QStringList staleUserList;
170 while (it != m_roster.end())
171 {
172 DisplayUserPtr p = it.value();
173 if (p != DisplayUserNullPtr)
174 {
175 time_t now = time(NULL);
176 if (now - p->getReceived() >= FRESHNESS)
177 {
Yingdi Yua1a688f2014-02-06 18:09:22 -0800178#ifdef _DEBUG
Yingdi Yu42f66462013-10-31 17:38:22 -0700179 std::cout << "Removing user: " << p->getNick().toStdString() << std::endl;
180 std::cout << "now - last = " << now - p->getReceived() << std::endl;
181#endif
182 staleUserList << p->getNick();
183 p = DisplayUserNullPtr;
184 it = m_roster.erase(it);
185 }
186 else
187 {
188 if (!m_currentPrefix.startsWith("/private/local") && p->getPrefix().startsWith("/private/local"))
189 {
Yingdi Yua1a688f2014-02-06 18:09:22 -0800190#ifdef _DEBUG
Yingdi Yu42f66462013-10-31 17:38:22 -0700191 std::cout << "erasing: " << p->getPrefix().toStdString() << std::endl;
192#endif
193 staleUserList << p->getNick();
194 p = DisplayUserNullPtr;
195 it = m_roster.erase(it);
196 continue;
197 }
198 ++it;
199 }
200 }
201 else
202 {
203 it = m_roster.erase(it);
204 }
205 }
206
207 // for simpicity here, whenever we replot, we also redo the roster list
208 emit rosterChanged(staleUserList);
209
210 int n = m_roster.size();
211
212 std::vector<TreeLayout::Coordinate> childNodesCo(n);
213
214 layout->setOneLevelLayout(childNodesCo);
215
216 plotEdge(childNodesCo, nodeSize);
217 plotNode(childNodesCo, digest, nodeSize);
218
219 previouslyUpdatedUser = DisplayUserNullPtr;
220
221}
222
223void
224DigestTreeScene::plotEdge(const std::vector<TreeLayout::Coordinate> &childNodesCo, int nodeSize)
225{
226 int n = childNodesCo.size();
227 for (int i = 0; i < n; i++) {
228 double x1 = 0.0, y1 = 0.0;
229 double x2 = childNodesCo[i].x, y2 = childNodesCo[i].y;
230 QPointF src(x1 + nodeSize/2, y1 + nodeSize/2);
231 QPointF dest(x2 + nodeSize/2, y2 + nodeSize/2);
232 QLineF line(src, dest);
233 double angle = ::acos(line.dx() / line.length());
234
235 double arrowSize = 10;
236 QPointF sourceArrowP0 = src + QPointF((nodeSize/2 + 10) * line.dx() / line.length(), (nodeSize/2 +10) * line.dy() / line.length());
237 QPointF sourceArrowP1 = sourceArrowP0 + QPointF(cos(angle + Pi / 3 - Pi/2) * arrowSize,
238 sin(angle + Pi / 3 - Pi/2) * arrowSize);
239 QPointF sourceArrowP2 = sourceArrowP0 + QPointF(cos(angle + Pi - Pi / 3 - Pi/2) * arrowSize,
240 sin(angle + Pi - Pi / 3 - Pi/2) * arrowSize);
241
242 addLine(QLineF(sourceArrowP0, dest), QPen(Qt::black));
243 addPolygon(QPolygonF() << sourceArrowP0<< sourceArrowP1 << sourceArrowP2, QPen(Qt::black), QBrush(Qt::black));
244 }
245}
246
247void
248DigestTreeScene::plotNode(const std::vector<TreeLayout::Coordinate> &childNodesCo, QString digest, int nodeSize)
249{
250 RosterIterator it(m_roster);
251 int n = childNodesCo.size();
252 int rim = 3;
253
254 // plot root node
255 QRectF rootBoundingRect(0, 0, nodeSize, nodeSize);
256 QRectF rootInnerBoundingRect(rim, rim, nodeSize - rim * 2, nodeSize - rim * 2);
257 addRect(rootBoundingRect, QPen(Qt::black), QBrush(Qt::darkRed));
258 addRect(rootInnerBoundingRect, QPen(Qt::black), QBrush(Qt::lightGray));
259 QRectF digestRect(- 5.5 * nodeSize , - nodeSize, 12 * nodeSize, 30);
260 addRect(digestRect, QPen(Qt::darkCyan), QBrush(Qt::darkCyan));
261
262 QGraphicsTextItem *digestItem = addText(digest);
263 QRectF digestBoundingRect = digestItem->boundingRect();
264 digestItem->setDefaultTextColor(Qt::black);
265 digestItem->setFont(QFont("Cursive", 12, QFont::Bold));
266 digestItem->setPos(- 4.5 * nodeSize + (12 * nodeSize - digestBoundingRect.width()) / 2, - nodeSize + 5);
267 m_rootDigest = digestItem;
268
269 // plot child nodes
270 for (int i = 0; i < n; i++)
271 {
272 if (it.hasNext())
273 {
274 it.next();
275 }
276 else
277 {
278 abort();
279 }
280
281 double x = childNodesCo[i].x;
282 double y = childNodesCo[i].y;
283 QRectF boundingRect(x, y, nodeSize, nodeSize);
284 QRectF innerBoundingRect(x + rim, y + rim, nodeSize - rim * 2, nodeSize - rim * 2);
285 DisplayUserPtr p = it.value();
286 QGraphicsRectItem *rectItem = addRect(boundingRect, QPen(Qt::black), QBrush(Qt::darkBlue));
287 p->setRimRectItem(rectItem);
288
289 QGraphicsRectItem *innerRectItem = addRect(innerBoundingRect, QPen(Qt::black), QBrush(Qt::lightGray));
290 p->setInnerRectItem(innerRectItem);
291
292 std::string s = boost::lexical_cast<std::string>(p->getSeqNo().getSeq());
293 QGraphicsTextItem *seqItem = addText(s.c_str());
294 seqItem->setFont(QFont("Cursive", 12, QFont::Bold));
295 QRectF seqBoundingRect = seqItem->boundingRect();
296 seqItem->setPos(x + nodeSize / 2 - seqBoundingRect.width() / 2, y + nodeSize / 2 - seqBoundingRect.height() / 2);
297 p->setSeqTextItem(seqItem);
298
299 QRectF textRect(x - nodeSize / 2, y + nodeSize, 2 * nodeSize, 30);
300 QGraphicsRectItem *nickRectItem = addRect(textRect, QPen(Qt::darkCyan), QBrush(Qt::darkCyan));
301 p->setNickRectItem(nickRectItem);
302 QGraphicsTextItem *nickItem = addText(p->getNick());
303 QRectF textBoundingRect = nickItem->boundingRect();
304 nickItem->setDefaultTextColor(Qt::white);
305 nickItem->setFont(QFont("Cursive", 12, QFont::Bold));
306 nickItem->setPos(x + nodeSize / 2 - textBoundingRect.width() / 2, y + nodeSize + 5);
307 p->setNickTextItem(nickItem);
308 }
309
310}
311
312void
313DigestTreeScene::reDrawNode(DisplayUserPtr p, QColor rimColor)
314{
315 QGraphicsRectItem *rimItem = p->getRimRectItem();
316 rimItem->setBrush(QBrush(rimColor));
317 QGraphicsRectItem *innerItem = p->getInnerRectItem();
318 innerItem->setBrush(QBrush(Qt::lightGray));
319 QGraphicsTextItem *seqTextItem = p->getSeqTextItem();
320 std::string s = boost::lexical_cast<std::string>(p->getSeqNo().getSeq());
321 seqTextItem->setPlainText(s.c_str());
322 QRectF textBR = seqTextItem->boundingRect();
323 QRectF innerBR = innerItem->boundingRect();
324 seqTextItem->setPos(innerBR.x() + (innerBR.width() - textBR.width())/2, innerBR.y() + (innerBR.height() - textBR.height())/2);
325}
326
327#if WAF
328#include "digesttreescene.moc"
329#include "digesttreescene.cpp.moc"
330#endif