~ubuntu-branches/ubuntu/natty/transmission/natty

« back to all changes in this revision

Viewing changes to qt/.svn/text-base/mainwin.cc.svn-base

  • Committer: Bazaar Package Importer
  • Author(s): Jamie Strandboge
  • Date: 2010-01-07 10:50:13 UTC
  • Revision ID: james.westby@ubuntu.com-20100107105013-gcb78xrsnjr0jzb4
Tags: 1.80~b1-0ubuntu2
* SECURITY UPDATE: fix arbitrary file overwrite via crafted torrent file
  - debian/patches/CVE-2010-0012.patch: adjust metainfo.c to check for '../'
  - CVE-2010-0012
  - LP: #500625

Show diffs side-by-side

added added

removed removed

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