source: trunk/qt/mainwin.cc @ 8345

Last change on this file since 8345 was 8345, checked in by charles, 13 years ago

(trunk qt) hide the network icon when the transmission session is being run inside the client. patch by stdisease

File size: 39.7 KB
Line 
1/*
2 * This file Copyright (C) 2009 Charles Kerr <charles@transmissionbt.com>
3 *
4 * This file is licensed by the GPL version 2.  Works owned by the
5 * Transmission project are granted a special exemption to clause 2(b)
6 * so that the bulk of its code can remain under the MIT license.
7 * This exemption does not extend to derived works not owned by
8 * the Transmission project.
9 *
10 * $Id:$
11 */
12
13#include <cassert>
14#include <iostream>
15
16#include <QCheckBox>
17#include <QDesktopServices>
18#include <QFileDialog>
19#include <QLabel>
20#include <QSize>
21#include <QStyle>
22#include <QHBoxLayout>
23#include <QSystemTrayIcon>
24#include <QUrl>
25#include <QSignalMapper>
26
27#include <libtransmission/version.h>
28
29#include "about.h"
30#include "details.h"
31#include "filters.h"
32#include "hig.h"
33#include "mainwin.h"
34#include "make-dialog.h"
35#include "options.h"
36#include "prefs.h"
37#include "prefs-dialog.h"
38#include "session.h"
39#include "session-dialog.h"
40#include "speed.h"
41#include "stats-dialog.h"
42#include "torrent-delegate.h"
43#include "torrent-delegate-min.h"
44#include "torrent-filter.h"
45#include "torrent-model.h"
46#include "triconpushbutton.h"
47#include "ui_mainwin.h"
48#include "utils.h"
49#include "qticonloader.h"
50
51#define PREFS_KEY "prefs-key";
52
53QIcon
54TrMainWindow :: getStockIcon( const QString& freedesktop_name, int fallback )
55{
56    QIcon fallbackIcon;
57
58    if( fallback > 0 )
59        fallbackIcon = style()->standardIcon( QStyle::StandardPixmap( fallback ), 0, this );
60
61    return QtIconLoader::icon( freedesktop_name, fallbackIcon );
62}
63
64namespace
65{
66    QSize calculateTextButtonSizeHint( QPushButton * button )
67    {
68        QStyleOptionButton opt;
69        opt.initFrom( button );
70        QString s( button->text( ) );
71        if( s.isEmpty( ) )
72            s = QString::fromLatin1( "XXXX" );
73        QFontMetrics fm = button->fontMetrics( );
74        QSize sz = fm.size( Qt::TextShowMnemonic, s );
75        return button->style()->sizeFromContents( QStyle::CT_PushButton, &opt, sz, button ).expandedTo( QApplication::globalStrut( ) );
76    }
77}
78
79
80TrMainWindow :: TrMainWindow( Session& session, Prefs& prefs, TorrentModel& model, bool minimized ):
81    myLastFullUpdateTime( 0 ),
82    mySessionDialog( new SessionDialog( session, prefs, this ) ),
83    myPrefsDialog( new PrefsDialog( session, prefs, this ) ),
84    myAboutDialog( new AboutDialog( this ) ),
85    myStatsDialog( new StatsDialog( session, this ) ),
86    myDetailsDialog( 0 ),
87    myFileDialog( 0 ),
88    myFilterModel( prefs ),
89    myTorrentDelegate( new TorrentDelegate( this ) ),
90    myTorrentDelegateMin( new TorrentDelegateMin( this ) ),
91    mySession( session ),
92    myPrefs( prefs ),
93    myModel( model ),
94    mySpeedModeOffIcon( ":/icons/alt-limit-off.png" ),
95    mySpeedModeOnIcon( ":/icons/alt-limit-on.png" ),
96    myLastSendTime( 0 ),
97    myLastReadTime( 0 ),
98    myNetworkTimer( this )
99{
100    QAction * sep = new QAction( this );
101    sep->setSeparator( true );
102
103    ui.setupUi( this );
104
105    QStyle * style = this->style();
106
107    int i = style->pixelMetric( QStyle::PM_SmallIconSize, 0, this );
108    const QSize smallIconSize( i, i );
109
110    // icons
111    ui.action_Add->setIcon( getStockIcon( "list-add", QStyle::SP_DialogOpenButton ) );
112    ui.action_New->setIcon( getStockIcon( "document-new", QStyle::SP_DesktopIcon ) );
113    ui.action_Properties->setIcon( getStockIcon( "document-properties", QStyle::SP_DesktopIcon ) );
114    ui.action_OpenFolder->setIcon( getStockIcon( "folder-open", QStyle::SP_DirOpenIcon ) );
115    ui.action_Start->setIcon( getStockIcon( "media-playback-start", QStyle::SP_MediaPlay ) );
116    ui.action_Announce->setIcon( getStockIcon( "network-transmit-receive" ) );
117    ui.action_Pause->setIcon( getStockIcon( "media-playback-pause", QStyle::SP_MediaPause ) );
118    ui.action_Remove->setIcon( getStockIcon( "list-remove", QStyle::SP_TrashIcon ) );
119    ui.action_Delete->setIcon( getStockIcon( "edit-delete", QStyle::SP_TrashIcon ) );
120    ui.action_StartAll->setIcon( getStockIcon( "media-playback-start", QStyle::SP_MediaPlay ) );
121    ui.action_PauseAll->setIcon( getStockIcon( "media-playback-pause", QStyle::SP_MediaPause ) );
122    ui.action_Quit->setIcon( getStockIcon( "application-exit" ) );
123    ui.action_SelectAll->setIcon( getStockIcon( "edit-select-all" ) );
124    ui.action_ReverseSortOrder->setIcon( getStockIcon( "view-sort-ascending", QStyle::SP_ArrowDown ) );
125    ui.action_Preferences->setIcon( getStockIcon( "preferences-system" ) );
126    ui.action_Contents->setIcon( getStockIcon( "help-contents", QStyle::SP_DialogHelpButton ) );
127    ui.action_About->setIcon( getStockIcon( "help-about" ) );
128
129    // ui signals
130    connect( ui.action_Toolbar, SIGNAL(toggled(bool)), this, SLOT(setToolbarVisible(bool)));
131    connect( ui.action_TrayIcon, SIGNAL(toggled(bool)), this, SLOT(setTrayIconVisible(bool)));
132    connect( ui.action_Filterbar, SIGNAL(toggled(bool)), this, SLOT(setFilterbarVisible(bool)));
133    connect( ui.action_Statusbar, SIGNAL(toggled(bool)), this, SLOT(setStatusbarVisible(bool)));
134    connect( ui.action_MinimalView, SIGNAL(toggled(bool)), this, SLOT(setMinimalView(bool)));
135    connect( ui.action_SortByActivity, SIGNAL(toggled(bool)), this, SLOT(onSortByActivityToggled(bool)));
136    connect( ui.action_SortByAge,      SIGNAL(toggled(bool)), this, SLOT(onSortByAgeToggled(bool)));
137    connect( ui.action_SortByETA,      SIGNAL(toggled(bool)), this, SLOT(onSortByETAToggled(bool)));
138    connect( ui.action_SortByName,     SIGNAL(toggled(bool)), this, SLOT(onSortByNameToggled(bool)));
139    connect( ui.action_SortByProgress, SIGNAL(toggled(bool)), this, SLOT(onSortByProgressToggled(bool)));
140    connect( ui.action_SortByRatio,    SIGNAL(toggled(bool)), this, SLOT(onSortByRatioToggled(bool)));
141    connect( ui.action_SortBySize,     SIGNAL(toggled(bool)), this, SLOT(onSortBySizeToggled(bool)));
142    connect( ui.action_SortByState,    SIGNAL(toggled(bool)), this, SLOT(onSortByStateToggled(bool)));
143    connect( ui.action_SortByTracker,  SIGNAL(toggled(bool)), this, SLOT(onSortByTrackerToggled(bool)));
144    connect( ui.action_ReverseSortOrder, SIGNAL(toggled(bool)), this, SLOT(setSortAscendingPref(bool)));
145    connect( ui.action_Start, SIGNAL(triggered()), this, SLOT(startSelected()));
146    connect( ui.action_Pause, SIGNAL(triggered()), this, SLOT(pauseSelected()));
147    connect( ui.action_Remove, SIGNAL(triggered()), this, SLOT(removeSelected()));
148    connect( ui.action_Delete, SIGNAL(triggered()), this, SLOT(deleteSelected()));
149    connect( ui.action_Verify, SIGNAL(triggered()), this, SLOT(verifySelected()) );
150    connect( ui.action_Announce, SIGNAL(triggered()), this, SLOT(reannounceSelected()) );
151    connect( ui.action_StartAll, SIGNAL(triggered()), this, SLOT(startAll()));
152    connect( ui.action_PauseAll, SIGNAL(triggered()), this, SLOT(pauseAll()));
153    connect( ui.action_Add, SIGNAL(triggered()), this, SLOT(openTorrent()));
154    connect( ui.action_New, SIGNAL(triggered()), this, SLOT(newTorrent()));
155    connect( ui.action_Preferences, SIGNAL(triggered()), myPrefsDialog, SLOT(show()));
156    connect( ui.action_Statistics, SIGNAL(triggered()), myStatsDialog, SLOT(show()));
157    connect( ui.action_About, SIGNAL(triggered()), myAboutDialog, SLOT(show()));
158    connect( ui.action_Contents, SIGNAL(triggered()), this, SLOT(openHelp()));
159    connect( ui.action_OpenFolder, SIGNAL(triggered()), this, SLOT(openFolder()));
160    connect( ui.action_Properties, SIGNAL(triggered()), this, SLOT(openProperties()));
161    connect( ui.action_SessionDialog, SIGNAL(triggered()), mySessionDialog, SLOT(show()));
162    connect( ui.listView, SIGNAL(activated(const QModelIndex&)), ui.action_Properties, SLOT(trigger()));
163
164    // context menu
165    QList<QAction*> actions;
166    actions << ui.action_Properties
167            << ui.action_OpenFolder
168            << sep
169            << ui.action_Start
170            << ui.action_Pause
171            << ui.action_Verify
172            << ui.action_Announce
173            << sep
174            << ui.action_Remove
175            << ui.action_Delete;
176    addActions( actions );
177    setContextMenuPolicy( Qt::ActionsContextMenu );
178
179    // signals
180    connect( ui.action_SelectAll, SIGNAL(triggered()), ui.listView, SLOT(selectAll()));
181    connect( ui.action_DeselectAll, SIGNAL(triggered()), ui.listView, SLOT(clearSelection()));
182
183    connect( &myFilterModel, SIGNAL(rowsInserted(const QModelIndex&,int,int)), this, SLOT(refreshVisibleCount()));
184    connect( &myFilterModel, SIGNAL(rowsRemoved(const QModelIndex&,int,int)), this, SLOT(refreshVisibleCount()));
185    connect( &myFilterModel, SIGNAL(rowsInserted(const QModelIndex&,int,int)), this, SLOT(refreshActionSensitivity()));
186    connect( &myFilterModel, SIGNAL(rowsRemoved(const QModelIndex&,int,int)), this, SLOT(refreshActionSensitivity()));
187
188    connect( ui.action_Quit, SIGNAL(triggered()), QCoreApplication::instance(), SLOT(quit()) );
189
190    // torrent view
191    myFilterModel.setSourceModel( &myModel );
192    connect( &myModel, SIGNAL(modelReset()), this, SLOT(onModelReset()));
193    connect( &myModel, SIGNAL(rowsRemoved(const QModelIndex&,int,int)), this, SLOT(onModelReset()));
194    connect( &myModel, SIGNAL(rowsInserted(const QModelIndex&,int,int)), this, SLOT(onModelReset()));
195    ui.listView->setModel( &myFilterModel );
196    connect( ui.listView->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&,const QItemSelection&)), this, SLOT(refreshActionSensitivity()));
197
198    QActionGroup * actionGroup = new QActionGroup( this );
199    actionGroup->addAction( ui.action_SortByActivity );
200    actionGroup->addAction( ui.action_SortByAge );
201    actionGroup->addAction( ui.action_SortByETA );
202    actionGroup->addAction( ui.action_SortByName );
203    actionGroup->addAction( ui.action_SortByProgress );
204    actionGroup->addAction( ui.action_SortByRatio );
205    actionGroup->addAction( ui.action_SortBySize );
206    actionGroup->addAction( ui.action_SortByState );
207    actionGroup->addAction( ui.action_SortByTracker );
208
209    QMenu * menu = new QMenu( );
210    menu->addAction( ui.action_Add );
211    menu->addSeparator( );
212    menu->addAction( ui.action_ShowMainWindow );
213    menu->addAction( ui.action_ShowMessageLog );
214    menu->addAction( ui.action_About );
215    menu->addSeparator( );
216    menu->addAction( ui.action_StartAll );
217    menu->addAction( ui.action_PauseAll );
218    menu->addSeparator( );
219    menu->addAction( ui.action_Quit );
220    myTrayIcon.setContextMenu( menu );
221    myTrayIcon.setIcon( QApplication::windowIcon( ) );
222
223    connect( &myPrefs, SIGNAL(changed(int)), this, SLOT(refreshPref(int)) );
224    connect( ui.action_ShowMainWindow, SIGNAL(toggled(bool)), this, SLOT(toggleWindows()));
225    connect( &myTrayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
226             this, SLOT(trayActivated(QSystemTrayIcon::ActivationReason)));
227
228    ui.action_ShowMainWindow->setChecked( !minimized );
229    ui.action_TrayIcon->setChecked( minimized || prefs.getBool( Prefs::SHOW_TRAY_ICON ) );
230
231    ui.verticalLayout->addWidget( createStatusBar( ) );
232    ui.verticalLayout->insertWidget( 0, createFilterBar( ) );
233
234    QList<int> initKeys;
235    initKeys << Prefs :: MAIN_WINDOW_X
236             << Prefs :: SHOW_TRAY_ICON
237             << Prefs :: SORT_REVERSED
238             << Prefs :: SORT_MODE
239             << Prefs :: FILTER_MODE
240             << Prefs :: FILTERBAR
241             << Prefs :: STATUSBAR
242             << Prefs :: STATUSBAR_STATS
243             << Prefs :: TOOLBAR
244             << Prefs :: ALT_SPEED_LIMIT_ENABLED
245             << Prefs :: MINIMAL_VIEW
246             << Prefs :: DSPEED
247             << Prefs :: DSPEED_ENABLED
248             << Prefs :: USPEED
249             << Prefs :: USPEED_ENABLED
250             << Prefs :: RATIO
251             << Prefs :: RATIO_ENABLED;
252    foreach( int key, initKeys )
253        refreshPref( key );
254
255    connect( &mySession, SIGNAL(sourceChanged()), this, SLOT(onSessionSourceChanged()) );
256    connect( &mySession, SIGNAL(statsUpdated()), this, SLOT(refreshStatusBar()) );
257    connect( &mySession, SIGNAL(dataReadProgress()), this, SLOT(dataReadProgress()) );
258    connect( &mySession, SIGNAL(dataSendProgress()), this, SLOT(dataSendProgress()) );
259    connect( &mySession, SIGNAL(httpAuthenticationRequired()), this, SLOT(wrongAuthentication()) );
260
261    if( mySession.isServer( ) )
262        myNetworkLabel->hide( );
263    else {
264        connect( &myNetworkTimer, SIGNAL(timeout()), this, SLOT(onNetworkTimer()));
265        myNetworkTimer.start( 1000 );
266    }
267
268    refreshActionSensitivity( );
269    refreshStatusBar( );
270    refreshTitle( );
271    refreshVisibleCount( );
272}
273
274TrMainWindow :: ~TrMainWindow( )
275{
276}
277
278/****
279*****
280****/
281
282void
283TrMainWindow :: onSessionSourceChanged( )
284{
285    myModel.clear( );
286}
287
288void
289TrMainWindow :: onModelReset( )
290{
291    refreshTitle( );
292    refreshVisibleCount( );
293    refreshActionSensitivity( );
294    refreshStatusBar( );
295}
296
297/****
298*****
299****/
300
301#define PREF_VARIANTS_KEY "pref-variants-list"
302
303void
304TrMainWindow :: onSetPrefs( )
305{
306    const QVariantList p = sender()->property( PREF_VARIANTS_KEY ).toList( );
307    assert( ( p.size( ) % 2 ) == 0 );
308    for( int i=0, n=p.size(); i<n; i+=2 )
309        myPrefs.set( p[i].toInt(), p[i+1] );
310}
311
312void
313TrMainWindow :: onSetPrefs( bool isChecked )
314{
315    if( isChecked )
316        onSetPrefs( );
317}
318
319#define SHOW_KEY "show-mode"
320
321void
322TrMainWindow :: onShowModeClicked( )
323{
324    setShowMode( sender()->property(SHOW_KEY).toInt() );
325}
326
327QWidget *
328TrMainWindow :: createFilterBar( )
329{
330    int i;
331    QMenu * m;
332    QLineEdit * e;
333    QPushButton * p;
334    QHBoxLayout * h;
335    QActionGroup * a;
336    const int smallSize = style( )->pixelMetric( QStyle::PM_SmallIconSize, 0, this );
337    const QSize smallIconSize( smallSize, smallSize );
338
339    QWidget * top = myFilterBar = new QWidget;
340    h = new QHBoxLayout( top );
341    h->setContentsMargins( HIG::PAD_SMALL, HIG::PAD_SMALL, HIG::PAD_SMALL, HIG::PAD_SMALL );
342    h->setSpacing( HIG::PAD_SMALL );
343
344    top->setStyleSheet(" \
345      QPushButton{ \
346        border-radius: 10px; \
347        padding: 0 5px; \
348        border: 1px none; \
349      } \
350      QPushButton:pressed, QPushButton:checked{ \
351        border-width: 1px; \
352        border-style: solid; \
353        border-color: #5f5f5f #979797 #979797; \
354        background-color: #979797; \
355        color: white; \
356      } \
357    ");
358
359        QList<QString> titles;
360        titles << tr( "A&ll" ) << tr( "&Active" ) << tr( "&Downloading" ) << tr( "&Seeding" ) << tr( "&Paused" );
361        for( i=0; i<titles.size(); ++i ) {
362            p = myFilterButtons[i] = new QPushButton( titles[i] );
363            p->setProperty( SHOW_KEY, i );
364            p->setFlat( true );
365            p->setCheckable( true );
366            p->setMaximumSize( calculateTextButtonSizeHint( p ) );
367            connect( p, SIGNAL(clicked()), this, SLOT(onShowModeClicked()));
368            h->addWidget( p );
369        }
370
371    h->addStretch( 1 );
372
373        a = new QActionGroup( this );
374        a->addAction( ui.action_FilterByName );
375        a->addAction( ui.action_FilterByFiles );
376        a->addAction( ui.action_FilterByTracker );
377        m = new QMenu( );
378        m->addAction( ui.action_FilterByName );
379        m->addAction( ui.action_FilterByFiles );
380        m->addAction( ui.action_FilterByTracker );
381        connect( ui.action_FilterByName, SIGNAL(triggered()), this, SLOT(filterByName()));
382        connect( ui.action_FilterByFiles, SIGNAL(triggered()), this, SLOT(filterByFiles()));
383        connect( ui.action_FilterByTracker, SIGNAL(triggered()), this, SLOT(filterByTracker()));
384        ui.action_FilterByName->setChecked( true );
385        p = myFilterTextButton = new TrIconPushButton;
386        p->setIcon( getStockIcon( "edit-find", QStyle::SP_ArrowForward ) );
387        p->setFlat( true );
388        p->setMenu( m );
389        h->addWidget( p );
390
391        e = myFilterTextLineEdit = new QLineEdit;
392        connect( e, SIGNAL(textChanged(QString)), &myFilterModel, SLOT(setText(QString)));
393        h->addWidget( e );
394
395        p = myFilterTextButton = new TrIconPushButton;
396        p->setIcon( getStockIcon( "edit-clear", QStyle::SP_DialogCloseButton ) );
397        p->setFlat( true );
398        connect( p, SIGNAL(clicked()), myFilterTextLineEdit, SLOT(clear()));
399        h->addWidget( p );
400
401    return top;
402}
403
404QWidget *
405TrMainWindow :: createStatusBar( )
406{
407    QMenu * m;
408    QLabel *l, *l2;
409    QWidget *w;
410    QHBoxLayout * h;
411    QPushButton * p;
412    QActionGroup * a;
413    const int i = style( )->pixelMetric( QStyle::PM_SmallIconSize, 0, this );
414    const QSize smallIconSize( i, i );
415
416    QWidget * top = myStatusBar = new QWidget;
417    h = new QHBoxLayout( top );
418    h->setContentsMargins( HIG::PAD_SMALL, HIG::PAD_SMALL, HIG::PAD_SMALL, HIG::PAD_SMALL );
419    h->setSpacing( HIG::PAD_SMALL );
420
421        p = myOptionsButton = new TrIconPushButton( this );
422        p->setIcon( QIcon( ":/icons/options.png" ) );
423        p->setFlat( true );
424        p->setMenu( createOptionsMenu( ) );
425        h->addWidget( p );
426
427        p = myAltSpeedButton = new TrIconPushButton( this );
428        p->setIcon( myPrefs.get<bool>(Prefs::ALT_SPEED_LIMIT_ENABLED) ? mySpeedModeOnIcon : mySpeedModeOffIcon );
429        p->setFlat( true );
430        h->addWidget( p );
431        connect( p, SIGNAL(clicked()), this, SLOT(toggleSpeedMode()));
432
433        l = myNetworkLabel = new QLabel;
434        h->addWidget( l );
435
436    h->addStretch( 1 );
437
438        l = myVisibleCountLabel = new QLabel( this );
439        h->addWidget( l );
440
441    h->addStretch( 1 );
442 
443        a = new QActionGroup( this );
444        a->addAction( ui.action_TotalRatio );
445        a->addAction( ui.action_TotalTransfer );
446        a->addAction( ui.action_SessionRatio );
447        a->addAction( ui.action_SessionTransfer );
448        m = new QMenu( );
449        m->addAction( ui.action_TotalRatio );
450        m->addAction( ui.action_TotalTransfer );
451        m->addAction( ui.action_SessionRatio );
452        m->addAction( ui.action_SessionTransfer );
453        connect( ui.action_TotalRatio, SIGNAL(triggered()), this, SLOT(showTotalRatio()));
454        connect( ui.action_TotalTransfer, SIGNAL(triggered()), this, SLOT(showTotalTransfer()));
455        connect( ui.action_SessionRatio, SIGNAL(triggered()), this, SLOT(showSessionRatio()));
456        connect( ui.action_SessionTransfer, SIGNAL(triggered()), this, SLOT(showSessionTransfer()));
457        p = myStatsModeButton = new TrIconPushButton( this );
458        p->setIcon( getStockIcon( "view-refresh", QStyle::SP_BrowserReload ) );
459        p->setFlat( true );
460        p->setMenu( m );
461        h->addWidget( p ); 
462        l = myStatsLabel = new QLabel( this );
463        h->addWidget( l ); 
464   
465        w = new QWidget( this );
466        w->setMinimumSize( HIG::PAD_BIG, 1 );
467        w->setMaximumSize( HIG::PAD_BIG, 1 );
468        h->addWidget( w );
469        l = new QLabel( this );
470        l->setPixmap( getStockIcon( "go-down", QStyle::SP_ArrowDown ).pixmap( smallIconSize ) );
471        h->addWidget( l );
472        l2 = myDownloadSpeedLabel = new QLabel( this );
473        h->addWidget( l2 );
474        myDownStatusWidgets << w << l << l2;
475
476        w = new QWidget( this );
477        w->setMinimumSize( HIG::PAD_BIG, 1 );
478        w->setMaximumSize( HIG::PAD_BIG, 1 );
479        h->addWidget( w );
480        l = new QLabel;
481        l->setPixmap( getStockIcon( "go-up", QStyle::SP_ArrowUp ).pixmap( smallIconSize ) );
482        h->addWidget( l );
483        l2 = myUploadSpeedLabel = new QLabel;
484        h->addWidget( l2 );
485        myUpStatusWidgets << w << l << l2;
486
487    return top;
488}
489
490QMenu *
491TrMainWindow :: createOptionsMenu( )
492{
493    QMenu * menu;
494    QMenu * sub;
495    QAction * a;
496    QActionGroup * g;
497
498    QList<int> stockSpeeds;
499    stockSpeeds << 5 << 10 << 20 << 30 << 40 << 50 << 75 << 100 << 150 << 200 << 250 << 500 << 750;
500    QList<double> stockRatios;
501    stockRatios << 0.25 << 0.50 << 0.75 << 1 << 1.5 << 2 << 3;
502
503    menu = new QMenu;
504    sub = menu->addMenu( tr( "Limit Download Speed" ) );
505        int currentVal = myPrefs.get<int>( Prefs::DSPEED );
506        g = new QActionGroup( this );
507        a = myDlimitOffAction = sub->addAction( tr( "Unlimited" ) );
508        a->setCheckable( true );
509        a->setProperty( PREF_VARIANTS_KEY, QVariantList() << Prefs::DSPEED_ENABLED << false );
510        g->addAction( a );
511        connect( a, SIGNAL(triggered(bool)), this, SLOT(onSetPrefs(bool)) );
512        a = myDlimitOnAction = sub->addAction( tr( "Limited at %1" ).arg( Utils::speedToString( Speed::fromKbps( currentVal ) ) ) );
513        a->setCheckable( true );
514        a->setProperty( PREF_VARIANTS_KEY, QVariantList() << Prefs::DSPEED << currentVal << Prefs::DSPEED_ENABLED << true );
515        g->addAction( a );
516        connect( a, SIGNAL(triggered(bool)), this, SLOT(onSetPrefs(bool)) );
517        sub->addSeparator( );
518        foreach( int i, stockSpeeds ) {
519            a = sub->addAction( Utils::speedToString( Speed::fromKbps(i) ) );
520            a->setProperty( PREF_VARIANTS_KEY, QVariantList() << Prefs::DSPEED << i << Prefs::DSPEED_ENABLED << true );
521            connect( a, SIGNAL(triggered(bool)), this, SLOT(onSetPrefs()));
522        }
523
524    sub = menu->addMenu( tr( "Limit Upload Speed" ) );
525        currentVal = myPrefs.get<int>( Prefs::USPEED );
526        g = new QActionGroup( this );
527        a = myUlimitOffAction = sub->addAction( tr( "Unlimited" ) );
528        a->setCheckable( true );
529        a->setProperty( PREF_VARIANTS_KEY, QVariantList() << Prefs::USPEED_ENABLED << false );
530        g->addAction( a );
531        connect( a, SIGNAL(triggered(bool)), this, SLOT(onSetPrefs(bool)) );
532        a = myUlimitOnAction = sub->addAction( tr( "Limited at %1" ).arg( Utils::speedToString( Speed::fromKbps( currentVal ) ) ) );
533        a->setCheckable( true );
534        a->setProperty( PREF_VARIANTS_KEY, QVariantList() << Prefs::USPEED << currentVal << Prefs::USPEED_ENABLED << true );
535        g->addAction( a );
536        connect( a, SIGNAL(triggered(bool)), this, SLOT(onSetPrefs(bool)) );
537        sub->addSeparator( );
538        foreach( int i, stockSpeeds ) {
539            a = sub->addAction( Utils::speedToString( Speed::fromKbps(i) ) );
540            a->setProperty( PREF_VARIANTS_KEY, QVariantList() << Prefs::USPEED << i << Prefs::USPEED_ENABLED << true );
541            connect( a, SIGNAL(triggered(bool)), this, SLOT(onSetPrefs()));
542        }
543
544    menu->addSeparator( );
545    sub = menu->addMenu( tr( "Stop Seeding at Ratio" ) );
546
547        double d = myPrefs.get<double>( Prefs::RATIO );
548        g = new QActionGroup( this );
549        a = myRatioOffAction = sub->addAction( tr( "Seed Forever" ) );
550        a->setCheckable( true );
551        a->setProperty( PREF_VARIANTS_KEY, QVariantList() << Prefs::RATIO_ENABLED << false );
552        g->addAction( a );
553        connect( a, SIGNAL(triggered(bool)), this, SLOT(onSetPrefs(bool)) );
554        a = myRatioOnAction = sub->addAction( tr( "Stop at Ratio (%1)" ).arg( Utils::ratioToString( d ) ) );
555        a->setCheckable( true );
556        a->setProperty( PREF_VARIANTS_KEY, QVariantList() << Prefs::RATIO << d << Prefs::RATIO_ENABLED << true );
557        g->addAction( a );
558        connect( a, SIGNAL(triggered(bool)), this, SLOT(onSetPrefs(bool)) );
559        sub->addSeparator( );
560        foreach( double i, stockRatios ) {
561            a = sub->addAction( Utils::ratioToString( i ) );
562            a->setProperty( PREF_VARIANTS_KEY, QVariantList() << Prefs::RATIO << i << Prefs::RATIO_ENABLED << true );
563            connect( a, SIGNAL(triggered(bool)), this, SLOT(onSetPrefs()));
564        }
565
566    return menu;
567}
568
569/****
570*****
571****/
572
573void
574TrMainWindow :: setSortPref( int i )
575{
576    myPrefs.set( Prefs::SORT_MODE, SortMode( i ) );
577}
578void TrMainWindow :: onSortByActivityToggled ( bool b ) { if( b ) setSortPref( SortMode::SORT_BY_ACTIVITY ); }
579void TrMainWindow :: onSortByAgeToggled      ( bool b ) { if( b ) setSortPref( SortMode::SORT_BY_AGE );      }
580void TrMainWindow :: onSortByETAToggled      ( bool b ) { if( b ) setSortPref( SortMode::SORT_BY_ETA );      }
581void TrMainWindow :: onSortByNameToggled     ( bool b ) { if( b ) setSortPref( SortMode::SORT_BY_NAME );     }
582void TrMainWindow :: onSortByProgressToggled ( bool b ) { if( b ) setSortPref( SortMode::SORT_BY_PROGRESS ); }
583void TrMainWindow :: onSortByRatioToggled    ( bool b ) { if( b ) setSortPref( SortMode::SORT_BY_RATIO );    }
584void TrMainWindow :: onSortBySizeToggled     ( bool b ) { if( b ) setSortPref( SortMode::SORT_BY_SIZE );     }
585void TrMainWindow :: onSortByStateToggled    ( bool b ) { if( b ) setSortPref( SortMode::SORT_BY_STATE );    }
586void TrMainWindow :: onSortByTrackerToggled  ( bool b ) { if( b ) setSortPref( SortMode::SORT_BY_TRACKER );  }
587
588void
589TrMainWindow :: setSortAscendingPref( bool b )
590{
591    myPrefs.set( Prefs::SORT_REVERSED, b );
592}
593
594/****
595*****
596****/
597
598void
599TrMainWindow :: onDetailsDestroyed( )
600{
601    myDetailsDialog = 0;
602}
603
604void
605TrMainWindow :: openProperties( )
606{
607    if( myDetailsDialog == 0 ) {
608        myDetailsDialog = new Details( mySession, myModel, this );
609        connect( myDetailsDialog, SIGNAL(destroyed(QObject*)), this, SLOT(onDetailsDestroyed()));
610    }
611
612    myDetailsDialog->setIds( getSelectedTorrents( ) );
613    myDetailsDialog->show( );
614}
615
616void
617TrMainWindow :: openFolder( )
618{
619    const int torrentId( *getSelectedTorrents().begin() );
620    const Torrent * tor( myModel.getTorrentFromId( torrentId ) );
621    const QString path( tor->getPath( ) );
622    QDesktopServices :: openUrl( QUrl::fromLocalFile( path ) );
623}
624
625void
626TrMainWindow :: openHelp( )
627{
628    const char * fmt = "http://www.transmissionbt.com/help/gtk/%d.%dx";
629    int major, minor;
630    sscanf( SHORT_VERSION_STRING, "%d.%d", &major, &minor );
631    char url[128];
632    snprintf( url, sizeof( url ), fmt, major, minor/10 );
633    QDesktopServices :: openUrl( QUrl( QString( url ) ) );
634}
635
636void
637TrMainWindow :: refreshTitle( )
638{
639    QString title( "Transmission" );
640    const QUrl url( mySession.getRemoteUrl( ) );
641    if( !url.isEmpty() )
642        title += tr( " - %1" ).arg( url.toString(QUrl::RemoveUserInfo) );
643    setWindowTitle( title );
644}
645
646void
647TrMainWindow :: refreshVisibleCount( )
648{
649    const int visibleCount( myFilterModel.rowCount( ) );
650    const int totalCount( visibleCount + myFilterModel.hiddenRowCount( ) );
651    QString str;
652    if( visibleCount == totalCount )
653        str = tr( "%Ln Torrent(s)", 0, totalCount );
654    else
655        str = tr( "%L1 of %Ln Torrent(s)", 0, totalCount ).arg( visibleCount );
656    myVisibleCountLabel->setText( str );
657    myVisibleCountLabel->setVisible( totalCount > 0 );
658}
659
660void
661TrMainWindow :: refreshStatusBar( )
662{
663    const Speed up( myModel.getUploadSpeed( ) );
664    const Speed down( myModel.getDownloadSpeed( ) );
665    myUploadSpeedLabel->setText( Utils :: speedToString( up ) );
666    myDownloadSpeedLabel->setText( Utils :: speedToString( down ) );
667    foreach( QWidget * w, myUpStatusWidgets ) w->setVisible( !up.isZero( ) );
668    foreach( QWidget * w, myDownStatusWidgets ) w->setVisible( !down.isZero( ) );
669
670    myNetworkLabel->setVisible( !mySession.isServer( ) );
671
672    const QString mode( myPrefs.getString( Prefs::STATUSBAR_STATS ) );
673    QString str;
674
675    if( mode == "session-ratio" )
676    {
677        str = tr( "Ratio: %1" ).arg( Utils :: ratioToString( mySession.getStats().ratio ) );
678    }
679    else if( mode == "session-transfer" )
680    {
681        const tr_session_stats& stats( mySession.getStats( ) );
682        str = tr( "Down: %1, Up: %2" ).arg( Utils :: sizeToString( stats.downloadedBytes ) )
683                                      .arg( Utils :: sizeToString( stats.uploadedBytes ) );
684    }
685    else if( mode == "total-transfer" )
686    {
687        const tr_session_stats& stats( mySession.getCumulativeStats( ) );
688        str = tr( "Down: %1, Up: %2" ).arg( Utils :: sizeToString( stats.downloadedBytes ) )
689                                      .arg( Utils :: sizeToString( stats.uploadedBytes ) );
690    }
691    else /* default is "total-ratio" */
692    {
693        str = tr( "Ratio: %1" ).arg( Utils :: ratioToString( mySession.getCumulativeStats().ratio ) );
694    }
695
696    myStatsLabel->setText( str );
697}
698
699void
700TrMainWindow :: refreshActionSensitivity( )
701{
702    int selected( 0 );
703    int paused( 0 );
704    int selectedAndPaused( 0 );
705    int canAnnounce( 0 );
706    const QAbstractItemModel * model( ui.listView->model( ) );
707    const QItemSelectionModel * selectionModel( ui.listView->selectionModel( ) );
708    const int rowCount( model->rowCount( ) );
709
710    /* count how many torrents are selected, paused, etc */
711    for( int row=0; row<rowCount; ++row ) {
712        const QModelIndex modelIndex( model->index( row, 0 ) );
713        assert( model == modelIndex.model( ) );
714        const Torrent * tor( model->data( modelIndex, TorrentModel::TorrentRole ).value<const Torrent*>( ) );
715        const bool isSelected( selectionModel->isSelected( modelIndex ) );
716        const bool isPaused( tor->isPaused( ) );
717        if( isSelected )
718            ++selected;
719        if( isPaused )
720            ++ paused;
721        if( isSelected && isPaused )
722            ++selectedAndPaused;
723        if( tor->canManualAnnounce( ) )
724            ++canAnnounce;
725    }
726
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
734    const bool oneSelection( selected == 1 );
735    ui.action_OpenFolder->setEnabled( oneSelection );
736
737    ui.action_SelectAll->setEnabled( selected < rowCount );
738    ui.action_StartAll->setEnabled( paused > 0 );
739    ui.action_PauseAll->setEnabled( paused < rowCount );
740    ui.action_Start->setEnabled( selectedAndPaused > 0 );
741    ui.action_Pause->setEnabled( selectedAndPaused < selected );
742    ui.action_Announce->setEnabled( selected > 0 && ( canAnnounce == selected ) );
743
744    if( myDetailsDialog )
745        myDetailsDialog->setIds( getSelectedTorrents( ) );
746}
747
748/**
749***
750**/
751
752void
753TrMainWindow :: clearSelection( )
754{
755    ui.action_DeselectAll->trigger( );
756}
757
758QSet<int>
759TrMainWindow :: getSelectedTorrents( ) const
760{
761    QSet<int> ids;
762
763    foreach( QModelIndex index, ui.listView->selectionModel( )->selectedRows( ) )
764    {
765        const Torrent * tor( index.model()->data( index, TorrentModel::TorrentRole ).value<const Torrent*>( ) );
766        ids.insert( tor->id( ) );
767    }
768
769    return ids;
770}
771
772void
773TrMainWindow :: startSelected( )
774{
775    mySession.startTorrents( getSelectedTorrents( ) );
776}
777void
778TrMainWindow :: pauseSelected( )
779{
780    mySession.pauseTorrents( getSelectedTorrents( ) );
781}
782void
783TrMainWindow :: startAll( )
784{
785    mySession.startTorrents( );
786}
787void
788TrMainWindow :: pauseAll( )
789{
790    mySession.pauseTorrents( );
791}
792void
793TrMainWindow :: removeSelected( )
794{
795    mySession.removeTorrents( getSelectedTorrents( ), false );
796}
797void
798TrMainWindow :: deleteSelected( )
799{
800    mySession.removeTorrents( getSelectedTorrents( ), true );
801}
802void
803TrMainWindow :: verifySelected( )
804{
805    mySession.verifyTorrents( getSelectedTorrents( ) );
806}
807void
808TrMainWindow :: reannounceSelected( )
809{
810    mySession.reannounceTorrents( getSelectedTorrents( ) );
811}
812
813/**
814***
815**/
816
817void TrMainWindow :: setShowMode     ( int i ) { myPrefs.set( Prefs::FILTER_MODE, FilterMode( i ) ); }
818void TrMainWindow :: showAll         ( ) { setShowMode( FilterMode :: SHOW_ALL ); }
819void TrMainWindow :: showActive      ( ) { setShowMode( FilterMode :: SHOW_ACTIVE ); }
820void TrMainWindow :: showDownloading ( ) { setShowMode( FilterMode :: SHOW_DOWNLOADING ); }
821void TrMainWindow :: showSeeding     ( ) { setShowMode( FilterMode :: SHOW_SEEDING ); }
822void TrMainWindow :: showPaused      ( ) { setShowMode( FilterMode :: SHOW_PAUSED ); }
823
824void TrMainWindow :: filterByName    ( ) { myFilterModel.setTextMode( TorrentFilter :: FILTER_BY_NAME ); }
825void TrMainWindow :: filterByTracker ( ) { myFilterModel.setTextMode( TorrentFilter :: FILTER_BY_TRACKER ); }
826void TrMainWindow :: filterByFiles   ( ) { myFilterModel.setTextMode( TorrentFilter :: FILTER_BY_FILES ); }
827
828void TrMainWindow :: showTotalRatio      ( ) { myPrefs.set( Prefs::STATUSBAR_STATS, "total-ratio"); }
829void TrMainWindow :: showTotalTransfer   ( ) { myPrefs.set( Prefs::STATUSBAR_STATS, "total-transfer"); }
830void TrMainWindow :: showSessionRatio    ( ) { myPrefs.set( Prefs::STATUSBAR_STATS, "session-ratio"); }
831void TrMainWindow :: showSessionTransfer ( ) { myPrefs.set( Prefs::STATUSBAR_STATS, "session-transfer"); }
832
833/**
834***
835**/
836
837void
838TrMainWindow :: setMinimalView( bool visible )
839{
840    myPrefs.set( Prefs :: MINIMAL_VIEW, visible );
841}
842void
843TrMainWindow :: setTrayIconVisible( bool visible )
844{
845    myPrefs.set( Prefs :: SHOW_TRAY_ICON, visible );
846}
847void
848TrMainWindow :: toggleSpeedMode( )
849{
850    myPrefs.toggleBool( Prefs :: ALT_SPEED_LIMIT_ENABLED );
851}
852void
853TrMainWindow :: setToolbarVisible( bool visible )
854{
855    myPrefs.set( Prefs::TOOLBAR, visible );
856}
857void
858TrMainWindow :: setFilterbarVisible( bool visible )
859{
860    myPrefs.set( Prefs::FILTERBAR, visible );
861}
862void
863TrMainWindow :: setStatusbarVisible( bool visible )
864{
865    myPrefs.set( Prefs::STATUSBAR, visible );
866}
867
868/**
869***
870**/
871
872void
873TrMainWindow :: toggleWindows( )
874{
875    setVisible( !isVisible( ) );
876}
877
878void
879TrMainWindow :: trayActivated( QSystemTrayIcon::ActivationReason reason )
880{
881    if( reason == QSystemTrayIcon::Trigger )
882        ui.action_ShowMainWindow->toggle( );
883}
884
885
886void
887TrMainWindow :: refreshPref( int key )
888{
889    bool b;
890    int i;
891    QString str;
892
893    switch( key )
894    {
895        case Prefs::STATUSBAR_STATS:
896            str = myPrefs.getString( key );
897            ui.action_TotalRatio->setChecked     ( str == "total-ratio" );
898            ui.action_TotalTransfer->setChecked  ( str == "total-transfer" );
899            ui.action_SessionRatio->setChecked   ( str == "session-ratio" );
900            ui.action_SessionTransfer->setChecked( str == "session-transfer" );
901            refreshStatusBar( );
902            break;
903
904        case Prefs::SORT_REVERSED:
905            ui.action_ReverseSortOrder->setChecked( myPrefs.getBool( key ) );
906            break;
907
908        case Prefs::SORT_MODE:
909            i = myPrefs.get<SortMode>(key).mode( );
910            ui.action_SortByActivity->setChecked ( i == SortMode::SORT_BY_ACTIVITY );
911            ui.action_SortByAge->setChecked      ( i == SortMode::SORT_BY_AGE );
912            ui.action_SortByETA->setChecked      ( i == SortMode::SORT_BY_ETA );
913            ui.action_SortByName->setChecked     ( i == SortMode::SORT_BY_NAME );
914            ui.action_SortByProgress->setChecked ( i == SortMode::SORT_BY_PROGRESS );
915            ui.action_SortByRatio->setChecked    ( i == SortMode::SORT_BY_RATIO );
916            ui.action_SortBySize->setChecked     ( i == SortMode::SORT_BY_SIZE );
917            ui.action_SortByState->setChecked    ( i == SortMode::SORT_BY_STATE );
918            ui.action_SortByTracker->setChecked  ( i == SortMode::SORT_BY_TRACKER );
919            break;
920
921        case Prefs::DSPEED_ENABLED:
922            (myPrefs.get<bool>(key) ? myDlimitOnAction : myDlimitOffAction)->setChecked( true );
923            break;
924     
925        case Prefs::DSPEED:
926            myDlimitOnAction->setText( tr( "Limited at %1" ).arg( Utils::speedToString( Speed::fromKbps( myPrefs.get<int>(key) ) ) ) );
927            break;
928
929        case Prefs::USPEED_ENABLED:
930            (myPrefs.get<bool>(key) ? myUlimitOnAction : myUlimitOffAction)->setChecked( true );
931            break;
932     
933        case Prefs::USPEED:
934            myUlimitOnAction->setText( tr( "Limited at %1" ).arg( Utils::speedToString( Speed::fromKbps( myPrefs.get<int>(key) ) ) ) );
935            break;
936
937        case Prefs::RATIO_ENABLED:
938            (myPrefs.get<bool>(key) ? myRatioOnAction : myRatioOffAction)->setChecked( true );
939            break;
940
941        case Prefs::RATIO:
942            myRatioOnAction->setText( tr( "Stop at Ratio (%1)" ).arg( Utils::ratioToString( myPrefs.get<double>(key) ) ) );
943            break;
944
945        case Prefs::FILTER_MODE:
946            i = myPrefs.get<FilterMode>(key).mode( );
947            for( int j=0; j<FilterMode::NUM_MODES; ++j )
948                myFilterButtons[j]->setChecked( i==j );
949            break;
950
951        case Prefs::FILTERBAR:
952            b = myPrefs.getBool( key );
953            myFilterBar->setVisible( b );
954            ui.action_Filterbar->setChecked( b );
955            break;
956
957        case Prefs::STATUSBAR:
958            b = myPrefs.getBool( key );
959            myStatusBar->setVisible( b );
960            ui.action_Statusbar->setChecked( b );
961            break;
962
963        case Prefs::TOOLBAR:
964            b = myPrefs.getBool( key );
965            ui.toolBar->setVisible( b );
966            ui.action_Toolbar->setChecked( b );
967            break;
968
969        case Prefs::SHOW_TRAY_ICON:
970            b = myPrefs.getBool( key );
971            ui.action_TrayIcon->setChecked( b );
972            myTrayIcon.setVisible( b );
973            break;
974
975        case Prefs::MINIMAL_VIEW:
976            b = myPrefs.getBool( key );
977            ui.action_MinimalView->setChecked( b );
978            ui.listView->setItemDelegate( b ? myTorrentDelegateMin : myTorrentDelegate );
979            ui.listView->reset( ); // force the rows to resize
980            break;
981
982        case Prefs::MAIN_WINDOW_X:
983        case Prefs::MAIN_WINDOW_Y:
984        case Prefs::MAIN_WINDOW_WIDTH:
985        case Prefs::MAIN_WINDOW_HEIGHT:
986            setGeometry( myPrefs.getInt( Prefs::MAIN_WINDOW_X ),
987                         myPrefs.getInt( Prefs::MAIN_WINDOW_Y ),
988                         myPrefs.getInt( Prefs::MAIN_WINDOW_WIDTH ),
989                         myPrefs.getInt( Prefs::MAIN_WINDOW_HEIGHT ) );
990            break;
991
992        case Prefs :: ALT_SPEED_LIMIT_ENABLED:
993            b = myPrefs.getBool( key );
994            myAltSpeedButton->setChecked( b );
995            myAltSpeedButton->setIcon( b ? mySpeedModeOnIcon : mySpeedModeOffIcon );
996            myAltSpeedButton->setToolTip( b ? tr( "Click to disable Speed Limit Mode" )
997                                            : tr( "Click to enable Speed Limit Mode" ) );
998            break;
999
1000        default:
1001            break;
1002    }
1003}
1004
1005/***
1006****
1007***/
1008
1009void
1010TrMainWindow :: newTorrent( )
1011{
1012    MakeDialog * d = new MakeDialog( mySession, this );
1013    d->show( );
1014}
1015
1016void
1017TrMainWindow :: openTorrent( )
1018{
1019    if( myFileDialog == 0 )
1020    {
1021        myFileDialog = new QFileDialog( this,
1022                                        tr( "Add Torrent" ),
1023                                        myPrefs.getString( Prefs::OPEN_DIALOG_FOLDER ),
1024                                        tr( "Torrent Files (*.torrent);;All Files (*.*)" ) );
1025        myFileDialog->setFileMode( QFileDialog::ExistingFiles );
1026
1027
1028        QCheckBox * button = new QCheckBox( tr( "Display &options dialog" ) );
1029        button->setChecked( myPrefs.getBool( Prefs::OPTIONS_PROMPT ) );
1030        QGridLayout * layout = dynamic_cast<QGridLayout*>(myFileDialog->layout());
1031        layout->addWidget( button, layout->rowCount( ), 0, 1, -1, Qt::AlignLeft );
1032        myFileDialogOptionsCheck = button;
1033
1034        connect( myFileDialog, SIGNAL(filesSelected(const QStringList&)), this, SLOT(addTorrents(const QStringList&)));
1035    }
1036
1037    myFileDialog->show( );
1038}
1039
1040void
1041TrMainWindow :: addTorrents( const QStringList& filenames )
1042{
1043    foreach( const QString& filename, filenames )
1044        addTorrent( filename );
1045}
1046
1047void
1048TrMainWindow :: addTorrent( const QString& filename )
1049{
1050    if( !myFileDialogOptionsCheck->isChecked( ) ) {
1051        mySession.addTorrent( filename );
1052        QApplication :: alert ( this );
1053    } else {
1054        Options * o = new Options( mySession, myPrefs, filename, this );
1055        o->show( );
1056        QApplication :: alert( o );
1057    }
1058}
1059
1060/***
1061****
1062***/
1063
1064void
1065TrMainWindow :: updateNetworkIcon( )
1066{
1067    const time_t now = time( NULL );
1068    const int period = 3;
1069    const bool isSending = now - myLastSendTime <= period;
1070    const bool isReading = now - myLastReadTime <= period;
1071    const char * key;
1072
1073    if( isSending && isReading )
1074        key = "network-transmit-receive";
1075    else if( isSending )
1076        key = "network-transmit";
1077    else if( isReading )
1078        key = "network-receive";
1079    else
1080        key = "network-idle";
1081
1082    QIcon icon = getStockIcon( key, QStyle::SP_DriveNetIcon );
1083    QPixmap pixmap = icon.pixmap ( 16, 16 );
1084    myNetworkLabel->setPixmap( pixmap );
1085    myNetworkLabel->setToolTip( isSending || isReading
1086        ? tr( "Transmission server is responding" )
1087        : tr( "Last response from server was %1 ago" ).arg( Utils::timeToString( now-std::max(myLastReadTime,myLastSendTime))));
1088}
1089
1090void
1091TrMainWindow :: onNetworkTimer( )
1092{
1093    updateNetworkIcon( );
1094}
1095
1096void
1097TrMainWindow :: dataReadProgress( )
1098{
1099    myLastReadTime = time( NULL );
1100    updateNetworkIcon( );
1101}
1102
1103void
1104TrMainWindow :: dataSendProgress( )
1105{
1106    myLastSendTime = time( NULL );
1107    updateNetworkIcon( );
1108}
1109
1110void
1111TrMainWindow :: wrongAuthentication( )
1112{
1113    mySession.stop( );
1114    mySessionDialog->show( );
1115}
Note: See TracBrowser for help on using the repository browser.