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"
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>
2017-03-30 05:17:39 +03:00
# include <QRegExp>
2018-05-24 18:41:03 +03:00
# include <QRegularExpression>
2017-03-30 05:17:39 +03:00
# include <QShortcut>
2018-05-24 18:39:02 +03:00
# include <QStylePainter>
2015-11-18 19:13:25 +03:00
# include <QTableView>
2017-03-30 05:17:39 +03:00
# include <QWheelEvent>
2017-07-10 02:15:08 +03:00
# include <QWidgetAction>
2010-12-26 12:51:37 +03:00
2015-09-25 11:10:05 +03:00
# include "base/bittorrent/session.h"
# include "base/bittorrent/torrenthandle.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"
2017-03-30 05:17:39 +03:00
# include "base/preferences.h"
2015-09-25 11:10:05 +03:00
# include "base/torrentfilter.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 "guiiconprovider.h"
# 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"
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"
2018-06-14 12:54:23 +03:00
# include "updownratiodialog.h"
2019-03-02 08:22:13 +03:00
# include "utils.h"
2010-07-16 19:03:18 +04:00
2017-12-12 18:00:56 +03:00
# ifdef Q_OS_MAC
# include "macutilities.h"
# endif
2017-07-10 02:15:08 +03:00
namespace
{
using ToggleFn = std : : function < void ( Qt : : CheckState ) > ;
QStringList extractHashes ( const QList < BitTorrent : : TorrentHandle * > & torrents )
{
QStringList hashes ;
2018-11-18 21:40:37 +03:00
for ( BitTorrent : : TorrentHandle * const torrent : torrents )
2017-07-10 02:15:08 +03:00
hashes < < torrent - > hash ( ) ;
return hashes ;
}
// Helper for setting style parameters when painting check box primitives.
2018-06-06 16:48:17 +03:00
class CheckBoxIconHelper : public QCheckBox
2017-07-10 02:15:08 +03:00
{
public :
explicit CheckBoxIconHelper ( QWidget * parent ) ;
QSize sizeHint ( ) const override ;
void initStyleOption ( QStyleOptionButton * opt ) const ;
protected :
void paintEvent ( QPaintEvent * ) override { }
} ;
CheckBoxIconHelper : : CheckBoxIconHelper ( QWidget * parent )
: QCheckBox ( parent )
{
setSizePolicy ( QSizePolicy : : Fixed , QSizePolicy : : Fixed ) ;
}
QSize CheckBoxIconHelper : : sizeHint ( ) const
{
const int dim = QCheckBox : : sizeHint ( ) . height ( ) ;
2019-02-14 20:16:42 +03:00
return { dim , dim } ;
2017-07-10 02:15:08 +03:00
}
void CheckBoxIconHelper : : initStyleOption ( QStyleOptionButton * opt ) const
{
QCheckBox : : initStyleOption ( opt ) ;
}
// Tristate checkbox styled for use in menus.
2018-06-06 16:48:17 +03:00
class MenuCheckBox : public QWidget
2017-07-10 02:15:08 +03:00
{
public :
MenuCheckBox ( const QString & text , const ToggleFn & onToggle , Qt : : CheckState initialState ) ;
QSize sizeHint ( ) const override ;
protected :
void paintEvent ( QPaintEvent * e ) override ;
void mousePressEvent ( QMouseEvent * ) override ;
private :
CheckBoxIconHelper * const m_checkBox ;
const QString m_text ;
QSize m_sizeHint ;
QSize m_checkBoxOffset ;
} ;
MenuCheckBox : : MenuCheckBox ( const QString & text , const ToggleFn & onToggle , Qt : : CheckState initialState )
: m_checkBox ( new CheckBoxIconHelper ( this ) )
, m_text ( text )
, m_sizeHint ( QCheckBox ( m_text ) . sizeHint ( ) )
{
m_checkBox - > setCheckState ( initialState ) ;
2018-03-08 20:22:29 +03:00
connect ( m_checkBox , & QCheckBox : : stateChanged , this , [ this , onToggle ] ( int newState )
2017-07-10 02:15:08 +03:00
{
m_checkBox - > setTristate ( false ) ;
onToggle ( static_cast < Qt : : CheckState > ( newState ) ) ;
} ) ;
setSizePolicy ( QSizePolicy : : Expanding , QSizePolicy : : Preferred ) ;
setMouseTracking ( true ) ;
// We attempt to mimic the amount of vertical whitespace padding around a QCheckBox.
QSize layoutPadding ( 3 , 0 ) ;
const int sizeHintMargin = ( m_sizeHint . height ( ) - m_checkBox - > sizeHint ( ) . height ( ) ) / 2 ;
if ( sizeHintMargin > 0 ) {
m_checkBoxOffset . setHeight ( sizeHintMargin ) ;
}
else {
layoutPadding . setHeight ( 1 ) ;
m_checkBoxOffset . setHeight ( 1 ) ;
}
m_checkBoxOffset . setWidth ( layoutPadding . width ( ) ) ;
2019-02-13 18:12:02 +03:00
auto * layout = new QHBoxLayout ( this ) ;
2017-07-10 02:15:08 +03:00
layout - > addWidget ( m_checkBox ) ;
layout - > addStretch ( ) ;
layout - > setContentsMargins ( layoutPadding . width ( ) , layoutPadding . height ( ) , layoutPadding . width ( ) , layoutPadding . height ( ) ) ;
setLayout ( layout ) ;
}
QSize MenuCheckBox : : sizeHint ( ) const
{
return m_sizeHint ;
}
void MenuCheckBox : : paintEvent ( QPaintEvent * e )
{
if ( ! rect ( ) . intersects ( e - > rect ( ) ) )
return ;
QStylePainter painter ( this ) ;
QStyleOptionMenuItem menuOpt ;
menuOpt . initFrom ( this ) ;
menuOpt . menuItemType = QStyleOptionMenuItem : : Normal ;
menuOpt . text = m_text ;
QStyleOptionButton checkBoxOpt ;
m_checkBox - > initStyleOption ( & checkBoxOpt ) ;
checkBoxOpt . rect . translate ( m_checkBoxOffset . width ( ) , m_checkBoxOffset . height ( ) ) ;
if ( rect ( ) . contains ( mapFromGlobal ( QCursor : : pos ( ) ) ) ) {
menuOpt . state | = QStyle : : State_Selected ;
checkBoxOpt . state | = QStyle : : State_MouseOver ;
}
painter . drawControl ( QStyle : : CE_MenuItem , menuOpt ) ;
painter . drawPrimitive ( QStyle : : PE_IndicatorCheckBox , checkBoxOpt ) ;
}
void MenuCheckBox : : mousePressEvent ( QMouseEvent * )
{
m_checkBox - > click ( ) ;
}
2018-06-06 16:48:17 +03:00
class CheckBoxMenuItem : public QWidgetAction
2017-07-10 02:15:08 +03:00
{
public :
CheckBoxMenuItem ( const QString & text , const ToggleFn & onToggle , Qt : : CheckState initialState , QObject * parent )
: QWidgetAction ( parent )
{
setDefaultWidget ( new MenuCheckBox ( text , onToggle , initialState ) ) ;
}
} ;
2018-10-24 20:20:33 +03:00
bool torrentContainsPreviewableFiles ( const BitTorrent : : TorrentHandle * const torrent )
{
if ( ! torrent - > hasMetadata ( ) )
return false ;
for ( int i = 0 ; i < torrent - > filesCount ( ) ; + + i ) {
if ( Utils : : Misc : : isPreviewable ( Utils : : Fs : : fileExtension ( torrent - > fileName ( i ) ) ) )
return true ;
}
return false ;
}
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 )
2015-04-19 18:17:47 +03:00
: QTreeView ( parent )
2017-09-25 20:03:24 +03:00
, m_mainWindow ( mainWindow )
2014-12-08 04:40:58 +03:00
{
setUniformRowHeights ( true ) ;
// Load settings
2018-06-06 16:48:17 +03:00
bool columnLoaded = loadSettings ( ) ;
2014-12-08 04:40:58 +03:00
// Create and apply delegate
2017-09-25 20:03:24 +03:00
m_listDelegate = new TransferListDelegate ( this ) ;
setItemDelegate ( m_listDelegate ) ;
2014-12-08 04:40:58 +03:00
// Create transfer list model
2018-06-14 12:54:23 +03:00
m_listModel = new TransferListModel ( this ) ;
2014-12-08 04:40:58 +03:00
2017-09-25 20:03:24 +03:00
m_sortFilterModel = new TransferListSortModel ( ) ;
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 ) ;
2014-12-08 04:40:58 +03:00
2017-09-25 20:03:24 +03:00
setModel ( m_sortFilterModel ) ;
2014-12-08 04:40:58 +03:00
// Visual settings
setRootIsDecorated ( false ) ;
setAllColumnsShowFocus ( true ) ;
setSortingEnabled ( true ) ;
setSelectionMode ( QAbstractItemView : : ExtendedSelection ) ;
setItemsExpandable ( false ) ;
setAutoScroll ( true ) ;
setDragDropMode ( QAbstractItemView : : DragOnly ) ;
2013-09-21 11:59:58 +04:00
# if defined(Q_OS_MAC)
2014-12-08 04:40:58 +03:00
setAttribute ( Qt : : WA_MacShowFocusRect , false ) ;
2012-06-30 19:25:09 +04:00
# endif
2014-12-08 04:40:58 +03:00
header ( ) - > setStretchLastSection ( false ) ;
// Default hidden columns
2018-06-06 16:48:17 +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 ;
2018-09-07 14:12:38 +03:00
for ( int i = 0 ; i < TransferListModel : : NB_COLUMNS ; + + i ) {
2014-12-08 04:40:58 +03:00
if ( ! isColumnHidden ( i ) ) {
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 )
2016-06-22 20:01:02 +03:00
if ( ( columnWidth ( i ) < = 0 ) & & ( ! isColumnHidden ( i ) ) )
2014-12-08 04:40:58 +03:00
resizeColumnToContents ( i ) ;
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 ) ;
2018-04-18 16:59:41 +03:00
connect ( header ( ) , & QWidget : : customContextMenuRequested , this , & TransferListWidget : : displayDLHoSMenu ) ;
connect ( header ( ) , & QHeaderView : : sectionMoved , this , & TransferListWidget : : saveSettings ) ;
connect ( header ( ) , & QHeaderView : : sectionResized , this , & TransferListWidget : : saveSettings ) ;
connect ( header ( ) , & QHeaderView : : sortIndicatorChanged , this , & TransferListWidget : : saveSettings ) ;
m_editHotkey = new QShortcut ( Qt : : Key_F2 , this , nullptr , nullptr , Qt : : WidgetShortcut ) ;
connect ( m_editHotkey , & QShortcut : : activated , this , & TransferListWidget : : renameSelectedTorrent ) ;
m_deleteHotkey = new QShortcut ( QKeySequence : : Delete , this , nullptr , nullptr , Qt : : WidgetShortcut ) ;
connect ( m_deleteHotkey , & QShortcut : : activated , this , & TransferListWidget : : softDeleteSelectedTorrents ) ;
m_permDeleteHotkey = new QShortcut ( Qt : : SHIFT + Qt : : Key_Delete , this , nullptr , nullptr , Qt : : WidgetShortcut ) ;
connect ( m_permDeleteHotkey , & QShortcut : : activated , this , & TransferListWidget : : permDeleteSelectedTorrents ) ;
m_doubleClickHotkey = new QShortcut ( Qt : : Key_Return , this , nullptr , nullptr , Qt : : WidgetShortcut ) ;
connect ( m_doubleClickHotkey , & QShortcut : : activated , this , & TransferListWidget : : torrentDoubleClicked ) ;
m_recheckHotkey = new QShortcut ( Qt : : CTRL + Qt : : Key_R , this , nullptr , nullptr , Qt : : WidgetShortcut ) ;
connect ( m_recheckHotkey , & QShortcut : : activated , this , & TransferListWidget : : recheckSelectedTorrents ) ;
2015-11-18 19:13:25 +03:00
// This hack fixes reordering of first column with Qt5.
// https://github.com/qtproject/qtbase/commit/e0fc088c0c8bc61dbcaf5928b24986cd61a22777
QTableView unused ;
unused . setVerticalHeader ( header ( ) ) ;
header ( ) - > setParent ( this ) ;
unused . setVerticalHeader ( new QHeaderView ( Qt : : Horizontal ) ) ;
2014-12-08 04:40:58 +03:00
}
TransferListWidget : : ~ TransferListWidget ( )
{
qDebug ( ) < < Q_FUNC_INFO < < " ENTER " ;
// Save settings
saveSettings ( ) ;
// Clean up
2017-09-25 20:03:24 +03:00
delete m_sortFilterModel ;
delete m_listModel ;
delete m_listDelegate ;
2014-12-08 04:40:58 +03:00
qDebug ( ) < < Q_FUNC_INFO < < " EXIT " ;
}
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
}
2019-02-12 03:45:30 +03:00
void TransferListWidget : : previewFile ( const QString & 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
}
inline QModelIndex TransferListWidget : : mapToSource ( const QModelIndex & index ) const
{
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 ;
}
inline QModelIndex TransferListWidget : : mapFromSource ( const QModelIndex & index ) const
{
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 ( ) ) ;
BitTorrent : : TorrentHandle * 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 ( ) ;
2018-06-06 16:48:17 +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 ;
case OPEN_DEST :
2017-12-17 02:16:36 +03:00
# ifdef Q_OS_MAC
MacUtils : : openFiles ( QSet < QString > { torrent - > contentPath ( true ) } ) ;
# else
2015-06-28 21:58:39 +03:00
if ( torrent - > filesCount ( ) = = 1 )
2019-03-02 08:22:13 +03:00
Utils : : Gui : : openFolderSelect ( torrent - > contentPath ( true ) ) ;
2015-06-28 21:58:39 +03:00
else
2019-03-02 08:22:13 +03:00
Utils : : Gui : : openPath ( torrent - > contentPath ( true ) ) ;
2017-12-17 02:16:36 +03:00
# endif
2015-06-28 21:58:39 +03:00
break ;
2010-08-14 19:53:05 +04:00
}
2009-11-07 22:55:33 +03:00
}
2015-06-07 15:03:30 +03:00
QList < BitTorrent : : TorrentHandle * > TransferListWidget : : getSelectedTorrents ( ) const
2014-12-08 04:40:58 +03:00
{
2015-06-07 15:03:30 +03:00
QList < BitTorrent : : TorrentHandle * > torrents ;
2018-11-27 23:15:04 +03:00
for ( const QModelIndex & index : asConst ( selectionModel ( ) - > 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
}
2014-12-08 04:40:58 +03:00
void TransferListWidget : : setSelectedTorrentsLocation ( )
{
2015-06-07 15:03:30 +03:00
const QList < BitTorrent : : TorrentHandle * > torrents = getSelectedTorrents ( ) ;
if ( torrents . isEmpty ( ) ) return ;
2015-04-19 18:17:47 +03:00
2016-12-27 17:14:49 +03:00
const QString oldLocation = torrents [ 0 ] - > savePath ( ) ;
2017-08-13 13:56:03 +03:00
qDebug ( " Old location is %s " , qUtf8Printable ( oldLocation ) ) ;
2016-12-27 17:14:49 +03:00
const QString newLocation = QFileDialog : : getExistingDirectory ( this , tr ( " Choose save path " ) , oldLocation ,
2014-12-08 04:40:58 +03:00
QFileDialog : : DontConfirmOverwrite | QFileDialog : : ShowDirsOnly | QFileDialog : : HideNameFilterDetails ) ;
2017-03-30 05:14:33 +03:00
if ( newLocation . isEmpty ( ) | | ! QDir ( newLocation ) . exists ( ) ) return ;
2017-08-13 13:56:03 +03:00
qDebug ( " New location is %s " , qUtf8Printable ( newLocation ) ) ;
2016-12-27 17:14:49 +03:00
// Actually move storage
2018-11-18 21:40:37 +03:00
for ( BitTorrent : : TorrentHandle * const torrent : torrents ) {
2018-03-06 18:49:12 +03:00
Logger : : instance ( ) - > addMessage ( tr ( " Set location: moving \" %1 \" , from \" %2 \" to \" %3 \" "
, " Set location: moving \" ubuntu_16_04.iso \" , from \" /home/dir1 \" to \" /home/dir2 \" " )
2018-04-23 12:42:42 +03:00
. arg ( torrent - > name ( ) , Utils : : Fs : : toNativePath ( torrent - > savePath ( ) )
, Utils : : Fs : : toNativePath ( newLocation ) ) ) ;
2016-12-27 17:14:49 +03:00
torrent - > move ( Utils : : Fs : : expandPathAbs ( newLocation ) ) ;
2017-03-30 05:06:09 +03:00
}
2009-11-07 22:55:33 +03:00
}
2015-04-19 18:17:47 +03:00
void TransferListWidget : : pauseAllTorrents ( )
{
2018-11-27 23:15:04 +03:00
for ( BitTorrent : : TorrentHandle * const torrent : asConst ( BitTorrent : : Session : : instance ( ) - > torrents ( ) ) )
2015-04-19 18:17:47 +03:00
torrent - > pause ( ) ;
}
void TransferListWidget : : resumeAllTorrents ( )
{
2018-11-27 23:15:04 +03:00
for ( BitTorrent : : TorrentHandle * 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 ( )
{
2018-11-27 23:15:04 +03:00
for ( BitTorrent : : TorrentHandle * 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 ( )
{
2018-11-27 23:15:04 +03:00
for ( BitTorrent : : TorrentHandle * const torrent : asConst ( getSelectedTorrents ( ) ) )
2015-06-07 15:03:30 +03:00
torrent - > resume ( true ) ;
2015-04-14 02:22:14 +03:00
}
2014-12-08 04:40:58 +03:00
void TransferListWidget : : startVisibleTorrents ( )
{
2017-09-25 20:03:24 +03:00
for ( int i = 0 ; i < m_sortFilterModel - > rowCount ( ) ; + + i ) {
BitTorrent : : TorrentHandle * const torrent = m_listModel - > torrentHandle ( mapToSource ( m_sortFilterModel - > index ( i , 0 ) ) ) ;
2015-04-19 18:17:47 +03:00
if ( torrent )
torrent - > resume ( ) ;
2009-11-07 22:55:33 +03:00
}
}
2014-12-08 04:40:58 +03:00
void TransferListWidget : : pauseSelectedTorrents ( )
{
2018-11-27 23:15:04 +03:00
for ( BitTorrent : : TorrentHandle * 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 ( )
{
2017-09-25 20:03:24 +03:00
for ( int i = 0 ; i < m_sortFilterModel - > rowCount ( ) ; + + i ) {
BitTorrent : : TorrentHandle * const torrent = m_listModel - > torrentHandle ( mapToSource ( m_sortFilterModel - > index ( i , 0 ) ) ) ;
2015-04-19 18:17:47 +03:00
if ( torrent )
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 ) ;
}
void TransferListWidget : : deleteSelectedTorrents ( 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
2015-06-07 15:03:30 +03:00
const QList < BitTorrent : : TorrentHandle * > torrents = getSelectedTorrents ( ) ;
if ( torrents . empty ( ) ) return ;
2017-02-06 18:51:25 +03:00
if ( Preferences : : instance ( ) - > confirmTorrentDeletion ( )
2018-06-14 12:54:23 +03:00
& & ! DeletionConfirmationDialog : : askForDeletionConfirmation ( this , deleteLocalFiles , torrents . size ( ) , torrents [ 0 ] - > name ( ) ) )
2014-12-08 04:40:58 +03:00
return ;
2018-11-18 21:40:37 +03:00
for ( BitTorrent : : TorrentHandle * const torrent : torrents )
2016-08-05 21:15:13 +03:00
BitTorrent : : Session : : instance ( ) - > deleteTorrent ( torrent - > hash ( ) , deleteLocalFiles ) ;
2014-12-08 04:40:58 +03:00
}
void TransferListWidget : : deleteVisibleTorrents ( )
{
2017-09-25 20:03:24 +03:00
if ( m_sortFilterModel - > rowCount ( ) < = 0 ) return ;
2015-04-19 18:17:47 +03:00
2015-06-07 15:03:30 +03:00
QList < BitTorrent : : TorrentHandle * > torrents ;
2017-09-25 20:03:24 +03:00
for ( int i = 0 ; i < m_sortFilterModel - > rowCount ( ) ; + + i )
torrents < < m_listModel - > torrentHandle ( mapToSource ( m_sortFilterModel - > index ( i , 0 ) ) ) ;
2015-06-07 15:03:30 +03:00
2016-08-05 21:15:13 +03:00
bool deleteLocalFiles = false ;
2017-02-06 18:51:25 +03:00
if ( Preferences : : instance ( ) - > confirmTorrentDeletion ( )
2018-06-14 12:54:23 +03:00
& & ! DeletionConfirmationDialog : : askForDeletionConfirmation ( this , deleteLocalFiles , torrents . size ( ) , torrents [ 0 ] - > name ( ) ) )
2015-03-17 00:57:03 +03:00
return ;
2015-10-26 11:43:41 +03:00
2018-11-27 23:15:04 +03:00
for ( BitTorrent : : TorrentHandle * const torrent : asConst ( torrents ) )
2016-08-05 21:15:13 +03:00
BitTorrent : : Session : : instance ( ) - > deleteTorrent ( torrent - > hash ( ) , deleteLocalFiles ) ;
2014-12-08 04:40:58 +03:00
}
void TransferListWidget : : increasePrioSelectedTorrents ( )
{
qDebug ( ) < < Q_FUNC_INFO ;
2017-09-25 20:03:24 +03:00
if ( m_mainWindow - > currentTabWidget ( ) = = this )
2015-06-07 15:03:30 +03:00
BitTorrent : : Session : : instance ( ) - > increaseTorrentsPriority ( extractHashes ( getSelectedTorrents ( ) ) ) ;
2011-03-07 22:26:44 +03:00
}
2014-12-08 04:40:58 +03:00
void TransferListWidget : : decreasePrioSelectedTorrents ( )
{
qDebug ( ) < < Q_FUNC_INFO ;
2017-09-25 20:03:24 +03:00
if ( m_mainWindow - > currentTabWidget ( ) = = this )
2015-06-07 15:03:30 +03:00
BitTorrent : : Session : : instance ( ) - > decreaseTorrentsPriority ( extractHashes ( getSelectedTorrents ( ) ) ) ;
2009-11-08 00:04:56 +03:00
}
2014-12-08 04:40:58 +03:00
void TransferListWidget : : topPrioSelectedTorrents ( )
{
2017-09-25 20:03:24 +03:00
if ( m_mainWindow - > currentTabWidget ( ) = = this )
2015-06-07 15:03:30 +03:00
BitTorrent : : Session : : instance ( ) - > topTorrentsPriority ( extractHashes ( getSelectedTorrents ( ) ) ) ;
2011-08-10 22:44:37 +04:00
}
2009-11-18 14:04:19 +03:00
2014-12-08 04:40:58 +03:00
void TransferListWidget : : bottomPrioSelectedTorrents ( )
{
2017-09-25 20:03:24 +03:00
if ( m_mainWindow - > currentTabWidget ( ) = = this )
2015-06-07 15:03:30 +03:00
BitTorrent : : Session : : instance ( ) - > bottomTorrentsPriority ( extractHashes ( 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 ;
2018-11-27 23:15:04 +03:00
for ( BitTorrent : : TorrentHandle * const torrent : asConst ( getSelectedTorrents ( ) ) )
2018-06-14 14:46:50 +03:00
magnetUris < < torrent - > toMagnetUri ( ) ;
2015-06-07 15:03:30 +03:00
2018-06-14 14:46:50 +03:00
qApp - > clipboard ( ) - > setText ( magnetUris . join ( ' \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 ;
2018-11-27 23:15:04 +03:00
for ( BitTorrent : : TorrentHandle * const torrent : asConst ( getSelectedTorrents ( ) ) )
2018-06-14 14:46:50 +03:00
torrentNames < < torrent - > name ( ) ;
2015-06-07 15:03:30 +03:00
2018-06-14 14:46:50 +03:00
qApp - > clipboard ( ) - > setText ( torrentNames . join ( ' \n ' ) ) ;
2015-02-01 16:52:36 +03:00
}
2017-08-06 11:35:12 +03:00
void TransferListWidget : : copySelectedHashes ( ) const
{
QStringList torrentHashes ;
2018-11-27 23:15:04 +03:00
for ( BitTorrent : : TorrentHandle * const torrent : asConst ( getSelectedTorrents ( ) ) )
2017-08-06 11:35:12 +03:00
torrentHashes < < torrent - > hash ( ) ;
qApp - > clipboard ( ) - > setText ( torrentHashes . join ( ' \n ' ) ) ;
}
2014-12-08 04:40:58 +03:00
void TransferListWidget : : hidePriorityColumn ( bool hide )
{
qDebug ( " hidePriorityColumn(%d) " , hide ) ;
2018-06-14 12:54:23 +03:00
setColumnHidden ( TransferListModel : : TR_PRIORITY , hide ) ;
if ( ! hide & & ! columnWidth ( TransferListModel : : TR_PRIORITY ) )
resizeColumnToContents ( TransferListModel : : TR_PRIORITY ) ;
2014-12-08 04:40:58 +03:00
}
void TransferListWidget : : openSelectedTorrentsFolder ( ) const
{
QSet < QString > pathsList ;
2017-12-12 18:00:56 +03:00
# ifdef Q_OS_MAC
// 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.
2018-11-27 23:15:04 +03:00
for ( BitTorrent : : TorrentHandle * const torrent : asConst ( getSelectedTorrents ( ) ) ) {
2017-12-12 18:00:56 +03:00
QString path = torrent - > contentPath ( true ) ;
pathsList . insert ( path ) ;
}
2017-12-12 20:20:48 +03:00
MacUtils : : openFiles ( pathsList ) ;
2017-12-12 18:00:56 +03:00
# else
2018-11-27 23:15:04 +03:00
for ( BitTorrent : : TorrentHandle * const torrent : asConst ( getSelectedTorrents ( ) ) ) {
2015-10-24 15:28:29 +03:00
QString path = torrent - > contentPath ( true ) ;
if ( ! pathsList . contains ( path ) ) {
if ( torrent - > filesCount ( ) = = 1 )
2019-03-02 08:22:13 +03:00
Utils : : Gui : : openFolderSelect ( path ) ;
2015-10-24 15:28:29 +03:00
else
2019-03-02 08:22:13 +03:00
Utils : : Gui : : openPath ( path ) ;
2015-06-28 21:58:39 +03:00
}
pathsList . insert ( path ) ;
2014-12-08 04:40:58 +03:00
}
2018-11-06 18:49:17 +03:00
# endif // Q_OS_MAC
2014-12-08 04:40:58 +03:00
}
void TransferListWidget : : previewSelectedTorrents ( )
{
2018-11-27 23:15:04 +03:00
for ( BitTorrent : : TorrentHandle * const torrent : asConst ( getSelectedTorrents ( ) ) ) {
2019-06-05 08:46:29 +03:00
if ( torrentContainsPreviewableFiles ( torrent ) ) {
const auto * dialog = new PreviewSelectDialog ( this , torrent ) ;
connect ( dialog , & PreviewSelectDialog : : readyToPreviewFile , this , & TransferListWidget : : previewFile ) ;
}
else {
2018-10-24 20:20:33 +03:00
QMessageBox : : critical ( this , tr ( " Unable to preview " ) , tr ( " The selected torrent does not contain previewable files " ) ) ;
2019-06-05 08:46:29 +03:00
}
2014-12-08 04:40:58 +03:00
}
}
void TransferListWidget : : setDlLimitSelectedTorrents ( )
{
2018-11-06 18:49:17 +03:00
QList < BitTorrent : : TorrentHandle * > torrentsList ;
2018-11-27 23:15:04 +03:00
for ( BitTorrent : : TorrentHandle * const torrent : asConst ( getSelectedTorrents ( ) ) ) {
2016-12-30 08:34:10 +03:00
if ( torrent - > isSeed ( ) )
continue ;
2018-11-06 18:49:17 +03:00
torrentsList + = torrent ;
2014-12-08 04:40:58 +03:00
}
2018-11-06 18:49:17 +03:00
if ( torrentsList . empty ( ) ) return ;
2015-06-07 15:03:30 +03:00
2018-11-06 18:49:17 +03:00
int oldLimit = torrentsList . first ( ) - > downloadLimit ( ) ;
2018-11-27 23:15:04 +03:00
for ( BitTorrent : : TorrentHandle * const torrent : asConst ( torrentsList ) ) {
2016-12-30 08:34:10 +03:00
if ( torrent - > downloadLimit ( ) ! = oldLimit ) {
oldLimit = - 1 ;
break ;
}
}
2014-12-08 04:40:58 +03:00
bool ok = false ;
2016-12-30 08:34:10 +03:00
const long newLimit = SpeedLimitDialog : : askSpeedLimit (
2015-10-26 11:38:54 +03:00
this , & ok , tr ( " Torrent Download Speed Limiting " ) , oldLimit
2016-05-01 11:05:52 +03:00
, BitTorrent : : Session : : instance ( ) - > globalDownloadSpeedLimit ( ) ) ;
2016-12-30 08:34:10 +03:00
if ( ! ok ) return ;
2018-11-27 23:15:04 +03:00
for ( BitTorrent : : TorrentHandle * const torrent : asConst ( torrentsList ) ) {
2017-08-13 13:56:03 +03:00
qDebug ( " Applying download speed limit of %ld Kb/s to torrent %s " , ( newLimit / 1024l ) , qUtf8Printable ( torrent - > hash ( ) ) ) ;
2016-12-30 08:34:10 +03:00
torrent - > setDownloadLimit ( newLimit ) ;
2014-12-08 04:40:58 +03:00
}
}
void TransferListWidget : : setUpLimitSelectedTorrents ( )
{
2018-11-06 18:49:17 +03:00
QList < BitTorrent : : TorrentHandle * > torrentsList = getSelectedTorrents ( ) ;
if ( torrentsList . empty ( ) ) return ;
2015-06-07 15:03:30 +03:00
2018-11-06 18:49:17 +03:00
int oldLimit = torrentsList . first ( ) - > uploadLimit ( ) ;
2018-11-27 23:15:04 +03:00
for ( BitTorrent : : TorrentHandle * const torrent : asConst ( torrentsList ) ) {
2016-12-30 08:34:10 +03:00
if ( torrent - > uploadLimit ( ) ! = oldLimit ) {
oldLimit = - 1 ;
break ;
}
}
2014-12-08 04:40:58 +03:00
bool ok = false ;
2016-12-30 08:34:10 +03:00
const long newLimit = SpeedLimitDialog : : askSpeedLimit (
2015-10-26 11:38:54 +03:00
this , & ok , tr ( " Torrent Upload Speed Limiting " ) , oldLimit
2016-05-01 11:05:52 +03:00
, BitTorrent : : Session : : instance ( ) - > globalUploadSpeedLimit ( ) ) ;
2016-12-30 08:34:10 +03:00
if ( ! ok ) return ;
2018-11-27 23:15:04 +03:00
for ( BitTorrent : : TorrentHandle * const torrent : asConst ( torrentsList ) ) {
2017-08-13 13:56:03 +03:00
qDebug ( " Applying upload speed limit of %ld Kb/s to torrent %s " , ( newLimit / 1024l ) , qUtf8Printable ( torrent - > hash ( ) ) ) ;
2016-12-30 08:34:10 +03:00
torrent - > setUploadLimit ( newLimit ) ;
2014-12-08 04:40:58 +03:00
}
}
void TransferListWidget : : setMaxRatioSelectedTorrents ( )
{
2015-06-07 15:03:30 +03:00
const QList < BitTorrent : : TorrentHandle * > torrents = getSelectedTorrents ( ) ;
if ( torrents . isEmpty ( ) ) return ;
2016-02-07 20:31:50 +03:00
qreal currentMaxRatio = BitTorrent : : Session : : instance ( ) - > globalMaxRatio ( ) ;
2015-06-07 15:03:30 +03:00
if ( torrents . count ( ) = = 1 )
2017-09-06 22:47:05 +03:00
currentMaxRatio = torrents [ 0 ] - > maxRatio ( ) ;
2015-04-19 18:17:47 +03:00
2016-02-07 20:31:50 +03:00
int currentMaxSeedingTime = BitTorrent : : Session : : instance ( ) - > globalMaxSeedingMinutes ( ) ;
if ( torrents . count ( ) = = 1 )
2017-09-06 22:47:05 +03:00
currentMaxSeedingTime = torrents [ 0 ] - > maxSeedingTime ( ) ;
bool useGlobalValue = true ;
if ( torrents . count ( ) = = 1 )
useGlobalValue = ( torrents [ 0 ] - > ratioLimit ( ) = = BitTorrent : : TorrentHandle : : USE_GLOBAL_RATIO )
& & ( torrents [ 0 ] - > seedingTimeLimit ( ) = = BitTorrent : : TorrentHandle : : USE_GLOBAL_SEEDING_TIME ) ;
2016-02-07 20:31:50 +03:00
2019-06-19 06:26:17 +03:00
auto dialog = new UpDownRatioDialog ( useGlobalValue , currentMaxRatio , BitTorrent : : TorrentHandle : : MAX_RATIO ,
2016-02-07 20:31:50 +03:00
currentMaxSeedingTime , BitTorrent : : TorrentHandle : : MAX_SEEDING_TIME , this ) ;
2019-06-19 06:26:17 +03:00
dialog - > setAttribute ( Qt : : WA_DeleteOnClose ) ;
connect ( dialog , & QDialog : : accepted , this , [ this , dialog , torrents ] ( )
{
for ( BitTorrent : : TorrentHandle * const torrent : torrents ) {
const qreal ratio = ( dialog - > useDefault ( )
? BitTorrent : : TorrentHandle : : USE_GLOBAL_RATIO : dialog - > ratio ( ) ) ;
torrent - > setRatioLimit ( ratio ) ;
const int seedingTime = ( dialog - > useDefault ( )
? BitTorrent : : TorrentHandle : : USE_GLOBAL_SEEDING_TIME : dialog - > seedingTime ( ) ) ;
torrent - > setSeedingTimeLimit ( seedingTime ) ;
}
} ) ;
dialog - > open ( ) ;
2014-12-08 04:40:58 +03:00
}
void TransferListWidget : : recheckSelectedTorrents ( )
{
2015-07-08 23:29:31 +03:00
if ( Preferences : : instance ( ) - > confirmTorrentRecheck ( ) ) {
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
2018-11-27 23:15:04 +03:00
for ( BitTorrent : : TorrentHandle * 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 ( )
{
2018-11-27 23:15:04 +03:00
for ( BitTorrent : : TorrentHandle * const torrent : asConst ( getSelectedTorrents ( ) ) )
2018-01-03 05:40:52 +03:00
torrent - > forceReannounce ( ) ;
}
2014-12-08 04:40:58 +03:00
// hide/show columns menu
void TransferListWidget : : displayDLHoSMenu ( const QPoint & )
{
2019-06-19 06:26:17 +03:00
auto menu = new QMenu ( this ) ;
menu - > setAttribute ( Qt : : WA_DeleteOnClose ) ;
menu - > setTitle ( tr ( " Column visibility " ) ) ;
2017-09-25 20:03:24 +03:00
for ( int i = 0 ; i < m_listModel - > columnCount ( ) ; + + i ) {
2019-06-19 06:26:17 +03:00
if ( ! BitTorrent : : Session : : instance ( ) - > isQueueingSystemEnabled ( ) & & ( i = = TransferListModel : : TR_PRIORITY ) )
2014-12-08 04:40:58 +03:00
continue ;
2019-06-19 06:26:17 +03:00
QAction * myAct = menu - > addAction ( m_listModel - > headerData ( i , Qt : : Horizontal , Qt : : DisplayRole ) . toString ( ) ) ;
2014-12-08 04:40:58 +03:00
myAct - > setCheckable ( true ) ;
myAct - > setChecked ( ! isColumnHidden ( i ) ) ;
2019-06-19 06:26:17 +03:00
myAct - > setData ( i ) ;
2014-12-08 04:40:58 +03:00
}
2019-06-19 06:26:17 +03:00
connect ( menu , & QMenu : : triggered , this , [ this ] ( const QAction * action )
{
int visibleCols = 0 ;
for ( int i = 0 ; i < TransferListModel : : NB_COLUMNS ; + + i ) {
if ( ! isColumnHidden ( i ) )
+ + visibleCols ;
if ( visibleCols > 1 )
break ;
}
const int col = action - > data ( ) . toInt ( ) ;
2014-12-08 04:40:58 +03:00
if ( ! isColumnHidden ( col ) & & visibleCols = = 1 )
return ;
2019-06-19 06:26:17 +03:00
2014-12-08 04:40:58 +03:00
setColumnHidden ( col , ! isColumnHidden ( col ) ) ;
2019-06-19 06:26:17 +03:00
2014-12-08 04:40:58 +03:00
if ( ! isColumnHidden ( col ) & & columnWidth ( col ) < = 5 )
2017-12-08 17:05:21 +03:00
resizeColumnToContents ( col ) ;
2019-06-19 06:26:17 +03:00
2014-12-15 15:05:49 +03:00
saveSettings ( ) ;
2019-06-19 06:26:17 +03:00
} ) ;
menu - > popup ( QCursor : : pos ( ) ) ;
2014-12-08 04:40:58 +03:00
}
void TransferListWidget : : toggleSelectedTorrentsSuperSeeding ( ) const
{
2018-11-27 23:15:04 +03:00
for ( BitTorrent : : TorrentHandle * const torrent : asConst ( getSelectedTorrents ( ) ) ) {
2015-06-07 15:03:30 +03:00
if ( torrent - > hasMetadata ( ) )
2015-04-19 18:17:47 +03:00
torrent - > setSuperSeeding ( ! torrent - > superSeeding ( ) ) ;
2014-12-08 04:40:58 +03:00
}
}
void TransferListWidget : : toggleSelectedTorrentsSequentialDownload ( ) const
{
2018-11-27 23:15:04 +03:00
for ( BitTorrent : : TorrentHandle * const torrent : asConst ( getSelectedTorrents ( ) ) )
2015-06-07 15:03:30 +03:00
torrent - > toggleSequentialDownload ( ) ;
2014-12-08 04:40:58 +03:00
}
void TransferListWidget : : toggleSelectedFirstLastPiecePrio ( ) const
{
2018-11-27 23:15:04 +03:00
for ( BitTorrent : : TorrentHandle * const torrent : asConst ( getSelectedTorrents ( ) ) )
2015-11-26 15:08:01 +03:00
torrent - > toggleFirstLastPiecePriority ( ) ;
2014-12-08 04:40:58 +03:00
}
2016-05-08 22:47:50 +03:00
void TransferListWidget : : setSelectedAutoTMMEnabled ( bool enabled ) const
2014-12-08 04:40:58 +03:00
{
2018-11-27 23:15:04 +03:00
for ( BitTorrent : : TorrentHandle * 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 ) ;
}
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 ;
while ( invalid ) {
bool ok = false ;
invalid = false ;
const QString tagsInput = AutoExpandableDialog : : getText (
this , dialogTitle , tr ( " Comma-separated tags: " ) , QLineEdit : : Normal , " " , & ok ) . trimmed ( ) ;
if ( ! ok | | tagsInput . isEmpty ( ) )
2019-02-14 20:16:42 +03:00
return { } ;
2017-06-05 03:22:17 +03:00
tags = tagsInput . split ( ' , ' , QString : : SkipEmptyParts ) ;
for ( QString & tag : tags ) {
tag = tag . trimmed ( ) ;
if ( ! BitTorrent : : Session : : isValidTag ( tag ) ) {
QMessageBox : : warning ( this , tr ( " Invalid tag " )
, tr ( " Tag name: '%1' is invalid " ) . arg ( tag ) ) ;
invalid = true ;
}
}
}
return tags ;
}
void TransferListWidget : : applyToSelectedTorrents ( const std : : function < void ( BitTorrent : : TorrentHandle * const ) > & fn )
{
2018-11-27 23:15:04 +03:00
for ( const QModelIndex & index : asConst ( selectionModel ( ) - > selectedRows ( ) ) ) {
2017-09-25 20:03:24 +03:00
BitTorrent : : TorrentHandle * 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 ) ;
2017-09-25 20:03:24 +03:00
BitTorrent : : TorrentHandle * 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
bool ok ;
2015-04-19 18:17:47 +03:00
QString name = AutoExpandableDialog : : getText ( this , tr ( " Rename " ) , tr ( " New name: " ) , QLineEdit : : Normal , torrent - > name ( ) , & ok ) ;
2014-12-08 04:40:58 +03:00
if ( ok & & ! name . isEmpty ( ) ) {
2018-05-24 18:41:03 +03:00
name . replace ( QRegularExpression ( " \r ? \n | \r " ) , " " ) ;
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 )
{
applyToSelectedTorrents ( [ & tag ] ( BitTorrent : : TorrentHandle * const torrent ) { torrent - > addTag ( tag ) ; } ) ;
}
void TransferListWidget : : removeSelectionTag ( const QString & tag )
{
applyToSelectedTorrents ( [ & tag ] ( BitTorrent : : TorrentHandle * const torrent ) { torrent - > removeTag ( tag ) ; } ) ;
}
void TransferListWidget : : clearSelectionTags ( )
{
applyToSelectedTorrents ( [ ] ( BitTorrent : : TorrentHandle * const torrent ) { torrent - > removeAllTags ( ) ; } ) ;
}
2014-12-08 04:40:58 +03:00
void TransferListWidget : : displayListMenu ( const QPoint & )
{
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
2014-12-08 04:40:58 +03:00
// Create actions
2019-06-03 10:10:19 +03:00
QAction * actionStart = new QAction ( GuiIconProvider : : instance ( ) - > getIcon ( " media-playback-start " ) , tr ( " Resume " , " Resume/start the torrent " ) , this ) ;
connect ( actionStart , & QAction : : triggered , this , & TransferListWidget : : startSelectedTorrents ) ;
QAction * actionPause = new QAction ( GuiIconProvider : : instance ( ) - > getIcon ( " media-playback-pause " ) , tr ( " Pause " , " Pause the torrent " ) , this ) ;
connect ( actionPause , & QAction : : triggered , this , & TransferListWidget : : pauseSelectedTorrents ) ;
QAction * actionForceStart = new QAction ( GuiIconProvider : : instance ( ) - > getIcon ( " media-seek-forward " ) , tr ( " Force Resume " , " Force Resume/start the torrent " ) , this ) ;
connect ( actionForceStart , & QAction : : triggered , this , & TransferListWidget : : forceStartSelectedTorrents ) ;
QAction * actionDelete = new QAction ( GuiIconProvider : : instance ( ) - > getIcon ( " edit-delete " ) , tr ( " Delete " , " Delete the torrent " ) , this ) ;
connect ( actionDelete , & QAction : : triggered , this , & TransferListWidget : : softDeleteSelectedTorrents ) ;
QAction * actionPreviewFile = new QAction ( GuiIconProvider : : instance ( ) - > getIcon ( " view-preview " ) , tr ( " Preview file... " ) , this ) ;
connect ( actionPreviewFile , & QAction : : triggered , this , & TransferListWidget : : previewSelectedTorrents ) ;
QAction * actionSetMaxRatio = new QAction ( QIcon ( QLatin1String ( " :/icons/skin/ratio.svg " ) ) , tr ( " Limit share ratio... " ) , this ) ;
connect ( actionSetMaxRatio , & QAction : : triggered , this , & TransferListWidget : : setMaxRatioSelectedTorrents ) ;
QAction * actionSetUploadLimit = new QAction ( GuiIconProvider : : instance ( ) - > getIcon ( " kt-set-max-upload-speed " ) , tr ( " Limit upload rate... " ) , this ) ;
connect ( actionSetUploadLimit , & QAction : : triggered , this , & TransferListWidget : : setUpLimitSelectedTorrents ) ;
QAction * actionSetDownloadLimit = new QAction ( GuiIconProvider : : instance ( ) - > getIcon ( " kt-set-max-download-speed " ) , tr ( " Limit download rate... " ) , this ) ;
connect ( actionSetDownloadLimit , & QAction : : triggered , this , & TransferListWidget : : setDlLimitSelectedTorrents ) ;
QAction * actionOpenDestinationFolder = new QAction ( GuiIconProvider : : instance ( ) - > getIcon ( " inode-directory " ) , tr ( " Open destination folder " ) , this ) ;
connect ( actionOpenDestinationFolder , & QAction : : triggered , this , & TransferListWidget : : openSelectedTorrentsFolder ) ;
QAction * actionIncreasePriority = new QAction ( GuiIconProvider : : instance ( ) - > getIcon ( " go-up " ) , tr ( " Move up " , " i.e. move up in the queue " ) , this ) ;
connect ( actionIncreasePriority , & QAction : : triggered , this , & TransferListWidget : : increasePrioSelectedTorrents ) ;
QAction * actionDecreasePriority = new QAction ( GuiIconProvider : : instance ( ) - > getIcon ( " go-down " ) , tr ( " Move down " , " i.e. Move down in the queue " ) , this ) ;
connect ( actionDecreasePriority , & QAction : : triggered , this , & TransferListWidget : : decreasePrioSelectedTorrents ) ;
QAction * actionTopPriority = new QAction ( GuiIconProvider : : instance ( ) - > getIcon ( " go-top " ) , tr ( " Move to top " , " i.e. Move to top of the queue " ) , this ) ;
connect ( actionTopPriority , & QAction : : triggered , this , & TransferListWidget : : topPrioSelectedTorrents ) ;
QAction * actionBottomPriority = new QAction ( GuiIconProvider : : instance ( ) - > getIcon ( " go-bottom " ) , tr ( " Move to bottom " , " i.e. Move to bottom of the queue " ) , this ) ;
connect ( actionBottomPriority , & QAction : : triggered , this , & TransferListWidget : : bottomPrioSelectedTorrents ) ;
QAction * actionSetTorrentPath = new QAction ( GuiIconProvider : : instance ( ) - > getIcon ( " inode-directory " ) , tr ( " Set location... " ) , this ) ;
connect ( actionSetTorrentPath , & QAction : : triggered , this , & TransferListWidget : : setSelectedTorrentsLocation ) ;
QAction * actionForceRecheck = new QAction ( GuiIconProvider : : instance ( ) - > getIcon ( " document-edit-verify " ) , tr ( " Force recheck " ) , this ) ;
connect ( actionForceRecheck , & QAction : : triggered , this , & TransferListWidget : : recheckSelectedTorrents ) ;
QAction * actionForceReannounce = new QAction ( GuiIconProvider : : instance ( ) - > getIcon ( " document-edit-verify " ) , tr ( " Force reannounce " ) , this ) ;
connect ( actionForceReannounce , & QAction : : triggered , this , & TransferListWidget : : reannounceSelectedTorrents ) ;
QAction * actionCopyMagnetLink = new QAction ( GuiIconProvider : : instance ( ) - > getIcon ( " kt-magnet " ) , tr ( " Copy magnet link " ) , this ) ;
connect ( actionCopyMagnetLink , & QAction : : triggered , this , & TransferListWidget : : copySelectedMagnetURIs ) ;
QAction * actionCopyName = new QAction ( GuiIconProvider : : instance ( ) - > getIcon ( " edit-copy " ) , tr ( " Copy name " ) , this ) ;
connect ( actionCopyName , & QAction : : triggered , this , & TransferListWidget : : copySelectedNames ) ;
QAction * actionCopyHash = new QAction ( GuiIconProvider : : instance ( ) - > getIcon ( " edit-copy " ) , tr ( " Copy hash " ) , this ) ;
connect ( actionCopyHash , & QAction : : triggered , this , & TransferListWidget : : copySelectedHashes ) ;
QAction * actionSuperSeedingMode = new QAction ( tr ( " Super seeding mode " ) , this ) ;
actionSuperSeedingMode - > setCheckable ( true ) ;
connect ( actionSuperSeedingMode , & QAction : : triggered , this , & TransferListWidget : : toggleSelectedTorrentsSuperSeeding ) ;
QAction * actionRename = new QAction ( GuiIconProvider : : instance ( ) - > getIcon ( " edit-rename " ) , tr ( " Rename... " ) , this ) ;
connect ( actionRename , & QAction : : triggered , this , & TransferListWidget : : renameSelectedTorrent ) ;
QAction * actionSequentialDownload = new QAction ( tr ( " Download in sequential order " ) , this ) ;
actionSequentialDownload - > setCheckable ( true ) ;
connect ( actionSequentialDownload , & QAction : : triggered , this , & TransferListWidget : : toggleSelectedTorrentsSequentialDownload ) ;
QAction * actionFirstLastPiecePrio = new QAction ( tr ( " Download first and last pieces first " ) , this ) ;
actionFirstLastPiecePrio - > setCheckable ( true ) ;
connect ( actionFirstLastPiecePrio , & QAction : : triggered , this , & TransferListWidget : : toggleSelectedFirstLastPiecePrio ) ;
QAction * actionAutoTMM = new QAction ( tr ( " Automatic Torrent Management " ) , this ) ;
actionAutoTMM - > setCheckable ( true ) ;
actionAutoTMM - > setToolTip ( tr ( " Automatic mode means that various torrent properties(eg save path) will be decided by the associated category " ) ) ;
connect ( actionAutoTMM , & QAction : : triggered , this , & TransferListWidget : : setSelectedAutoTMMEnabled ) ;
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 ;
2016-05-08 22:47:50 +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 ;
2017-07-10 02:15:08 +03:00
QSet < QString > tagsInAny ;
QSet < QString > tagsInAll ;
2015-04-19 18:17:47 +03:00
2018-11-18 21:40:37 +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
2019-06-03 10:10:19 +03:00
const BitTorrent : : TorrentHandle * 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
2017-07-10 02:15:08 +03:00
tagsInAny . unite ( torrent - > tags ( ) ) ;
2017-06-05 03:22:17 +03:00
2017-07-10 02:15:08 +03:00
if ( first ) {
2016-05-08 22:47:50 +03:00
firstAutoTMM = torrent - > isAutoTMMEnabled ( ) ;
2017-07-10 02:15:08 +03:00
tagsInAll = torrent - > tags ( ) ;
}
else {
tagsInAll . intersect ( torrent - > tags ( ) ) ;
}
2016-05-08 22:47:50 +03:00
if ( firstAutoTMM ! = torrent - > isAutoTMMEnabled ( ) )
allSameAutoTMM = false ;
2015-09-16 02:01:51 +03:00
2015-04-19 18:17:47 +03:00
if ( torrent - > hasMetadata ( ) )
2018-06-06 16:48:17 +03:00
oneHasMetadata = true ;
2015-04-19 18:17:47 +03:00
if ( ! torrent - > isSeed ( ) ) {
2018-06-06 16:48:17 +03:00
oneNotSeed = true ;
2018-08-14 11:42:28 +03:00
if ( first ) {
sequentialDownloadMode = torrent - > isSequentialDownload ( ) ;
prioritizeFirstLast = torrent - > hasFirstLastPiecePriority ( ) ;
}
else {
if ( sequentialDownloadMode ! = torrent - > isSequentialDownload ( ) )
allSameSequentialDownloadMode = false ;
if ( prioritizeFirstLast ! = torrent - > hasFirstLastPiecePriority ( ) )
allSamePrioFirstlast = false ;
2014-12-08 04:40:58 +03:00
}
}
else {
2018-06-06 16:48:17 +03:00
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
}
}
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 ;
2015-07-19 22:59:07 +03:00
if ( torrent - > 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 ;
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
2014-12-08 04:40:58 +03:00
first = false ;
2015-07-19 22:59:07 +03:00
2018-06-06 16:48:17 +03:00
if ( oneHasMetadata & & oneNotSeed & & ! allSameSequentialDownloadMode
& & ! allSamePrioFirstlast & & ! allSameSuperSeeding & & ! allSameCategory
& & needsStart & & needsForce & & needsPause & & needsPreview & & ! allSameAutoTMM ) {
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
QMenu * listMenu = new QMenu ( this ) ;
listMenu - > setAttribute ( Qt : : WA_DeleteOnClose ) ;
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 ( ) ;
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 ) ;
2016-02-09 11:56:48 +03:00
// Category Menu
2017-09-24 14:54:42 +03:00
QStringList categories = BitTorrent : : Session : : instance ( ) - > categories ( ) . keys ( ) ;
2017-11-30 12:10:30 +03:00
std : : sort ( categories . begin ( ) , categories . end ( ) , Utils : : String : : naturalLessThan < Qt : : CaseInsensitive > ) ;
2019-06-03 10:10:19 +03:00
QMenu * categoryMenu = listMenu - > addMenu ( GuiIconProvider : : instance ( ) - > getIcon ( " view-categories " ) , tr ( " Category " ) ) ;
const QAction * newCategoryAction = categoryMenu - > addAction ( GuiIconProvider : : instance ( ) - > getIcon ( " list-add " ) , tr ( " New... " , " New category... " ) ) ;
connect ( newCategoryAction , & QAction : : triggered , this , & TransferListWidget : : askNewCategoryForSelection ) ;
const QAction * resetCategoryAction = categoryMenu - > addAction ( GuiIconProvider : : instance ( ) - > getIcon ( " edit-clear " ) , tr ( " Reset " , " Reset category " ) ) ;
connect ( resetCategoryAction , & QAction : : triggered , this , [ this ] ( ) { setSelectionCategory ( " " ) ; } ) ;
2016-02-09 11:56:48 +03:00
categoryMenu - > addSeparator ( ) ;
2019-06-03 10:10:19 +03:00
for ( const QString & category : asConst ( categories ) ) {
const QString escapedCategory = QString ( category ) . replace ( ' & ' , " && " ) ; // avoid '&' becomes accelerator key
QAction * cat = new QAction ( GuiIconProvider : : instance ( ) - > getIcon ( " inode-directory " ) , escapedCategory , categoryMenu ) ;
2016-02-09 11:56:48 +03:00
if ( allSameCategory & & ( category = = firstCategory ) ) {
cat - > setCheckable ( true ) ;
cat - > setChecked ( true ) ;
2015-09-16 02:01:51 +03:00
}
2019-06-03 10:10:19 +03:00
2016-02-09 11:56:48 +03:00
categoryMenu - > addAction ( cat ) ;
2019-06-03 10:10:19 +03:00
connect ( cat , & QAction : : triggered , this , [ this , category ] ( ) { setSelectionCategory ( category ) ; } ) ;
2015-07-19 08:02:41 +03:00
}
2016-02-09 11:56:48 +03:00
2017-06-05 03:22:17 +03:00
// Tag Menu
QStringList tags ( BitTorrent : : Session : : instance ( ) - > tags ( ) . toList ( ) ) ;
2017-11-30 12:10:30 +03:00
std : : sort ( tags . begin ( ) , tags . end ( ) , Utils : : String : : naturalLessThan < Qt : : CaseInsensitive > ) ;
2019-06-03 10:10:19 +03:00
QMenu * tagsMenu = listMenu - > addMenu ( GuiIconProvider : : instance ( ) - > getIcon ( " view-categories " ) , tr ( " Tags " ) ) ;
const QAction * addTagAction = tagsMenu - > addAction ( GuiIconProvider : : instance ( ) - > getIcon ( " list-add " ) , tr ( " Add... " , " Add / assign multiple tags... " ) ) ;
connect ( addTagAction , & QAction : : triggered , this , & TransferListWidget : : askAddTagsForSelection ) ;
const QAction * removeTagsAction = tagsMenu - > addAction ( GuiIconProvider : : instance ( ) - > getIcon ( " edit-clear " ) , tr ( " Remove All " , " Remove all tags " ) ) ;
connect ( removeTagsAction , & QAction : : triggered , this , [ this ] ( )
{
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
2018-11-27 23:15:04 +03:00
for ( const QString & tag : asConst ( tags ) ) {
2017-07-10 02:15:08 +03:00
const Qt : : CheckState initialState = tagsInAll . contains ( tag ) ? Qt : : Checked
: tagsInAny . contains ( tag ) ? Qt : : PartiallyChecked
: Qt : : Unchecked ;
const ToggleFn onToggle = [ this , tag ] ( Qt : : CheckState newState )
{
Q_ASSERT ( newState = = Qt : : CheckState : : Checked | | newState = = Qt : : CheckState : : Unchecked ) ;
if ( newState = = Qt : : CheckState : : Checked )
addSelectionTag ( tag ) ;
else
removeSelectionTag ( tag ) ;
} ;
tagsMenu - > addAction ( new CheckBoxMenuItem ( tag , onToggle , initialState , tagsMenu ) ) ;
2017-06-05 03:22:17 +03:00
}
2016-05-08 22:47:50 +03:00
if ( allSameAutoTMM ) {
2019-06-03 10:10:19 +03:00
actionAutoTMM - > setChecked ( firstAutoTMM ) ;
listMenu - > addAction ( actionAutoTMM ) ;
2016-02-09 11:56:48 +03:00
}
2019-06-03 10:10:19 +03:00
listMenu - > addSeparator ( ) ;
2018-06-06 16:48:17 +03:00
if ( oneNotSeed )
2019-06-03 10:10:19 +03:00
listMenu - > addAction ( actionSetDownloadLimit ) ;
listMenu - > addAction ( actionSetUploadLimit ) ;
listMenu - > addAction ( actionSetMaxRatio ) ;
2018-06-06 16:48:17 +03:00
if ( ! oneNotSeed & & allSameSuperSeeding & & oneHasMetadata ) {
2019-06-03 10:10:19 +03:00
actionSuperSeedingMode - > setChecked ( superSeedingMode ) ;
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 ;
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
}
2018-08-14 11:42:28 +03:00
if ( oneNotSeed ) {
2018-06-06 16:48:17 +03:00
if ( allSameSequentialDownloadMode ) {
2019-06-03 10:10:19 +03:00
actionSequentialDownload - > setChecked ( sequentialDownloadMode ) ;
listMenu - > addAction ( actionSequentialDownload ) ;
2018-06-06 16:48:17 +03:00
addedPreviewAction = true ;
2014-12-08 04:40:58 +03:00
}
2018-06-06 16:48:17 +03:00
if ( allSamePrioFirstlast ) {
2019-06-03 10:10:19 +03:00
actionFirstLastPiecePrio - > setChecked ( prioritizeFirstLast ) ;
listMenu - > addAction ( actionFirstLastPiecePrio ) ;
2018-06-06 16:48:17 +03:00
addedPreviewAction = true ;
2014-12-08 04:40:58 +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 ( ) ;
2018-06-06 16:48:17 +03:00
if ( oneHasMetadata ) {
2019-06-03 10:10:19 +03:00
listMenu - > addAction ( actionForceRecheck ) ;
listMenu - > addAction ( actionForceReannounce ) ;
listMenu - > addSeparator ( ) ;
2014-12-08 04:40:58 +03:00
}
2019-06-03 10:10:19 +03:00
listMenu - > addAction ( actionOpenDestinationFolder ) ;
2018-06-06 16:48:17 +03:00
if ( BitTorrent : : Session : : instance ( ) - > isQueueingSystemEnabled ( ) & & oneNotSeed ) {
2019-06-03 10:10:19 +03:00
listMenu - > addSeparator ( ) ;
QMenu * prioMenu = listMenu - > addMenu ( tr ( " Priority " ) ) ;
prioMenu - > addAction ( actionTopPriority ) ;
prioMenu - > addAction ( actionIncreasePriority ) ;
prioMenu - > addAction ( actionDecreasePriority ) ;
prioMenu - > addAction ( actionBottomPriority ) ;
2014-12-08 04:40:58 +03:00
}
2019-06-03 10:10:19 +03:00
listMenu - > addSeparator ( ) ;
listMenu - > addAction ( actionCopyName ) ;
listMenu - > addAction ( actionCopyHash ) ;
listMenu - > addAction ( actionCopyMagnetLink ) ;
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 " ) ;
2018-04-15 13:06:31 +03:00
BitTorrent : : TorrentHandle * torrent = nullptr ;
2014-12-08 04:40:58 +03:00
if ( current . isValid ( ) ) {
2017-09-25 20:03:24 +03:00
torrent = m_listModel - > torrentHandle ( mapToSource ( current ) ) ;
2014-12-08 04:40:58 +03:00
// Scroll Fix
scrollTo ( current ) ;
}
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
}
void TransferListWidget : : applyTrackerFilter ( const QStringList & hashes )
{
2017-09-25 20:03:24 +03:00
m_sortFilterModel - > setTrackerFilter ( hashes ) ;
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
{
2018-08-12 17:46:16 +03:00
const QRegExp : : PatternSyntax patternSyntax = Preferences : : instance ( ) - > getRegexAsFilteringPatternForTransferList ( )
2018-07-29 15:46:19 +03:00
? QRegExp : : RegExp : QRegExp : : WildcardUnix ;
m_sortFilterModel - > setFilterRegExp ( QRegExp ( name , Qt : : CaseInsensitive , patternSyntax ) ) ;
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
2018-06-06 16:48:17 +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 )
{
2017-02-06 18:51:25 +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 ( ) ;
2016-11-27 10:14:41 +03:00
QWheelEvent scrollHEvent ( event - > pos ( ) , event - > globalPos ( ) , event - > delta ( ) , event - > buttons ( ) , event - > modifiers ( ) , Qt : : Horizontal ) ;
QTreeView : : wheelEvent ( & scrollHEvent ) ;
return ;
}
QTreeView : : wheelEvent ( event ) ; // event delegated to base class
}