blob: 403610e18f19ba7bacf2b5c569fdc76841e2e45d [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 Zhuc61dbc22012-10-08 11:36:37 -070031 time_t tempTime = time(NULL) - FRESHNESS + 1;
Zhenkai Zhu86df7412012-09-27 16:30:20 -070032 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);
Zhenkai Zhuba707342012-10-08 16:20:15 -070036#ifdef __DEBUG
37 std::cout << "<<<<<<< Adding user. Prefix = " << p->getPrefix().toStdString() << std::endl;
38#endif
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -070039 }
Zhenkai Zhud1c5a972012-06-05 14:07:41 -070040 else
41 {
42 it.value()->setSeq(v[i].high);
43 }
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -070044 }
45
46 if (rePlot)
47 {
48 plot(digest);
Zhenkai Zhu86df7412012-09-27 16:30:20 -070049 QTimer::singleShot(2100, this, SLOT(emitReplot()));
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -070050 }
51 else
52 {
53 for (int i = 0; i < n; i++)
54 {
55 Roster_iterator it = m_roster.find(v[i].prefix.c_str());
56 if (it != m_roster.end()) {
57 DisplayUserPtr p = it.value();
58 QGraphicsTextItem *item = p->getSeqTextItem();
Zhenkai Zhud13acd02012-06-04 15:25:20 -070059 QGraphicsRectItem *rectItem = p->getInnerRectItem();
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -070060 std::string s = boost::lexical_cast<std::string>(p->getSeqNo().getSeq());
61 item->setPlainText(s.c_str());
Zhenkai Zhud13acd02012-06-04 15:25:20 -070062 QRectF textBR = item->boundingRect();
63 QRectF rectBR = rectItem->boundingRect();
64 item->setPos(rectBR.x() + (rectBR.width() - textBR.width())/2, rectBR.y() + (rectBR.height() - textBR.height())/2);
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -070065 }
66 }
67 m_rootDigest->setPlainText(digest);
68 }
69}
70
71void
Zhenkai Zhu86df7412012-09-27 16:30:20 -070072DigestTreeScene::emitReplot()
73{
74 emit replot();
75}
76
Zhenkai Zhu9036e032012-09-27 20:59:33 -070077QStringList
Zhenkai Zhu6082ede2012-09-27 17:28:46 -070078DigestTreeScene::getRosterList()
79{
Zhenkai Zhu9036e032012-09-27 20:59:33 -070080 QStringList rosterList;
81 RosterIterator it(m_roster);
82 while(it.hasNext())
83 {
84 it.next();
85 DisplayUserPtr p = it.value();
86 if (p != DisplayUserNullPtr)
87 {
88 rosterList << "- " + p->getNick();
89 }
90 }
91 return rosterList;
Zhenkai Zhu6082ede2012-09-27 17:28:46 -070092}
93
94void
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -070095DigestTreeScene::msgReceived(QString prefix, QString nick)
96{
Zhenkai Zhuba707342012-10-08 16:20:15 -070097#ifdef __DEBUG
98 std::cout << "<<<<<<< MsgReceived. Prefix = " << prefix.toStdString() << ". Nick = " << nick.toStdString() << std::endl;
99#endif
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700100 Roster_iterator it = m_roster.find(prefix);
101 if (it != m_roster.end())
102 {
103 DisplayUserPtr p = it.value();
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700104 p->setReceived(time(NULL));
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700105 if (nick != p->getNick()) {
106 p->setNick(nick);
107 QGraphicsTextItem *nickItem = p->getNickTextItem();
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700108 QGraphicsRectItem *nickRectItem = p->getNickRectItem();
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700109 nickItem->setPlainText(p->getNick());
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700110 QRectF rectBR = nickRectItem->boundingRect();
111 QRectF nickBR = nickItem->boundingRect();
112 nickItem->setPos(rectBR.x() + (rectBR.width() - nickBR.width())/2, rectBR.y() + 5);
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700113 emit rosterChanged(QStringList());
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700114 }
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700115
116 reDrawNode(p, Qt::red);
117
Zhenkai Zhud1c5a972012-06-05 14:07:41 -0700118 if (previouslyUpdatedUser != DisplayUserNullPtr && previouslyUpdatedUser != p)
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700119 {
120 reDrawNode(previouslyUpdatedUser, Qt::darkBlue);
121 }
122
123 previouslyUpdatedUser = p;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700124 }
125}
126
127void
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700128DigestTreeScene::clearAll()
129{
130 clear();
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700131 m_roster.clear();
132}
133
Zhenkai Zhu591e8c32012-09-26 11:57:50 -0700134bool
135DigestTreeScene::removeNode(const QString prefix)
136{
137 int removedCount = m_roster.remove(prefix);
138 return (removedCount > 0);
139}
140
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700141void
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700142DigestTreeScene::plot(QString digest)
143{
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700144#ifdef __DEBUG
145 std::cout << "Plotting at time: " << time(NULL) << std::endl;
146#endif
Zhenkai Zhu6fcdee42012-05-30 17:02:49 -0700147 clear();
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700148
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700149 int nodeSize = 40;
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700150
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700151 int siblingDistance = 100, levelDistance = 100;
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700152 std::auto_ptr<TreeLayout> layout(new OneLevelTreeLayout());
153 layout->setSiblingDistance(siblingDistance);
154 layout->setLevelDistance(levelDistance);
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -0700155
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700156 // do some cleaning, get rid of stale member info
157 Roster_iterator it = m_roster.begin();
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700158 QStringList staleUserList;
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700159 while (it != m_roster.end())
160 {
161 DisplayUserPtr p = it.value();
162 if (p != DisplayUserNullPtr)
163 {
164 time_t now = time(NULL);
Zhenkai Zhuc61dbc22012-10-08 11:36:37 -0700165 if (now - p->getReceived() >= FRESHNESS)
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700166 {
167#ifdef __DEBUG
168 std::cout << "Removing user: " << p->getNick().toStdString() << std::endl;
169 std::cout << "now - last = " << now - p->getReceived() << std::endl;
170#endif
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700171 staleUserList << p->getNick();
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700172 p = DisplayUserNullPtr;
173 it = m_roster.erase(it);
174 }
175 else
176 {
177 ++it;
178 }
179 }
180 else
181 {
182 it = m_roster.erase(it);
183 }
184 }
185
Zhenkai Zhu6082ede2012-09-27 17:28:46 -0700186 // for simpicity here, whenever we replot, we also redo the roster list
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700187 emit rosterChanged(staleUserList);
Zhenkai Zhu6082ede2012-09-27 17:28:46 -0700188
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700189 int n = m_roster.size();
190 std::vector<TreeLayout::Coordinate> childNodesCo(n);
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -0700191
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700192 layout->setOneLevelLayout(childNodesCo);
193
194 plotEdge(childNodesCo, nodeSize);
195 plotNode(childNodesCo, digest, nodeSize);
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700196
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700197 previouslyUpdatedUser = DisplayUserNullPtr;
198
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700199}
200
201void
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700202DigestTreeScene::plotEdge(const std::vector<TreeLayout::Coordinate> &childNodesCo, int nodeSize)
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700203{
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700204 int n = childNodesCo.size();
205 for (int i = 0; i < n; i++) {
206 double x1 = 0.0, y1 = 0.0;
207 double x2 = childNodesCo[i].x, y2 = childNodesCo[i].y;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700208 QPointF src(x1 + nodeSize/2, y1 + nodeSize/2);
209 QPointF dest(x2 + nodeSize/2, y2 + nodeSize/2);
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -0700210 QLineF line(src, dest);
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -0700211 double angle = ::acos(line.dx() / line.length());
212
213 double arrowSize = 10;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700214 QPointF sourceArrowP0 = src + QPointF((nodeSize/2 + 10) * line.dx() / line.length(), (nodeSize/2 +10) * line.dy() / line.length());
215 QPointF sourceArrowP1 = sourceArrowP0 + QPointF(cos(angle + Pi / 3 - Pi/2) * arrowSize,
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -0700216 sin(angle + Pi / 3 - Pi/2) * arrowSize);
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700217 QPointF sourceArrowP2 = sourceArrowP0 + QPointF(cos(angle + Pi - Pi / 3 - Pi/2) * arrowSize,
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -0700218 sin(angle + Pi - Pi / 3 - Pi/2) * arrowSize);
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -0700219
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700220 addLine(QLineF(sourceArrowP0, dest), QPen(Qt::black));
221 addPolygon(QPolygonF() << sourceArrowP0<< sourceArrowP1 << sourceArrowP2, QPen(Qt::black), QBrush(Qt::black));
222 }
223}
224
225void
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700226DigestTreeScene::plotNode(const std::vector<TreeLayout::Coordinate> &childNodesCo, QString digest, int nodeSize)
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700227{
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700228 RosterIterator it(m_roster);
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700229 int n = childNodesCo.size();
230 int rim = 3;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700231
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700232 // plot root node
233 QRectF rootBoundingRect(0, 0, nodeSize, nodeSize);
234 QRectF rootInnerBoundingRect(rim, rim, nodeSize - rim * 2, nodeSize - rim * 2);
235 addRect(rootBoundingRect, QPen(Qt::black), QBrush(Qt::darkRed));
236 addRect(rootInnerBoundingRect, QPen(Qt::black), QBrush(Qt::lightGray));
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700237 QRectF digestRect(- 5.5 * nodeSize , - nodeSize, 12 * nodeSize, 30);
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700238 addRect(digestRect, QPen(Qt::darkCyan), QBrush(Qt::darkCyan));
Zhenkai Zhu27df8d42012-06-05 12:04:04 -0700239
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700240 QGraphicsTextItem *digestItem = addText(digest);
241 QRectF digestBoundingRect = digestItem->boundingRect();
Zhenkai Zhu27df8d42012-06-05 12:04:04 -0700242 digestItem->setDefaultTextColor(Qt::black);
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700243 digestItem->setFont(QFont("Cursive", 12, QFont::Bold));
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700244 digestItem->setPos(- 4.5 * nodeSize + (12 * nodeSize - digestBoundingRect.width()) / 2, - nodeSize + 5);
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700245 m_rootDigest = digestItem;
246
247 // plot child nodes
248 for (int i = 0; i < n; i++)
249 {
250 if (it.hasNext())
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700251 {
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700252 it.next();
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700253 }
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700254 else
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700255 {
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700256 abort();
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700257 }
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700258
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700259 double x = childNodesCo[i].x;
260 double y = childNodesCo[i].y;
261 QRectF boundingRect(x, y, nodeSize, nodeSize);
262 QRectF innerBoundingRect(x + rim, y + rim, nodeSize - rim * 2, nodeSize - rim * 2);
263 DisplayUserPtr p = it.value();
264 QGraphicsRectItem *rectItem = addRect(boundingRect, QPen(Qt::black), QBrush(Qt::darkBlue));
265 p->setRimRectItem(rectItem);
266
267 QGraphicsRectItem *innerRectItem = addRect(innerBoundingRect, QPen(Qt::black), QBrush(Qt::lightGray));
268 p->setInnerRectItem(innerRectItem);
269
270 std::string s = boost::lexical_cast<std::string>(p->getSeqNo().getSeq());
271 QGraphicsTextItem *seqItem = addText(s.c_str());
272 seqItem->setFont(QFont("Cursive", 12, QFont::Bold));
273 QRectF seqBoundingRect = seqItem->boundingRect();
274 seqItem->setPos(x + nodeSize / 2 - seqBoundingRect.width() / 2, y + nodeSize / 2 - seqBoundingRect.height() / 2);
275 p->setSeqTextItem(seqItem);
276
277 QRectF textRect(x - nodeSize / 2, y + nodeSize, 2 * nodeSize, 30);
278 QGraphicsRectItem *nickRectItem = addRect(textRect, QPen(Qt::darkCyan), QBrush(Qt::darkCyan));
279 p->setNickRectItem(nickRectItem);
280 QGraphicsTextItem *nickItem = addText(p->getNick());
281 QRectF textBoundingRect = nickItem->boundingRect();
282 nickItem->setDefaultTextColor(Qt::white);
283 nickItem->setFont(QFont("Cursive", 12, QFont::Bold));
284 nickItem->setPos(x + nodeSize / 2 - textBoundingRect.width() / 2, y + nodeSize + 5);
285 p->setNickTextItem(nickItem);
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -0700286 }
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700287
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -0700288}
289
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700290void
291DigestTreeScene::reDrawNode(DisplayUserPtr p, QColor rimColor)
292{
293 QGraphicsRectItem *rimItem = p->getRimRectItem();
294 rimItem->setBrush(QBrush(rimColor));
295 QGraphicsRectItem *innerItem = p->getInnerRectItem();
296 innerItem->setBrush(QBrush(Qt::lightGray));
297 QGraphicsTextItem *seqTextItem = p->getSeqTextItem();
298 std::string s = boost::lexical_cast<std::string>(p->getSeqNo().getSeq());
299 seqTextItem->setPlainText(s.c_str());
300 QRectF textBR = seqTextItem->boundingRect();
301 QRectF innerBR = innerItem->boundingRect();
302 seqTextItem->setPos(innerBR.x() + (innerBR.width() - textBR.width())/2, innerBR.y() + (innerBR.height() - textBR.height())/2);
303}
304