partially working new chronochat
diff --git a/src/digesttreescene.cpp b/src/digesttreescene.cpp
new file mode 100644
index 0000000..5c785e6
--- /dev/null
+++ b/src/digesttreescene.cpp
@@ -0,0 +1,330 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Yingdi Yu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "digesttreescene.h"
+
+#include <QtGui>
+
+#ifndef Q_MOC_RUN
+#include <vector>
+#include <iostream>
+#include <assert.h>
+#include <boost/lexical_cast.hpp>
+#include <memory>
+#endif
+
+static const double Pi = 3.14159265358979323846264338327950288419717;
+
+//DisplayUserPtr DisplayUserNullPtr;
+
+DigestTreeScene::DigestTreeScene(QWidget *parent)
+ : QGraphicsScene(parent)
+{
+ previouslyUpdatedUser = DisplayUserNullPtr;
+}
+
+void
+DigestTreeScene::processUpdate(const std::vector<Sync::MissingDataInfo> &v, QString digest)
+{
+ int n = v.size();
+ bool rePlot = false;
+ for (int i = 0; i < n; i++)
+ {
+ Roster_iterator it = m_roster.find(v[i].prefix.c_str());
+ if (it == m_roster.end())
+ {
+ rePlot = true;
+ DisplayUserPtr p(new DisplayUser());
+ time_t tempTime = time(NULL) - FRESHNESS + 1;
+ p->setReceived(tempTime);
+ p->setPrefix(v[i].prefix.c_str());
+ p->setSeq(v[i].high);
+ m_roster.insert(p->getPrefix(), p);
+ }
+ else
+ {
+ it.value()->setSeq(v[i].high);
+ }
+ }
+
+ if (rePlot)
+ {
+ plot(digest);
+ QTimer::singleShot(2100, this, SLOT(emitReplot()));
+ }
+ else
+ {
+ for (int i = 0; i < n; i++)
+ {
+ Roster_iterator it = m_roster.find(v[i].prefix.c_str());
+ if (it != m_roster.end()) {
+ DisplayUserPtr p = it.value();
+ QGraphicsTextItem *item = p->getSeqTextItem();
+ QGraphicsRectItem *rectItem = p->getInnerRectItem();
+ std::string s = boost::lexical_cast<std::string>(p->getSeqNo().getSeq());
+ item->setPlainText(s.c_str());
+ QRectF textBR = item->boundingRect();
+ QRectF rectBR = rectItem->boundingRect();
+ item->setPos(rectBR.x() + (rectBR.width() - textBR.width())/2, rectBR.y() + (rectBR.height() - textBR.height())/2);
+ }
+ }
+ m_rootDigest->setPlainText(digest);
+ }
+}
+
+void
+DigestTreeScene::emitReplot()
+{
+ emit replot();
+}
+
+QStringList
+DigestTreeScene::getRosterList()
+{
+ QStringList rosterList;
+ RosterIterator it(m_roster);
+ while(it.hasNext())
+ {
+ it.next();
+ DisplayUserPtr p = it.value();
+ if (p != DisplayUserNullPtr)
+ {
+ rosterList << "- " + p->getNick();
+ }
+ }
+ return rosterList;
+}
+
+void
+DigestTreeScene::msgReceived(QString prefix, QString nick)
+{
+ Roster_iterator it = m_roster.find(prefix);
+ if (it != m_roster.end())
+ {
+ std::cout << "Updating for prefix = " << prefix.toStdString() << " nick = " << nick.toStdString() << std::endl;
+ DisplayUserPtr p = it.value();
+ p->setReceived(time(NULL));
+ if (nick != p->getNick()) {
+ std::cout << "old nick = " << p->getNick().toStdString() << std::endl;
+ p->setNick(nick);
+ QGraphicsTextItem *nickItem = p->getNickTextItem();
+ QGraphicsRectItem *nickRectItem = p->getNickRectItem();
+ nickItem->setPlainText(p->getNick());
+ QRectF rectBR = nickRectItem->boundingRect();
+ QRectF nickBR = nickItem->boundingRect();
+ nickItem->setPos(rectBR.x() + (rectBR.width() - nickBR.width())/2, rectBR.y() + 5);
+ emit rosterChanged(QStringList());
+ }
+
+ reDrawNode(p, Qt::red);
+
+ if (previouslyUpdatedUser != DisplayUserNullPtr && previouslyUpdatedUser != p)
+ {
+ reDrawNode(previouslyUpdatedUser, Qt::darkBlue);
+ }
+
+ previouslyUpdatedUser = p;
+ }
+}
+
+void
+DigestTreeScene::clearAll()
+{
+ clear();
+ m_roster.clear();
+}
+
+bool
+DigestTreeScene::removeNode(const QString prefix)
+{
+ int removedCount = m_roster.remove(prefix);
+ return (removedCount > 0);
+}
+
+void
+DigestTreeScene::plot(QString digest)
+{
+#ifdef __DEBUG
+ std::cout << "Plotting at time: " << time(NULL) << std::endl;
+#endif
+ clear();
+
+ int nodeSize = 40;
+
+ int siblingDistance = 100, levelDistance = 100;
+ std::auto_ptr<TreeLayout> layout(new OneLevelTreeLayout());
+ layout->setSiblingDistance(siblingDistance);
+ layout->setLevelDistance(levelDistance);
+
+ // do some cleaning, get rid of stale member info
+ Roster_iterator it = m_roster.begin();
+ QStringList staleUserList;
+ while (it != m_roster.end())
+ {
+ DisplayUserPtr p = it.value();
+ if (p != DisplayUserNullPtr)
+ {
+ time_t now = time(NULL);
+ if (now - p->getReceived() >= FRESHNESS)
+ {
+#ifdef __DEBUG
+ std::cout << "Removing user: " << p->getNick().toStdString() << std::endl;
+ std::cout << "now - last = " << now - p->getReceived() << std::endl;
+#endif
+ staleUserList << p->getNick();
+ p = DisplayUserNullPtr;
+ it = m_roster.erase(it);
+ }
+ else
+ {
+ if (!m_currentPrefix.startsWith("/private/local") && p->getPrefix().startsWith("/private/local"))
+ {
+#ifdef __DEBUG
+ std::cout << "erasing: " << p->getPrefix().toStdString() << std::endl;
+#endif
+ staleUserList << p->getNick();
+ p = DisplayUserNullPtr;
+ it = m_roster.erase(it);
+ continue;
+ }
+ ++it;
+ }
+ }
+ else
+ {
+ it = m_roster.erase(it);
+ }
+ }
+
+ // for simpicity here, whenever we replot, we also redo the roster list
+ emit rosterChanged(staleUserList);
+
+ int n = m_roster.size();
+
+ std::vector<TreeLayout::Coordinate> childNodesCo(n);
+
+ layout->setOneLevelLayout(childNodesCo);
+
+ plotEdge(childNodesCo, nodeSize);
+ plotNode(childNodesCo, digest, nodeSize);
+
+ previouslyUpdatedUser = DisplayUserNullPtr;
+
+}
+
+void
+DigestTreeScene::plotEdge(const std::vector<TreeLayout::Coordinate> &childNodesCo, int nodeSize)
+{
+ int n = childNodesCo.size();
+ for (int i = 0; i < n; i++) {
+ double x1 = 0.0, y1 = 0.0;
+ double x2 = childNodesCo[i].x, y2 = childNodesCo[i].y;
+ QPointF src(x1 + nodeSize/2, y1 + nodeSize/2);
+ QPointF dest(x2 + nodeSize/2, y2 + nodeSize/2);
+ QLineF line(src, dest);
+ double angle = ::acos(line.dx() / line.length());
+
+ double arrowSize = 10;
+ QPointF sourceArrowP0 = src + QPointF((nodeSize/2 + 10) * line.dx() / line.length(), (nodeSize/2 +10) * line.dy() / line.length());
+ QPointF sourceArrowP1 = sourceArrowP0 + QPointF(cos(angle + Pi / 3 - Pi/2) * arrowSize,
+ sin(angle + Pi / 3 - Pi/2) * arrowSize);
+ QPointF sourceArrowP2 = sourceArrowP0 + QPointF(cos(angle + Pi - Pi / 3 - Pi/2) * arrowSize,
+ sin(angle + Pi - Pi / 3 - Pi/2) * arrowSize);
+
+ addLine(QLineF(sourceArrowP0, dest), QPen(Qt::black));
+ addPolygon(QPolygonF() << sourceArrowP0<< sourceArrowP1 << sourceArrowP2, QPen(Qt::black), QBrush(Qt::black));
+ }
+}
+
+void
+DigestTreeScene::plotNode(const std::vector<TreeLayout::Coordinate> &childNodesCo, QString digest, int nodeSize)
+{
+ RosterIterator it(m_roster);
+ int n = childNodesCo.size();
+ int rim = 3;
+
+ // plot root node
+ QRectF rootBoundingRect(0, 0, nodeSize, nodeSize);
+ QRectF rootInnerBoundingRect(rim, rim, nodeSize - rim * 2, nodeSize - rim * 2);
+ addRect(rootBoundingRect, QPen(Qt::black), QBrush(Qt::darkRed));
+ addRect(rootInnerBoundingRect, QPen(Qt::black), QBrush(Qt::lightGray));
+ QRectF digestRect(- 5.5 * nodeSize , - nodeSize, 12 * nodeSize, 30);
+ addRect(digestRect, QPen(Qt::darkCyan), QBrush(Qt::darkCyan));
+
+ QGraphicsTextItem *digestItem = addText(digest);
+ QRectF digestBoundingRect = digestItem->boundingRect();
+ digestItem->setDefaultTextColor(Qt::black);
+ digestItem->setFont(QFont("Cursive", 12, QFont::Bold));
+ digestItem->setPos(- 4.5 * nodeSize + (12 * nodeSize - digestBoundingRect.width()) / 2, - nodeSize + 5);
+ m_rootDigest = digestItem;
+
+ // plot child nodes
+ for (int i = 0; i < n; i++)
+ {
+ if (it.hasNext())
+ {
+ it.next();
+ }
+ else
+ {
+ abort();
+ }
+
+ double x = childNodesCo[i].x;
+ double y = childNodesCo[i].y;
+ QRectF boundingRect(x, y, nodeSize, nodeSize);
+ QRectF innerBoundingRect(x + rim, y + rim, nodeSize - rim * 2, nodeSize - rim * 2);
+ DisplayUserPtr p = it.value();
+ QGraphicsRectItem *rectItem = addRect(boundingRect, QPen(Qt::black), QBrush(Qt::darkBlue));
+ p->setRimRectItem(rectItem);
+
+ QGraphicsRectItem *innerRectItem = addRect(innerBoundingRect, QPen(Qt::black), QBrush(Qt::lightGray));
+ p->setInnerRectItem(innerRectItem);
+
+ std::string s = boost::lexical_cast<std::string>(p->getSeqNo().getSeq());
+ QGraphicsTextItem *seqItem = addText(s.c_str());
+ seqItem->setFont(QFont("Cursive", 12, QFont::Bold));
+ QRectF seqBoundingRect = seqItem->boundingRect();
+ seqItem->setPos(x + nodeSize / 2 - seqBoundingRect.width() / 2, y + nodeSize / 2 - seqBoundingRect.height() / 2);
+ p->setSeqTextItem(seqItem);
+
+ QRectF textRect(x - nodeSize / 2, y + nodeSize, 2 * nodeSize, 30);
+ QGraphicsRectItem *nickRectItem = addRect(textRect, QPen(Qt::darkCyan), QBrush(Qt::darkCyan));
+ p->setNickRectItem(nickRectItem);
+ QGraphicsTextItem *nickItem = addText(p->getNick());
+ QRectF textBoundingRect = nickItem->boundingRect();
+ nickItem->setDefaultTextColor(Qt::white);
+ nickItem->setFont(QFont("Cursive", 12, QFont::Bold));
+ nickItem->setPos(x + nodeSize / 2 - textBoundingRect.width() / 2, y + nodeSize + 5);
+ p->setNickTextItem(nickItem);
+ }
+
+}
+
+void
+DigestTreeScene::reDrawNode(DisplayUserPtr p, QColor rimColor)
+{
+ QGraphicsRectItem *rimItem = p->getRimRectItem();
+ rimItem->setBrush(QBrush(rimColor));
+ QGraphicsRectItem *innerItem = p->getInnerRectItem();
+ innerItem->setBrush(QBrush(Qt::lightGray));
+ QGraphicsTextItem *seqTextItem = p->getSeqTextItem();
+ std::string s = boost::lexical_cast<std::string>(p->getSeqNo().getSeq());
+ seqTextItem->setPlainText(s.c_str());
+ QRectF textBR = seqTextItem->boundingRect();
+ QRectF innerBR = innerItem->boundingRect();
+ seqTextItem->setPos(innerBR.x() + (innerBR.width() - textBR.width())/2, innerBR.y() + (innerBR.height() - textBR.height())/2);
+}
+
+#if WAF
+#include "digesttreescene.moc"
+#include "digesttreescene.cpp.moc"
+#endif