blob: 17bc67abd2665d649cf46e783b7f985a3362f0d9 [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 Yu0b0a7362014-08-05 16:31:30 -070012#include "digest-tree-scene.hpp"
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
Yingdi Yueb692ac2015-02-10 18:46:18 -080024namespace chronochat {
Yingdi Yu0b0a7362014-08-05 16:31:30 -070025
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -070026static const double Pi = 3.14159265358979323846264338327950288419717;
Yingdi Yud45777b2014-10-16 23:54:11 -070027static const int NODE_SIZE = 40;
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -070028
Zhenkai Zhu7f52e1b2012-10-09 11:45:36 -070029//DisplayUserPtr DisplayUserNullPtr;
Zhenkai Zhud13acd02012-06-04 15:25:20 -070030
Yingdi Yu348f5ea2014-03-01 14:47:25 -080031DigestTreeScene::DigestTreeScene(QWidget *parent)
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -070032 : QGraphicsScene(parent)
33{
Yingdi Yud45777b2014-10-16 23:54:11 -070034 m_previouslyUpdatedUser = DisplayUserNullPtr;
Zhenkai Zhu6fcdee42012-05-30 17:02:49 -070035}
36
37void
Yingdi Yueb692ac2015-02-10 18:46:18 -080038DigestTreeScene::processSyncUpdate(const std::vector<chronochat::NodeInfo>& nodeInfos,
Yingdi Yud45777b2014-10-16 23:54:11 -070039 const QString& digest)
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -070040{
Yingdi Yud45777b2014-10-16 23:54:11 -070041 m_rootDigest = digest;
Qiuhan Ding7a4e7ef2015-02-03 20:25:50 -080042}
Yingdi Yu5a5ff202014-03-17 10:03:02 -070043
Qiuhan Ding7a4e7ef2015-02-03 20:25:50 -080044void
45DigestTreeScene::updateNode(QString sessionPrefix, QString nick, uint64_t seqNo)
46{
47 Roster_iterator it = m_roster.find(sessionPrefix);
48 if (it == m_roster.end()) {
49 DisplayUserPtr p(new DisplayUser());
50 p->setPrefix(sessionPrefix);
51 p->setSeq(seqNo);
52 m_roster.insert(p->getPrefix(), p);
Yingdi Yud45777b2014-10-16 23:54:11 -070053 plot(m_rootDigest);
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -070054 }
Qiuhan Ding7a4e7ef2015-02-03 20:25:50 -080055 else {
56 it.value()->setSeq(seqNo);
57 DisplayUserPtr p = it.value();
58 QGraphicsTextItem *item = p->getSeqTextItem();
59 QGraphicsRectItem *rectItem = p->getInnerRectItem();
60 std::string s = boost::lexical_cast<std::string>(p->getSeqNo());
61 item->setPlainText(s.c_str());
62 QRectF textBR = item->boundingRect();
63 QRectF rectBR = rectItem->boundingRect();
64 item->setPos(rectBR.x() + (rectBR.width() - textBR.width())/2,
65 rectBR.y() + (rectBR.height() - textBR.height())/2);
66 }
67 m_displayRootDigest->setPlainText(m_rootDigest);
68 updateNick(sessionPrefix, nick);
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -070069}
70
71void
Yingdi Yud45777b2014-10-16 23:54:11 -070072DigestTreeScene::updateNick(QString sessionPrefix, QString nick)
Zhenkai Zhu86df7412012-09-27 16:30:20 -070073{
Yingdi Yud45777b2014-10-16 23:54:11 -070074 Roster_iterator it = m_roster.find(sessionPrefix);
75 if (it != m_roster.end()) {
76 DisplayUserPtr p = it.value();
77 if (nick != p->getNick()) {
78 p->setNick(nick);
79 QGraphicsTextItem *nickItem = p->getNickTextItem();
80 QGraphicsRectItem *nickRectItem = p->getNickRectItem();
81 nickItem->setPlainText(p->getNick());
82 QRectF rectBR = nickRectItem->boundingRect();
83 QRectF nickBR = nickItem->boundingRect();
84 nickItem->setPos(rectBR.x() + (rectBR.width() - nickBR.width())/2, rectBR.y() + 5);
85 }
86 }
87}
88
89void
90DigestTreeScene::messageReceived(QString sessionPrefix)
91{
92 Roster_iterator it = m_roster.find(sessionPrefix);
93 if (it != m_roster.end()) {
94 DisplayUserPtr p = it.value();
95
96 reDrawNode(p, Qt::red);
97
98 if (m_previouslyUpdatedUser != DisplayUserNullPtr && m_previouslyUpdatedUser != p) {
99 reDrawNode(m_previouslyUpdatedUser, Qt::darkBlue);
100 }
101
102 m_previouslyUpdatedUser = p;
103 }
104}
105
106void
107DigestTreeScene::clearAll()
108{
109 clear();
110 m_roster.clear();
111}
112
113void
114DigestTreeScene::removeNode(const QString sessionPrefix)
115{
116 m_roster.remove(sessionPrefix);
117 plot(m_rootDigest);
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700118}
119
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700120QStringList
Zhenkai Zhu6082ede2012-09-27 17:28:46 -0700121DigestTreeScene::getRosterList()
122{
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700123 QStringList rosterList;
124 RosterIterator it(m_roster);
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700125 while (it.hasNext()) {
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700126 it.next();
127 DisplayUserPtr p = it.value();
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700128 if (p != DisplayUserNullPtr) {
Zhenkai Zhu9036e032012-09-27 20:59:33 -0700129 rosterList << "- " + p->getNick();
130 }
131 }
132 return rosterList;
Zhenkai Zhu6082ede2012-09-27 17:28:46 -0700133}
134
Yingdi Yud45777b2014-10-16 23:54:11 -0700135QStringList
136DigestTreeScene::getRosterPrefixList()
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700137{
Yingdi Yud45777b2014-10-16 23:54:11 -0700138 QStringList prefixList;
139 RosterIterator it(m_roster);
140 while (it.hasNext()) {
141 it.next();
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700142 DisplayUserPtr p = it.value();
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700143 if (p != DisplayUserNullPtr) {
Qiuhan Ding43c8e162015-02-02 15:16:48 -0800144 prefixList << p->getPrefix();
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700145 }
146 }
Yingdi Yud45777b2014-10-16 23:54:11 -0700147 return prefixList;
148}
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700149
Yingdi Yud45777b2014-10-16 23:54:11 -0700150void
151DigestTreeScene::plot(QString rootDigest)
152{
153 clear();
Zhenkai Zhu6082ede2012-09-27 17:28:46 -0700154
Yingdi Yud45777b2014-10-16 23:54:11 -0700155 shared_ptr<TreeLayout> layout(new OneLevelTreeLayout());
156 layout->setSiblingDistance(100);
157 layout->setLevelDistance(100);
Zhenkai Zhu716fe852012-10-08 18:27:55 -0700158
Yingdi Yud45777b2014-10-16 23:54:11 -0700159 std::vector<TreeLayout::Coordinate> childNodesCo(m_roster.size());
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700160 layout->setOneLevelLayout(childNodesCo);
Yingdi Yud45777b2014-10-16 23:54:11 -0700161 plotEdge(childNodesCo, NODE_SIZE);
162 plotNode(childNodesCo, rootDigest, NODE_SIZE);
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700163
Yingdi Yud45777b2014-10-16 23:54:11 -0700164 m_previouslyUpdatedUser = DisplayUserNullPtr;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700165}
166
167void
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700168DigestTreeScene::plotEdge(const std::vector<TreeLayout::Coordinate> &childNodesCo, int nodeSize)
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700169{
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700170 int n = childNodesCo.size();
171 for (int i = 0; i < n; i++) {
172 double x1 = 0.0, y1 = 0.0;
173 double x2 = childNodesCo[i].x, y2 = childNodesCo[i].y;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700174 QPointF src(x1 + nodeSize/2, y1 + nodeSize/2);
175 QPointF dest(x2 + nodeSize/2, y2 + nodeSize/2);
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -0700176 QLineF line(src, dest);
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -0700177 double angle = ::acos(line.dx() / line.length());
178
179 double arrowSize = 10;
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700180 QPointF sourceArrowP0 = src + QPointF((nodeSize/2 + 10) * line.dx() / line.length(),
181 (nodeSize/2 +10) * line.dy() / line.length());
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700182 QPointF sourceArrowP1 = sourceArrowP0 + QPointF(cos(angle + Pi / 3 - Pi/2) * arrowSize,
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -0700183 sin(angle + Pi / 3 - Pi/2) * arrowSize);
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700184 QPointF sourceArrowP2 = sourceArrowP0 + QPointF(cos(angle + Pi - Pi / 3 - Pi/2) * arrowSize,
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700185 sin(angle + Pi - Pi / 3 - Pi/2) * arrowSize);
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -0700186
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700187 addLine(QLineF(sourceArrowP0, dest), QPen(Qt::black));
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700188 addPolygon(QPolygonF() << sourceArrowP0<< sourceArrowP1 <<
189 sourceArrowP2, QPen(Qt::black), QBrush(Qt::black));
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700190 }
191}
192
193void
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700194DigestTreeScene::plotNode(const std::vector<TreeLayout::Coordinate>& childNodesCo,
195 QString digest, int nodeSize)
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700196{
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700197 RosterIterator it(m_roster);
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700198 int n = childNodesCo.size();
199 int rim = 3;
Zhenkai Zhu71b42cb2012-06-04 09:42:53 -0700200
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700201 // plot root node
202 QRectF rootBoundingRect(0, 0, nodeSize, nodeSize);
203 QRectF rootInnerBoundingRect(rim, rim, nodeSize - rim * 2, nodeSize - rim * 2);
204 addRect(rootBoundingRect, QPen(Qt::black), QBrush(Qt::darkRed));
205 addRect(rootInnerBoundingRect, QPen(Qt::black), QBrush(Qt::lightGray));
Zhenkai Zhuc5470612012-06-05 12:28:59 -0700206 QRectF digestRect(- 5.5 * nodeSize , - nodeSize, 12 * nodeSize, 30);
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700207 addRect(digestRect, QPen(Qt::darkCyan), QBrush(Qt::darkCyan));
Zhenkai Zhu27df8d42012-06-05 12:04:04 -0700208
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700209 QGraphicsTextItem *digestItem = addText(digest);
210 QRectF digestBoundingRect = digestItem->boundingRect();
Zhenkai Zhu27df8d42012-06-05 12:04:04 -0700211 digestItem->setDefaultTextColor(Qt::black);
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700212 digestItem->setFont(QFont("Cursive", 12, QFont::Bold));
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700213 digestItem->setPos(- 4.5 * nodeSize + (12 * nodeSize - digestBoundingRect.width()) / 2,
214 - nodeSize + 5);
Yingdi Yud45777b2014-10-16 23:54:11 -0700215 m_displayRootDigest = digestItem;
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700216
217 // plot child nodes
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700218 for (int i = 0; i < n; i++) {
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700219 if (it.hasNext())
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700220 it.next();
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700221 else
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700222 abort();
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700223
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700224 double x = childNodesCo[i].x;
225 double y = childNodesCo[i].y;
226 QRectF boundingRect(x, y, nodeSize, nodeSize);
227 QRectF innerBoundingRect(x + rim, y + rim, nodeSize - rim * 2, nodeSize - rim * 2);
228 DisplayUserPtr p = it.value();
229 QGraphicsRectItem *rectItem = addRect(boundingRect, QPen(Qt::black), QBrush(Qt::darkBlue));
230 p->setRimRectItem(rectItem);
231
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700232 QGraphicsRectItem *innerRectItem = addRect(innerBoundingRect,
233 QPen(Qt::black),
234 QBrush(Qt::lightGray));
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700235 p->setInnerRectItem(innerRectItem);
236
Yingdi Yud45777b2014-10-16 23:54:11 -0700237 std::string s = boost::lexical_cast<std::string>(p->getSeqNo());
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700238 QGraphicsTextItem *seqItem = addText(s.c_str());
239 seqItem->setFont(QFont("Cursive", 12, QFont::Bold));
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700240 QRectF seqBoundingRect = seqItem->boundingRect();
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700241 seqItem->setPos(x + nodeSize / 2 - seqBoundingRect.width() / 2,
242 y + nodeSize / 2 - seqBoundingRect.height() / 2);
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700243 p->setSeqTextItem(seqItem);
244
245 QRectF textRect(x - nodeSize / 2, y + nodeSize, 2 * nodeSize, 30);
246 QGraphicsRectItem *nickRectItem = addRect(textRect, QPen(Qt::darkCyan), QBrush(Qt::darkCyan));
247 p->setNickRectItem(nickRectItem);
248 QGraphicsTextItem *nickItem = addText(p->getNick());
249 QRectF textBoundingRect = nickItem->boundingRect();
250 nickItem->setDefaultTextColor(Qt::white);
251 nickItem->setFont(QFont("Cursive", 12, QFont::Bold));
252 nickItem->setPos(x + nodeSize / 2 - textBoundingRect.width() / 2, y + nodeSize + 5);
253 p->setNickTextItem(nickItem);
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -0700254 }
Zhenkai Zhu21d75f92012-06-04 21:23:34 -0700255
Zhenkai Zhuf474a0a2012-05-30 15:06:29 -0700256}
257
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700258void
259DigestTreeScene::reDrawNode(DisplayUserPtr p, QColor rimColor)
260{
261 QGraphicsRectItem *rimItem = p->getRimRectItem();
262 rimItem->setBrush(QBrush(rimColor));
263 QGraphicsRectItem *innerItem = p->getInnerRectItem();
264 innerItem->setBrush(QBrush(Qt::lightGray));
265 QGraphicsTextItem *seqTextItem = p->getSeqTextItem();
Yingdi Yud45777b2014-10-16 23:54:11 -0700266 std::string s = boost::lexical_cast<std::string>(p->getSeqNo());
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700267 seqTextItem->setPlainText(s.c_str());
268 QRectF textBR = seqTextItem->boundingRect();
269 QRectF innerBR = innerItem->boundingRect();
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700270 seqTextItem->setPos(innerBR.x() + (innerBR.width() - textBR.width())/2,
271 innerBR.y() + (innerBR.height() - textBR.height())/2);
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700272}
273
Yingdi Yueb692ac2015-02-10 18:46:18 -0800274} // namespace chronochat
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700275
Alexander Afanasyevb4b92292013-07-09 13:54:59 -0700276#if WAF
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -0700277#include "digest-tree-scene.moc"
Yingdi Yu42125862014-08-07 17:04:28 -0700278// #include "digest-tree-scene.cpp.moc"
Alexander Afanasyevb4b92292013-07-09 13:54:59 -0700279#endif