~hendrik-grewe/transmission/private-patch

« back to all changes in this revision

Viewing changes to qt/mainwin.cc

  • Committer: charles
  • Date: 2009-04-09 17:55:47 UTC
  • Revision ID: svn-v4:f4695dd4-2c0a-0410-b89c-da849a56a58e:trunk:8188
(trunk) add the Qt beta into svn 

Show diffs side-by-side

added added

removed removed

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