source: trunk/qt/mainwin.cc @ 8216

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

(qt) better integration of sort & filter modes into the preferences mechanism

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