bantablemodel.cpp raw

   1  // Copyright (c) 2011-present The Bitcoin Core developers
   2  // Distributed under the MIT software license, see the accompanying
   3  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
   4  
   5  #include <qt/bantablemodel.h>
   6  
   7  #include <interfaces/node.h>
   8  #include <net_types.h>
   9  
  10  #include <utility>
  11  
  12  #include <QDateTime>
  13  #include <QList>
  14  #include <QLocale>
  15  #include <QModelIndex>
  16  #include <QVariant>
  17  
  18  bool BannedNodeLessThan::operator()(const CCombinedBan& left, const CCombinedBan& right) const
  19  {
  20      const CCombinedBan* pLeft = &left;
  21      const CCombinedBan* pRight = &right;
  22  
  23      if (order == Qt::DescendingOrder)
  24          std::swap(pLeft, pRight);
  25  
  26      switch (static_cast<BanTableModel::ColumnIndex>(column)) {
  27      case BanTableModel::Address:
  28          return pLeft->subnet.ToString().compare(pRight->subnet.ToString()) < 0;
  29      case BanTableModel::Bantime:
  30          return pLeft->banEntry.nBanUntil < pRight->banEntry.nBanUntil;
  31      } // no default case, so the compiler can warn about missing cases
  32      assert(false);
  33  }
  34  
  35  // private implementation
  36  class BanTablePriv
  37  {
  38  public:
  39      /** Local cache of peer information */
  40      QList<CCombinedBan> cachedBanlist;
  41      /** Column to sort nodes by (default to unsorted) */
  42      int sortColumn{-1};
  43      /** Order (ascending or descending) to sort nodes by */
  44      Qt::SortOrder sortOrder;
  45  
  46      /** Pull a full list of banned nodes from interfaces::Node into our cache */
  47      void refreshBanlist(interfaces::Node& node)
  48      {
  49          banmap_t banMap;
  50          node.getBanned(banMap);
  51  
  52          cachedBanlist.clear();
  53          cachedBanlist.reserve(banMap.size());
  54          for (const auto& entry : banMap)
  55          {
  56              CCombinedBan banEntry;
  57              banEntry.subnet = entry.first;
  58              banEntry.banEntry = entry.second;
  59              cachedBanlist.append(banEntry);
  60          }
  61  
  62          if (sortColumn >= 0)
  63              // sort cachedBanlist (use stable sort to prevent rows jumping around unnecessarily)
  64              std::stable_sort(cachedBanlist.begin(), cachedBanlist.end(), BannedNodeLessThan(sortColumn, sortOrder));
  65      }
  66  
  67      int size() const
  68      {
  69          return cachedBanlist.size();
  70      }
  71  
  72      CCombinedBan *index(int idx)
  73      {
  74          if (idx >= 0 && idx < cachedBanlist.size())
  75              return &cachedBanlist[idx];
  76  
  77          return nullptr;
  78      }
  79  };
  80  
  81  BanTableModel::BanTableModel(interfaces::Node& node, QObject* parent) :
  82      QAbstractTableModel(parent),
  83      m_node(node)
  84  {
  85      columns << tr("IP/Netmask") << tr("Banned Until");
  86      priv.reset(new BanTablePriv());
  87  
  88      // load initial data
  89      refresh();
  90  }
  91  
  92  BanTableModel::~BanTableModel() = default;
  93  
  94  int BanTableModel::rowCount(const QModelIndex &parent) const
  95  {
  96      if (parent.isValid()) {
  97          return 0;
  98      }
  99      return priv->size();
 100  }
 101  
 102  int BanTableModel::columnCount(const QModelIndex &parent) const
 103  {
 104      if (parent.isValid()) {
 105          return 0;
 106      }
 107      return columns.length();
 108  }
 109  
 110  QVariant BanTableModel::data(const QModelIndex &index, int role) const
 111  {
 112      if(!index.isValid())
 113          return QVariant();
 114  
 115      CCombinedBan *rec = static_cast<CCombinedBan*>(index.internalPointer());
 116  
 117      const auto column = static_cast<ColumnIndex>(index.column());
 118      if (role == Qt::DisplayRole) {
 119          switch (column) {
 120          case Address:
 121              return QString::fromStdString(rec->subnet.ToString());
 122          case Bantime:
 123              QDateTime date = QDateTime::fromMSecsSinceEpoch(0);
 124              date = date.addSecs(rec->banEntry.nBanUntil);
 125              return QLocale::system().toString(date, QLocale::LongFormat);
 126          } // no default case, so the compiler can warn about missing cases
 127          assert(false);
 128      }
 129  
 130      return QVariant();
 131  }
 132  
 133  QVariant BanTableModel::headerData(int section, Qt::Orientation orientation, int role) const
 134  {
 135      if(orientation == Qt::Horizontal)
 136      {
 137          if(role == Qt::DisplayRole && section < columns.size())
 138          {
 139              return columns[section];
 140          }
 141      }
 142      return QVariant();
 143  }
 144  
 145  Qt::ItemFlags BanTableModel::flags(const QModelIndex &index) const
 146  {
 147      if (!index.isValid()) return Qt::NoItemFlags;
 148  
 149      Qt::ItemFlags retval = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
 150      return retval;
 151  }
 152  
 153  QModelIndex BanTableModel::index(int row, int column, const QModelIndex &parent) const
 154  {
 155      Q_UNUSED(parent);
 156      CCombinedBan *data = priv->index(row);
 157  
 158      if (data)
 159          return createIndex(row, column, data);
 160      return QModelIndex();
 161  }
 162  
 163  void BanTableModel::refresh()
 164  {
 165      Q_EMIT layoutAboutToBeChanged();
 166      priv->refreshBanlist(m_node);
 167      Q_EMIT layoutChanged();
 168  }
 169  
 170  void BanTableModel::sort(int column, Qt::SortOrder order)
 171  {
 172      priv->sortColumn = column;
 173      priv->sortOrder = order;
 174      refresh();
 175  }
 176  
 177  bool BanTableModel::shouldShow()
 178  {
 179      return priv->size() > 0;
 180  }
 181  
 182  bool BanTableModel::unban(const QModelIndex& index)
 183  {
 184      CCombinedBan* ban{static_cast<CCombinedBan*>(index.internalPointer())};
 185      return ban != nullptr && m_node.unban(ban->subnet);
 186  }
 187