transmission: update from 2.13 to 2.22
[tomato.git] / release / src / router / transmission / qt / mainwin.cc
blobf351a4d93b99aff51804b6458a53d248fb2b0884
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 11744 2011-01-21 21:51:50Z jordan $
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 "add-data.h"
24 #include "app.h"
25 #include "details.h"
26 #include "filterbar.h"
27 #include "filters.h"
28 #include "formatter.h"
29 #include "hig.h"
30 #include "mainwin.h"
31 #include "make-dialog.h"
32 #include "options.h"
33 #include "prefs.h"
34 #include "prefs-dialog.h"
35 #include "relocate.h"
36 #include "session.h"
37 #include "session-dialog.h"
38 #include "speed.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";
49 QIcon
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 );
57 return icon;
60 namespace
62 QSize calculateTextButtonSizeHint( QPushButton * button )
64 QStyleOptionButton opt;
65 opt.initFrom( button );
66 QString s( button->text( ) );
67 if( s.isEmpty( ) )
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 ) ),
79 myPrefsDialog( 0 ),
80 myAboutDialog( new AboutDialog( this ) ),
81 myStatsDialog( new StatsDialog( session, this ) ),
82 myDetailsDialog( 0 ),
83 myFilterModel( prefs ),
84 myTorrentDelegate( new TorrentDelegate( this ) ),
85 myTorrentDelegateMin( new TorrentDelegateMin( this ) ),
86 mySession( session ),
87 myPrefs( prefs ),
88 myModel( model ),
89 mySpeedModeOffIcon( ":/icons/alt-limit-off.png" ),
90 mySpeedModeOnIcon( ":/icons/alt-limit-on.png" ),
91 myLastSendTime( 0 ),
92 myLastReadTime( 0 ),
93 myNetworkTimer( this )
95 setAcceptDrops( true );
97 QAction * sep = new QAction( this );
98 sep->setSeparator( true );
100 ui.setupUi( this );
102 QStyle * style = this->style();
104 int i = style->pixelMetric( QStyle::PM_SmallIconSize, 0, this );
105 const QSize smallIconSize( i, i );
107 // icons
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" ) );
126 // ui signals
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 );
168 // context menu
169 QList<QAction*> actions;
170 actions << ui.action_Properties
171 << ui.action_OpenFolder
172 << sep2
173 << ui.action_Start
174 << ui.action_Announce
175 << ui.action_Pause
176 << ui.action_CopyMagnetToClipboard
177 << sep3
178 << ui.action_Verify
179 << ui.action_SetLocation
180 << sep
181 << ui.action_Remove
182 << ui.action_Delete;
183 addActions( actions );
184 setContextMenuPolicy( Qt::ActionsContextMenu );
186 // signals
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()) );
197 // torrent view
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 ) );
243 QList<int> initKeys;
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
251 << Prefs :: TOOLBAR
252 << Prefs :: ALT_SPEED_LIMIT_ENABLED
253 << Prefs :: COMPACT_VIEW
254 << Prefs :: DSPEED
255 << Prefs :: DSPEED_ENABLED
256 << Prefs :: USPEED
257 << Prefs :: USPEED_ENABLED
258 << Prefs :: RATIO
259 << Prefs :: RATIO_ENABLED;
260 foreach( int key, initKeys )
261 refreshPref( key );
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( );
271 else {
272 connect( &myNetworkTimer, SIGNAL(timeout()), this, SLOT(onNetworkTimer()));
273 myNetworkTimer.start( 1000 );
276 refreshActionSensitivity( );
277 refreshTrayIcon( );
278 refreshStatusBar( );
279 refreshTitle( );
280 refreshVisibleCount( );
283 TrMainWindow :: ~TrMainWindow( )
287 /****
288 *****
289 ****/
291 void
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 ) )
297 event->accept( );
298 else {
299 toggleWindows( false );
300 event->ignore( );
304 /****
305 *****
306 ****/
308 void
309 TrMainWindow :: onSessionSourceChanged( )
311 myModel.clear( );
314 void
315 TrMainWindow :: onModelReset( )
317 refreshTitle( );
318 refreshVisibleCount( );
319 refreshActionSensitivity( );
320 refreshStatusBar( );
321 refreshTrayIcon( );
324 /****
325 *****
326 ****/
328 #define PREF_VARIANTS_KEY "pref-variants-list"
330 void
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] );
339 void
340 TrMainWindow :: onSetPrefs( bool isChecked )
342 if( isChecked )
343 onSetPrefs( );
346 #define SHOW_KEY "show-mode"
348 QWidget *
349 TrMainWindow :: createStatusBar( )
351 QMenu * m;
352 QLabel * l;
353 QHBoxLayout * h;
354 QPushButton * p;
355 QActionGroup * a;
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() );
367 p->setFlat( true );
368 p->setMenu( createOptionsMenu( ) );
369 h->addWidget( p );
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() );
376 p->setFlat( true );
377 h->addWidget( p );
378 connect( p, SIGNAL(clicked()), this, SLOT(toggleSpeedMode()));
380 l = myNetworkLabel = new QLabel;
381 h->addWidget( l );
383 h->addStretch( 1 );
385 l = myVisibleCountLabel = new QLabel( this );
386 h->addWidget( l );
388 h->addStretch( 1 );
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 );
395 m = new QMenu( );
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() );
407 p->setFlat( true );
408 p->setMenu( m );
409 h->addWidget( p );
410 l = myStatsLabel = new QLabel( this );
411 h->addWidget( l );
413 h->addStretch( 1 );
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 );
419 h->addWidget( l );
420 l = new QLabel( this );
421 l->setPixmap( getStockIcon( "go-down", QStyle::SP_ArrowDown ).pixmap( smallIconSize ) );
422 h->addWidget( l );
424 h->addStretch( 1 );
426 l = myUploadSpeedLabel = new QLabel;
427 l->setMinimumWidth( minimumSpeedWidth );
428 l->setAlignment( Qt::AlignRight|Qt::AlignVCenter );
429 h->addWidget( l );
430 l = new QLabel;
431 l->setPixmap( getStockIcon( "go-up", QStyle::SP_ArrowUp ).pixmap( smallIconSize ) );
432 h->addWidget( l );
434 return top;
437 QMenu *
438 TrMainWindow :: createOptionsMenu( )
440 QMenu * menu;
441 QMenu * sub;
442 QAction * a;
443 QActionGroup * g;
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;
450 menu = new QMenu;
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 );
457 g->addAction( a );
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 );
462 g->addAction( a );
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 );
477 g->addAction( a );
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 );
482 g->addAction( a );
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 );
499 g->addAction( a );
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 );
504 g->addAction( a );
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()));
513 return menu;
516 /****
517 *****
518 ****/
520 void
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 ); }
534 void
535 TrMainWindow :: setSortAscendingPref( bool b )
537 myPrefs.set( Prefs::SORT_REVERSED, b );
540 /****
541 *****
542 ****/
544 void
545 TrMainWindow :: onPrefsDestroyed( )
547 myPrefsDialog = 0;
550 void
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( );
561 void
562 TrMainWindow :: onDetailsDestroyed( )
564 myDetailsDialog = 0;
567 void
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( );
579 void
580 TrMainWindow :: setLocation( )
582 QDialog * d = new RelocateDialog( mySession, myModel, getSelectedTorrents(), this );
583 d->show( );
586 void
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 ) );
595 void
596 TrMainWindow :: copyMagnetLinkToClipboard( )
598 const int id( *getSelectedTorrents().begin() );
599 mySession.copyMagnetLinkToClipboard( id );
602 void
603 TrMainWindow :: openDonate( )
605 QDesktopServices :: openUrl( QUrl( "http://www.transmissionbt.com/donate.php" ) );
608 void
609 TrMainWindow :: openHelp( )
611 const char * fmt = "http://www.transmissionbt.com/help/gtk/%d.%dx";
612 int major, minor;
613 sscanf( SHORT_VERSION_STRING, "%d.%d", &major, &minor );
614 char url[128];
615 tr_snprintf( url, sizeof( url ), fmt, major, minor/10 );
616 QDesktopServices :: openUrl( QUrl( url ) );
619 void
620 TrMainWindow :: refreshTitle( )
622 QString title( "Transmission" );
623 const QUrl url( mySession.getRemoteUrl( ) );
624 if( !url.isEmpty() )
625 title += tr( " - %1:%2" ).arg( url.host() ).arg( url.port() );
626 setWindowTitle( title );
629 void
630 TrMainWindow :: refreshVisibleCount( )
632 const int visibleCount( myFilterModel.rowCount( ) );
633 const int totalCount( visibleCount + myFilterModel.hiddenRowCount( ) );
634 QString str;
635 if( visibleCount == totalCount )
636 str = tr( "%Ln Torrent(s)", 0, totalCount );
637 else
638 str = tr( "%L1 of %Ln Torrent(s)", 0, totalCount ).arg( visibleCount );
639 myVisibleCountLabel->setText( str );
640 myVisibleCountLabel->setVisible( totalCount > 0 );
643 void
644 TrMainWindow :: refreshTrayIcon( )
646 Speed u, d;
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 ) ) );
660 void
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 ) );
671 QString str;
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 );
697 void
698 TrMainWindow :: refreshActionSensitivity( )
700 int selected( 0 );
701 int paused( 0 );
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*>( ) );
713 if( tor ) {
714 const bool isSelected( selectionModel->isSelected( modelIndex ) );
715 const bool isPaused( tor->isPaused( ) );
716 if( isSelected )
717 ++selected;
718 if( isPaused )
719 ++ paused;
720 if( isSelected && isPaused )
721 ++selectedAndPaused;
722 if( tor->canManualAnnounce( ) )
723 ++canAnnounce;
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( ) );
754 void
755 TrMainWindow :: clearSelection( )
757 ui.action_DeselectAll->trigger( );
760 QSet<int>
761 TrMainWindow :: getSelectedTorrents( ) const
763 QSet<int> ids;
765 foreach( QModelIndex index, ui.listView->selectionModel( )->selectedRows( ) )
767 const Torrent * tor( index.data( TorrentModel::TorrentRole ).value<const Torrent*>( ) );
768 ids.insert( tor->id( ) );
771 return ids;
774 void
775 TrMainWindow :: startSelected( )
777 mySession.startTorrents( getSelectedTorrents( ) );
779 void
780 TrMainWindow :: pauseSelected( )
782 mySession.pauseTorrents( getSelectedTorrents( ) );
784 void
785 TrMainWindow :: startAll( )
787 mySession.startTorrents( );
789 void
790 TrMainWindow :: pauseAll( )
792 mySession.pauseTorrents( );
794 void
795 TrMainWindow :: removeSelected( )
797 removeTorrents( false );
799 void
800 TrMainWindow :: deleteSelected( )
802 removeTorrents( true );
804 void
805 TrMainWindow :: verifySelected( )
807 mySession.verifyTorrents( getSelectedTorrents( ) );
809 void
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"); }
828 void
829 TrMainWindow :: setCompactView( bool visible )
831 myPrefs.set( Prefs :: COMPACT_VIEW, visible );
833 void
834 TrMainWindow :: toggleSpeedMode( )
836 myPrefs.toggleBool( Prefs :: ALT_SPEED_LIMIT_ENABLED );
838 void
839 TrMainWindow :: setToolbarVisible( bool visible )
841 myPrefs.set( Prefs::TOOLBAR, visible );
843 void
844 TrMainWindow :: setFilterbarVisible( bool visible )
846 myPrefs.set( Prefs::FILTERBAR, visible );
848 void
849 TrMainWindow :: setStatusbarVisible( bool visible )
851 myPrefs.set( Prefs::STATUSBAR, visible );
858 void
859 TrMainWindow :: toggleWindows( bool doShow )
861 if( !doShow )
863 hide( );
865 else
867 if ( !isVisible( ) ) show( );
868 if ( isMinimized( ) ) showNormal( );
869 //activateWindow( );
870 raise( );
871 QApplication::setActiveWindow( this );
875 void
876 TrMainWindow :: trayActivated( QSystemTrayIcon::ActivationReason reason )
878 if( reason == QSystemTrayIcon::Trigger )
880 if( isMinimized ( ) )
881 toggleWindows( true );
882 else
883 ui.action_ShowMainWindow->toggle( );
888 void
889 TrMainWindow :: refreshPref( int key )
891 bool b;
892 int i;
893 QString str;
895 switch( 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" );
903 refreshStatusBar( );
904 break;
906 case Prefs::SORT_REVERSED:
907 ui.action_ReverseSortOrder->setChecked( myPrefs.getBool( key ) );
908 break;
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 );
920 break;
922 case Prefs::DSPEED_ENABLED:
923 (myPrefs.get<bool>(key) ? myDlimitOnAction : myDlimitOffAction)->setChecked( true );
924 break;
926 case Prefs::DSPEED:
927 myDlimitOnAction->setText( tr( "Limited at %1" ).arg( Formatter::speedToString( Speed::fromKBps( myPrefs.get<int>(key) ) ) ) );
928 break;
930 case Prefs::USPEED_ENABLED:
931 (myPrefs.get<bool>(key) ? myUlimitOnAction : myUlimitOffAction)->setChecked( true );
932 break;
934 case Prefs::USPEED:
935 myUlimitOnAction->setText( tr( "Limited at %1" ).arg( Formatter::speedToString( Speed::fromKBps( myPrefs.get<int>(key) ) ) ) );
936 break;
938 case Prefs::RATIO_ENABLED:
939 (myPrefs.get<bool>(key) ? myRatioOnAction : myRatioOffAction)->setChecked( true );
940 break;
942 case Prefs::RATIO:
943 myRatioOnAction->setText( tr( "Stop at Ratio (%1)" ).arg( Formatter::ratioToString( myPrefs.get<double>(key) ) ) );
944 break;
946 case Prefs::FILTERBAR:
947 b = myPrefs.getBool( key );
948 myFilterBar->setVisible( b );
949 ui.action_Filterbar->setChecked( b );
950 break;
952 case Prefs::STATUSBAR:
953 b = myPrefs.getBool( key );
954 myStatusBar->setVisible( b );
955 ui.action_Statusbar->setChecked( b );
956 break;
958 case Prefs::TOOLBAR:
959 b = myPrefs.getBool( key );
960 ui.toolBar->setVisible( b );
961 ui.action_Toolbar->setChecked( b );
962 break;
964 case Prefs::SHOW_TRAY_ICON:
965 b = myPrefs.getBool( key );
966 ui.action_TrayIcon->setChecked( b );
967 myTrayIcon.setVisible( b );
968 refreshTrayIcon( );
969 break;
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 );
982 break;
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 ) );
993 break;
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 ) ) );
1007 break;
1010 default:
1011 break;
1015 /***
1016 ****
1017 ***/
1019 void
1020 TrMainWindow :: newTorrent( )
1022 MakeDialog * dialog = new MakeDialog( mySession, this );
1023 dialog->show( );
1026 void
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( );
1048 void
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 ) )
1057 str.clear();
1059 openURL( str );
1062 void
1063 TrMainWindow :: openURL( QString url )
1065 bool ok;
1066 const QString key = QInputDialog::getText( this,
1067 tr( "Open URL or Magnet Link" ),
1068 tr( "Open URL or Magnet Link" ),
1069 QLineEdit::Normal,
1070 url,
1071 &ok );
1072 if( ok && !key.isEmpty( ) )
1073 mySession.addTorrent( key );
1076 void
1077 TrMainWindow :: addTorrents( const QStringList& filenames )
1079 foreach( const QString& filename, filenames )
1080 addTorrent( filename );
1083 void
1084 TrMainWindow :: addTorrent( const QString& filename )
1086 if( !myFileDialogOptionsCheck->isChecked( ) ) {
1087 mySession.addTorrent( filename );
1088 QApplication :: alert ( this );
1089 } else {
1090 Options * o = new Options( mySession, myPrefs, filename, this );
1091 o->show( );
1092 QApplication :: alert( o );
1096 void
1097 TrMainWindow :: removeTorrents( const bool deleteFiles )
1099 QSet<int> ids;
1100 QMessageBox msgBox( this );
1101 QString primary_text, secondary_text;
1102 int incomplete = 0;
1103 int connected = 0;
1104 int count;
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( ) )
1111 ++connected;
1112 if( !tor->isDone( ) )
1113 ++incomplete;
1116 if( ids.isEmpty() )
1117 return;
1118 count = ids.size();
1120 if( !deleteFiles )
1122 primary_text = ( count == 1 )
1123 ? tr( "Remove torrent?" )
1124 : tr( "Remove %1 torrents?" ).arg( count );
1126 else
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." );
1151 else
1153 if( connected )
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";
1165 if( incomplete )
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 );
1191 /***
1192 ****
1193 ***/
1195 void
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;
1202 const char * key;
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";
1210 else
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))));
1221 void
1222 TrMainWindow :: onNetworkTimer( )
1224 updateNetworkIcon( );
1227 void
1228 TrMainWindow :: dataReadProgress( )
1230 myLastReadTime = time( NULL );
1231 updateNetworkIcon( );
1234 void
1235 TrMainWindow :: dataSendProgress( )
1237 myLastSendTime = time( NULL );
1238 updateNetworkIcon( );
1241 void
1242 TrMainWindow :: wrongAuthentication( )
1244 mySession.stop( );
1245 mySessionDialog->show( );
1248 /***
1249 ****
1250 ***/
1252 void
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();
1262 void
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 );