2010-11-14 22:32:29 +03:00
/*
2015-06-07 15:03:30 +03:00
* Bittorrent Client using Qt and libtorrent .
* Copyright ( C ) 2015 Vladimir Golovnev < glassez @ yandex . ru >
* Copyright ( C ) 2010 Christophe Dumez < chris @ qbittorrent . org >
2010-11-14 22:32:29 +03:00
*
* This program 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 2
* of the License , or ( at your option ) any later version .
*
* This program 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 this program ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA .
*
* In addition , as a special exception , the copyright holders give permission to
* link this program with the OpenSSL project ' s " OpenSSL " library ( or with
* modified versions of it that use the same license as the " OpenSSL " library ) ,
* and distribute the linked executables . You must obey the GNU General Public
* License in all respects for all of the code used other than " OpenSSL " . If you
* modify file ( s ) , you may extend this exception to your version of the file ( s ) ,
* but you are not obligated to do so . If you do not wish to do so , delete this
* exception statement from your version .
*/
2018-06-14 12:54:23 +03:00
# include "transferlistmodel.h"
2018-06-06 16:48:17 +03:00
2015-04-12 16:23:06 +03:00
# include <QApplication>
2019-03-02 08:22:13 +03:00
# include <QDateTime>
2018-06-06 16:48:17 +03:00
# include <QDebug>
2010-11-14 18:28:22 +03:00
2022-10-08 06:43:52 +03:00
# include "base/bittorrent/infohash.h"
2015-09-25 11:10:05 +03:00
# include "base/bittorrent/session.h"
2021-01-06 15:12:40 +03:00
# include "base/bittorrent/torrent.h"
2018-11-18 21:40:37 +03:00
# include "base/global.h"
2019-12-17 21:57:36 +03:00
# include "base/preferences.h"
2022-08-27 08:01:24 +03:00
# include "base/types.h"
2019-12-17 21:57:36 +03:00
# include "base/unicodestrings.h"
2015-09-25 11:10:05 +03:00
# include "base/utils/fs.h"
2019-12-17 21:57:36 +03:00
# include "base/utils/misc.h"
# include "base/utils/string.h"
2020-05-06 14:07:37 +03:00
# include "uithememanager.h"
2010-11-14 18:28:22 +03:00
2022-05-26 22:12:10 +03:00
namespace
{
2020-05-06 14:07:37 +03:00
QHash < BitTorrent : : TorrentState , QColor > torrentStateColorsFromUITheme ( )
{
struct TorrentStateColorDescriptor
{
const BitTorrent : : TorrentState state ;
const QString id ;
} ;
const TorrentStateColorDescriptor colorDescriptors [ ] =
{
2022-03-29 05:41:17 +03:00
{ BitTorrent : : TorrentState : : Downloading , u " TransferList.Downloading " _qs } ,
{ BitTorrent : : TorrentState : : StalledDownloading , u " TransferList.StalledDownloading " _qs } ,
{ BitTorrent : : TorrentState : : DownloadingMetadata , u " TransferList.DownloadingMetadata " _qs } ,
{ BitTorrent : : TorrentState : : ForcedDownloadingMetadata , u " TransferList.ForcedDownloadingMetadata " _qs } ,
{ BitTorrent : : TorrentState : : ForcedDownloading , u " TransferList.ForcedDownloading " _qs } ,
{ BitTorrent : : TorrentState : : Uploading , u " TransferList.Uploading " _qs } ,
{ BitTorrent : : TorrentState : : StalledUploading , u " TransferList.StalledUploading " _qs } ,
{ BitTorrent : : TorrentState : : ForcedUploading , u " TransferList.ForcedUploading " _qs } ,
{ BitTorrent : : TorrentState : : QueuedDownloading , u " TransferList.QueuedDownloading " _qs } ,
{ BitTorrent : : TorrentState : : QueuedUploading , u " TransferList.QueuedUploading " _qs } ,
{ BitTorrent : : TorrentState : : CheckingDownloading , u " TransferList.CheckingDownloading " _qs } ,
{ BitTorrent : : TorrentState : : CheckingUploading , u " TransferList.CheckingUploading " _qs } ,
{ BitTorrent : : TorrentState : : CheckingResumeData , u " TransferList.CheckingResumeData " _qs } ,
{ BitTorrent : : TorrentState : : PausedDownloading , u " TransferList.PausedDownloading " _qs } ,
{ BitTorrent : : TorrentState : : PausedUploading , u " TransferList.PausedUploading " _qs } ,
{ BitTorrent : : TorrentState : : Moving , u " TransferList.Moving " _qs } ,
{ BitTorrent : : TorrentState : : MissingFiles , u " TransferList.MissingFiles " _qs } ,
{ BitTorrent : : TorrentState : : Error , u " TransferList.Error " _qs }
2020-05-06 14:07:37 +03:00
} ;
QHash < BitTorrent : : TorrentState , QColor > colors ;
2020-11-16 10:02:11 +03:00
for ( const TorrentStateColorDescriptor & colorDescriptor : colorDescriptors )
{
2023-02-07 22:07:15 +03:00
const QColor themeColor = UIThemeManager : : instance ( ) - > getColor ( colorDescriptor . id ) ;
colors . insert ( colorDescriptor . state , themeColor ) ;
2020-05-06 14:07:37 +03:00
}
return colors ;
}
}
2018-06-14 12:54:23 +03:00
// TransferListModel
2014-05-11 15:29:06 +04:00
2018-06-14 12:54:23 +03:00
TransferListModel : : TransferListModel ( QObject * parent )
2019-12-17 21:57:36 +03:00
: QAbstractListModel { parent }
2020-11-16 10:02:11 +03:00
, m_statusStrings
{
2019-12-17 21:57:36 +03:00
{ BitTorrent : : TorrentState : : Downloading , tr ( " Downloading " ) } ,
{ BitTorrent : : TorrentState : : StalledDownloading , tr ( " Stalled " , " Torrent is waiting for download to begin " ) } ,
{ BitTorrent : : TorrentState : : DownloadingMetadata , tr ( " Downloading metadata " , " Used when loading a magnet link " ) } ,
2021-07-17 21:33:14 +03:00
{ BitTorrent : : TorrentState : : ForcedDownloadingMetadata , tr ( " [F] Downloading metadata " , " Used when forced to load a magnet link. You probably shouldn't translate the F. " ) } ,
2019-12-17 21:57:36 +03:00
{ BitTorrent : : TorrentState : : ForcedDownloading , tr ( " [F] Downloading " , " Used when the torrent is forced started. You probably shouldn't translate the F. " ) } ,
{ BitTorrent : : TorrentState : : Uploading , tr ( " Seeding " , " Torrent is complete and in upload-only mode " ) } ,
{ BitTorrent : : TorrentState : : StalledUploading , tr ( " Seeding " , " Torrent is complete and in upload-only mode " ) } ,
{ BitTorrent : : TorrentState : : ForcedUploading , tr ( " [F] Seeding " , " Used when the torrent is forced started. You probably shouldn't translate the F. " ) } ,
{ BitTorrent : : TorrentState : : QueuedDownloading , tr ( " Queued " , " Torrent is queued " ) } ,
{ BitTorrent : : TorrentState : : QueuedUploading , tr ( " Queued " , " Torrent is queued " ) } ,
{ BitTorrent : : TorrentState : : CheckingDownloading , tr ( " Checking " , " Torrent local data is being checked " ) } ,
{ BitTorrent : : TorrentState : : CheckingUploading , tr ( " Checking " , " Torrent local data is being checked " ) } ,
{ BitTorrent : : TorrentState : : CheckingResumeData , tr ( " Checking resume data " , " Used when loading the torrents from disk after qbt is launched. It checks the correctness of the .fastresume file. Normally it is completed in a fraction of a second, unless loading many many torrents. " ) } ,
{ BitTorrent : : TorrentState : : PausedDownloading , tr ( " Paused " ) } ,
{ BitTorrent : : TorrentState : : PausedUploading , tr ( " Completed " ) } ,
{ BitTorrent : : TorrentState : : Moving , tr ( " Moving " , " Torrent local data are being moved/relocated " ) } ,
{ BitTorrent : : TorrentState : : MissingFiles , tr ( " Missing Files " ) } ,
{ BitTorrent : : TorrentState : : Error , tr ( " Errored " , " Torrent status, the torrent has an error " ) }
2022-05-26 22:46:14 +03:00
}
2020-05-06 14:07:37 +03:00
, m_stateThemeColors { torrentStateColorsFromUITheme ( ) }
2022-12-25 16:25:56 +03:00
, m_checkingIcon { UIThemeManager : : instance ( ) - > getIcon ( u " force-recheck " _qs , u " checking " _qs ) }
, m_completedIcon { UIThemeManager : : instance ( ) - > getIcon ( u " checked-completed " _qs , u " completed " _qs ) }
2022-05-26 22:46:14 +03:00
, m_downloadingIcon { UIThemeManager : : instance ( ) - > getIcon ( u " downloading " _qs ) }
, m_errorIcon { UIThemeManager : : instance ( ) - > getIcon ( u " error " _qs ) }
2023-01-27 18:46:39 +03:00
, m_pausedIcon { UIThemeManager : : instance ( ) - > getIcon ( u " stopped " _qs , u " media-playback-pause " _qs ) }
2022-05-26 22:46:14 +03:00
, m_queuedIcon { UIThemeManager : : instance ( ) - > getIcon ( u " queued " _qs ) }
, m_stalledDLIcon { UIThemeManager : : instance ( ) - > getIcon ( u " stalledDL " _qs ) }
, m_stalledUPIcon { UIThemeManager : : instance ( ) - > getIcon ( u " stalledUP " _qs ) }
2022-12-25 16:25:56 +03:00
, m_uploadingIcon { UIThemeManager : : instance ( ) - > getIcon ( u " upload " _qs , u " uploading " _qs ) }
2015-06-07 15:03:30 +03:00
{
2020-01-23 11:20:38 +03:00
configure ( ) ;
connect ( Preferences : : instance ( ) , & Preferences : : changed , this , & TransferListModel : : configure ) ;
2015-06-07 15:03:30 +03:00
// Load the torrents
2018-04-18 16:59:41 +03:00
using namespace BitTorrent ;
2022-07-04 12:48:21 +03:00
addTorrents ( Session : : instance ( ) - > torrents ( ) ) ;
2014-05-11 15:29:06 +04:00
2015-06-07 15:03:30 +03:00
// Listen for torrent changes
2022-07-04 12:48:21 +03:00
connect ( Session : : instance ( ) , & Session : : torrentsLoaded , this , & TransferListModel : : addTorrents ) ;
2018-06-14 12:54:23 +03:00
connect ( Session : : instance ( ) , & Session : : torrentAboutToBeRemoved , this , & TransferListModel : : handleTorrentAboutToBeRemoved ) ;
connect ( Session : : instance ( ) , & Session : : torrentsUpdated , this , & TransferListModel : : handleTorrentsUpdated ) ;
connect ( Session : : instance ( ) , & Session : : torrentFinished , this , & TransferListModel : : handleTorrentStatusUpdated ) ;
2020-12-02 09:16:11 +03:00
connect ( Session : : instance ( ) , & Session : : torrentMetadataReceived , this , & TransferListModel : : handleTorrentStatusUpdated ) ;
2018-06-14 12:54:23 +03:00
connect ( Session : : instance ( ) , & Session : : torrentResumed , this , & TransferListModel : : handleTorrentStatusUpdated ) ;
connect ( Session : : instance ( ) , & Session : : torrentPaused , this , & TransferListModel : : handleTorrentStatusUpdated ) ;
connect ( Session : : instance ( ) , & Session : : torrentFinishedChecking , this , & TransferListModel : : handleTorrentStatusUpdated ) ;
2014-05-11 15:29:06 +04:00
}
2019-08-17 12:09:31 +03:00
int TransferListModel : : rowCount ( const QModelIndex & ) const
2015-03-28 22:09:13 +03:00
{
2019-08-17 12:09:31 +03:00
return m_torrentList . size ( ) ;
2015-03-28 22:09:13 +03:00
}
2019-08-17 12:09:31 +03:00
int TransferListModel : : columnCount ( const QModelIndex & ) const
2010-11-14 18:28:22 +03:00
{
2015-06-07 15:03:30 +03:00
return NB_COLUMNS ;
2010-11-14 18:28:22 +03:00
}
2022-06-22 10:47:13 +03:00
QVariant TransferListModel : : headerData ( const int section , const Qt : : Orientation orientation , const int role ) const
2015-04-19 18:17:47 +03:00
{
2020-11-16 10:02:11 +03:00
if ( orientation = = Qt : : Horizontal )
{
if ( role = = Qt : : DisplayRole )
{
switch ( section )
{
2022-03-19 10:57:41 +03:00
case TR_QUEUE_POSITION : return QChar ( u ' # ' ) ;
2015-06-07 15:03:30 +03:00
case TR_NAME : return tr ( " Name " , " i.e: torrent name " ) ;
case TR_SIZE : return tr ( " Size " , " i.e: torrent size " ) ;
2020-10-28 07:58:20 +03:00
case TR_PROGRESS : return tr ( " Progress " , " % Done " ) ;
2015-06-07 15:03:30 +03:00
case TR_STATUS : return tr ( " Status " , " Torrent status (e.g. downloading, seeding, paused) " ) ;
case TR_SEEDS : return tr ( " Seeds " , " i.e. full sources (often untranslated) " ) ;
case TR_PEERS : return tr ( " Peers " , " i.e. partial sources (often untranslated) " ) ;
case TR_DLSPEED : return tr ( " Down Speed " , " i.e: Download speed " ) ;
case TR_UPSPEED : return tr ( " Up Speed " , " i.e: Upload speed " ) ;
case TR_RATIO : return tr ( " Ratio " , " Share ratio " ) ;
case TR_ETA : return tr ( " ETA " , " i.e: Estimated Time of Arrival / Time left " ) ;
2016-02-09 11:56:48 +03:00
case TR_CATEGORY : return tr ( " Category " ) ;
2017-06-05 03:22:17 +03:00
case TR_TAGS : return tr ( " Tags " ) ;
2015-06-07 15:03:30 +03:00
case TR_ADD_DATE : return tr ( " Added On " , " Torrent was added to transfer list on 01/01/2010 08:00 " ) ;
case TR_SEED_DATE : return tr ( " Completed On " , " Torrent was completed on 01/01/2010 08:00 " ) ;
case TR_TRACKER : return tr ( " Tracker " ) ;
case TR_DLLIMIT : return tr ( " Down Limit " , " i.e: Download limit " ) ;
case TR_UPLIMIT : return tr ( " Up Limit " , " i.e: Upload limit " ) ;
case TR_AMOUNT_DOWNLOADED : return tr ( " Downloaded " , " Amount of data downloaded (e.g. in MB) " ) ;
case TR_AMOUNT_UPLOADED : return tr ( " Uploaded " , " Amount of data uploaded (e.g. in MB) " ) ;
case TR_AMOUNT_DOWNLOADED_SESSION : return tr ( " Session Download " , " Amount of data downloaded since program open (e.g. in MB) " ) ;
case TR_AMOUNT_UPLOADED_SESSION : return tr ( " Session Upload " , " Amount of data uploaded since program open (e.g. in MB) " ) ;
case TR_AMOUNT_LEFT : return tr ( " Remaining " , " Amount of data left to download (e.g. in MB) " ) ;
case TR_TIME_ELAPSED : return tr ( " Time Active " , " Time (duration) the torrent is active (not paused) " ) ;
2022-10-08 19:16:00 +03:00
case TR_SAVE_PATH : return tr ( " Save Path " , " Torrent save path " ) ;
2022-10-08 06:43:52 +03:00
case TR_DOWNLOAD_PATH : return tr ( " Incomplete Save Path " , " Torrent incomplete save path " ) ;
2015-06-07 15:03:30 +03:00
case TR_COMPLETED : return tr ( " Completed " , " Amount of data completed (e.g. in MB) " ) ;
case TR_RATIO_LIMIT : return tr ( " Ratio Limit " , " Upload share ratio limit " ) ;
case TR_SEEN_COMPLETE_DATE : return tr ( " Last Seen Complete " , " Indicates the time when the torrent was last seen complete/whole " ) ;
case TR_LAST_ACTIVITY : return tr ( " Last Activity " , " Time passed since a chunk was downloaded/uploaded " ) ;
case TR_TOTAL_SIZE : return tr ( " Total Size " , " i.e. Size including unwanted data " ) ;
2019-07-21 10:20:54 +03:00
case TR_AVAILABILITY : return tr ( " Availability " , " The number of distributed copies of the torrent " ) ;
2022-10-08 06:43:52 +03:00
case TR_INFOHASH_V1 : return tr ( " Info Hash v1 " , " i.e: torrent info hash v1 " ) ;
case TR_INFOHASH_V2 : return tr ( " Info Hash v2 " , " i.e: torrent info hash v2 " ) ;
2019-07-21 10:20:54 +03:00
default : return { } ;
2015-06-07 15:03:30 +03:00
}
}
2020-11-16 10:02:11 +03:00
else if ( role = = Qt : : TextAlignmentRole )
{
switch ( section )
{
2015-06-07 15:03:30 +03:00
case TR_AMOUNT_DOWNLOADED :
case TR_AMOUNT_UPLOADED :
case TR_AMOUNT_DOWNLOADED_SESSION :
case TR_AMOUNT_UPLOADED_SESSION :
case TR_AMOUNT_LEFT :
case TR_COMPLETED :
case TR_SIZE :
case TR_TOTAL_SIZE :
case TR_ETA :
case TR_SEEDS :
case TR_PEERS :
case TR_UPSPEED :
case TR_DLSPEED :
case TR_UPLIMIT :
case TR_DLLIMIT :
case TR_RATIO_LIMIT :
case TR_RATIO :
2018-12-08 02:01:09 +03:00
case TR_QUEUE_POSITION :
2015-06-07 15:03:30 +03:00
case TR_LAST_ACTIVITY :
2019-07-21 10:20:54 +03:00
case TR_AVAILABILITY :
2019-02-22 04:59:31 +03:00
return QVariant ( Qt : : AlignRight | Qt : : AlignVCenter ) ;
2015-06-07 15:03:30 +03:00
default :
return QAbstractListModel : : headerData ( section , orientation , role ) ;
}
}
2015-02-25 12:48:40 +03:00
}
2014-10-25 14:12:05 +04:00
2022-06-22 10:47:13 +03:00
return QAbstractListModel : : headerData ( section , orientation , role ) ;
2014-10-25 14:12:05 +04:00
}
2021-01-06 15:12:40 +03:00
QString TransferListModel : : displayValue ( const BitTorrent : : Torrent * torrent , const int column ) const
2010-11-14 18:28:22 +03:00
{
2020-01-23 11:20:38 +03:00
bool hideValues = false ;
if ( m_hideZeroValuesMode = = HideZeroValuesMode : : Always )
hideValues = true ;
2021-02-06 06:25:17 +03:00
else if ( m_hideZeroValuesMode = = HideZeroValuesMode : : Paused )
2020-01-23 11:20:38 +03:00
hideValues = ( torrent - > state ( ) = = BitTorrent : : TorrentState : : PausedDownloading ) ;
2015-04-19 18:17:47 +03:00
2019-12-17 21:57:36 +03:00
const auto availabilityString = [ hideValues ] ( const qreal value ) - > QString
{
2021-02-06 06:09:17 +03:00
if ( hideValues & & ( value = = 0 ) )
return { } ;
return ( value > = 0 )
? Utils : : String : : fromDouble ( value , 3 )
: tr ( " N/A " ) ;
2019-12-17 21:57:36 +03:00
} ;
2010-11-14 18:28:22 +03:00
2019-12-17 21:57:36 +03:00
const auto unitString = [ hideValues ] ( const qint64 value , const bool isSpeedUnit = false ) - > QString
{
2020-10-11 20:22:27 +03:00
return ( hideValues & & ( value = = 0 ) )
2019-12-17 21:57:36 +03:00
? QString { } : Utils : : Misc : : friendlyUnit ( value , isSpeedUnit ) ;
} ;
2015-04-19 18:17:47 +03:00
2019-12-17 21:57:36 +03:00
const auto limitString = [ hideValues ] ( const qint64 value ) - > QString
{
2021-02-06 06:49:04 +03:00
if ( hideValues & & ( value < = 0 ) )
2019-12-17 21:57:36 +03:00
return { } ;
2015-04-19 18:17:47 +03:00
2019-12-17 21:57:36 +03:00
return ( value > 0 )
? Utils : : Misc : : friendlyUnit ( value , true )
2022-03-12 17:00:58 +03:00
: C_INFINITY ;
2019-12-17 21:57:36 +03:00
} ;
2015-04-19 18:17:47 +03:00
2019-12-17 21:57:36 +03:00
const auto amountString = [ hideValues ] ( const qint64 value , const qint64 total ) - > QString
{
2021-02-06 06:25:17 +03:00
if ( hideValues & & ( value = = 0 ) & & ( total = = 0 ) )
return { } ;
2022-03-29 05:41:17 +03:00
return u " %1 (%2) " _qs . arg ( QString : : number ( value ) , QString : : number ( total ) ) ;
2019-12-17 21:57:36 +03:00
} ;
2021-02-06 06:59:37 +03:00
const auto etaString = [ hideValues ] ( const qlonglong value ) - > QString
{
if ( hideValues & & ( value > = MAX_ETA ) )
return { } ;
return Utils : : Misc : : userFriendlyDuration ( value , MAX_ETA ) ;
} ;
2019-12-17 21:57:36 +03:00
const auto ratioString = [ hideValues ] ( const qreal value ) - > QString
{
2020-10-11 20:22:27 +03:00
if ( hideValues & & ( value < = 0 ) )
2019-12-17 21:57:36 +03:00
return { } ;
2021-01-06 15:12:40 +03:00
return ( ( static_cast < int > ( value ) = = - 1 ) | | ( value > BitTorrent : : Torrent : : MAX_RATIO ) )
2022-03-12 17:00:58 +03:00
? C_INFINITY : Utils : : String : : fromDouble ( value , 2 ) ;
2019-12-17 21:57:36 +03:00
} ;
const auto queuePositionString = [ ] ( const qint64 value ) - > QString
{
2022-03-29 05:41:17 +03:00
return ( value > = 0 ) ? QString : : number ( value + 1 ) : u " * " _qs ;
2019-12-17 21:57:36 +03:00
} ;
const auto lastActivityString = [ hideValues ] ( qint64 value ) - > QString
{
if ( hideValues & & ( ( value < 0 ) | | ( value > = MAX_ETA ) ) )
2021-02-06 06:25:17 +03:00
return { } ;
2019-12-17 21:57:36 +03:00
// Show '< 1m ago' when elapsed time is 0
if ( value = = 0 )
value = 1 ;
return ( value > = 0 )
? tr ( " %1 ago " , " e.g.: 1h 20m ago " ) . arg ( Utils : : Misc : : userFriendlyDuration ( value ) )
: Utils : : Misc : : userFriendlyDuration ( value ) ;
} ;
2021-02-06 06:45:35 +03:00
const auto timeElapsedString = [ hideValues ] ( const qint64 elapsedTime , const qint64 seedingTime ) - > QString
2019-12-17 21:57:36 +03:00
{
if ( seedingTime < = 0 )
2021-02-06 06:45:35 +03:00
{
if ( hideValues & & ( elapsedTime = = 0 ) )
return { } ;
2019-12-17 21:57:36 +03:00
return Utils : : Misc : : userFriendlyDuration ( elapsedTime ) ;
2021-02-06 06:45:35 +03:00
}
2019-12-17 21:57:36 +03:00
return tr ( " %1 (seeded for %2) " , " e.g. 4m39s (seeded for 3m10s) " )
. arg ( Utils : : Misc : : userFriendlyDuration ( elapsedTime )
, Utils : : Misc : : userFriendlyDuration ( seedingTime ) ) ;
} ;
2020-11-29 15:16:14 +03:00
const auto progressString = [ ] ( const qreal progress ) - > QString
2019-12-17 21:57:36 +03:00
{
2020-11-29 15:16:14 +03:00
return ( progress > = 1 )
2022-03-29 05:41:17 +03:00
? u " 100% " _qs
: ( Utils : : String : : fromDouble ( ( progress * 100 ) , 1 ) + u ' % ' ) ;
2019-12-17 21:57:36 +03:00
} ;
const auto statusString = [ this ] ( const BitTorrent : : TorrentState state , const QString & errorMessage ) - > QString
{
return ( state = = BitTorrent : : TorrentState : : Error )
2022-03-12 17:00:58 +03:00
? m_statusStrings [ state ] + u " : " + errorMessage
2019-12-17 21:57:36 +03:00
: m_statusStrings [ state ] ;
} ;
2022-10-08 19:09:43 +03:00
const auto hashString = [ hideValues ] ( const auto & hash ) - > QString
{
if ( hideValues & & ! hash . isValid ( ) )
return { } ;
return hash . isValid ( ) ? hash . toString ( ) : tr ( " N/A " ) ;
} ;
2020-11-16 10:02:11 +03:00
switch ( column )
{
2019-12-17 21:57:36 +03:00
case TR_NAME :
return torrent - > name ( ) ;
case TR_QUEUE_POSITION :
return queuePositionString ( torrent - > queuePosition ( ) ) ;
case TR_SIZE :
return unitString ( torrent - > wantedSize ( ) ) ;
case TR_PROGRESS :
return progressString ( torrent - > progress ( ) ) ;
case TR_STATUS :
return statusString ( torrent - > state ( ) , torrent - > error ( ) ) ;
case TR_SEEDS :
return amountString ( torrent - > seedsCount ( ) , torrent - > totalSeedsCount ( ) ) ;
case TR_PEERS :
return amountString ( torrent - > leechsCount ( ) , torrent - > totalLeechersCount ( ) ) ;
case TR_DLSPEED :
return unitString ( torrent - > downloadPayloadRate ( ) , true ) ;
case TR_UPSPEED :
return unitString ( torrent - > uploadPayloadRate ( ) , true ) ;
case TR_ETA :
2021-02-06 06:59:37 +03:00
return etaString ( torrent - > eta ( ) ) ;
2019-12-17 21:57:36 +03:00
case TR_RATIO :
return ratioString ( torrent - > realRatio ( ) ) ;
case TR_RATIO_LIMIT :
return ratioString ( torrent - > maxRatio ( ) ) ;
case TR_CATEGORY :
return torrent - > category ( ) ;
case TR_TAGS :
2022-03-29 05:41:17 +03:00
return torrent - > tags ( ) . join ( u " , " _qs ) ;
2019-12-17 21:57:36 +03:00
case TR_ADD_DATE :
2021-01-06 07:47:18 +03:00
return QLocale ( ) . toString ( torrent - > addedTime ( ) . toLocalTime ( ) , QLocale : : ShortFormat ) ;
2019-12-17 21:57:36 +03:00
case TR_SEED_DATE :
2021-01-06 07:47:18 +03:00
return QLocale ( ) . toString ( torrent - > completedTime ( ) . toLocalTime ( ) , QLocale : : ShortFormat ) ;
2019-12-17 21:57:36 +03:00
case TR_TRACKER :
return torrent - > currentTracker ( ) ;
case TR_DLLIMIT :
return limitString ( torrent - > downloadLimit ( ) ) ;
case TR_UPLIMIT :
return limitString ( torrent - > uploadLimit ( ) ) ;
case TR_AMOUNT_DOWNLOADED :
return unitString ( torrent - > totalDownload ( ) ) ;
case TR_AMOUNT_UPLOADED :
return unitString ( torrent - > totalUpload ( ) ) ;
case TR_AMOUNT_DOWNLOADED_SESSION :
return unitString ( torrent - > totalPayloadDownload ( ) ) ;
case TR_AMOUNT_UPLOADED_SESSION :
return unitString ( torrent - > totalPayloadUpload ( ) ) ;
case TR_AMOUNT_LEFT :
2020-04-19 16:12:50 +03:00
return unitString ( torrent - > remainingSize ( ) ) ;
2019-12-17 21:57:36 +03:00
case TR_TIME_ELAPSED :
2022-01-07 10:22:51 +03:00
return timeElapsedString ( torrent - > activeTime ( ) , torrent - > finishedTime ( ) ) ;
2019-12-17 21:57:36 +03:00
case TR_SAVE_PATH :
2022-02-08 06:03:48 +03:00
return torrent - > savePath ( ) . toString ( ) ;
2022-10-08 06:43:52 +03:00
case TR_DOWNLOAD_PATH :
return torrent - > downloadPath ( ) . toString ( ) ;
2019-12-17 21:57:36 +03:00
case TR_COMPLETED :
return unitString ( torrent - > completedSize ( ) ) ;
case TR_SEEN_COMPLETE_DATE :
2021-01-06 07:47:18 +03:00
return QLocale ( ) . toString ( torrent - > lastSeenComplete ( ) . toLocalTime ( ) , QLocale : : ShortFormat ) ;
2019-12-17 21:57:36 +03:00
case TR_LAST_ACTIVITY :
2021-04-19 06:24:07 +03:00
return lastActivityString ( torrent - > timeSinceActivity ( ) ) ;
2019-12-17 21:57:36 +03:00
case TR_AVAILABILITY :
return availabilityString ( torrent - > distributedCopies ( ) ) ;
case TR_TOTAL_SIZE :
return unitString ( torrent - > totalSize ( ) ) ;
2022-10-08 06:43:52 +03:00
case TR_INFOHASH_V1 :
2022-10-08 19:09:43 +03:00
return hashString ( torrent - > infoHash ( ) . v1 ( ) ) ;
2022-10-08 06:43:52 +03:00
case TR_INFOHASH_V2 :
2022-10-08 19:09:43 +03:00
return hashString ( torrent - > infoHash ( ) . v2 ( ) ) ;
2019-12-17 21:57:36 +03:00
}
return { } ;
}
2021-01-06 15:12:40 +03:00
QVariant TransferListModel : : internalValue ( const BitTorrent : : Torrent * torrent , const int column , const bool alt ) const
2019-12-17 21:57:36 +03:00
{
2020-11-16 10:02:11 +03:00
switch ( column )
{
2015-02-25 12:48:40 +03:00
case TR_NAME :
2015-06-07 15:03:30 +03:00
return torrent - > name ( ) ;
2018-12-08 02:01:09 +03:00
case TR_QUEUE_POSITION :
2015-06-07 15:03:30 +03:00
return torrent - > queuePosition ( ) ;
2015-02-25 12:48:40 +03:00
case TR_SIZE :
2015-06-07 15:03:30 +03:00
return torrent - > wantedSize ( ) ;
2015-02-25 12:48:40 +03:00
case TR_PROGRESS :
2019-12-17 21:57:36 +03:00
return torrent - > progress ( ) * 100 ;
2015-02-25 12:48:40 +03:00
case TR_STATUS :
2019-12-17 21:57:36 +03:00
return QVariant : : fromValue ( torrent - > state ( ) ) ;
2015-04-19 18:17:47 +03:00
case TR_SEEDS :
2019-12-17 21:57:36 +03:00
return ! alt ? torrent - > seedsCount ( ) : torrent - > totalSeedsCount ( ) ;
2015-04-19 18:17:47 +03:00
case TR_PEERS :
2019-12-17 21:57:36 +03:00
return ! alt ? torrent - > leechsCount ( ) : torrent - > totalLeechersCount ( ) ;
2015-02-25 12:48:40 +03:00
case TR_DLSPEED :
2015-06-07 15:03:30 +03:00
return torrent - > downloadPayloadRate ( ) ;
2015-02-25 12:48:40 +03:00
case TR_UPSPEED :
2015-06-07 15:03:30 +03:00
return torrent - > uploadPayloadRate ( ) ;
2015-04-19 18:17:47 +03:00
case TR_ETA :
2015-06-07 15:03:30 +03:00
return torrent - > eta ( ) ;
2015-02-25 12:48:40 +03:00
case TR_RATIO :
2015-06-07 15:03:30 +03:00
return torrent - > realRatio ( ) ;
2016-02-09 11:56:48 +03:00
case TR_CATEGORY :
return torrent - > category ( ) ;
2019-12-17 21:57:36 +03:00
case TR_TAGS :
2021-04-02 08:45:50 +03:00
return QVariant : : fromValue ( torrent - > tags ( ) ) ;
2015-02-25 12:48:40 +03:00
case TR_ADD_DATE :
2015-06-07 15:03:30 +03:00
return torrent - > addedTime ( ) ;
2015-02-25 12:48:40 +03:00
case TR_SEED_DATE :
2015-06-07 15:03:30 +03:00
return torrent - > completedTime ( ) ;
2015-02-25 12:48:40 +03:00
case TR_TRACKER :
2015-06-07 15:03:30 +03:00
return torrent - > currentTracker ( ) ;
2015-02-25 12:48:40 +03:00
case TR_DLLIMIT :
2015-06-07 15:03:30 +03:00
return torrent - > downloadLimit ( ) ;
2015-02-25 12:48:40 +03:00
case TR_UPLIMIT :
2015-06-07 15:03:30 +03:00
return torrent - > uploadLimit ( ) ;
2015-02-25 12:48:40 +03:00
case TR_AMOUNT_DOWNLOADED :
2015-06-07 15:03:30 +03:00
return torrent - > totalDownload ( ) ;
2015-02-25 12:48:40 +03:00
case TR_AMOUNT_UPLOADED :
2015-06-07 15:03:30 +03:00
return torrent - > totalUpload ( ) ;
2015-03-16 17:41:39 +03:00
case TR_AMOUNT_DOWNLOADED_SESSION :
2015-06-07 15:03:30 +03:00
return torrent - > totalPayloadDownload ( ) ;
2015-03-16 17:41:39 +03:00
case TR_AMOUNT_UPLOADED_SESSION :
2015-06-07 15:03:30 +03:00
return torrent - > totalPayloadUpload ( ) ;
2015-02-25 12:48:40 +03:00
case TR_AMOUNT_LEFT :
2020-04-19 16:12:50 +03:00
return torrent - > remainingSize ( ) ;
2015-02-25 12:48:40 +03:00
case TR_TIME_ELAPSED :
2022-01-07 10:22:51 +03:00
return ! alt ? torrent - > activeTime ( ) : torrent - > finishedTime ( ) ;
2022-10-08 06:43:52 +03:00
case TR_DOWNLOAD_PATH :
return torrent - > downloadPath ( ) . data ( ) ;
2015-02-25 12:48:40 +03:00
case TR_SAVE_PATH :
2022-10-08 19:12:35 +03:00
return torrent - > savePath ( ) . data ( ) ;
2015-02-25 12:48:40 +03:00
case TR_COMPLETED :
2015-06-07 15:03:30 +03:00
return torrent - > completedSize ( ) ;
2015-04-19 18:17:47 +03:00
case TR_RATIO_LIMIT :
2015-06-07 15:03:30 +03:00
return torrent - > maxRatio ( ) ;
2015-02-25 12:48:40 +03:00
case TR_SEEN_COMPLETE_DATE :
2015-06-07 15:03:30 +03:00
return torrent - > lastSeenComplete ( ) ;
2015-02-25 12:48:40 +03:00
case TR_LAST_ACTIVITY :
2021-04-19 06:24:07 +03:00
return torrent - > timeSinceActivity ( ) ;
2019-07-21 10:20:54 +03:00
case TR_AVAILABILITY :
return torrent - > distributedCopies ( ) ;
2015-02-25 12:48:40 +03:00
case TR_TOTAL_SIZE :
2017-01-08 03:46:01 +03:00
return torrent - > totalSize ( ) ;
2022-10-08 06:43:52 +03:00
case TR_INFOHASH_V1 :
return QVariant : : fromValue ( torrent - > infoHash ( ) . v1 ( ) ) ;
case TR_INFOHASH_V2 :
return QVariant : : fromValue ( torrent - > infoHash ( ) . v2 ( ) ) ;
2015-02-25 12:48:40 +03:00
}
2010-11-14 18:28:22 +03:00
2019-02-14 20:16:42 +03:00
return { } ;
2015-03-22 02:18:21 +03:00
}
2019-12-17 21:57:36 +03:00
QVariant TransferListModel : : data ( const QModelIndex & index , const int role ) const
{
if ( ! index . isValid ( ) ) return { } ;
2021-01-06 15:12:40 +03:00
const BitTorrent : : Torrent * torrent = m_torrentList . value ( index . row ( ) ) ;
2019-12-17 21:57:36 +03:00
if ( ! torrent ) return { } ;
2020-11-16 10:02:11 +03:00
switch ( role )
{
2019-12-17 21:57:36 +03:00
case Qt : : ForegroundRole :
2023-02-07 22:07:15 +03:00
return m_stateThemeColors . value ( torrent - > state ( ) ) ;
2019-12-17 21:57:36 +03:00
case Qt : : DisplayRole :
return displayValue ( torrent , index . column ( ) ) ;
case UnderlyingDataRole :
2021-03-18 07:04:46 +03:00
return internalValue ( torrent , index . column ( ) , false ) ;
2019-12-17 21:57:36 +03:00
case AdditionalUnderlyingDataRole :
return internalValue ( torrent , index . column ( ) , true ) ;
case Qt : : DecorationRole :
if ( index . column ( ) = = TR_NAME )
return getIconByState ( torrent - > state ( ) ) ;
break ;
2020-05-01 10:30:45 +03:00
case Qt : : ToolTipRole :
2020-11-16 10:02:11 +03:00
switch ( index . column ( ) )
{
2020-05-01 10:30:45 +03:00
case TR_NAME :
case TR_STATUS :
case TR_CATEGORY :
case TR_TAGS :
case TR_TRACKER :
case TR_SAVE_PATH :
2022-10-08 06:43:52 +03:00
case TR_DOWNLOAD_PATH :
case TR_INFOHASH_V1 :
case TR_INFOHASH_V2 :
2020-05-01 10:30:45 +03:00
return displayValue ( torrent , index . column ( ) ) ;
}
break ;
2019-12-17 21:57:36 +03:00
case Qt : : TextAlignmentRole :
2020-11-16 10:02:11 +03:00
switch ( index . column ( ) )
{
2019-12-17 21:57:36 +03:00
case TR_AMOUNT_DOWNLOADED :
case TR_AMOUNT_UPLOADED :
case TR_AMOUNT_DOWNLOADED_SESSION :
case TR_AMOUNT_UPLOADED_SESSION :
case TR_AMOUNT_LEFT :
case TR_COMPLETED :
case TR_SIZE :
case TR_TOTAL_SIZE :
case TR_ETA :
case TR_SEEDS :
case TR_PEERS :
case TR_UPSPEED :
case TR_DLSPEED :
case TR_UPLIMIT :
case TR_DLLIMIT :
case TR_RATIO_LIMIT :
case TR_RATIO :
case TR_QUEUE_POSITION :
case TR_LAST_ACTIVITY :
case TR_AVAILABILITY :
2022-06-22 10:47:13 +03:00
return QVariant ( Qt : : AlignRight | Qt : : AlignVCenter ) ;
2019-12-17 21:57:36 +03:00
}
2022-06-22 10:47:13 +03:00
break ;
default :
break ;
2019-12-17 21:57:36 +03:00
}
return { } ;
}
2018-06-14 12:54:23 +03:00
bool TransferListModel : : setData ( const QModelIndex & index , const QVariant & value , int role )
2010-11-14 18:28:22 +03:00
{
2015-06-07 15:03:30 +03:00
if ( ! index . isValid ( ) | | ( role ! = Qt : : DisplayRole ) ) return false ;
2010-11-14 18:28:22 +03:00
2021-01-06 15:12:40 +03:00
BitTorrent : : Torrent * const torrent = m_torrentList . value ( index . row ( ) ) ;
2015-06-07 15:03:30 +03:00
if ( ! torrent ) return false ;
2015-04-19 18:17:47 +03:00
2019-08-07 09:04:03 +03:00
// Category and Name columns can be edited
2020-11-16 10:02:11 +03:00
switch ( index . column ( ) )
{
2015-06-07 15:03:30 +03:00
case TR_NAME :
torrent - > setName ( value . toString ( ) ) ;
break ;
2016-02-09 11:56:48 +03:00
case TR_CATEGORY :
torrent - > setCategory ( value . toString ( ) ) ;
2015-06-07 15:03:30 +03:00
break ;
default :
return false ;
}
2015-04-19 18:17:47 +03:00
2015-06-07 15:03:30 +03:00
return true ;
2010-11-14 18:28:22 +03:00
}
2022-07-04 12:48:21 +03:00
void TransferListModel : : addTorrents ( const QVector < BitTorrent : : Torrent * > & torrents )
2015-06-07 15:03:30 +03:00
{
2022-11-02 11:35:40 +03:00
qsizetype row = m_torrentList . size ( ) ;
const qsizetype total = row + torrents . size ( ) ;
2019-08-17 12:09:31 +03:00
2022-11-02 11:35:40 +03:00
beginInsertRows ( { } , row , total ) ;
m_torrentList . reserve ( total ) ;
2022-07-04 12:48:21 +03:00
for ( BitTorrent : : Torrent * torrent : torrents )
{
Q_ASSERT ( ! m_torrentMap . contains ( torrent ) ) ;
m_torrentList . append ( torrent ) ;
m_torrentMap [ torrent ] = row + + ;
}
2019-08-17 12:09:31 +03:00
endInsertRows ( ) ;
2010-11-14 18:28:22 +03:00
}
2018-06-14 12:54:23 +03:00
Qt : : ItemFlags TransferListModel : : flags ( const QModelIndex & index ) const
2010-11-14 18:28:22 +03:00
{
2018-09-07 14:12:38 +03:00
if ( ! index . isValid ( ) ) return Qt : : NoItemFlags ;
2010-11-14 18:28:22 +03:00
2015-06-07 15:03:30 +03:00
// Explicitly mark as editable
return QAbstractListModel : : flags ( index ) | Qt : : ItemIsEditable ;
2010-11-14 18:28:22 +03:00
}
2021-01-06 15:12:40 +03:00
BitTorrent : : Torrent * TransferListModel : : torrentHandle ( const QModelIndex & index ) const
2010-11-14 18:28:22 +03:00
{
2018-09-07 14:12:38 +03:00
if ( ! index . isValid ( ) ) return nullptr ;
2015-04-19 18:17:47 +03:00
2019-08-17 12:09:31 +03:00
return m_torrentList . value ( index . row ( ) ) ;
2010-11-14 18:28:22 +03:00
}
2021-01-06 15:12:40 +03:00
void TransferListModel : : handleTorrentAboutToBeRemoved ( BitTorrent : : Torrent * const torrent )
2010-11-14 18:28:22 +03:00
{
2019-08-17 12:09:31 +03:00
const int row = m_torrentMap . value ( torrent , - 1 ) ;
2019-08-28 15:43:02 +03:00
Q_ASSERT ( row > = 0 ) ;
2019-08-17 12:09:31 +03:00
beginRemoveRows ( { } , row , row ) ;
m_torrentList . removeAt ( row ) ;
m_torrentMap . remove ( torrent ) ;
2020-11-16 10:02:11 +03:00
for ( int & value : m_torrentMap )
{
2019-08-17 12:09:31 +03:00
if ( value > row )
- - value ;
2015-04-19 18:17:47 +03:00
}
2019-08-17 12:09:31 +03:00
endRemoveRows ( ) ;
2010-11-14 18:28:22 +03:00
}
2021-01-06 15:12:40 +03:00
void TransferListModel : : handleTorrentStatusUpdated ( BitTorrent : : Torrent * const torrent )
2010-11-14 18:28:22 +03:00
{
2019-08-17 12:09:31 +03:00
const int row = m_torrentMap . value ( torrent , - 1 ) ;
2019-08-28 15:43:02 +03:00
Q_ASSERT ( row > = 0 ) ;
2019-08-17 12:09:31 +03:00
emit dataChanged ( index ( row , 0 ) , index ( row , columnCount ( ) - 1 ) ) ;
2010-11-14 18:28:22 +03:00
}
2021-01-06 15:12:40 +03:00
void TransferListModel : : handleTorrentsUpdated ( const QVector < BitTorrent : : Torrent * > & torrents )
2015-11-05 19:17:10 +03:00
{
2019-08-17 09:58:10 +03:00
const int columns = ( columnCount ( ) - 1 ) ;
2020-11-16 10:02:11 +03:00
if ( torrents . size ( ) < = ( m_torrentList . size ( ) * 0.5 ) )
{
2021-01-06 15:12:40 +03:00
for ( BitTorrent : : Torrent * const torrent : torrents )
2020-11-16 10:02:11 +03:00
{
2019-08-28 10:32:21 +03:00
const int row = m_torrentMap . value ( torrent , - 1 ) ;
2019-08-28 15:43:02 +03:00
Q_ASSERT ( row > = 0 ) ;
2019-08-28 10:32:21 +03:00
emit dataChanged ( index ( row , 0 ) , index ( row , columns ) ) ;
}
}
2020-11-16 10:02:11 +03:00
else
{
2019-08-28 10:32:21 +03:00
// save the overhead when more than half of the torrent list needs update
emit dataChanged ( index ( 0 , 0 ) , index ( ( rowCount ( ) - 1 ) , columns ) ) ;
2019-08-17 09:58:10 +03:00
}
2015-11-05 19:17:10 +03:00
}
2020-01-23 11:20:38 +03:00
void TransferListModel : : configure ( )
{
const Preferences * pref = Preferences : : instance ( ) ;
HideZeroValuesMode hideZeroValuesMode = HideZeroValuesMode : : Never ;
2020-11-16 10:02:11 +03:00
if ( pref - > getHideZeroValues ( ) )
{
2020-01-23 11:20:38 +03:00
if ( pref - > getHideZeroComboValues ( ) = = 1 )
hideZeroValuesMode = HideZeroValuesMode : : Paused ;
else
hideZeroValuesMode = HideZeroValuesMode : : Always ;
}
2020-11-16 10:02:11 +03:00
if ( m_hideZeroValuesMode ! = hideZeroValuesMode )
{
2020-01-23 11:20:38 +03:00
m_hideZeroValuesMode = hideZeroValuesMode ;
emit dataChanged ( index ( 0 , 0 ) , index ( ( rowCount ( ) - 1 ) , ( columnCount ( ) - 1 ) ) ) ;
}
}
2022-05-26 22:46:14 +03:00
QIcon TransferListModel : : getIconByState ( const BitTorrent : : TorrentState state ) const
{
switch ( state )
{
case BitTorrent : : TorrentState : : Downloading :
case BitTorrent : : TorrentState : : ForcedDownloading :
case BitTorrent : : TorrentState : : DownloadingMetadata :
case BitTorrent : : TorrentState : : ForcedDownloadingMetadata :
return m_downloadingIcon ;
case BitTorrent : : TorrentState : : StalledDownloading :
return m_stalledDLIcon ;
case BitTorrent : : TorrentState : : StalledUploading :
return m_stalledUPIcon ;
case BitTorrent : : TorrentState : : Uploading :
case BitTorrent : : TorrentState : : ForcedUploading :
return m_uploadingIcon ;
case BitTorrent : : TorrentState : : PausedDownloading :
return m_pausedIcon ;
case BitTorrent : : TorrentState : : PausedUploading :
return m_completedIcon ;
case BitTorrent : : TorrentState : : QueuedDownloading :
case BitTorrent : : TorrentState : : QueuedUploading :
return m_queuedIcon ;
case BitTorrent : : TorrentState : : CheckingDownloading :
case BitTorrent : : TorrentState : : CheckingUploading :
case BitTorrent : : TorrentState : : CheckingResumeData :
case BitTorrent : : TorrentState : : Moving :
return m_checkingIcon ;
case BitTorrent : : TorrentState : : Unknown :
case BitTorrent : : TorrentState : : MissingFiles :
case BitTorrent : : TorrentState : : Error :
return m_errorIcon ;
default :
Q_ASSERT ( false ) ;
return m_errorIcon ;
}
}