source: trunk/qt/mainwin.cc @ 8890

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

(trunk qt) #2321: in qt client in 1.73, When main window minimized click on tray icon does nothing

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