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 11744 2011-01-21 21:51:50Z 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 )
95 setAcceptDrops( true );
97 QAction
* sep
= new QAction( this );
98 sep
->setSeparator( true );
102 QStyle
* style
= this->style();
104 int i
= style
->pixelMetric( QStyle::PM_SmallIconSize
, 0, this );
105 const QSize
smallIconSize( i
, i
);
108 ui
.action_OpenFile
->setIcon( getStockIcon( "folder-open", QStyle::SP_DialogOpenButton
) );
109 ui
.action_New
->setIcon( getStockIcon( "document-new", QStyle::SP_DesktopIcon
) );
110 ui
.action_Properties
->setIcon( getStockIcon( "document-properties", QStyle::SP_DesktopIcon
) );
111 ui
.action_OpenFolder
->setIcon( getStockIcon( "folder-open", QStyle::SP_DirOpenIcon
) );
112 ui
.action_Start
->setIcon( getStockIcon( "media-playback-start", QStyle::SP_MediaPlay
) );
113 ui
.action_Announce
->setIcon( getStockIcon( "network-transmit-receive" ) );
114 ui
.action_Pause
->setIcon( getStockIcon( "media-playback-pause", QStyle::SP_MediaPause
) );
115 ui
.action_Remove
->setIcon( getStockIcon( "list-remove", QStyle::SP_TrashIcon
) );
116 ui
.action_Delete
->setIcon( getStockIcon( "edit-delete", QStyle::SP_TrashIcon
) );
117 ui
.action_StartAll
->setIcon( getStockIcon( "media-playback-start", QStyle::SP_MediaPlay
) );
118 ui
.action_PauseAll
->setIcon( getStockIcon( "media-playback-pause", QStyle::SP_MediaPause
) );
119 ui
.action_Quit
->setIcon( getStockIcon( "application-exit" ) );
120 ui
.action_SelectAll
->setIcon( getStockIcon( "edit-select-all" ) );
121 ui
.action_ReverseSortOrder
->setIcon( getStockIcon( "view-sort-ascending", QStyle::SP_ArrowDown
) );
122 ui
.action_Preferences
->setIcon( getStockIcon( "preferences-system" ) );
123 ui
.action_Contents
->setIcon( getStockIcon( "help-contents", QStyle::SP_DialogHelpButton
) );
124 ui
.action_About
->setIcon( getStockIcon( "help-about" ) );
127 connect( ui
.action_Toolbar
, SIGNAL(toggled(bool)), this, SLOT(setToolbarVisible(bool)));
128 connect( ui
.action_Filterbar
, SIGNAL(toggled(bool)), this, SLOT(setFilterbarVisible(bool)));
129 connect( ui
.action_Statusbar
, SIGNAL(toggled(bool)), this, SLOT(setStatusbarVisible(bool)));
130 connect( ui
.action_CompactView
, SIGNAL(toggled(bool)), this, SLOT(setCompactView(bool)));
131 connect( ui
.action_SortByActivity
, SIGNAL(toggled(bool)), this, SLOT(onSortByActivityToggled(bool)));
132 connect( ui
.action_SortByAge
, SIGNAL(toggled(bool)), this, SLOT(onSortByAgeToggled(bool)));
133 connect( ui
.action_SortByETA
, SIGNAL(toggled(bool)), this, SLOT(onSortByETAToggled(bool)));
134 connect( ui
.action_SortByName
, SIGNAL(toggled(bool)), this, SLOT(onSortByNameToggled(bool)));
135 connect( ui
.action_SortByProgress
, SIGNAL(toggled(bool)), this, SLOT(onSortByProgressToggled(bool)));
136 connect( ui
.action_SortByRatio
, SIGNAL(toggled(bool)), this, SLOT(onSortByRatioToggled(bool)));
137 connect( ui
.action_SortBySize
, SIGNAL(toggled(bool)), this, SLOT(onSortBySizeToggled(bool)));
138 connect( ui
.action_SortByState
, SIGNAL(toggled(bool)), this, SLOT(onSortByStateToggled(bool)));
139 connect( ui
.action_ReverseSortOrder
, SIGNAL(toggled(bool)), this, SLOT(setSortAscendingPref(bool)));
140 connect( ui
.action_Start
, SIGNAL(triggered()), this, SLOT(startSelected()));
141 connect( ui
.action_Pause
, SIGNAL(triggered()), this, SLOT(pauseSelected()));
142 connect( ui
.action_Remove
, SIGNAL(triggered()), this, SLOT(removeSelected()));
143 connect( ui
.action_Delete
, SIGNAL(triggered()), this, SLOT(deleteSelected()));
144 connect( ui
.action_Verify
, SIGNAL(triggered()), this, SLOT(verifySelected()) );
145 connect( ui
.action_Announce
, SIGNAL(triggered()), this, SLOT(reannounceSelected()) );
146 connect( ui
.action_StartAll
, SIGNAL(triggered()), this, SLOT(startAll()));
147 connect( ui
.action_PauseAll
, SIGNAL(triggered()), this, SLOT(pauseAll()));
148 connect( ui
.action_OpenFile
, SIGNAL(triggered()), this, SLOT(openTorrent()));
149 connect( ui
.action_AddURL
, SIGNAL(triggered()), this, SLOT(openURL()));
150 connect( ui
.action_New
, SIGNAL(triggered()), this, SLOT(newTorrent()));
151 connect( ui
.action_Preferences
, SIGNAL(triggered()), this, SLOT(openPreferences()));
152 connect( ui
.action_Statistics
, SIGNAL(triggered()), myStatsDialog
, SLOT(show()));
153 connect( ui
.action_Donate
, SIGNAL(triggered()), this, SLOT(openDonate()));
154 connect( ui
.action_About
, SIGNAL(triggered()), myAboutDialog
, SLOT(show()));
155 connect( ui
.action_Contents
, SIGNAL(triggered()), this, SLOT(openHelp()));
156 connect( ui
.action_OpenFolder
, SIGNAL(triggered()), this, SLOT(openFolder()));
157 connect( ui
.action_CopyMagnetToClipboard
, SIGNAL(triggered()), this, SLOT(copyMagnetLinkToClipboard()));
158 connect( ui
.action_SetLocation
, SIGNAL(triggered()), this, SLOT(setLocation()));
159 connect( ui
.action_Properties
, SIGNAL(triggered()), this, SLOT(openProperties()));
160 connect( ui
.action_SessionDialog
, SIGNAL(triggered()), mySessionDialog
, SLOT(show()));
161 connect( ui
.listView
, SIGNAL(activated(const QModelIndex
&)), ui
.action_Properties
, SLOT(trigger()));
163 QAction
* sep2
= new QAction( this );
164 sep2
->setSeparator( true );
165 QAction
* sep3
= new QAction( this );
166 sep3
->setSeparator( true );
169 QList
<QAction
*> actions
;
170 actions
<< ui
.action_Properties
171 << ui
.action_OpenFolder
174 << ui
.action_Announce
176 << ui
.action_CopyMagnetToClipboard
179 << ui
.action_SetLocation
183 addActions( actions
);
184 setContextMenuPolicy( Qt::ActionsContextMenu
);
187 connect( ui
.action_SelectAll
, SIGNAL(triggered()), ui
.listView
, SLOT(selectAll()));
188 connect( ui
.action_DeselectAll
, SIGNAL(triggered()), ui
.listView
, SLOT(clearSelection()));
190 connect( &myFilterModel
, SIGNAL(rowsInserted(const QModelIndex
&,int,int)), this, SLOT(refreshVisibleCount()));
191 connect( &myFilterModel
, SIGNAL(rowsRemoved(const QModelIndex
&,int,int)), this, SLOT(refreshVisibleCount()));
192 connect( &myFilterModel
, SIGNAL(rowsInserted(const QModelIndex
&,int,int)), this, SLOT(refreshActionSensitivity()));
193 connect( &myFilterModel
, SIGNAL(rowsRemoved(const QModelIndex
&,int,int)), this, SLOT(refreshActionSensitivity()));
195 connect( ui
.action_Quit
, SIGNAL(triggered()), QCoreApplication::instance(), SLOT(quit()) );
198 myFilterModel
.setSourceModel( &myModel
);
199 connect( &myModel
, SIGNAL(modelReset()), this, SLOT(onModelReset()));
200 connect( &myModel
, SIGNAL(rowsRemoved(const QModelIndex
&,int,int)), this, SLOT(onModelReset()));
201 connect( &myModel
, SIGNAL(rowsInserted(const QModelIndex
&,int,int)), this, SLOT(onModelReset()));
202 connect( &myModel
, SIGNAL(dataChanged(const QModelIndex
&,const QModelIndex
&)), this, SLOT(refreshTrayIcon()));
204 ui
.listView
->setModel( &myFilterModel
);
205 connect( ui
.listView
->selectionModel(), SIGNAL(selectionChanged(const QItemSelection
&,const QItemSelection
&)), this, SLOT(refreshActionSensitivity()));
207 QActionGroup
* actionGroup
= new QActionGroup( this );
208 actionGroup
->addAction( ui
.action_SortByActivity
);
209 actionGroup
->addAction( ui
.action_SortByAge
);
210 actionGroup
->addAction( ui
.action_SortByETA
);
211 actionGroup
->addAction( ui
.action_SortByName
);
212 actionGroup
->addAction( ui
.action_SortByProgress
);
213 actionGroup
->addAction( ui
.action_SortByRatio
);
214 actionGroup
->addAction( ui
.action_SortBySize
);
215 actionGroup
->addAction( ui
.action_SortByState
);
217 QMenu
* menu
= new QMenu( );
218 menu
->addAction( ui
.action_OpenFile
);
219 menu
->addAction( ui
.action_AddURL
);
220 menu
->addSeparator( );
221 menu
->addAction( ui
.action_ShowMainWindow
);
222 menu
->addAction( ui
.action_ShowMessageLog
);
223 menu
->addAction( ui
.action_About
);
224 menu
->addSeparator( );
225 menu
->addAction( ui
.action_StartAll
);
226 menu
->addAction( ui
.action_PauseAll
);
227 menu
->addSeparator( );
228 menu
->addAction( ui
.action_Quit
);
229 myTrayIcon
.setContextMenu( menu
);
230 myTrayIcon
.setIcon( QApplication::windowIcon( ) );
232 connect( &myPrefs
, SIGNAL(changed(int)), this, SLOT(refreshPref(int)) );
233 connect( ui
.action_ShowMainWindow
, SIGNAL(toggled(bool)), this, SLOT(toggleWindows(bool)));
234 connect( &myTrayIcon
, SIGNAL(activated(QSystemTrayIcon::ActivationReason
)),
235 this, SLOT(trayActivated(QSystemTrayIcon::ActivationReason
)));
237 ui
.action_ShowMainWindow
->setChecked( !minimized
);
238 ui
.action_TrayIcon
->setChecked( minimized
|| prefs
.getBool( Prefs::SHOW_TRAY_ICON
) );
240 ui
.verticalLayout
->addWidget( createStatusBar( ) );
241 ui
.verticalLayout
->insertWidget( 0, myFilterBar
= new FilterBar( myPrefs
, myModel
, myFilterModel
) );
244 initKeys
<< Prefs :: MAIN_WINDOW_X
245 << Prefs :: SHOW_TRAY_ICON
246 << Prefs :: SORT_REVERSED
247 << Prefs :: SORT_MODE
248 << Prefs :: FILTERBAR
249 << Prefs :: STATUSBAR
250 << Prefs :: STATUSBAR_STATS
252 << Prefs :: ALT_SPEED_LIMIT_ENABLED
253 << Prefs :: COMPACT_VIEW
255 << Prefs :: DSPEED_ENABLED
257 << Prefs :: USPEED_ENABLED
259 << Prefs :: RATIO_ENABLED
;
260 foreach( int key
, initKeys
)
263 connect( &mySession
, SIGNAL(sourceChanged()), this, SLOT(onSessionSourceChanged()) );
264 connect( &mySession
, SIGNAL(statsUpdated()), this, SLOT(refreshStatusBar()) );
265 connect( &mySession
, SIGNAL(dataReadProgress()), this, SLOT(dataReadProgress()) );
266 connect( &mySession
, SIGNAL(dataSendProgress()), this, SLOT(dataSendProgress()) );
267 connect( &mySession
, SIGNAL(httpAuthenticationRequired()), this, SLOT(wrongAuthentication()) );
269 if( mySession
.isServer( ) )
270 myNetworkLabel
->hide( );
272 connect( &myNetworkTimer
, SIGNAL(timeout()), this, SLOT(onNetworkTimer()));
273 myNetworkTimer
.start( 1000 );
276 refreshActionSensitivity( );
280 refreshVisibleCount( );
283 TrMainWindow :: ~TrMainWindow( )
292 TrMainWindow :: closeEvent( QCloseEvent
* event
)
294 // if they're using a tray icon, close to the tray
295 // instead of exiting
296 if( !myPrefs
.getBool( Prefs :: SHOW_TRAY_ICON
) )
299 toggleWindows( false );
309 TrMainWindow :: onSessionSourceChanged( )
315 TrMainWindow :: onModelReset( )
318 refreshVisibleCount( );
319 refreshActionSensitivity( );
328 #define PREF_VARIANTS_KEY "pref-variants-list"
331 TrMainWindow :: onSetPrefs( )
333 const QVariantList p
= sender()->property( PREF_VARIANTS_KEY
).toList( );
334 assert( ( p
.size( ) % 2 ) == 0 );
335 for( int i
=0, n
=p
.size(); i
<n
; i
+=2 )
336 myPrefs
.set( p
[i
].toInt(), p
[i
+1] );
340 TrMainWindow :: onSetPrefs( bool isChecked
)
346 #define SHOW_KEY "show-mode"
349 TrMainWindow :: createStatusBar( )
356 const int i
= style( )->pixelMetric( QStyle::PM_SmallIconSize
, 0, this );
357 const QSize
smallIconSize( i
, i
);
359 QWidget
* top
= myStatusBar
= new QWidget
;
360 h
= new QHBoxLayout( top
);
361 h
->setContentsMargins( HIG::PAD_SMALL
, HIG::PAD_SMALL
, HIG::PAD_SMALL
, HIG::PAD_SMALL
);
362 h
->setSpacing( HIG::PAD_SMALL
);
364 p
= myOptionsButton
= new TrIconPushButton( this );
365 p
->setIcon( QIcon( ":/icons/utilities.png" ) );
366 p
->setIconSize( QPixmap( ":/icons/utilities.png" ).size() );
368 p
->setMenu( createOptionsMenu( ) );
371 p
= myAltSpeedButton
= new QPushButton( this );
372 p
->setIcon( myPrefs
.get
<bool>(Prefs::ALT_SPEED_LIMIT_ENABLED
) ? mySpeedModeOnIcon
: mySpeedModeOffIcon
);
373 p
->setIconSize( QPixmap( ":/icons/alt-limit-on.png" ).size() );
374 p
->setCheckable( true );
375 p
->setFixedWidth( p
->height() );
378 connect( p
, SIGNAL(clicked()), this, SLOT(toggleSpeedMode()));
380 l
= myNetworkLabel
= new QLabel
;
385 l
= myVisibleCountLabel
= new QLabel( this );
390 a
= new QActionGroup( this );
391 a
->addAction( ui
.action_TotalRatio
);
392 a
->addAction( ui
.action_TotalTransfer
);
393 a
->addAction( ui
.action_SessionRatio
);
394 a
->addAction( ui
.action_SessionTransfer
);
396 m
->addAction( ui
.action_TotalRatio
);
397 m
->addAction( ui
.action_TotalTransfer
);
398 m
->addAction( ui
.action_SessionRatio
);
399 m
->addAction( ui
.action_SessionTransfer
);
400 connect( ui
.action_TotalRatio
, SIGNAL(triggered()), this, SLOT(showTotalRatio()));
401 connect( ui
.action_TotalTransfer
, SIGNAL(triggered()), this, SLOT(showTotalTransfer()));
402 connect( ui
.action_SessionRatio
, SIGNAL(triggered()), this, SLOT(showSessionRatio()));
403 connect( ui
.action_SessionTransfer
, SIGNAL(triggered()), this, SLOT(showSessionTransfer()));
404 p
= myStatsModeButton
= new TrIconPushButton( this );
405 p
->setIcon( QIcon( ":/icons/ratio.png" ) );
406 p
->setIconSize( QPixmap( ":/icons/ratio.png" ).size() );
410 l
= myStatsLabel
= new QLabel( this );
415 l
= myDownloadSpeedLabel
= new QLabel( this );
416 const int minimumSpeedWidth
= l
->fontMetrics().width( Formatter::speedToString(Speed::fromKBps(999.99)));
417 l
->setMinimumWidth( minimumSpeedWidth
);
418 l
->setAlignment( Qt::AlignRight
|Qt::AlignVCenter
);
420 l
= new QLabel( this );
421 l
->setPixmap( getStockIcon( "go-down", QStyle::SP_ArrowDown
).pixmap( smallIconSize
) );
426 l
= myUploadSpeedLabel
= new QLabel
;
427 l
->setMinimumWidth( minimumSpeedWidth
);
428 l
->setAlignment( Qt::AlignRight
|Qt::AlignVCenter
);
431 l
->setPixmap( getStockIcon( "go-up", QStyle::SP_ArrowUp
).pixmap( smallIconSize
) );
438 TrMainWindow :: createOptionsMenu( )
445 QList
<int> stockSpeeds
;
446 stockSpeeds
<< 5 << 10 << 20 << 30 << 40 << 50 << 75 << 100 << 150 << 200 << 250 << 500 << 750;
447 QList
<double> stockRatios
;
448 stockRatios
<< 0.25 << 0.50 << 0.75 << 1 << 1.5 << 2 << 3;
451 sub
= menu
->addMenu( tr( "Limit Download Speed" ) );
452 int currentVal
= myPrefs
.get
<int>( Prefs::DSPEED
);
453 g
= new QActionGroup( this );
454 a
= myDlimitOffAction
= sub
->addAction( tr( "Unlimited" ) );
455 a
->setCheckable( true );
456 a
->setProperty( PREF_VARIANTS_KEY
, QVariantList() << Prefs::DSPEED_ENABLED
<< false );
458 connect( a
, SIGNAL(triggered(bool)), this, SLOT(onSetPrefs(bool)) );
459 a
= myDlimitOnAction
= sub
->addAction( tr( "Limited at %1" ).arg( Formatter::speedToString( Speed::fromKBps( currentVal
) ) ) );
460 a
->setCheckable( true );
461 a
->setProperty( PREF_VARIANTS_KEY
, QVariantList() << Prefs::DSPEED
<< currentVal
<< Prefs::DSPEED_ENABLED
<< true );
463 connect( a
, SIGNAL(triggered(bool)), this, SLOT(onSetPrefs(bool)) );
464 sub
->addSeparator( );
465 foreach( int i
, stockSpeeds
) {
466 a
= sub
->addAction( Formatter::speedToString( Speed::fromKBps( i
) ) );
467 a
->setProperty( PREF_VARIANTS_KEY
, QVariantList() << Prefs::DSPEED
<< i
<< Prefs::DSPEED_ENABLED
<< true );
468 connect( a
, SIGNAL(triggered(bool)), this, SLOT(onSetPrefs()));
471 sub
= menu
->addMenu( tr( "Limit Upload Speed" ) );
472 currentVal
= myPrefs
.get
<int>( Prefs::USPEED
);
473 g
= new QActionGroup( this );
474 a
= myUlimitOffAction
= sub
->addAction( tr( "Unlimited" ) );
475 a
->setCheckable( true );
476 a
->setProperty( PREF_VARIANTS_KEY
, QVariantList() << Prefs::USPEED_ENABLED
<< false );
478 connect( a
, SIGNAL(triggered(bool)), this, SLOT(onSetPrefs(bool)) );
479 a
= myUlimitOnAction
= sub
->addAction( tr( "Limited at %1" ).arg( Formatter::speedToString( Speed::fromKBps( currentVal
) ) ) );
480 a
->setCheckable( true );
481 a
->setProperty( PREF_VARIANTS_KEY
, QVariantList() << Prefs::USPEED
<< currentVal
<< Prefs::USPEED_ENABLED
<< true );
483 connect( a
, SIGNAL(triggered(bool)), this, SLOT(onSetPrefs(bool)) );
484 sub
->addSeparator( );
485 foreach( int i
, stockSpeeds
) {
486 a
= sub
->addAction( Formatter::speedToString( Speed::fromKBps( i
) ) );
487 a
->setProperty( PREF_VARIANTS_KEY
, QVariantList() << Prefs::USPEED
<< i
<< Prefs::USPEED_ENABLED
<< true );
488 connect( a
, SIGNAL(triggered(bool)), this, SLOT(onSetPrefs()));
491 menu
->addSeparator( );
492 sub
= menu
->addMenu( tr( "Stop Seeding at Ratio" ) );
494 double d
= myPrefs
.get
<double>( Prefs::RATIO
);
495 g
= new QActionGroup( this );
496 a
= myRatioOffAction
= sub
->addAction( tr( "Seed Forever" ) );
497 a
->setCheckable( true );
498 a
->setProperty( PREF_VARIANTS_KEY
, QVariantList() << Prefs::RATIO_ENABLED
<< false );
500 connect( a
, SIGNAL(triggered(bool)), this, SLOT(onSetPrefs(bool)) );
501 a
= myRatioOnAction
= sub
->addAction( tr( "Stop at Ratio (%1)" ).arg( Formatter::ratioToString( d
) ) );
502 a
->setCheckable( true );
503 a
->setProperty( PREF_VARIANTS_KEY
, QVariantList() << Prefs::RATIO
<< d
<< Prefs::RATIO_ENABLED
<< true );
505 connect( a
, SIGNAL(triggered(bool)), this, SLOT(onSetPrefs(bool)) );
506 sub
->addSeparator( );
507 foreach( double i
, stockRatios
) {
508 a
= sub
->addAction( Formatter::ratioToString( i
) );
509 a
->setProperty( PREF_VARIANTS_KEY
, QVariantList() << Prefs::RATIO
<< i
<< Prefs::RATIO_ENABLED
<< true );
510 connect( a
, SIGNAL(triggered(bool)), this, SLOT(onSetPrefs()));
521 TrMainWindow :: setSortPref( int i
)
523 myPrefs
.set( Prefs::SORT_MODE
, SortMode( i
) );
525 void TrMainWindow :: onSortByActivityToggled ( bool b
) { if( b
) setSortPref( SortMode::SORT_BY_ACTIVITY
); }
526 void TrMainWindow :: onSortByAgeToggled ( bool b
) { if( b
) setSortPref( SortMode::SORT_BY_AGE
); }
527 void TrMainWindow :: onSortByETAToggled ( bool b
) { if( b
) setSortPref( SortMode::SORT_BY_ETA
); }
528 void TrMainWindow :: onSortByNameToggled ( bool b
) { if( b
) setSortPref( SortMode::SORT_BY_NAME
); }
529 void TrMainWindow :: onSortByProgressToggled ( bool b
) { if( b
) setSortPref( SortMode::SORT_BY_PROGRESS
); }
530 void TrMainWindow :: onSortByRatioToggled ( bool b
) { if( b
) setSortPref( SortMode::SORT_BY_RATIO
); }
531 void TrMainWindow :: onSortBySizeToggled ( bool b
) { if( b
) setSortPref( SortMode::SORT_BY_SIZE
); }
532 void TrMainWindow :: onSortByStateToggled ( bool b
) { if( b
) setSortPref( SortMode::SORT_BY_STATE
); }
535 TrMainWindow :: setSortAscendingPref( bool b
)
537 myPrefs
.set( Prefs::SORT_REVERSED
, b
);
545 TrMainWindow :: onPrefsDestroyed( )
551 TrMainWindow :: openPreferences( )
553 if( myPrefsDialog
== 0 ) {
554 myPrefsDialog
= new PrefsDialog( mySession
, myPrefs
, this );
555 connect( myPrefsDialog
, SIGNAL(destroyed(QObject
*)), this, SLOT(onPrefsDestroyed()));
558 myPrefsDialog
->show( );
562 TrMainWindow :: onDetailsDestroyed( )
568 TrMainWindow :: openProperties( )
570 if( myDetailsDialog
== 0 ) {
571 myDetailsDialog
= new Details( mySession
, myPrefs
, myModel
, this );
572 connect( myDetailsDialog
, SIGNAL(destroyed(QObject
*)), this, SLOT(onDetailsDestroyed()));
575 myDetailsDialog
->setIds( getSelectedTorrents( ) );
576 myDetailsDialog
->show( );
580 TrMainWindow :: setLocation( )
582 QDialog
* d
= new RelocateDialog( mySession
, myModel
, getSelectedTorrents(), this );
587 TrMainWindow :: openFolder( )
589 const int torrentId( *getSelectedTorrents().begin() );
590 const Torrent
* tor( myModel
.getTorrentFromId( torrentId
) );
591 const QString
path( tor
->getPath( ) );
592 QDesktopServices :: openUrl( QUrl::fromLocalFile( path
) );
596 TrMainWindow :: copyMagnetLinkToClipboard( )
598 const int id( *getSelectedTorrents().begin() );
599 mySession
.copyMagnetLinkToClipboard( id
);
603 TrMainWindow :: openDonate( )
605 QDesktopServices :: openUrl( QUrl( "http://www.transmissionbt.com/donate.php" ) );
609 TrMainWindow :: openHelp( )
611 const char * fmt
= "http://www.transmissionbt.com/help/gtk/%d.%dx";
613 sscanf( SHORT_VERSION_STRING
, "%d.%d", &major
, &minor
);
615 tr_snprintf( url
, sizeof( url
), fmt
, major
, minor
/10 );
616 QDesktopServices :: openUrl( QUrl( url
) );
620 TrMainWindow :: refreshTitle( )
622 QString
title( "Transmission" );
623 const QUrl
url( mySession
.getRemoteUrl( ) );
625 title
+= tr( " - %1:%2" ).arg( url
.host() ).arg( url
.port() );
626 setWindowTitle( title
);
630 TrMainWindow :: refreshVisibleCount( )
632 const int visibleCount( myFilterModel
.rowCount( ) );
633 const int totalCount( visibleCount
+ myFilterModel
.hiddenRowCount( ) );
635 if( visibleCount
== totalCount
)
636 str
= tr( "%Ln Torrent(s)", 0, totalCount
);
638 str
= tr( "%L1 of %Ln Torrent(s)", 0, totalCount
).arg( visibleCount
);
639 myVisibleCountLabel
->setText( str
);
640 myVisibleCountLabel
->setVisible( totalCount
> 0 );
644 TrMainWindow :: refreshTrayIcon( )
647 const QString idle
= tr( "Idle" );
649 foreach( int id
, myModel
.getIds( ) ) {
650 const Torrent
* tor
= myModel
.getTorrentFromId( id
);
651 u
+= tor
->uploadSpeed( );
652 d
+= tor
->downloadSpeed( );
655 myTrayIcon
.setToolTip( tr( "Transmission\nUp: %1\nDown: %2" )
656 .arg( u
.isZero() ? idle
: Formatter::speedToString( u
) )
657 .arg( d
.isZero() ? idle
: Formatter::speedToString( d
) ) );
661 TrMainWindow :: refreshStatusBar( )
663 const Speed
up( myModel
.getUploadSpeed( ) );
664 const Speed
down( myModel
.getDownloadSpeed( ) );
665 myUploadSpeedLabel
->setText( Formatter:: speedToString( up
) );
666 myDownloadSpeedLabel
->setText( Formatter:: speedToString( down
) );
668 myNetworkLabel
->setVisible( !mySession
.isServer( ) );
670 const QString
mode( myPrefs
.getString( Prefs::STATUSBAR_STATS
) );
673 if( mode
== "session-ratio" )
675 str
= tr( "Ratio: %1" ).arg( Formatter:: ratioToString( mySession
.getStats().ratio
) );
677 else if( mode
== "session-transfer" )
679 const tr_session_stats
& stats( mySession
.getStats( ) );
680 str
= tr( "Down: %1, Up: %2" ).arg( Formatter:: sizeToString( stats
.downloadedBytes
) )
681 .arg( Formatter:: sizeToString( stats
.uploadedBytes
) );
683 else if( mode
== "total-transfer" )
685 const tr_session_stats
& stats( mySession
.getCumulativeStats( ) );
686 str
= tr( "Down: %1, Up: %2" ).arg( Formatter:: sizeToString( stats
.downloadedBytes
) )
687 .arg( Formatter:: sizeToString( stats
.uploadedBytes
) );
689 else // default is "total-ratio"
691 str
= tr( "Ratio: %1" ).arg( Formatter:: ratioToString( mySession
.getCumulativeStats().ratio
) );
694 myStatsLabel
->setText( str
);
698 TrMainWindow :: refreshActionSensitivity( )
702 int selectedAndPaused( 0 );
703 int canAnnounce( 0 );
704 const QAbstractItemModel
* model( ui
.listView
->model( ) );
705 const QItemSelectionModel
* selectionModel( ui
.listView
->selectionModel( ) );
706 const int rowCount( model
->rowCount( ) );
708 // count how many torrents are selected, paused, etc
709 for( int row
=0; row
<rowCount
; ++row
) {
710 const QModelIndex
modelIndex( model
->index( row
, 0 ) );
711 assert( model
== modelIndex
.model( ) );
712 const Torrent
* tor( model
->data( modelIndex
, TorrentModel::TorrentRole
).value
<const Torrent
*>( ) );
714 const bool isSelected( selectionModel
->isSelected( modelIndex
) );
715 const bool isPaused( tor
->isPaused( ) );
720 if( isSelected
&& isPaused
)
722 if( tor
->canManualAnnounce( ) )
727 const bool haveSelection( selected
> 0 );
728 ui
.action_Verify
->setEnabled( haveSelection
);
729 ui
.action_Remove
->setEnabled( haveSelection
);
730 ui
.action_Delete
->setEnabled( haveSelection
);
731 ui
.action_Properties
->setEnabled( haveSelection
);
732 ui
.action_DeselectAll
->setEnabled( haveSelection
);
733 ui
.action_SetLocation
->setEnabled( haveSelection
);
735 const bool oneSelection( selected
== 1 );
736 ui
.action_OpenFolder
->setEnabled( oneSelection
&& mySession
.isLocal( ) );
737 ui
.action_CopyMagnetToClipboard
->setEnabled( oneSelection
);
739 ui
.action_SelectAll
->setEnabled( selected
< rowCount
);
740 ui
.action_StartAll
->setEnabled( paused
> 0 );
741 ui
.action_PauseAll
->setEnabled( paused
< rowCount
);
742 ui
.action_Start
->setEnabled( selectedAndPaused
> 0 );
743 ui
.action_Pause
->setEnabled( selectedAndPaused
< selected
);
744 ui
.action_Announce
->setEnabled( selected
> 0 && ( canAnnounce
== selected
) );
746 if( myDetailsDialog
)
747 myDetailsDialog
->setIds( getSelectedTorrents( ) );
755 TrMainWindow :: clearSelection( )
757 ui
.action_DeselectAll
->trigger( );
761 TrMainWindow :: getSelectedTorrents( ) const
765 foreach( QModelIndex index
, ui
.listView
->selectionModel( )->selectedRows( ) )
767 const Torrent
* tor( index
.data( TorrentModel::TorrentRole
).value
<const Torrent
*>( ) );
768 ids
.insert( tor
->id( ) );
775 TrMainWindow :: startSelected( )
777 mySession
.startTorrents( getSelectedTorrents( ) );
780 TrMainWindow :: pauseSelected( )
782 mySession
.pauseTorrents( getSelectedTorrents( ) );
785 TrMainWindow :: startAll( )
787 mySession
.startTorrents( );
790 TrMainWindow :: pauseAll( )
792 mySession
.pauseTorrents( );
795 TrMainWindow :: removeSelected( )
797 removeTorrents( false );
800 TrMainWindow :: deleteSelected( )
802 removeTorrents( true );
805 TrMainWindow :: verifySelected( )
807 mySession
.verifyTorrents( getSelectedTorrents( ) );
810 TrMainWindow :: reannounceSelected( )
812 mySession
.reannounceTorrents( getSelectedTorrents( ) );
819 void TrMainWindow :: showTotalRatio ( ) { myPrefs
.set( Prefs::STATUSBAR_STATS
, "total-ratio"); }
820 void TrMainWindow :: showTotalTransfer ( ) { myPrefs
.set( Prefs::STATUSBAR_STATS
, "total-transfer"); }
821 void TrMainWindow :: showSessionRatio ( ) { myPrefs
.set( Prefs::STATUSBAR_STATS
, "session-ratio"); }
822 void TrMainWindow :: showSessionTransfer ( ) { myPrefs
.set( Prefs::STATUSBAR_STATS
, "session-transfer"); }
829 TrMainWindow :: setCompactView( bool visible
)
831 myPrefs
.set( Prefs :: COMPACT_VIEW
, visible
);
834 TrMainWindow :: toggleSpeedMode( )
836 myPrefs
.toggleBool( Prefs :: ALT_SPEED_LIMIT_ENABLED
);
839 TrMainWindow :: setToolbarVisible( bool visible
)
841 myPrefs
.set( Prefs::TOOLBAR
, visible
);
844 TrMainWindow :: setFilterbarVisible( bool visible
)
846 myPrefs
.set( Prefs::FILTERBAR
, visible
);
849 TrMainWindow :: setStatusbarVisible( bool visible
)
851 myPrefs
.set( Prefs::STATUSBAR
, visible
);
859 TrMainWindow :: toggleWindows( bool doShow
)
867 if ( !isVisible( ) ) show( );
868 if ( isMinimized( ) ) showNormal( );
871 QApplication::setActiveWindow( this );
876 TrMainWindow :: trayActivated( QSystemTrayIcon::ActivationReason reason
)
878 if( reason
== QSystemTrayIcon::Trigger
)
880 if( isMinimized ( ) )
881 toggleWindows( true );
883 ui
.action_ShowMainWindow
->toggle( );
889 TrMainWindow :: refreshPref( int key
)
897 case Prefs::STATUSBAR_STATS
:
898 str
= myPrefs
.getString( key
);
899 ui
.action_TotalRatio
->setChecked ( str
== "total-ratio" );
900 ui
.action_TotalTransfer
->setChecked ( str
== "total-transfer" );
901 ui
.action_SessionRatio
->setChecked ( str
== "session-ratio" );
902 ui
.action_SessionTransfer
->setChecked( str
== "session-transfer" );
906 case Prefs::SORT_REVERSED
:
907 ui
.action_ReverseSortOrder
->setChecked( myPrefs
.getBool( key
) );
910 case Prefs::SORT_MODE
:
911 i
= myPrefs
.get
<SortMode
>(key
).mode( );
912 ui
.action_SortByActivity
->setChecked ( i
== SortMode::SORT_BY_ACTIVITY
);
913 ui
.action_SortByAge
->setChecked ( i
== SortMode::SORT_BY_AGE
);
914 ui
.action_SortByETA
->setChecked ( i
== SortMode::SORT_BY_ETA
);
915 ui
.action_SortByName
->setChecked ( i
== SortMode::SORT_BY_NAME
);
916 ui
.action_SortByProgress
->setChecked ( i
== SortMode::SORT_BY_PROGRESS
);
917 ui
.action_SortByRatio
->setChecked ( i
== SortMode::SORT_BY_RATIO
);
918 ui
.action_SortBySize
->setChecked ( i
== SortMode::SORT_BY_SIZE
);
919 ui
.action_SortByState
->setChecked ( i
== SortMode::SORT_BY_STATE
);
922 case Prefs::DSPEED_ENABLED
:
923 (myPrefs
.get
<bool>(key
) ? myDlimitOnAction
: myDlimitOffAction
)->setChecked( true );
927 myDlimitOnAction
->setText( tr( "Limited at %1" ).arg( Formatter::speedToString( Speed::fromKBps( myPrefs
.get
<int>(key
) ) ) ) );
930 case Prefs::USPEED_ENABLED
:
931 (myPrefs
.get
<bool>(key
) ? myUlimitOnAction
: myUlimitOffAction
)->setChecked( true );
935 myUlimitOnAction
->setText( tr( "Limited at %1" ).arg( Formatter::speedToString( Speed::fromKBps( myPrefs
.get
<int>(key
) ) ) ) );
938 case Prefs::RATIO_ENABLED
:
939 (myPrefs
.get
<bool>(key
) ? myRatioOnAction
: myRatioOffAction
)->setChecked( true );
943 myRatioOnAction
->setText( tr( "Stop at Ratio (%1)" ).arg( Formatter::ratioToString( myPrefs
.get
<double>(key
) ) ) );
946 case Prefs::FILTERBAR
:
947 b
= myPrefs
.getBool( key
);
948 myFilterBar
->setVisible( b
);
949 ui
.action_Filterbar
->setChecked( b
);
952 case Prefs::STATUSBAR
:
953 b
= myPrefs
.getBool( key
);
954 myStatusBar
->setVisible( b
);
955 ui
.action_Statusbar
->setChecked( b
);
959 b
= myPrefs
.getBool( key
);
960 ui
.toolBar
->setVisible( b
);
961 ui
.action_Toolbar
->setChecked( b
);
964 case Prefs::SHOW_TRAY_ICON
:
965 b
= myPrefs
.getBool( key
);
966 ui
.action_TrayIcon
->setChecked( b
);
967 myTrayIcon
.setVisible( b
);
971 case Prefs::COMPACT_VIEW
: {
972 QItemSelectionModel
* selectionModel( ui
.listView
->selectionModel( ) );
973 const QItemSelection
selection( selectionModel
->selection( ) );
974 const QModelIndex
currentIndex( selectionModel
->currentIndex( ) );
975 b
= myPrefs
.getBool( key
);
976 ui
.action_CompactView
->setChecked( b
);
977 ui
.listView
->setItemDelegate( b
? myTorrentDelegateMin
: myTorrentDelegate
);
978 selectionModel
->clear( );
979 ui
.listView
->reset( ); // force the rows to resize
980 selectionModel
->select( selection
, QItemSelectionModel::Select
);
981 selectionModel
->setCurrentIndex( currentIndex
, QItemSelectionModel::NoUpdate
);
985 case Prefs::MAIN_WINDOW_X
:
986 case Prefs::MAIN_WINDOW_Y
:
987 case Prefs::MAIN_WINDOW_WIDTH
:
988 case Prefs::MAIN_WINDOW_HEIGHT
:
989 setGeometry( myPrefs
.getInt( Prefs::MAIN_WINDOW_X
),
990 myPrefs
.getInt( Prefs::MAIN_WINDOW_Y
),
991 myPrefs
.getInt( Prefs::MAIN_WINDOW_WIDTH
),
992 myPrefs
.getInt( Prefs::MAIN_WINDOW_HEIGHT
) );
995 case Prefs :: ALT_SPEED_LIMIT_ENABLED
:
996 case Prefs :: ALT_SPEED_LIMIT_UP
:
997 case Prefs :: ALT_SPEED_LIMIT_DOWN
: {
998 b
= myPrefs
.getBool( Prefs :: ALT_SPEED_LIMIT_ENABLED
);
999 myAltSpeedButton
->setChecked( b
);
1000 myAltSpeedButton
->setIcon( b
? mySpeedModeOnIcon
: mySpeedModeOffIcon
);
1001 const QString fmt
= b
? tr( "Click to disable Temporary Speed Limits\n(%1 down, %2 up)" )
1002 : tr( "Click to enable Temporary Speed Limits\n(%1 down, %2 up)" );
1003 const Speed d
= Speed::fromKBps( myPrefs
.getInt( Prefs::ALT_SPEED_LIMIT_DOWN
) );
1004 const Speed u
= Speed::fromKBps( myPrefs
.getInt( Prefs::ALT_SPEED_LIMIT_UP
) );
1005 myAltSpeedButton
->setToolTip( fmt
.arg( Formatter::speedToString( d
) )
1006 .arg( Formatter::speedToString( u
) ) );
1020 TrMainWindow :: newTorrent( )
1022 MakeDialog
* dialog
= new MakeDialog( mySession
, this );
1027 TrMainWindow :: openTorrent( )
1029 QFileDialog
* myFileDialog
;
1030 myFileDialog
= new QFileDialog( this,
1031 tr( "Open Torrent" ),
1032 myPrefs
.getString( Prefs::OPEN_DIALOG_FOLDER
),
1033 tr( "Torrent Files (*.torrent);;All Files (*.*)" ) );
1034 myFileDialog
->setFileMode( QFileDialog::ExistingFiles
);
1036 QCheckBox
* button
= new QCheckBox( tr( "Show &options dialog" ) );
1037 button
->setChecked( myPrefs
.getBool( Prefs::OPTIONS_PROMPT
) );
1038 QGridLayout
* layout
= dynamic_cast<QGridLayout
*>(myFileDialog
->layout());
1039 layout
->addWidget( button
, layout
->rowCount( ), 0, 1, -1, Qt::AlignLeft
);
1040 myFileDialogOptionsCheck
= button
;
1042 connect( myFileDialog
, SIGNAL(filesSelected(const QStringList
&)),
1043 this, SLOT(addTorrents(const QStringList
&)));
1045 myFileDialog
->show( );
1049 TrMainWindow :: openURL( )
1051 QString str
= QApplication::clipboard()->text( QClipboard::Selection
);
1053 if( !AddData::isSupported( str
) )
1054 str
= QApplication::clipboard()->text( QClipboard::Clipboard
);
1056 if( !AddData::isSupported( str
) )
1063 TrMainWindow :: openURL( QString url
)
1066 const QString key
= QInputDialog::getText( this,
1067 tr( "Open URL or Magnet Link" ),
1068 tr( "Open URL or Magnet Link" ),
1072 if( ok
&& !key
.isEmpty( ) )
1073 mySession
.addTorrent( key
);
1077 TrMainWindow :: addTorrents( const QStringList
& filenames
)
1079 foreach( const QString
& filename
, filenames
)
1080 addTorrent( filename
);
1084 TrMainWindow :: addTorrent( const QString
& filename
)
1086 if( !myFileDialogOptionsCheck
->isChecked( ) ) {
1087 mySession
.addTorrent( filename
);
1088 QApplication :: alert ( this );
1090 Options
* o
= new Options( mySession
, myPrefs
, filename
, this );
1092 QApplication :: alert( o
);
1097 TrMainWindow :: removeTorrents( const bool deleteFiles
)
1100 QMessageBox
msgBox( this );
1101 QString primary_text
, secondary_text
;
1106 foreach( QModelIndex index
, ui
.listView
->selectionModel( )->selectedRows( ) )
1108 const Torrent
* tor( index
.data( TorrentModel::TorrentRole
).value
<const Torrent
*>( ) );
1109 ids
.insert( tor
->id( ) );
1110 if( tor
->connectedPeers( ) )
1112 if( !tor
->isDone( ) )
1122 primary_text
= ( count
== 1 )
1123 ? tr( "Remove torrent?" )
1124 : tr( "Remove %1 torrents?" ).arg( count
);
1128 primary_text
= ( count
== 1 )
1129 ? tr( "Delete this torrent's downloaded files?" )
1130 : tr( "Delete these %1 torrents' downloaded files?" ).arg( count
);
1133 if( !incomplete
&& !connected
)
1135 secondary_text
= ( count
== 1 )
1136 ? tr( "Once removed, continuing the transfer will require the torrent file or magnet link." )
1137 : tr( "Once removed, continuing the transfers will require the torrent files or magnet links." );
1139 else if( count
== incomplete
)
1141 secondary_text
= ( count
== 1 )
1142 ? tr( "This torrent has not finished downloading." )
1143 : tr( "These torrents have not finished downloading." );
1145 else if( count
== connected
)
1147 secondary_text
= ( count
== 1 )
1148 ? tr( "This torrent is connected to peers." )
1149 : tr( "These torrents are connected to peers." );
1155 secondary_text
= ( connected
== 1 )
1156 ? tr( "One of these torrents is connected to peers." )
1157 : tr( "Some of these torrents are connected to peers." );
1160 if( connected
&& incomplete
)
1162 secondary_text
+= "\n";
1167 secondary_text
+= ( incomplete
== 1 )
1168 ? tr( "One of these torrents has not finished downloading." )
1169 : tr( "Some of these torrents have not finished downloading." );
1173 msgBox
.setWindowTitle( QString(" ") );
1174 msgBox
.setText( QString( "<big><b>%1</big></b>" ).arg( primary_text
) );
1175 msgBox
.setInformativeText( secondary_text
);
1176 msgBox
.setStandardButtons( QMessageBox::Ok
| QMessageBox::Cancel
);
1177 msgBox
.setDefaultButton( QMessageBox::Cancel
);
1178 msgBox
.setIcon( QMessageBox::Question
);
1179 /* hack needed to keep the dialog from being too narrow */
1180 QGridLayout
* layout
= (QGridLayout
*)msgBox
.layout();
1181 QSpacerItem
* spacer
= new QSpacerItem( 450, 0, QSizePolicy::Minimum
, QSizePolicy::Expanding
);
1182 layout
->addItem( spacer
, layout
->rowCount(), 0, 1, layout
->columnCount() );
1184 if( msgBox
.exec() == QMessageBox::Ok
)
1186 ui
.listView
->selectionModel()->clear();
1187 mySession
.removeTorrents( ids
, deleteFiles
);
1196 TrMainWindow :: updateNetworkIcon( )
1198 const time_t now
= time( NULL
);
1199 const int period
= 3;
1200 const bool isSending
= now
- myLastSendTime
<= period
;
1201 const bool isReading
= now
- myLastReadTime
<= period
;
1204 if( isSending
&& isReading
)
1205 key
= "network-transmit-receive";
1206 else if( isSending
)
1207 key
= "network-transmit";
1208 else if( isReading
)
1209 key
= "network-receive";
1211 key
= "network-idle";
1213 QIcon icon
= getStockIcon( key
, QStyle::SP_DriveNetIcon
);
1214 QPixmap pixmap
= icon
.pixmap ( 16, 16 );
1215 myNetworkLabel
->setPixmap( pixmap
);
1216 myNetworkLabel
->setToolTip( isSending
|| isReading
1217 ? tr( "Transmission server is responding" )
1218 : tr( "Last response from server was %1 ago" ).arg( Formatter::timeToString( now
-std::max(myLastReadTime
,myLastSendTime
))));
1222 TrMainWindow :: onNetworkTimer( )
1224 updateNetworkIcon( );
1228 TrMainWindow :: dataReadProgress( )
1230 myLastReadTime
= time( NULL
);
1231 updateNetworkIcon( );
1235 TrMainWindow :: dataSendProgress( )
1237 myLastSendTime
= time( NULL
);
1238 updateNetworkIcon( );
1242 TrMainWindow :: wrongAuthentication( )
1245 mySessionDialog
->show( );
1253 TrMainWindow :: dragEnterEvent( QDragEnterEvent
* event
)
1255 const QMimeData
* mime
= event
->mimeData( );
1257 if( mime
->hasFormat("application/x-bittorrent")
1258 || mime
->text().trimmed().endsWith(".torrent", Qt::CaseInsensitive
) )
1259 event
->acceptProposedAction();
1263 TrMainWindow :: dropEvent( QDropEvent
* event
)
1265 QString key
= event
->mimeData()->text().trimmed();
1267 const QUrl
url( key
);
1268 if( url
.scheme() == "file" )
1269 key
= QUrl::fromPercentEncoding( url
.path().toUtf8( ) );
1271 dynamic_cast<MyApp
*>(QApplication::instance())->addTorrent( key
);