source: trunk/qt/mainwin.cc @ 8344

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

(trunk qt) use the bubble-filter button patch

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    const QString mode( myPrefs.getString( Prefs::STATUSBAR_STATS ) );
671    QString str;
672
673    if( mode == "session-ratio" )
674    {
675        str = tr( "Ratio: %1" ).arg( Utils :: ratioToString( mySession.getStats().ratio ) );
676    }
677    else if( mode == "session-transfer" )
678    {
679        const tr_session_stats& stats( mySession.getStats( ) );
680        str = tr( "Down: %1, Up: %2" ).arg( Utils :: sizeToString( stats.downloadedBytes ) )
681                                      .arg( Utils :: sizeToString( stats.uploadedBytes ) );
682    }
683    else if( mode == "total-transfer" )
684    {
685        const tr_session_stats& stats( mySession.getCumulativeStats( ) );
686        str = tr( "Down: %1, Up: %2" ).arg( Utils :: sizeToString( stats.downloadedBytes ) )
687                                      .arg( Utils :: sizeToString( stats.uploadedBytes ) );
688    }
689    else /* default is "total-ratio" */
690    {
691        str = tr( "Ratio: %1" ).arg( Utils :: ratioToString( mySession.getCumulativeStats().ratio ) );
692    }
693
694    myStatsLabel->setText( str );
695}
696
697void
698TrMainWindow :: refreshActionSensitivity( )
699{
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( ) );
707
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        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;
723    }
724
725    const bool haveSelection( selected > 0 );
726    ui.action_Verify->setEnabled( haveSelection );
727    ui.action_Remove->setEnabled( haveSelection );
728    ui.action_Delete->setEnabled( haveSelection );
729    ui.action_Properties->setEnabled( haveSelection );
730    ui.action_DeselectAll->setEnabled( haveSelection );
731
732    const bool oneSelection( selected == 1 );
733    ui.action_OpenFolder->setEnabled( oneSelection );
734
735    ui.action_SelectAll->setEnabled( selected < rowCount );
736    ui.action_StartAll->setEnabled( paused > 0 );
737    ui.action_PauseAll->setEnabled( paused < rowCount );
738    ui.action_Start->setEnabled( selectedAndPaused > 0 );
739    ui.action_Pause->setEnabled( selectedAndPaused < selected );
740    ui.action_Announce->setEnabled( selected > 0 && ( canAnnounce == selected ) );
741
742    if( myDetailsDialog )
743        myDetailsDialog->setIds( getSelectedTorrents( ) );
744}
745
746/**
747***
748**/
749
750void
751TrMainWindow :: clearSelection( )
752{
753    ui.action_DeselectAll->trigger( );
754}
755
756QSet<int>
757TrMainWindow :: getSelectedTorrents( ) const
758{
759    QSet<int> ids;
760
761    foreach( QModelIndex index, ui.listView->selectionModel( )->selectedRows( ) )
762    {
763        const Torrent * tor( index.model()->data( index, TorrentModel::TorrentRole ).value<const Torrent*>( ) );
764        ids.insert( tor->id( ) );
765    }
766
767    return ids;
768}
769
770void
771TrMainWindow :: startSelected( )
772{
773    mySession.startTorrents( getSelectedTorrents( ) );
774}
775void
776TrMainWindow :: pauseSelected( )
777{
778    mySession.pauseTorrents( getSelectedTorrents( ) );
779}
780void
781TrMainWindow :: startAll( )
782{
783    mySession.startTorrents( );
784}
785void
786TrMainWindow :: pauseAll( )
787{
788    mySession.pauseTorrents( );
789}
790void
791TrMainWindow :: removeSelected( )
792{
793    mySession.removeTorrents( getSelectedTorrents( ), false );
794}
795void
796TrMainWindow :: deleteSelected( )
797{
798    mySession.removeTorrents( getSelectedTorrents( ), true );
799}
800void
801TrMainWindow :: verifySelected( )
802{
803    mySession.verifyTorrents( getSelectedTorrents( ) );
804}
805void
806TrMainWindow :: reannounceSelected( )
807{
808    mySession.reannounceTorrents( getSelectedTorrents( ) );
809}
810
811/**
812***
813**/
814
815void TrMainWindow :: setShowMode     ( int i ) { myPrefs.set( Prefs::FILTER_MODE, FilterMode( i ) ); }
816void TrMainWindow :: showAll         ( ) { setShowMode( FilterMode :: SHOW_ALL ); }
817void TrMainWindow :: showActive      ( ) { setShowMode( FilterMode :: SHOW_ACTIVE ); }
818void TrMainWindow :: showDownloading ( ) { setShowMode( FilterMode :: SHOW_DOWNLOADING ); }
819void TrMainWindow :: showSeeding     ( ) { setShowMode( FilterMode :: SHOW_SEEDING ); }
820void TrMainWindow :: showPaused      ( ) { setShowMode( FilterMode :: SHOW_PAUSED ); }
821
822void TrMainWindow :: filterByName    ( ) { myFilterModel.setTextMode( TorrentFilter :: FILTER_BY_NAME ); }
823void TrMainWindow :: filterByTracker ( ) { myFilterModel.setTextMode( TorrentFilter :: FILTER_BY_TRACKER ); }
824void TrMainWindow :: filterByFiles   ( ) { myFilterModel.setTextMode( TorrentFilter :: FILTER_BY_FILES ); }
825
826void TrMainWindow :: showTotalRatio      ( ) { myPrefs.set( Prefs::STATUSBAR_STATS, "total-ratio"); }
827void TrMainWindow :: showTotalTransfer   ( ) { myPrefs.set( Prefs::STATUSBAR_STATS, "total-transfer"); }
828void TrMainWindow :: showSessionRatio    ( ) { myPrefs.set( Prefs::STATUSBAR_STATS, "session-ratio"); }
829void TrMainWindow :: showSessionTransfer ( ) { myPrefs.set( Prefs::STATUSBAR_STATS, "session-transfer"); }
830
831/**
832***
833**/
834
835void
836TrMainWindow :: setMinimalView( bool visible )
837{
838    myPrefs.set( Prefs :: MINIMAL_VIEW, visible );
839}
840void
841TrMainWindow :: setTrayIconVisible( bool visible )
842{
843    myPrefs.set( Prefs :: SHOW_TRAY_ICON, visible );
844}
845void
846TrMainWindow :: toggleSpeedMode( )
847{
848    myPrefs.toggleBool( Prefs :: ALT_SPEED_LIMIT_ENABLED );
849}
850void
851TrMainWindow :: setToolbarVisible( bool visible )
852{
853    myPrefs.set( Prefs::TOOLBAR, visible );
854}
855void
856TrMainWindow :: setFilterbarVisible( bool visible )
857{
858    myPrefs.set( Prefs::FILTERBAR, visible );
859}
860void
861TrMainWindow :: setStatusbarVisible( bool visible )
862{
863    myPrefs.set( Prefs::STATUSBAR, visible );
864}
865
866/**
867***
868**/
869
870void
871TrMainWindow :: toggleWindows( )
872{
873    setVisible( !isVisible( ) );
874}
875
876void
877TrMainWindow :: trayActivated( QSystemTrayIcon::ActivationReason reason )
878{
879    if( reason == QSystemTrayIcon::Trigger )
880        ui.action_ShowMainWindow->toggle( );
881}
882
883
884void
885TrMainWindow :: refreshPref( int key )
886{
887    bool b;
888    int i;
889    QString str;
890
891    switch( key )
892    {
893        case Prefs::STATUSBAR_STATS:
894            str = myPrefs.getString( key );
895            ui.action_TotalRatio->setChecked     ( str == "total-ratio" );
896            ui.action_TotalTransfer->setChecked  ( str == "total-transfer" );
897            ui.action_SessionRatio->setChecked   ( str == "session-ratio" );
898            ui.action_SessionTransfer->setChecked( str == "session-transfer" );
899            refreshStatusBar( );
900            break;
901
902        case Prefs::SORT_REVERSED:
903            ui.action_ReverseSortOrder->setChecked( myPrefs.getBool( key ) );
904            break;
905
906        case Prefs::SORT_MODE:
907            i = myPrefs.get<SortMode>(key).mode( );
908            ui.action_SortByActivity->setChecked ( i == SortMode::SORT_BY_ACTIVITY );
909            ui.action_SortByAge->setChecked      ( i == SortMode::SORT_BY_AGE );
910            ui.action_SortByETA->setChecked      ( i == SortMode::SORT_BY_ETA );
911            ui.action_SortByName->setChecked     ( i == SortMode::SORT_BY_NAME );
912            ui.action_SortByProgress->setChecked ( i == SortMode::SORT_BY_PROGRESS );
913            ui.action_SortByRatio->setChecked    ( i == SortMode::SORT_BY_RATIO );
914            ui.action_SortBySize->setChecked     ( i == SortMode::SORT_BY_SIZE );
915            ui.action_SortByState->setChecked    ( i == SortMode::SORT_BY_STATE );
916            ui.action_SortByTracker->setChecked  ( i == SortMode::SORT_BY_TRACKER );
917            break;
918
919        case Prefs::DSPEED_ENABLED:
920            (myPrefs.get<bool>(key) ? myDlimitOnAction : myDlimitOffAction)->setChecked( true );
921            break;
922     
923        case Prefs::DSPEED:
924            myDlimitOnAction->setText( tr( "Limited at %1" ).arg( Utils::speedToString( Speed::fromKbps( myPrefs.get<int>(key) ) ) ) );
925            break;
926
927        case Prefs::USPEED_ENABLED:
928            (myPrefs.get<bool>(key) ? myUlimitOnAction : myUlimitOffAction)->setChecked( true );
929            break;
930     
931        case Prefs::USPEED:
932            myUlimitOnAction->setText( tr( "Limited at %1" ).arg( Utils::speedToString( Speed::fromKbps( myPrefs.get<int>(key) ) ) ) );
933            break;
934
935        case Prefs::RATIO_ENABLED:
936            (myPrefs.get<bool>(key) ? myRatioOnAction : myRatioOffAction)->setChecked( true );
937            break;
938
939        case Prefs::RATIO:
940            myRatioOnAction->setText( tr( "Stop at Ratio (%1)" ).arg( Utils::ratioToString( myPrefs.get<double>(key) ) ) );
941            break;
942
943        case Prefs::FILTER_MODE:
944            i = myPrefs.get<FilterMode>(key).mode( );
945            for( int j=0; j<FilterMode::NUM_MODES; ++j )
946                myFilterButtons[j]->setChecked( i==j );
947            break;
948
949        case Prefs::FILTERBAR:
950            b = myPrefs.getBool( key );
951            myFilterBar->setVisible( b );
952            ui.action_Filterbar->setChecked( b );
953            break;
954
955        case Prefs::STATUSBAR:
956            b = myPrefs.getBool( key );
957            myStatusBar->setVisible( b );
958            ui.action_Statusbar->setChecked( b );
959            break;
960
961        case Prefs::TOOLBAR:
962            b = myPrefs.getBool( key );
963            ui.toolBar->setVisible( b );
964            ui.action_Toolbar->setChecked( b );
965            break;
966
967        case Prefs::SHOW_TRAY_ICON:
968            b = myPrefs.getBool( key );
969            ui.action_TrayIcon->setChecked( b );
970            myTrayIcon.setVisible( b );
971            break;
972
973        case Prefs::MINIMAL_VIEW:
974            b = myPrefs.getBool( key );
975            ui.action_MinimalView->setChecked( b );
976            ui.listView->setItemDelegate( b ? myTorrentDelegateMin : myTorrentDelegate );
977            ui.listView->reset( ); // force the rows to resize
978            break;
979
980        case Prefs::MAIN_WINDOW_X:
981        case Prefs::MAIN_WINDOW_Y:
982        case Prefs::MAIN_WINDOW_WIDTH:
983        case Prefs::MAIN_WINDOW_HEIGHT:
984            setGeometry( myPrefs.getInt( Prefs::MAIN_WINDOW_X ),
985                         myPrefs.getInt( Prefs::MAIN_WINDOW_Y ),
986                         myPrefs.getInt( Prefs::MAIN_WINDOW_WIDTH ),
987                         myPrefs.getInt( Prefs::MAIN_WINDOW_HEIGHT ) );
988            break;
989
990        case Prefs :: ALT_SPEED_LIMIT_ENABLED:
991            b = myPrefs.getBool( key );
992            myAltSpeedButton->setChecked( b );
993            myAltSpeedButton->setIcon( b ? mySpeedModeOnIcon : mySpeedModeOffIcon );
994            myAltSpeedButton->setToolTip( b ? tr( "Click to disable Speed Limit Mode" )
995                                            : tr( "Click to enable Speed Limit Mode" ) );
996            break;
997
998        default:
999            break;
1000    }
1001}
1002
1003/***
1004****
1005***/
1006
1007void
1008TrMainWindow :: newTorrent( )
1009{
1010    MakeDialog * d = new MakeDialog( mySession, this );
1011    d->show( );
1012}
1013
1014void
1015TrMainWindow :: openTorrent( )
1016{
1017    if( myFileDialog == 0 )
1018    {
1019        myFileDialog = new QFileDialog( this,
1020                                        tr( "Add Torrent" ),
1021                                        myPrefs.getString( Prefs::OPEN_DIALOG_FOLDER ),
1022                                        tr( "Torrent Files (*.torrent);;All Files (*.*)" ) );
1023        myFileDialog->setFileMode( QFileDialog::ExistingFiles );
1024
1025
1026        QCheckBox * button = new QCheckBox( tr( "Display &options dialog" ) );
1027        button->setChecked( myPrefs.getBool( Prefs::OPTIONS_PROMPT ) );
1028        QGridLayout * layout = dynamic_cast<QGridLayout*>(myFileDialog->layout());
1029        layout->addWidget( button, layout->rowCount( ), 0, 1, -1, Qt::AlignLeft );
1030        myFileDialogOptionsCheck = button;
1031
1032        connect( myFileDialog, SIGNAL(filesSelected(const QStringList&)), this, SLOT(addTorrents(const QStringList&)));
1033    }
1034
1035    myFileDialog->show( );
1036}
1037
1038void
1039TrMainWindow :: addTorrents( const QStringList& filenames )
1040{
1041    foreach( const QString& filename, filenames )
1042        addTorrent( filename );
1043}
1044
1045void
1046TrMainWindow :: addTorrent( const QString& filename )
1047{
1048    if( !myFileDialogOptionsCheck->isChecked( ) ) {
1049        mySession.addTorrent( filename );
1050        QApplication :: alert ( this );
1051    } else {
1052        Options * o = new Options( mySession, myPrefs, filename, this );
1053        o->show( );
1054        QApplication :: alert( o );
1055    }
1056}
1057
1058/***
1059****
1060***/
1061
1062void
1063TrMainWindow :: updateNetworkIcon( )
1064{
1065    const time_t now = time( NULL );
1066    const int period = 3;
1067    const bool isSending = now - myLastSendTime <= period;
1068    const bool isReading = now - myLastReadTime <= period;
1069    const char * key;
1070
1071    if( isSending && isReading )
1072        key = "network-transmit-receive";
1073    else if( isSending )
1074        key = "network-transmit";
1075    else if( isReading )
1076        key = "network-receive";
1077    else
1078        key = "network-idle";
1079
1080    QIcon icon = getStockIcon( key, QStyle::SP_DriveNetIcon );
1081    QPixmap pixmap = icon.pixmap ( 16, 16 );
1082    myNetworkLabel->setPixmap( pixmap );
1083    myNetworkLabel->setToolTip( isSending || isReading
1084        ? tr( "Transmission server is responding" )
1085        : tr( "Last response from server was %1 ago" ).arg( Utils::timeToString( now-std::max(myLastReadTime,myLastSendTime))));
1086}
1087
1088void
1089TrMainWindow :: onNetworkTimer( )
1090{
1091    updateNetworkIcon( );
1092}
1093
1094void
1095TrMainWindow :: dataReadProgress( )
1096{
1097    myLastReadTime = time( NULL );
1098    updateNetworkIcon( );
1099}
1100
1101void
1102TrMainWindow :: dataSendProgress( )
1103{
1104    myLastSendTime = time( NULL );
1105    updateNetworkIcon( );
1106}
1107
1108void
1109TrMainWindow :: wrongAuthentication( )
1110{
1111    mySession.stop( );
1112    mySessionDialog->show( );
1113}
Note: See TracBrowser for help on using the repository browser.