Finish forwarder status information dispaly

- Add channel display
- Add strategy choice display

Change-Id: I4e1923b8a0ed0220150c71a3736f6fd618c30abe
diff --git a/src/channel-status.cpp b/src/channel-status.cpp
new file mode 100644
index 0000000..17c1714
--- /dev/null
+++ b/src/channel-status.cpp
@@ -0,0 +1,95 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2017, Regents of the University of California,
+ *
+ * This file is part of NFD Control Center.  See AUTHORS.md for complete list of NFD
+ * authors and contributors.
+ *
+ * NFD Control Center is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD Control Center is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with NFD
+ * Control Center, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "channel-status.hpp"
+#include "channel-status.moc"
+
+namespace ndn {
+
+ChannelStatusModel::ChannelStatusModel(QObject* parent/* = 0*/)
+  : QAbstractListModel(parent)
+{
+  connect(this, SIGNAL(onDataReceived(std::vector<ndn::nfd::ChannelStatus>)), this,
+          SLOT(updateStatus(std::vector<ndn::nfd::ChannelStatus>)),
+          Qt::QueuedConnection);
+}
+
+int
+ChannelStatusModel::rowCount(const QModelIndex& parent/* = QModelIndex()*/) const
+{
+  return m_items.count();
+}
+
+void
+ChannelStatusModel::addItem(const ChannelStatusItem& item)
+{
+  beginInsertRows(QModelIndex(), rowCount(), rowCount());
+  m_items << item;
+  endInsertRows();
+}
+
+QVariant
+ChannelStatusModel::data(const QModelIndex& index, int role) const
+{
+  if (index.row() < 0 || index.row() >= m_items.count()) {
+    return QVariant();
+  }
+
+  const ChannelStatusItem& item = m_items.at(index.row());
+  if (role == ChannelRole) {
+    return item.channel();
+  }
+
+  return QVariant();
+}
+
+QHash<int, QByteArray>
+ChannelStatusModel::roleNames() const
+{
+  QHash<int, QByteArray> roles;
+  roles[ChannelRole] = "channel";
+  return roles;
+}
+
+void
+ChannelStatusModel::clear()
+{
+  beginResetModel();
+  m_items.clear();
+  endResetModel();
+}
+
+void
+ChannelStatusModel::updateStatus(std::vector<ndn::nfd::ChannelStatus> status)
+{
+  beginResetModel();
+  m_items.clear();
+  for (auto const& channel : status) {
+    addItem(ChannelStatusItem(QString::fromStdString(channel.getLocalUri())));
+  }
+  endResetModel();
+}
+
+void
+ChannelStatusModel::onTimeout()
+{
+  std::cerr << "Request timed out (should not really happen)" << std::endl;
+}
+
+} // namespace ndn
diff --git a/src/channel-status.hpp b/src/channel-status.hpp
new file mode 100644
index 0000000..45658b3
--- /dev/null
+++ b/src/channel-status.hpp
@@ -0,0 +1,95 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2017, Regents of the University of California,
+ *
+ * This file is part of NFD Control Center.  See AUTHORS.md for complete list of NFD
+ * authors and contributors.
+ *
+ * NFD Control Center is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD Control Center is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with NFD
+ * Control Center, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NCC_CHANNEL_STATUS_HPP
+#define NCC_CHANNEL_STATUS_HPP
+
+#include <QtCore/QAbstractListModel>
+#include <QtCore/QStringList>
+
+#include <ndn-cxx/mgmt/nfd/channel-status.hpp>
+
+namespace ndn {
+
+class ChannelStatusItem
+{
+public:
+  ChannelStatusItem(const QString& channel)
+    : m_channel(channel)
+  {
+  }
+
+  const QString&
+  channel() const
+  {
+    return m_channel;
+  }
+
+private:
+  QString m_channel;
+};
+
+
+class ChannelStatusModel : public QAbstractListModel
+{
+  Q_OBJECT
+
+signals:
+  void
+  onDataReceived(std::vector<ndn::nfd::ChannelStatus> status);
+
+public:
+
+  enum ChannelStatusRoles {
+    ChannelRole = Qt::UserRole + 1
+  };
+
+  explicit
+  ChannelStatusModel(QObject* parent = 0);
+
+  int
+  rowCount(const QModelIndex& parent = QModelIndex()) const;
+
+  void
+  addItem(const ChannelStatusItem& item);
+
+  QVariant
+  data(const QModelIndex& index, int role) const;
+
+  QHash<int, QByteArray>
+  roleNames() const;
+
+  void
+  clear();
+
+  void
+  onTimeout();
+
+private slots:
+
+  void
+  updateStatus(std::vector<ndn::nfd::ChannelStatus> status);
+
+private:
+  QList<ChannelStatusItem> m_items;
+};
+
+} // namespace ndn
+
+#endif // NCC_CHANNEL_STATUS_HPP
diff --git a/src/main.cpp b/src/main.cpp
index 9d42157..9cfff3a 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -28,7 +28,6 @@
 #include <ndn-cxx/name.hpp>
 #include <ndn-cxx/util/scheduler.hpp>
 #include <ndn-cxx/mgmt/nfd/fib-entry.hpp>
-#include <ndn-cxx/mgmt/nfd/rib-entry.hpp>
 #include <ndn-cxx/mgmt/nfd/controller.hpp>
 #include <ndn-cxx/mgmt/nfd/status-dataset.hpp>
 
@@ -161,6 +160,8 @@
 Q_DECLARE_METATYPE(std::vector<ndn::nfd::FibEntry>)
 Q_DECLARE_METATYPE(std::vector<ndn::nfd::RibEntry>)
 Q_DECLARE_METATYPE(std::vector<ndn::nfd::FaceStatus>)
+Q_DECLARE_METATYPE(std::vector<ndn::nfd::ChannelStatus>)
+Q_DECLARE_METATYPE(std::vector<ndn::nfd::StrategyChoice>)
 
 int
 main(int argc, char *argv[])
@@ -170,6 +171,8 @@
   qRegisterMetaType<std::vector<ndn::nfd::FibEntry>>();
   qRegisterMetaType<std::vector<ndn::nfd::RibEntry>>();
   qRegisterMetaType<std::vector<ndn::nfd::FaceStatus>>();
+  qRegisterMetaType<std::vector<ndn::nfd::ChannelStatus>>();
+  qRegisterMetaType<std::vector<ndn::nfd::StrategyChoice>>();
 
   QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
   QApplication app(argc, argv);
diff --git a/src/main.qml b/src/main.qml
index 0ae8d29..c134df4 100644
--- a/src/main.qml
+++ b/src/main.qml
@@ -128,7 +128,6 @@
                 anchors.bottomMargin: 20
                 anchors.leftMargin: 20
             }
-
             Row {
                 spacing: 20
                 anchors.topMargin: 30
diff --git a/src/rib-status.cpp b/src/rib-status.cpp
index 2b80773..4a928d3 100644
--- a/src/rib-status.cpp
+++ b/src/rib-status.cpp
@@ -107,7 +107,7 @@
   for (auto const& ribEntry : status) {
     bool isSamePrefix = false;
     for (auto const& route : ribEntry.getRoutes()) {
-      QString expirationPeriod = route.hasInfiniteExpirationPeriod() ? QString("Never") :
+      QString expirationPeriod = route.hasExpirationPeriod() ? QString("Never") :
                                  QString::fromStdString(std::to_string(route.getExpirationPeriod().count()));
       if (!isSamePrefix) {
         addItem(RibStatusItem(QString::fromStdString(ribEntry.getName().toUri()), route.getFaceId(), route.getOrigin(),
diff --git a/src/status-viewer.cpp b/src/status-viewer.cpp
index 6bc5879..f4f81f4 100644
--- a/src/status-viewer.cpp
+++ b/src/status-viewer.cpp
@@ -31,9 +31,11 @@
   QQmlContext* s_context = s_engine.rootContext();
 
   s_context->setContextProperty("forwarderModel", &s_forwarderStatusModel);
+  s_context->setContextProperty("channelModel", &s_channelModel);
   s_context->setContextProperty("faceModel", &s_faceModel);
   s_context->setContextProperty("fibModel", &s_fibModel);
   s_context->setContextProperty("ribModel", &s_ribModel);
+  s_context->setContextProperty("strategyModel", &s_strategyModel);
   s_context->setContextProperty("statusViewer", this);
 
   s_engine.load((QUrl("qrc:/status.qml")));
@@ -46,6 +48,12 @@
 }
 
 void
+StatusViewer::onChannelStatusRetrieved(const std::vector<nfd::ChannelStatus>& status)
+{
+  emit s_channelModel.onDataReceived(status);
+}
+
+void
 StatusViewer::onFaceStatusRetrieved(const std::vector<nfd::FaceStatus>& status)
 {
   emit s_faceModel.onDataReceived(status);
@@ -64,6 +72,12 @@
 }
 
 void
+StatusViewer::onStrategyChoiceStatusRetrieved(const std::vector<nfd::StrategyChoice>& status)
+{
+  emit s_strategyModel.onDataReceived(status);
+}
+
+void
 StatusViewer::onStatusTimeout()
 {
   std::cerr << "Should not really happen, most likely a serious problem" << std::endl;
@@ -74,13 +88,17 @@
 StatusViewer::requestNfdStatus()
 {
   s_controller->fetch<ndn::nfd::ForwarderGeneralStatusDataset>(bind(&StatusViewer::onStatusRetrieved, this, _1),
-                                                              bind(&StatusViewer::onStatusTimeout, this));
+                                                               bind(&StatusViewer::onStatusTimeout, this));
+  s_controller->fetch<ndn::nfd::ChannelDataset>(bind(&StatusViewer::onChannelStatusRetrieved, this, _1),
+                                                bind(&StatusViewer::onStatusTimeout, this));
   s_controller->fetch<ndn::nfd::FaceDataset>(bind(&StatusViewer::onFaceStatusRetrieved, this, _1),
                                              bind(&StatusViewer::onStatusTimeout, this));
   s_controller->fetch<ndn::nfd::FibDataset>(bind(&StatusViewer::onFibStatusRetrieved, this, _1),
-                                           bind(&StatusViewer::onStatusTimeout, this));
+                                            bind(&StatusViewer::onStatusTimeout, this));
   s_controller->fetch<ndn::nfd::RibDataset>(bind(&StatusViewer::onRibStatusRetrieved, this, _1),
-                                           bind(&StatusViewer::onStatusTimeout, this));
+                                            bind(&StatusViewer::onStatusTimeout, this));
+  s_controller->fetch<ndn::nfd::StrategyChoiceDataset>(bind(&StatusViewer::onStrategyChoiceStatusRetrieved, this, _1),
+                                                       bind(&StatusViewer::onStatusTimeout, this));
   s_scheduler.scheduleEvent(time::seconds(15), bind(&StatusViewer::requestNfdStatus, this));
 }
 
diff --git a/src/status-viewer.hpp b/src/status-viewer.hpp
index b627bdb..ac815b8 100644
--- a/src/status-viewer.hpp
+++ b/src/status-viewer.hpp
@@ -21,16 +21,20 @@
 #define NCC_STATUS_VIEWER_HPP
 
 #include "forwarder-status.hpp"
+#include "channel-status.hpp"
 #include "face-status.hpp"
 #include "fib-status.hpp"
 #include "rib-status.hpp"
+#include "strategy-status.hpp"
 
 #include <ndn-cxx/face.hpp>
 #include <ndn-cxx/name.hpp>
 #include <ndn-cxx/util/scheduler.hpp>
+#include <ndn-cxx/mgmt/nfd/channel-status.hpp>
 #include <ndn-cxx/mgmt/nfd/face-status.hpp>
 #include <ndn-cxx/mgmt/nfd/fib-entry.hpp>
 #include <ndn-cxx/mgmt/nfd/rib-entry.hpp>
+#include <ndn-cxx/mgmt/nfd/strategy-choice.hpp>
 #include <ndn-cxx/mgmt/nfd/controller.hpp>
 #include <ndn-cxx/mgmt/nfd/status-dataset.hpp>
 
@@ -51,6 +55,9 @@
   onStatusRetrieved(const nfd::ForwarderStatus& status);
 
   void
+  onChannelStatusRetrieved(const std::vector<nfd::ChannelStatus>& status);
+
+  void
   onFaceStatusRetrieved(const std::vector<nfd::FaceStatus>& status);
 
   void
@@ -60,6 +67,9 @@
   onRibStatusRetrieved(const std::vector<nfd::RibEntry>& status);
 
   void
+  onStrategyChoiceStatusRetrieved(const std::vector<nfd::StrategyChoice>& status);
+
+  void
   onStatusTimeout();
 
 private:
@@ -83,9 +93,11 @@
   QQmlApplicationEngine s_engine;
 
   ForwarderStatusModel s_forwarderStatusModel;
+  ChannelStatusModel s_channelModel;
   FaceStatusModel s_faceModel;
   FibStatusModel s_fibModel;
   RibStatusModel s_ribModel;
+  StrategyStatusModel s_strategyModel;
 };
 
 } // namespace ndn
diff --git a/src/status.qml b/src/status.qml
index c4bb56c..27f89bf 100644
--- a/src/status.qml
+++ b/src/status.qml
@@ -39,6 +39,22 @@
             }
         }
         Tab {
+            title: "Channel"
+            TableView {
+                anchors.fill: parent
+                anchors.topMargin: 20
+                anchors.bottomMargin: 20
+                anchors.leftMargin: 20
+                anchors.rightMargin: 20
+                model: channelModel
+                TableViewColumn{
+                    role: "channel"
+                    title: "Channel"
+                    width: 500
+                }
+            }
+        }
+        Tab {
             title: "Face"
             TableView {
                 anchors.fill: parent
@@ -191,6 +207,27 @@
                 }
             }
         }
+        Tab {
+            title: "Strategy"
+            TableView {
+                anchors.fill: parent
+                anchors.topMargin: 20
+                anchors.bottomMargin: 20
+                anchors.leftMargin: 20
+                anchors.rightMargin: 20
+                model: strategyModel
+                TableViewColumn{
+                    role: "prefix"
+                    title: "NDN prefix"
+                    width: 300
+                }
+                TableViewColumn{
+                    role: "strategy"
+                    title: "Strategy Choice"
+                    width: 300
+                }
+            }
+        }
     }
     Connections {
         target: statusViewer;
diff --git a/src/strategy-status.cpp b/src/strategy-status.cpp
new file mode 100644
index 0000000..f970120
--- /dev/null
+++ b/src/strategy-status.cpp
@@ -0,0 +1,100 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2017, Regents of the University of California,
+ *
+ * This file is part of NFD Control Center.  See AUTHORS.md for complete list of NFD
+ * authors and contributors.
+ *
+ * NFD Control Center is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD Control Center is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with NFD
+ * Control Center, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "strategy-status.hpp"
+#include "strategy-status.moc"
+
+namespace ndn {
+
+StrategyStatusModel::StrategyStatusModel(QObject* parent/* = 0*/)
+  : QAbstractListModel(parent)
+{
+  connect(this, SIGNAL(onDataReceived(std::vector<ndn::nfd::StrategyChoice>)), this,
+          SLOT(updateStatus(std::vector<ndn::nfd::StrategyChoice>)),
+          Qt::QueuedConnection);
+}
+
+int
+StrategyStatusModel::rowCount(const QModelIndex& parent/* = QModelIndex()*/) const
+{
+  return m_items.count();
+}
+
+void
+StrategyStatusModel::addItem(const StrategyStatusItem& item)
+{
+  beginInsertRows(QModelIndex(), rowCount(), rowCount());
+  m_items << item;
+  endInsertRows();
+}
+
+QVariant
+StrategyStatusModel::data(const QModelIndex& index, int role) const
+{
+  if (index.row() < 0 || index.row() >= m_items.count()) {
+    return QVariant();
+  }
+
+  const StrategyStatusItem& item = m_items.at(index.row());
+  if (role == PrefixRole) {
+    return item.prefix();
+  }
+  else if (role == StrategyRole) {
+    return item.strategy();
+  }
+
+  return QVariant();
+}
+
+QHash<int, QByteArray>
+StrategyStatusModel::roleNames() const
+{
+  QHash<int, QByteArray> roles;
+  roles[PrefixRole] = "prefix";
+  roles[StrategyRole] = "strategy";
+  return roles;
+}
+
+void
+StrategyStatusModel::clear()
+{
+  beginResetModel();
+  m_items.clear();
+  endResetModel();
+}
+
+void
+StrategyStatusModel::updateStatus(std::vector<ndn::nfd::StrategyChoice> status)
+{
+  beginResetModel();
+  m_items.clear();
+  for (auto const& strategy : status) {
+    addItem(StrategyStatusItem(QString::fromStdString(strategy.getName().toUri()),
+                               QString::fromStdString(strategy.getStrategy().toUri())));
+  }
+  endResetModel();
+}
+
+void
+StrategyStatusModel::onTimeout()
+{
+  std::cerr << "Request timed out (should not really happen)" << std::endl;
+}
+
+} // namespace ndn
diff --git a/src/strategy-status.hpp b/src/strategy-status.hpp
new file mode 100644
index 0000000..9b885c4
--- /dev/null
+++ b/src/strategy-status.hpp
@@ -0,0 +1,102 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2017, Regents of the University of California,
+ *
+ * This file is part of NFD Control Center.  See AUTHORS.md for complete list of NFD
+ * authors and contributors.
+ *
+ * NFD Control Center is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD Control Center is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with NFD
+ * Control Center, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NCC_STRATEGY_STATUS_HPP
+#define NCC_STRATEGY_STATUS_HPP
+
+#include <QtCore/QAbstractListModel>
+#include <QtCore/QStringList>
+
+#include <ndn-cxx/mgmt/nfd/strategy-choice.hpp>
+
+namespace ndn {
+
+class StrategyStatusItem
+{
+public:
+  StrategyStatusItem(const QString& prefix, const QString& strategy)
+    : m_prefix(prefix)
+    , m_strategy(strategy)
+  {
+  }
+
+  const QString&
+  prefix() const
+  {
+    return m_prefix;
+  }
+
+  const QString&
+  strategy() const
+  {
+    return m_strategy;
+  }
+
+private:
+  QString m_prefix;
+  QString m_strategy;
+};
+
+class StrategyStatusModel : public QAbstractListModel
+{
+  Q_OBJECT
+
+signals:
+  void
+  onDataReceived(std::vector<ndn::nfd::StrategyChoice> status);
+
+public:
+  enum StrategyStatusRoles {
+    PrefixRole = Qt::UserRole + 1,
+    StrategyRole
+  };
+
+  explicit
+  StrategyStatusModel(QObject* parent = 0);
+
+  int
+  rowCount(const QModelIndex& parent = QModelIndex()) const;
+
+  void
+  addItem(const StrategyStatusItem& item);
+
+  QVariant
+  data(const QModelIndex& index, int role) const;
+
+  QHash<int, QByteArray>
+  roleNames() const;
+
+  void
+  clear();
+
+  void
+  onTimeout();
+
+private slots:
+
+  void
+  updateStatus(std::vector<ndn::nfd::StrategyChoice> status);
+
+private:
+  QList<StrategyStatusItem> m_items;
+};
+
+} // namespace ndn
+
+#endif // NCC_STRATEGY_STATUS_HPP
diff --git a/wscript b/wscript
index 0b9396e..575167c 100644
--- a/wscript
+++ b/wscript
@@ -42,7 +42,7 @@
         features=['qt5', 'cxxprogram', 'cxx'],
         includes = ". src",
         use = "NDN_CXX BOOST QT5CORE QT5DBUS QT5QML QT5WIDGETS",
-        moc = "src/tray-menu.hpp src/key-tree-model.hpp src/key-viewer-dialog.hpp src/cert-tree-model.hpp src/status-viewer.hpp src/face-status.hpp src/fib-status.hpp src/rib-status.hpp src/forwarder-status.hpp",
+        moc = "src/tray-menu.hpp src/key-tree-model.hpp src/key-viewer-dialog.hpp src/cert-tree-model.hpp src/status-viewer.hpp src/channel-status.hpp src/face-status.hpp src/fib-status.hpp src/rib-status.hpp src/strategy-status.hpp src/forwarder-status.hpp",
         source = bld.path.ant_glob(['src/*.cpp', 'src/**/*.qrc', 'src/**/*.ui', 'src/**/*.qrc'], excl=['src/osx-*']),
         )