source: trunk/qt/mainwin.cc @ 8233

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

(trunk) make it possible to #include "version.h" without having to add -I${TOP}/libtransmission/ to your CFLAGS

File size: 30.3 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 <QSize>
20#include <QStyle>
21#include <QHBoxLayout>
22#include <QSystemTrayIcon>
23#include <QUrl>
24#include <QSignalMapper>
25
26#include <libtransmission/version.h>
27
28#include "about.h"
29#include "details.h"
30#include "filters.h"
31#include "mainwin.h"
32#include "make-dialog.h"
33#include "options.h"
34#include "prefs.h"
35#include "prefs-dialog.h"
36#include "session.h"
37#include "speed.h"
38#include "stats-dialog.h"
39#include "torrent-delegate.h"
40#include "torrent-delegate-min.h"
41#include "torrent-filter.h"
42#include "torrent-model.h"
43#include "ui_mainwin.h"
44#include "utils.h"
45#include "qticonloader.h"
46
47#define PREFS_KEY "prefs-key";
48
49QIcon
50TrMainWindow :: getStockIcon( const QString& freedesktop_name, int fallback )
51{
52    QIcon fallbackIcon;
53
54    if( fallback > 0 )
55        fallbackIcon = style()->standardIcon( QStyle::StandardPixmap( fallback ), 0, this );
56
57    return QtIconLoader::icon( freedesktop_name, fallbackIcon );
58}
59
60namespace
61{
62    QSize calculateTextButtonSizeHint( QPushButton * button )
63    {
64        QStyleOptionButton opt;
65        opt.initFrom( button );
66        QString s( button->text( ) );
67        if( s.isEmpty( ) )
68            s = QString::fromLatin1( "XXXX" );
69        QFontMetrics fm = button->fontMetrics( );
70        QSize sz = fm.size( Qt::TextShowMnemonic, s );
71        return button->style()->sizeFromContents( QStyle::CT_PushButton, &opt, sz, button ).expandedTo( QApplication::globalStrut( ) );
72    }
73
74    void setTextButtonSizeHint( QPushButton * button )
75    {
76        /* this is kind of a hack, possibly coming from my being new to Qt.
77         * Qt 4.4's sizeHint calculations for QPushButton have it include
78         * space for an icon, even if no icon is used.  because of this,
79         * default pushbuttons look way too wide in the filterbar...
80         * so this routine recalculates the sizeHint without icons.
81         * If there's a Right Way to do this that I've missed, let me know */
82        button->setMaximumSize( calculateTextButtonSizeHint( button ) );
83    }
84}
85
86
87TrMainWindow :: TrMainWindow( Session& session, Prefs& prefs, TorrentModel& model, bool minimized ):
88    myLastFullUpdateTime( 0 ),
89    myPrefsDialog( new PrefsDialog( session, prefs, this ) ),
90    myAboutDialog( new AboutDialog( this ) ),
91    myStatsDialog( new StatsDialog( session, this ) ),
92    myFileDialog( 0 ),
93    myFilterModel( prefs ),
94    myTorrentDelegate( new TorrentDelegate( this ) ),
95    myTorrentDelegateMin( new TorrentDelegateMin( this ) ),
96    mySession( session ),
97    myPrefs( prefs ),
98    myModel( model ),
99    mySpeedModeOffIcon( ":/icons/alt-limit-off.png" ),
100    mySpeedModeOnIcon( ":/icons/alt-limit-on.png" ),
101    myLastSendTime( 0 ),
102    myLastReadTime( 0 ),
103    myNetworkTimer( this )
104{
105    QAction * sep = new QAction( this );
106    sep->setSeparator( true );
107
108    ui.setupUi( this );
109
110    QString title( "Transmission" );
111    const QUrl remoteUrl( session.getRemoteUrl( ) );
112    if( !remoteUrl.isEmpty( ) )
113        title += tr( " - %1" ).arg( remoteUrl.toString() );
114    setWindowTitle( title );
115
116    QStyle * style = this->style();
117
118    int i = style->pixelMetric( QStyle::PM_SmallIconSize, 0, this );
119    const QSize smallIconSize( i, i );
120
121    // icons
122    ui.action_Add->setIcon( getStockIcon( "list-add", QStyle::SP_DialogOpenButton ) );
123    ui.action_New->setIcon( getStockIcon( "document-new", QStyle::SP_DesktopIcon ) );
124    ui.action_Properties->setIcon( getStockIcon( "document-properties", QStyle::SP_DesktopIcon ) );
125    ui.action_OpenFolder->setIcon( getStockIcon( "folder-open", QStyle::SP_DirOpenIcon ) );
126    ui.action_Start->setIcon( getStockIcon( "media-playback-start", QStyle::SP_MediaPlay ) );
127    ui.action_Announce->setIcon( getStockIcon( "network-transmit-receive" ) );
128    ui.action_Pause->setIcon( getStockIcon( "media-playback-pause", QStyle::SP_MediaPause ) );
129    ui.action_Remove->setIcon( getStockIcon( "list-remove", QStyle::SP_TrashIcon ) );
130    ui.action_Delete->setIcon( getStockIcon( "edit-delete", QStyle::SP_TrashIcon ) );
131    ui.action_StartAll->setIcon( getStockIcon( "media-playback-start", QStyle::SP_MediaPlay ) );
132    ui.action_PauseAll->setIcon( getStockIcon( "media-playback-pause", QStyle::SP_MediaPause ) );
133    ui.action_Quit->setIcon( getStockIcon( "application-exit" ) );
134    ui.action_SelectAll->setIcon( getStockIcon( "edit-select-all" ) );
135    ui.action_ReverseSortOrder->setIcon( getStockIcon( "view-sort-ascending", QStyle::SP_ArrowDown ) );
136    ui.action_Preferences->setIcon( getStockIcon( "preferences-system" ) );
137    ui.action_Contents->setIcon( getStockIcon( "help-contents", QStyle::SP_DialogHelpButton ) );
138    ui.action_About->setIcon( getStockIcon( "help-about" ) );
139    ui.statusbarStatsButton->setIcon( getStockIcon( "view-refresh", QStyle::SP_BrowserReload ) );
140    ui.downloadIconLabel->setPixmap( getStockIcon( "go-down", QStyle::SP_ArrowDown ).pixmap( smallIconSize ) );
141    ui.uploadIconLabel->setPixmap( getStockIcon( "go-up", QStyle::SP_ArrowUp ).pixmap( smallIconSize ) );
142    ui.filterEntryModeButton->setIcon( getStockIcon( "edit-find", QStyle::SP_ArrowForward ) );
143    ui.filterEntryClearButton->setIcon( getStockIcon( "edit-clear", QStyle::SP_DialogCloseButton ) );
144
145    // ui signals
146    connect( ui.action_Toolbar, SIGNAL(toggled(bool)), this, SLOT(setToolbarVisible(bool)));
147    connect( ui.action_TrayIcon, SIGNAL(toggled(bool)), this, SLOT(setTrayIconVisible(bool)));
148    connect( ui.action_Filterbar, SIGNAL(toggled(bool)), this, SLOT(setFilterbarVisible(bool)));
149    connect( ui.action_Statusbar, SIGNAL(toggled(bool)), this, SLOT(setStatusbarVisible(bool)));
150    connect( ui.action_MinimalView, SIGNAL(toggled(bool)), this, SLOT(setMinimalView(bool)));
151    connect( ui.action_SortByActivity, SIGNAL(toggled(bool)), this, SLOT(onSortByActivityToggled(bool)));
152    connect( ui.action_SortByAge,      SIGNAL(toggled(bool)), this, SLOT(onSortByAgeToggled(bool)));
153    connect( ui.action_SortByETA,      SIGNAL(toggled(bool)), this, SLOT(onSortByETAToggled(bool)));
154    connect( ui.action_SortByName,     SIGNAL(toggled(bool)), this, SLOT(onSortByNameToggled(bool)));
155    connect( ui.action_SortByProgress, SIGNAL(toggled(bool)), this, SLOT(onSortByProgressToggled(bool)));
156    connect( ui.action_SortByRatio,    SIGNAL(toggled(bool)), this, SLOT(onSortByRatioToggled(bool)));
157    connect( ui.action_SortBySize,     SIGNAL(toggled(bool)), this, SLOT(onSortBySizeToggled(bool)));
158    connect( ui.action_SortByState,    SIGNAL(toggled(bool)), this, SLOT(onSortByStateToggled(bool)));
159    connect( ui.action_SortByTracker,  SIGNAL(toggled(bool)), this, SLOT(onSortByTrackerToggled(bool)));
160    connect( ui.action_ReverseSortOrder, SIGNAL(toggled(bool)), this, SLOT(setSortAscendingPref(bool)));
161    connect( ui.action_Start, SIGNAL(triggered()), this, SLOT(startSelected()));
162    connect( ui.action_Pause, SIGNAL(triggered()), this, SLOT(pauseSelected()));
163    connect( ui.action_Remove, SIGNAL(triggered()), this, SLOT(removeSelected()));
164    connect( ui.action_Delete, SIGNAL(triggered()), this, SLOT(deleteSelected()));
165    connect( ui.action_Verify, SIGNAL(triggered()), this, SLOT(verifySelected()) );
166    connect( ui.action_Announce, SIGNAL(triggered()), this, SLOT(reannounceSelected()) );
167    connect( ui.action_StartAll, SIGNAL(triggered()), this, SLOT(startAll()));
168    connect( ui.action_PauseAll, SIGNAL(triggered()), this, SLOT(pauseAll()));
169    connect( ui.action_Add, SIGNAL(triggered()), this, SLOT(openTorrent()));
170    connect( ui.action_New, SIGNAL(triggered()), this, SLOT(newTorrent()));
171    connect( ui.action_Preferences, SIGNAL(triggered()), myPrefsDialog, SLOT(show()));
172    connect( ui.action_Statistics, SIGNAL(triggered()), myStatsDialog, SLOT(show()));
173    connect( ui.action_About, SIGNAL(triggered()), myAboutDialog, SLOT(show()));
174    connect( ui.action_Contents, SIGNAL(triggered()), this, SLOT(openHelp()));
175    connect( ui.action_OpenFolder, SIGNAL(triggered()), this, SLOT(openFolder()));
176    connect( ui.action_Properties, SIGNAL(triggered()), this, SLOT(openProperties()));
177    connect( ui.listView, SIGNAL(activated(const QModelIndex&)), ui.action_Properties, SLOT(trigger()));
178
179    // context menu
180    QList<QAction*> actions;
181    actions << ui.action_Properties
182            << ui.action_OpenFolder
183            << sep
184            << ui.action_Start
185            << ui.action_Pause
186            << ui.action_Verify
187            << ui.action_Announce
188            << sep
189            << ui.action_Remove
190            << ui.action_Delete;
191    addActions( actions );
192    setContextMenuPolicy( Qt::ActionsContextMenu );
193
194    // signals
195    connect( ui.speedLimitModeButton, SIGNAL(clicked()), this, SLOT(toggleSpeedMode()));
196    connect( ui.filterAll, SIGNAL(clicked()), this, SLOT(showAll()));
197    connect( ui.filterActive, SIGNAL(clicked()), this, SLOT(showActive()));
198    connect( ui.filterDownloading, SIGNAL(clicked()), this, SLOT(showDownloading()));
199    connect( ui.filterSeeding, SIGNAL(clicked()), this, SLOT(showSeeding()));
200    connect( ui.filterPaused, SIGNAL(clicked()), this, SLOT(showPaused()));
201    connect( ui.filterEntryClearButton, SIGNAL(clicked()), ui.filterEntry, SLOT(clear()));
202    connect( ui.filterEntry, SIGNAL(textChanged(QString)), &myFilterModel, SLOT(setText(QString)));
203    connect( ui.action_SelectAll, SIGNAL(triggered()), ui.listView, SLOT(selectAll()));
204    connect( ui.action_DeselectAll, SIGNAL(triggered()), ui.listView, SLOT(clearSelection()));
205    setTextButtonSizeHint( ui.filterAll );
206    setTextButtonSizeHint( ui.filterActive );
207    setTextButtonSizeHint( ui.filterDownloading );
208    setTextButtonSizeHint( ui.filterSeeding );
209    setTextButtonSizeHint( ui.filterPaused );
210
211    connect( &myFilterModel, SIGNAL(rowsInserted(const QModelIndex&,int,int)), this, SLOT(refreshVisibleCount()));
212    connect( &myFilterModel, SIGNAL(rowsRemoved(const QModelIndex&,int,int)), this, SLOT(refreshVisibleCount()));
213    connect( &myFilterModel, SIGNAL(rowsInserted(const QModelIndex&,int,int)), this, SLOT(refreshActionSensitivity()));
214    connect( &myFilterModel, SIGNAL(rowsRemoved(const QModelIndex&,int,int)), this, SLOT(refreshActionSensitivity()));
215
216    connect( ui.action_Quit, SIGNAL(triggered()), QCoreApplication::instance(), SLOT(quit()) );
217
218    // torrent view
219    myFilterModel.setSourceModel( &myModel );
220    ui.listView->setModel( &myFilterModel );
221    connect( ui.listView->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&,const QItemSelection&)), this, SLOT(refreshActionSensitivity()));
222
223    QActionGroup * actionGroup = new QActionGroup( this );
224    actionGroup->addAction( ui.action_FilterByName );
225    actionGroup->addAction( ui.action_FilterByFiles );
226    actionGroup->addAction( ui.action_FilterByTracker );
227    QMenu * menu = new QMenu( );
228    menu->addAction( ui.action_FilterByName );
229    menu->addAction( ui.action_FilterByFiles );
230    menu->addAction( ui.action_FilterByTracker );
231    ui.filterEntryModeButton->setMenu( menu );
232    connect( ui.action_FilterByName, SIGNAL(triggered()), this, SLOT(filterByName()));
233    connect( ui.action_FilterByFiles, SIGNAL(triggered()), this, SLOT(filterByFiles()));
234    connect( ui.action_FilterByTracker, SIGNAL(triggered()), this, SLOT(filterByTracker()));
235    ui.action_FilterByName->setChecked( true );
236
237    actionGroup = new QActionGroup( this );
238    actionGroup->addAction( ui.action_TotalRatio );
239    actionGroup->addAction( ui.action_TotalTransfer );
240    actionGroup->addAction( ui.action_SessionRatio );
241    actionGroup->addAction( ui.action_SessionTransfer );
242    menu = new QMenu( );
243    menu->addAction( ui.action_TotalRatio );
244    menu->addAction( ui.action_TotalTransfer );
245    menu->addAction( ui.action_SessionRatio );
246    menu->addAction( ui.action_SessionTransfer );
247    connect( ui.action_TotalRatio, SIGNAL(triggered()), this, SLOT(showTotalRatio()));
248    connect( ui.action_TotalTransfer, SIGNAL(triggered()), this, SLOT(showTotalTransfer()));
249    connect( ui.action_SessionRatio, SIGNAL(triggered()), this, SLOT(showSessionRatio()));
250    connect( ui.action_SessionTransfer, SIGNAL(triggered()), this, SLOT(showSessionTransfer()));
251    ui.statusbarStatsButton->setMenu( menu );
252
253    actionGroup = new QActionGroup( this );
254    actionGroup->addAction( ui.action_SortByActivity );
255    actionGroup->addAction( ui.action_SortByAge );
256    actionGroup->addAction( ui.action_SortByETA );
257    actionGroup->addAction( ui.action_SortByName );
258    actionGroup->addAction( ui.action_SortByProgress );
259    actionGroup->addAction( ui.action_SortByRatio );
260    actionGroup->addAction( ui.action_SortBySize );
261    actionGroup->addAction( ui.action_SortByState );
262    actionGroup->addAction( ui.action_SortByTracker );
263
264    menu = new QMenu( );
265    menu->addAction( ui.action_Add );
266    menu->addSeparator( );
267    menu->addAction( ui.action_ShowMainWindow );
268    menu->addAction( ui.action_ShowMessageLog );
269    menu->addAction( ui.action_About );
270    menu->addSeparator( );
271    menu->addAction( ui.action_StartAll );
272    menu->addAction( ui.action_PauseAll );
273    menu->addSeparator( );
274    menu->addAction( ui.action_Quit );
275    myTrayIcon.setContextMenu( menu );
276    myTrayIcon.setIcon( QApplication::windowIcon( ) );
277
278    connect( ui.action_ShowMainWindow, SIGNAL(toggled(bool)), this, SLOT(toggleWindows()));
279    connect( &myTrayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(trayActivated(QSystemTrayIcon::ActivationReason)));
280    connect( &myPrefs, SIGNAL(changed(int)), this, SLOT(refreshPref(int)) );
281
282    ui.action_ShowMainWindow->setChecked( !minimized );
283    ui.action_TrayIcon->setChecked( minimized || prefs.getBool( Prefs::SHOW_TRAY_ICON ) );
284
285    QList<int> initKeys;
286    initKeys << Prefs :: MAIN_WINDOW_X
287             << Prefs :: SHOW_TRAY_ICON
288             << Prefs :: SORT_REVERSED
289             << Prefs :: SORT_MODE
290             << Prefs :: FILTER_MODE
291             << Prefs :: FILTERBAR
292             << Prefs :: STATUSBAR
293             << Prefs :: STATUSBAR_STATS
294             << Prefs :: TOOLBAR
295             << Prefs :: ALT_SPEED_LIMIT_ENABLED
296             << Prefs :: MINIMAL_VIEW;
297    foreach( int key, initKeys )
298        refreshPref( key );
299
300    connect( &mySession, SIGNAL(statsUpdated()), this, SLOT(refreshStatusBar()) );
301    connect( &mySession, SIGNAL(dataReadProgress()), this, SLOT(dataReadProgress()) );
302    connect( &mySession, SIGNAL(dataSendProgress()), this, SLOT(dataSendProgress()) );
303
304    if( mySession.isServer( ) )
305        ui.networkLabel->hide( );
306    else {
307        connect( &myNetworkTimer, SIGNAL(timeout()), this, SLOT(onNetworkTimer()));
308        myNetworkTimer.start( 1000 );
309    }
310
311    refreshActionSensitivity( );
312    refreshStatusBar( );
313    refreshVisibleCount( );
314}
315
316TrMainWindow :: ~TrMainWindow( )
317{
318}
319
320/****
321*****
322****/
323
324void
325TrMainWindow :: setSortPref( int i )
326{
327    myPrefs.set( Prefs::SORT_MODE, SortMode( i ) );
328}
329void TrMainWindow :: onSortByActivityToggled ( bool b ) { if( b ) setSortPref( SortMode::SORT_BY_ACTIVITY ); }
330void TrMainWindow :: onSortByAgeToggled      ( bool b ) { if( b ) setSortPref( SortMode::SORT_BY_AGE );      }
331void TrMainWindow :: onSortByETAToggled      ( bool b ) { if( b ) setSortPref( SortMode::SORT_BY_ETA );      }
332void TrMainWindow :: onSortByNameToggled     ( bool b ) { if( b ) setSortPref( SortMode::SORT_BY_NAME );     }
333void TrMainWindow :: onSortByProgressToggled ( bool b ) { if( b ) setSortPref( SortMode::SORT_BY_PROGRESS ); }
334void TrMainWindow :: onSortByRatioToggled    ( bool b ) { if( b ) setSortPref( SortMode::SORT_BY_RATIO );    }
335void TrMainWindow :: onSortBySizeToggled     ( bool b ) { if( b ) setSortPref( SortMode::SORT_BY_SIZE );     }
336void TrMainWindow :: onSortByStateToggled    ( bool b ) { if( b ) setSortPref( SortMode::SORT_BY_STATE );    }
337void TrMainWindow :: onSortByTrackerToggled  ( bool b ) { if( b ) setSortPref( SortMode::SORT_BY_TRACKER );  }
338
339void
340TrMainWindow :: setSortAscendingPref( bool b )
341{
342    myPrefs.set( Prefs::SORT_REVERSED, b );
343}
344
345/****
346*****
347****/
348
349void
350TrMainWindow :: openProperties( )
351{
352    const int id( *getSelectedTorrents().begin() );
353    Torrent * torrent( myModel.getTorrentFromId( id ) );
354    assert( torrent != 0 );
355    QDialog * d( new Details( mySession, *torrent, this ) );
356    d->show( );
357}
358
359void
360TrMainWindow :: openFolder( )
361{
362    const int torrentId( *getSelectedTorrents().begin() );
363    const Torrent * tor( myModel.getTorrentFromId( torrentId ) );
364    const QString path( tor->getPath( ) );
365    QDesktopServices :: openUrl( QUrl::fromLocalFile( path ) );
366}
367
368void
369TrMainWindow :: openHelp( )
370{
371    const char * fmt = "http://www.transmissionbt.com/help/gtk/%d.%dx";
372    int major, minor;
373    sscanf( SHORT_VERSION_STRING, "%d.%d", &major, &minor );
374    char url[128];
375    snprintf( url, sizeof( url ), fmt, major, minor/10 );
376    QDesktopServices :: openUrl( QUrl( QString( url ) ) );
377}
378
379void
380TrMainWindow :: refreshVisibleCount( )
381{
382    const int visibleCount( myFilterModel.rowCount( ) );
383    const int totalCount( visibleCount + myFilterModel.hiddenRowCount( ) );
384    QString str;
385    if( visibleCount == totalCount )
386        str = tr( "%Ln Torrent(s)", 0, totalCount );
387    else
388        str = tr( "%L1 of %Ln Torrent(s)", 0, totalCount ).arg( visibleCount );
389    ui.visibleCountLabel->setText( str );
390}
391
392void
393TrMainWindow :: refreshStatusBar( )
394{
395    const Speed up( myModel.getUploadSpeed( ) );
396    const Speed down( myModel.getDownloadSpeed( ) );
397    ui.uploadTextLabel->setText( Utils :: speedToString( up ) );
398    ui.downloadTextLabel->setText( Utils :: speedToString( down ) );
399    const QString mode( myPrefs.getString( Prefs::STATUSBAR_STATS ) );
400    QString str;
401
402    if( mode == "session-ratio" )
403    {
404        str = tr( "Ratio: %1" ).arg( Utils :: ratioToString( mySession.getStats().ratio ) );
405    }
406    else if( mode == "session-transfer" )
407    {
408        const tr_session_stats& stats( mySession.getStats( ) );
409        str = tr( "Down: %1, Up: %2" ).arg( Utils :: sizeToString( stats.downloadedBytes ) )
410                                      .arg( Utils :: sizeToString( stats.uploadedBytes ) );
411    }
412    else if( mode == "total-transfer" )
413    {
414        const tr_session_stats& stats( mySession.getCumulativeStats( ) );
415        str = tr( "Down: %1, Up: %2" ).arg( Utils :: sizeToString( stats.downloadedBytes ) )
416                                      .arg( Utils :: sizeToString( stats.uploadedBytes ) );
417    }
418    else /* default is "total-ratio" */
419    {
420        str = tr( "Ratio: %1" ).arg( Utils :: ratioToString( mySession.getCumulativeStats().ratio ) );
421    }
422
423    ui.statusbarStatsLabel->setText( str );
424}
425
426void
427TrMainWindow :: refreshActionSensitivity( )
428{
429    int selected( 0 );
430    int paused( 0 );
431    int selectedAndPaused( 0 );
432    int canAnnounce( 0 );
433    const QAbstractItemModel * model( ui.listView->model( ) );
434    const QItemSelectionModel * selectionModel( ui.listView->selectionModel( ) );
435    const int rowCount( model->rowCount( ) );
436
437    /* count how many torrents are selected, paused, etc */
438    for( int row=0; row<rowCount; ++row ) {
439        const QModelIndex modelIndex( model->index( row, 0 ) );
440        assert( model == modelIndex.model( ) );
441        const Torrent * tor( model->data( modelIndex, TorrentModel::TorrentRole ).value<const Torrent*>( ) );
442        const bool isSelected( selectionModel->isSelected( modelIndex ) );
443        const bool isPaused( tor->isPaused( ) );
444        if( isSelected )
445            ++selected;
446        if( isPaused )
447            ++ paused;
448        if( isSelected && isPaused )
449            ++selectedAndPaused;
450        if( tor->canManualAnnounce( ) )
451            ++canAnnounce;
452    }
453
454    const bool haveSelection( selected > 0 );
455    ui.action_Verify->setEnabled( haveSelection );
456    ui.action_Remove->setEnabled( haveSelection );
457    ui.action_Delete->setEnabled( haveSelection );
458    ui.action_DeselectAll->setEnabled( haveSelection );
459
460    const bool oneSelection( selected == 1 );
461    ui.action_Properties->setEnabled( oneSelection );
462    ui.action_OpenFolder->setEnabled( oneSelection );
463
464    ui.action_SelectAll->setEnabled( selected < rowCount );
465    ui.action_StartAll->setEnabled( paused > 0 );
466    ui.action_PauseAll->setEnabled( paused < rowCount );
467    ui.action_Start->setEnabled( selectedAndPaused > 0 );
468    ui.action_Pause->setEnabled( selectedAndPaused < selected );
469    ui.action_Announce->setEnabled( selected > 0 && ( canAnnounce == selected ) );
470}
471
472/**
473***
474**/
475
476void
477TrMainWindow :: clearSelection( )
478{
479    ui.action_DeselectAll->trigger( );
480}
481
482QSet<int>
483TrMainWindow :: getSelectedTorrents( ) const
484{
485    QSet<int> ids;
486
487    foreach( QModelIndex index, ui.listView->selectionModel( )->selectedRows( ) )
488    {
489        const Torrent * tor( index.model()->data( index, TorrentModel::TorrentRole ).value<const Torrent*>( ) );
490        ids.insert( tor->id( ) );
491    }
492
493    return ids;
494}
495
496void
497TrMainWindow :: startSelected( )
498{
499    mySession.start( getSelectedTorrents( ) );
500}
501void
502TrMainWindow :: pauseSelected( )
503{
504    mySession.pause( getSelectedTorrents( ) );
505}
506void
507TrMainWindow :: startAll( )
508{
509    mySession.start( );
510}
511void
512TrMainWindow :: pauseAll( )
513{
514    mySession.pause( );
515}
516void
517TrMainWindow :: removeSelected( )
518{
519    mySession.removeTorrents( getSelectedTorrents( ), false );
520}
521void
522TrMainWindow :: deleteSelected( )
523{
524    mySession.removeTorrents( getSelectedTorrents( ), true );
525}
526void
527TrMainWindow :: verifySelected( )
528{
529    mySession.verifyTorrents( getSelectedTorrents( ) );
530}
531void
532TrMainWindow :: reannounceSelected( )
533{
534    mySession.reannounceTorrents( getSelectedTorrents( ) );
535}
536
537/**
538***
539**/
540
541void TrMainWindow :: setShowMode     ( int i ) { myPrefs.set( Prefs::FILTER_MODE, FilterMode( i ) ); }
542void TrMainWindow :: showAll         ( ) { setShowMode( FilterMode :: SHOW_ALL ); }
543void TrMainWindow :: showActive      ( ) { setShowMode( FilterMode :: SHOW_ACTIVE ); }
544void TrMainWindow :: showDownloading ( ) { setShowMode( FilterMode :: SHOW_DOWNLOADING ); }
545void TrMainWindow :: showSeeding     ( ) { setShowMode( FilterMode :: SHOW_SEEDING ); }
546void TrMainWindow :: showPaused      ( ) { setShowMode( FilterMode :: SHOW_PAUSED ); }
547
548void TrMainWindow :: filterByName    ( ) { myFilterModel.setTextMode( TorrentFilter :: FILTER_BY_NAME ); }
549void TrMainWindow :: filterByTracker ( ) { myFilterModel.setTextMode( TorrentFilter :: FILTER_BY_TRACKER ); }
550void TrMainWindow :: filterByFiles   ( ) { myFilterModel.setTextMode( TorrentFilter :: FILTER_BY_FILES ); }
551
552void TrMainWindow :: showTotalRatio      ( ) { myPrefs.set( Prefs::STATUSBAR_STATS, "total-ratio"); }
553void TrMainWindow :: showTotalTransfer   ( ) { myPrefs.set( Prefs::STATUSBAR_STATS, "total-transfer"); }
554void TrMainWindow :: showSessionRatio    ( ) { myPrefs.set( Prefs::STATUSBAR_STATS, "session-ratio"); }
555void TrMainWindow :: showSessionTransfer ( ) { myPrefs.set( Prefs::STATUSBAR_STATS, "session-transfer"); }
556
557/**
558***
559**/
560
561void
562TrMainWindow :: setMinimalView( bool visible )
563{
564    myPrefs.set( Prefs :: MINIMAL_VIEW, visible );
565}
566void
567TrMainWindow :: setTrayIconVisible( bool visible )
568{
569    myPrefs.set( Prefs :: SHOW_TRAY_ICON, visible );
570}
571void
572TrMainWindow :: toggleSpeedMode( )
573{
574    myPrefs.toggleBool( Prefs :: ALT_SPEED_LIMIT_ENABLED );
575}
576void
577TrMainWindow :: setToolbarVisible( bool visible )
578{
579    myPrefs.set( Prefs::TOOLBAR, visible );
580}
581void
582TrMainWindow :: setFilterbarVisible( bool visible )
583{
584    myPrefs.set( Prefs::FILTERBAR, visible );
585}
586void
587TrMainWindow :: setStatusbarVisible( bool visible )
588{
589    myPrefs.set( Prefs::STATUSBAR, visible );
590}
591
592/**
593***
594**/
595
596void
597TrMainWindow :: toggleWindows( )
598{
599    setVisible( !isVisible( ) );
600}
601
602void
603TrMainWindow :: trayActivated( QSystemTrayIcon::ActivationReason reason )
604{
605    if( reason == QSystemTrayIcon::Trigger )
606        ui.action_ShowMainWindow->toggle( );
607}
608
609
610void
611TrMainWindow :: refreshPref( int key )
612{
613    bool b;
614    int i;
615    QString str;
616
617    switch( key )
618    {
619        case Prefs::STATUSBAR_STATS:
620            str = myPrefs.getString( key );
621            ui.action_TotalRatio->setChecked     ( str == "total-ratio" );
622            ui.action_TotalTransfer->setChecked  ( str == "total-transfer" );
623            ui.action_SessionRatio->setChecked   ( str == "session-ratio" );
624            ui.action_SessionTransfer->setChecked( str == "session-transfer" );
625            refreshStatusBar( );
626            break;
627
628        case Prefs::SORT_REVERSED:
629            ui.action_ReverseSortOrder->setChecked( myPrefs.getBool( key ) );
630            break;
631
632        case Prefs::SORT_MODE:
633            i = myPrefs.get<SortMode>(key).mode( );
634            ui.action_SortByActivity->setChecked ( i == SortMode::SORT_BY_ACTIVITY );
635            ui.action_SortByAge->setChecked      ( i == SortMode::SORT_BY_AGE );
636            ui.action_SortByETA->setChecked      ( i == SortMode::SORT_BY_ETA );
637            ui.action_SortByName->setChecked     ( i == SortMode::SORT_BY_NAME );
638            ui.action_SortByProgress->setChecked ( i == SortMode::SORT_BY_PROGRESS );
639            ui.action_SortByRatio->setChecked    ( i == SortMode::SORT_BY_RATIO );
640            ui.action_SortBySize->setChecked     ( i == SortMode::SORT_BY_SIZE );
641            ui.action_SortByState->setChecked    ( i == SortMode::SORT_BY_STATE );
642            ui.action_SortByTracker->setChecked  ( i == SortMode::SORT_BY_TRACKER );
643            break;
644
645        case Prefs::FILTER_MODE:
646            i = myPrefs.get<FilterMode>(key).mode( );
647            ui.filterAll->setChecked         ( i == FilterMode::SHOW_ALL );
648            ui.filterActive->setChecked      ( i == FilterMode::SHOW_ACTIVE );
649            ui.filterDownloading->setChecked ( i == FilterMode::SHOW_DOWNLOADING );
650            ui.filterSeeding->setChecked     ( i == FilterMode::SHOW_SEEDING );
651            ui.filterPaused->setChecked      ( i == FilterMode::SHOW_PAUSED );
652            break;
653
654        case Prefs::FILTERBAR:
655            b = myPrefs.getBool( key );
656            ui.filterbar->setVisible( b );
657            ui.action_Filterbar->setChecked( b );
658            break;
659
660        case Prefs::STATUSBAR:
661            b = myPrefs.getBool( key );
662            ui.statusbar->setVisible( b );
663            ui.action_Statusbar->setChecked( b );
664            break;
665
666        case Prefs::TOOLBAR:
667            b = myPrefs.getBool( key );
668            ui.toolBar->setVisible( b );
669            ui.action_Toolbar->setChecked( b );
670            break;
671
672        case Prefs::SHOW_TRAY_ICON:
673            b = myPrefs.getBool( key );
674            ui.action_TrayIcon->setChecked( b );
675            myTrayIcon.setVisible( b );
676            break;
677
678        case Prefs::MINIMAL_VIEW:
679            b = myPrefs.getBool( key );
680            ui.action_MinimalView->setChecked( b );
681            ui.listView->setItemDelegate( b ? myTorrentDelegateMin : myTorrentDelegate );
682            ui.listView->reset( ); // force the rows to resize
683            break;
684
685        case Prefs::MAIN_WINDOW_X:
686        case Prefs::MAIN_WINDOW_Y:
687        case Prefs::MAIN_WINDOW_WIDTH:
688        case Prefs::MAIN_WINDOW_HEIGHT:
689            setGeometry( myPrefs.getInt( Prefs::MAIN_WINDOW_X ),
690                         myPrefs.getInt( Prefs::MAIN_WINDOW_Y ),
691                         myPrefs.getInt( Prefs::MAIN_WINDOW_WIDTH ),
692                         myPrefs.getInt( Prefs::MAIN_WINDOW_HEIGHT ) );
693            break;
694
695        case Prefs :: ALT_SPEED_LIMIT_ENABLED:
696            b = myPrefs.getBool( key );
697            ui.speedLimitModeButton->setChecked( b );
698            ui.speedLimitModeButton->setIcon( b ? mySpeedModeOnIcon : mySpeedModeOffIcon );
699            ui.speedLimitModeButton->setToolTip( b ? tr( "Click to disable Speed Limit Mode" )
700                                                   : tr( "Click to enable Speed Limit Mode" ) );
701            break;
702
703        default:
704            break;
705    }
706}
707
708/***
709****
710***/
711
712void
713TrMainWindow :: newTorrent( )
714{
715    MakeDialog * d = new MakeDialog( mySession, this );
716    d->show( );
717}
718
719void
720TrMainWindow :: openTorrent( )
721{
722    if( myFileDialog == 0 )
723    {
724        myFileDialog = new QFileDialog( this,
725                                        tr( "Add Torrent" ),
726                                        myPrefs.getString( Prefs::OPEN_DIALOG_FOLDER ),
727                                        tr( "Torrent Files (*.torrent);;All Files (*.*)" ) );
728        myFileDialog->setFileMode( QFileDialog::ExistingFiles );
729
730
731        QCheckBox * button = new QCheckBox( tr( "Display &options dialog" ) );
732        button->setChecked( myPrefs.getBool( Prefs::OPTIONS_PROMPT ) );
733        QGridLayout * layout = dynamic_cast<QGridLayout*>(myFileDialog->layout());
734        layout->addWidget( button, layout->rowCount( ), 0, 1, -1, Qt::AlignLeft );
735        myFileDialogOptionsCheck = button;
736
737        connect( myFileDialog, SIGNAL(filesSelected(const QStringList&)), this, SLOT(addTorrents(const QStringList&)));
738    }
739
740    myFileDialog->show( );
741}
742
743void
744TrMainWindow :: addTorrents( const QStringList& filenames )
745{
746    foreach( const QString& filename, filenames )
747        addTorrent( filename );
748}
749
750void
751TrMainWindow :: addTorrent( const QString& filename )
752{
753    if( !myFileDialogOptionsCheck->isChecked( ) ) {
754        mySession.addTorrent( filename );
755        QApplication :: alert ( this );
756    } else {
757        Options * o = new Options( mySession, myPrefs, filename, this );
758        o->show( );
759        QApplication :: alert( o );
760    }
761}
762
763/***
764****
765***/
766
767void
768TrMainWindow :: updateNetworkIcon( )
769{
770    const time_t now = time( NULL );
771    const int period = 3;
772    const bool isSending = now - myLastSendTime <= period;
773    const bool isReading = now - myLastReadTime <= period;
774    const char * key;
775
776    if( isSending && isReading )
777        key = "network-transmit-receive";
778    else if( isSending )
779        key = "network-transmit";
780    else if( isReading )
781        key = "network-receive";
782    else
783        key = "network-idle";
784
785    QIcon icon = getStockIcon( key, QStyle::SP_DriveNetIcon );
786    QPixmap pixmap = icon.pixmap ( 16, 16 );
787    ui.networkLabel->setPixmap( pixmap );
788    ui.networkLabel->setToolTip( isSending || isReading
789        ? tr( "Transmission server is responding" )
790        : tr( "Last response from server was %1 ago" ).arg( Utils::timeToString( now-std::max(myLastReadTime,myLastSendTime))));
791}
792
793void
794TrMainWindow :: onNetworkTimer( )
795{
796    updateNetworkIcon( );
797}
798
799void
800TrMainWindow :: dataReadProgress( )
801{
802    myLastReadTime = time( NULL );
803    updateNetworkIcon( );
804}
805
806void
807TrMainWindow :: dataSendProgress( )
808{
809    myLastSendTime = time( NULL );
810    updateNetworkIcon( );
811}
Note: See TracBrowser for help on using the repository browser.