blob: 5e474bf19cac84cc1600e83bd87051e7fbc2a5d2 [file] [log] [blame]
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -07001#include "digesttreescene.h"
2
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -07003#include <QtGui>
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -07004
5#ifndef Q_MOC_RUN
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -07006#include <vector>
7#include <iostream>
8#include <assert.h>
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -07009#include <boost/lexical_cast.hpp>
Zhenkai Zhu21d75f92012-06-04 21:23:34 -070010#include <memory>
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -070011#endif
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -070012
13static const double Pi = 3.14159265358979323846264338327950288419717;
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -070014
Zhenkai Zhu7f52e1b2012-10-09 11:45:36 -070015//DisplayUserPtr DisplayUserNullPtr;
Zhenkai Zhud13acd02012-06-04 15:25:20 -070016
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -070017DigestTreeScene::DigestTreeScene(QWidget *parent)
18 : QGraphicsScene(parent)
19{
Zhenkai Zhud13acd02012-06-04 15:25:20 -070020 previouslyUpdatedUser = DisplayUserNullPtr;
Zhenkai Zhu6fcdee42012-05-30 17:02:49 -070021}
22
23void
Zhenkai Zhu82a62752012-06-04 17:11:04 -070024DigestTreeScene::processUpdate(const std::vector<Sync::MissingDataInfo> &v, QString digest)
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -070025{
26 int n = v.size();
27 bool rePlot = false;
28 for (int i = 0; i < n; i++)
29 {
30 Roster_iterator it = m_roster.find(v[i].prefix.c_str());
Zhenkai Zhud1c5a972012-06-05 14:07:41 -070031 if (it == m_roster.end())
32 {
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -070033 rePlot = true;
34 DisplayUserPtr p(new DisplayUser());
Zhenkai Zhuc61dbc22012-10-08 11:36:37 -070035 time_t tempTime = time(NULL) - FRESHNESS + 1;
Zhenkai Zhu86df7412012-09-27 16:30:20 -070036 p->setReceived(tempTime);
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -070037 p->setPrefix(v[i].prefix.c_str());
38 p->setSeq(v[i].high);
39 m_roster.insert(p->getPrefix(), p);
40 }
Zhenkai Zhud1c5a972012-06-05 14:07:41 -070041 else
42 {
43 it.value()->setSeq(v[i].high);
44 }
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -070045 }
46
47 if (rePlot)
48 {
49 plot(digest);
Zhenkai Zhu86df7412012-09-27 16:30:20 -070050 QTimer::singleShot(2100, this, SLOT(emitReplot()));
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -070051 }
52 else
53 {
54 for (int i = 0; i < n; i++)
55 {
56 Roster_iterator it = m_roster.find(v[i].prefix.c_str());
57 if (it != m_roster.end()) {
58 DisplayUserPtr p = it.value();
59 QGraphicsTextItem *item = p->getSeqTextItem();
Zhenkai Zhud13acd02012-06-04 15:25:20 -070060 QGraphicsRectItem *rectItem = p->getInnerRectItem();
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -070061 std::string s = boost::lexical_cast<std::string>(p->getSeqNo().getSeq());
62 item->setPlainText(s.c_str());
Zhenkai Zhud13acd02012-06-04 15:25:20 -070063 QRectF textBR = item->boundingRect();
64 QRectF rectBR = rectItem->boundingRect();
65 item->setPos(rectBR.x() + (rectBR.width() - textBR.width())/2, rectBR.y() + (rectBR.height() - textBR.height())/2);
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -070066 }
67 }
68 m_rootDigest->setPlainText(digest);
69 }
70}
71
72void
Zhenkai Zhu86df7412012-09-27 16:30:20 -070073DigestTreeScene::emitReplot()
74{
75 emit replot();
76}
77
Zhenkai Zhu9036e032012-09-27 20:59:33 -070078QStringList
Zhenkai Zhu6082ede2012-09-27 17:28:46 -070079DigestTreeScene::getRosterList()
80{
Zhenkai Zhu9036e032012-09-27 20:59:33 -070081 QStringList rosterList;
82 RosterIterator it(m_roster);
83 while(it.hasNext())
84 {
85 it.next();
86 DisplayUserPtr p = it.value();
87 if (p != DisplayUserNullPtr)
88 {
89 rosterList << "- " + p->getNick();
90 }
91 }
92 return rosterList;
Zhenkai Zhu6082ede2012-09-27 17:28:46 -070093}
94
95void
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -070096DigestTreeScene::msgReceived(QString prefix, QString nick)
97{
98 Roster_iterator it = m_roster.find(prefix);
99 if (it != m_roster.end())
100 {
Zhenkai Zhu716fe852012-10-08 18:27:55 -0700101 std::cout << "Updating for prefix = " << prefix.toStdString() << " nick = " << nick.toStdString() << std::endl;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700102 DisplayUserPtr p = it.value();
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700103 p->setReceived(time(NULL));
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700104 if (nick != p->getNick()) {
Zhenkai Zhu716fe852012-10-08 18:27:55 -0700105 std::cout << "old nick = " << p->getNick().toStdString() << std::endl;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700106 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 {
Zhenkai Zhu716fe852012-10-08 18:27:55 -0700177 if (!m_currentPrefix.startsWith("/private/local") && p->getPrefix().startsWith("/private/local"))
178 {
179#ifdef __DEBUG
180 std::cout << "erasing: " << p->getPrefix().toStdString() << std::endl;
181#endif
182 staleUserList << p->getNick();
183 p = DisplayUserNullPtr;
184 it = m_roster.erase(it);
185 continue;
186 }
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700187 ++it;
188 }
189 }
190 else
191 {
192 it = m_roster.erase(it);
193 }
194 }
195
Zhenkai Zhu6082ede2012-09-27 17:28:46 -0700196 // for simpicity here, whenever we replot, we also redo the roster list
Zhenkai Zhu25e33e52012-09-28 13:00:07 -0700197 emit rosterChanged(staleUserList);
Zhenkai Zhu6082ede2012-09-27 17:28:46 -0700198
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700199 int n = m_roster.size();
Zhenkai Zhu716fe852012-10-08 18:27:55 -0700200
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700201 std::vector<TreeLayout::Coordinate> childNodesCo(n);
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -0700202
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700203 layout->setOneLevelLayout(childNodesCo);
204
205 plotEdge(childNodesCo, nodeSize);
206 plotNode(childNodesCo, digest, nodeSize);
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700207
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700208 previouslyUpdatedUser = DisplayUserNullPtr;
209
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700210}
211
212void
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700213DigestTreeScene::plotEdge(const std::vector<TreeLayout::Coordinate> &childNodesCo, int nodeSize)
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700214{
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700215 int n = childNodesCo.size();
216 for (int i = 0; i < n; i++) {
217 double x1 = 0.0, y1 = 0.0;
218 double x2 = childNodesCo[i].x, y2 = childNodesCo[i].y;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700219 QPointF src(x1 + nodeSize/2, y1 + nodeSize/2);
220 QPointF dest(x2 + nodeSize/2, y2 + nodeSize/2);
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -0700221 QLineF line(src, dest);
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -0700222 double angle = ::acos(line.dx() / line.length());
223
224 double arrowSize = 10;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700225 QPointF sourceArrowP0 = src + QPointF((nodeSize/2 + 10) * line.dx() / line.length(), (nodeSize/2 +10) * line.dy() / line.length());
226 QPointF sourceArrowP1 = sourceArrowP0 + QPointF(cos(angle + Pi / 3 - Pi/2) * arrowSize,
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -0700227 sin(angle + Pi / 3 - Pi/2) * arrowSize);
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700228 QPointF sourceArrowP2 = sourceArrowP0 + QPointF(cos(angle + Pi - Pi / 3 - Pi/2) * arrowSize,
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -0700229 sin(angle + Pi - Pi / 3 - Pi/2) * arrowSize);
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -0700230
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700231 addLine(QLineF(sourceArrowP0, dest), QPen(Qt::black));
232 addPolygon(QPolygonF() << sourceArrowP0<< sourceArrowP1 << sourceArrowP2, QPen(Qt::black), QBrush(Qt::black));
233 }
234}
235
236void
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700237DigestTreeScene::plotNode(const std::vector<TreeLayout::Coordinate> &childNodesCo, QString digest, int nodeSize)
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700238{
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700239 RosterIterator it(m_roster);
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700240 int n = childNodesCo.size();
241 int rim = 3;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700242
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700243 // plot root node
244 QRectF rootBoundingRect(0, 0, nodeSize, nodeSize);
245 QRectF rootInnerBoundingRect(rim, rim, nodeSize - rim * 2, nodeSize - rim * 2);
246 addRect(rootBoundingRect, QPen(Qt::black), QBrush(Qt::darkRed));
247 addRect(rootInnerBoundingRect, QPen(Qt::black), QBrush(Qt::lightGray));
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700248 QRectF digestRect(- 5.5 * nodeSize , - nodeSize, 12 * nodeSize, 30);
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700249 addRect(digestRect, QPen(Qt::darkCyan), QBrush(Qt::darkCyan));
Zhenkai Zhu27df8d42012-06-05 12:04:04 -0700250
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700251 QGraphicsTextItem *digestItem = addText(digest);
252 QRectF digestBoundingRect = digestItem->boundingRect();
Zhenkai Zhu27df8d42012-06-05 12:04:04 -0700253 digestItem->setDefaultTextColor(Qt::black);
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700254 digestItem->setFont(QFont("Cursive", 12, QFont::Bold));
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700255 digestItem->setPos(- 4.5 * nodeSize + (12 * nodeSize - digestBoundingRect.width()) / 2, - nodeSize + 5);
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700256 m_rootDigest = digestItem;
257
258 // plot child nodes
259 for (int i = 0; i < n; i++)
260 {
261 if (it.hasNext())
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700262 {
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700263 it.next();
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700264 }
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700265 else
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700266 {
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700267 abort();
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700268 }
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700269
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700270 double x = childNodesCo[i].x;
271 double y = childNodesCo[i].y;
272 QRectF boundingRect(x, y, nodeSize, nodeSize);
273 QRectF innerBoundingRect(x + rim, y + rim, nodeSize - rim * 2, nodeSize - rim * 2);
274 DisplayUserPtr p = it.value();
275 QGraphicsRectItem *rectItem = addRect(boundingRect, QPen(Qt::black), QBrush(Qt::darkBlue));
276 p->setRimRectItem(rectItem);
277
278 QGraphicsRectItem *innerRectItem = addRect(innerBoundingRect, QPen(Qt::black), QBrush(Qt::lightGray));
279 p->setInnerRectItem(innerRectItem);
280
281 std::string s = boost::lexical_cast<std::string>(p->getSeqNo().getSeq());
282 QGraphicsTextItem *seqItem = addText(s.c_str());
283 seqItem->setFont(QFont("Cursive", 12, QFont::Bold));
284 QRectF seqBoundingRect = seqItem->boundingRect();
285 seqItem->setPos(x + nodeSize / 2 - seqBoundingRect.width() / 2, y + nodeSize / 2 - seqBoundingRect.height() / 2);
286 p->setSeqTextItem(seqItem);
287
288 QRectF textRect(x - nodeSize / 2, y + nodeSize, 2 * nodeSize, 30);
289 QGraphicsRectItem *nickRectItem = addRect(textRect, QPen(Qt::darkCyan), QBrush(Qt::darkCyan));
290 p->setNickRectItem(nickRectItem);
291 QGraphicsTextItem *nickItem = addText(p->getNick());
292 QRectF textBoundingRect = nickItem->boundingRect();
293 nickItem->setDefaultTextColor(Qt::white);
294 nickItem->setFont(QFont("Cursive", 12, QFont::Bold));
295 nickItem->setPos(x + nodeSize / 2 - textBoundingRect.width() / 2, y + nodeSize + 5);
296 p->setNickTextItem(nickItem);
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -0700297 }
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700298
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -0700299}
300
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700301void
302DigestTreeScene::reDrawNode(DisplayUserPtr p, QColor rimColor)
303{
304 QGraphicsRectItem *rimItem = p->getRimRectItem();
305 rimItem->setBrush(QBrush(rimColor));
306 QGraphicsRectItem *innerItem = p->getInnerRectItem();
307 innerItem->setBrush(QBrush(Qt::lightGray));
308 QGraphicsTextItem *seqTextItem = p->getSeqTextItem();
309 std::string s = boost::lexical_cast<std::string>(p->getSeqNo().getSeq());
310 seqTextItem->setPlainText(s.c_str());
311 QRectF textBR = seqTextItem->boundingRect();
312 QRectF innerBR = innerItem->boundingRect();
313 seqTextItem->setPos(innerBR.x() + (innerBR.width() - textBR.width())/2, innerBR.y() + (innerBR.height() - textBR.height())/2);
314}
315