blob: 5364f0ffce385364cdf7094b1e33065f9637dd32 [file] [log] [blame]
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -07001#include <QtGui>
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -07002#include <vector>
3#include <iostream>
4#include <assert.h>
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -07005#include <boost/lexical_cast.hpp>
Zhenkai Zhu21d75f92012-06-04 21:23:34 -07006#include <memory>
7#include "digesttreescene.h"
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -07008
9static const double Pi = 3.14159265358979323846264338327950288419717;
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -070010
Zhenkai Zhud13acd02012-06-04 15:25:20 -070011DigestTreeScene::DisplayUserPtr DigestTreeScene::DisplayUserNullPtr;
12
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -070013DigestTreeScene::DigestTreeScene(QWidget *parent)
14 : QGraphicsScene(parent)
15{
Zhenkai Zhud13acd02012-06-04 15:25:20 -070016 previouslyUpdatedUser = DisplayUserNullPtr;
Zhenkai Zhu6fcdee42012-05-30 17:02:49 -070017}
18
19void
Zhenkai Zhu82a62752012-06-04 17:11:04 -070020DigestTreeScene::processUpdate(const std::vector<Sync::MissingDataInfo> &v, QString digest)
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -070021{
22 int n = v.size();
23 bool rePlot = false;
24 for (int i = 0; i < n; i++)
25 {
26 Roster_iterator it = m_roster.find(v[i].prefix.c_str());
Zhenkai Zhud1c5a972012-06-05 14:07:41 -070027 if (it == m_roster.end())
28 {
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -070029 rePlot = true;
30 DisplayUserPtr p(new DisplayUser());
Zhenkai Zhu86df7412012-09-27 16:30:20 -070031 time_t tempTime = time(NULL) - 2 * FRESHNESS + 1;
32 p->setReceived(tempTime);
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -070033 p->setPrefix(v[i].prefix.c_str());
34 p->setSeq(v[i].high);
35 m_roster.insert(p->getPrefix(), p);
36 }
Zhenkai Zhud1c5a972012-06-05 14:07:41 -070037 else
38 {
39 it.value()->setSeq(v[i].high);
40 }
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -070041 }
42
43 if (rePlot)
44 {
45 plot(digest);
Zhenkai Zhu86df7412012-09-27 16:30:20 -070046 QTimer::singleShot(2100, this, SLOT(emitReplot()));
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -070047 }
48 else
49 {
50 for (int i = 0; i < n; i++)
51 {
52 Roster_iterator it = m_roster.find(v[i].prefix.c_str());
53 if (it != m_roster.end()) {
54 DisplayUserPtr p = it.value();
55 QGraphicsTextItem *item = p->getSeqTextItem();
Zhenkai Zhud13acd02012-06-04 15:25:20 -070056 QGraphicsRectItem *rectItem = p->getInnerRectItem();
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -070057 std::string s = boost::lexical_cast<std::string>(p->getSeqNo().getSeq());
58 item->setPlainText(s.c_str());
Zhenkai Zhud13acd02012-06-04 15:25:20 -070059 QRectF textBR = item->boundingRect();
60 QRectF rectBR = rectItem->boundingRect();
61 item->setPos(rectBR.x() + (rectBR.width() - textBR.width())/2, rectBR.y() + (rectBR.height() - textBR.height())/2);
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -070062 }
63 }
64 m_rootDigest->setPlainText(digest);
65 }
66}
67
68void
Zhenkai Zhu86df7412012-09-27 16:30:20 -070069DigestTreeScene::emitReplot()
70{
71 emit replot();
72}
73
Zhenkai Zhu9036e032012-09-27 20:59:33 -070074QStringList
Zhenkai Zhu6082ede2012-09-27 17:28:46 -070075DigestTreeScene::getRosterList()
76{
Zhenkai Zhu9036e032012-09-27 20:59:33 -070077 QStringList rosterList;
78 RosterIterator it(m_roster);
79 while(it.hasNext())
80 {
81 it.next();
82 DisplayUserPtr p = it.value();
83 if (p != DisplayUserNullPtr)
84 {
85 rosterList << "- " + p->getNick();
86 }
87 }
88 return rosterList;
Zhenkai Zhu6082ede2012-09-27 17:28:46 -070089}
90
91void
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -070092DigestTreeScene::msgReceived(QString prefix, QString nick)
93{
Zhenkai Zhu097bfe72012-06-05 14:30:17 -070094#ifdef __DEBUG
95 std::cout << "Finding " << prefix.toStdString() << std::endl;
96#endif
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -070097 Roster_iterator it = m_roster.find(prefix);
98 if (it != m_roster.end())
99 {
100 DisplayUserPtr p = it.value();
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700101 p->setReceived(time(NULL));
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700102 if (nick != p->getNick()) {
103 p->setNick(nick);
104 QGraphicsTextItem *nickItem = p->getNickTextItem();
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700105 QGraphicsRectItem *nickRectItem = p->getNickRectItem();
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700106 nickItem->setPlainText(p->getNick());
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700107 QRectF rectBR = nickRectItem->boundingRect();
108 QRectF nickBR = nickItem->boundingRect();
109 nickItem->setPos(rectBR.x() + (rectBR.width() - nickBR.width())/2, rectBR.y() + 5);
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700110 emit rosterChanged();
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700111 }
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700112
113 reDrawNode(p, Qt::red);
114
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700115 if (previouslyUpdatedUser != DisplayUserNullPtr && previouslyUpdatedUser != p)
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700116 {
117 reDrawNode(previouslyUpdatedUser, Qt::darkBlue);
118 }
119
120 previouslyUpdatedUser = p;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700121 }
Zhenkai Zhu097bfe72012-06-05 14:30:17 -0700122#ifdef __DEBUG
123 else
124 {
Zhenkai Zhu59245aa2012-09-26 16:07:04 -0700125 std::cout << "Couldn't find prefix, " << prefix.toStdString() << ": let's check"<< std::endl;
Zhenkai Zhu097bfe72012-06-05 14:30:17 -0700126 Roster_iterator ii = m_roster.begin();
127 while (ii != m_roster.end())
128 {
129 std::cout <<"Prefix: " << ii.key().toStdString() << std::endl;
130 ++ii;
131 }
132 }
133#endif
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700134}
135
136void
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700137DigestTreeScene::clearAll()
138{
139 clear();
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700140 m_roster.clear();
141}
142
Zhenkai Zhu591e8c32012-09-26 11:57:50 -0700143bool
144DigestTreeScene::removeNode(const QString prefix)
145{
146 int removedCount = m_roster.remove(prefix);
147 return (removedCount > 0);
148}
149
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700150void
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700151DigestTreeScene::plot(QString digest)
152{
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700153#ifdef __DEBUG
154 std::cout << "Plotting at time: " << time(NULL) << std::endl;
155#endif
Zhenkai Zhu6fcdee42012-05-30 17:02:49 -0700156 clear();
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700157
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700158 int nodeSize = 40;
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700159
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700160 int siblingDistance = 100, levelDistance = 100;
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700161 std::auto_ptr<TreeLayout> layout(new OneLevelTreeLayout());
162 layout->setSiblingDistance(siblingDistance);
163 layout->setLevelDistance(levelDistance);
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -0700164
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700165 // do some cleaning, get rid of stale member info
166 Roster_iterator it = m_roster.begin();
167 while (it != m_roster.end())
168 {
169 DisplayUserPtr p = it.value();
170 if (p != DisplayUserNullPtr)
171 {
172 time_t now = time(NULL);
173 if (now - p->getReceived() >= FRESHNESS * 2)
174 {
175#ifdef __DEBUG
176 std::cout << "Removing user: " << p->getNick().toStdString() << std::endl;
177 std::cout << "now - last = " << now - p->getReceived() << std::endl;
178#endif
179 p = DisplayUserNullPtr;
180 it = m_roster.erase(it);
181 }
182 else
183 {
184 ++it;
185 }
186 }
187 else
188 {
189 it = m_roster.erase(it);
190 }
191 }
192
Zhenkai Zhu6082ede2012-09-27 17:28:46 -0700193 // for simpicity here, whenever we replot, we also redo the roster list
194 emit rosterChanged();
195
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700196 int n = m_roster.size();
197 std::vector<TreeLayout::Coordinate> childNodesCo(n);
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -0700198
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700199 layout->setOneLevelLayout(childNodesCo);
200
201 plotEdge(childNodesCo, nodeSize);
202 plotNode(childNodesCo, digest, nodeSize);
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700203
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700204 previouslyUpdatedUser = DisplayUserNullPtr;
205
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700206}
207
208void
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700209DigestTreeScene::plotEdge(const std::vector<TreeLayout::Coordinate> &childNodesCo, int nodeSize)
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700210{
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700211 int n = childNodesCo.size();
212 for (int i = 0; i < n; i++) {
213 double x1 = 0.0, y1 = 0.0;
214 double x2 = childNodesCo[i].x, y2 = childNodesCo[i].y;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700215 QPointF src(x1 + nodeSize/2, y1 + nodeSize/2);
216 QPointF dest(x2 + nodeSize/2, y2 + nodeSize/2);
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -0700217 QLineF line(src, dest);
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -0700218 double angle = ::acos(line.dx() / line.length());
219
220 double arrowSize = 10;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700221 QPointF sourceArrowP0 = src + QPointF((nodeSize/2 + 10) * line.dx() / line.length(), (nodeSize/2 +10) * line.dy() / line.length());
222 QPointF sourceArrowP1 = sourceArrowP0 + QPointF(cos(angle + Pi / 3 - Pi/2) * arrowSize,
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -0700223 sin(angle + Pi / 3 - Pi/2) * arrowSize);
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700224 QPointF sourceArrowP2 = sourceArrowP0 + QPointF(cos(angle + Pi - Pi / 3 - Pi/2) * arrowSize,
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -0700225 sin(angle + Pi - Pi / 3 - Pi/2) * arrowSize);
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -0700226
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700227 addLine(QLineF(sourceArrowP0, dest), QPen(Qt::black));
228 addPolygon(QPolygonF() << sourceArrowP0<< sourceArrowP1 << sourceArrowP2, QPen(Qt::black), QBrush(Qt::black));
229 }
230}
231
232void
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700233DigestTreeScene::plotNode(const std::vector<TreeLayout::Coordinate> &childNodesCo, QString digest, int nodeSize)
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700234{
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700235 RosterIterator it(m_roster);
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700236 int n = childNodesCo.size();
237 int rim = 3;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700238
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700239 // plot root node
240 QRectF rootBoundingRect(0, 0, nodeSize, nodeSize);
241 QRectF rootInnerBoundingRect(rim, rim, nodeSize - rim * 2, nodeSize - rim * 2);
242 addRect(rootBoundingRect, QPen(Qt::black), QBrush(Qt::darkRed));
243 addRect(rootInnerBoundingRect, QPen(Qt::black), QBrush(Qt::lightGray));
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700244 QRectF digestRect(- 5.5 * nodeSize , - nodeSize, 12 * nodeSize, 30);
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700245 addRect(digestRect, QPen(Qt::darkCyan), QBrush(Qt::darkCyan));
Zhenkai Zhu27df8d42012-06-05 12:04:04 -0700246
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700247 QGraphicsTextItem *digestItem = addText(digest);
248 QRectF digestBoundingRect = digestItem->boundingRect();
Zhenkai Zhu27df8d42012-06-05 12:04:04 -0700249 digestItem->setDefaultTextColor(Qt::black);
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700250 digestItem->setFont(QFont("Cursive", 12, QFont::Bold));
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700251 digestItem->setPos(- 4.5 * nodeSize + (12 * nodeSize - digestBoundingRect.width()) / 2, - nodeSize + 5);
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700252 m_rootDigest = digestItem;
253
254 // plot child nodes
255 for (int i = 0; i < n; i++)
256 {
257 if (it.hasNext())
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700258 {
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700259 it.next();
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700260 }
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700261 else
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700262 {
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700263 abort();
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700264 }
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700265
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700266 double x = childNodesCo[i].x;
267 double y = childNodesCo[i].y;
268 QRectF boundingRect(x, y, nodeSize, nodeSize);
269 QRectF innerBoundingRect(x + rim, y + rim, nodeSize - rim * 2, nodeSize - rim * 2);
270 DisplayUserPtr p = it.value();
271 QGraphicsRectItem *rectItem = addRect(boundingRect, QPen(Qt::black), QBrush(Qt::darkBlue));
272 p->setRimRectItem(rectItem);
273
274 QGraphicsRectItem *innerRectItem = addRect(innerBoundingRect, QPen(Qt::black), QBrush(Qt::lightGray));
275 p->setInnerRectItem(innerRectItem);
276
277 std::string s = boost::lexical_cast<std::string>(p->getSeqNo().getSeq());
278 QGraphicsTextItem *seqItem = addText(s.c_str());
279 seqItem->setFont(QFont("Cursive", 12, QFont::Bold));
280 QRectF seqBoundingRect = seqItem->boundingRect();
281 seqItem->setPos(x + nodeSize / 2 - seqBoundingRect.width() / 2, y + nodeSize / 2 - seqBoundingRect.height() / 2);
282 p->setSeqTextItem(seqItem);
283
284 QRectF textRect(x - nodeSize / 2, y + nodeSize, 2 * nodeSize, 30);
285 QGraphicsRectItem *nickRectItem = addRect(textRect, QPen(Qt::darkCyan), QBrush(Qt::darkCyan));
286 p->setNickRectItem(nickRectItem);
287 QGraphicsTextItem *nickItem = addText(p->getNick());
288 QRectF textBoundingRect = nickItem->boundingRect();
289 nickItem->setDefaultTextColor(Qt::white);
290 nickItem->setFont(QFont("Cursive", 12, QFont::Bold));
291 nickItem->setPos(x + nodeSize / 2 - textBoundingRect.width() / 2, y + nodeSize + 5);
292 p->setNickTextItem(nickItem);
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -0700293 }
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700294
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -0700295}
296
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700297void
298DigestTreeScene::reDrawNode(DisplayUserPtr p, QColor rimColor)
299{
300 QGraphicsRectItem *rimItem = p->getRimRectItem();
301 rimItem->setBrush(QBrush(rimColor));
302 QGraphicsRectItem *innerItem = p->getInnerRectItem();
303 innerItem->setBrush(QBrush(Qt::lightGray));
304 QGraphicsTextItem *seqTextItem = p->getSeqTextItem();
305 std::string s = boost::lexical_cast<std::string>(p->getSeqNo().getSeq());
306 seqTextItem->setPlainText(s.c_str());
307 QRectF textBR = seqTextItem->boundingRect();
308 QRectF innerBR = innerItem->boundingRect();
309 seqTextItem->setPos(innerBR.x() + (innerBR.width() - textBR.width())/2, innerBR.y() + (innerBR.height() - textBR.height())/2);
310}
311