Revert "transmission: update from 2.13 to 2.22"
[tomato.git] / release / src / router / transmission / qt / mainwin.cc
blobc6d26196ec45dcd587071096cdceb4e3f794ad7a
1 /*
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 11263 2010-09-24 15:22:53Z charles $
13 #include <cassert>
14 #include <iostream>
16 #include <QtGui>
18 #include <libtransmission/transmission.h>
19 #include <libtransmission/utils.h>
20 #include <libtransmission/version.h>
22 #include "about.h"
23 #include "app.h"
24 #include "details.h"
25 #include "filterbar.h"
26 #include "filters.h"
27 #include "formatter.h"
28 #include "hig.h"
29 #include "mainwin.h"
30 #include "make-dialog.h"
31 #include "options.h"
32 #include "prefs.h"
33 #include "prefs-dialog.h"
34 #include "relocate.h"
35 #include "session.h"
36 #include "session-dialog.h"
37 #include "speed.h"
38 #include "stats-dialog.h"
39 #include "torrent-delegate.h"
40 #include "torrent-delegate-min.h"
41 #include "torrent-filter.h"
42 #include "torrent-model.h"
43 #include "triconpushbutton.h"
44 #include "ui_mainwin.h"
46 #define PREFS_KEY "prefs-key";
48 QIcon
49 TrMainWindow :: getStockIcon( const QString& name, int fallback )
51 QIcon icon = QIcon::fromTheme( name );
53 if( icon.isNull( ) && ( fallback >= 0 ) )
54 icon = style()->standardIcon( QStyle::StandardPixmap( fallback ), 0, this );
56 return icon;
59 namespace
61 QSize calculateTextButtonSizeHint( QPushButton * button )
63 QStyleOptionButton opt;
64 opt.initFrom( button );
65 QString s( button->text( ) );
66 if( s.isEmpty( ) )
67 s = QString::fromLatin1( "XXXX" );
68 QFontMetrics fm = button->fontMetrics( );
69 QSize sz = fm.size( Qt::TextShowMnemonic, s );
70 return button->style()->sizeFromContents( QStyle::CT_PushButton, &opt, sz, button ).expandedTo( QApplication::globalStrut( ) );
75 TrMainWindow :: TrMainWindow( Session& session, Prefs& prefs, TorrentModel& model, bool minimized ):
76 myLastFullUpdateTime( 0 ),
77 mySessionDialog( new SessionDialog( session, prefs, this ) ),
78 myPrefsDialog( 0 ),
79 myAboutDialog( new AboutDialog( this ) ),
80 myStatsDialog( new StatsDialog( session, this ) ),
81 myDetailsDialog( 0 ),
82 myFilterModel( prefs ),
83 myTorrentDelegate( new TorrentDelegate( this ) ),
84 myTorrentDelegateMin( new TorrentDelegateMin( this ) ),
85 mySession( session ),
86 myPrefs( prefs ),
87 myModel( model ),
88 mySpeedModeOffIcon( ":/icons/alt-limit-off.png" ),
89 mySpeedModeOnIcon( ":/icons/alt-limit-on.png" ),
90 myLastSendTime( 0 ),
91 myLastReadTime( 0 ),
92 myNetworkTimer( this )
94 setAcceptDrops( true );
96 QAction * sep = new QAction( this );
97 sep->setSeparator( true );
99 ui.setupUi( this );
101 QStyle * style = this->style();
103 int i = style->pixelMetric( QStyle::PM_SmallIconSize, 0, this );
104 const QSize smallIconSize( i, i );
106 // icons
107 ui.action_AddFile->setIcon( getStockIcon( "list-add", QStyle::SP_DialogOpenButton ) );
108 ui.action_New->setIcon( getStockIcon( "document-new", QStyle::SP_DesktopIcon ) );
109 ui.action_Properties->setIcon( getStockIcon( "document-properties", QStyle::SP_DesktopIcon ) );
110 ui.action_OpenFolder->setIcon( getStockIcon( "folder-open", QStyle::SP_DirOpenIcon ) );
111 ui.action_Start->setIcon( getStockIcon( "media-playback-start", QStyle::SP_MediaPlay ) );
112 ui.action_Announce->setIcon( getStockIcon( "network-transmit-receive" ) );
113 ui.action_Pause->setIcon( getStockIcon( "media-playback-pause", QStyle::SP_MediaPause ) );
114 ui.action_Remove->setIcon( getStockIcon( "list-remove", QStyle::SP_TrashIcon ) );
115 ui.action_Delete->setIcon( getStockIcon( "edit-delete", QStyle::SP_TrashIcon ) );
116 ui.action_StartAll->setIcon( getStockIcon( "media-playback-start", QStyle::SP_MediaPlay ) );
117 ui.action_PauseAll->setIcon( getStockIcon( "media-playback-pause", QStyle::SP_MediaPause ) );
118 ui.action_Quit->setIcon( getStockIcon( "application-exit" ) );
119 ui.action_SelectAll->setIcon( getStockIcon( "edit-select-all" ) );
120 ui.action_ReverseSortOrder->setIcon( getStockIcon( "view-sort-ascending", QStyle::SP_ArrowDown ) );
121 ui.action_Preferences->setIcon( getStockIcon( "preferences-system" ) );
122 ui.action_Contents->setIcon( getStockIcon( "help-contents", QStyle::SP_DialogHelpButton ) );
123 ui.action_About->setIcon( getStockIcon( "help-about" ) );
125 // ui signals
126 connect( ui.action_Toolbar, SIGNAL(toggled(bool)), this, SLOT(setToolbarVisible(bool)));
127 connect( ui.action_Filterbar, SIGNAL(toggled(bool)), this, SLOT(setFilterbarVisible(bool)));
128 connect( ui.action_Statusbar, SIGNAL(toggled(bool)), this, SLOT(setStatusbarVisible(bool)));
129 connect( ui.action_CompactView, SIGNAL(toggled(bool)), this, SLOT(setCompactView(bool)));
130 connect( ui.action_SortByActivity, SIGNAL(toggled(bool)), this, SLOT(onSortByActivityToggled(bool)));
131 connect( ui.action_SortByAge, SIGNAL(toggled(bool)), this, SLOT(onSortByAgeToggled(bool)));
132 connect( ui.action_SortByETA, SIGNAL(toggled(bool)), this, SLOT(onSortByETAToggled(bool)));
133 connect( ui.action_SortByName, SIGNAL(toggled(bool)), this, SLOT(onSortByNameToggled(bool)));
134 connect( ui.action_SortByProgress, SIGNAL(toggled(bool)), this, SLOT(onSortByProgressToggled(bool)));
135 connect( ui.action_SortByRatio, SIGNAL(toggled(bool)), this, SLOT(onSortByRatioToggled(bool)));
136 connect( ui.action_SortBySize, SIGNAL(toggled(bool)), this, SLOT(onSortBySizeToggled(bool)));
137 connect( ui.action_SortByState, SIGNAL(toggled(bool)), this, SLOT(onSortByStateToggled(bool)));
138 connect( ui.action_ReverseSortOrder, SIGNAL(toggled(bool)), this, SLOT(setSortAscendingPref(bool)));
139 connect( ui.action_Start, SIGNAL(triggered()), this, SLOT(startSelected()));
140 connect( ui.action_Pause, SIGNAL(triggered()), this, SLOT(pauseSelected()));
141 connect( ui.action_Remove, SIGNAL(triggered()), this, SLOT(removeSelected()));
142 connect( ui.action_Delete, SIGNAL(triggered()), this, SLOT(deleteSelected()));
143 connect( ui.action_Verify, SIGNAL(triggered()), this, SLOT(verifySelected()) );
144 connect( ui.action_Announce, SIGNAL(triggered()), this, SLOT(reannounceSelected()) );
145 connect( ui.action_StartAll, SIGNAL(triggered()), this, SLOT(startAll()));
146 connect( ui.action_PauseAll, SIGNAL(triggered()), this, SLOT(pauseAll()));
147 connect( ui.action_AddFile, SIGNAL(triggered()), this, SLOT(openTorrent()));
148 connect( ui.action_AddURL, SIGNAL(triggered()), this, SLOT(openURL()));
149 connect( ui.action_New, SIGNAL(triggered()), this, SLOT(newTorrent()));
150 connect( ui.action_Preferences, SIGNAL(triggered()), this, SLOT(openPreferences()));
151 connect( ui.action_Statistics, SIGNAL(triggered()), myStatsDialog, SLOT(show()));
152 connect( ui.action_Donate, SIGNAL(triggered()), this, SLOT(openDonate()));
153 connect( ui.action_About, SIGNAL(triggered()), myAboutDialog, SLOT(show()));
154 connect( ui.action_Contents, SIGNAL(triggered()), this, SLOT(openHelp()));
155 connect( ui.action_OpenFolder, SIGNAL(triggered()), this, SLOT(openFolder()));
156 connect( ui.action_CopyMagnetToClipboard, SIGNAL(triggered()), this, SLOT(copyMagnetLinkToClipboard()));
157 connect( ui.action_SetLocation, SIGNAL(triggered()), this, SLOT(setLocation()));
158 connect( ui.action_Properties, SIGNAL(triggered()), this, SLOT(openProperties()));
159 connect( ui.action_SessionDialog, SIGNAL(triggered()), mySessionDialog, SLOT(show()));
160 connect( ui.listView, SIGNAL(activated(const QModelIndex&)), ui.action_Properties, SLOT(trigger()));
162 QAction * sep2 = new QAction( this );
163 sep2->setSeparator( true );
164 QAction * sep3 = new QAction( this );
165 sep3->setSeparator( true );
167 // context menu
168 QList<QAction*> actions;
169 actions << ui.action_Properties
170 << ui.action_OpenFolder
171 << sep2
172 << ui.action_Start
173 << ui.action_Announce
174 << ui.action_Pause
175 << ui.action_CopyMagnetToClipboard
176 << sep3
177 << ui.action_Verify
178 << ui.action_SetLocation
179 << sep
180 << ui.action_Remove
181 << ui.action_Delete;
182 addActions( actions );
183 setContextMenuPolicy( Qt::ActionsContextMenu );
185 // signals
186 connect( ui.action_SelectAll, SIGNAL(triggered()), ui.listView, SLOT(selectAll()));
187 connect( ui.action_DeselectAll, SIGNAL(triggered()), ui.listView, SLOT(clearSelection()));
189 connect( &myFilterModel, SIGNAL(rowsInserted(const QModelIndex&,int,int)), this, SLOT(refreshVisibleCount()));
190 connect( &myFilterModel, SIGNAL(rowsRemoved(const QModelIndex&,int,int)), this, SLOT(refreshVisibleCount()));
191 connect( &myFilterModel, SIGNAL(rowsInserted(const QModelIndex&,int,int)), this, SLOT(refreshActionSensitivity()));
192 connect( &myFilterModel, SIGNAL(rowsRemoved(const QModelIndex&,int,int)), this, SLOT(refreshActionSensitivity()));
194 connect( ui.action_Quit, SIGNAL(triggered()), QCoreApplication::instance(), SLOT(quit()) );
196 // torrent view
197 myFilterModel.setSourceModel( &myModel );
198 connect( &myModel, SIGNAL(modelReset()), this, SLOT(onModelReset()));
199 connect( &myModel, SIGNAL(rowsRemoved(const QModelIndex&,int,int)), this, SLOT(onModelReset()));
200 connect( &myModel, SIGNAL(rowsInserted(const QModelIndex&,int,int)), this, SLOT(onModelReset()));
201 connect( &myModel, SIGNAL(dataChanged(const QModelIndex&,const QModelIndex&)), this, SLOT(refreshTrayIcon()));
203 ui.listView->setModel( &myFilterModel );
204 connect( ui.listView->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&,const QItemSelection&)), this, SLOT(refreshActionSensitivity()));
206 QActionGroup * actionGroup = new QActionGroup( this );
207 actionGroup->addAction( ui.action_SortByActivity );
208 actionGroup->addAction( ui.action_SortByAge );
209 actionGroup->addAction( ui.action_SortByETA );
210 actionGroup->addAction( ui.action_SortByName );
211 actionGroup->addAction( ui.action_SortByProgress );
212 actionGroup->addAction( ui.action_SortByRatio );
213 actionGroup->addAction( ui.action_SortBySize );
214 actionGroup->addAction( ui.action_SortByState );
216 QMenu * menu = new QMenu( );
217 menu->addAction( ui.action_AddFile );
218 menu->addAction( ui.action_AddURL );
219 menu->addSeparator( );
220 menu->addAction( ui.action_ShowMainWindow );
221 menu->addAction( ui.action_ShowMessageLog );
222 menu->addAction( ui.action_About );
223 menu->addSeparator( );
224 menu->addAction( ui.action_StartAll );
225 menu->addAction( ui.action_PauseAll );
226 menu->addSeparator( );
227 menu->addAction( ui.action_Quit );
228 myTrayIcon.setContextMenu( menu );
229 myTrayIcon.setIcon( QApplication::windowIcon( ) );
231 connect( &myPrefs, SIGNAL(changed(int)), this, SLOT(refreshPref(int)) );
232 connect( ui.action_ShowMainWindow, SIGNAL(toggled(bool)), this, SLOT(toggleWindows(bool)));
233 connect( &myTrayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
234 this, SLOT(trayActivated(QSystemTrayIcon::ActivationReason)));
236 ui.action_ShowMainWindow->setChecked( !minimized );
237 ui.action_TrayIcon->setChecked( minimized || prefs.getBool( Prefs::SHOW_TRAY_ICON ) );
239 ui.verticalLayout->addWidget( createStatusBar( ) );
240 ui.verticalLayout->insertWidget( 0, myFilterBar = new FilterBar( myPrefs, myModel, myFilterModel ) );
242 QList<int> initKeys;
243 initKeys << Prefs :: MAIN_WINDOW_X
244 << Prefs :: SHOW_TRAY_ICON
245 << Prefs :: SORT_REVERSED
246 << Prefs :: SORT_MODE
247 << Prefs :: FILTERBAR
248 << Prefs :: STATUSBAR
249 << Prefs :: STATUSBAR_STATS
250 << Prefs :: TOOLBAR
251 << Prefs :: ALT_SPEED_LIMIT_ENABLED
252 << Prefs :: COMPACT_VIEW
253 << Prefs :: DSPEED
254 << Prefs :: DSPEED_ENABLED
255 << Prefs :: USPEED
256 << Prefs :: USPEED_ENABLED
257 << Prefs :: RATIO
258 << Prefs :: RATIO_ENABLED;
259 foreach( int key, initKeys )
260 refreshPref( key );
262 connect( &mySession, SIGNAL(sourceChanged()), this, SLOT(onSessionSourceChanged()) );
263 connect( &mySession, SIGNAL(statsUpdated()), this, SLOT(refreshStatusBar()) );
264 connect( &mySession, SIGNAL(dataReadProgress()), this, SLOT(dataReadProgress()) );
265 connect( &mySession, SIGNAL(dataSendProgress()), this, SLOT(dataSendProgress()) );
266 connect( &mySession, SIGNAL(httpAuthenticationRequired()), this, SLOT(wrongAuthentication()) );
268 if( mySession.isServer( ) )
269 myNetworkLabel->hide( );
270 else {
271 connect( &myNetworkTimer, SIGNAL(timeout()), this, SLOT(onNetworkTimer()));
272 myNetworkTimer.start( 1000 );
275 refreshActionSensitivity( );
276 refreshTrayIcon( );
277 refreshStatusBar( );
278 refreshTitle( );
279 refreshVisibleCount( );
282 TrMainWindow :: ~TrMainWindow( )
286 /****
287 *****
288 ****/
290 void
291 TrMainWindow :: closeEvent( QCloseEvent * event )
293 // if they're using a tray icon, close to the tray
294 // instead of exiting
295 if( !myPrefs.getBool( Prefs :: SHOW_TRAY_ICON ) )
296 event->accept( );
297 else {
298 toggleWindows( false );
299 event->ignore( );
303 /****
304 *****
305 ****/
307 void
308 TrMainWindow :: onSessionSourceChanged( )
310 myModel.clear( );
313 void
314 TrMainWindow :: onModelReset( )
316 refreshTitle( );
317 refreshVisibleCount( );
318 refreshActionSensitivity( );
319 refreshStatusBar( );
320 refreshTrayIcon( );
323 /****
324 *****
325 ****/
327 #define PREF_VARIANTS_KEY "pref-variants-list"
329 void
330 TrMainWindow :: onSetPrefs( )
332 const QVariantList p = sender()->property( PREF_VARIANTS_KEY ).toList( );
333 assert( ( p.size( ) % 2 ) == 0 );
334 for( int i=0, n=p.size(); i<n; i+=2 )
335 myPrefs.set( p[i].toInt(), p[i+1] );
338 void
339 TrMainWindow :: onSetPrefs( bool isChecked )
341 if( isChecked )
342 onSetPrefs( );
345 #define SHOW_KEY "show-mode"
347 QWidget *
348 TrMainWindow :: createStatusBar( )
350 QMenu * m;
351 QLabel * l;
352 QHBoxLayout * h;
353 QPushButton * p;
354 QActionGroup * a;
355 const int i = style( )->pixelMetric( QStyle::PM_SmallIconSize, 0, this );
356 const QSize smallIconSize( i, i );
358 QWidget * top = myStatusBar = new QWidget;
359 h = new QHBoxLayout( top );
360 h->setContentsMargins( HIG::PAD_SMALL, HIG::PAD_SMALL, HIG::PAD_SMALL, HIG::PAD_SMALL );
361 h->setSpacing( HIG::PAD_SMALL );
363 p = myOptionsButton = new TrIconPushButton( this );
364 p->setIcon( QIcon( ":/icons/utilities.png" ) );
365 p->setIconSize( QPixmap( ":/icons/utilities.png" ).size() );
366 p->setFlat( true );
367 p->setMenu( createOptionsMenu( ) );
368 h->addWidget( p );
370 p = myAltSpeedButton = new QPushButton( this );
371 p->setIcon( myPrefs.get<bool>(Prefs::ALT_SPEED_LIMIT_ENABLED) ? mySpeedModeOnIcon : mySpeedModeOffIcon );
372 p->setIconSize( QPixmap( ":/icons/alt-limit-on.png" ).size() );
373 p->setCheckable( true );
374 p->setFixedWidth( p->height() );
375 p->setFlat( true );
376 h->addWidget( p );
377 connect( p, SIGNAL(clicked()), this, SLOT(toggleSpeedMode()));
379 l = myNetworkLabel = new QLabel;
380 h->addWidget( l );
382 h->addStretch( 1 );
384 l = myVisibleCountLabel = new QLabel( this );
385 h->addWidget( l );
387 h->addStretch( 1 );
389 a = new QActionGroup( this );
390 a->addAction( ui.action_TotalRatio );
391 a->addAction( ui.action_TotalTransfer );
392 a->addAction( ui.action_SessionRatio );
393 a->addAction( ui.action_SessionTransfer );
394 m = new QMenu( );
395 m->addAction( ui.action_TotalRatio );
396 m->addAction( ui.action_TotalTransfer );
397 m->addAction( ui.action_SessionRatio );
398 m->addAction( ui.action_SessionTransfer );
399 connect( ui.action_TotalRatio, SIGNAL(triggered()), this, SLOT(showTotalRatio()));
400 connect( ui.action_TotalTransfer, SIGNAL(triggered()), this, SLOT(showTotalTransfer()));
401 connect( ui.action_SessionRatio, SIGNAL(triggered()), this, SLOT(showSessionRatio()));
402 connect( ui.action_SessionTransfer, SIGNAL(triggered()), this, SLOT(showSessionTransfer()));
403 p = myStatsModeButton = new TrIconPushButton( this );
404 p->setIcon( QIcon( ":/icons/ratio.png" ) );
405 p->setIconSize( QPixmap( ":/icons/ratio.png" ).size() );
406 p->setFlat( true );
407 p->setMenu( m );
408 h->addWidget( p );
409 l = myStatsLabel = new QLabel( this );
410 h->addWidget( l );
412 h->addStretch( 1 );
414 l = myDownloadSpeedLabel = new QLabel( this );
415 const int minimumSpeedWidth = l->fontMetrics().width( Formatter::speedToString(Speed::fromKBps(999.99)));
416 l->setMinimumWidth( minimumSpeedWidth );
417 l->setAlignment( Qt::AlignRight|Qt::AlignVCenter );
418 h->addWidget( l );
419 l = new QLabel( this );
420 l->setPixmap( getStockIcon( "go-down", QStyle::SP_ArrowDown ).pixmap( smallIconSize ) );
421 h->addWidget( l );
423 h->addStretch( 1 );
425 l = myUploadSpeedLabel = new QLabel;
426 l->setMinimumWidth( minimumSpeedWidth );
427 l->setAlignment( Qt::AlignRight|Qt::AlignVCenter );
428 h->addWidget( l );
429 l = new QLabel;
430 l->setPixmap( getStockIcon( "go-up", QStyle::SP_ArrowUp ).pixmap( smallIconSize ) );
431 h->addWidget( l );
433 return top;
436 QMenu *
437 TrMainWindow :: createOptionsMenu( )
439 QMenu * menu;
440 QMenu * sub;
441 QAction * a;
442 QActionGroup * g;
444 QList<int> stockSpeeds;
445 stockSpeeds << 5 << 10 << 20 << 30 << 40 << 50 << 75 << 100 << 150 << 200 << 250 << 500 << 750;
446 QList<double> stockRatios;
447 stockRatios << 0.25 << 0.50 << 0.75 << 1 << 1.5 << 2 << 3;
449 menu = new QMenu;
450 sub = menu->addMenu( tr( "Limit Download Speed" ) );
451 int currentVal = myPrefs.get<int>( Prefs::DSPEED );
452 g = new QActionGroup( this );
453 a = myDlimitOffAction = sub->addAction( tr( "Unlimited" ) );
454 a->setCheckable( true );
455 a->setProperty( PREF_VARIANTS_KEY, QVariantList() << Prefs::DSPEED_ENABLED << false );
456 g->addAction( a );
457 connect( a, SIGNAL(triggered(bool)), this, SLOT(onSetPrefs(bool)) );
458 a = myDlimitOnAction = sub->addAction( tr( "Limited at %1" ).arg( Formatter::speedToString( Speed::fromKBps( currentVal ) ) ) );
459 a->setCheckable( true );
460 a->setProperty( PREF_VARIANTS_KEY, QVariantList() << Prefs::DSPEED << currentVal << Prefs::DSPEED_ENABLED << true );
461 g->addAction( a );
462 connect( a, SIGNAL(triggered(bool)), this, SLOT(onSetPrefs(bool)) );
463 sub->addSeparator( );
464 foreach( int i, stockSpeeds ) {
465 a = sub->addAction( Formatter::speedToString( Speed::fromKBps( i ) ) );
466 a->setProperty( PREF_VARIANTS_KEY, QVariantList() << Prefs::DSPEED << i << Prefs::DSPEED_ENABLED << true );
467 connect( a, SIGNAL(triggered(bool)), this, SLOT(onSetPrefs()));
470 sub = menu->addMenu( tr( "Limit Upload Speed" ) );
471 currentVal = myPrefs.get<int>( Prefs::USPEED );
472 g = new QActionGroup( this );
473 a = myUlimitOffAction = sub->addAction( tr( "Unlimited" ) );
474 a->setCheckable( true );
475 a->setProperty( PREF_VARIANTS_KEY, QVariantList() << Prefs::USPEED_ENABLED << false );
476 g->addAction( a );
477 connect( a, SIGNAL(triggered(bool)), this, SLOT(onSetPrefs(bool)) );
478 a = myUlimitOnAction = sub->addAction( tr( "Limited at %1" ).arg( Formatter::speedToString( Speed::fromKBps( currentVal ) ) ) );
479 a->setCheckable( true );
480 a->setProperty( PREF_VARIANTS_KEY, QVariantList() << Prefs::USPEED << currentVal << Prefs::USPEED_ENABLED << true );
481 g->addAction( a );
482 connect( a, SIGNAL(triggered(bool)), this, SLOT(onSetPrefs(bool)) );
483 sub->addSeparator( );
484 foreach( int i, stockSpeeds ) {
485 a = sub->addAction( Formatter::speedToString( Speed::fromKBps( i ) ) );
486 a->setProperty( PREF_VARIANTS_KEY, QVariantList() << Prefs::USPEED << i << Prefs::USPEED_ENABLED << true );
487 connect( a, SIGNAL(triggered(bool)), this, SLOT(onSetPrefs()));
490 menu->addSeparator( );
491 sub = menu->addMenu( tr( "Stop Seeding at Ratio" ) );
493 double d = myPrefs.get<double>( Prefs::RATIO );
494 g = new QActionGroup( this );
495 a = myRatioOffAction = sub->addAction( tr( "Seed Forever" ) );
496 a->setCheckable( true );
497 a->setProperty( PREF_VARIANTS_KEY, QVariantList() << Prefs::RATIO_ENABLED << false );
498 g->addAction( a );
499 connect( a, SIGNAL(triggered(bool)), this, SLOT(onSetPrefs(bool)) );
500 a = myRatioOnAction = sub->addAction( tr( "Stop at Ratio (%1)" ).arg( Formatter::ratioToString( d ) ) );
501 a->setCheckable( true );
502 a->setProperty( PREF_VARIANTS_KEY, QVariantList() << Prefs::RATIO << d << Prefs::RATIO_ENABLED << true );
503 g->addAction( a );
504 connect( a, SIGNAL(triggered(bool)), this, SLOT(onSetPrefs(bool)) );
505 sub->addSeparator( );
506 foreach( double i, stockRatios ) {
507 a = sub->addAction( Formatter::ratioToString( i ) );
508 a->setProperty( PREF_VARIANTS_KEY, QVariantList() << Prefs::RATIO << i << Prefs::RATIO_ENABLED << true );
509 connect( a, SIGNAL(triggered(bool)), this, SLOT(onSetPrefs()));
512 return menu;
515 /****
516 *****
517 ****/
519 void
520 TrMainWindow :: setSortPref( int i )
522 myPrefs.set( Prefs::SORT_MODE, SortMode( i ) );
524 void TrMainWindow :: onSortByActivityToggled ( bool b ) { if( b ) setSortPref( SortMode::SORT_BY_ACTIVITY ); }
525 void TrMainWindow :: onSortByAgeToggled ( bool b ) { if( b ) setSortPref( SortMode::SORT_BY_AGE ); }
526 void TrMainWindow :: onSortByETAToggled ( bool b ) { if( b ) setSortPref( SortMode::SORT_BY_ETA ); }
527 void TrMainWindow :: onSortByNameToggled ( bool b ) { if( b ) setSortPref( SortMode::SORT_BY_NAME ); }
528 void TrMainWindow :: onSortByProgressToggled ( bool b ) { if( b ) setSortPref( SortMode::SORT_BY_PROGRESS ); }
529 void TrMainWindow :: onSortByRatioToggled ( bool b ) { if( b ) setSortPref( SortMode::SORT_BY_RATIO ); }
530 void TrMainWindow :: onSortBySizeToggled ( bool b ) { if( b ) setSortPref( SortMode::SORT_BY_SIZE ); }
531 void TrMainWindow :: onSortByStateToggled ( bool b ) { if( b ) setSortPref( SortMode::SORT_BY_STATE ); }
533 void
534 TrMainWindow :: setSortAscendingPref( bool b )
536 myPrefs.set( Prefs::SORT_REVERSED, b );
539 /****
540 *****
541 ****/
543 void
544 TrMainWindow :: onPrefsDestroyed( )
546 myPrefsDialog = 0;
549 void
550 TrMainWindow :: openPreferences( )
552 if( myPrefsDialog == 0 ) {
553 myPrefsDialog = new PrefsDialog( mySession, myPrefs, this );
554 connect( myPrefsDialog, SIGNAL(destroyed(QObject*)), this, SLOT(onPrefsDestroyed()));
557 myPrefsDialog->show( );
560 void
561 TrMainWindow :: onDetailsDestroyed( )
563 myDetailsDialog = 0;
566 void
567 TrMainWindow :: openProperties( )
569 if( myDetailsDialog == 0 ) {
570 myDetailsDialog = new Details( mySession, myPrefs, myModel, this );
571 connect( myDetailsDialog, SIGNAL(destroyed(QObject*)), this, SLOT(onDetailsDestroyed()));
574 myDetailsDialog->setIds( getSelectedTorrents( ) );
575 myDetailsDialog->show( );
578 void
579 TrMainWindow :: setLocation( )
581 QDialog * d = new RelocateDialog( mySession, myModel, getSelectedTorrents(), this );
582 d->show( );
585 void
586 TrMainWindow :: openFolder( )
588 const int torrentId( *getSelectedTorrents().begin() );
589 const Torrent * tor( myModel.getTorrentFromId( torrentId ) );
590 const QString path( tor->getPath( ) );
591 QDesktopServices :: openUrl( QUrl::fromLocalFile( path ) );
594 void
595 TrMainWindow :: copyMagnetLinkToClipboard( )
597 const int id( *getSelectedTorrents().begin() );
598 mySession.copyMagnetLinkToClipboard( id );
601 void
602 TrMainWindow :: openDonate( )
604 QDesktopServices :: openUrl( QUrl( "http://www.transmissionbt.com/donate.php" ) );
607 void
608 TrMainWindow :: openHelp( )
610 const char * fmt = "http://www.transmissionbt.com/help/gtk/%d.%dx";
611 int major, minor;
612 sscanf( SHORT_VERSION_STRING, "%d.%d", &major, &minor );
613 char url[128];
614 tr_snprintf( url, sizeof( url ), fmt, major, minor/10 );
615 QDesktopServices :: openUrl( QUrl( url ) );
618 void
619 TrMainWindow :: refreshTitle( )
621 QString title( "Transmission" );
622 const QUrl url( mySession.getRemoteUrl( ) );
623 if( !url.isEmpty() )
624 title += tr( " - %1:%2" ).arg( url.host() ).arg( url.port() );
625 setWindowTitle( title );
628 void
629 TrMainWindow :: refreshVisibleCount( )
631 const int visibleCount( myFilterModel.rowCount( ) );
632 const int totalCount( visibleCount + myFilterModel.hiddenRowCount( ) );
633 QString str;
634 if( visibleCount == totalCount )
635 str = tr( "%Ln Torrent(s)", 0, totalCount );
636 else
637 str = tr( "%L1 of %Ln Torrent(s)", 0, totalCount ).arg( visibleCount );
638 myVisibleCountLabel->setText( str );
639 myVisibleCountLabel->setVisible( totalCount > 0 );
642 void
643 TrMainWindow :: refreshTrayIcon( )
645 Speed u, d;
646 const QString idle = tr( "Idle" );
648 foreach( int id, myModel.getIds( ) ) {
649 const Torrent * tor = myModel.getTorrentFromId( id );
650 u += tor->uploadSpeed( );
651 d += tor->downloadSpeed( );
654 myTrayIcon.setToolTip( tr( "Transmission\nUp: %1\nDown: %2" )
655 .arg( u.isZero() ? idle : Formatter::speedToString( u ) )
656 .arg( d.isZero() ? idle : Formatter::speedToString( d ) ) );
659 void
660 TrMainWindow :: refreshStatusBar( )
662 const Speed up( myModel.getUploadSpeed( ) );
663 const Speed down( myModel.getDownloadSpeed( ) );
664 myUploadSpeedLabel->setText( Formatter:: speedToString( up ) );
665 myDownloadSpeedLabel->setText( Formatter:: speedToString( down ) );
667 myNetworkLabel->setVisible( !mySession.isServer( ) );
669 const QString mode( myPrefs.getString( Prefs::STATUSBAR_STATS ) );
670 QString str;
672 if( mode == "session-ratio" )
674 str = tr( "Ratio: %1" ).arg( Formatter:: ratioToString( mySession.getStats().ratio ) );
676 else if( mode == "session-transfer" )
678 const tr_session_stats& stats( mySession.getStats( ) );
679 str = tr( "Down: %1, Up: %2" ).arg( Formatter:: sizeToString( stats.downloadedBytes ) )
680 .arg( Formatter:: sizeToString( stats.uploadedBytes ) );
682 else if( mode == "total-transfer" )
684 const tr_session_stats& stats( mySession.getCumulativeStats( ) );
685 str = tr( "Down: %1, Up: %2" ).arg( Formatter:: sizeToString( stats.downloadedBytes ) )
686 .arg( Formatter:: sizeToString( stats.uploadedBytes ) );
688 else // default is "total-ratio"
690 str = tr( "Ratio: %1" ).arg( Formatter:: ratioToString( mySession.getCumulativeStats().ratio ) );
693 myStatsLabel->setText( str );
696 void
697 TrMainWindow :: refreshActionSensitivity( )
699 int selected( 0 );
700 int paused( 0 );
701 int selectedAndPaused( 0 );
702 int canAnnounce( 0 );
703 const QAbstractItemModel * model( ui.listView->model( ) );
704 const QItemSelectionModel * selectionModel( ui.listView->selectionModel( ) );
705 const int rowCount( model->rowCount( ) );
707 // count how many torrents are selected, paused, etc
708 for( int row=0; row<rowCount; ++row ) {
709 const QModelIndex modelIndex( model->index( row, 0 ) );
710 assert( model == modelIndex.model( ) );
711 const Torrent * tor( model->data( modelIndex, TorrentModel::TorrentRole ).value<const Torrent*>( ) );
712 if( tor ) {
713 const bool isSelected( selectionModel->isSelected( modelIndex ) );
714 const bool isPaused( tor->isPaused( ) );
715 if( isSelected )
716 ++selected;
717 if( isPaused )
718 ++ paused;
719 if( isSelected && isPaused )
720 ++selectedAndPaused;
721 if( tor->canManualAnnounce( ) )
722 ++canAnnounce;
726 const bool haveSelection( selected > 0 );
727 ui.action_Verify->setEnabled( haveSelection );
728 ui.action_Remove->setEnabled( haveSelection );
729 ui.action_Delete->setEnabled( haveSelection );
730 ui.action_Properties->setEnabled( haveSelection );
731 ui.action_DeselectAll->setEnabled( haveSelection );
732 ui.action_SetLocation->setEnabled( haveSelection );
734 const bool oneSelection( selected == 1 );
735 ui.action_OpenFolder->setEnabled( oneSelection && mySession.isLocal( ) );
736 ui.action_CopyMagnetToClipboard->setEnabled( oneSelection );
738 ui.action_SelectAll->setEnabled( selected < rowCount );
739 ui.action_StartAll->setEnabled( paused > 0 );
740 ui.action_PauseAll->setEnabled( paused < rowCount );
741 ui.action_Start->setEnabled( selectedAndPaused > 0 );
742 ui.action_Pause->setEnabled( selectedAndPaused < selected );
743 ui.action_Announce->setEnabled( selected > 0 && ( canAnnounce == selected ) );
745 if( myDetailsDialog )
746 myDetailsDialog->setIds( getSelectedTorrents( ) );
753 void
754 TrMainWindow :: clearSelection( )
756 ui.action_DeselectAll->trigger( );
759 QSet<int>
760 TrMainWindow :: getSelectedTorrents( ) const
762 QSet<int> ids;
764 foreach( QModelIndex index, ui.listView->selectionModel( )->selectedRows( ) )
766 const Torrent * tor( index.data( TorrentModel::TorrentRole ).value<const Torrent*>( ) );
767 ids.insert( tor->id( ) );
770 return ids;
773 void
774 TrMainWindow :: startSelected( )
776 mySession.startTorrents( getSelectedTorrents( ) );
778 void
779 TrMainWindow :: pauseSelected( )
781 mySession.pauseTorrents( getSelectedTorrents( ) );
783 void
784 TrMainWindow :: startAll( )
786 mySession.startTorrents( );
788 void
789 TrMainWindow :: pauseAll( )
791 mySession.pauseTorrents( );
793 void
794 TrMainWindow :: removeSelected( )
796 removeTorrents( false );
798 void
799 TrMainWindow :: deleteSelected( )
801 removeTorrents( true );
803 void
804 TrMainWindow :: verifySelected( )
806 mySession.verifyTorrents( getSelectedTorrents( ) );
808 void
809 TrMainWindow :: reannounceSelected( )
811 mySession.reannounceTorrents( getSelectedTorrents( ) );
818 void TrMainWindow :: showTotalRatio ( ) { myPrefs.set( Prefs::STATUSBAR_STATS, "total-ratio"); }
819 void TrMainWindow :: showTotalTransfer ( ) { myPrefs.set( Prefs::STATUSBAR_STATS, "total-transfer"); }
820 void TrMainWindow :: showSessionRatio ( ) { myPrefs.set( Prefs::STATUSBAR_STATS, "session-ratio"); }
821 void TrMainWindow :: showSessionTransfer ( ) { myPrefs.set( Prefs::STATUSBAR_STATS, "session-transfer"); }
827 void
828 TrMainWindow :: setCompactView( bool visible )
830 myPrefs.set( Prefs :: COMPACT_VIEW, visible );
832 void
833 TrMainWindow :: toggleSpeedMode( )
835 myPrefs.toggleBool( Prefs :: ALT_SPEED_LIMIT_ENABLED );
837 void
838 TrMainWindow :: setToolbarVisible( bool visible )
840 myPrefs.set( Prefs::TOOLBAR, visible );
842 void
843 TrMainWindow :: setFilterbarVisible( bool visible )
845 myPrefs.set( Prefs::FILTERBAR, visible );
847 void
848 TrMainWindow :: setStatusbarVisible( bool visible )
850 myPrefs.set( Prefs::STATUSBAR, visible );
857 void
858 TrMainWindow :: toggleWindows( bool doShow )
860 if( !doShow )
862 hide( );
864 else
866 if ( !isVisible( ) ) show( );
867 if ( isMinimized( ) ) showNormal( );
868 //activateWindow( );
869 raise( );
870 QApplication::setActiveWindow( this );
874 void
875 TrMainWindow :: trayActivated( QSystemTrayIcon::ActivationReason reason )
877 if( reason == QSystemTrayIcon::Trigger )
879 if( isMinimized ( ) )
880 toggleWindows( true );
881 else
882 ui.action_ShowMainWindow->toggle( );
887 void
888 TrMainWindow :: refreshPref( int key )
890 bool b;
891 int i;
892 QString str;
894 switch( key )
896 case Prefs::STATUSBAR_STATS:
897 str = myPrefs.getString( key );
898 ui.action_TotalRatio->setChecked ( str == "total-ratio" );
899 ui.action_TotalTransfer->setChecked ( str == "total-transfer" );
900 ui.action_SessionRatio->setChecked ( str == "session-ratio" );
901 ui.action_SessionTransfer->setChecked( str == "session-transfer" );
902 refreshStatusBar( );
903 break;
905 case Prefs::SORT_REVERSED:
906 ui.action_ReverseSortOrder->setChecked( myPrefs.getBool( key ) );
907 break;
909 case Prefs::SORT_MODE:
910 i = myPrefs.get<SortMode>(key).mode( );
911 ui.action_SortByActivity->setChecked ( i == SortMode::SORT_BY_ACTIVITY );
912 ui.action_SortByAge->setChecked ( i == SortMode::SORT_BY_AGE );
913 ui.action_SortByETA->setChecked ( i == SortMode::SORT_BY_ETA );
914 ui.action_SortByName->setChecked ( i == SortMode::SORT_BY_NAME );
915 ui.action_SortByProgress->setChecked ( i == SortMode::SORT_BY_PROGRESS );
916 ui.action_SortByRatio->setChecked ( i == SortMode::SORT_BY_RATIO );
917 ui.action_SortBySize->setChecked ( i == SortMode::SORT_BY_SIZE );
918 ui.action_SortByState->setChecked ( i == SortMode::SORT_BY_STATE );
919 break;
921 case Prefs::DSPEED_ENABLED:
922 (myPrefs.get<bool>(key) ? myDlimitOnAction : myDlimitOffAction)->setChecked( true );
923 break;
925 case Prefs::DSPEED:
926 myDlimitOnAction->setText( tr( "Limited at %1" ).arg( Formatter::speedToString( Speed::fromKBps( myPrefs.get<int>(key) ) ) ) );
927 break;
929 case Prefs::USPEED_ENABLED:
930 (myPrefs.get<bool>(key) ? myUlimitOnAction : myUlimitOffAction)->setChecked( true );
931 break;
933 case Prefs::USPEED:
934 myUlimitOnAction->setText( tr( "Limited at %1" ).arg( Formatter::speedToString( Speed::fromKBps( myPrefs.get<int>(key) ) ) ) );
935 break;
937 case Prefs::RATIO_ENABLED:
938 (myPrefs.get<bool>(key) ? myRatioOnAction : myRatioOffAction)->setChecked( true );
939 break;
941 case Prefs::RATIO:
942 myRatioOnAction->setText( tr( "Stop at Ratio (%1)" ).arg( Formatter::ratioToString( myPrefs.get<double>(key) ) ) );
943 break;
945 case Prefs::FILTERBAR:
946 b = myPrefs.getBool( key );
947 myFilterBar->setVisible( b );
948 ui.action_Filterbar->setChecked( b );
949 break;
951 case Prefs::STATUSBAR:
952 b = myPrefs.getBool( key );
953 myStatusBar->setVisible( b );
954 ui.action_Statusbar->setChecked( b );
955 break;
957 case Prefs::TOOLBAR:
958 b = myPrefs.getBool( key );
959 ui.toolBar->setVisible( b );
960 ui.action_Toolbar->setChecked( b );
961 break;
963 case Prefs::SHOW_TRAY_ICON:
964 b = myPrefs.getBool( key );
965 ui.action_TrayIcon->setChecked( b );
966 myTrayIcon.setVisible( b );
967 refreshTrayIcon( );
968 break;
970 case Prefs::COMPACT_VIEW: {
971 QItemSelectionModel * selectionModel( ui.listView->selectionModel( ) );
972 const QItemSelection selection( selectionModel->selection( ) );
973 const QModelIndex currentIndex( selectionModel->currentIndex( ) );
974 b = myPrefs.getBool( key );
975 ui.action_CompactView->setChecked( b );
976 ui.listView->setItemDelegate( b ? myTorrentDelegateMin : myTorrentDelegate );
977 selectionModel->clear( );
978 ui.listView->reset( ); // force the rows to resize
979 selectionModel->select( selection, QItemSelectionModel::Select );
980 selectionModel->setCurrentIndex( currentIndex, QItemSelectionModel::NoUpdate );
981 break;
984 case Prefs::MAIN_WINDOW_X:
985 case Prefs::MAIN_WINDOW_Y:
986 case Prefs::MAIN_WINDOW_WIDTH:
987 case Prefs::MAIN_WINDOW_HEIGHT:
988 setGeometry( myPrefs.getInt( Prefs::MAIN_WINDOW_X ),
989 myPrefs.getInt( Prefs::MAIN_WINDOW_Y ),
990 myPrefs.getInt( Prefs::MAIN_WINDOW_WIDTH ),
991 myPrefs.getInt( Prefs::MAIN_WINDOW_HEIGHT ) );
992 break;
994 case Prefs :: ALT_SPEED_LIMIT_ENABLED:
995 case Prefs :: ALT_SPEED_LIMIT_UP:
996 case Prefs :: ALT_SPEED_LIMIT_DOWN: {
997 b = myPrefs.getBool( Prefs :: ALT_SPEED_LIMIT_ENABLED );
998 myAltSpeedButton->setChecked( b );
999 myAltSpeedButton->setIcon( b ? mySpeedModeOnIcon : mySpeedModeOffIcon );
1000 const QString fmt = b ? tr( "Click to disable Temporary Speed Limits\n(%1 down, %2 up)" )
1001 : tr( "Click to enable Temporary Speed Limits\n(%1 down, %2 up)" );
1002 const Speed d = Speed::fromKBps( myPrefs.getInt( Prefs::ALT_SPEED_LIMIT_DOWN ) );
1003 const Speed u = Speed::fromKBps( myPrefs.getInt( Prefs::ALT_SPEED_LIMIT_UP ) );
1004 myAltSpeedButton->setToolTip( fmt.arg( Formatter::speedToString( d ) )
1005 .arg( Formatter::speedToString( u ) ) );
1006 break;
1009 default:
1010 break;
1014 /***
1015 ****
1016 ***/
1018 void
1019 TrMainWindow :: newTorrent( )
1021 MakeDialog * dialog = new MakeDialog( mySession, this );
1022 dialog->show( );
1025 void
1026 TrMainWindow :: openTorrent( )
1028 QFileDialog * myFileDialog;
1029 myFileDialog = new QFileDialog( this,
1030 tr( "Add Torrent" ),
1031 myPrefs.getString( Prefs::OPEN_DIALOG_FOLDER ),
1032 tr( "Torrent Files (*.torrent);;All Files (*.*)" ) );
1033 myFileDialog->setFileMode( QFileDialog::ExistingFiles );
1035 QCheckBox * button = new QCheckBox( tr( "Show &options dialog" ) );
1036 button->setChecked( myPrefs.getBool( Prefs::OPTIONS_PROMPT ) );
1037 QGridLayout * layout = dynamic_cast<QGridLayout*>(myFileDialog->layout());
1038 layout->addWidget( button, layout->rowCount( ), 0, 1, -1, Qt::AlignLeft );
1039 myFileDialogOptionsCheck = button;
1041 connect( myFileDialog, SIGNAL(filesSelected(const QStringList&)),
1042 this, SLOT(addTorrents(const QStringList&)));
1044 myFileDialog->show( );
1047 void
1048 TrMainWindow :: openURL( )
1050 QString tmp;
1051 openURL( tmp );
1054 void
1055 TrMainWindow :: openURL( QString url )
1057 bool ok;
1058 const QString key = QInputDialog::getText( this,
1059 tr( "Add URL or Magnet Link" ),
1060 tr( "Add URL or Magnet Link" ),
1061 QLineEdit::Normal,
1062 url,
1063 &ok );
1064 if( ok && !key.isEmpty( ) )
1065 mySession.addTorrent( key );
1068 void
1069 TrMainWindow :: addTorrents( const QStringList& filenames )
1071 foreach( const QString& filename, filenames )
1072 addTorrent( filename );
1075 void
1076 TrMainWindow :: addTorrent( const QString& filename )
1078 if( !myFileDialogOptionsCheck->isChecked( ) ) {
1079 mySession.addTorrent( filename );
1080 QApplication :: alert ( this );
1081 } else {
1082 Options * o = new Options( mySession, myPrefs, filename, this );
1083 o->show( );
1084 QApplication :: alert( o );
1088 void
1089 TrMainWindow :: removeTorrents( const bool deleteFiles )
1091 QSet<int> ids;
1092 QMessageBox msgBox( this );
1093 QString primary_text, secondary_text;
1094 int incomplete = 0;
1095 int connected = 0;
1096 int count;
1098 foreach( QModelIndex index, ui.listView->selectionModel( )->selectedRows( ) )
1100 const Torrent * tor( index.data( TorrentModel::TorrentRole ).value<const Torrent*>( ) );
1101 ids.insert( tor->id( ) );
1102 if( tor->connectedPeers( ) )
1103 ++connected;
1104 if( !tor->isDone( ) )
1105 ++incomplete;
1108 if( ids.isEmpty() )
1109 return;
1110 count = ids.size();
1112 if( !deleteFiles )
1114 primary_text = ( count == 1 )
1115 ? tr( "Remove torrent?" )
1116 : tr( "Remove %1 torrents?" ).arg( count );
1118 else
1120 primary_text = ( count == 1 )
1121 ? tr( "Delete this torrent's downloaded files?" )
1122 : tr( "Delete these %1 torrents' downloaded files?" ).arg( count );
1125 if( !incomplete && !connected )
1127 secondary_text = ( count == 1 )
1128 ? tr( "Once removed, continuing the transfer will require the torrent file or magnet link." )
1129 : tr( "Once removed, continuing the transfers will require the torrent files or magnet links." );
1131 else if( count == incomplete )
1133 secondary_text = ( count == 1 )
1134 ? tr( "This torrent has not finished downloading." )
1135 : tr( "These torrents have not finished downloading." );
1137 else if( count == connected )
1139 secondary_text = ( count == 1 )
1140 ? tr( "This torrent is connected to peers." )
1141 : tr( "These torrents are connected to peers." );
1143 else
1145 if( connected )
1147 secondary_text = ( connected == 1 )
1148 ? tr( "One of these torrents is connected to peers." )
1149 : tr( "Some of these torrents are connected to peers." );
1152 if( connected && incomplete )
1154 secondary_text += "\n";
1157 if( incomplete )
1159 secondary_text += ( incomplete == 1 )
1160 ? tr( "One of these torrents has not finished downloading." )
1161 : tr( "Some of these torrents have not finished downloading." );
1165 msgBox.setWindowTitle( QString(" ") );
1166 msgBox.setText( QString( "<big><b>%1</big></b>" ).arg( primary_text ) );
1167 msgBox.setInformativeText( secondary_text );
1168 msgBox.setStandardButtons( QMessageBox::Ok | QMessageBox::Cancel );
1169 msgBox.setDefaultButton( QMessageBox::Cancel );
1170 msgBox.setIcon( QMessageBox::Question );
1171 /* hack needed to keep the dialog from being too narrow */
1172 QGridLayout* layout = (QGridLayout*)msgBox.layout();
1173 QSpacerItem* spacer = new QSpacerItem( 450, 0, QSizePolicy::Minimum, QSizePolicy::Expanding );
1174 layout->addItem( spacer, layout->rowCount(), 0, 1, layout->columnCount() );
1176 if( msgBox.exec() == QMessageBox::Ok )
1178 ui.listView->selectionModel()->clear();
1179 mySession.removeTorrents( ids, deleteFiles );
1183 /***
1184 ****
1185 ***/
1187 void
1188 TrMainWindow :: updateNetworkIcon( )
1190 const time_t now = time( NULL );
1191 const int period = 3;
1192 const bool isSending = now - myLastSendTime <= period;
1193 const bool isReading = now - myLastReadTime <= period;
1194 const char * key;
1196 if( isSending && isReading )
1197 key = "network-transmit-receive";
1198 else if( isSending )
1199 key = "network-transmit";
1200 else if( isReading )
1201 key = "network-receive";
1202 else
1203 key = "network-idle";
1205 QIcon icon = getStockIcon( key, QStyle::SP_DriveNetIcon );
1206 QPixmap pixmap = icon.pixmap ( 16, 16 );
1207 myNetworkLabel->setPixmap( pixmap );
1208 myNetworkLabel->setToolTip( isSending || isReading
1209 ? tr( "Transmission server is responding" )
1210 : tr( "Last response from server was %1 ago" ).arg( Formatter::timeToString( now-std::max(myLastReadTime,myLastSendTime))));
1213 void
1214 TrMainWindow :: onNetworkTimer( )
1216 updateNetworkIcon( );
1219 void
1220 TrMainWindow :: dataReadProgress( )
1222 myLastReadTime = time( NULL );
1223 updateNetworkIcon( );
1226 void
1227 TrMainWindow :: dataSendProgress( )
1229 myLastSendTime = time( NULL );
1230 updateNetworkIcon( );
1233 void
1234 TrMainWindow :: wrongAuthentication( )
1236 mySession.stop( );
1237 mySessionDialog->show( );
1240 /***
1241 ****
1242 ***/
1244 void
1245 TrMainWindow :: dragEnterEvent( QDragEnterEvent * event )
1247 const QMimeData * mime = event->mimeData( );
1249 if( mime->hasFormat("application/x-bittorrent")
1250 || mime->text().trimmed().endsWith(".torrent", Qt::CaseInsensitive) )
1251 event->acceptProposedAction();
1254 void
1255 TrMainWindow :: dropEvent( QDropEvent * event )
1257 QString key = event->mimeData()->text().trimmed();
1259 const QUrl url( key );
1260 if( url.scheme() == "file" )
1261 key = QUrl::fromPercentEncoding( url.path().toUtf8( ) );
1263 dynamic_cast<MyApp*>(QApplication::instance())->addTorrent( key );