gui: Display the trust tree

Change-Id: Id48227b0f2e903905d7c8eb9795d038d6562794c
diff --git a/src/chat-dialog.cpp b/src/chat-dialog.cpp
index baa9f78..061c74f 100644
--- a/src/chat-dialog.cpp
+++ b/src/chat-dialog.cpp
@@ -24,6 +24,7 @@
 #include <ndn-cpp-dev/util/random.hpp>
 #include <cryptopp/hex.h>
 #include <cryptopp/files.h>
+#include <queue>
 #include "logging.h"
 #endif
 
@@ -71,13 +72,17 @@
   qRegisterMetaType<size_t>("size_t");
 
   m_scene = new DigestTreeScene(this);
+  m_trustScene = new TrustTreeScene(this);
   m_rosterModel = new QStringListModel(this);
   m_timer = new QTimer(this);
 
   ui->setupUi(this);
-  ui->treeViewer->setScene(m_scene);
+  ui->syncTreeViewer->setScene(m_scene);
   m_scene->setSceneRect(m_scene->itemsBoundingRect());
-  ui->treeViewer->hide();
+  ui->syncTreeViewer->hide();
+  ui->trustTreeViewer->setScene(m_trustScene);
+  m_trustScene->setSceneRect(m_trustScene->itemsBoundingRect());
+  ui->trustTreeViewer->hide();
   ui->listView->setModel(m_rosterModel);
 
   m_identity = IdentityCertificate::certificateNameToPublicKeyName(m_myCertificate.getName()).getPrefix(-1);
@@ -89,8 +94,10 @@
 
   connect(ui->lineEdit, SIGNAL(returnPressed()), 
           this, SLOT(onReturnPressed()));
-  connect(ui->treeButton, SIGNAL(pressed()), 
-          this, SLOT(onTreeButtonPressed()));
+  connect(ui->syncTreeButton, SIGNAL(pressed()), 
+          this, SLOT(onSyncTreeButtonPressed()));
+  connect(ui->trustTreeButton, SIGNAL(pressed()), 
+          this, SLOT(onTrustTreeButtonPressed()));
   connect(m_scene, SIGNAL(replot()),
           this, SLOT(onReplot()));
   connect(m_scene, SIGNAL(rosterChanged(QStringList)), 
@@ -120,6 +127,8 @@
                                                 "==", "\\1", "\\1", true);
 
       ui->inviteButton->setEnabled(true);
+      ui->trustTreeButton->setEnabled(true);
+
       connect(ui->inviteButton, SIGNAL(clicked()),
               this, SLOT(onInviteListDialogRequested()));
       connect(m_inviteListDialog, SIGNAL(sendInvitation(const QString&)),
@@ -159,6 +168,7 @@
   _LOG_DEBUG("Add sync anchor from invation");
   // Add inviter certificate as trust anchor.
   m_sock->addParticipant(invitation.getInviterCertificate());
+  plotTrustTree();
 
   // Ask inviter for IntroCertificate
   Name inviterNameSpace = IdentityCertificate::certificateNameToPublicKeyName(invitation.getInviterCertificate().getName()).getPrefix(-1);
@@ -308,8 +318,8 @@
 
   QTimer::singleShot(600, this, SLOT(sendJoin()));
   m_timer->start(FRESHNESS * 1000);
-  disableTreeDisplay();
-  QTimer::singleShot(2200, this, SLOT(enableTreeDisplay()));
+  disableSyncTreeDisplay();
+  QTimer::singleShot(2200, this, SLOT(enableSyncTreeDisplay()));
 }
 
 void
@@ -411,6 +421,7 @@
 {
   // Add invitee certificate as trust anchor.
   m_sock->addParticipant(inviteeCert);
+  plotTrustTree();
 
   // Ask invitee for IntroCertificate.
   Name inviteeNameSpace = IdentityCertificate::certificateNameToPublicKeyName(inviteeCert.getName()).getPrefix(-1);
@@ -492,7 +503,7 @@
 
   Chronos::IntroCertListMsg msg;
 
-  vector<Name>::const_iterator it = certNameList.begin();
+  vector<Name>::const_iterator it  = certNameList.begin();
   vector<Name>::const_iterator end = certNameList.end();
   for(; it != end; it++)
     {
@@ -568,10 +579,10 @@
   }
 }
 
-void ChatDialog::disableTreeDisplay()
+void ChatDialog::disableSyncTreeDisplay()
 {
-  ui->treeButton->setEnabled(false);
-  ui->treeViewer->hide();
+  ui->syncTreeButton->setEnabled(false);
+  ui->syncTreeViewer->hide();
   fitView();
 }
 
@@ -775,7 +786,11 @@
   boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
   QRectF rect = m_scene->itemsBoundingRect();
   m_scene->setSceneRect(rect);
-  ui->treeViewer->fitInView(m_scene->itemsBoundingRect(), Qt::KeepAspectRatio);
+  ui->syncTreeViewer->fitInView(m_scene->itemsBoundingRect(), Qt::KeepAspectRatio);
+
+  QRectF trustRect = m_trustScene->itemsBoundingRect();
+  m_trustScene->setSceneRect(trustRect);
+  ui->trustTreeViewer->fitInView(m_trustScene->itemsBoundingRect(), Qt::KeepAspectRatio);
 }
 
 void
@@ -818,6 +833,94 @@
   reap();
 }
 
+void
+ChatDialog::getTree(TrustTreeNodeList& nodeList)
+{
+  typedef map<Name, shared_ptr<TrustTreeNode> > NodeMap;
+
+  vector<Name> certNameList;
+  NodeMap nodeMap;
+
+  m_sock->getIntroCertNames(certNameList);
+
+  vector<Name>::const_iterator it  = certNameList.begin();
+  vector<Name>::const_iterator end = certNameList.end();
+  for(; it != end; it++)
+    {
+      Name introducerCertName;
+      Name introduceeCertName;
+
+      introducerCertName.wireDecode(it->get(-2).blockFromValue());
+      introduceeCertName.wireDecode(it->get(-3).blockFromValue());
+
+      Name introducerName = IdentityCertificate::certificateNameToPublicKeyName(introducerCertName).getPrefix(-1);
+      Name introduceeName = IdentityCertificate::certificateNameToPublicKeyName(introduceeCertName).getPrefix(-1);
+
+      NodeMap::iterator introducerIt = nodeMap.find(introducerName);
+      if(introducerIt == nodeMap.end())
+        {
+          shared_ptr<TrustTreeNode> introducerNode(new TrustTreeNode(introducerName));
+          nodeMap[introducerName] = introducerNode;
+        }
+      shared_ptr<TrustTreeNode> erNode = nodeMap[introducerName];
+
+      NodeMap::iterator introduceeIt = nodeMap.find(introduceeName);
+      if(introduceeIt == nodeMap.end())
+        {
+          shared_ptr<TrustTreeNode> introduceeNode(new TrustTreeNode(introduceeName));
+          nodeMap[introduceeName] = introduceeNode;
+        }
+      shared_ptr<TrustTreeNode> eeNode = nodeMap[introduceeName];
+
+      erNode->addIntroducee(eeNode);
+      eeNode->addIntroducer(erNode);
+    }
+  
+  nodeList.clear();
+  queue<shared_ptr<TrustTreeNode> > nodeQueue;
+
+  NodeMap::iterator nodeIt = nodeMap.find(m_identity);
+  if(nodeIt == nodeMap.end())
+    return;
+
+  nodeQueue.push(nodeIt->second);
+  nodeIt->second->setLevel(0);
+  while(!nodeQueue.empty())
+    {
+      shared_ptr<TrustTreeNode>& node = nodeQueue.front();
+      node->setVisited();
+
+      TrustTreeNodeList& introducees = node->getIntroducees();
+      TrustTreeNodeList::iterator eeIt  = introducees.begin();
+      TrustTreeNodeList::iterator eeEnd = introducees.end();
+
+      for(; eeIt != eeEnd; eeIt++)
+        {
+          _LOG_DEBUG("introducee: " << (*eeIt)->name() << " visited: " << boolalpha << (*eeIt)->visited());
+          if(!(*eeIt)->visited())
+            {
+              nodeQueue.push(*eeIt);
+              (*eeIt)->setLevel(node->level()+1);
+            }
+        }
+
+      nodeList.push_back(node);
+      nodeQueue.pop();
+    }
+}
+
+void
+ChatDialog::plotTrustTree()
+{
+  TrustTreeNodeList nodeList;
+
+  getTree(nodeList);
+  {
+    boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
+    m_trustScene->plotTrustTree(nodeList);
+    fitView();
+  }
+}
 
 // public slots:
 void
@@ -865,8 +968,8 @@
           usleep(100000);
           QTimer::singleShot(600, this, SLOT(sendJoin()));
           m_timer->start(FRESHNESS * 1000);
-          disableTreeDisplay();
-          QTimer::singleShot(2200, this, SLOT(enableTreeDisplay()));
+          disableSyncTreeDisplay();
+          QTimer::singleShot(2200, this, SLOT(enableSyncTreeDisplay()));
         }
       else
         initializeSync();
@@ -922,17 +1025,34 @@
 }
 
 void 
-ChatDialog::onTreeButtonPressed()
+ChatDialog::onSyncTreeButtonPressed()
 {
-  if (ui->treeViewer->isVisible())
+  if (ui->syncTreeViewer->isVisible())
   {
-    ui->treeViewer->hide();
-    ui->treeButton->setText("Show ChronoSync Tree");
+    ui->syncTreeViewer->hide();
+    ui->syncTreeButton->setText("Show ChronoSync Tree");
   }
   else
   {
-    ui->treeViewer->show();
-    ui->treeButton->setText("Hide ChronoSync Tree");
+    ui->syncTreeViewer->show();
+    ui->syncTreeButton->setText("Hide ChronoSync Tree");
+  }
+
+  fitView();
+}
+
+void
+ChatDialog::onTrustTreeButtonPressed()
+{
+  if (ui->trustTreeViewer->isVisible())
+  {
+    ui->trustTreeViewer->hide();
+    ui->trustTreeButton->setText("Show Trust Tree");
+  }
+  else
+  {
+    ui->trustTreeViewer->show();
+    ui->trustTreeButton->setText("Hide Trust Tree");
   }
 
   fitView();
@@ -965,9 +1085,7 @@
   if (!isHistory)
   {
     // update the tree view
-    std::string stdStrName = data->getName().toUri();
-    std::string stdStrNameWithoutSeq = stdStrName.substr(0, stdStrName.find_last_of('/'));
-    std::string prefix = stdStrNameWithoutSeq.substr(0, stdStrNameWithoutSeq.find_last_of('/'));
+    std::string prefix = data->getName().getPrefix(-2).toUri();
     _LOG_DEBUG("<<< updating scene for" << prefix << ": " << msg.from());
     if (msg.type() == SyncDemo::ChatMessage::LEAVE)
     {
@@ -1051,6 +1169,7 @@
     msg.set_from(nick);
     appendMessage(msg);
   }
+  plotTrustTree();
 }
 
 void
@@ -1108,9 +1227,9 @@
   _LOG_DEBUG("Sync REMOVE signal sent");
 }
 
-void ChatDialog::enableTreeDisplay()
+void ChatDialog::enableSyncTreeDisplay()
 {
-  ui->treeButton->setEnabled(true);
+  ui->syncTreeButton->setEnabled(true);
   // treeViewer->show();
   // fitView();
 }
@@ -1185,6 +1304,7 @@
   innerData.wireDecode(data->getContent().blockFromValue());
   Sync::IntroCertificate introCert(innerData);
   m_sock->addParticipant(introCert);
+  plotTrustTree();
 }
 
 void
@@ -1194,7 +1314,6 @@
 }
 
 
-
 #if WAF
 #include "chat-dialog.moc"
 #include "chat-dialog.cpp.moc"
diff --git a/src/chat-dialog.h b/src/chat-dialog.h
index 0ddbc85..c95aabf 100644
--- a/src/chat-dialog.h
+++ b/src/chat-dialog.h
@@ -28,12 +28,13 @@
 #include "contact.h"
 #include "chatbuf.pb.h"
 #include "intro-cert-list.pb.h"
-#include "digesttreescene.h"
+#include "digest-tree-scene.h"
+#include "trust-tree-scene.h"
+#include "trust-tree-node.h"
 #include <sync-socket.h>
 #include <sync-seq-no.h>
 #include <ndn-cpp-dev/security/key-chain.hpp>
 #include "validator-invitation.h"
-
 #include <boost/thread/locks.hpp>
 #include <boost/thread/recursive_mutex.hpp>
 #include <boost/thread/thread.hpp>
@@ -162,7 +163,7 @@
   sendMsg(SyncDemo::ChatMessage &msg);
 
   void 
-  disableTreeDisplay();
+  disableSyncTreeDisplay();
 
   void 
   appendMessage(const SyncDemo::ChatMessage msg, bool isHistory = false);
@@ -197,6 +198,12 @@
   void 
   summonReaper();
 
+  void
+  getTree(TrustTreeNodeList& nodeList);
+
+  void
+  plotTrustTree();
+
 signals:  
   void
   processData(const ndn::shared_ptr<const ndn::Data>& data, bool show, bool isHistory);
@@ -248,7 +255,10 @@
   onReturnPressed();
 
   void 
-  onTreeButtonPressed();
+  onSyncTreeButtonPressed();
+
+  void
+  onTrustTreeButtonPressed();
 
   void 
   onProcessData(const ndn::shared_ptr<const ndn::Data>& data,
@@ -276,7 +286,7 @@
   sendLeave();
 
   void 
-  enableTreeDisplay();
+  enableSyncTreeDisplay();
 
   void
   reap();
@@ -324,6 +334,7 @@
   ndn::Name m_localChatPrefix;
   std::string m_nick;
   DigestTreeScene *m_scene;
+  TrustTreeScene *m_trustScene;
   QStringListModel *m_rosterModel;
   QTimer* m_timer;
 
diff --git a/src/chat-dialog.ui b/src/chat-dialog.ui
index 2d174c0..1473eeb 100644
--- a/src/chat-dialog.ui
+++ b/src/chat-dialog.ui
@@ -13,15 +13,9 @@
   <property name="windowTitle">
    <string>ChronoChat -- Powered By ChronoSync</string>
   </property>
-  <layout class="QVBoxLayout">
-   <property name="spacing">
-    <number>6</number>
-   </property>
+  <layout class="QVBoxLayout" name="verticalLayout_2">
    <item>
-    <layout class="QHBoxLayout" name="horizontalLayout">
-     <property name="spacing">
-      <number>-1</number>
-     </property>
+    <layout class="QHBoxLayout" name="firstLayout">
      <item>
       <layout class="QVBoxLayout" name="infoLayout">
        <item>
@@ -58,17 +52,32 @@
       </spacer>
      </item>
      <item>
-      <layout class="QVBoxLayout" name="buttonLayout">
-       <property name="sizeConstraint">
-        <enum>QLayout::SetFixedSize</enum>
-       </property>
+      <layout class="QVBoxLayout" name="treeButtonLayout">
        <item>
-        <widget class="QPushButton" name="inviteButton">
+        <widget class="QPushButton" name="trustTreeButton">
          <property name="enabled">
           <bool>false</bool>
          </property>
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="minimumSize">
+          <size>
+           <width>0</width>
+           <height>0</height>
+          </size>
+         </property>
+         <property name="maximumSize">
+          <size>
+           <width>200</width>
+           <height>16777215</height>
+          </size>
+         </property>
          <property name="text">
-          <string>Invite</string>
+          <string>Show Trust Tree</string>
          </property>
          <property name="autoDefault">
           <bool>false</bool>
@@ -76,19 +85,19 @@
         </widget>
        </item>
        <item>
-        <widget class="QPushButton" name="treeButton">
+        <widget class="QPushButton" name="syncTreeButton">
          <property name="enabled">
           <bool>false</bool>
          </property>
          <property name="sizePolicy">
-          <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+          <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
            <horstretch>0</horstretch>
            <verstretch>0</verstretch>
           </sizepolicy>
          </property>
          <property name="minimumSize">
           <size>
-           <width>200</width>
+           <width>0</width>
            <height>0</height>
           </size>
          </property>
@@ -104,6 +113,9 @@
          <property name="text">
           <string>Show ChronoSync Tree</string>
          </property>
+         <property name="autoDefault">
+          <bool>false</bool>
+         </property>
         </widget>
        </item>
       </layout>
@@ -111,11 +123,14 @@
     </layout>
    </item>
    <item>
-    <layout class="QHBoxLayout" name="chatLayout_2">
+    <layout class="QHBoxLayout" name="secondLayout" stretch="1,6">
+     <property name="leftMargin">
+      <number>5</number>
+     </property>
      <item>
       <widget class="QListView" name="listView">
        <property name="sizePolicy">
-        <sizepolicy hsizetype="Fixed" vsizetype="Expanding">
+        <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
          <horstretch>0</horstretch>
          <verstretch>0</verstretch>
         </sizepolicy>
@@ -146,13 +161,24 @@
       </widget>
      </item>
      <item>
-      <layout class="QVBoxLayout" name="messageLayout">
+      <layout class="QVBoxLayout" name="viewerLayout">
        <item>
-        <widget class="QGraphicsView" name="treeViewer">
-         <property name="focusPolicy">
-          <enum>Qt::NoFocus</enum>
-         </property>
-        </widget>
+        <layout class="QHBoxLayout" name="treeViewLayout">
+         <item>
+          <widget class="QGraphicsView" name="syncTreeViewer">
+           <property name="focusPolicy">
+            <enum>Qt::NoFocus</enum>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QGraphicsView" name="trustTreeViewer">
+           <property name="focusPolicy">
+            <enum>Qt::NoFocus</enum>
+           </property>
+          </widget>
+         </item>
+        </layout>
        </item>
        <item>
         <widget class="QTextEdit" name="textEdit">
@@ -164,19 +190,54 @@
          </property>
         </widget>
        </item>
+      </layout>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="thirdLayout" stretch="1,6">
+     <property name="spacing">
+      <number>10</number>
+     </property>
+     <property name="leftMargin">
+      <number>0</number>
+     </property>
+     <item>
+      <widget class="QPushButton" name="inviteButton">
+       <property name="enabled">
+        <bool>false</bool>
+       </property>
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="minimumSize">
+        <size>
+         <width>0</width>
+         <height>0</height>
+        </size>
+       </property>
+       <property name="text">
+        <string>Invite</string>
+       </property>
+       <property name="autoDefault">
+        <bool>false</bool>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <layout class="QHBoxLayout" name="inputLayout">
        <item>
-        <layout class="QHBoxLayout" name="inputLayout">
-         <item>
-          <widget class="QLabel" name="label">
-           <property name="text">
-            <string>Message:</string>
-           </property>
-          </widget>
-         </item>
-         <item>
-          <widget class="QLineEdit" name="lineEdit"/>
-         </item>
-        </layout>
+        <widget class="QLabel" name="label">
+         <property name="text">
+          <string>Message:</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QLineEdit" name="lineEdit"/>
        </item>
       </layout>
      </item>
diff --git a/src/controller.cpp b/src/controller.cpp
index 43e79a4..9904a64 100644
--- a/src/controller.cpp
+++ b/src/controller.cpp
@@ -647,8 +647,10 @@
   delete m_startChatDialog;
   delete m_profileEditor;
   delete m_invitationDialog;
+  delete m_browseContactDialog;
   delete m_addContactPanel;
-  // TODO: clean up all the dialog.
+
+  m_face->shutdown();
 
   QApplication::quit();
 }
diff --git a/src/digesttreescene.cpp b/src/digest-tree-scene.cpp
similarity index 89%
rename from src/digesttreescene.cpp
rename to src/digest-tree-scene.cpp
index c2aa865..14f95bd 100644
--- a/src/digesttreescene.cpp
+++ b/src/digest-tree-scene.cpp
@@ -9,7 +9,7 @@
  *         Alexander Afanasyev <alexander.afanasyev@ucla.edu>
  */
 
-#include "digesttreescene.h"
+#include "digest-tree-scene.h"
 
 #include <QtGui>
 
@@ -108,31 +108,32 @@
 {
   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);
-    }
+      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());
+        }
 
-    previouslyUpdatedUser = p;
-  }
+      reDrawNode(p, Qt::red);
+
+      if (previouslyUpdatedUser != DisplayUserNullPtr && previouslyUpdatedUser != p) 
+        {
+          reDrawNode(previouslyUpdatedUser, Qt::darkBlue);
+        }
+
+      previouslyUpdatedUser = p;
+    }
 }
 
 void
@@ -325,6 +326,6 @@
 }
 
 #if WAF
-#include "digesttreescene.moc"
-#include "digesttreescene.cpp.moc"
+#include "digest-tree-scene.moc"
+#include "digest-tree-scene.cpp.moc"
 #endif
diff --git a/src/digesttreescene.h b/src/digest-tree-scene.h
similarity index 96%
rename from src/digesttreescene.h
rename to src/digest-tree-scene.h
index 9f1c63f..6ac6b1c 100644
--- a/src/digesttreescene.h
+++ b/src/digest-tree-scene.h
@@ -9,16 +9,15 @@
  *         Alexander Afanasyev <alexander.afanasyev@ucla.edu>
  */
 
-#ifndef DIGESTTREESCENE_H
-#define DIGESTTREESCENE_H
-
-#include "treelayout.h"
+#ifndef DIGEST_TREE_SCENE_H
+#define DIGEST_TREE_SCENE_H
 
 #include <QtGui/QGraphicsScene>
 #include <QColor>
 #include <QMap>
 
 #ifndef Q_MOC_RUN
+#include "tree-layout.h"
 #include <sync-seq-no.h>
 #include <sync-logic.h>
 #include <ctime>
@@ -122,4 +121,4 @@
   QGraphicsRectItem *m_nickRectItem;
 };
 
-#endif
+#endif // DIGEST_TREE_SCENE_H
diff --git a/src/tree-layout.cpp b/src/tree-layout.cpp
new file mode 100644
index 0000000..7fba509
--- /dev/null
+++ b/src/tree-layout.cpp
@@ -0,0 +1,71 @@
+/* -*- 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>
+ *         Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+#include "tree-layout.h"
+
+#include <iostream>
+
+void
+OneLevelTreeLayout::setOneLevelLayout(std::vector<Coordinate> &childNodesCo)
+{
+  if (childNodesCo.empty())
+  {
+    return;
+  }
+  double y = getLevelDistance();
+  double sd = getSiblingDistance();
+  int n = childNodesCo.size();
+  double x = - (n - 1) * sd / 2;
+  for (int i = 0; i < n; i++)
+  {
+    childNodesCo[i].x = x;
+    childNodesCo[i].y = y;
+    x += sd;
+  }
+}
+
+void
+MultipleLevelTreeLayout::setMultipleLevelTreeLayout(TrustTreeNodeList& nodeList)
+{
+  if(nodeList.empty())
+    return;
+
+  double ld = getLevelDistance();
+  double sd = getSiblingDistance();
+
+  std::map<int, double> layerSpan;
+
+  TrustTreeNodeList::iterator it  = nodeList.begin();
+  TrustTreeNodeList::iterator end = nodeList.end();
+  for(; it != end; it++)
+    {
+      int layer = (*it)->level();
+      (*it)->y = layer * ld;
+      (*it)->x = layerSpan[layer];
+      layerSpan[layer] += sd;
+    }
+
+  std::map<int, double>::iterator layerIt  = layerSpan.begin();
+  std::map<int, double>::iterator layerEnd = layerSpan.end();
+  for(; layerIt != layerEnd; layerIt++)
+    {
+      double shift = (layerIt->second - sd) / 2;
+      layerIt->second = shift;
+    }
+
+  it  = nodeList.begin();
+  end = nodeList.end();
+  for(; it != end; it++)
+    {
+      (*it)->x -= layerSpan[(*it)->level()];
+    }
+}
diff --git a/src/treelayout.h b/src/tree-layout.h
similarity index 71%
rename from src/treelayout.h
rename to src/tree-layout.h
index 4942f62..99e8cca 100644
--- a/src/treelayout.h
+++ b/src/tree-layout.h
@@ -7,11 +7,14 @@
  *
  * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
  *         Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ *         Yingdi Yu <yingdi@cs.ucla.edu>
  */
 
-#ifndef TREELAYOUT_H
-#define TREELAYOUT_H
+#ifndef TREE_LAYOUT_H
+#define TREE_LAYOUT_H
+
 #include <vector>
+#include "trust-tree-node.h"
 
 class TreeLayout 
 {
@@ -33,11 +36,20 @@
   int m_levelDistance;
 };
 
-class OneLevelTreeLayout: public TreeLayout
+class OneLevelTreeLayout : public TreeLayout
 {
 public:
   OneLevelTreeLayout(){}
   virtual void setOneLevelLayout(std::vector<Coordinate> &childNodesCo);
   virtual ~OneLevelTreeLayout(){}
 };
-#endif
+
+class MultipleLevelTreeLayout : public TreeLayout
+{
+public:
+  MultipleLevelTreeLayout(){}
+  virtual ~MultipleLevelTreeLayout(){}
+  virtual void setMultipleLevelTreeLayout(TrustTreeNodeList& nodeList);
+};
+
+#endif // TREE_LAYOUT_H
diff --git a/src/treelayout.cpp b/src/treelayout.cpp
deleted file mode 100644
index c1fecf3..0000000
--- a/src/treelayout.cpp
+++ /dev/null
@@ -1,31 +0,0 @@
-/* -*- 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 "treelayout.h"
-
-void
-OneLevelTreeLayout::setOneLevelLayout(std::vector<Coordinate> &childNodesCo)
-{
-  if (childNodesCo.empty())
-  {
-    return;
-  }
-  double y = getLevelDistance();
-  double sd = getSiblingDistance();
-  int n = childNodesCo.size();
-  double x = - (n - 1) * sd / 2;
-  for (int i = 0; i < n; i++)
-  {
-    childNodesCo[i].x = x;
-    childNodesCo[i].y = y;
-    x += sd;
-  }
-}
diff --git a/src/trust-tree-node.h b/src/trust-tree-node.h
new file mode 100644
index 0000000..c080672
--- /dev/null
+++ b/src/trust-tree-node.h
@@ -0,0 +1,112 @@
+/* -*- 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: Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+#ifndef TRUST_TREE_NODE_H
+#define TRUST_TREE_NODE_H
+
+#include <vector>
+#include <ndn-cpp-dev/name.hpp>
+
+class TrustTreeNode;
+
+typedef std::vector<ndn::shared_ptr<TrustTreeNode> > TrustTreeNodeList;
+
+class TrustTreeNode
+{
+public:
+  TrustTreeNode()
+    : m_level(-1)
+    , m_visited(false)
+  {}
+
+  TrustTreeNode(const ndn::Name& name)
+    : m_name(name)
+    , m_level(-1)
+    , m_visited(false)
+  {}
+  
+  ~TrustTreeNode()
+  {}
+
+  const ndn::Name&
+  name()
+  {
+    return m_name;
+  }
+
+  void
+  addIntroducee(const ndn::shared_ptr<TrustTreeNode>& introducee)
+  {
+    m_introducees.push_back(introducee);
+  }
+
+  TrustTreeNodeList&
+  getIntroducees()
+  {
+    return m_introducees;
+  }
+
+  void
+  addIntroducer(const ndn::shared_ptr<TrustTreeNode>& introducer)
+  {
+    m_introducers.push_back(introducer);
+  }
+
+  TrustTreeNodeList&
+  getIntroducers()
+  {
+    return m_introducers;
+  }
+
+  void
+  setLevel(int level)
+  {
+    m_level = level;
+  }
+
+  int
+  level()
+  {
+    return m_level;
+  }
+
+  void
+  setVisited()
+  {
+    m_visited = true;
+  }
+
+  void
+  resetVisited()
+  {
+    m_visited = false;
+  }
+
+  bool
+  visited()
+  {
+    return m_visited;
+  }
+
+public:
+  double x;
+  double y;
+
+private:
+  ndn::Name m_name;
+  TrustTreeNodeList m_introducees;
+  TrustTreeNodeList m_introducers;
+  int m_level;
+  bool m_visited;
+};
+
+
+
+#endif // TRUST_TREE_NODE_H
diff --git a/src/trust-tree-scene.cpp b/src/trust-tree-scene.cpp
new file mode 100644
index 0000000..c62d82f
--- /dev/null
+++ b/src/trust-tree-scene.cpp
@@ -0,0 +1,117 @@
+/* -*- 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: Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+#include "trust-tree-scene.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;
+
+TrustTreeScene::TrustTreeScene(QWidget *parent)
+  : QGraphicsScene(parent) 
+{}
+
+void
+TrustTreeScene::plotTrustTree(TrustTreeNodeList& nodeList)
+{
+  clear();
+
+  int nodeSize = 40;
+  int siblingDistance = 100, levelDistance = 100;
+
+  boost::shared_ptr<MultipleLevelTreeLayout> layout(new MultipleLevelTreeLayout());
+  layout->setSiblingDistance(siblingDistance);
+  layout->setLevelDistance(levelDistance);
+  layout->setMultipleLevelTreeLayout(nodeList);
+
+  plotEdge(nodeList, nodeSize);
+  plotNode(nodeList, nodeSize);
+}
+
+void
+TrustTreeScene::plotEdge(const TrustTreeNodeList& nodeList, int nodeSize)
+{
+  TrustTreeNodeList::const_iterator it  = nodeList.begin();
+  TrustTreeNodeList::const_iterator end = nodeList.end();
+  for(; it != end; it++)
+    {
+      TrustTreeNodeList& introducees = (*it)->getIntroducees();
+      TrustTreeNodeList::iterator eeIt  = introducees.begin();
+      TrustTreeNodeList::iterator eeEnd = introducees.end();
+      
+      for(; eeIt != eeEnd; eeIt++)
+        {
+          if((*it)->level() >= (*eeIt)->level())
+            continue;
+          
+          double x1 = (*it)->x;
+          double y1 = (*it)->y;
+          double x2 = (*eeIt)->x;
+          double y2 = (*eeIt)->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 endP0 = src + QPointF((nodeSize/2) * line.dx() / line.dy(), nodeSize/2);
+          QPointF sourceArrowP0 = dest + QPointF((-nodeSize/2) * line.dx() / line.dy(), -nodeSize/2);
+          QPointF sourceArrowP1 = sourceArrowP0 + QPointF(-cos(angle - Pi / 6) * arrowSize,
+                                                          -sin(angle - Pi / 6) * arrowSize);
+          QPointF sourceArrowP2 = sourceArrowP0 + QPointF(-cos(angle + Pi / 6) * arrowSize,
+                                                          -sin(angle + Pi / 6) * arrowSize);
+
+          addLine(QLineF(sourceArrowP0, endP0), QPen(Qt::black));
+          addPolygon(QPolygonF() << sourceArrowP0 << sourceArrowP1 << sourceArrowP2, QPen(Qt::black), QBrush(Qt::black));
+        }
+    }
+}
+
+void
+TrustTreeScene::plotNode(const TrustTreeNodeList& nodeList, int nodeSize)
+{
+  int rim = 3;
+
+  // plot nodes
+  TrustTreeNodeList::const_iterator it  = nodeList.begin();
+  TrustTreeNodeList::const_iterator end = nodeList.end();
+  for(; it != end; it++)
+  {
+    double x = (*it)->x;
+    double y = (*it)->y;
+    QRectF boundingRect(x, y, nodeSize, nodeSize);
+    QRectF innerBoundingRect(x + rim, y + rim, nodeSize - rim * 2, nodeSize - rim * 2);
+    addRect(boundingRect, QPen(Qt::black), QBrush(Qt::darkBlue));
+    addRect(innerBoundingRect, QPen(Qt::black), QBrush(Qt::lightGray));
+
+    QRectF textRect(x - nodeSize / 2, y + nodeSize, 2 * nodeSize, 30);
+    addRect(textRect, QPen(Qt::darkCyan), QBrush(Qt::darkCyan));
+    QGraphicsTextItem *nickItem = addText(QString::fromStdString((*it)->name().toUri()));
+    QRectF textBoundingRect = nickItem->boundingRect();
+    nickItem->setDefaultTextColor(Qt::white);
+    nickItem->setFont(QFont("Cursive", 8, QFont::Bold));
+    nickItem->setPos(x - nodeSize / 2 + 10, y + nodeSize + 5);
+  }
+
+}
+
+#if WAF
+#include "trust-tree-scene.moc"
+#include "trust-tree-scene.cpp.moc"
+#endif
diff --git a/src/trust-tree-scene.h b/src/trust-tree-scene.h
new file mode 100644
index 0000000..59fdd8c
--- /dev/null
+++ b/src/trust-tree-scene.h
@@ -0,0 +1,42 @@
+/* -*- 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: Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+#ifndef TRUST_TREE_SCENE_H
+#define TRUST_TREE_SCENE_H
+
+
+
+#include <QtGui/QGraphicsScene>
+#include <QColor>
+#include <QMap>
+
+#ifndef Q_MOC_RUN
+#include <vector>
+#include "trust-tree-node.h"
+#include "tree-layout.h"
+#endif
+
+class QGraphicsTextItem;
+
+class TrustTreeScene : public QGraphicsScene
+{
+  Q_OBJECT
+
+public:
+  TrustTreeScene(QWidget *parent = 0);
+
+  void plotTrustTree(TrustTreeNodeList& nodeList);
+
+private:
+  void plotEdge(const TrustTreeNodeList& nodeList, int nodeSize);
+  void plotNode(const TrustTreeNodeList& nodeList, int nodeSize);
+};
+
+#endif // TRUST_TREE_SCENE_H