2009-11-07 22:55:33 +03:00
/*
2018-06-06 16:48:17 +03:00
* Bittorrent Client using Qt and libtorrent .
2018-05-24 18:39:02 +03:00
* Copyright ( C ) 2006 Christophe Dumez < chris @ qbittorrent . org >
2009-11-07 22:55:33 +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 .
*/
2017-03-30 05:17:39 +03:00
# include "transferlistwidget.h"
2019-06-24 18:37:31 +03:00
# include <algorithm>
2009-11-07 22:55:33 +03:00
# include <QClipboard>
2017-03-30 05:17:39 +03:00
# include <QDebug>
2010-05-21 18:26:18 +04:00
# include <QFileDialog>
2019-02-24 19:31:39 +03:00
# include <QHeaderView>
2017-03-30 05:17:39 +03:00
# include <QMenu>
2010-12-26 12:51:37 +03:00
# include <QMessageBox>
2018-05-24 18:41:03 +03:00
# include <QRegularExpression>
2019-06-24 18:37:31 +03:00
# include <QSet>
2017-03-30 05:17:39 +03:00
# include <QShortcut>
2020-11-30 09:39:03 +03:00
# include <QVector>
2017-03-30 05:17:39 +03:00
# include <QWheelEvent>
2010-12-26 12:51:37 +03:00
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"
2019-06-24 18:37:31 +03:00
# include "base/bittorrent/trackerentry.h"
2018-11-18 21:40:37 +03:00
# include "base/global.h"
2017-03-30 05:06:09 +03:00
# include "base/logger.h"
2022-04-16 09:57:21 +03:00
# include "base/path.h"
2017-03-30 05:17:39 +03:00
# include "base/preferences.h"
2015-09-25 11:10:05 +03:00
# include "base/torrentfilter.h"
2021-04-05 08:02:28 +03:00
# include "base/utils/compare.h"
2017-03-30 05:17:39 +03:00
# include "base/utils/fs.h"
2018-10-24 20:20:33 +03:00
# include "base/utils/misc.h"
2017-03-30 05:17:39 +03:00
# include "base/utils/string.h"
2018-05-24 18:39:02 +03:00
# include "autoexpandabledialog.h"
2018-06-14 12:54:23 +03:00
# include "deletionconfirmationdialog.h"
2017-03-30 05:17:39 +03:00
# include "mainwindow.h"
2018-06-14 12:54:23 +03:00
# include "optionsdialog.h"
2017-09-11 21:32:11 +03:00
# include "previewselectdialog.h"
2018-06-14 12:54:23 +03:00
# include "speedlimitdialog.h"
2017-09-24 14:54:42 +03:00
# include "torrentcategorydialog.h"
2020-11-29 17:36:07 +03:00
# include "torrentoptionsdialog.h"
2019-06-24 18:37:31 +03:00
# include "trackerentriesdialog.h"
2017-03-30 05:17:39 +03:00
# include "transferlistdelegate.h"
2018-06-14 12:54:23 +03:00
# include "transferlistmodel.h"
2014-09-13 17:12:07 +04:00
# include "transferlistsortmodel.h"
2019-07-07 16:02:13 +03:00
# include "tristateaction.h"
2019-07-16 07:01:33 +03:00
# include "uithememanager.h"
2019-03-02 08:22:13 +03:00
# include "utils.h"
2010-07-16 19:03:18 +04:00
2019-09-05 15:11:33 +03:00
# ifdef Q_OS_MACOS
2017-12-12 18:00:56 +03:00
# include "macutilities.h"
# endif
2017-07-10 02:15:08 +03:00
namespace
{
2021-03-05 12:43:58 +03:00
QVector < BitTorrent : : TorrentID > extractIDs ( const QVector < BitTorrent : : Torrent * > & torrents )
2017-07-10 02:15:08 +03:00
{
2021-03-05 12:43:58 +03:00
QVector < BitTorrent : : TorrentID > torrentIDs ;
torrentIDs . reserve ( torrents . size ( ) ) ;
2021-01-06 15:12:40 +03:00
for ( const BitTorrent : : Torrent * torrent : torrents )
2021-03-05 12:43:58 +03:00
torrentIDs < < torrent - > id ( ) ;
return torrentIDs ;
2017-07-10 02:15:08 +03:00
}
2021-01-06 15:12:40 +03:00
bool torrentContainsPreviewableFiles ( const BitTorrent : : Torrent * const torrent )
2018-10-24 20:20:33 +03:00
{
if ( ! torrent - > hasMetadata ( ) )
return false ;
2022-02-08 06:03:48 +03:00
for ( const Path & filePath : asConst ( torrent - > filePaths ( ) ) )
2020-11-16 10:02:11 +03:00
{
2022-02-08 06:03:48 +03:00
if ( Utils : : Misc : : isPreviewable ( filePath ) )
2018-10-24 20:20:33 +03:00
return true ;
}
return false ;
}
2019-09-29 05:50:07 +03:00
2021-01-06 15:12:40 +03:00
void openDestinationFolder ( const BitTorrent : : Torrent * const torrent )
2019-11-10 19:50:35 +03:00
{
# ifdef Q_OS_MACOS
2021-05-20 10:36:44 +03:00
MacUtils : : openFiles ( { torrent - > contentPath ( ) } ) ;
2019-11-10 19:50:35 +03:00
# else
if ( torrent - > filesCount ( ) = = 1 )
2021-05-20 10:36:44 +03:00
Utils : : Gui : : openFolderSelect ( torrent - > contentPath ( ) ) ;
2019-11-10 19:50:35 +03:00
else
2021-05-20 10:36:44 +03:00
Utils : : Gui : : openPath ( torrent - > contentPath ( ) ) ;
2019-11-10 19:50:35 +03:00
# endif
}
2021-01-06 15:12:40 +03:00
void removeTorrents ( const QVector < BitTorrent : : Torrent * > & torrents , const bool isDeleteFileSelected )
2019-09-29 05:50:07 +03:00
{
auto * session = BitTorrent : : Session : : instance ( ) ;
2021-01-06 15:12:40 +03:00
const DeleteOption deleteOption = isDeleteFileSelected ? DeleteTorrentAndFiles : DeleteTorrent ;
for ( const BitTorrent : : Torrent * torrent : torrents )
2021-03-05 12:43:58 +03:00
session - > deleteTorrent ( torrent - > id ( ) , deleteOption ) ;
2019-09-29 05:50:07 +03:00
}
2017-07-10 02:15:08 +03:00
}
2015-06-07 15:03:30 +03:00
2017-09-25 20:03:24 +03:00
TransferListWidget : : TransferListWidget ( QWidget * parent , MainWindow * mainWindow )
2021-03-10 10:52:30 +03:00
: QTreeView { parent }
, m_listModel { new TransferListModel { this } }
, m_sortFilterModel { new TransferListSortModel { this } }
, m_mainWindow { mainWindow }
2014-12-08 04:40:58 +03:00
{
// Load settings
2021-03-10 10:52:30 +03:00
const bool columnLoaded = loadSettings ( ) ;
2014-12-08 04:40:58 +03:00
// Create and apply delegate
2021-03-10 10:52:30 +03:00
setItemDelegate ( new TransferListDelegate { this } ) ;
2014-12-08 04:40:58 +03:00
2017-09-25 20:03:24 +03:00
m_sortFilterModel - > setDynamicSortFilter ( true ) ;
m_sortFilterModel - > setSourceModel ( m_listModel ) ;
2018-06-14 12:54:23 +03:00
m_sortFilterModel - > setFilterKeyColumn ( TransferListModel : : TR_NAME ) ;
2017-09-25 20:03:24 +03:00
m_sortFilterModel - > setFilterRole ( Qt : : DisplayRole ) ;
m_sortFilterModel - > setSortCaseSensitivity ( Qt : : CaseInsensitive ) ;
2020-01-11 18:19:48 +03:00
m_sortFilterModel - > setSortRole ( TransferListModel : : UnderlyingDataRole ) ;
2017-09-25 20:03:24 +03:00
setModel ( m_sortFilterModel ) ;
2014-12-08 04:40:58 +03:00
// Visual settings
2021-03-10 10:52:30 +03:00
setUniformRowHeights ( true ) ;
2014-12-08 04:40:58 +03:00
setRootIsDecorated ( false ) ;
setAllColumnsShowFocus ( true ) ;
setSortingEnabled ( true ) ;
setSelectionMode ( QAbstractItemView : : ExtendedSelection ) ;
setItemsExpandable ( false ) ;
setAutoScroll ( true ) ;
setDragDropMode ( QAbstractItemView : : DragOnly ) ;
2019-09-05 15:11:33 +03:00
# if defined(Q_OS_MACOS)
2014-12-08 04:40:58 +03:00
setAttribute ( Qt : : WA_MacShowFocusRect , false ) ;
2012-06-30 19:25:09 +04:00
# endif
2022-03-01 07:50:10 +03:00
header ( ) - > setFirstSectionMovable ( true ) ;
2014-12-08 04:40:58 +03:00
header ( ) - > setStretchLastSection ( false ) ;
2021-09-08 06:47:55 +03:00
header ( ) - > setTextElideMode ( Qt : : ElideRight ) ;
2014-12-08 04:40:58 +03:00
// Default hidden columns
2020-11-16 10:02:11 +03:00
if ( ! columnLoaded )
{
2018-06-14 12:54:23 +03:00
setColumnHidden ( TransferListModel : : TR_ADD_DATE , true ) ;
setColumnHidden ( TransferListModel : : TR_SEED_DATE , true ) ;
setColumnHidden ( TransferListModel : : TR_UPLIMIT , true ) ;
setColumnHidden ( TransferListModel : : TR_DLLIMIT , true ) ;
setColumnHidden ( TransferListModel : : TR_TRACKER , true ) ;
setColumnHidden ( TransferListModel : : TR_AMOUNT_DOWNLOADED , true ) ;
setColumnHidden ( TransferListModel : : TR_AMOUNT_UPLOADED , true ) ;
setColumnHidden ( TransferListModel : : TR_AMOUNT_DOWNLOADED_SESSION , true ) ;
setColumnHidden ( TransferListModel : : TR_AMOUNT_UPLOADED_SESSION , true ) ;
setColumnHidden ( TransferListModel : : TR_AMOUNT_LEFT , true ) ;
setColumnHidden ( TransferListModel : : TR_TIME_ELAPSED , true ) ;
setColumnHidden ( TransferListModel : : TR_SAVE_PATH , true ) ;
setColumnHidden ( TransferListModel : : TR_COMPLETED , true ) ;
setColumnHidden ( TransferListModel : : TR_RATIO_LIMIT , true ) ;
setColumnHidden ( TransferListModel : : TR_SEEN_COMPLETE_DATE , true ) ;
setColumnHidden ( TransferListModel : : TR_LAST_ACTIVITY , true ) ;
setColumnHidden ( TransferListModel : : TR_TOTAL_SIZE , true ) ;
2014-12-08 04:40:58 +03:00
}
2009-11-08 22:54:22 +03:00
2014-12-08 04:40:58 +03:00
//Ensure that at least one column is visible at all times
bool atLeastOne = false ;
2020-11-16 10:02:11 +03:00
for ( int i = 0 ; i < TransferListModel : : NB_COLUMNS ; + + i )
{
if ( ! isColumnHidden ( i ) )
{
2014-12-08 04:40:58 +03:00
atLeastOne = true ;
break ;
}
2010-08-14 19:53:05 +04:00
}
2014-12-08 04:40:58 +03:00
if ( ! atLeastOne )
2018-06-14 12:54:23 +03:00
setColumnHidden ( TransferListModel : : TR_NAME , false ) ;
2014-12-08 04:40:58 +03:00
//When adding/removing columns between versions some may
//end up being size 0 when the new version is launched with
//a conf file from the previous version.
2018-09-07 14:12:38 +03:00
for ( int i = 0 ; i < TransferListModel : : NB_COLUMNS ; + + i )
2022-01-18 10:15:54 +03:00
{
2016-06-22 20:01:02 +03:00
if ( ( columnWidth ( i ) < = 0 ) & & ( ! isColumnHidden ( i ) ) )
2014-12-08 04:40:58 +03:00
resizeColumnToContents ( i ) ;
2022-01-18 10:15:54 +03:00
}
2014-12-08 04:40:58 +03:00
setContextMenuPolicy ( Qt : : CustomContextMenu ) ;
// Listen for list events
2018-04-18 16:59:41 +03:00
connect ( this , & QAbstractItemView : : doubleClicked , this , & TransferListWidget : : torrentDoubleClicked ) ;
connect ( this , & QWidget : : customContextMenuRequested , this , & TransferListWidget : : displayListMenu ) ;
2014-12-08 04:40:58 +03:00
header ( ) - > setContextMenuPolicy ( Qt : : CustomContextMenu ) ;
2022-01-18 10:15:54 +03:00
connect ( header ( ) , & QWidget : : customContextMenuRequested , this , & TransferListWidget : : displayColumnHeaderMenu ) ;
2018-04-18 16:59:41 +03:00
connect ( header ( ) , & QHeaderView : : sectionMoved , this , & TransferListWidget : : saveSettings ) ;
connect ( header ( ) , & QHeaderView : : sectionResized , this , & TransferListWidget : : saveSettings ) ;
connect ( header ( ) , & QHeaderView : : sortIndicatorChanged , this , & TransferListWidget : : saveSettings ) ;
2019-07-13 07:55:21 +03:00
const auto * editHotkey = new QShortcut ( Qt : : Key_F2 , this , nullptr , nullptr , Qt : : WidgetShortcut ) ;
connect ( editHotkey , & QShortcut : : activated , this , & TransferListWidget : : renameSelectedTorrent ) ;
const auto * deleteHotkey = new QShortcut ( QKeySequence : : Delete , this , nullptr , nullptr , Qt : : WidgetShortcut ) ;
connect ( deleteHotkey , & QShortcut : : activated , this , & TransferListWidget : : softDeleteSelectedTorrents ) ;
const auto * permDeleteHotkey = new QShortcut ( Qt : : SHIFT + Qt : : Key_Delete , this , nullptr , nullptr , Qt : : WidgetShortcut ) ;
connect ( permDeleteHotkey , & QShortcut : : activated , this , & TransferListWidget : : permDeleteSelectedTorrents ) ;
2019-09-23 10:14:18 +03:00
const auto * doubleClickHotkeyReturn = new QShortcut ( Qt : : Key_Return , this , nullptr , nullptr , Qt : : WidgetShortcut ) ;
connect ( doubleClickHotkeyReturn , & QShortcut : : activated , this , & TransferListWidget : : torrentDoubleClicked ) ;
const auto * doubleClickHotkeyEnter = new QShortcut ( Qt : : Key_Enter , this , nullptr , nullptr , Qt : : WidgetShortcut ) ;
connect ( doubleClickHotkeyEnter , & QShortcut : : activated , this , & TransferListWidget : : torrentDoubleClicked ) ;
2019-07-13 07:55:21 +03:00
const auto * recheckHotkey = new QShortcut ( Qt : : CTRL + Qt : : Key_R , this , nullptr , nullptr , Qt : : WidgetShortcut ) ;
connect ( recheckHotkey , & QShortcut : : activated , this , & TransferListWidget : : recheckSelectedTorrents ) ;
2022-05-10 06:34:43 +03:00
const auto * forceStartHotkey = new QShortcut ( Qt : : CTRL + Qt : : Key_M , this , nullptr , nullptr , Qt : : WidgetShortcut ) ;
connect ( forceStartHotkey , & QShortcut : : activated , this , & TransferListWidget : : forceStartSelectedTorrents ) ;
2014-12-08 04:40:58 +03:00
}
TransferListWidget : : ~ TransferListWidget ( )
{
// Save settings
saveSettings ( ) ;
}
2018-06-14 12:54:23 +03:00
TransferListModel * TransferListWidget : : getSourceModel ( ) const
2014-12-08 04:40:58 +03:00
{
2017-09-25 20:03:24 +03:00
return m_listModel ;
2014-12-08 04:40:58 +03:00
}
2022-02-08 06:03:48 +03:00
void TransferListWidget : : previewFile ( const Path & filePath )
2014-12-08 04:40:58 +03:00
{
2019-03-02 08:22:13 +03:00
Utils : : Gui : : openPath ( filePath ) ;
2014-12-08 04:40:58 +03:00
}
2019-07-14 06:46:10 +03:00
QModelIndex TransferListWidget : : mapToSource ( const QModelIndex & index ) const
2014-12-08 04:40:58 +03:00
{
Q_ASSERT ( index . isValid ( ) ) ;
2017-09-25 20:03:24 +03:00
if ( index . model ( ) = = m_sortFilterModel )
return m_sortFilterModel - > mapToSource ( index ) ;
2014-12-08 04:40:58 +03:00
return index ;
}
2019-07-14 06:46:10 +03:00
QModelIndex TransferListWidget : : mapFromSource ( const QModelIndex & index ) const
2014-12-08 04:40:58 +03:00
{
Q_ASSERT ( index . isValid ( ) ) ;
2017-09-25 20:03:24 +03:00
Q_ASSERT ( index . model ( ) = = m_sortFilterModel ) ;
return m_sortFilterModel - > mapFromSource ( index ) ;
2014-12-08 04:40:58 +03:00
}
2017-01-24 14:10:08 +03:00
void TransferListWidget : : torrentDoubleClicked ( )
2014-12-08 04:40:58 +03:00
{
2017-01-24 14:10:08 +03:00
const QModelIndexList selectedIndexes = selectionModel ( ) - > selectedRows ( ) ;
2017-02-06 18:51:25 +03:00
if ( ( selectedIndexes . size ( ) ! = 1 ) | | ! selectedIndexes . first ( ) . isValid ( ) ) return ;
2017-01-24 14:10:08 +03:00
2017-09-25 20:03:24 +03:00
const QModelIndex index = m_listModel - > index ( mapToSource ( selectedIndexes . first ( ) ) . row ( ) ) ;
2021-01-06 15:12:40 +03:00
BitTorrent : : Torrent * const torrent = m_listModel - > torrentHandle ( index ) ;
2015-04-19 18:17:47 +03:00
if ( ! torrent ) return ;
2014-12-08 04:40:58 +03:00
int action ;
2015-04-19 18:17:47 +03:00
if ( torrent - > isSeed ( ) )
2014-12-08 04:40:58 +03:00
action = Preferences : : instance ( ) - > getActionOnDblClOnTorrentFn ( ) ;
else
action = Preferences : : instance ( ) - > getActionOnDblClOnTorrentDl ( ) ;
2020-11-16 10:02:11 +03:00
switch ( action )
{
2014-12-08 04:40:58 +03:00
case TOGGLE_PAUSE :
2015-04-19 18:17:47 +03:00
if ( torrent - > isPaused ( ) )
torrent - > resume ( ) ;
2014-12-08 04:40:58 +03:00
else
2015-04-19 18:17:47 +03:00
torrent - > pause ( ) ;
2014-12-08 04:40:58 +03:00
break ;
2019-11-10 19:50:35 +03:00
case PREVIEW_FILE :
2020-11-16 10:02:11 +03:00
if ( torrentContainsPreviewableFiles ( torrent ) )
{
2019-11-10 19:50:35 +03:00
auto * dialog = new PreviewSelectDialog ( this , torrent ) ;
dialog - > setAttribute ( Qt : : WA_DeleteOnClose ) ;
connect ( dialog , & PreviewSelectDialog : : readyToPreviewFile , this , & TransferListWidget : : previewFile ) ;
dialog - > show ( ) ;
}
2020-11-16 10:02:11 +03:00
else
{
2019-11-10 19:50:35 +03:00
openDestinationFolder ( torrent ) ;
}
break ;
2014-12-08 04:40:58 +03:00
case OPEN_DEST :
2019-11-10 19:50:35 +03:00
openDestinationFolder ( torrent ) ;
2015-06-28 21:58:39 +03:00
break ;
2021-12-19 09:01:20 +03:00
case SHOW_OPTIONS :
setTorrentOptions ( ) ;
break ;
2010-08-14 19:53:05 +04:00
}
2009-11-07 22:55:33 +03:00
}
2021-01-06 15:12:40 +03:00
QVector < BitTorrent : : Torrent * > TransferListWidget : : getSelectedTorrents ( ) const
2014-12-08 04:40:58 +03:00
{
2019-10-02 07:52:51 +03:00
const QModelIndexList selectedRows = selectionModel ( ) - > selectedRows ( ) ;
2021-01-06 15:12:40 +03:00
QVector < BitTorrent : : Torrent * > torrents ;
2019-10-02 07:52:51 +03:00
torrents . reserve ( selectedRows . size ( ) ) ;
for ( const QModelIndex & index : selectedRows )
2017-09-25 20:03:24 +03:00
torrents < < m_listModel - > torrentHandle ( mapToSource ( index ) ) ;
2015-06-07 15:03:30 +03:00
return torrents ;
2009-11-07 22:55:33 +03:00
}
2021-01-06 15:12:40 +03:00
QVector < BitTorrent : : Torrent * > TransferListWidget : : getVisibleTorrents ( ) const
2020-04-26 04:42:08 +03:00
{
const int visibleTorrentsCount = m_sortFilterModel - > rowCount ( ) ;
2021-01-06 15:12:40 +03:00
QVector < BitTorrent : : Torrent * > torrents ;
2020-04-26 04:42:08 +03:00
torrents . reserve ( visibleTorrentsCount ) ;
for ( int i = 0 ; i < visibleTorrentsCount ; + + i )
torrents < < m_listModel - > torrentHandle ( mapToSource ( m_sortFilterModel - > index ( i , 0 ) ) ) ;
return torrents ;
}
2022-01-14 09:45:03 +03:00
void TransferListWidget : : setSelectedTorrentsLocation ( )
{
const QVector < BitTorrent : : Torrent * > torrents = getSelectedTorrents ( ) ;
2022-01-20 07:22:16 +03:00
if ( torrents . isEmpty ( ) )
return ;
2022-01-14 09:45:03 +03:00
2022-02-08 06:03:48 +03:00
const Path oldLocation = torrents [ 0 ] - > savePath ( ) ;
2022-01-14 09:45:03 +03:00
2022-02-08 06:03:48 +03:00
auto fileDialog = new QFileDialog ( this , tr ( " Choose save path " ) , oldLocation . data ( ) ) ;
2022-01-20 07:22:16 +03:00
fileDialog - > setAttribute ( Qt : : WA_DeleteOnClose ) ;
fileDialog - > setFileMode ( QFileDialog : : Directory ) ;
fileDialog - > setOptions ( QFileDialog : : DontConfirmOverwrite | QFileDialog : : ShowDirsOnly | QFileDialog : : HideNameFilterDetails ) ;
connect ( fileDialog , & QDialog : : accepted , this , [ this , fileDialog ] ( )
2022-01-14 09:45:03 +03:00
{
2022-01-20 07:22:16 +03:00
const QVector < BitTorrent : : Torrent * > torrents = getSelectedTorrents ( ) ;
if ( torrents . isEmpty ( ) )
return ;
2022-02-08 06:03:48 +03:00
const Path newLocation { fileDialog - > selectedFiles ( ) . constFirst ( ) } ;
2022-03-21 11:58:37 +03:00
if ( ! newLocation . exists ( ) )
2022-01-20 07:22:16 +03:00
return ;
// Actually move storage
for ( BitTorrent : : Torrent * const torrent : torrents )
{
torrent - > setAutoTMMEnabled ( false ) ;
torrent - > setSavePath ( newLocation ) ;
}
} ) ;
2022-04-05 07:26:17 +03:00
fileDialog - > open ( ) ;
2022-01-14 09:45:03 +03:00
}
2015-04-19 18:17:47 +03:00
void TransferListWidget : : pauseAllTorrents ( )
{
2021-01-06 15:12:40 +03:00
for ( BitTorrent : : Torrent * const torrent : asConst ( BitTorrent : : Session : : instance ( ) - > torrents ( ) ) )
2015-04-19 18:17:47 +03:00
torrent - > pause ( ) ;
}
void TransferListWidget : : resumeAllTorrents ( )
{
2021-01-06 15:12:40 +03:00
for ( BitTorrent : : Torrent * const torrent : asConst ( BitTorrent : : Session : : instance ( ) - > torrents ( ) ) )
2015-04-19 18:17:47 +03:00
torrent - > resume ( ) ;
}
2014-12-08 04:40:58 +03:00
void TransferListWidget : : startSelectedTorrents ( )
{
2021-01-06 15:12:40 +03:00
for ( BitTorrent : : Torrent * const torrent : asConst ( getSelectedTorrents ( ) ) )
2015-06-07 15:03:30 +03:00
torrent - > resume ( ) ;
2014-12-08 04:40:58 +03:00
}
2015-04-14 02:22:14 +03:00
void TransferListWidget : : forceStartSelectedTorrents ( )
{
2021-01-06 15:12:40 +03:00
for ( BitTorrent : : Torrent * const torrent : asConst ( getSelectedTorrents ( ) ) )
2020-04-19 16:12:50 +03:00
torrent - > resume ( BitTorrent : : TorrentOperatingMode : : Forced ) ;
2015-04-14 02:22:14 +03:00
}
2014-12-08 04:40:58 +03:00
void TransferListWidget : : startVisibleTorrents ( )
{
2021-01-06 15:12:40 +03:00
for ( BitTorrent : : Torrent * const torrent : asConst ( getVisibleTorrents ( ) ) )
2020-04-26 04:42:08 +03:00
torrent - > resume ( ) ;
2009-11-07 22:55:33 +03:00
}
2014-12-08 04:40:58 +03:00
void TransferListWidget : : pauseSelectedTorrents ( )
{
2021-01-06 15:12:40 +03:00
for ( BitTorrent : : Torrent * const torrent : asConst ( getSelectedTorrents ( ) ) )
2015-06-07 15:03:30 +03:00
torrent - > pause ( ) ;
2014-12-08 04:40:58 +03:00
}
void TransferListWidget : : pauseVisibleTorrents ( )
{
2021-01-06 15:12:40 +03:00
for ( BitTorrent : : Torrent * const torrent : asConst ( getVisibleTorrents ( ) ) )
2020-04-26 04:42:08 +03:00
torrent - > pause ( ) ;
2009-11-07 22:55:33 +03:00
}
2016-08-05 21:15:13 +03:00
void TransferListWidget : : softDeleteSelectedTorrents ( )
{
deleteSelectedTorrents ( false ) ;
}
void TransferListWidget : : permDeleteSelectedTorrents ( )
{
deleteSelectedTorrents ( true ) ;
}
2019-09-29 05:50:07 +03:00
void TransferListWidget : : deleteSelectedTorrents ( const bool deleteLocalFiles )
2014-12-08 04:40:58 +03:00
{
2017-09-25 20:03:24 +03:00
if ( m_mainWindow - > currentTabWidget ( ) ! = this ) return ;
2015-04-19 18:17:47 +03:00
2021-01-06 15:12:40 +03:00
const QVector < BitTorrent : : Torrent * > torrents = getSelectedTorrents ( ) ;
2015-06-07 15:03:30 +03:00
if ( torrents . empty ( ) ) return ;
2020-11-16 10:02:11 +03:00
if ( Preferences : : instance ( ) - > confirmTorrentDeletion ( ) )
{
2019-09-29 05:50:07 +03:00
auto * dialog = new DeletionConfirmationDialog ( this , torrents . size ( ) , torrents [ 0 ] - > name ( ) , deleteLocalFiles ) ;
dialog - > setAttribute ( Qt : : WA_DeleteOnClose ) ;
2020-04-26 04:42:08 +03:00
connect ( dialog , & DeletionConfirmationDialog : : accepted , this , [ this , dialog ] ( )
2019-09-29 05:50:07 +03:00
{
2020-04-26 04:42:08 +03:00
// Some torrents might be removed when waiting for user input, so refetch the torrent list
// NOTE: this will only work when dialog is modal
removeTorrents ( getSelectedTorrents ( ) , dialog - > isDeleteFileSelected ( ) ) ;
2019-09-29 05:50:07 +03:00
} ) ;
dialog - > open ( ) ;
}
2020-11-16 10:02:11 +03:00
else
{
2019-09-29 05:50:07 +03:00
removeTorrents ( torrents , deleteLocalFiles ) ;
}
2014-12-08 04:40:58 +03:00
}
void TransferListWidget : : deleteVisibleTorrents ( )
{
2021-01-06 15:12:40 +03:00
const QVector < BitTorrent : : Torrent * > torrents = getVisibleTorrents ( ) ;
2020-04-26 04:42:08 +03:00
if ( torrents . empty ( ) ) return ;
2015-06-07 15:03:30 +03:00
2020-11-16 10:02:11 +03:00
if ( Preferences : : instance ( ) - > confirmTorrentDeletion ( ) )
{
2019-09-29 05:50:07 +03:00
auto * dialog = new DeletionConfirmationDialog ( this , torrents . size ( ) , torrents [ 0 ] - > name ( ) , false ) ;
dialog - > setAttribute ( Qt : : WA_DeleteOnClose ) ;
2020-04-26 04:42:08 +03:00
connect ( dialog , & DeletionConfirmationDialog : : accepted , this , [ this , dialog ] ( )
2019-09-29 05:50:07 +03:00
{
2020-04-26 04:42:08 +03:00
// Some torrents might be removed when waiting for user input, so refetch the torrent list
// NOTE: this will only work when dialog is modal
removeTorrents ( getVisibleTorrents ( ) , dialog - > isDeleteFileSelected ( ) ) ;
2019-09-29 05:50:07 +03:00
} ) ;
dialog - > open ( ) ;
}
2020-11-16 10:02:11 +03:00
else
{
2019-09-29 05:50:07 +03:00
removeTorrents ( torrents , false ) ;
}
2014-12-08 04:40:58 +03:00
}
2018-12-08 02:01:09 +03:00
void TransferListWidget : : increaseQueuePosSelectedTorrents ( )
2014-12-08 04:40:58 +03:00
{
qDebug ( ) < < Q_FUNC_INFO ;
2017-09-25 20:03:24 +03:00
if ( m_mainWindow - > currentTabWidget ( ) = = this )
2021-03-05 12:43:58 +03:00
BitTorrent : : Session : : instance ( ) - > increaseTorrentsQueuePos ( extractIDs ( getSelectedTorrents ( ) ) ) ;
2011-03-07 22:26:44 +03:00
}
2018-12-08 02:01:09 +03:00
void TransferListWidget : : decreaseQueuePosSelectedTorrents ( )
2014-12-08 04:40:58 +03:00
{
qDebug ( ) < < Q_FUNC_INFO ;
2017-09-25 20:03:24 +03:00
if ( m_mainWindow - > currentTabWidget ( ) = = this )
2021-03-05 12:43:58 +03:00
BitTorrent : : Session : : instance ( ) - > decreaseTorrentsQueuePos ( extractIDs ( getSelectedTorrents ( ) ) ) ;
2009-11-08 00:04:56 +03:00
}
2018-12-08 02:01:09 +03:00
void TransferListWidget : : topQueuePosSelectedTorrents ( )
2014-12-08 04:40:58 +03:00
{
2017-09-25 20:03:24 +03:00
if ( m_mainWindow - > currentTabWidget ( ) = = this )
2021-03-05 12:43:58 +03:00
BitTorrent : : Session : : instance ( ) - > topTorrentsQueuePos ( extractIDs ( getSelectedTorrents ( ) ) ) ;
2011-08-10 22:44:37 +04:00
}
2009-11-18 14:04:19 +03:00
2018-12-08 02:01:09 +03:00
void TransferListWidget : : bottomQueuePosSelectedTorrents ( )
2014-12-08 04:40:58 +03:00
{
2017-09-25 20:03:24 +03:00
if ( m_mainWindow - > currentTabWidget ( ) = = this )
2021-03-05 12:43:58 +03:00
BitTorrent : : Session : : instance ( ) - > bottomTorrentsQueuePos ( extractIDs ( getSelectedTorrents ( ) ) ) ;
2009-11-19 15:45:11 +03:00
}
2014-12-08 04:40:58 +03:00
void TransferListWidget : : copySelectedMagnetURIs ( ) const
{
2018-06-14 14:46:50 +03:00
QStringList magnetUris ;
2021-01-06 15:12:40 +03:00
for ( BitTorrent : : Torrent * const torrent : asConst ( getSelectedTorrents ( ) ) )
2020-04-12 18:08:19 +03:00
magnetUris < < torrent - > createMagnetURI ( ) ;
2015-06-07 15:03:30 +03:00
2022-03-12 17:00:58 +03:00
qApp - > clipboard ( ) - > setText ( magnetUris . join ( u ' \n ' ) ) ;
2014-12-08 04:40:58 +03:00
}
2015-02-06 21:56:24 +03:00
void TransferListWidget : : copySelectedNames ( ) const
2015-02-01 16:52:36 +03:00
{
2018-06-14 14:46:50 +03:00
QStringList torrentNames ;
2021-01-06 15:12:40 +03:00
for ( BitTorrent : : Torrent * const torrent : asConst ( getSelectedTorrents ( ) ) )
2018-06-14 14:46:50 +03:00
torrentNames < < torrent - > name ( ) ;
2015-06-07 15:03:30 +03:00
2022-03-12 17:00:58 +03:00
qApp - > clipboard ( ) - > setText ( torrentNames . join ( u ' \n ' ) ) ;
2015-02-01 16:52:36 +03:00
}
2021-06-25 20:44:23 +03:00
void TransferListWidget : : copySelectedInfohashes ( const CopyInfohashPolicy policy ) const
{
const auto selectedTorrents = getSelectedTorrents ( ) ;
QStringList infoHashes ;
infoHashes . reserve ( selectedTorrents . size ( ) ) ;
switch ( policy )
{
case CopyInfohashPolicy : : Version1 :
for ( const BitTorrent : : Torrent * torrent : selectedTorrents )
{
if ( const auto infoHash = torrent - > infoHash ( ) . v1 ( ) ; infoHash . isValid ( ) )
infoHashes < < infoHash . toString ( ) ;
}
break ;
case CopyInfohashPolicy : : Version2 :
for ( const BitTorrent : : Torrent * torrent : selectedTorrents )
{
if ( const auto infoHash = torrent - > infoHash ( ) . v2 ( ) ; infoHash . isValid ( ) )
infoHashes < < infoHash . toString ( ) ;
}
break ;
}
2022-03-12 17:00:58 +03:00
qApp - > clipboard ( ) - > setText ( infoHashes . join ( u ' \n ' ) ) ;
2021-06-25 20:44:23 +03:00
}
void TransferListWidget : : copySelectedIDs ( ) const
2017-08-06 11:35:12 +03:00
{
2021-03-05 12:43:58 +03:00
QStringList torrentIDs ;
2021-01-06 15:12:40 +03:00
for ( BitTorrent : : Torrent * const torrent : asConst ( getSelectedTorrents ( ) ) )
2021-03-05 12:43:58 +03:00
torrentIDs < < torrent - > id ( ) . toString ( ) ;
2017-08-06 11:35:12 +03:00
2022-03-12 17:00:58 +03:00
qApp - > clipboard ( ) - > setText ( torrentIDs . join ( u ' \n ' ) ) ;
2017-08-06 11:35:12 +03:00
}
2018-12-08 02:01:09 +03:00
void TransferListWidget : : hideQueuePosColumn ( bool hide )
2014-12-08 04:40:58 +03:00
{
2018-12-08 02:01:09 +03:00
setColumnHidden ( TransferListModel : : TR_QUEUE_POSITION , hide ) ;
if ( ! hide & & ( columnWidth ( TransferListModel : : TR_QUEUE_POSITION ) = = 0 ) )
resizeColumnToContents ( TransferListModel : : TR_QUEUE_POSITION ) ;
2014-12-08 04:40:58 +03:00
}
void TransferListWidget : : openSelectedTorrentsFolder ( ) const
{
2022-02-08 06:03:48 +03:00
QSet < Path > paths ;
2019-09-05 15:11:33 +03:00
# ifdef Q_OS_MACOS
2017-12-12 18:00:56 +03:00
// On macOS you expect both the files and folders to be opened in their parent
// folders prehilighted for opening, so we use a custom method.
2021-01-06 15:12:40 +03:00
for ( BitTorrent : : Torrent * const torrent : asConst ( getSelectedTorrents ( ) ) )
2020-11-16 10:02:11 +03:00
{
2022-07-02 00:07:02 +03:00
const Path contentPath = torrent - > contentPath ( ) ;
2022-02-08 06:03:48 +03:00
paths . insert ( contentPath ) ;
2017-12-12 18:00:56 +03:00
}
2022-02-08 06:03:48 +03:00
MacUtils : : openFiles ( PathList ( paths . cbegin ( ) , paths . cend ( ) ) ) ;
2017-12-12 18:00:56 +03:00
# else
2021-01-06 15:12:40 +03:00
for ( BitTorrent : : Torrent * const torrent : asConst ( getSelectedTorrents ( ) ) )
2020-11-16 10:02:11 +03:00
{
2022-02-08 06:03:48 +03:00
const Path contentPath = torrent - > contentPath ( ) ;
if ( ! paths . contains ( contentPath ) )
2020-11-16 10:02:11 +03:00
{
2015-10-24 15:28:29 +03:00
if ( torrent - > filesCount ( ) = = 1 )
2021-05-20 10:36:44 +03:00
Utils : : Gui : : openFolderSelect ( contentPath ) ;
2015-10-24 15:28:29 +03:00
else
2021-05-20 10:36:44 +03:00
Utils : : Gui : : openPath ( contentPath ) ;
2015-06-28 21:58:39 +03:00
}
2022-02-08 06:03:48 +03:00
paths . insert ( contentPath ) ;
2014-12-08 04:40:58 +03:00
}
2019-09-05 15:11:33 +03:00
# endif // Q_OS_MACOS
2014-12-08 04:40:58 +03:00
}
void TransferListWidget : : previewSelectedTorrents ( )
{
2021-01-06 15:12:40 +03:00
for ( const BitTorrent : : Torrent * torrent : asConst ( getSelectedTorrents ( ) ) )
2020-11-16 10:02:11 +03:00
{
if ( torrentContainsPreviewableFiles ( torrent ) )
{
2019-10-02 14:19:33 +03:00
auto * dialog = new PreviewSelectDialog ( this , torrent ) ;
dialog - > setAttribute ( Qt : : WA_DeleteOnClose ) ;
2019-06-05 08:46:29 +03:00
connect ( dialog , & PreviewSelectDialog : : readyToPreviewFile , this , & TransferListWidget : : previewFile ) ;
2019-10-02 14:29:28 +03:00
dialog - > show ( ) ;
2019-06-05 08:46:29 +03:00
}
2020-11-16 10:02:11 +03:00
else
{
2019-10-02 16:02:05 +03:00
QMessageBox : : critical ( this , tr ( " Unable to preview " ) , tr ( " The selected torrent \" %1 \" does not contain previewable files " )
. arg ( torrent - > name ( ) ) ) ;
2019-06-05 08:46:29 +03:00
}
2014-12-08 04:40:58 +03:00
}
}
2020-11-29 17:36:07 +03:00
void TransferListWidget : : setTorrentOptions ( )
2014-12-08 04:40:58 +03:00
{
2021-01-06 15:12:40 +03:00
const QVector < BitTorrent : : Torrent * > selectedTorrents = getSelectedTorrents ( ) ;
2020-11-29 17:36:07 +03:00
if ( selectedTorrents . empty ( ) ) return ;
2015-06-07 15:03:30 +03:00
2020-11-29 17:36:07 +03:00
auto dialog = new TorrentOptionsDialog { this , selectedTorrents } ;
2019-06-19 06:26:17 +03:00
dialog - > setAttribute ( Qt : : WA_DeleteOnClose ) ;
dialog - > open ( ) ;
2014-12-08 04:40:58 +03:00
}
void TransferListWidget : : recheckSelectedTorrents ( )
{
2020-11-16 10:02:11 +03:00
if ( Preferences : : instance ( ) - > confirmTorrentRecheck ( ) )
{
2015-07-08 23:29:31 +03:00
QMessageBox : : StandardButton ret = QMessageBox : : question ( this , tr ( " Recheck confirmation " ) , tr ( " Are you sure you want to recheck the selected torrent(s)? " ) , QMessageBox : : Yes | QMessageBox : : No , QMessageBox : : Yes ) ;
if ( ret ! = QMessageBox : : Yes ) return ;
}
2015-04-19 18:17:47 +03:00
2021-01-06 15:12:40 +03:00
for ( BitTorrent : : Torrent * const torrent : asConst ( getSelectedTorrents ( ) ) )
2015-06-07 15:03:30 +03:00
torrent - > forceRecheck ( ) ;
2014-12-08 04:40:58 +03:00
}
2018-01-03 05:40:52 +03:00
void TransferListWidget : : reannounceSelectedTorrents ( )
{
2021-01-06 15:12:40 +03:00
for ( BitTorrent : : Torrent * const torrent : asConst ( getSelectedTorrents ( ) ) )
2018-01-03 05:40:52 +03:00
torrent - > forceReannounce ( ) ;
}
2022-01-18 10:15:54 +03:00
int TransferListWidget : : visibleColumnsCount ( ) const
{
int count = 0 ;
for ( int i = 0 , iMax = header ( ) - > count ( ) ; i < iMax ; + + i )
{
if ( ! isColumnHidden ( i ) )
+ + count ;
}
return count ;
}
2014-12-08 04:40:58 +03:00
// hide/show columns menu
2022-01-18 10:15:54 +03:00
void TransferListWidget : : displayColumnHeaderMenu ( )
2014-12-08 04:40:58 +03:00
{
2019-06-19 06:26:17 +03:00
auto menu = new QMenu ( this ) ;
menu - > setAttribute ( Qt : : WA_DeleteOnClose ) ;
menu - > setTitle ( tr ( " Column visibility " ) ) ;
2022-01-18 10:45:31 +03:00
menu - > setToolTipsVisible ( true ) ;
2019-06-19 06:26:17 +03:00
2022-01-18 10:15:54 +03:00
for ( int i = 0 ; i < TransferListModel : : NB_COLUMNS ; + + i )
2020-11-16 10:02:11 +03:00
{
2018-12-08 02:01:09 +03:00
if ( ! BitTorrent : : Session : : instance ( ) - > isQueueingSystemEnabled ( ) & & ( i = = TransferListModel : : TR_QUEUE_POSITION ) )
2014-12-08 04:40:58 +03:00
continue ;
2019-06-19 06:26:17 +03:00
2022-01-18 10:15:54 +03:00
const auto columnName = m_listModel - > headerData ( i , Qt : : Horizontal , Qt : : DisplayRole ) . toString ( ) ;
QAction * action = menu - > addAction ( columnName , this , [ this , i ] ( const bool checked )
2020-11-16 10:02:11 +03:00
{
2022-01-18 10:15:54 +03:00
if ( ! checked & & ( visibleColumnsCount ( ) < = 1 ) )
return ;
2014-12-08 04:40:58 +03:00
2022-01-18 10:15:54 +03:00
setColumnHidden ( i , ! checked ) ;
2019-06-19 06:26:17 +03:00
2022-01-18 10:15:54 +03:00
if ( checked & & ( columnWidth ( i ) < = 5 ) )
resizeColumnToContents ( i ) ;
2019-06-19 06:26:17 +03:00
2022-01-18 10:15:54 +03:00
saveSettings ( ) ;
} ) ;
action - > setCheckable ( true ) ;
action - > setChecked ( ! isColumnHidden ( i ) ) ;
}
2019-06-19 06:26:17 +03:00
2022-01-18 10:45:31 +03:00
menu - > addSeparator ( ) ;
QAction * resizeAction = menu - > addAction ( tr ( " Resize columns " ) , this , [ this ] ( )
{
for ( int i = 0 , count = header ( ) - > count ( ) ; i < count ; + + i )
{
if ( ! isColumnHidden ( i ) )
resizeColumnToContents ( i ) ;
}
saveSettings ( ) ;
} ) ;
resizeAction - > setToolTip ( tr ( " Resize all non-hidden columns to the size of their contents " ) ) ;
2019-06-19 06:26:17 +03:00
menu - > popup ( QCursor : : pos ( ) ) ;
2014-12-08 04:40:58 +03:00
}
2019-07-07 16:02:13 +03:00
void TransferListWidget : : setSelectedTorrentsSuperSeeding ( const bool enabled ) const
2014-12-08 04:40:58 +03:00
{
2021-01-06 15:12:40 +03:00
for ( BitTorrent : : Torrent * const torrent : asConst ( getSelectedTorrents ( ) ) )
2020-11-16 10:02:11 +03:00
{
2015-06-07 15:03:30 +03:00
if ( torrent - > hasMetadata ( ) )
2019-07-07 16:02:13 +03:00
torrent - > setSuperSeeding ( enabled ) ;
2014-12-08 04:40:58 +03:00
}
}
2022-01-14 09:45:03 +03:00
void TransferListWidget : : setSelectedTorrentsSequentialDownload ( const bool enabled ) const
{
for ( BitTorrent : : Torrent * const torrent : asConst ( getSelectedTorrents ( ) ) )
torrent - > setSequentialDownload ( enabled ) ;
}
void TransferListWidget : : setSelectedFirstLastPiecePrio ( const bool enabled ) const
{
for ( BitTorrent : : Torrent * const torrent : asConst ( getSelectedTorrents ( ) ) )
torrent - > setFirstLastPiecePriority ( enabled ) ;
}
2022-01-23 21:37:38 +03:00
void TransferListWidget : : setSelectedAutoTMMEnabled ( const bool enabled )
2014-12-08 04:40:58 +03:00
{
2022-01-23 21:37:38 +03:00
if ( enabled )
{
const QMessageBox : : StandardButton btn = QMessageBox : : question ( this , tr ( " Enable automatic torrent management " )
, tr ( " Are you sure you want to enable Automatic Torrent Management for the selected torrent(s)? They may be relocated. " )
, ( QMessageBox : : Yes | QMessageBox : : No ) , QMessageBox : : Yes ) ;
if ( btn ! = QMessageBox : : Yes ) return ;
}
2021-01-06 15:12:40 +03:00
for ( BitTorrent : : Torrent * const torrent : asConst ( getSelectedTorrents ( ) ) )
2016-05-08 22:47:50 +03:00
torrent - > setAutoTMMEnabled ( enabled ) ;
2016-02-09 11:56:48 +03:00
}
void TransferListWidget : : askNewCategoryForSelection ( )
{
2017-09-24 14:54:42 +03:00
const QString newCategoryName = TorrentCategoryDialog : : createCategory ( this ) ;
if ( ! newCategoryName . isEmpty ( ) )
setSelectionCategory ( newCategoryName ) ;
2014-12-08 04:40:58 +03:00
}
2017-06-05 03:22:17 +03:00
void TransferListWidget : : askAddTagsForSelection ( )
{
const QStringList tags = askTagsForSelection ( tr ( " Add Tags " ) ) ;
2018-11-18 21:40:37 +03:00
for ( const QString & tag : tags )
2017-06-05 03:22:17 +03:00
addSelectionTag ( tag ) ;
}
2019-06-24 18:37:31 +03:00
void TransferListWidget : : editTorrentTrackers ( )
{
2021-01-06 15:12:40 +03:00
const QVector < BitTorrent : : Torrent * > torrents = getSelectedTorrents ( ) ;
2019-06-27 18:36:54 +03:00
QVector < BitTorrent : : TrackerEntry > commonTrackers ;
2019-06-24 18:37:31 +03:00
2020-11-16 10:02:11 +03:00
if ( ! torrents . empty ( ) )
{
2019-06-24 18:37:31 +03:00
commonTrackers = torrents [ 0 ] - > trackers ( ) ;
2021-01-06 15:12:40 +03:00
for ( const BitTorrent : : Torrent * torrent : torrents )
2020-11-16 10:02:11 +03:00
{
2019-06-24 18:37:31 +03:00
QSet < BitTorrent : : TrackerEntry > trackerSet ;
for ( const BitTorrent : : TrackerEntry & entry : asConst ( torrent - > trackers ( ) ) )
trackerSet . insert ( entry ) ;
commonTrackers . erase ( std : : remove_if ( commonTrackers . begin ( ) , commonTrackers . end ( )
, [ & trackerSet ] ( const BitTorrent : : TrackerEntry & entry ) { return ! trackerSet . contains ( entry ) ; } )
, commonTrackers . end ( ) ) ;
}
}
auto trackerDialog = new TrackerEntriesDialog ( this ) ;
trackerDialog - > setAttribute ( Qt : : WA_DeleteOnClose ) ;
trackerDialog - > setTrackers ( commonTrackers ) ;
connect ( trackerDialog , & QDialog : : accepted , this , [ torrents , trackerDialog ] ( )
{
2021-01-06 15:12:40 +03:00
for ( BitTorrent : : Torrent * torrent : torrents )
2019-06-24 18:37:31 +03:00
torrent - > replaceTrackers ( trackerDialog - > trackers ( ) ) ;
} ) ;
trackerDialog - > open ( ) ;
}
2022-04-16 09:57:21 +03:00
void TransferListWidget : : exportTorrent ( )
{
if ( getSelectedTorrents ( ) . isEmpty ( ) )
return ;
auto fileDialog = new QFileDialog ( this , tr ( " Choose folder to save exported .torrent files " ) ) ;
fileDialog - > setAttribute ( Qt : : WA_DeleteOnClose ) ;
fileDialog - > setFileMode ( QFileDialog : : Directory ) ;
fileDialog - > setOptions ( QFileDialog : : ShowDirsOnly ) ;
connect ( fileDialog , & QFileDialog : : fileSelected , this , [ this ] ( const QString & dir )
{
const QVector < BitTorrent : : Torrent * > torrents = getSelectedTorrents ( ) ;
if ( torrents . isEmpty ( ) )
return ;
const Path savePath { dir } ;
if ( ! savePath . exists ( ) )
return ;
const QString errorMsg = tr ( " Export .torrent file failed. Torrent: \" %1 \" . Save path: \" %2 \" . Reason: \" %3 \" " ) ;
bool hasError = false ;
for ( const BitTorrent : : Torrent * torrent : torrents )
{
const Path filePath = savePath / Path ( torrent - > name ( ) + u " .torrent " ) ;
if ( filePath . exists ( ) )
{
LogMsg ( errorMsg . arg ( torrent - > name ( ) , filePath . toString ( ) , tr ( " A file with the same name already exists " ) ) , Log : : WARNING ) ;
hasError = true ;
continue ;
}
const nonstd : : expected < void , QString > result = torrent - > exportToFile ( filePath ) ;
if ( ! result )
{
LogMsg ( errorMsg . arg ( torrent - > name ( ) , filePath . toString ( ) , result . error ( ) ) , Log : : WARNING ) ;
hasError = true ;
continue ;
}
}
if ( hasError )
{
QMessageBox : : warning ( this , tr ( " Export .torrent file error " )
2022-07-06 08:11:11 +03:00
, tr ( " Errors occurred when exporting .torrent files. Check execution log for details. " ) ) ;
2022-04-16 09:57:21 +03:00
}
} ) ;
fileDialog - > open ( ) ;
}
2017-06-05 03:22:17 +03:00
void TransferListWidget : : confirmRemoveAllTagsForSelection ( )
{
QMessageBox : : StandardButton response = QMessageBox : : question (
this , tr ( " Remove All Tags " ) , tr ( " Remove all tags from selected torrents? " ) ,
QMessageBox : : Yes | QMessageBox : : No ) ;
if ( response = = QMessageBox : : Yes )
clearSelectionTags ( ) ;
}
QStringList TransferListWidget : : askTagsForSelection ( const QString & dialogTitle )
{
QStringList tags ;
bool invalid = true ;
2020-11-16 10:02:11 +03:00
while ( invalid )
{
2017-06-05 03:22:17 +03:00
bool ok = false ;
invalid = false ;
const QString tagsInput = AutoExpandableDialog : : getText (
2022-03-12 17:00:58 +03:00
this , dialogTitle , tr ( " Comma-separated tags: " ) , QLineEdit : : Normal , { } , & ok ) . trimmed ( ) ;
2017-06-05 03:22:17 +03:00
if ( ! ok | | tagsInput . isEmpty ( ) )
2019-02-14 20:16:42 +03:00
return { } ;
2022-03-12 17:00:58 +03:00
tags = tagsInput . split ( u ' , ' , Qt : : SkipEmptyParts ) ;
2020-11-16 10:02:11 +03:00
for ( QString & tag : tags )
{
2017-06-05 03:22:17 +03:00
tag = tag . trimmed ( ) ;
2020-11-16 10:02:11 +03:00
if ( ! BitTorrent : : Session : : isValidTag ( tag ) )
{
2017-06-05 03:22:17 +03:00
QMessageBox : : warning ( this , tr ( " Invalid tag " )
, tr ( " Tag name: '%1' is invalid " ) . arg ( tag ) ) ;
invalid = true ;
}
}
}
return tags ;
}
2021-01-06 15:12:40 +03:00
void TransferListWidget : : applyToSelectedTorrents ( const std : : function < void ( BitTorrent : : Torrent * const ) > & fn )
2017-06-05 03:22:17 +03:00
{
2020-11-16 10:02:11 +03:00
for ( const QModelIndex & index : asConst ( selectionModel ( ) - > selectedRows ( ) ) )
{
2021-01-06 15:12:40 +03:00
BitTorrent : : Torrent * const torrent = m_listModel - > torrentHandle ( mapToSource ( index ) ) ;
2017-06-05 03:22:17 +03:00
Q_ASSERT ( torrent ) ;
fn ( torrent ) ;
}
}
2014-12-08 04:40:58 +03:00
void TransferListWidget : : renameSelectedTorrent ( )
{
const QModelIndexList selectedIndexes = selectionModel ( ) - > selectedRows ( ) ;
2017-02-06 18:51:25 +03:00
if ( ( selectedIndexes . size ( ) ! = 1 ) | | ! selectedIndexes . first ( ) . isValid ( ) ) return ;
2015-06-07 15:03:30 +03:00
2018-06-14 12:54:23 +03:00
const QModelIndex mi = m_listModel - > index ( mapToSource ( selectedIndexes . first ( ) ) . row ( ) , TransferListModel : : TR_NAME ) ;
2021-01-06 15:12:40 +03:00
BitTorrent : : Torrent * const torrent = m_listModel - > torrentHandle ( mi ) ;
2015-04-19 18:17:47 +03:00
if ( ! torrent ) return ;
2014-12-08 04:40:58 +03:00
// Ask for a new Name
2020-03-06 10:04:29 +03:00
bool ok = false ;
2015-04-19 18:17:47 +03:00
QString name = AutoExpandableDialog : : getText ( this , tr ( " Rename " ) , tr ( " New name: " ) , QLineEdit : : Normal , torrent - > name ( ) , & ok ) ;
2020-11-16 10:02:11 +03:00
if ( ok & & ! name . isEmpty ( ) )
{
2022-03-12 17:00:58 +03:00
name . replace ( QRegularExpression ( u " \r ? \n | \r " _qs ) , u " " _qs ) ;
2014-12-08 04:40:58 +03:00
// Rename the torrent
2017-09-25 20:03:24 +03:00
m_listModel - > setData ( mi , name , Qt : : DisplayRole ) ;
2014-12-08 04:40:58 +03:00
}
}
2019-02-12 03:45:30 +03:00
void TransferListWidget : : setSelectionCategory ( const QString & category )
2014-12-08 04:40:58 +03:00
{
2018-11-27 23:15:04 +03:00
for ( const QModelIndex & index : asConst ( selectionModel ( ) - > selectedRows ( ) ) )
2018-06-14 12:54:23 +03:00
m_listModel - > setData ( m_listModel - > index ( mapToSource ( index ) . row ( ) , TransferListModel : : TR_CATEGORY ) , category , Qt : : DisplayRole ) ;
2014-12-08 04:40:58 +03:00
}
2017-06-05 03:22:17 +03:00
void TransferListWidget : : addSelectionTag ( const QString & tag )
{
2021-01-06 15:12:40 +03:00
applyToSelectedTorrents ( [ & tag ] ( BitTorrent : : Torrent * const torrent ) { torrent - > addTag ( tag ) ; } ) ;
2017-06-05 03:22:17 +03:00
}
void TransferListWidget : : removeSelectionTag ( const QString & tag )
{
2021-01-06 15:12:40 +03:00
applyToSelectedTorrents ( [ & tag ] ( BitTorrent : : Torrent * const torrent ) { torrent - > removeTag ( tag ) ; } ) ;
2017-06-05 03:22:17 +03:00
}
void TransferListWidget : : clearSelectionTags ( )
{
2021-01-06 15:12:40 +03:00
applyToSelectedTorrents ( [ ] ( BitTorrent : : Torrent * const torrent ) { torrent - > removeAllTags ( ) ; } ) ;
2017-06-05 03:22:17 +03:00
}
2022-01-21 12:31:31 +03:00
void TransferListWidget : : displayListMenu ( )
2014-12-08 04:40:58 +03:00
{
2018-11-18 21:40:37 +03:00
const QModelIndexList selectedIndexes = selectionModel ( ) - > selectedRows ( ) ;
2019-02-13 18:51:07 +03:00
if ( selectedIndexes . isEmpty ( ) ) return ;
2017-02-06 18:51:25 +03:00
2019-07-07 16:02:13 +03:00
auto * listMenu = new QMenu ( this ) ;
2019-06-23 18:45:21 +03:00
listMenu - > setAttribute ( Qt : : WA_DeleteOnClose ) ;
2022-01-24 01:15:04 +03:00
listMenu - > setToolTipsVisible ( true ) ;
2019-06-23 18:45:21 +03:00
2014-12-08 04:40:58 +03:00
// Create actions
2019-07-16 07:01:33 +03:00
2022-07-31 08:31:38 +03:00
auto * actionStart = new QAction ( UIThemeManager : : instance ( ) - > getIcon ( u " torrent-start " _qs ) , tr ( " &Resume " , " Resume/start the torrent " ) , listMenu ) ;
2019-06-03 10:10:19 +03:00
connect ( actionStart , & QAction : : triggered , this , & TransferListWidget : : startSelectedTorrents ) ;
2022-07-31 08:31:38 +03:00
auto * actionPause = new QAction ( UIThemeManager : : instance ( ) - > getIcon ( u " torrent-stop " _qs ) , tr ( " &Pause " , " Pause the torrent " ) , listMenu ) ;
2019-06-03 10:10:19 +03:00
connect ( actionPause , & QAction : : triggered , this , & TransferListWidget : : pauseSelectedTorrents ) ;
2022-07-31 08:31:38 +03:00
auto * actionForceStart = new QAction ( UIThemeManager : : instance ( ) - > getIcon ( u " torrent-start-forced " _qs ) , tr ( " Force Resu&me " , " Force Resume/start the torrent " ) , listMenu ) ;
2019-06-03 10:10:19 +03:00
connect ( actionForceStart , & QAction : : triggered , this , & TransferListWidget : : forceStartSelectedTorrents ) ;
2022-05-10 06:34:43 +03:00
auto * actionDelete = new QAction ( UIThemeManager : : instance ( ) - > getIcon ( u " list-remove " _qs ) , tr ( " &Delete " , " Delete the torrent " ) , listMenu ) ;
2019-06-03 10:10:19 +03:00
connect ( actionDelete , & QAction : : triggered , this , & TransferListWidget : : softDeleteSelectedTorrents ) ;
2022-05-10 06:34:43 +03:00
auto * actionPreviewFile = new QAction ( UIThemeManager : : instance ( ) - > getIcon ( u " view-preview " _qs ) , tr ( " Pre&view file... " ) , listMenu ) ;
2019-06-03 10:10:19 +03:00
connect ( actionPreviewFile , & QAction : : triggered , this , & TransferListWidget : : previewSelectedTorrents ) ;
2022-05-10 06:34:43 +03:00
auto * actionTorrentOptions = new QAction ( UIThemeManager : : instance ( ) - > getIcon ( u " configure " _qs ) , tr ( " Torrent &options... " ) , listMenu ) ;
2020-11-29 17:36:07 +03:00
connect ( actionTorrentOptions , & QAction : : triggered , this , & TransferListWidget : : setTorrentOptions ) ;
2022-07-31 08:31:38 +03:00
auto * actionOpenDestinationFolder = new QAction ( UIThemeManager : : instance ( ) - > getIcon ( u " directory " _qs ) , tr ( " Open destination &folder " ) , listMenu ) ;
2019-06-03 10:10:19 +03:00
connect ( actionOpenDestinationFolder , & QAction : : triggered , this , & TransferListWidget : : openSelectedTorrentsFolder ) ;
2022-05-10 06:34:43 +03:00
auto * actionIncreaseQueuePos = new QAction ( UIThemeManager : : instance ( ) - > getIcon ( u " go-up " _qs ) , tr ( " Move &up " , " i.e. move up in the queue " ) , listMenu ) ;
2018-12-08 02:01:09 +03:00
connect ( actionIncreaseQueuePos , & QAction : : triggered , this , & TransferListWidget : : increaseQueuePosSelectedTorrents ) ;
2022-05-10 06:34:43 +03:00
auto * actionDecreaseQueuePos = new QAction ( UIThemeManager : : instance ( ) - > getIcon ( u " go-down " _qs ) , tr ( " Move &down " , " i.e. Move down in the queue " ) , listMenu ) ;
2018-12-08 02:01:09 +03:00
connect ( actionDecreaseQueuePos , & QAction : : triggered , this , & TransferListWidget : : decreaseQueuePosSelectedTorrents ) ;
2022-05-10 06:34:43 +03:00
auto * actionTopQueuePos = new QAction ( UIThemeManager : : instance ( ) - > getIcon ( u " go-top " _qs ) , tr ( " Move to &top " , " i.e. Move to top of the queue " ) , listMenu ) ;
2018-12-08 02:01:09 +03:00
connect ( actionTopQueuePos , & QAction : : triggered , this , & TransferListWidget : : topQueuePosSelectedTorrents ) ;
2022-05-10 06:34:43 +03:00
auto * actionBottomQueuePos = new QAction ( UIThemeManager : : instance ( ) - > getIcon ( u " go-bottom " _qs ) , tr ( " Move to &bottom " , " i.e. Move to bottom of the queue " ) , listMenu ) ;
2018-12-08 02:01:09 +03:00
connect ( actionBottomQueuePos , & QAction : : triggered , this , & TransferListWidget : : bottomQueuePosSelectedTorrents ) ;
2021-11-21 18:59:38 +03:00
auto * actionSetTorrentPath = new QAction ( UIThemeManager : : instance ( ) - > getIcon ( u " set-location " _qs ) , tr ( " Set loc&ation... " ) , listMenu ) ;
2022-01-14 09:45:03 +03:00
connect ( actionSetTorrentPath , & QAction : : triggered , this , & TransferListWidget : : setSelectedTorrentsLocation ) ;
2021-11-21 18:59:38 +03:00
auto * actionForceRecheck = new QAction ( UIThemeManager : : instance ( ) - > getIcon ( u " force-recheck " _qs ) , tr ( " Force rec&heck " ) , listMenu ) ;
2019-06-03 10:10:19 +03:00
connect ( actionForceRecheck , & QAction : : triggered , this , & TransferListWidget : : recheckSelectedTorrents ) ;
2021-11-21 18:59:38 +03:00
auto * actionForceReannounce = new QAction ( UIThemeManager : : instance ( ) - > getIcon ( u " reannounce " _qs ) , tr ( " Force r&eannounce " ) , listMenu ) ;
2019-06-03 10:10:19 +03:00
connect ( actionForceReannounce , & QAction : : triggered , this , & TransferListWidget : : reannounceSelectedTorrents ) ;
2022-07-31 08:31:38 +03:00
auto * actionCopyMagnetLink = new QAction ( UIThemeManager : : instance ( ) - > getIcon ( u " torrent-magnet " _qs ) , tr ( " &Magnet link " ) , listMenu ) ;
2019-06-03 10:10:19 +03:00
connect ( actionCopyMagnetLink , & QAction : : triggered , this , & TransferListWidget : : copySelectedMagnetURIs ) ;
2021-11-21 18:59:38 +03:00
auto * actionCopyID = new QAction ( UIThemeManager : : instance ( ) - > getIcon ( u " help-about " _qs ) , tr ( " Torrent &ID " ) , listMenu ) ;
2021-06-25 20:44:23 +03:00
connect ( actionCopyID , & QAction : : triggered , this , & TransferListWidget : : copySelectedIDs ) ;
2021-11-21 18:59:38 +03:00
auto * actionCopyName = new QAction ( UIThemeManager : : instance ( ) - > getIcon ( u " name " _qs ) , tr ( " &Name " ) , listMenu ) ;
2019-06-03 10:10:19 +03:00
connect ( actionCopyName , & QAction : : triggered , this , & TransferListWidget : : copySelectedNames ) ;
2021-11-21 18:59:38 +03:00
auto * actionCopyHash1 = new QAction ( UIThemeManager : : instance ( ) - > getIcon ( u " hash " _qs ) , tr ( " Info &hash v1 " ) , listMenu ) ;
2021-06-25 20:44:23 +03:00
connect ( actionCopyHash1 , & QAction : : triggered , this , [ this ] ( ) { copySelectedInfohashes ( CopyInfohashPolicy : : Version1 ) ; } ) ;
2021-11-21 18:59:38 +03:00
auto * actionCopyHash2 = new QAction ( UIThemeManager : : instance ( ) - > getIcon ( u " hash " _qs ) , tr ( " Info h&ash v2 " ) , listMenu ) ;
2021-06-25 20:44:23 +03:00
connect ( actionCopyHash2 , & QAction : : triggered , this , [ this ] ( ) { copySelectedInfohashes ( CopyInfohashPolicy : : Version2 ) ; } ) ;
2019-07-07 16:02:13 +03:00
auto * actionSuperSeedingMode = new TriStateAction ( tr ( " Super seeding mode " ) , listMenu ) ;
connect ( actionSuperSeedingMode , & QAction : : triggered , this , & TransferListWidget : : setSelectedTorrentsSuperSeeding ) ;
2022-05-10 06:34:43 +03:00
auto * actionRename = new QAction ( UIThemeManager : : instance ( ) - > getIcon ( u " edit-rename " _qs ) , tr ( " Re&name... " ) , listMenu ) ;
2019-06-03 10:10:19 +03:00
connect ( actionRename , & QAction : : triggered , this , & TransferListWidget : : renameSelectedTorrent ) ;
2022-01-14 09:45:03 +03:00
auto * actionSequentialDownload = new TriStateAction ( tr ( " Download in sequential order " ) , listMenu ) ;
connect ( actionSequentialDownload , & QAction : : triggered , this , & TransferListWidget : : setSelectedTorrentsSequentialDownload ) ;
auto * actionFirstLastPiecePrio = new TriStateAction ( tr ( " Download first and last pieces first " ) , listMenu ) ;
connect ( actionFirstLastPiecePrio , & QAction : : triggered , this , & TransferListWidget : : setSelectedFirstLastPiecePrio ) ;
auto * actionAutoTMM = new TriStateAction ( tr ( " Automatic Torrent Management " ) , listMenu ) ;
2022-01-24 01:15:04 +03:00
actionAutoTMM - > setToolTip ( tr ( " Automatic mode means that various torrent properties (e.g. save path) will be decided by the associated category " ) ) ;
2022-01-14 09:45:03 +03:00
connect ( actionAutoTMM , & QAction : : triggered , this , & TransferListWidget : : setSelectedAutoTMMEnabled ) ;
2022-05-10 06:34:43 +03:00
auto * actionEditTracker = new QAction ( UIThemeManager : : instance ( ) - > getIcon ( u " edit-rename " _qs ) , tr ( " Edit trac&kers... " ) , listMenu ) ;
2019-06-24 18:37:31 +03:00
connect ( actionEditTracker , & QAction : : triggered , this , & TransferListWidget : : editTorrentTrackers ) ;
2022-05-10 06:34:43 +03:00
auto * actionExportTorrent = new QAction ( UIThemeManager : : instance ( ) - > getIcon ( u " edit-copy " _qs ) , tr ( " E&xport .torrent... " ) , listMenu ) ;
2022-04-16 09:57:21 +03:00
connect ( actionExportTorrent , & QAction : : triggered , this , & TransferListWidget : : exportTorrent ) ;
2014-12-08 04:40:58 +03:00
// End of actions
2015-07-19 22:59:07 +03:00
2014-12-08 04:40:58 +03:00
// Enable/disable pause/start action given the DL state
2018-06-06 16:48:17 +03:00
bool needsPause = false , needsStart = false , needsForce = false , needsPreview = false ;
bool allSameSuperSeeding = true ;
bool superSeedingMode = false ;
bool allSameSequentialDownloadMode = true , allSamePrioFirstlast = true ;
bool sequentialDownloadMode = false , prioritizeFirstLast = false ;
bool oneHasMetadata = false , oneNotSeed = false ;
2016-02-09 11:56:48 +03:00
bool allSameCategory = true ;
2022-01-14 09:45:03 +03:00
bool allSameAutoTMM = true ;
bool firstAutoTMM = false ;
2016-02-09 11:56:48 +03:00
QString firstCategory ;
2014-12-08 04:40:58 +03:00
bool first = true ;
2021-04-02 08:45:50 +03:00
TagSet tagsInAny ;
TagSet tagsInAll ;
2021-06-25 20:44:23 +03:00
bool hasInfohashV1 = false , hasInfohashV2 = false ;
2022-03-06 07:59:31 +03:00
bool oneCanForceReannounce = false ;
2015-04-19 18:17:47 +03:00
2020-11-16 10:02:11 +03:00
for ( const QModelIndex & index : selectedIndexes )
{
2014-12-08 04:40:58 +03:00
// Get the file name
// Get handle and pause the torrent
2021-01-06 15:12:40 +03:00
const BitTorrent : : Torrent * torrent = m_listModel - > torrentHandle ( mapToSource ( index ) ) ;
2015-04-19 18:17:47 +03:00
if ( ! torrent ) continue ;
2016-02-09 11:56:48 +03:00
if ( firstCategory . isEmpty ( ) & & first )
firstCategory = torrent - > category ( ) ;
if ( firstCategory ! = torrent - > category ( ) )
allSameCategory = false ;
2015-09-16 02:01:51 +03:00
2021-04-02 08:45:50 +03:00
const TagSet torrentTags = torrent - > tags ( ) ;
tagsInAny . unite ( torrentTags ) ;
2017-06-05 03:22:17 +03:00
2020-11-16 10:02:11 +03:00
if ( first )
{
2022-01-14 09:45:03 +03:00
firstAutoTMM = torrent - > isAutoTMMEnabled ( ) ;
2021-04-02 08:45:50 +03:00
tagsInAll = torrentTags ;
2017-07-10 02:15:08 +03:00
}
2020-11-16 10:02:11 +03:00
else
{
2021-04-02 08:45:50 +03:00
tagsInAll . intersect ( torrentTags ) ;
2017-07-10 02:15:08 +03:00
}
2019-07-07 16:02:13 +03:00
2022-01-14 09:45:03 +03:00
if ( firstAutoTMM ! = torrent - > isAutoTMMEnabled ( ) )
allSameAutoTMM = false ;
2015-04-19 18:17:47 +03:00
if ( torrent - > hasMetadata ( ) )
2018-06-06 16:48:17 +03:00
oneHasMetadata = true ;
2020-11-16 10:02:11 +03:00
if ( ! torrent - > isSeed ( ) )
{
2018-06-06 16:48:17 +03:00
oneNotSeed = true ;
2020-11-16 10:02:11 +03:00
if ( first )
{
2018-08-14 11:42:28 +03:00
sequentialDownloadMode = torrent - > isSequentialDownload ( ) ;
prioritizeFirstLast = torrent - > hasFirstLastPiecePriority ( ) ;
}
2020-11-16 10:02:11 +03:00
else
{
2018-08-14 11:42:28 +03:00
if ( sequentialDownloadMode ! = torrent - > isSequentialDownload ( ) )
allSameSequentialDownloadMode = false ;
if ( prioritizeFirstLast ! = torrent - > hasFirstLastPiecePriority ( ) )
allSamePrioFirstlast = false ;
2014-12-08 04:40:58 +03:00
}
}
2020-11-16 10:02:11 +03:00
else
{
if ( ! oneNotSeed & & allSameSuperSeeding & & torrent - > hasMetadata ( ) )
{
2018-08-14 11:42:28 +03:00
if ( first )
2018-06-06 16:48:17 +03:00
superSeedingMode = torrent - > superSeeding ( ) ;
else if ( superSeedingMode ! = torrent - > superSeeding ( ) )
allSameSuperSeeding = false ;
2014-12-08 04:40:58 +03:00
}
}
2020-04-19 16:12:50 +03:00
2015-07-19 22:59:07 +03:00
if ( ! torrent - > isForced ( ) )
2018-06-06 16:48:17 +03:00
needsForce = true ;
2015-07-19 22:59:07 +03:00
else
2018-06-06 16:48:17 +03:00
needsStart = true ;
2020-04-19 16:12:50 +03:00
2022-03-06 07:59:31 +03:00
const bool isPaused = torrent - > isPaused ( ) ;
if ( isPaused )
2018-06-06 16:48:17 +03:00
needsStart = true ;
2015-07-19 22:59:07 +03:00
else
2018-06-06 16:48:17 +03:00
needsPause = true ;
2020-04-19 16:12:50 +03:00
2020-11-16 10:02:11 +03:00
if ( torrent - > isErrored ( ) | | torrent - > hasMissingFiles ( ) )
{
2020-04-19 16:12:50 +03:00
// If torrent is in "errored" or "missing files" state
// it cannot keep further processing until you restart it.
needsStart = true ;
needsForce = true ;
}
2015-07-19 22:59:07 +03:00
if ( torrent - > hasMetadata ( ) )
2018-06-06 16:48:17 +03:00
needsPreview = true ;
2015-07-19 22:59:07 +03:00
2021-06-25 20:44:23 +03:00
if ( ! hasInfohashV1 & & torrent - > infoHash ( ) . v1 ( ) . isValid ( ) )
hasInfohashV1 = true ;
if ( ! hasInfohashV2 & & torrent - > infoHash ( ) . v2 ( ) . isValid ( ) )
hasInfohashV2 = true ;
2014-12-08 04:40:58 +03:00
first = false ;
2015-07-19 22:59:07 +03:00
2022-03-06 07:59:31 +03:00
const bool rechecking = torrent - > isChecking ( ) ;
const bool queued = ( BitTorrent : : Session : : instance ( ) - > isQueueingSystemEnabled ( ) & & torrent - > isQueued ( ) ) ;
if ( ! isPaused & & ! rechecking & & ! queued )
oneCanForceReannounce = true ;
2018-06-06 16:48:17 +03:00
if ( oneHasMetadata & & oneNotSeed & & ! allSameSequentialDownloadMode
& & ! allSamePrioFirstlast & & ! allSameSuperSeeding & & ! allSameCategory
2022-01-14 09:45:03 +03:00
& & needsStart & & needsForce & & needsPause & & needsPreview & & ! allSameAutoTMM
2022-03-06 07:59:31 +03:00
& & hasInfohashV1 & & hasInfohashV2 & & oneCanForceReannounce )
2021-06-25 20:44:23 +03:00
{
2015-07-19 22:59:07 +03:00
break ;
}
2014-12-08 04:40:58 +03:00
}
2019-06-03 10:10:19 +03:00
2018-06-06 16:48:17 +03:00
if ( needsStart )
2019-06-03 10:10:19 +03:00
listMenu - > addAction ( actionStart ) ;
2018-06-06 16:48:17 +03:00
if ( needsPause )
2019-06-03 10:10:19 +03:00
listMenu - > addAction ( actionPause ) ;
2018-06-06 16:48:17 +03:00
if ( needsForce )
2019-06-03 10:10:19 +03:00
listMenu - > addAction ( actionForceStart ) ;
listMenu - > addSeparator ( ) ;
listMenu - > addAction ( actionDelete ) ;
listMenu - > addSeparator ( ) ;
2022-01-14 09:45:03 +03:00
listMenu - > addAction ( actionSetTorrentPath ) ;
2014-12-08 04:40:58 +03:00
if ( selectedIndexes . size ( ) = = 1 )
2019-06-03 10:10:19 +03:00
listMenu - > addAction ( actionRename ) ;
2019-06-24 18:37:31 +03:00
listMenu - > addAction ( actionEditTracker ) ;
2019-06-03 10:10:19 +03:00
2022-01-14 09:45:03 +03:00
// Category Menu
QStringList categories = BitTorrent : : Session : : instance ( ) - > categories ( ) ;
std : : sort ( categories . begin ( ) , categories . end ( ) , Utils : : Compare : : NaturalLessThan < Qt : : CaseInsensitive > ( ) ) ;
2022-05-10 06:34:43 +03:00
QMenu * categoryMenu = listMenu - > addMenu ( UIThemeManager : : instance ( ) - > getIcon ( u " view-categories " _qs ) , tr ( " Categor&y " ) ) ;
2022-01-14 09:45:03 +03:00
2022-05-10 06:34:43 +03:00
categoryMenu - > addAction ( UIThemeManager : : instance ( ) - > getIcon ( u " list-add " _qs ) , tr ( " &New... " , " New category... " )
2022-01-14 09:45:03 +03:00
, this , & TransferListWidget : : askNewCategoryForSelection ) ;
2022-05-10 06:34:43 +03:00
categoryMenu - > addAction ( UIThemeManager : : instance ( ) - > getIcon ( u " edit-clear " _qs ) , tr ( " &Reset " , " Reset category " )
2022-03-12 17:00:58 +03:00
, this , [ this ] ( ) { setSelectionCategory ( u " " _qs ) ; } ) ;
2022-01-14 09:45:03 +03:00
categoryMenu - > addSeparator ( ) ;
for ( const QString & category : asConst ( categories ) )
{
2022-03-12 17:00:58 +03:00
const QString escapedCategory = QString ( category ) . replace ( u ' & ' , u " && " _qs ) ; // avoid '&' becomes accelerator key
2021-11-21 18:59:38 +03:00
QAction * categoryAction = categoryMenu - > addAction ( UIThemeManager : : instance ( ) - > getIcon ( u " view-categories " _qs ) , escapedCategory
2022-01-14 09:45:03 +03:00
, this , [ this , category ] ( ) { setSelectionCategory ( category ) ; } ) ;
if ( allSameCategory & & ( category = = firstCategory ) )
{
categoryAction - > setCheckable ( true ) ;
categoryAction - > setChecked ( true ) ;
}
}
2017-06-05 03:22:17 +03:00
// Tag Menu
2019-12-23 04:58:28 +03:00
QStringList tags ( BitTorrent : : Session : : instance ( ) - > tags ( ) . values ( ) ) ;
2021-04-05 08:02:28 +03:00
std : : sort ( tags . begin ( ) , tags . end ( ) , Utils : : Compare : : NaturalLessThan < Qt : : CaseInsensitive > ( ) ) ;
2019-06-03 10:10:19 +03:00
2021-11-21 18:59:38 +03:00
QMenu * tagsMenu = listMenu - > addMenu ( UIThemeManager : : instance ( ) - > getIcon ( u " tags " _qs ) , tr ( " Ta&gs " ) ) ;
2019-06-03 10:10:19 +03:00
2022-05-10 06:34:43 +03:00
tagsMenu - > addAction ( UIThemeManager : : instance ( ) - > getIcon ( u " list-add " _qs ) , tr ( " &Add... " , " Add / assign multiple tags... " )
2021-01-17 09:56:56 +03:00
, this , & TransferListWidget : : askAddTagsForSelection ) ;
2022-05-10 06:34:43 +03:00
tagsMenu - > addAction ( UIThemeManager : : instance ( ) - > getIcon ( u " edit-clear " _qs ) , tr ( " &Remove All " , " Remove all tags " )
2021-01-17 09:56:56 +03:00
, this , [ this ] ( )
2019-06-03 10:10:19 +03:00
{
if ( Preferences : : instance ( ) - > confirmRemoveAllTags ( ) )
confirmRemoveAllTagsForSelection ( ) ;
else
clearSelectionTags ( ) ;
} ) ;
2017-06-05 03:22:17 +03:00
tagsMenu - > addSeparator ( ) ;
2019-06-03 10:10:19 +03:00
2020-11-16 10:02:11 +03:00
for ( const QString & tag : asConst ( tags ) )
{
2019-07-07 16:02:13 +03:00
auto * action = new TriStateAction ( tag , tagsMenu ) ;
2021-06-16 17:57:56 +03:00
action - > setCloseOnInteraction ( false ) ;
2019-07-07 16:02:13 +03:00
2017-07-10 02:15:08 +03:00
const Qt : : CheckState initialState = tagsInAll . contains ( tag ) ? Qt : : Checked
2021-04-02 08:45:50 +03:00
: tagsInAny . contains ( tag ) ? Qt : : PartiallyChecked : Qt : : Unchecked ;
2019-07-07 16:02:13 +03:00
action - > setCheckState ( initialState ) ;
2017-07-10 02:15:08 +03:00
2021-06-16 17:57:56 +03:00
connect ( action , & QAction : : toggled , this , [ this , tag ] ( const bool checked )
2017-07-10 02:15:08 +03:00
{
2019-07-07 16:02:13 +03:00
if ( checked )
2017-07-10 02:15:08 +03:00
addSelectionTag ( tag ) ;
else
removeSelectionTag ( tag ) ;
2019-07-07 16:02:13 +03:00
} ) ;
2017-07-10 02:15:08 +03:00
2019-07-07 16:02:13 +03:00
tagsMenu - > addAction ( action ) ;
2017-06-05 03:22:17 +03:00
}
2022-01-14 09:45:03 +03:00
actionAutoTMM - > setCheckState ( allSameAutoTMM
? ( firstAutoTMM ? Qt : : Checked : Qt : : Unchecked )
: Qt : : PartiallyChecked ) ;
listMenu - > addAction ( actionAutoTMM ) ;
2019-06-03 10:10:19 +03:00
listMenu - > addSeparator ( ) ;
2020-11-29 17:36:07 +03:00
listMenu - > addAction ( actionTorrentOptions ) ;
2020-11-16 10:02:11 +03:00
if ( ! oneNotSeed & & oneHasMetadata )
{
2019-07-07 16:02:13 +03:00
actionSuperSeedingMode - > setCheckState ( allSameSuperSeeding
? ( superSeedingMode ? Qt : : Checked : Qt : : Unchecked )
: Qt : : PartiallyChecked ) ;
2019-06-03 10:10:19 +03:00
listMenu - > addAction ( actionSuperSeedingMode ) ;
2014-12-08 04:40:58 +03:00
}
2019-06-03 10:10:19 +03:00
listMenu - > addSeparator ( ) ;
2018-06-06 16:48:17 +03:00
bool addedPreviewAction = false ;
2020-11-16 10:02:11 +03:00
if ( needsPreview )
{
2019-06-03 10:10:19 +03:00
listMenu - > addAction ( actionPreviewFile ) ;
2018-06-06 16:48:17 +03:00
addedPreviewAction = true ;
2014-12-08 04:40:58 +03:00
}
2020-11-16 10:02:11 +03:00
if ( oneNotSeed )
2022-01-14 09:45:03 +03:00
{
actionSequentialDownload - > setCheckState ( allSameSequentialDownloadMode
? ( sequentialDownloadMode ? Qt : : Checked : Qt : : Unchecked )
: Qt : : PartiallyChecked ) ;
listMenu - > addAction ( actionSequentialDownload ) ;
actionFirstLastPiecePrio - > setCheckState ( allSamePrioFirstlast
? ( prioritizeFirstLast ? Qt : : Checked : Qt : : Unchecked )
: Qt : : PartiallyChecked ) ;
listMenu - > addAction ( actionFirstLastPiecePrio ) ;
2022-01-20 07:30:46 +03:00
2019-07-07 16:02:13 +03:00
addedPreviewAction = true ;
2022-01-20 07:30:46 +03:00
}
2016-02-09 11:56:48 +03:00
2018-06-06 16:48:17 +03:00
if ( addedPreviewAction )
2019-06-03 10:10:19 +03:00
listMenu - > addSeparator ( ) ;
2020-11-16 10:02:11 +03:00
if ( oneHasMetadata )
2019-06-03 10:10:19 +03:00
listMenu - > addAction ( actionForceRecheck ) ;
2022-03-06 07:59:31 +03:00
// We can not force reannounce torrents that are paused/errored/checking/missing files/queued.
// We may already have the tracker list from magnet url. So we can force reannounce torrents without metadata anyway.
listMenu - > addAction ( actionForceReannounce ) ;
actionForceReannounce - > setEnabled ( oneCanForceReannounce ) ;
if ( ! oneCanForceReannounce )
actionForceReannounce - > setToolTip ( tr ( " Can not force reannounce if torrent is Paused/Queued/Errored/Checking " ) ) ;
listMenu - > addSeparator ( ) ;
2019-06-03 10:10:19 +03:00
listMenu - > addAction ( actionOpenDestinationFolder ) ;
2020-11-16 10:02:11 +03:00
if ( BitTorrent : : Session : : instance ( ) - > isQueueingSystemEnabled ( ) & & oneNotSeed )
{
2019-06-03 10:10:19 +03:00
listMenu - > addSeparator ( ) ;
2021-11-21 18:59:38 +03:00
QMenu * queueMenu = listMenu - > addMenu (
UIThemeManager : : instance ( ) - > getIcon ( u " queued " _qs ) , tr ( " &Queue " ) ) ;
2018-12-08 02:01:09 +03:00
queueMenu - > addAction ( actionTopQueuePos ) ;
queueMenu - > addAction ( actionIncreaseQueuePos ) ;
queueMenu - > addAction ( actionDecreaseQueuePos ) ;
queueMenu - > addAction ( actionBottomQueuePos ) ;
2014-12-08 04:40:58 +03:00
}
2019-06-23 18:13:58 +03:00
2022-05-10 06:34:43 +03:00
QMenu * copySubMenu = listMenu - > addMenu ( UIThemeManager : : instance ( ) - > getIcon ( u " edit-copy " _qs ) , tr ( " &Copy " ) ) ;
2019-06-23 18:13:58 +03:00
copySubMenu - > addAction ( actionCopyName ) ;
2021-06-25 20:44:23 +03:00
copySubMenu - > addAction ( actionCopyHash1 ) ;
actionCopyHash1 - > setEnabled ( hasInfohashV1 ) ;
copySubMenu - > addAction ( actionCopyHash2 ) ;
actionCopyHash2 - > setEnabled ( hasInfohashV2 ) ;
2019-06-23 18:13:58 +03:00
copySubMenu - > addAction ( actionCopyMagnetLink ) ;
2021-06-25 20:44:23 +03:00
copySubMenu - > addAction ( actionCopyID ) ;
2019-06-03 10:10:19 +03:00
2022-04-16 09:57:21 +03:00
actionExportTorrent - > setToolTip ( u " Exported torrent is not necessarily the same as the imported " _qs ) ;
listMenu - > addAction ( actionExportTorrent ) ;
2019-06-03 10:10:19 +03:00
listMenu - > popup ( QCursor : : pos ( ) ) ;
2014-12-08 04:40:58 +03:00
}
2018-11-06 18:49:17 +03:00
void TransferListWidget : : currentChanged ( const QModelIndex & current , const QModelIndex & )
2014-12-08 04:40:58 +03:00
{
qDebug ( " CURRENT CHANGED " ) ;
2021-01-06 15:12:40 +03:00
BitTorrent : : Torrent * torrent = nullptr ;
2020-11-16 10:02:11 +03:00
if ( current . isValid ( ) )
{
2017-09-25 20:03:24 +03:00
torrent = m_listModel - > torrentHandle ( mapToSource ( current ) ) ;
2022-03-01 07:49:40 +03:00
// Fix scrolling to the lowermost visible torrent
QMetaObject : : invokeMethod ( this , [ this , current ] { scrollTo ( current ) ; } , Qt : : QueuedConnection ) ;
2014-12-08 04:40:58 +03:00
}
2015-04-19 18:17:47 +03:00
emit currentTorrentChanged ( torrent ) ;
2014-12-08 04:40:58 +03:00
}
2019-02-12 03:45:30 +03:00
void TransferListWidget : : applyCategoryFilter ( const QString & category )
2014-12-08 04:40:58 +03:00
{
2016-02-09 11:56:48 +03:00
if ( category . isNull ( ) )
2017-09-25 20:03:24 +03:00
m_sortFilterModel - > disableCategoryFilter ( ) ;
2015-07-14 16:03:51 +03:00
else
2017-09-25 20:03:24 +03:00
m_sortFilterModel - > setCategoryFilter ( category ) ;
2014-12-08 04:40:58 +03:00
}
2017-06-05 03:22:17 +03:00
void TransferListWidget : : applyTagFilter ( const QString & tag )
{
if ( tag . isNull ( ) )
2017-09-25 20:03:24 +03:00
m_sortFilterModel - > disableTagFilter ( ) ;
2017-06-05 03:22:17 +03:00
else
2017-09-25 20:03:24 +03:00
m_sortFilterModel - > setTagFilter ( tag ) ;
2017-06-05 03:22:17 +03:00
}
2015-03-22 02:18:21 +03:00
void TransferListWidget : : applyTrackerFilterAll ( )
{
2017-09-25 20:03:24 +03:00
m_sortFilterModel - > disableTrackerFilter ( ) ;
2015-03-22 02:18:21 +03:00
}
2021-03-05 12:43:58 +03:00
void TransferListWidget : : applyTrackerFilter ( const QSet < BitTorrent : : TorrentID > & torrentIDs )
2015-03-22 02:18:21 +03:00
{
2021-03-05 12:43:58 +03:00
m_sortFilterModel - > setTrackerFilter ( torrentIDs ) ;
2015-03-22 02:18:21 +03:00
}
2018-06-06 16:48:17 +03:00
void TransferListWidget : : applyNameFilter ( const QString & name )
2014-12-08 04:40:58 +03:00
{
2021-03-14 18:11:23 +03:00
const QString pattern = ( Preferences : : instance ( ) - > getRegexAsFilteringPatternForTransferList ( )
? name : Utils : : String : : wildcardToRegexPattern ( name ) ) ;
m_sortFilterModel - > setFilterRegularExpression ( QRegularExpression ( pattern , QRegularExpression : : CaseInsensitiveOption ) ) ;
2014-12-08 04:40:58 +03:00
}
void TransferListWidget : : applyStatusFilter ( int f )
{
2017-09-25 20:03:24 +03:00
m_sortFilterModel - > setStatusFilter ( static_cast < TorrentFilter : : Type > ( f ) ) ;
2014-12-08 04:40:58 +03:00
// Select first item if nothing is selected
2020-11-16 10:02:11 +03:00
if ( selectionModel ( ) - > selectedRows ( 0 ) . empty ( ) & & ( m_sortFilterModel - > rowCount ( ) > 0 ) )
{
2018-06-14 12:54:23 +03:00
qDebug ( " Nothing is selected, selecting first row: %s " , qUtf8Printable ( m_sortFilterModel - > index ( 0 , TransferListModel : : TR_NAME ) . data ( ) . toString ( ) ) ) ;
selectionModel ( ) - > setCurrentIndex ( m_sortFilterModel - > index ( 0 , TransferListModel : : TR_NAME ) , QItemSelectionModel : : SelectCurrent | QItemSelectionModel : : Rows ) ;
2014-12-08 04:40:58 +03:00
}
2009-11-08 16:19:00 +03:00
}
2009-11-09 11:56:21 +03:00
2010-12-04 12:51:43 +03:00
void TransferListWidget : : saveSettings ( )
{
2014-12-08 04:40:58 +03:00
Preferences : : instance ( ) - > setTransHeaderState ( header ( ) - > saveState ( ) ) ;
2010-12-04 12:51:43 +03:00
}
2011-03-13 20:49:56 +03:00
bool TransferListWidget : : loadSettings ( )
2010-12-04 12:51:43 +03:00
{
2017-12-08 17:05:21 +03:00
return header ( ) - > restoreState ( Preferences : : instance ( ) - > getTransHeaderState ( ) ) ;
2010-12-04 12:51:43 +03:00
}
2016-11-27 10:14:41 +03:00
void TransferListWidget : : wheelEvent ( QWheelEvent * event )
{
2020-11-16 10:02:11 +03:00
if ( event - > modifiers ( ) & Qt : : ShiftModifier )
{
2016-11-27 10:14:41 +03:00
// Shift + scroll = horizontal scroll
2019-06-11 15:32:34 +03:00
event - > accept ( ) ;
2022-03-17 04:45:24 +03:00
QWheelEvent scrollHEvent { event - > position ( ) , event - > globalPosition ( )
2020-06-04 08:29:32 +03:00
, event - > pixelDelta ( ) , event - > angleDelta ( ) . transposed ( ) , event - > buttons ( )
2022-03-17 04:45:24 +03:00
, event - > modifiers ( ) , event - > phase ( ) , event - > inverted ( ) , event - > source ( ) } ;
2016-11-27 10:14:41 +03:00
QTreeView : : wheelEvent ( & scrollHEvent ) ;
return ;
}
QTreeView : : wheelEvent ( event ) ; // event delegated to base class
}