mirror of
https://github.com/transmission/transmission
synced 2024-12-27 01:57:52 +00:00
413c91f4a8
When opening the "Add URL" dialog, check the clipboard selection & clipboard proper to see if either contains a URL, magnet link, or info hash code. If it has any of those things, put that in the dialog's entry field as the default action. Patch by cantabile.
1272 lines
43 KiB
C++
1272 lines
43 KiB
C++
/*
|
|
* This file Copyright (C) Mnemosyne LLC
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2
|
|
* as published by the Free Software Foundation.
|
|
*
|
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|
*
|
|
* $Id$
|
|
*/
|
|
|
|
#include <cassert>
|
|
#include <iostream>
|
|
|
|
#include <QtGui>
|
|
|
|
#include <libtransmission/transmission.h>
|
|
#include <libtransmission/utils.h>
|
|
#include <libtransmission/version.h>
|
|
|
|
#include "about.h"
|
|
#include "add-data.h"
|
|
#include "app.h"
|
|
#include "details.h"
|
|
#include "filterbar.h"
|
|
#include "filters.h"
|
|
#include "formatter.h"
|
|
#include "hig.h"
|
|
#include "mainwin.h"
|
|
#include "make-dialog.h"
|
|
#include "options.h"
|
|
#include "prefs.h"
|
|
#include "prefs-dialog.h"
|
|
#include "relocate.h"
|
|
#include "session.h"
|
|
#include "session-dialog.h"
|
|
#include "speed.h"
|
|
#include "stats-dialog.h"
|
|
#include "torrent-delegate.h"
|
|
#include "torrent-delegate-min.h"
|
|
#include "torrent-filter.h"
|
|
#include "torrent-model.h"
|
|
#include "triconpushbutton.h"
|
|
#include "ui_mainwin.h"
|
|
|
|
#define PREFS_KEY "prefs-key";
|
|
|
|
QIcon
|
|
TrMainWindow :: getStockIcon( const QString& name, int fallback )
|
|
{
|
|
QIcon icon = QIcon::fromTheme( name );
|
|
|
|
if( icon.isNull( ) && ( fallback >= 0 ) )
|
|
icon = style()->standardIcon( QStyle::StandardPixmap( fallback ), 0, this );
|
|
|
|
return icon;
|
|
}
|
|
|
|
namespace
|
|
{
|
|
QSize calculateTextButtonSizeHint( QPushButton * button )
|
|
{
|
|
QStyleOptionButton opt;
|
|
opt.initFrom( button );
|
|
QString s( button->text( ) );
|
|
if( s.isEmpty( ) )
|
|
s = QString::fromLatin1( "XXXX" );
|
|
QFontMetrics fm = button->fontMetrics( );
|
|
QSize sz = fm.size( Qt::TextShowMnemonic, s );
|
|
return button->style()->sizeFromContents( QStyle::CT_PushButton, &opt, sz, button ).expandedTo( QApplication::globalStrut( ) );
|
|
}
|
|
}
|
|
|
|
|
|
TrMainWindow :: TrMainWindow( Session& session, Prefs& prefs, TorrentModel& model, bool minimized ):
|
|
myLastFullUpdateTime( 0 ),
|
|
mySessionDialog( new SessionDialog( session, prefs, this ) ),
|
|
myPrefsDialog( 0 ),
|
|
myAboutDialog( new AboutDialog( this ) ),
|
|
myStatsDialog( new StatsDialog( session, this ) ),
|
|
myDetailsDialog( 0 ),
|
|
myFilterModel( prefs ),
|
|
myTorrentDelegate( new TorrentDelegate( this ) ),
|
|
myTorrentDelegateMin( new TorrentDelegateMin( this ) ),
|
|
mySession( session ),
|
|
myPrefs( prefs ),
|
|
myModel( model ),
|
|
mySpeedModeOffIcon( ":/icons/alt-limit-off.png" ),
|
|
mySpeedModeOnIcon( ":/icons/alt-limit-on.png" ),
|
|
myLastSendTime( 0 ),
|
|
myLastReadTime( 0 ),
|
|
myNetworkTimer( this )
|
|
{
|
|
setAcceptDrops( true );
|
|
|
|
QAction * sep = new QAction( this );
|
|
sep->setSeparator( true );
|
|
|
|
ui.setupUi( this );
|
|
|
|
QStyle * style = this->style();
|
|
|
|
int i = style->pixelMetric( QStyle::PM_SmallIconSize, 0, this );
|
|
const QSize smallIconSize( i, i );
|
|
|
|
// icons
|
|
ui.action_OpenFile->setIcon( getStockIcon( "folder-open", QStyle::SP_DialogOpenButton ) );
|
|
ui.action_New->setIcon( getStockIcon( "document-new", QStyle::SP_DesktopIcon ) );
|
|
ui.action_Properties->setIcon( getStockIcon( "document-properties", QStyle::SP_DesktopIcon ) );
|
|
ui.action_OpenFolder->setIcon( getStockIcon( "folder-open", QStyle::SP_DirOpenIcon ) );
|
|
ui.action_Start->setIcon( getStockIcon( "media-playback-start", QStyle::SP_MediaPlay ) );
|
|
ui.action_Announce->setIcon( getStockIcon( "network-transmit-receive" ) );
|
|
ui.action_Pause->setIcon( getStockIcon( "media-playback-pause", QStyle::SP_MediaPause ) );
|
|
ui.action_Remove->setIcon( getStockIcon( "list-remove", QStyle::SP_TrashIcon ) );
|
|
ui.action_Delete->setIcon( getStockIcon( "edit-delete", QStyle::SP_TrashIcon ) );
|
|
ui.action_StartAll->setIcon( getStockIcon( "media-playback-start", QStyle::SP_MediaPlay ) );
|
|
ui.action_PauseAll->setIcon( getStockIcon( "media-playback-pause", QStyle::SP_MediaPause ) );
|
|
ui.action_Quit->setIcon( getStockIcon( "application-exit" ) );
|
|
ui.action_SelectAll->setIcon( getStockIcon( "edit-select-all" ) );
|
|
ui.action_ReverseSortOrder->setIcon( getStockIcon( "view-sort-ascending", QStyle::SP_ArrowDown ) );
|
|
ui.action_Preferences->setIcon( getStockIcon( "preferences-system" ) );
|
|
ui.action_Contents->setIcon( getStockIcon( "help-contents", QStyle::SP_DialogHelpButton ) );
|
|
ui.action_About->setIcon( getStockIcon( "help-about" ) );
|
|
|
|
// ui signals
|
|
connect( ui.action_Toolbar, SIGNAL(toggled(bool)), this, SLOT(setToolbarVisible(bool)));
|
|
connect( ui.action_Filterbar, SIGNAL(toggled(bool)), this, SLOT(setFilterbarVisible(bool)));
|
|
connect( ui.action_Statusbar, SIGNAL(toggled(bool)), this, SLOT(setStatusbarVisible(bool)));
|
|
connect( ui.action_CompactView, SIGNAL(toggled(bool)), this, SLOT(setCompactView(bool)));
|
|
connect( ui.action_SortByActivity, SIGNAL(toggled(bool)), this, SLOT(onSortByActivityToggled(bool)));
|
|
connect( ui.action_SortByAge, SIGNAL(toggled(bool)), this, SLOT(onSortByAgeToggled(bool)));
|
|
connect( ui.action_SortByETA, SIGNAL(toggled(bool)), this, SLOT(onSortByETAToggled(bool)));
|
|
connect( ui.action_SortByName, SIGNAL(toggled(bool)), this, SLOT(onSortByNameToggled(bool)));
|
|
connect( ui.action_SortByProgress, SIGNAL(toggled(bool)), this, SLOT(onSortByProgressToggled(bool)));
|
|
connect( ui.action_SortByRatio, SIGNAL(toggled(bool)), this, SLOT(onSortByRatioToggled(bool)));
|
|
connect( ui.action_SortBySize, SIGNAL(toggled(bool)), this, SLOT(onSortBySizeToggled(bool)));
|
|
connect( ui.action_SortByState, SIGNAL(toggled(bool)), this, SLOT(onSortByStateToggled(bool)));
|
|
connect( ui.action_ReverseSortOrder, SIGNAL(toggled(bool)), this, SLOT(setSortAscendingPref(bool)));
|
|
connect( ui.action_Start, SIGNAL(triggered()), this, SLOT(startSelected()));
|
|
connect( ui.action_Pause, SIGNAL(triggered()), this, SLOT(pauseSelected()));
|
|
connect( ui.action_Remove, SIGNAL(triggered()), this, SLOT(removeSelected()));
|
|
connect( ui.action_Delete, SIGNAL(triggered()), this, SLOT(deleteSelected()));
|
|
connect( ui.action_Verify, SIGNAL(triggered()), this, SLOT(verifySelected()) );
|
|
connect( ui.action_Announce, SIGNAL(triggered()), this, SLOT(reannounceSelected()) );
|
|
connect( ui.action_StartAll, SIGNAL(triggered()), this, SLOT(startAll()));
|
|
connect( ui.action_PauseAll, SIGNAL(triggered()), this, SLOT(pauseAll()));
|
|
connect( ui.action_OpenFile, SIGNAL(triggered()), this, SLOT(openTorrent()));
|
|
connect( ui.action_AddURL, SIGNAL(triggered()), this, SLOT(openURL()));
|
|
connect( ui.action_New, SIGNAL(triggered()), this, SLOT(newTorrent()));
|
|
connect( ui.action_Preferences, SIGNAL(triggered()), this, SLOT(openPreferences()));
|
|
connect( ui.action_Statistics, SIGNAL(triggered()), myStatsDialog, SLOT(show()));
|
|
connect( ui.action_Donate, SIGNAL(triggered()), this, SLOT(openDonate()));
|
|
connect( ui.action_About, SIGNAL(triggered()), myAboutDialog, SLOT(show()));
|
|
connect( ui.action_Contents, SIGNAL(triggered()), this, SLOT(openHelp()));
|
|
connect( ui.action_OpenFolder, SIGNAL(triggered()), this, SLOT(openFolder()));
|
|
connect( ui.action_CopyMagnetToClipboard, SIGNAL(triggered()), this, SLOT(copyMagnetLinkToClipboard()));
|
|
connect( ui.action_SetLocation, SIGNAL(triggered()), this, SLOT(setLocation()));
|
|
connect( ui.action_Properties, SIGNAL(triggered()), this, SLOT(openProperties()));
|
|
connect( ui.action_SessionDialog, SIGNAL(triggered()), mySessionDialog, SLOT(show()));
|
|
connect( ui.listView, SIGNAL(activated(const QModelIndex&)), ui.action_Properties, SLOT(trigger()));
|
|
|
|
QAction * sep2 = new QAction( this );
|
|
sep2->setSeparator( true );
|
|
QAction * sep3 = new QAction( this );
|
|
sep3->setSeparator( true );
|
|
|
|
// context menu
|
|
QList<QAction*> actions;
|
|
actions << ui.action_Properties
|
|
<< ui.action_OpenFolder
|
|
<< sep2
|
|
<< ui.action_Start
|
|
<< ui.action_Announce
|
|
<< ui.action_Pause
|
|
<< ui.action_CopyMagnetToClipboard
|
|
<< sep3
|
|
<< ui.action_Verify
|
|
<< ui.action_SetLocation
|
|
<< sep
|
|
<< ui.action_Remove
|
|
<< ui.action_Delete;
|
|
addActions( actions );
|
|
setContextMenuPolicy( Qt::ActionsContextMenu );
|
|
|
|
// signals
|
|
connect( ui.action_SelectAll, SIGNAL(triggered()), ui.listView, SLOT(selectAll()));
|
|
connect( ui.action_DeselectAll, SIGNAL(triggered()), ui.listView, SLOT(clearSelection()));
|
|
|
|
connect( &myFilterModel, SIGNAL(rowsInserted(const QModelIndex&,int,int)), this, SLOT(refreshVisibleCount()));
|
|
connect( &myFilterModel, SIGNAL(rowsRemoved(const QModelIndex&,int,int)), this, SLOT(refreshVisibleCount()));
|
|
connect( &myFilterModel, SIGNAL(rowsInserted(const QModelIndex&,int,int)), this, SLOT(refreshActionSensitivity()));
|
|
connect( &myFilterModel, SIGNAL(rowsRemoved(const QModelIndex&,int,int)), this, SLOT(refreshActionSensitivity()));
|
|
|
|
connect( ui.action_Quit, SIGNAL(triggered()), QCoreApplication::instance(), SLOT(quit()) );
|
|
|
|
// torrent view
|
|
myFilterModel.setSourceModel( &myModel );
|
|
connect( &myModel, SIGNAL(modelReset()), this, SLOT(onModelReset()));
|
|
connect( &myModel, SIGNAL(rowsRemoved(const QModelIndex&,int,int)), this, SLOT(onModelReset()));
|
|
connect( &myModel, SIGNAL(rowsInserted(const QModelIndex&,int,int)), this, SLOT(onModelReset()));
|
|
connect( &myModel, SIGNAL(dataChanged(const QModelIndex&,const QModelIndex&)), this, SLOT(refreshTrayIcon()));
|
|
|
|
ui.listView->setModel( &myFilterModel );
|
|
connect( ui.listView->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&,const QItemSelection&)), this, SLOT(refreshActionSensitivity()));
|
|
|
|
QActionGroup * actionGroup = new QActionGroup( this );
|
|
actionGroup->addAction( ui.action_SortByActivity );
|
|
actionGroup->addAction( ui.action_SortByAge );
|
|
actionGroup->addAction( ui.action_SortByETA );
|
|
actionGroup->addAction( ui.action_SortByName );
|
|
actionGroup->addAction( ui.action_SortByProgress );
|
|
actionGroup->addAction( ui.action_SortByRatio );
|
|
actionGroup->addAction( ui.action_SortBySize );
|
|
actionGroup->addAction( ui.action_SortByState );
|
|
|
|
QMenu * menu = new QMenu( );
|
|
menu->addAction( ui.action_OpenFile );
|
|
menu->addAction( ui.action_AddURL );
|
|
menu->addSeparator( );
|
|
menu->addAction( ui.action_ShowMainWindow );
|
|
menu->addAction( ui.action_ShowMessageLog );
|
|
menu->addAction( ui.action_About );
|
|
menu->addSeparator( );
|
|
menu->addAction( ui.action_StartAll );
|
|
menu->addAction( ui.action_PauseAll );
|
|
menu->addSeparator( );
|
|
menu->addAction( ui.action_Quit );
|
|
myTrayIcon.setContextMenu( menu );
|
|
myTrayIcon.setIcon( QApplication::windowIcon( ) );
|
|
|
|
connect( &myPrefs, SIGNAL(changed(int)), this, SLOT(refreshPref(int)) );
|
|
connect( ui.action_ShowMainWindow, SIGNAL(toggled(bool)), this, SLOT(toggleWindows(bool)));
|
|
connect( &myTrayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
|
|
this, SLOT(trayActivated(QSystemTrayIcon::ActivationReason)));
|
|
|
|
ui.action_ShowMainWindow->setChecked( !minimized );
|
|
ui.action_TrayIcon->setChecked( minimized || prefs.getBool( Prefs::SHOW_TRAY_ICON ) );
|
|
|
|
ui.verticalLayout->addWidget( createStatusBar( ) );
|
|
ui.verticalLayout->insertWidget( 0, myFilterBar = new FilterBar( myPrefs, myModel, myFilterModel ) );
|
|
|
|
QList<int> initKeys;
|
|
initKeys << Prefs :: MAIN_WINDOW_X
|
|
<< Prefs :: SHOW_TRAY_ICON
|
|
<< Prefs :: SORT_REVERSED
|
|
<< Prefs :: SORT_MODE
|
|
<< Prefs :: FILTERBAR
|
|
<< Prefs :: STATUSBAR
|
|
<< Prefs :: STATUSBAR_STATS
|
|
<< Prefs :: TOOLBAR
|
|
<< Prefs :: ALT_SPEED_LIMIT_ENABLED
|
|
<< Prefs :: COMPACT_VIEW
|
|
<< Prefs :: DSPEED
|
|
<< Prefs :: DSPEED_ENABLED
|
|
<< Prefs :: USPEED
|
|
<< Prefs :: USPEED_ENABLED
|
|
<< Prefs :: RATIO
|
|
<< Prefs :: RATIO_ENABLED;
|
|
foreach( int key, initKeys )
|
|
refreshPref( key );
|
|
|
|
connect( &mySession, SIGNAL(sourceChanged()), this, SLOT(onSessionSourceChanged()) );
|
|
connect( &mySession, SIGNAL(statsUpdated()), this, SLOT(refreshStatusBar()) );
|
|
connect( &mySession, SIGNAL(dataReadProgress()), this, SLOT(dataReadProgress()) );
|
|
connect( &mySession, SIGNAL(dataSendProgress()), this, SLOT(dataSendProgress()) );
|
|
connect( &mySession, SIGNAL(httpAuthenticationRequired()), this, SLOT(wrongAuthentication()) );
|
|
|
|
if( mySession.isServer( ) )
|
|
myNetworkLabel->hide( );
|
|
else {
|
|
connect( &myNetworkTimer, SIGNAL(timeout()), this, SLOT(onNetworkTimer()));
|
|
myNetworkTimer.start( 1000 );
|
|
}
|
|
|
|
refreshActionSensitivity( );
|
|
refreshTrayIcon( );
|
|
refreshStatusBar( );
|
|
refreshTitle( );
|
|
refreshVisibleCount( );
|
|
}
|
|
|
|
TrMainWindow :: ~TrMainWindow( )
|
|
{
|
|
}
|
|
|
|
/****
|
|
*****
|
|
****/
|
|
|
|
void
|
|
TrMainWindow :: closeEvent( QCloseEvent * event )
|
|
{
|
|
// if they're using a tray icon, close to the tray
|
|
// instead of exiting
|
|
if( !myPrefs.getBool( Prefs :: SHOW_TRAY_ICON ) )
|
|
event->accept( );
|
|
else {
|
|
toggleWindows( false );
|
|
event->ignore( );
|
|
}
|
|
}
|
|
|
|
/****
|
|
*****
|
|
****/
|
|
|
|
void
|
|
TrMainWindow :: onSessionSourceChanged( )
|
|
{
|
|
myModel.clear( );
|
|
}
|
|
|
|
void
|
|
TrMainWindow :: onModelReset( )
|
|
{
|
|
refreshTitle( );
|
|
refreshVisibleCount( );
|
|
refreshActionSensitivity( );
|
|
refreshStatusBar( );
|
|
refreshTrayIcon( );
|
|
}
|
|
|
|
/****
|
|
*****
|
|
****/
|
|
|
|
#define PREF_VARIANTS_KEY "pref-variants-list"
|
|
|
|
void
|
|
TrMainWindow :: onSetPrefs( )
|
|
{
|
|
const QVariantList p = sender()->property( PREF_VARIANTS_KEY ).toList( );
|
|
assert( ( p.size( ) % 2 ) == 0 );
|
|
for( int i=0, n=p.size(); i<n; i+=2 )
|
|
myPrefs.set( p[i].toInt(), p[i+1] );
|
|
}
|
|
|
|
void
|
|
TrMainWindow :: onSetPrefs( bool isChecked )
|
|
{
|
|
if( isChecked )
|
|
onSetPrefs( );
|
|
}
|
|
|
|
#define SHOW_KEY "show-mode"
|
|
|
|
QWidget *
|
|
TrMainWindow :: createStatusBar( )
|
|
{
|
|
QMenu * m;
|
|
QLabel * l;
|
|
QHBoxLayout * h;
|
|
QPushButton * p;
|
|
QActionGroup * a;
|
|
const int i = style( )->pixelMetric( QStyle::PM_SmallIconSize, 0, this );
|
|
const QSize smallIconSize( i, i );
|
|
|
|
QWidget * top = myStatusBar = new QWidget;
|
|
h = new QHBoxLayout( top );
|
|
h->setContentsMargins( HIG::PAD_SMALL, HIG::PAD_SMALL, HIG::PAD_SMALL, HIG::PAD_SMALL );
|
|
h->setSpacing( HIG::PAD_SMALL );
|
|
|
|
p = myOptionsButton = new TrIconPushButton( this );
|
|
p->setIcon( QIcon( ":/icons/utilities.png" ) );
|
|
p->setIconSize( QPixmap( ":/icons/utilities.png" ).size() );
|
|
p->setFlat( true );
|
|
p->setMenu( createOptionsMenu( ) );
|
|
h->addWidget( p );
|
|
|
|
p = myAltSpeedButton = new QPushButton( this );
|
|
p->setIcon( myPrefs.get<bool>(Prefs::ALT_SPEED_LIMIT_ENABLED) ? mySpeedModeOnIcon : mySpeedModeOffIcon );
|
|
p->setIconSize( QPixmap( ":/icons/alt-limit-on.png" ).size() );
|
|
p->setCheckable( true );
|
|
p->setFixedWidth( p->height() );
|
|
p->setFlat( true );
|
|
h->addWidget( p );
|
|
connect( p, SIGNAL(clicked()), this, SLOT(toggleSpeedMode()));
|
|
|
|
l = myNetworkLabel = new QLabel;
|
|
h->addWidget( l );
|
|
|
|
h->addStretch( 1 );
|
|
|
|
l = myVisibleCountLabel = new QLabel( this );
|
|
h->addWidget( l );
|
|
|
|
h->addStretch( 1 );
|
|
|
|
a = new QActionGroup( this );
|
|
a->addAction( ui.action_TotalRatio );
|
|
a->addAction( ui.action_TotalTransfer );
|
|
a->addAction( ui.action_SessionRatio );
|
|
a->addAction( ui.action_SessionTransfer );
|
|
m = new QMenu( );
|
|
m->addAction( ui.action_TotalRatio );
|
|
m->addAction( ui.action_TotalTransfer );
|
|
m->addAction( ui.action_SessionRatio );
|
|
m->addAction( ui.action_SessionTransfer );
|
|
connect( ui.action_TotalRatio, SIGNAL(triggered()), this, SLOT(showTotalRatio()));
|
|
connect( ui.action_TotalTransfer, SIGNAL(triggered()), this, SLOT(showTotalTransfer()));
|
|
connect( ui.action_SessionRatio, SIGNAL(triggered()), this, SLOT(showSessionRatio()));
|
|
connect( ui.action_SessionTransfer, SIGNAL(triggered()), this, SLOT(showSessionTransfer()));
|
|
p = myStatsModeButton = new TrIconPushButton( this );
|
|
p->setIcon( QIcon( ":/icons/ratio.png" ) );
|
|
p->setIconSize( QPixmap( ":/icons/ratio.png" ).size() );
|
|
p->setFlat( true );
|
|
p->setMenu( m );
|
|
h->addWidget( p );
|
|
l = myStatsLabel = new QLabel( this );
|
|
h->addWidget( l );
|
|
|
|
h->addStretch( 1 );
|
|
|
|
l = myDownloadSpeedLabel = new QLabel( this );
|
|
const int minimumSpeedWidth = l->fontMetrics().width( Formatter::speedToString(Speed::fromKBps(999.99)));
|
|
l->setMinimumWidth( minimumSpeedWidth );
|
|
l->setAlignment( Qt::AlignRight|Qt::AlignVCenter );
|
|
h->addWidget( l );
|
|
l = new QLabel( this );
|
|
l->setPixmap( getStockIcon( "go-down", QStyle::SP_ArrowDown ).pixmap( smallIconSize ) );
|
|
h->addWidget( l );
|
|
|
|
h->addStretch( 1 );
|
|
|
|
l = myUploadSpeedLabel = new QLabel;
|
|
l->setMinimumWidth( minimumSpeedWidth );
|
|
l->setAlignment( Qt::AlignRight|Qt::AlignVCenter );
|
|
h->addWidget( l );
|
|
l = new QLabel;
|
|
l->setPixmap( getStockIcon( "go-up", QStyle::SP_ArrowUp ).pixmap( smallIconSize ) );
|
|
h->addWidget( l );
|
|
|
|
return top;
|
|
}
|
|
|
|
QMenu *
|
|
TrMainWindow :: createOptionsMenu( )
|
|
{
|
|
QMenu * menu;
|
|
QMenu * sub;
|
|
QAction * a;
|
|
QActionGroup * g;
|
|
|
|
QList<int> stockSpeeds;
|
|
stockSpeeds << 5 << 10 << 20 << 30 << 40 << 50 << 75 << 100 << 150 << 200 << 250 << 500 << 750;
|
|
QList<double> stockRatios;
|
|
stockRatios << 0.25 << 0.50 << 0.75 << 1 << 1.5 << 2 << 3;
|
|
|
|
menu = new QMenu;
|
|
sub = menu->addMenu( tr( "Limit Download Speed" ) );
|
|
int currentVal = myPrefs.get<int>( Prefs::DSPEED );
|
|
g = new QActionGroup( this );
|
|
a = myDlimitOffAction = sub->addAction( tr( "Unlimited" ) );
|
|
a->setCheckable( true );
|
|
a->setProperty( PREF_VARIANTS_KEY, QVariantList() << Prefs::DSPEED_ENABLED << false );
|
|
g->addAction( a );
|
|
connect( a, SIGNAL(triggered(bool)), this, SLOT(onSetPrefs(bool)) );
|
|
a = myDlimitOnAction = sub->addAction( tr( "Limited at %1" ).arg( Formatter::speedToString( Speed::fromKBps( currentVal ) ) ) );
|
|
a->setCheckable( true );
|
|
a->setProperty( PREF_VARIANTS_KEY, QVariantList() << Prefs::DSPEED << currentVal << Prefs::DSPEED_ENABLED << true );
|
|
g->addAction( a );
|
|
connect( a, SIGNAL(triggered(bool)), this, SLOT(onSetPrefs(bool)) );
|
|
sub->addSeparator( );
|
|
foreach( int i, stockSpeeds ) {
|
|
a = sub->addAction( Formatter::speedToString( Speed::fromKBps( i ) ) );
|
|
a->setProperty( PREF_VARIANTS_KEY, QVariantList() << Prefs::DSPEED << i << Prefs::DSPEED_ENABLED << true );
|
|
connect( a, SIGNAL(triggered(bool)), this, SLOT(onSetPrefs()));
|
|
}
|
|
|
|
sub = menu->addMenu( tr( "Limit Upload Speed" ) );
|
|
currentVal = myPrefs.get<int>( Prefs::USPEED );
|
|
g = new QActionGroup( this );
|
|
a = myUlimitOffAction = sub->addAction( tr( "Unlimited" ) );
|
|
a->setCheckable( true );
|
|
a->setProperty( PREF_VARIANTS_KEY, QVariantList() << Prefs::USPEED_ENABLED << false );
|
|
g->addAction( a );
|
|
connect( a, SIGNAL(triggered(bool)), this, SLOT(onSetPrefs(bool)) );
|
|
a = myUlimitOnAction = sub->addAction( tr( "Limited at %1" ).arg( Formatter::speedToString( Speed::fromKBps( currentVal ) ) ) );
|
|
a->setCheckable( true );
|
|
a->setProperty( PREF_VARIANTS_KEY, QVariantList() << Prefs::USPEED << currentVal << Prefs::USPEED_ENABLED << true );
|
|
g->addAction( a );
|
|
connect( a, SIGNAL(triggered(bool)), this, SLOT(onSetPrefs(bool)) );
|
|
sub->addSeparator( );
|
|
foreach( int i, stockSpeeds ) {
|
|
a = sub->addAction( Formatter::speedToString( Speed::fromKBps( i ) ) );
|
|
a->setProperty( PREF_VARIANTS_KEY, QVariantList() << Prefs::USPEED << i << Prefs::USPEED_ENABLED << true );
|
|
connect( a, SIGNAL(triggered(bool)), this, SLOT(onSetPrefs()));
|
|
}
|
|
|
|
menu->addSeparator( );
|
|
sub = menu->addMenu( tr( "Stop Seeding at Ratio" ) );
|
|
|
|
double d = myPrefs.get<double>( Prefs::RATIO );
|
|
g = new QActionGroup( this );
|
|
a = myRatioOffAction = sub->addAction( tr( "Seed Forever" ) );
|
|
a->setCheckable( true );
|
|
a->setProperty( PREF_VARIANTS_KEY, QVariantList() << Prefs::RATIO_ENABLED << false );
|
|
g->addAction( a );
|
|
connect( a, SIGNAL(triggered(bool)), this, SLOT(onSetPrefs(bool)) );
|
|
a = myRatioOnAction = sub->addAction( tr( "Stop at Ratio (%1)" ).arg( Formatter::ratioToString( d ) ) );
|
|
a->setCheckable( true );
|
|
a->setProperty( PREF_VARIANTS_KEY, QVariantList() << Prefs::RATIO << d << Prefs::RATIO_ENABLED << true );
|
|
g->addAction( a );
|
|
connect( a, SIGNAL(triggered(bool)), this, SLOT(onSetPrefs(bool)) );
|
|
sub->addSeparator( );
|
|
foreach( double i, stockRatios ) {
|
|
a = sub->addAction( Formatter::ratioToString( i ) );
|
|
a->setProperty( PREF_VARIANTS_KEY, QVariantList() << Prefs::RATIO << i << Prefs::RATIO_ENABLED << true );
|
|
connect( a, SIGNAL(triggered(bool)), this, SLOT(onSetPrefs()));
|
|
}
|
|
|
|
return menu;
|
|
}
|
|
|
|
/****
|
|
*****
|
|
****/
|
|
|
|
void
|
|
TrMainWindow :: setSortPref( int i )
|
|
{
|
|
myPrefs.set( Prefs::SORT_MODE, SortMode( i ) );
|
|
}
|
|
void TrMainWindow :: onSortByActivityToggled ( bool b ) { if( b ) setSortPref( SortMode::SORT_BY_ACTIVITY ); }
|
|
void TrMainWindow :: onSortByAgeToggled ( bool b ) { if( b ) setSortPref( SortMode::SORT_BY_AGE ); }
|
|
void TrMainWindow :: onSortByETAToggled ( bool b ) { if( b ) setSortPref( SortMode::SORT_BY_ETA ); }
|
|
void TrMainWindow :: onSortByNameToggled ( bool b ) { if( b ) setSortPref( SortMode::SORT_BY_NAME ); }
|
|
void TrMainWindow :: onSortByProgressToggled ( bool b ) { if( b ) setSortPref( SortMode::SORT_BY_PROGRESS ); }
|
|
void TrMainWindow :: onSortByRatioToggled ( bool b ) { if( b ) setSortPref( SortMode::SORT_BY_RATIO ); }
|
|
void TrMainWindow :: onSortBySizeToggled ( bool b ) { if( b ) setSortPref( SortMode::SORT_BY_SIZE ); }
|
|
void TrMainWindow :: onSortByStateToggled ( bool b ) { if( b ) setSortPref( SortMode::SORT_BY_STATE ); }
|
|
|
|
void
|
|
TrMainWindow :: setSortAscendingPref( bool b )
|
|
{
|
|
myPrefs.set( Prefs::SORT_REVERSED, b );
|
|
}
|
|
|
|
/****
|
|
*****
|
|
****/
|
|
|
|
void
|
|
TrMainWindow :: onPrefsDestroyed( )
|
|
{
|
|
myPrefsDialog = 0;
|
|
}
|
|
|
|
void
|
|
TrMainWindow :: openPreferences( )
|
|
{
|
|
if( myPrefsDialog == 0 ) {
|
|
myPrefsDialog = new PrefsDialog( mySession, myPrefs, this );
|
|
connect( myPrefsDialog, SIGNAL(destroyed(QObject*)), this, SLOT(onPrefsDestroyed()));
|
|
}
|
|
|
|
myPrefsDialog->show( );
|
|
}
|
|
|
|
void
|
|
TrMainWindow :: onDetailsDestroyed( )
|
|
{
|
|
myDetailsDialog = 0;
|
|
}
|
|
|
|
void
|
|
TrMainWindow :: openProperties( )
|
|
{
|
|
if( myDetailsDialog == 0 ) {
|
|
myDetailsDialog = new Details( mySession, myPrefs, myModel, this );
|
|
connect( myDetailsDialog, SIGNAL(destroyed(QObject*)), this, SLOT(onDetailsDestroyed()));
|
|
}
|
|
|
|
myDetailsDialog->setIds( getSelectedTorrents( ) );
|
|
myDetailsDialog->show( );
|
|
}
|
|
|
|
void
|
|
TrMainWindow :: setLocation( )
|
|
{
|
|
QDialog * d = new RelocateDialog( mySession, myModel, getSelectedTorrents(), this );
|
|
d->show( );
|
|
}
|
|
|
|
void
|
|
TrMainWindow :: openFolder( )
|
|
{
|
|
const int torrentId( *getSelectedTorrents().begin() );
|
|
const Torrent * tor( myModel.getTorrentFromId( torrentId ) );
|
|
const QString path( tor->getPath( ) );
|
|
QDesktopServices :: openUrl( QUrl::fromLocalFile( path ) );
|
|
}
|
|
|
|
void
|
|
TrMainWindow :: copyMagnetLinkToClipboard( )
|
|
{
|
|
const int id( *getSelectedTorrents().begin() );
|
|
mySession.copyMagnetLinkToClipboard( id );
|
|
}
|
|
|
|
void
|
|
TrMainWindow :: openDonate( )
|
|
{
|
|
QDesktopServices :: openUrl( QUrl( "http://www.transmissionbt.com/donate.php" ) );
|
|
}
|
|
|
|
void
|
|
TrMainWindow :: openHelp( )
|
|
{
|
|
const char * fmt = "http://www.transmissionbt.com/help/gtk/%d.%dx";
|
|
int major, minor;
|
|
sscanf( SHORT_VERSION_STRING, "%d.%d", &major, &minor );
|
|
char url[128];
|
|
tr_snprintf( url, sizeof( url ), fmt, major, minor/10 );
|
|
QDesktopServices :: openUrl( QUrl( url ) );
|
|
}
|
|
|
|
void
|
|
TrMainWindow :: refreshTitle( )
|
|
{
|
|
QString title( "Transmission" );
|
|
const QUrl url( mySession.getRemoteUrl( ) );
|
|
if( !url.isEmpty() )
|
|
title += tr( " - %1:%2" ).arg( url.host() ).arg( url.port() );
|
|
setWindowTitle( title );
|
|
}
|
|
|
|
void
|
|
TrMainWindow :: refreshVisibleCount( )
|
|
{
|
|
const int visibleCount( myFilterModel.rowCount( ) );
|
|
const int totalCount( visibleCount + myFilterModel.hiddenRowCount( ) );
|
|
QString str;
|
|
if( visibleCount == totalCount )
|
|
str = tr( "%Ln Torrent(s)", 0, totalCount );
|
|
else
|
|
str = tr( "%L1 of %Ln Torrent(s)", 0, totalCount ).arg( visibleCount );
|
|
myVisibleCountLabel->setText( str );
|
|
myVisibleCountLabel->setVisible( totalCount > 0 );
|
|
}
|
|
|
|
void
|
|
TrMainWindow :: refreshTrayIcon( )
|
|
{
|
|
Speed u, d;
|
|
const QString idle = tr( "Idle" );
|
|
|
|
foreach( int id, myModel.getIds( ) ) {
|
|
const Torrent * tor = myModel.getTorrentFromId( id );
|
|
u += tor->uploadSpeed( );
|
|
d += tor->downloadSpeed( );
|
|
}
|
|
|
|
myTrayIcon.setToolTip( tr( "Transmission\nUp: %1\nDown: %2" )
|
|
.arg( u.isZero() ? idle : Formatter::speedToString( u ) )
|
|
.arg( d.isZero() ? idle : Formatter::speedToString( d ) ) );
|
|
}
|
|
|
|
void
|
|
TrMainWindow :: refreshStatusBar( )
|
|
{
|
|
const Speed up( myModel.getUploadSpeed( ) );
|
|
const Speed down( myModel.getDownloadSpeed( ) );
|
|
myUploadSpeedLabel->setText( Formatter:: speedToString( up ) );
|
|
myDownloadSpeedLabel->setText( Formatter:: speedToString( down ) );
|
|
|
|
myNetworkLabel->setVisible( !mySession.isServer( ) );
|
|
|
|
const QString mode( myPrefs.getString( Prefs::STATUSBAR_STATS ) );
|
|
QString str;
|
|
|
|
if( mode == "session-ratio" )
|
|
{
|
|
str = tr( "Ratio: %1" ).arg( Formatter:: ratioToString( mySession.getStats().ratio ) );
|
|
}
|
|
else if( mode == "session-transfer" )
|
|
{
|
|
const tr_session_stats& stats( mySession.getStats( ) );
|
|
str = tr( "Down: %1, Up: %2" ).arg( Formatter:: sizeToString( stats.downloadedBytes ) )
|
|
.arg( Formatter:: sizeToString( stats.uploadedBytes ) );
|
|
}
|
|
else if( mode == "total-transfer" )
|
|
{
|
|
const tr_session_stats& stats( mySession.getCumulativeStats( ) );
|
|
str = tr( "Down: %1, Up: %2" ).arg( Formatter:: sizeToString( stats.downloadedBytes ) )
|
|
.arg( Formatter:: sizeToString( stats.uploadedBytes ) );
|
|
}
|
|
else // default is "total-ratio"
|
|
{
|
|
str = tr( "Ratio: %1" ).arg( Formatter:: ratioToString( mySession.getCumulativeStats().ratio ) );
|
|
}
|
|
|
|
myStatsLabel->setText( str );
|
|
}
|
|
|
|
void
|
|
TrMainWindow :: refreshActionSensitivity( )
|
|
{
|
|
int selected( 0 );
|
|
int paused( 0 );
|
|
int selectedAndPaused( 0 );
|
|
int canAnnounce( 0 );
|
|
const QAbstractItemModel * model( ui.listView->model( ) );
|
|
const QItemSelectionModel * selectionModel( ui.listView->selectionModel( ) );
|
|
const int rowCount( model->rowCount( ) );
|
|
|
|
// count how many torrents are selected, paused, etc
|
|
for( int row=0; row<rowCount; ++row ) {
|
|
const QModelIndex modelIndex( model->index( row, 0 ) );
|
|
assert( model == modelIndex.model( ) );
|
|
const Torrent * tor( model->data( modelIndex, TorrentModel::TorrentRole ).value<const Torrent*>( ) );
|
|
if( tor ) {
|
|
const bool isSelected( selectionModel->isSelected( modelIndex ) );
|
|
const bool isPaused( tor->isPaused( ) );
|
|
if( isSelected )
|
|
++selected;
|
|
if( isPaused )
|
|
++ paused;
|
|
if( isSelected && isPaused )
|
|
++selectedAndPaused;
|
|
if( tor->canManualAnnounce( ) )
|
|
++canAnnounce;
|
|
}
|
|
}
|
|
|
|
const bool haveSelection( selected > 0 );
|
|
ui.action_Verify->setEnabled( haveSelection );
|
|
ui.action_Remove->setEnabled( haveSelection );
|
|
ui.action_Delete->setEnabled( haveSelection );
|
|
ui.action_Properties->setEnabled( haveSelection );
|
|
ui.action_DeselectAll->setEnabled( haveSelection );
|
|
ui.action_SetLocation->setEnabled( haveSelection );
|
|
|
|
const bool oneSelection( selected == 1 );
|
|
ui.action_OpenFolder->setEnabled( oneSelection && mySession.isLocal( ) );
|
|
ui.action_CopyMagnetToClipboard->setEnabled( oneSelection );
|
|
|
|
ui.action_SelectAll->setEnabled( selected < rowCount );
|
|
ui.action_StartAll->setEnabled( paused > 0 );
|
|
ui.action_PauseAll->setEnabled( paused < rowCount );
|
|
ui.action_Start->setEnabled( selectedAndPaused > 0 );
|
|
ui.action_Pause->setEnabled( selectedAndPaused < selected );
|
|
ui.action_Announce->setEnabled( selected > 0 && ( canAnnounce == selected ) );
|
|
|
|
if( myDetailsDialog )
|
|
myDetailsDialog->setIds( getSelectedTorrents( ) );
|
|
}
|
|
|
|
/**
|
|
***
|
|
**/
|
|
|
|
void
|
|
TrMainWindow :: clearSelection( )
|
|
{
|
|
ui.action_DeselectAll->trigger( );
|
|
}
|
|
|
|
QSet<int>
|
|
TrMainWindow :: getSelectedTorrents( ) const
|
|
{
|
|
QSet<int> ids;
|
|
|
|
foreach( QModelIndex index, ui.listView->selectionModel( )->selectedRows( ) )
|
|
{
|
|
const Torrent * tor( index.data( TorrentModel::TorrentRole ).value<const Torrent*>( ) );
|
|
ids.insert( tor->id( ) );
|
|
}
|
|
|
|
return ids;
|
|
}
|
|
|
|
void
|
|
TrMainWindow :: startSelected( )
|
|
{
|
|
mySession.startTorrents( getSelectedTorrents( ) );
|
|
}
|
|
void
|
|
TrMainWindow :: pauseSelected( )
|
|
{
|
|
mySession.pauseTorrents( getSelectedTorrents( ) );
|
|
}
|
|
void
|
|
TrMainWindow :: startAll( )
|
|
{
|
|
mySession.startTorrents( );
|
|
}
|
|
void
|
|
TrMainWindow :: pauseAll( )
|
|
{
|
|
mySession.pauseTorrents( );
|
|
}
|
|
void
|
|
TrMainWindow :: removeSelected( )
|
|
{
|
|
removeTorrents( false );
|
|
}
|
|
void
|
|
TrMainWindow :: deleteSelected( )
|
|
{
|
|
removeTorrents( true );
|
|
}
|
|
void
|
|
TrMainWindow :: verifySelected( )
|
|
{
|
|
mySession.verifyTorrents( getSelectedTorrents( ) );
|
|
}
|
|
void
|
|
TrMainWindow :: reannounceSelected( )
|
|
{
|
|
mySession.reannounceTorrents( getSelectedTorrents( ) );
|
|
}
|
|
|
|
/**
|
|
***
|
|
**/
|
|
|
|
void TrMainWindow :: showTotalRatio ( ) { myPrefs.set( Prefs::STATUSBAR_STATS, "total-ratio"); }
|
|
void TrMainWindow :: showTotalTransfer ( ) { myPrefs.set( Prefs::STATUSBAR_STATS, "total-transfer"); }
|
|
void TrMainWindow :: showSessionRatio ( ) { myPrefs.set( Prefs::STATUSBAR_STATS, "session-ratio"); }
|
|
void TrMainWindow :: showSessionTransfer ( ) { myPrefs.set( Prefs::STATUSBAR_STATS, "session-transfer"); }
|
|
|
|
/**
|
|
***
|
|
**/
|
|
|
|
void
|
|
TrMainWindow :: setCompactView( bool visible )
|
|
{
|
|
myPrefs.set( Prefs :: COMPACT_VIEW, visible );
|
|
}
|
|
void
|
|
TrMainWindow :: toggleSpeedMode( )
|
|
{
|
|
myPrefs.toggleBool( Prefs :: ALT_SPEED_LIMIT_ENABLED );
|
|
}
|
|
void
|
|
TrMainWindow :: setToolbarVisible( bool visible )
|
|
{
|
|
myPrefs.set( Prefs::TOOLBAR, visible );
|
|
}
|
|
void
|
|
TrMainWindow :: setFilterbarVisible( bool visible )
|
|
{
|
|
myPrefs.set( Prefs::FILTERBAR, visible );
|
|
}
|
|
void
|
|
TrMainWindow :: setStatusbarVisible( bool visible )
|
|
{
|
|
myPrefs.set( Prefs::STATUSBAR, visible );
|
|
}
|
|
|
|
/**
|
|
***
|
|
**/
|
|
|
|
void
|
|
TrMainWindow :: toggleWindows( bool doShow )
|
|
{
|
|
if( !doShow )
|
|
{
|
|
hide( );
|
|
}
|
|
else
|
|
{
|
|
if ( !isVisible( ) ) show( );
|
|
if ( isMinimized( ) ) showNormal( );
|
|
//activateWindow( );
|
|
raise( );
|
|
QApplication::setActiveWindow( this );
|
|
}
|
|
}
|
|
|
|
void
|
|
TrMainWindow :: trayActivated( QSystemTrayIcon::ActivationReason reason )
|
|
{
|
|
if( reason == QSystemTrayIcon::Trigger )
|
|
{
|
|
if( isMinimized ( ) )
|
|
toggleWindows( true );
|
|
else
|
|
ui.action_ShowMainWindow->toggle( );
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
TrMainWindow :: refreshPref( int key )
|
|
{
|
|
bool b;
|
|
int i;
|
|
QString str;
|
|
|
|
switch( key )
|
|
{
|
|
case Prefs::STATUSBAR_STATS:
|
|
str = myPrefs.getString( key );
|
|
ui.action_TotalRatio->setChecked ( str == "total-ratio" );
|
|
ui.action_TotalTransfer->setChecked ( str == "total-transfer" );
|
|
ui.action_SessionRatio->setChecked ( str == "session-ratio" );
|
|
ui.action_SessionTransfer->setChecked( str == "session-transfer" );
|
|
refreshStatusBar( );
|
|
break;
|
|
|
|
case Prefs::SORT_REVERSED:
|
|
ui.action_ReverseSortOrder->setChecked( myPrefs.getBool( key ) );
|
|
break;
|
|
|
|
case Prefs::SORT_MODE:
|
|
i = myPrefs.get<SortMode>(key).mode( );
|
|
ui.action_SortByActivity->setChecked ( i == SortMode::SORT_BY_ACTIVITY );
|
|
ui.action_SortByAge->setChecked ( i == SortMode::SORT_BY_AGE );
|
|
ui.action_SortByETA->setChecked ( i == SortMode::SORT_BY_ETA );
|
|
ui.action_SortByName->setChecked ( i == SortMode::SORT_BY_NAME );
|
|
ui.action_SortByProgress->setChecked ( i == SortMode::SORT_BY_PROGRESS );
|
|
ui.action_SortByRatio->setChecked ( i == SortMode::SORT_BY_RATIO );
|
|
ui.action_SortBySize->setChecked ( i == SortMode::SORT_BY_SIZE );
|
|
ui.action_SortByState->setChecked ( i == SortMode::SORT_BY_STATE );
|
|
break;
|
|
|
|
case Prefs::DSPEED_ENABLED:
|
|
(myPrefs.get<bool>(key) ? myDlimitOnAction : myDlimitOffAction)->setChecked( true );
|
|
break;
|
|
|
|
case Prefs::DSPEED:
|
|
myDlimitOnAction->setText( tr( "Limited at %1" ).arg( Formatter::speedToString( Speed::fromKBps( myPrefs.get<int>(key) ) ) ) );
|
|
break;
|
|
|
|
case Prefs::USPEED_ENABLED:
|
|
(myPrefs.get<bool>(key) ? myUlimitOnAction : myUlimitOffAction)->setChecked( true );
|
|
break;
|
|
|
|
case Prefs::USPEED:
|
|
myUlimitOnAction->setText( tr( "Limited at %1" ).arg( Formatter::speedToString( Speed::fromKBps( myPrefs.get<int>(key) ) ) ) );
|
|
break;
|
|
|
|
case Prefs::RATIO_ENABLED:
|
|
(myPrefs.get<bool>(key) ? myRatioOnAction : myRatioOffAction)->setChecked( true );
|
|
break;
|
|
|
|
case Prefs::RATIO:
|
|
myRatioOnAction->setText( tr( "Stop at Ratio (%1)" ).arg( Formatter::ratioToString( myPrefs.get<double>(key) ) ) );
|
|
break;
|
|
|
|
case Prefs::FILTERBAR:
|
|
b = myPrefs.getBool( key );
|
|
myFilterBar->setVisible( b );
|
|
ui.action_Filterbar->setChecked( b );
|
|
break;
|
|
|
|
case Prefs::STATUSBAR:
|
|
b = myPrefs.getBool( key );
|
|
myStatusBar->setVisible( b );
|
|
ui.action_Statusbar->setChecked( b );
|
|
break;
|
|
|
|
case Prefs::TOOLBAR:
|
|
b = myPrefs.getBool( key );
|
|
ui.toolBar->setVisible( b );
|
|
ui.action_Toolbar->setChecked( b );
|
|
break;
|
|
|
|
case Prefs::SHOW_TRAY_ICON:
|
|
b = myPrefs.getBool( key );
|
|
ui.action_TrayIcon->setChecked( b );
|
|
myTrayIcon.setVisible( b );
|
|
refreshTrayIcon( );
|
|
break;
|
|
|
|
case Prefs::COMPACT_VIEW: {
|
|
QItemSelectionModel * selectionModel( ui.listView->selectionModel( ) );
|
|
const QItemSelection selection( selectionModel->selection( ) );
|
|
const QModelIndex currentIndex( selectionModel->currentIndex( ) );
|
|
b = myPrefs.getBool( key );
|
|
ui.action_CompactView->setChecked( b );
|
|
ui.listView->setItemDelegate( b ? myTorrentDelegateMin : myTorrentDelegate );
|
|
selectionModel->clear( );
|
|
ui.listView->reset( ); // force the rows to resize
|
|
selectionModel->select( selection, QItemSelectionModel::Select );
|
|
selectionModel->setCurrentIndex( currentIndex, QItemSelectionModel::NoUpdate );
|
|
break;
|
|
}
|
|
|
|
case Prefs::MAIN_WINDOW_X:
|
|
case Prefs::MAIN_WINDOW_Y:
|
|
case Prefs::MAIN_WINDOW_WIDTH:
|
|
case Prefs::MAIN_WINDOW_HEIGHT:
|
|
setGeometry( myPrefs.getInt( Prefs::MAIN_WINDOW_X ),
|
|
myPrefs.getInt( Prefs::MAIN_WINDOW_Y ),
|
|
myPrefs.getInt( Prefs::MAIN_WINDOW_WIDTH ),
|
|
myPrefs.getInt( Prefs::MAIN_WINDOW_HEIGHT ) );
|
|
break;
|
|
|
|
case Prefs :: ALT_SPEED_LIMIT_ENABLED:
|
|
case Prefs :: ALT_SPEED_LIMIT_UP:
|
|
case Prefs :: ALT_SPEED_LIMIT_DOWN: {
|
|
b = myPrefs.getBool( Prefs :: ALT_SPEED_LIMIT_ENABLED );
|
|
myAltSpeedButton->setChecked( b );
|
|
myAltSpeedButton->setIcon( b ? mySpeedModeOnIcon : mySpeedModeOffIcon );
|
|
const QString fmt = b ? tr( "Click to disable Temporary Speed Limits\n(%1 down, %2 up)" )
|
|
: tr( "Click to enable Temporary Speed Limits\n(%1 down, %2 up)" );
|
|
const Speed d = Speed::fromKBps( myPrefs.getInt( Prefs::ALT_SPEED_LIMIT_DOWN ) );
|
|
const Speed u = Speed::fromKBps( myPrefs.getInt( Prefs::ALT_SPEED_LIMIT_UP ) );
|
|
myAltSpeedButton->setToolTip( fmt.arg( Formatter::speedToString( d ) )
|
|
.arg( Formatter::speedToString( u ) ) );
|
|
break;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/***
|
|
****
|
|
***/
|
|
|
|
void
|
|
TrMainWindow :: newTorrent( )
|
|
{
|
|
MakeDialog * dialog = new MakeDialog( mySession, this );
|
|
dialog->show( );
|
|
}
|
|
|
|
void
|
|
TrMainWindow :: openTorrent( )
|
|
{
|
|
QFileDialog * myFileDialog;
|
|
myFileDialog = new QFileDialog( this,
|
|
tr( "Open Torrent" ),
|
|
myPrefs.getString( Prefs::OPEN_DIALOG_FOLDER ),
|
|
tr( "Torrent Files (*.torrent);;All Files (*.*)" ) );
|
|
myFileDialog->setFileMode( QFileDialog::ExistingFiles );
|
|
|
|
QCheckBox * button = new QCheckBox( tr( "Show &options dialog" ) );
|
|
button->setChecked( myPrefs.getBool( Prefs::OPTIONS_PROMPT ) );
|
|
QGridLayout * layout = dynamic_cast<QGridLayout*>(myFileDialog->layout());
|
|
layout->addWidget( button, layout->rowCount( ), 0, 1, -1, Qt::AlignLeft );
|
|
myFileDialogOptionsCheck = button;
|
|
|
|
connect( myFileDialog, SIGNAL(filesSelected(const QStringList&)),
|
|
this, SLOT(addTorrents(const QStringList&)));
|
|
|
|
myFileDialog->show( );
|
|
}
|
|
|
|
void
|
|
TrMainWindow :: openURL( )
|
|
{
|
|
QString str = QApplication::clipboard()->text( QClipboard::Selection );
|
|
|
|
if( !AddData::isSupported( str ) )
|
|
str = QApplication::clipboard()->text( QClipboard::Clipboard );
|
|
|
|
if( !AddData::isSupported( str ) )
|
|
str.clear();
|
|
|
|
openURL( str );
|
|
}
|
|
|
|
void
|
|
TrMainWindow :: openURL( QString url )
|
|
{
|
|
bool ok;
|
|
const QString key = QInputDialog::getText( this,
|
|
tr( "Open URL or Magnet Link" ),
|
|
tr( "Open URL or Magnet Link" ),
|
|
QLineEdit::Normal,
|
|
url,
|
|
&ok );
|
|
if( ok && !key.isEmpty( ) )
|
|
mySession.addTorrent( key );
|
|
}
|
|
|
|
void
|
|
TrMainWindow :: addTorrents( const QStringList& filenames )
|
|
{
|
|
foreach( const QString& filename, filenames )
|
|
addTorrent( filename );
|
|
}
|
|
|
|
void
|
|
TrMainWindow :: addTorrent( const QString& filename )
|
|
{
|
|
if( !myFileDialogOptionsCheck->isChecked( ) ) {
|
|
mySession.addTorrent( filename );
|
|
QApplication :: alert ( this );
|
|
} else {
|
|
Options * o = new Options( mySession, myPrefs, filename, this );
|
|
o->show( );
|
|
QApplication :: alert( o );
|
|
}
|
|
}
|
|
|
|
void
|
|
TrMainWindow :: removeTorrents( const bool deleteFiles )
|
|
{
|
|
QSet<int> ids;
|
|
QMessageBox msgBox( this );
|
|
QString primary_text, secondary_text;
|
|
int incomplete = 0;
|
|
int connected = 0;
|
|
int count;
|
|
|
|
foreach( QModelIndex index, ui.listView->selectionModel( )->selectedRows( ) )
|
|
{
|
|
const Torrent * tor( index.data( TorrentModel::TorrentRole ).value<const Torrent*>( ) );
|
|
ids.insert( tor->id( ) );
|
|
if( tor->connectedPeers( ) )
|
|
++connected;
|
|
if( !tor->isDone( ) )
|
|
++incomplete;
|
|
}
|
|
|
|
if( ids.isEmpty() )
|
|
return;
|
|
count = ids.size();
|
|
|
|
if( !deleteFiles )
|
|
{
|
|
primary_text = ( count == 1 )
|
|
? tr( "Remove torrent?" )
|
|
: tr( "Remove %1 torrents?" ).arg( count );
|
|
}
|
|
else
|
|
{
|
|
primary_text = ( count == 1 )
|
|
? tr( "Delete this torrent's downloaded files?" )
|
|
: tr( "Delete these %1 torrents' downloaded files?" ).arg( count );
|
|
}
|
|
|
|
if( !incomplete && !connected )
|
|
{
|
|
secondary_text = ( count == 1 )
|
|
? tr( "Once removed, continuing the transfer will require the torrent file or magnet link." )
|
|
: tr( "Once removed, continuing the transfers will require the torrent files or magnet links." );
|
|
}
|
|
else if( count == incomplete )
|
|
{
|
|
secondary_text = ( count == 1 )
|
|
? tr( "This torrent has not finished downloading." )
|
|
: tr( "These torrents have not finished downloading." );
|
|
}
|
|
else if( count == connected )
|
|
{
|
|
secondary_text = ( count == 1 )
|
|
? tr( "This torrent is connected to peers." )
|
|
: tr( "These torrents are connected to peers." );
|
|
}
|
|
else
|
|
{
|
|
if( connected )
|
|
{
|
|
secondary_text = ( connected == 1 )
|
|
? tr( "One of these torrents is connected to peers." )
|
|
: tr( "Some of these torrents are connected to peers." );
|
|
}
|
|
|
|
if( connected && incomplete )
|
|
{
|
|
secondary_text += "\n";
|
|
}
|
|
|
|
if( incomplete )
|
|
{
|
|
secondary_text += ( incomplete == 1 )
|
|
? tr( "One of these torrents has not finished downloading." )
|
|
: tr( "Some of these torrents have not finished downloading." );
|
|
}
|
|
}
|
|
|
|
msgBox.setWindowTitle( QString(" ") );
|
|
msgBox.setText( QString( "<big><b>%1</big></b>" ).arg( primary_text ) );
|
|
msgBox.setInformativeText( secondary_text );
|
|
msgBox.setStandardButtons( QMessageBox::Ok | QMessageBox::Cancel );
|
|
msgBox.setDefaultButton( QMessageBox::Cancel );
|
|
msgBox.setIcon( QMessageBox::Question );
|
|
/* hack needed to keep the dialog from being too narrow */
|
|
QGridLayout* layout = (QGridLayout*)msgBox.layout();
|
|
QSpacerItem* spacer = new QSpacerItem( 450, 0, QSizePolicy::Minimum, QSizePolicy::Expanding );
|
|
layout->addItem( spacer, layout->rowCount(), 0, 1, layout->columnCount() );
|
|
|
|
if( msgBox.exec() == QMessageBox::Ok )
|
|
{
|
|
ui.listView->selectionModel()->clear();
|
|
mySession.removeTorrents( ids, deleteFiles );
|
|
}
|
|
}
|
|
|
|
/***
|
|
****
|
|
***/
|
|
|
|
void
|
|
TrMainWindow :: updateNetworkIcon( )
|
|
{
|
|
const time_t now = time( NULL );
|
|
const int period = 3;
|
|
const bool isSending = now - myLastSendTime <= period;
|
|
const bool isReading = now - myLastReadTime <= period;
|
|
const char * key;
|
|
|
|
if( isSending && isReading )
|
|
key = "network-transmit-receive";
|
|
else if( isSending )
|
|
key = "network-transmit";
|
|
else if( isReading )
|
|
key = "network-receive";
|
|
else
|
|
key = "network-idle";
|
|
|
|
QIcon icon = getStockIcon( key, QStyle::SP_DriveNetIcon );
|
|
QPixmap pixmap = icon.pixmap ( 16, 16 );
|
|
myNetworkLabel->setPixmap( pixmap );
|
|
myNetworkLabel->setToolTip( isSending || isReading
|
|
? tr( "Transmission server is responding" )
|
|
: tr( "Last response from server was %1 ago" ).arg( Formatter::timeToString( now-std::max(myLastReadTime,myLastSendTime))));
|
|
}
|
|
|
|
void
|
|
TrMainWindow :: onNetworkTimer( )
|
|
{
|
|
updateNetworkIcon( );
|
|
}
|
|
|
|
void
|
|
TrMainWindow :: dataReadProgress( )
|
|
{
|
|
myLastReadTime = time( NULL );
|
|
updateNetworkIcon( );
|
|
}
|
|
|
|
void
|
|
TrMainWindow :: dataSendProgress( )
|
|
{
|
|
myLastSendTime = time( NULL );
|
|
updateNetworkIcon( );
|
|
}
|
|
|
|
void
|
|
TrMainWindow :: wrongAuthentication( )
|
|
{
|
|
mySession.stop( );
|
|
mySessionDialog->show( );
|
|
}
|
|
|
|
/***
|
|
****
|
|
***/
|
|
|
|
void
|
|
TrMainWindow :: dragEnterEvent( QDragEnterEvent * event )
|
|
{
|
|
const QMimeData * mime = event->mimeData( );
|
|
|
|
if( mime->hasFormat("application/x-bittorrent")
|
|
|| mime->text().trimmed().endsWith(".torrent", Qt::CaseInsensitive) )
|
|
event->acceptProposedAction();
|
|
}
|
|
|
|
void
|
|
TrMainWindow :: dropEvent( QDropEvent * event )
|
|
{
|
|
QString key = event->mimeData()->text().trimmed();
|
|
|
|
const QUrl url( key );
|
|
if( url.scheme() == "file" )
|
|
key = QUrl::fromPercentEncoding( url.path().toUtf8( ) );
|
|
|
|
dynamic_cast<MyApp*>(QApplication::instance())->addTorrent( key );
|
|
}
|