2 * This file Copyright (C) Mnemosyne LLC
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2
6 * as published by the Free Software Foundation.
8 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
10 * $Id: mainwin.cc 12557 2011-07-19 21:19:18Z jordan $
18 #include <libtransmission/transmission.h>
19 #include <libtransmission/utils.h>
20 #include <libtransmission/version.h>
26 #include "filterbar.h"
28 #include "formatter.h"
31 #include "make-dialog.h"
34 #include "prefs-dialog.h"
37 #include "session-dialog.h"
39 #include "stats-dialog.h"
40 #include "torrent-delegate.h"
41 #include "torrent-delegate-min.h"
42 #include "torrent-filter.h"
43 #include "torrent-model.h"
44 #include "triconpushbutton.h"
45 #include "ui_mainwin.h"
47 #define PREFS_KEY "prefs-key";
50 TrMainWindow :: getStockIcon( const QString
& name
, int fallback
)
52 QIcon icon
= QIcon::fromTheme( name
);
54 if( icon
.isNull( ) && ( fallback
>= 0 ) )
55 icon
= style()->standardIcon( QStyle::StandardPixmap( fallback
), 0, this );
62 QSize
calculateTextButtonSizeHint( QPushButton
* button
)
64 QStyleOptionButton opt
;
65 opt
.initFrom( button
);
66 QString
s( button
->text( ) );
68 s
= QString::fromLatin1( "XXXX" );
69 QFontMetrics fm
= button
->fontMetrics( );
70 QSize sz
= fm
.size( Qt::TextShowMnemonic
, s
);
71 return button
->style()->sizeFromContents( QStyle::CT_PushButton
, &opt
, sz
, button
).expandedTo( QApplication::globalStrut( ) );
76 TrMainWindow :: TrMainWindow( Session
& session
, Prefs
& prefs
, TorrentModel
& model
, bool minimized
):
77 myLastFullUpdateTime( 0 ),
78 mySessionDialog( new SessionDialog( session
, prefs
, this ) ),
80 myAboutDialog( new AboutDialog( this ) ),
81 myStatsDialog( new StatsDialog( session
, this ) ),
83 myFilterModel( prefs
),
84 myTorrentDelegate( new TorrentDelegate( this ) ),
85 myTorrentDelegateMin( new TorrentDelegateMin( this ) ),
89 mySpeedModeOffIcon( ":/icons/alt-limit-off.png" ),
90 mySpeedModeOnIcon( ":/icons/alt-limit-on.png" ),
93 myNetworkTimer( this ),
94 myRefreshTrayIconTimer( this ),
95 myRefreshActionSensitivityTimer( this )
97 setAcceptDrops( true );
99 QAction
* sep
= new QAction( this );
100 sep
->setSeparator( true );
104 QStyle
* style
= this->style();
106 int i
= style
->pixelMetric( QStyle::PM_SmallIconSize
, 0, this );
107 const QSize
smallIconSize( i
, i
);
110 ui
.action_OpenFile
->setIcon( getStockIcon( "folder-open", QStyle::SP_DialogOpenButton
) );
111 ui
.action_New
->setIcon( getStockIcon( "document-new", QStyle::SP_DesktopIcon
) );
112 ui
.action_Properties
->setIcon( getStockIcon( "document-properties", QStyle::SP_DesktopIcon
) );
113 ui
.action_OpenFolder
->setIcon( getStockIcon( "folder-open", QStyle::SP_DirOpenIcon
) );
114 ui
.action_Start
->setIcon( getStockIcon( "media-playback-start", QStyle::SP_MediaPlay
) );
115 ui
.action_Announce
->setIcon( getStockIcon( "network-transmit-receive" ) );
116 ui
.action_Pause
->setIcon( getStockIcon( "media-playback-pause", QStyle::SP_MediaPause
) );
117 ui
.action_Remove
->setIcon( getStockIcon( "list-remove", QStyle::SP_TrashIcon
) );
118 ui
.action_Delete
->setIcon( getStockIcon( "edit-delete", QStyle::SP_TrashIcon
) );
119 ui
.action_StartAll
->setIcon( getStockIcon( "media-playback-start", QStyle::SP_MediaPlay
) );
120 ui
.action_PauseAll
->setIcon( getStockIcon( "media-playback-pause", QStyle::SP_MediaPause
) );
121 ui
.action_Quit
->setIcon( getStockIcon( "application-exit" ) );
122 ui
.action_SelectAll
->setIcon( getStockIcon( "edit-select-all" ) );
123 ui
.action_ReverseSortOrder
->setIcon( getStockIcon( "view-sort-ascending", QStyle::SP_ArrowDown
) );
124 ui
.action_Preferences
->setIcon( getStockIcon( "preferences-system" ) );
125 ui
.action_Contents
->setIcon( getStockIcon( "help-contents", QStyle::SP_DialogHelpButton
) );
126 ui
.action_About
->setIcon( getStockIcon( "help-about" ) );
129 connect( ui
.action_Toolbar
, SIGNAL(toggled(bool)), this, SLOT(setToolbarVisible(bool)));
130 connect( ui
.action_Filterbar
, SIGNAL(toggled(bool)), this, SLOT(setFilterbarVisible(bool)));
131 connect( ui
.action_Statusbar
, SIGNAL(toggled(bool)), this, SLOT(setStatusbarVisible(bool)));
132 connect( ui
.action_CompactView
, SIGNAL(toggled(bool)), this, SLOT(setCompactView(bool)));
133 connect( ui
.action_SortByActivity
, SIGNAL(toggled(bool)), this, SLOT(onSortByActivityToggled(bool)));
134 connect( ui
.action_SortByAge
, SIGNAL(toggled(bool)), this, SLOT(onSortByAgeToggled(bool)));
135 connect( ui
.action_SortByETA
, SIGNAL(toggled(bool)), this, SLOT(onSortByETAToggled(bool)));
136 connect( ui
.action_SortByName
, SIGNAL(toggled(bool)), this, SLOT(onSortByNameToggled(bool)));
137 connect( ui
.action_SortByProgress
, SIGNAL(toggled(bool)), this, SLOT(onSortByProgressToggled(bool)));
138 connect( ui
.action_SortByRatio
, SIGNAL(toggled(bool)), this, SLOT(onSortByRatioToggled(bool)));
139 connect( ui
.action_SortBySize
, SIGNAL(toggled(bool)), this, SLOT(onSortBySizeToggled(bool)));
140 connect( ui
.action_SortByState
, SIGNAL(toggled(bool)), this, SLOT(onSortByStateToggled(bool)));
141 connect( ui
.action_ReverseSortOrder
, SIGNAL(toggled(bool)), this, SLOT(setSortAscendingPref(bool)));
142 connect( ui
.action_Start
, SIGNAL(triggered()), this, SLOT(startSelected()));
143 connect( ui
.action_Pause
, SIGNAL(triggered()), this, SLOT(pauseSelected()));
144 connect( ui
.action_Remove
, SIGNAL(triggered()), this, SLOT(removeSelected()));
145 connect( ui
.action_Delete
, SIGNAL(triggered()), this, SLOT(deleteSelected()));
146 connect( ui
.action_Verify
, SIGNAL(triggered()), this, SLOT(verifySelected()) );
147 connect( ui
.action_Announce
, SIGNAL(triggered()), this, SLOT(reannounceSelected()) );
148 connect( ui
.action_StartAll
, SIGNAL(triggered()), this, SLOT(startAll()));
149 connect( ui
.action_PauseAll
, SIGNAL(triggered()), this, SLOT(pauseAll()));
150 connect( ui
.action_OpenFile
, SIGNAL(triggered()), this, SLOT(openTorrent()));
151 connect( ui
.action_AddURL
, SIGNAL(triggered()), this, SLOT(openURL()));
152 connect( ui
.action_New
, SIGNAL(triggered()), this, SLOT(newTorrent()));
153 connect( ui
.action_Preferences
, SIGNAL(triggered()), this, SLOT(openPreferences()));
154 connect( ui
.action_Statistics
, SIGNAL(triggered()), myStatsDialog
, SLOT(show()));
155 connect( ui
.action_Donate
, SIGNAL(triggered()), this, SLOT(openDonate()));
156 connect( ui
.action_About
, SIGNAL(triggered()), myAboutDialog
, SLOT(show()));
157 connect( ui
.action_Contents
, SIGNAL(triggered()), this, SLOT(openHelp()));
158 connect( ui
.action_OpenFolder
, SIGNAL(triggered()), this, SLOT(openFolder()));
159 connect( ui
.action_CopyMagnetToClipboard
, SIGNAL(triggered()), this, SLOT(copyMagnetLinkToClipboard()));
160 connect( ui
.action_SetLocation
, SIGNAL(triggered()), this, SLOT(setLocation()));
161 connect( ui
.action_Properties
, SIGNAL(triggered()), this, SLOT(openProperties()));
162 connect( ui
.action_SessionDialog
, SIGNAL(triggered()), mySessionDialog
, SLOT(show()));
163 connect( ui
.listView
, SIGNAL(activated(const QModelIndex
&)), ui
.action_Properties
, SLOT(trigger()));
165 QAction
* sep2
= new QAction( this );
166 sep2
->setSeparator( true );
167 QAction
* sep3
= new QAction( this );
168 sep3
->setSeparator( true );
171 QList
<QAction
*> actions
;
172 actions
<< ui
.action_Properties
173 << ui
.action_OpenFolder
176 << ui
.action_Announce
178 << ui
.action_CopyMagnetToClipboard
181 << ui
.action_SetLocation
185 addActions( actions
);
186 setContextMenuPolicy( Qt::ActionsContextMenu
);
189 connect( ui
.action_SelectAll
, SIGNAL(triggered()), ui
.listView
, SLOT(selectAll()));
190 connect( ui
.action_DeselectAll
, SIGNAL(triggered()), ui
.listView
, SLOT(clearSelection()));
192 connect( &myFilterModel
, SIGNAL(rowsInserted(const QModelIndex
&,int,int)), this, SLOT(refreshVisibleCount()));
193 connect( &myFilterModel
, SIGNAL(rowsRemoved(const QModelIndex
&,int,int)), this, SLOT(refreshVisibleCount()));
194 connect( &myFilterModel
, SIGNAL(rowsInserted(const QModelIndex
&,int,int)), this, SLOT(refreshActionSensitivitySoon()));
195 connect( &myFilterModel
, SIGNAL(rowsRemoved(const QModelIndex
&,int,int)), this, SLOT(refreshActionSensitivitySoon()));
197 connect( ui
.action_Quit
, SIGNAL(triggered()), QCoreApplication::instance(), SLOT(quit()) );
200 myFilterModel
.setSourceModel( &myModel
);
201 connect( &myModel
, SIGNAL(modelReset()), this, SLOT(onModelReset()));
202 connect( &myModel
, SIGNAL(rowsRemoved(const QModelIndex
&,int,int)), this, SLOT(onModelReset()));
203 connect( &myModel
, SIGNAL(rowsInserted(const QModelIndex
&,int,int)), this, SLOT(onModelReset()));
204 connect( &myModel
, SIGNAL(dataChanged(const QModelIndex
&,const QModelIndex
&)), this, SLOT(refreshTrayIconSoon()));
206 ui
.listView
->setModel( &myFilterModel
);
207 connect( ui
.listView
->selectionModel(), SIGNAL(selectionChanged(const QItemSelection
&,const QItemSelection
&)), this, SLOT(refreshActionSensitivitySoon()));
209 QActionGroup
* actionGroup
= new QActionGroup( this );
210 actionGroup
->addAction( ui
.action_SortByActivity
);
211 actionGroup
->addAction( ui
.action_SortByAge
);
212 actionGroup
->addAction( ui
.action_SortByETA
);
213 actionGroup
->addAction( ui
.action_SortByName
);
214 actionGroup
->addAction( ui
.action_SortByProgress
);
215 actionGroup
->addAction( ui
.action_SortByRatio
);
216 actionGroup
->addAction( ui
.action_SortBySize
);
217 actionGroup
->addAction( ui
.action_SortByState
);
219 QMenu
* menu
= new QMenu( );
220 menu
->addAction( ui
.action_OpenFile
);
221 menu
->addAction( ui
.action_AddURL
);
222 menu
->addSeparator( );
223 menu
->addAction( ui
.action_ShowMainWindow
);
224 menu
->addAction( ui
.action_ShowMessageLog
);
225 menu
->addAction( ui
.action_About
);
226 menu
->addSeparator( );
227 menu
->addAction( ui
.action_StartAll
);
228 menu
->addAction( ui
.action_PauseAll
);
229 menu
->addSeparator( );
230 menu
->addAction( ui
.action_Quit
);
231 myTrayIcon
.setContextMenu( menu
);
232 myTrayIcon
.setIcon( QApplication::windowIcon( ) );
234 connect( &myPrefs
, SIGNAL(changed(int)), this, SLOT(refreshPref(int)) );
235 connect( ui
.action_ShowMainWindow
, SIGNAL(toggled(bool)), this, SLOT(toggleWindows(bool)));
236 connect( &myTrayIcon
, SIGNAL(activated(QSystemTrayIcon::ActivationReason
)),
237 this, SLOT(trayActivated(QSystemTrayIcon::ActivationReason
)));
239 ui
.action_ShowMainWindow
->setChecked( !minimized
);
240 ui
.action_TrayIcon
->setChecked( minimized
|| prefs
.getBool( Prefs::SHOW_TRAY_ICON
) );
242 ui
.verticalLayout
->addWidget( createStatusBar( ) );
243 ui
.verticalLayout
->insertWidget( 0, myFilterBar
= new FilterBar( myPrefs
, myModel
, myFilterModel
) );
246 initKeys
<< Prefs :: MAIN_WINDOW_X
247 << Prefs :: SHOW_TRAY_ICON
248 << Prefs :: SORT_REVERSED
249 << Prefs :: SORT_MODE
250 << Prefs :: FILTERBAR
251 << Prefs :: STATUSBAR
252 << Prefs :: STATUSBAR_STATS
254 << Prefs :: ALT_SPEED_LIMIT_ENABLED
255 << Prefs :: COMPACT_VIEW
257 << Prefs :: DSPEED_ENABLED
259 << Prefs :: USPEED_ENABLED
261 << Prefs :: RATIO_ENABLED
;
262 foreach( int key
, initKeys
)
265 connect( &mySession
, SIGNAL(sourceChanged()), this, SLOT(onSessionSourceChanged()) );
266 connect( &mySession
, SIGNAL(statsUpdated()), this, SLOT(refreshStatusBar()) );
267 connect( &mySession
, SIGNAL(dataReadProgress()), this, SLOT(dataReadProgress()) );
268 connect( &mySession
, SIGNAL(dataSendProgress()), this, SLOT(dataSendProgress()) );
269 connect( &mySession
, SIGNAL(httpAuthenticationRequired()), this, SLOT(wrongAuthentication()) );
271 if( mySession
.isServer( ) )
272 myNetworkLabel
->hide( );
274 connect( &myNetworkTimer
, SIGNAL(timeout()), this, SLOT(onNetworkTimer()));
275 myNetworkTimer
.start( 1000 );
278 connect( &myRefreshTrayIconTimer
, SIGNAL(timeout()), this, SLOT(refreshTrayIcon()) );
279 connect( &myRefreshActionSensitivityTimer
, SIGNAL(timeout()), this, SLOT(refreshActionSensitivity()) );
282 refreshActionSensitivitySoon( );
283 refreshTrayIconSoon( );
286 refreshVisibleCount( );
289 TrMainWindow :: ~TrMainWindow( )
298 TrMainWindow :: closeEvent( QCloseEvent
* event
)
300 // if they're using a tray icon, close to the tray
301 // instead of exiting
302 if( !myPrefs
.getBool( Prefs :: SHOW_TRAY_ICON
) )
305 toggleWindows( false );
315 TrMainWindow :: onSessionSourceChanged( )
321 TrMainWindow :: onModelReset( )
324 refreshVisibleCount( );
325 refreshActionSensitivitySoon( );
327 refreshTrayIconSoon( );
334 #define PREF_VARIANTS_KEY "pref-variants-list"
337 TrMainWindow :: onSetPrefs( )
339 const QVariantList p
= sender()->property( PREF_VARIANTS_KEY
).toList( );
340 assert( ( p
.size( ) % 2 ) == 0 );
341 for( int i
=0, n
=p
.size(); i
<n
; i
+=2 )
342 myPrefs
.set( p
[i
].toInt(), p
[i
+1] );
346 TrMainWindow :: onSetPrefs( bool isChecked
)
352 #define SHOW_KEY "show-mode"
355 TrMainWindow :: createStatusBar( )
362 const int i
= style( )->pixelMetric( QStyle::PM_SmallIconSize
, 0, this );
363 const QSize
smallIconSize( i
, i
);
365 QWidget
* top
= myStatusBar
= new QWidget
;
366 h
= new QHBoxLayout( top
);
367 h
->setContentsMargins( HIG::PAD_SMALL
, HIG::PAD_SMALL
, HIG::PAD_SMALL
, HIG::PAD_SMALL
);
368 h
->setSpacing( HIG::PAD_SMALL
);
370 p
= myOptionsButton
= new TrIconPushButton( this );
371 p
->setIcon( QIcon( ":/icons/utilities.png" ) );
372 p
->setIconSize( QPixmap( ":/icons/utilities.png" ).size() );
374 p
->setMenu( createOptionsMenu( ) );
377 p
= myAltSpeedButton
= new QPushButton( this );
378 p
->setIcon( myPrefs
.get
<bool>(Prefs::ALT_SPEED_LIMIT_ENABLED
) ? mySpeedModeOnIcon
: mySpeedModeOffIcon
);
379 p
->setIconSize( QPixmap( ":/icons/alt-limit-on.png" ).size() );
380 p
->setCheckable( true );
381 p
->setFixedWidth( p
->height() );
384 connect( p
, SIGNAL(clicked()), this, SLOT(toggleSpeedMode()));
386 l
= myNetworkLabel
= new QLabel
;
391 l
= myVisibleCountLabel
= new QLabel( this );
396 a
= new QActionGroup( this );
397 a
->addAction( ui
.action_TotalRatio
);
398 a
->addAction( ui
.action_TotalTransfer
);
399 a
->addAction( ui
.action_SessionRatio
);
400 a
->addAction( ui
.action_SessionTransfer
);
402 m
->addAction( ui
.action_TotalRatio
);
403 m
->addAction( ui
.action_TotalTransfer
);
404 m
->addAction( ui
.action_SessionRatio
);
405 m
->addAction( ui
.action_SessionTransfer
);
406 connect( ui
.action_TotalRatio
, SIGNAL(triggered()), this, SLOT(showTotalRatio()));
407 connect( ui
.action_TotalTransfer
, SIGNAL(triggered()), this, SLOT(showTotalTransfer()));
408 connect( ui
.action_SessionRatio
, SIGNAL(triggered()), this, SLOT(showSessionRatio()));
409 connect( ui
.action_SessionTransfer
, SIGNAL(triggered()), this, SLOT(showSessionTransfer()));
410 p
= myStatsModeButton
= new TrIconPushButton( this );
411 p
->setIcon( QIcon( ":/icons/ratio.png" ) );
412 p
->setIconSize( QPixmap( ":/icons/ratio.png" ).size() );
416 l
= myStatsLabel
= new QLabel( this );
421 l
= myDownloadSpeedLabel
= new QLabel( this );
422 const int minimumSpeedWidth
= l
->fontMetrics().width( Formatter::speedToString(Speed::fromKBps(999.99)));
423 l
->setMinimumWidth( minimumSpeedWidth
);
424 l
->setAlignment( Qt::AlignRight
|Qt::AlignVCenter
);
426 l
= new QLabel( this );
427 l
->setPixmap( getStockIcon( "go-down", QStyle::SP_ArrowDown
).pixmap( smallIconSize
) );
432 l
= myUploadSpeedLabel
= new QLabel
;
433 l
->setMinimumWidth( minimumSpeedWidth
);
434 l
->setAlignment( Qt::AlignRight
|Qt::AlignVCenter
);
437 l
->setPixmap( getStockIcon( "go-up", QStyle::SP_ArrowUp
).pixmap( smallIconSize
) );
444 TrMainWindow :: createOptionsMenu( )
451 QList
<int> stockSpeeds
;
452 stockSpeeds
<< 5 << 10 << 20 << 30 << 40 << 50 << 75 << 100 << 150 << 200 << 250 << 500 << 750;
453 QList
<double> stockRatios
;
454 stockRatios
<< 0.25 << 0.50 << 0.75 << 1 << 1.5 << 2 << 3;
457 sub
= menu
->addMenu( tr( "Limit Download Speed" ) );
458 int currentVal
= myPrefs
.get
<int>( Prefs::DSPEED
);
459 g
= new QActionGroup( this );
460 a
= myDlimitOffAction
= sub
->addAction( tr( "Unlimited" ) );
461 a
->setCheckable( true );
462 a
->setProperty( PREF_VARIANTS_KEY
, QVariantList() << Prefs::DSPEED_ENABLED
<< false );
464 connect( a
, SIGNAL(triggered(bool)), this, SLOT(onSetPrefs(bool)) );
465 a
= myDlimitOnAction
= sub
->addAction( tr( "Limited at %1" ).arg( Formatter::speedToString( Speed::fromKBps( currentVal
) ) ) );
466 a
->setCheckable( true );
467 a
->setProperty( PREF_VARIANTS_KEY
, QVariantList() << Prefs::DSPEED
<< currentVal
<< Prefs::DSPEED_ENABLED
<< true );
469 connect( a
, SIGNAL(triggered(bool)), this, SLOT(onSetPrefs(bool)) );
470 sub
->addSeparator( );
471 foreach( int i
, stockSpeeds
) {
472 a
= sub
->addAction( Formatter::speedToString( Speed::fromKBps( i
) ) );
473 a
->setProperty( PREF_VARIANTS_KEY
, QVariantList() << Prefs::DSPEED
<< i
<< Prefs::DSPEED_ENABLED
<< true );
474 connect( a
, SIGNAL(triggered(bool)), this, SLOT(onSetPrefs()));
477 sub
= menu
->addMenu( tr( "Limit Upload Speed" ) );
478 currentVal
= myPrefs
.get
<int>( Prefs::USPEED
);
479 g
= new QActionGroup( this );
480 a
= myUlimitOffAction
= sub
->addAction( tr( "Unlimited" ) );
481 a
->setCheckable( true );
482 a
->setProperty( PREF_VARIANTS_KEY
, QVariantList() << Prefs::USPEED_ENABLED
<< false );
484 connect( a
, SIGNAL(triggered(bool)), this, SLOT(onSetPrefs(bool)) );
485 a
= myUlimitOnAction
= sub
->addAction( tr( "Limited at %1" ).arg( Formatter::speedToString( Speed::fromKBps( currentVal
) ) ) );
486 a
->setCheckable( true );
487 a
->setProperty( PREF_VARIANTS_KEY
, QVariantList() << Prefs::USPEED
<< currentVal
<< Prefs::USPEED_ENABLED
<< true );
489 connect( a
, SIGNAL(triggered(bool)), this, SLOT(onSetPrefs(bool)) );
490 sub
->addSeparator( );
491 foreach( int i
, stockSpeeds
) {
492 a
= sub
->addAction( Formatter::speedToString( Speed::fromKBps( i
) ) );
493 a
->setProperty( PREF_VARIANTS_KEY
, QVariantList() << Prefs::USPEED
<< i
<< Prefs::USPEED_ENABLED
<< true );
494 connect( a
, SIGNAL(triggered(bool)), this, SLOT(onSetPrefs()));
497 menu
->addSeparator( );
498 sub
= menu
->addMenu( tr( "Stop Seeding at Ratio" ) );
500 double d
= myPrefs
.get
<double>( Prefs::RATIO
);
501 g
= new QActionGroup( this );
502 a
= myRatioOffAction
= sub
->addAction( tr( "Seed Forever" ) );
503 a
->setCheckable( true );
504 a
->setProperty( PREF_VARIANTS_KEY
, QVariantList() << Prefs::RATIO_ENABLED
<< false );
506 connect( a
, SIGNAL(triggered(bool)), this, SLOT(onSetPrefs(bool)) );
507 a
= myRatioOnAction
= sub
->addAction( tr( "Stop at Ratio (%1)" ).arg( Formatter::ratioToString( d
) ) );
508 a
->setCheckable( true );
509 a
->setProperty( PREF_VARIANTS_KEY
, QVariantList() << Prefs::RATIO
<< d
<< Prefs::RATIO_ENABLED
<< true );
511 connect( a
, SIGNAL(triggered(bool)), this, SLOT(onSetPrefs(bool)) );
512 sub
->addSeparator( );
513 foreach( double i
, stockRatios
) {
514 a
= sub
->addAction( Formatter::ratioToString( i
) );
515 a
->setProperty( PREF_VARIANTS_KEY
, QVariantList() << Prefs::RATIO
<< i
<< Prefs::RATIO_ENABLED
<< true );
516 connect( a
, SIGNAL(triggered(bool)), this, SLOT(onSetPrefs()));
527 TrMainWindow :: setSortPref( int i
)
529 myPrefs
.set( Prefs::SORT_MODE
, SortMode( i
) );
531 void TrMainWindow :: onSortByActivityToggled ( bool b
) { if( b
) setSortPref( SortMode::SORT_BY_ACTIVITY
); }
532 void TrMainWindow :: onSortByAgeToggled ( bool b
) { if( b
) setSortPref( SortMode::SORT_BY_AGE
); }
533 void TrMainWindow :: onSortByETAToggled ( bool b
) { if( b
) setSortPref( SortMode::SORT_BY_ETA
); }
534 void TrMainWindow :: onSortByNameToggled ( bool b
) { if( b
) setSortPref( SortMode::SORT_BY_NAME
); }
535 void TrMainWindow :: onSortByProgressToggled ( bool b
) { if( b
) setSortPref( SortMode::SORT_BY_PROGRESS
); }
536 void TrMainWindow :: onSortByRatioToggled ( bool b
) { if( b
) setSortPref( SortMode::SORT_BY_RATIO
); }
537 void TrMainWindow :: onSortBySizeToggled ( bool b
) { if( b
) setSortPref( SortMode::SORT_BY_SIZE
); }
538 void TrMainWindow :: onSortByStateToggled ( bool b
) { if( b
) setSortPref( SortMode::SORT_BY_STATE
); }
541 TrMainWindow :: setSortAscendingPref( bool b
)
543 myPrefs
.set( Prefs::SORT_REVERSED
, b
);
551 TrMainWindow :: onPrefsDestroyed( )
557 TrMainWindow :: openPreferences( )
559 if( myPrefsDialog
== 0 ) {
560 myPrefsDialog
= new PrefsDialog( mySession
, myPrefs
, this );
561 connect( myPrefsDialog
, SIGNAL(destroyed(QObject
*)), this, SLOT(onPrefsDestroyed()));
564 myPrefsDialog
->show( );
568 TrMainWindow :: onDetailsDestroyed( )
574 TrMainWindow :: openProperties( )
576 if( myDetailsDialog
== 0 ) {
577 myDetailsDialog
= new Details( mySession
, myPrefs
, myModel
, this );
578 connect( myDetailsDialog
, SIGNAL(destroyed(QObject
*)), this, SLOT(onDetailsDestroyed()));
581 myDetailsDialog
->setIds( getSelectedTorrents( ) );
582 myDetailsDialog
->show( );
586 TrMainWindow :: setLocation( )
588 QDialog
* d
= new RelocateDialog( mySession
, myModel
, getSelectedTorrents(), this );
593 TrMainWindow :: openFolder( )
595 const int torrentId( *getSelectedTorrents().begin() );
596 const Torrent
* tor( myModel
.getTorrentFromId( torrentId
) );
597 const QString
path( tor
->getPath( ) );
598 QDesktopServices :: openUrl( QUrl::fromLocalFile( path
) );
602 TrMainWindow :: copyMagnetLinkToClipboard( )
604 const int id( *getSelectedTorrents().begin() );
605 mySession
.copyMagnetLinkToClipboard( id
);
609 TrMainWindow :: openDonate( )
611 QDesktopServices :: openUrl( QUrl( "http://www.transmissionbt.com/donate.php" ) );
615 TrMainWindow :: openHelp( )
617 const char * fmt
= "http://www.transmissionbt.com/help/gtk/%d.%dx";
619 sscanf( SHORT_VERSION_STRING
, "%d.%d", &major
, &minor
);
621 tr_snprintf( url
, sizeof( url
), fmt
, major
, minor
/10 );
622 QDesktopServices :: openUrl( QUrl( url
) );
626 TrMainWindow :: refreshTitle( )
628 QString
title( "Transmission" );
629 const QUrl
url( mySession
.getRemoteUrl( ) );
631 title
+= tr( " - %1:%2" ).arg( url
.host() ).arg( url
.port() );
632 setWindowTitle( title
);
636 TrMainWindow :: refreshVisibleCount( )
638 const int visibleCount( myFilterModel
.rowCount( ) );
639 const int totalCount( visibleCount
+ myFilterModel
.hiddenRowCount( ) );
641 if( visibleCount
== totalCount
)
642 str
= tr( "%Ln Torrent(s)", 0, totalCount
);
644 str
= tr( "%L1 of %Ln Torrent(s)", 0, totalCount
).arg( visibleCount
);
645 myVisibleCountLabel
->setText( str
);
646 myVisibleCountLabel
->setVisible( totalCount
> 0 );
650 TrMainWindow :: refreshTrayIconSoon( )
652 if( !myRefreshTrayIconTimer
.isActive( ) )
654 myRefreshTrayIconTimer
.setSingleShot( true );
655 myRefreshTrayIconTimer
.start( 500 );
659 TrMainWindow :: refreshTrayIcon( )
662 const QString idle
= tr( "Idle" );
664 foreach( int id
, myModel
.getIds( ) ) {
665 const Torrent
* tor
= myModel
.getTorrentFromId( id
);
666 u
+= tor
->uploadSpeed( );
667 d
+= tor
->downloadSpeed( );
670 myTrayIcon
.setToolTip( tr( "Transmission\nUp: %1\nDown: %2" )
671 .arg( u
.isZero() ? idle
: Formatter::speedToString( u
) )
672 .arg( d
.isZero() ? idle
: Formatter::speedToString( d
) ) );
676 TrMainWindow :: refreshStatusBar( )
678 const Speed
up( myModel
.getUploadSpeed( ) );
679 const Speed
down( myModel
.getDownloadSpeed( ) );
680 myUploadSpeedLabel
->setText( Formatter:: speedToString( up
) );
681 myDownloadSpeedLabel
->setText( Formatter:: speedToString( down
) );
683 myNetworkLabel
->setVisible( !mySession
.isServer( ) );
685 const QString
mode( myPrefs
.getString( Prefs::STATUSBAR_STATS
) );
688 if( mode
== "session-ratio" )
690 str
= tr( "Ratio: %1" ).arg( Formatter:: ratioToString( mySession
.getStats().ratio
) );
692 else if( mode
== "session-transfer" )
694 const tr_session_stats
& stats( mySession
.getStats( ) );
695 str
= tr( "Down: %1, Up: %2" ).arg( Formatter:: sizeToString( stats
.downloadedBytes
) )
696 .arg( Formatter:: sizeToString( stats
.uploadedBytes
) );
698 else if( mode
== "total-transfer" )
700 const tr_session_stats
& stats( mySession
.getCumulativeStats( ) );
701 str
= tr( "Down: %1, Up: %2" ).arg( Formatter:: sizeToString( stats
.downloadedBytes
) )
702 .arg( Formatter:: sizeToString( stats
.uploadedBytes
) );
704 else // default is "total-ratio"
706 str
= tr( "Ratio: %1" ).arg( Formatter:: ratioToString( mySession
.getCumulativeStats().ratio
) );
709 myStatsLabel
->setText( str
);
715 TrMainWindow :: refreshActionSensitivitySoon( )
717 if( !myRefreshActionSensitivityTimer
.isActive( ) )
719 myRefreshActionSensitivityTimer
.setSingleShot( true );
720 myRefreshActionSensitivityTimer
.start( 500 );
724 TrMainWindow :: refreshActionSensitivity( )
728 int selectedAndPaused( 0 );
729 int canAnnounce( 0 );
730 const QAbstractItemModel
* model( ui
.listView
->model( ) );
731 const QItemSelectionModel
* selectionModel( ui
.listView
->selectionModel( ) );
732 const int rowCount( model
->rowCount( ) );
734 // count how many torrents are selected, paused, etc
735 for( int row
=0; row
<rowCount
; ++row
) {
736 const QModelIndex
modelIndex( model
->index( row
, 0 ) );
737 assert( model
== modelIndex
.model( ) );
738 const Torrent
* tor( model
->data( modelIndex
, TorrentModel::TorrentRole
).value
<const Torrent
*>( ) );
740 const bool isSelected( selectionModel
->isSelected( modelIndex
) );
741 const bool isPaused( tor
->isPaused( ) );
746 if( isSelected
&& isPaused
)
748 if( tor
->canManualAnnounce( ) )
753 const bool haveSelection( selected
> 0 );
754 ui
.action_Verify
->setEnabled( haveSelection
);
755 ui
.action_Remove
->setEnabled( haveSelection
);
756 ui
.action_Delete
->setEnabled( haveSelection
);
757 ui
.action_Properties
->setEnabled( haveSelection
);
758 ui
.action_DeselectAll
->setEnabled( haveSelection
);
759 ui
.action_SetLocation
->setEnabled( haveSelection
);
761 const bool oneSelection( selected
== 1 );
762 ui
.action_OpenFolder
->setEnabled( oneSelection
&& mySession
.isLocal( ) );
763 ui
.action_CopyMagnetToClipboard
->setEnabled( oneSelection
);
765 ui
.action_SelectAll
->setEnabled( selected
< rowCount
);
766 ui
.action_StartAll
->setEnabled( paused
> 0 );
767 ui
.action_PauseAll
->setEnabled( paused
< rowCount
);
768 ui
.action_Start
->setEnabled( selectedAndPaused
> 0 );
769 ui
.action_Pause
->setEnabled( selectedAndPaused
< selected
);
770 ui
.action_Announce
->setEnabled( selected
> 0 && ( canAnnounce
== selected
) );
772 if( myDetailsDialog
)
773 myDetailsDialog
->setIds( getSelectedTorrents( ) );
781 TrMainWindow :: clearSelection( )
783 ui
.action_DeselectAll
->trigger( );
787 TrMainWindow :: getSelectedTorrents( ) const
791 foreach( QModelIndex index
, ui
.listView
->selectionModel( )->selectedRows( ) )
793 const Torrent
* tor( index
.data( TorrentModel::TorrentRole
).value
<const Torrent
*>( ) );
794 ids
.insert( tor
->id( ) );
801 TrMainWindow :: startSelected( )
803 mySession
.startTorrents( getSelectedTorrents( ) );
806 TrMainWindow :: pauseSelected( )
808 mySession
.pauseTorrents( getSelectedTorrents( ) );
811 TrMainWindow :: startAll( )
813 mySession
.startTorrents( );
816 TrMainWindow :: pauseAll( )
818 mySession
.pauseTorrents( );
821 TrMainWindow :: removeSelected( )
823 removeTorrents( false );
826 TrMainWindow :: deleteSelected( )
828 removeTorrents( true );
831 TrMainWindow :: verifySelected( )
833 mySession
.verifyTorrents( getSelectedTorrents( ) );
836 TrMainWindow :: reannounceSelected( )
838 mySession
.reannounceTorrents( getSelectedTorrents( ) );
845 void TrMainWindow :: showTotalRatio ( ) { myPrefs
.set( Prefs::STATUSBAR_STATS
, "total-ratio"); }
846 void TrMainWindow :: showTotalTransfer ( ) { myPrefs
.set( Prefs::STATUSBAR_STATS
, "total-transfer"); }
847 void TrMainWindow :: showSessionRatio ( ) { myPrefs
.set( Prefs::STATUSBAR_STATS
, "session-ratio"); }
848 void TrMainWindow :: showSessionTransfer ( ) { myPrefs
.set( Prefs::STATUSBAR_STATS
, "session-transfer"); }
855 TrMainWindow :: setCompactView( bool visible
)
857 myPrefs
.set( Prefs :: COMPACT_VIEW
, visible
);
860 TrMainWindow :: toggleSpeedMode( )
862 myPrefs
.toggleBool( Prefs :: ALT_SPEED_LIMIT_ENABLED
);
865 TrMainWindow :: setToolbarVisible( bool visible
)
867 myPrefs
.set( Prefs::TOOLBAR
, visible
);
870 TrMainWindow :: setFilterbarVisible( bool visible
)
872 myPrefs
.set( Prefs::FILTERBAR
, visible
);
875 TrMainWindow :: setStatusbarVisible( bool visible
)
877 myPrefs
.set( Prefs::STATUSBAR
, visible
);
885 TrMainWindow :: toggleWindows( bool doShow
)
893 if ( !isVisible( ) ) show( );
894 if ( isMinimized( ) ) showNormal( );
897 QApplication::setActiveWindow( this );
902 TrMainWindow :: trayActivated( QSystemTrayIcon::ActivationReason reason
)
904 if( reason
== QSystemTrayIcon::Trigger
)
906 if( isMinimized ( ) )
907 toggleWindows( true );
909 ui
.action_ShowMainWindow
->toggle( );
915 TrMainWindow :: refreshPref( int key
)
923 case Prefs::STATUSBAR_STATS
:
924 str
= myPrefs
.getString( key
);
925 ui
.action_TotalRatio
->setChecked ( str
== "total-ratio" );
926 ui
.action_TotalTransfer
->setChecked ( str
== "total-transfer" );
927 ui
.action_SessionRatio
->setChecked ( str
== "session-ratio" );
928 ui
.action_SessionTransfer
->setChecked( str
== "session-transfer" );
932 case Prefs::SORT_REVERSED
:
933 ui
.action_ReverseSortOrder
->setChecked( myPrefs
.getBool( key
) );
936 case Prefs::SORT_MODE
:
937 i
= myPrefs
.get
<SortMode
>(key
).mode( );
938 ui
.action_SortByActivity
->setChecked ( i
== SortMode::SORT_BY_ACTIVITY
);
939 ui
.action_SortByAge
->setChecked ( i
== SortMode::SORT_BY_AGE
);
940 ui
.action_SortByETA
->setChecked ( i
== SortMode::SORT_BY_ETA
);
941 ui
.action_SortByName
->setChecked ( i
== SortMode::SORT_BY_NAME
);
942 ui
.action_SortByProgress
->setChecked ( i
== SortMode::SORT_BY_PROGRESS
);
943 ui
.action_SortByRatio
->setChecked ( i
== SortMode::SORT_BY_RATIO
);
944 ui
.action_SortBySize
->setChecked ( i
== SortMode::SORT_BY_SIZE
);
945 ui
.action_SortByState
->setChecked ( i
== SortMode::SORT_BY_STATE
);
948 case Prefs::DSPEED_ENABLED
:
949 (myPrefs
.get
<bool>(key
) ? myDlimitOnAction
: myDlimitOffAction
)->setChecked( true );
953 myDlimitOnAction
->setText( tr( "Limited at %1" ).arg( Formatter::speedToString( Speed::fromKBps( myPrefs
.get
<int>(key
) ) ) ) );
956 case Prefs::USPEED_ENABLED
:
957 (myPrefs
.get
<bool>(key
) ? myUlimitOnAction
: myUlimitOffAction
)->setChecked( true );
961 myUlimitOnAction
->setText( tr( "Limited at %1" ).arg( Formatter::speedToString( Speed::fromKBps( myPrefs
.get
<int>(key
) ) ) ) );
964 case Prefs::RATIO_ENABLED
:
965 (myPrefs
.get
<bool>(key
) ? myRatioOnAction
: myRatioOffAction
)->setChecked( true );
969 myRatioOnAction
->setText( tr( "Stop at Ratio (%1)" ).arg( Formatter::ratioToString( myPrefs
.get
<double>(key
) ) ) );
972 case Prefs::FILTERBAR
:
973 b
= myPrefs
.getBool( key
);
974 myFilterBar
->setVisible( b
);
975 ui
.action_Filterbar
->setChecked( b
);
978 case Prefs::STATUSBAR
:
979 b
= myPrefs
.getBool( key
);
980 myStatusBar
->setVisible( b
);
981 ui
.action_Statusbar
->setChecked( b
);
985 b
= myPrefs
.getBool( key
);
986 ui
.toolBar
->setVisible( b
);
987 ui
.action_Toolbar
->setChecked( b
);
990 case Prefs::SHOW_TRAY_ICON
:
991 b
= myPrefs
.getBool( key
);
992 ui
.action_TrayIcon
->setChecked( b
);
993 myTrayIcon
.setVisible( b
);
994 refreshTrayIconSoon( );
997 case Prefs::COMPACT_VIEW
: {
998 QItemSelectionModel
* selectionModel( ui
.listView
->selectionModel( ) );
999 const QItemSelection
selection( selectionModel
->selection( ) );
1000 const QModelIndex
currentIndex( selectionModel
->currentIndex( ) );
1001 b
= myPrefs
.getBool( key
);
1002 ui
.action_CompactView
->setChecked( b
);
1003 ui
.listView
->setItemDelegate( b
? myTorrentDelegateMin
: myTorrentDelegate
);
1004 selectionModel
->clear( );
1005 ui
.listView
->reset( ); // force the rows to resize
1006 selectionModel
->select( selection
, QItemSelectionModel::Select
);
1007 selectionModel
->setCurrentIndex( currentIndex
, QItemSelectionModel::NoUpdate
);
1011 case Prefs::MAIN_WINDOW_X
:
1012 case Prefs::MAIN_WINDOW_Y
:
1013 case Prefs::MAIN_WINDOW_WIDTH
:
1014 case Prefs::MAIN_WINDOW_HEIGHT
:
1015 setGeometry( myPrefs
.getInt( Prefs::MAIN_WINDOW_X
),
1016 myPrefs
.getInt( Prefs::MAIN_WINDOW_Y
),
1017 myPrefs
.getInt( Prefs::MAIN_WINDOW_WIDTH
),
1018 myPrefs
.getInt( Prefs::MAIN_WINDOW_HEIGHT
) );
1021 case Prefs :: ALT_SPEED_LIMIT_ENABLED
:
1022 case Prefs :: ALT_SPEED_LIMIT_UP
:
1023 case Prefs :: ALT_SPEED_LIMIT_DOWN
: {
1024 b
= myPrefs
.getBool( Prefs :: ALT_SPEED_LIMIT_ENABLED
);
1025 myAltSpeedButton
->setChecked( b
);
1026 myAltSpeedButton
->setIcon( b
? mySpeedModeOnIcon
: mySpeedModeOffIcon
);
1027 const QString fmt
= b
? tr( "Click to disable Temporary Speed Limits\n(%1 down, %2 up)" )
1028 : tr( "Click to enable Temporary Speed Limits\n(%1 down, %2 up)" );
1029 const Speed d
= Speed::fromKBps( myPrefs
.getInt( Prefs::ALT_SPEED_LIMIT_DOWN
) );
1030 const Speed u
= Speed::fromKBps( myPrefs
.getInt( Prefs::ALT_SPEED_LIMIT_UP
) );
1031 myAltSpeedButton
->setToolTip( fmt
.arg( Formatter::speedToString( d
) )
1032 .arg( Formatter::speedToString( u
) ) );
1046 TrMainWindow :: newTorrent( )
1048 MakeDialog
* dialog
= new MakeDialog( mySession
, this );
1053 TrMainWindow :: openTorrent( )
1055 QFileDialog
* myFileDialog
;
1056 myFileDialog
= new QFileDialog( this,
1057 tr( "Open Torrent" ),
1058 myPrefs
.getString( Prefs::OPEN_DIALOG_FOLDER
),
1059 tr( "Torrent Files (*.torrent);;All Files (*.*)" ) );
1060 myFileDialog
->setFileMode( QFileDialog::ExistingFiles
);
1062 QCheckBox
* button
= new QCheckBox( tr( "Show &options dialog" ) );
1063 button
->setChecked( myPrefs
.getBool( Prefs::OPTIONS_PROMPT
) );
1064 QGridLayout
* layout
= dynamic_cast<QGridLayout
*>(myFileDialog
->layout());
1065 layout
->addWidget( button
, layout
->rowCount( ), 0, 1, -1, Qt::AlignLeft
);
1066 myFileDialogOptionsCheck
= button
;
1068 connect( myFileDialog
, SIGNAL(filesSelected(const QStringList
&)),
1069 this, SLOT(addTorrents(const QStringList
&)));
1071 myFileDialog
->show( );
1075 TrMainWindow :: openURL( )
1077 QString str
= QApplication::clipboard()->text( QClipboard::Selection
);
1079 if( !AddData::isSupported( str
) )
1080 str
= QApplication::clipboard()->text( QClipboard::Clipboard
);
1082 if( !AddData::isSupported( str
) )
1089 TrMainWindow :: openURL( QString url
)
1092 const QString key
= QInputDialog::getText( this,
1093 tr( "Open URL or Magnet Link" ),
1094 tr( "Open URL or Magnet Link" ),
1098 if( ok
&& !key
.isEmpty( ) )
1099 mySession
.addTorrent( key
);
1103 TrMainWindow :: addTorrents( const QStringList
& filenames
)
1105 foreach( const QString
& filename
, filenames
)
1106 addTorrent( filename
);
1110 TrMainWindow :: addTorrent( const QString
& filename
)
1112 if( !myFileDialogOptionsCheck
->isChecked( ) ) {
1113 mySession
.addTorrent( filename
);
1114 QApplication :: alert ( this );
1116 Options
* o
= new Options( mySession
, myPrefs
, filename
, this );
1118 QApplication :: alert( o
);
1123 TrMainWindow :: removeTorrents( const bool deleteFiles
)
1126 QMessageBox
msgBox( this );
1127 QString primary_text
, secondary_text
;
1132 foreach( QModelIndex index
, ui
.listView
->selectionModel( )->selectedRows( ) )
1134 const Torrent
* tor( index
.data( TorrentModel::TorrentRole
).value
<const Torrent
*>( ) );
1135 ids
.insert( tor
->id( ) );
1136 if( tor
->connectedPeers( ) )
1138 if( !tor
->isDone( ) )
1148 primary_text
= ( count
== 1 )
1149 ? tr( "Remove torrent?" )
1150 : tr( "Remove %1 torrents?" ).arg( count
);
1154 primary_text
= ( count
== 1 )
1155 ? tr( "Delete this torrent's downloaded files?" )
1156 : tr( "Delete these %1 torrents' downloaded files?" ).arg( count
);
1159 if( !incomplete
&& !connected
)
1161 secondary_text
= ( count
== 1 )
1162 ? tr( "Once removed, continuing the transfer will require the torrent file or magnet link." )
1163 : tr( "Once removed, continuing the transfers will require the torrent files or magnet links." );
1165 else if( count
== incomplete
)
1167 secondary_text
= ( count
== 1 )
1168 ? tr( "This torrent has not finished downloading." )
1169 : tr( "These torrents have not finished downloading." );
1171 else if( count
== connected
)
1173 secondary_text
= ( count
== 1 )
1174 ? tr( "This torrent is connected to peers." )
1175 : tr( "These torrents are connected to peers." );
1181 secondary_text
= ( connected
== 1 )
1182 ? tr( "One of these torrents is connected to peers." )
1183 : tr( "Some of these torrents are connected to peers." );
1186 if( connected
&& incomplete
)
1188 secondary_text
+= "\n";
1193 secondary_text
+= ( incomplete
== 1 )
1194 ? tr( "One of these torrents has not finished downloading." )
1195 : tr( "Some of these torrents have not finished downloading." );
1199 msgBox
.setWindowTitle( QString(" ") );
1200 msgBox
.setText( QString( "<big><b>%1</big></b>" ).arg( primary_text
) );
1201 msgBox
.setInformativeText( secondary_text
);
1202 msgBox
.setStandardButtons( QMessageBox::Ok
| QMessageBox::Cancel
);
1203 msgBox
.setDefaultButton( QMessageBox::Cancel
);
1204 msgBox
.setIcon( QMessageBox::Question
);
1205 /* hack needed to keep the dialog from being too narrow */
1206 QGridLayout
* layout
= (QGridLayout
*)msgBox
.layout();
1207 QSpacerItem
* spacer
= new QSpacerItem( 450, 0, QSizePolicy::Minimum
, QSizePolicy::Expanding
);
1208 layout
->addItem( spacer
, layout
->rowCount(), 0, 1, layout
->columnCount() );
1210 if( msgBox
.exec() == QMessageBox::Ok
)
1212 ui
.listView
->selectionModel()->clear();
1213 mySession
.removeTorrents( ids
, deleteFiles
);
1222 TrMainWindow :: updateNetworkIcon( )
1224 const time_t now
= time( NULL
);
1225 const int period
= 3;
1226 const bool isSending
= now
- myLastSendTime
<= period
;
1227 const bool isReading
= now
- myLastReadTime
<= period
;
1230 if( isSending
&& isReading
)
1231 key
= "network-transmit-receive";
1232 else if( isSending
)
1233 key
= "network-transmit";
1234 else if( isReading
)
1235 key
= "network-receive";
1237 key
= "network-idle";
1239 QIcon icon
= getStockIcon( key
, QStyle::SP_DriveNetIcon
);
1240 QPixmap pixmap
= icon
.pixmap ( 16, 16 );
1241 myNetworkLabel
->setPixmap( pixmap
);
1242 myNetworkLabel
->setToolTip( isSending
|| isReading
1243 ? tr( "Transmission server is responding" )
1244 : tr( "Last response from server was %1 ago" ).arg( Formatter::timeToString( now
-std::max(myLastReadTime
,myLastSendTime
))));
1248 TrMainWindow :: onNetworkTimer( )
1250 updateNetworkIcon( );
1254 TrMainWindow :: dataReadProgress( )
1256 myLastReadTime
= time( NULL
);
1257 updateNetworkIcon( );
1261 TrMainWindow :: dataSendProgress( )
1263 myLastSendTime
= time( NULL
);
1264 updateNetworkIcon( );
1268 TrMainWindow :: wrongAuthentication( )
1271 mySessionDialog
->show( );
1279 TrMainWindow :: dragEnterEvent( QDragEnterEvent
* event
)
1281 const QMimeData
* mime
= event
->mimeData( );
1283 if( mime
->hasFormat("application/x-bittorrent")
1284 || mime
->text().trimmed().endsWith(".torrent", Qt::CaseInsensitive
) )
1285 event
->acceptProposedAction();
1289 TrMainWindow :: dropEvent( QDropEvent
* event
)
1291 QString key
= event
->mimeData()->text().trimmed();
1293 const QUrl
url( key
);
1294 if( url
.scheme() == "file" )
1295 key
= QUrl::fromPercentEncoding( url
.path().toUtf8( ) );
1297 dynamic_cast<MyApp
*>(QApplication::instance())->addTorrent( key
);