File indexing completed on 2024-05-05 04:59:12

0001 /***************************************************************************
0002  *   Copyright (C) 2007 by Joris Guisson and Ivan Vasic                    *
0003  *   joris.guisson@gmail.com                                               *
0004  *   ivasic@gmail.com                                                      *
0005  *                                                                         *
0006  *   This program is free software; you can redistribute it and/or modify  *
0007  *   it under the terms of the GNU General Public License as published by  *
0008  *   the Free Software Foundation; either version 2 of the License, or     *
0009  *   (at your option) any later version.                                   *
0010  *                                                                         *
0011  *   This program is distributed in the hope that it will be useful,       *
0012  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
0013  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
0014  *   GNU General Public License for more details.                          *
0015  *                                                                         *
0016  *   You should have received a copy of the GNU General Public License     *
0017  *   along with this program; if not, write to the                         *
0018  *   Free Software Foundation, Inc.,                                       *
0019  *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.          *
0020  ***************************************************************************/
0021 #include "chunkdownloadmodel.h"
0022 
0023 #include <interfaces/torrentfileinterface.h>
0024 #include <interfaces/torrentinterface.h>
0025 #include <util/functions.h>
0026 
0027 #include <KLocalizedString>
0028 
0029 using namespace bt;
0030 
0031 namespace kt
0032 {
0033 
0034 ChunkDownloadModel::Item::Item(ChunkDownloadInterface *cd, const QString &files)
0035     : cd(cd)
0036     , files(files)
0037 {
0038     cd->getStats(stats);
0039 }
0040 
0041 bool ChunkDownloadModel::Item::changed(int col, bool &modified) const
0042 {
0043     ChunkDownloadInterface::Stats s;
0044     cd->getStats(s);
0045     bool ret = false;
0046     switch (col) {
0047     case 1:
0048         ret = s.pieces_downloaded != stats.pieces_downloaded;
0049         break;
0050     case 2:
0051         ret = s.current_peer_id != stats.current_peer_id;
0052         break;
0053     case 3:
0054         ret = s.download_speed != stats.download_speed;
0055         break;
0056     default:
0057         break;
0058     }
0059 
0060     modified = s.pieces_downloaded != stats.pieces_downloaded || s.download_speed != stats.download_speed || s.current_peer_id != stats.current_peer_id;
0061 
0062     stats = s;
0063     return ret;
0064 }
0065 
0066 QVariant ChunkDownloadModel::Item::data(int col) const
0067 {
0068     switch (col) {
0069     case 0:
0070         return stats.chunk_index;
0071     case 1:
0072         return QString("%1 / %2").arg(stats.pieces_downloaded).arg(stats.total_pieces);
0073     case 2:
0074         return stats.current_peer_id;
0075     case 3:
0076         return BytesPerSecToString(stats.download_speed);
0077     case 4:
0078         return files;
0079     }
0080     return QVariant();
0081 }
0082 
0083 bool ChunkDownloadModel::Item::lessThan(int col, const Item *other) const
0084 {
0085     switch (col) {
0086     case 0:
0087         return stats.chunk_index < other->stats.chunk_index;
0088     case 1:
0089         return stats.pieces_downloaded < other->stats.pieces_downloaded;
0090     case 2:
0091         return stats.current_peer_id < other->stats.current_peer_id;
0092     case 3:
0093         return stats.download_speed < other->stats.download_speed;
0094     case 4:
0095         return files < other->files;
0096     }
0097     return false;
0098 }
0099 
0100 /////////////////////////////////////////////////////////////
0101 
0102 ChunkDownloadModel::ChunkDownloadModel(QObject *parent)
0103     : QAbstractTableModel(parent)
0104     , tc(nullptr)
0105 {
0106     sort_column = 0;
0107     sort_order = Qt::AscendingOrder;
0108 }
0109 
0110 ChunkDownloadModel::~ChunkDownloadModel()
0111 {
0112     qDeleteAll(items);
0113 }
0114 
0115 void ChunkDownloadModel::downloadAdded(bt::ChunkDownloadInterface *cd)
0116 {
0117     if (!tc)
0118         return;
0119 
0120     bt::ChunkDownloadInterface::Stats stats;
0121     cd->getStats(stats);
0122     QString files;
0123     int n = 0;
0124     if (tc->getStats().multi_file_torrent) {
0125         for (Uint32 i = 0; i < tc->getNumFiles(); ++i) {
0126             const bt::TorrentFileInterface &tf = tc->getTorrentFile(i);
0127             if (stats.chunk_index >= tf.getFirstChunk() && stats.chunk_index <= tf.getLastChunk()) {
0128                 if (n > 0)
0129                     files += '\n';
0130 
0131                 files += tf.getPath();
0132                 n++;
0133             } else if (stats.chunk_index < tf.getFirstChunk())
0134                 break;
0135         }
0136     }
0137 
0138     Item *nitem = new Item(cd, files);
0139     items.append(nitem);
0140     insertRow(items.count() - 1);
0141     sort(sort_column, sort_order);
0142 }
0143 
0144 void ChunkDownloadModel::downloadRemoved(bt::ChunkDownloadInterface *cd)
0145 {
0146     int idx = 0;
0147     for (QList<Item *>::iterator i = items.begin(); i != items.end(); i++) {
0148         const Item *item = *i;
0149         if (item->cd == cd) {
0150             items.erase(i);
0151             delete item;
0152             removeRow(idx);
0153             break;
0154         }
0155         idx++;
0156     }
0157 }
0158 
0159 void ChunkDownloadModel::changeTC(bt::TorrentInterface *tc)
0160 {
0161     beginResetModel();
0162     qDeleteAll(items);
0163     items.clear();
0164     this->tc = tc;
0165     endResetModel();
0166 }
0167 
0168 void ChunkDownloadModel::clear()
0169 {
0170     beginResetModel();
0171     qDeleteAll(items);
0172     items.clear();
0173     endResetModel();
0174 }
0175 
0176 void ChunkDownloadModel::update()
0177 {
0178     bool resort = false;
0179     Uint32 idx = 0;
0180     foreach (Item *i, items) {
0181         bool modified = false;
0182         if (i->changed(sort_column, modified))
0183             resort = true;
0184 
0185         if (modified && !resort)
0186             Q_EMIT dataChanged(index(idx, 1), index(idx, 3));
0187         idx++;
0188     }
0189 
0190     if (resort)
0191         sort(sort_column, sort_order);
0192 }
0193 
0194 int ChunkDownloadModel::rowCount(const QModelIndex &parent) const
0195 {
0196     if (parent.isValid())
0197         return 0;
0198     else
0199         return items.count();
0200 }
0201 
0202 int ChunkDownloadModel::columnCount(const QModelIndex &parent) const
0203 {
0204     if (parent.isValid())
0205         return 0;
0206     else
0207         return 5;
0208 }
0209 
0210 QVariant ChunkDownloadModel::headerData(int section, Qt::Orientation orientation, int role) const
0211 {
0212     if (orientation != Qt::Horizontal)
0213         return QVariant();
0214 
0215     if (role == Qt::DisplayRole) {
0216         switch (section) {
0217         case 0:
0218             return i18n("Chunk");
0219         case 1:
0220             return i18n("Progress");
0221         case 2:
0222             return i18n("Peer");
0223         case 3:
0224             return i18n("Down Speed");
0225         case 4:
0226             return i18n("Files");
0227         default:
0228             return QVariant();
0229         }
0230     } else if (role == Qt::ToolTipRole) {
0231         switch (section) {
0232         case 0:
0233             return i18n("Number of the chunk");
0234         case 1:
0235             return i18n("Download progress of the chunk");
0236         case 2:
0237             return i18n("Which peer we are downloading it from");
0238         case 3:
0239             return i18n("Download speed of the chunk");
0240         case 4:
0241             return i18n("Which files the chunk is located in");
0242         default:
0243             return QVariant();
0244         }
0245     }
0246 
0247     return QVariant();
0248 }
0249 
0250 QModelIndex ChunkDownloadModel::index(int row, int column, const QModelIndex &parent) const
0251 {
0252     if (!hasIndex(row, column, parent) || parent.isValid())
0253         return QModelIndex();
0254     else
0255         return createIndex(row, column, items[row]);
0256 }
0257 
0258 QVariant ChunkDownloadModel::data(const QModelIndex &index, int role) const
0259 {
0260     if (!index.isValid() || index.row() >= items.count() || index.row() < 0)
0261         return QVariant();
0262 
0263     if (role == Qt::DisplayRole)
0264         return items[index.row()]->data(index.column());
0265 
0266     return QVariant();
0267 }
0268 
0269 bool ChunkDownloadModel::removeRows(int row, int count, const QModelIndex & /*parent*/)
0270 {
0271     beginRemoveRows(QModelIndex(), row, row + count - 1);
0272     endRemoveRows();
0273     return true;
0274 }
0275 
0276 bool ChunkDownloadModel::insertRows(int row, int count, const QModelIndex & /*parent*/)
0277 {
0278     beginInsertRows(QModelIndex(), row, row + count - 1);
0279     endInsertRows();
0280     return true;
0281 }
0282 
0283 class ChunkDownloadModelItemCmp
0284 {
0285 public:
0286     ChunkDownloadModelItemCmp(int col, Qt::SortOrder order)
0287         : col(col)
0288         , order(order)
0289     {
0290     }
0291 
0292     bool operator()(ChunkDownloadModel::Item *a, ChunkDownloadModel::Item *b)
0293     {
0294         if (order == Qt::AscendingOrder)
0295             return a->lessThan(col, b);
0296         else
0297             return !a->lessThan(col, b);
0298     }
0299 
0300     int col;
0301     Qt::SortOrder order;
0302 };
0303 
0304 void ChunkDownloadModel::sort(int col, Qt::SortOrder order)
0305 {
0306     sort_column = col;
0307     sort_order = order;
0308     Q_EMIT layoutAboutToBeChanged();
0309     std::stable_sort(items.begin(), items.end(), ChunkDownloadModelItemCmp(col, order));
0310     Q_EMIT layoutChanged();
0311 }
0312 }
0313 
0314 #include "moc_chunkdownloadmodel.cpp"