source: trunk/qt/prefs-dialog.cc @ 10931

Last change on this file since 10931 was 10931, checked in by charles, 12 years ago

(trunk) #3045 "make libtransmission's API byte-oriented instead of KiB-oriented." -- implemented. This is a largish commit and will break the mac build for a little while.

  • Property svn:keywords set to Date Rev Author Id
File size: 27.3 KB
Line 
1/*
2 * This file Copyright (C) 2009-2010 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: prefs-dialog.cc 10931 2010-07-03 00:25:22Z charles $
11 */
12
13#include <cassert>
14#include <iostream>
15
16#include <QCheckBox>
17#include <QComboBox>
18#include <QCoreApplication>
19#include <QDialogButtonBox>
20#include <QDoubleSpinBox>
21#include <QFileIconProvider>
22#include <QFileInfo>
23#include <QHBoxLayout>
24#include <QHttp>
25#include <QIcon>
26#include <QLabel>
27#include <QLineEdit>
28#include <QList>
29#include <QMessageBox>
30#include <QPushButton>
31#include <QSpinBox>
32#include <QStyle>
33#include <QTabWidget>
34#include <QTime>
35#include <QTimeEdit>
36#include <QTimer>
37#include <QVBoxLayout>
38
39#include "hig.h"
40#include "prefs.h"
41#include "prefs-dialog.h"
42#include "qticonloader.h"
43#include "session.h"
44#include "units.h"
45#include "utils.h"
46
47/***
48****
49***/
50
51namespace
52{
53    const char * PREF_KEY( "pref-key" );
54    const char * MULTIPLIER_KEY( "multiplier-key" );
55};
56
57void
58PrefsDialog :: checkBoxToggled( bool checked )
59{
60    const int key( sender( )->property( PREF_KEY ).toInt( ) );
61    myPrefs.set( key, checked );
62}
63
64QCheckBox *
65PrefsDialog :: checkBoxNew( const QString& text, int key )
66{
67    QCheckBox * box = new QCheckBox( text );
68    box->setChecked( myPrefs.getBool( key ) );
69    box->setProperty( PREF_KEY, key );
70    connect( box, SIGNAL(toggled(bool)), this, SLOT(checkBoxToggled(bool)));
71    myWidgets.insert( key, box );
72    return box;
73}
74
75void
76PrefsDialog :: enableBuddyWhenChecked( QCheckBox * box, QWidget * buddy )
77{
78    connect( box, SIGNAL(toggled(bool)), buddy, SLOT(setEnabled(bool)) );
79    buddy->setEnabled( box->isChecked( ) );
80}
81
82void
83PrefsDialog :: spinBoxChangedIdle( )
84{
85    const QObject * spin( sender()->property( "SPIN" ).value<QObject*>( ) );
86    const int key = spin->property( PREF_KEY ).toInt( );
87    const int multiplier = spin->property( MULTIPLIER_KEY ).toInt( );
88
89    const QDoubleSpinBox * d = qobject_cast<const QDoubleSpinBox*>( spin );
90    if( d != 0 )
91        myPrefs.set( key, multiplier * d->value( ) );
92    else
93        myPrefs.set( key, multiplier * qobject_cast<const QSpinBox*>(spin)->value( ) );
94}
95
96void
97PrefsDialog :: spinBoxChanged( int value )
98{
99    Q_UNUSED( value );
100
101    static const QString timerName( "TIMER_CHILD" );
102    QObject * o( sender( ) );
103
104    // user may be spinning through many values, so let's hold off
105    // for a moment to kekep from flooding a bunch of prefs changes
106    QTimer * timer( o->findChild<QTimer*>( timerName ) );
107    if( timer == 0 )
108    {
109        timer = new QTimer( o );
110        timer->setObjectName( timerName );
111        timer->setSingleShot( true );
112        timer->setProperty( "SPIN", qVariantFromValue( o ) );
113        connect( timer, SIGNAL(timeout()), this, SLOT(spinBoxChangedIdle()));
114    }
115    timer->start( 200 );
116}
117
118QSpinBox *
119PrefsDialog :: spinBoxNew( int key, int low, int high, int step, int multiplier )
120{
121    QSpinBox * spin = new QSpinBox( );
122    spin->setRange( low, high );
123    spin->setSingleStep( step );
124    spin->setValue( myPrefs.getInt( key ) / multiplier );
125    spin->setProperty( PREF_KEY, key );
126    spin->setProperty( MULTIPLIER_KEY, multiplier );
127    connect( spin, SIGNAL(valueChanged(int)), this, SLOT(spinBoxChanged(int)));
128    myWidgets.insert( key, spin );
129    return spin;
130}
131
132void
133PrefsDialog :: doubleSpinBoxChanged( double value )
134{
135    Q_UNUSED( value );
136
137    spinBoxChanged( 0 );
138}
139
140QDoubleSpinBox *
141PrefsDialog :: doubleSpinBoxNew( int key, double low, double high, double step, int decimals, int multiplier )
142{
143    QDoubleSpinBox * spin = new QDoubleSpinBox( );
144    spin->setRange( low, high );
145    spin->setSingleStep( step );
146    spin->setDecimals( decimals );
147    spin->setValue( myPrefs.getDouble( key ) / multiplier );
148    spin->setProperty( PREF_KEY, key );
149    spin->setProperty( MULTIPLIER_KEY, multiplier );
150    connect( spin, SIGNAL(valueChanged(double)), this, SLOT(doubleSpinBoxChanged(double)));
151    myWidgets.insert( key, spin );
152    return spin;
153}
154
155void
156PrefsDialog :: timeChanged( const QTime& time )
157{
158    const int key( sender()->property( PREF_KEY ).toInt( ) );
159    const int seconds( QTime().secsTo( time ) );
160    myPrefs.set( key, seconds / 60 );
161}
162
163QTimeEdit*
164PrefsDialog :: timeEditNew( int key )
165{
166    const int minutes( myPrefs.getInt( key ) );
167    QTimeEdit * e = new QTimeEdit( );
168    e->setDisplayFormat( "hh:mm" );
169    e->setProperty( PREF_KEY, key );
170    e->setTime( QTime().addSecs( minutes * 60 ) );
171    myWidgets.insert( key, e );
172    connect( e, SIGNAL(timeChanged(const QTime&)), this, SLOT(timeChanged(const QTime&)) );
173    return e;
174}
175
176void
177PrefsDialog :: textChanged( const QString& text )
178{
179    const int key( sender()->property( PREF_KEY ).toInt( ) );
180    myPrefs.set( key, text );
181}
182
183QLineEdit*
184PrefsDialog :: lineEditNew( int key, int echoMode )
185{
186    QLineEdit * e = new QLineEdit( myPrefs.getString( key ) );
187    e->setProperty( PREF_KEY, key );
188    e->setEchoMode( QLineEdit::EchoMode( echoMode ) );
189    myWidgets.insert( key, e );
190    connect( e, SIGNAL(textChanged(const QString&)), this, SLOT(textChanged(const QString&)) );
191    return e;
192}
193
194/***
195****
196***/
197
198QWidget *
199PrefsDialog :: createTrackerTab( )
200{
201    QWidget *l, *r;
202    HIG * hig = new HIG( );
203    hig->addSectionTitle( tr( "Tracker Proxy" ) );
204    hig->addWideControl( l = checkBoxNew( tr( "Connect to tracker via a pro&xy" ), Prefs::PROXY_ENABLED ) );
205    myUnsupportedWhenRemote << l;
206    l = hig->addRow( tr( "Proxy &server:" ), r = lineEditNew( Prefs::PROXY ) );
207    myProxyWidgets << l << r;
208    l = hig->addRow( tr( "Proxy &port:" ), r = spinBoxNew( Prefs::PROXY_PORT, 1, 65535, 1 ) );
209    myProxyWidgets << l << r;
210    hig->addWideControl( l = checkBoxNew( tr( "Use &authentication" ), Prefs::PROXY_AUTH_ENABLED ) );
211    myProxyWidgets << l;
212    l = hig->addRow( tr( "&Username:" ), r = lineEditNew( Prefs::PROXY_USERNAME ) );
213    myProxyAuthWidgets << l << r;
214    l = hig->addRow( tr( "Pass&word:" ), r = lineEditNew( Prefs::PROXY_PASSWORD, QLineEdit::Password ) );
215    myProxyAuthWidgets << l << r;
216    myUnsupportedWhenRemote << myProxyAuthWidgets;
217    hig->finish( );
218    return hig;
219}
220
221/***
222****
223***/
224
225QWidget *
226PrefsDialog :: createWebTab( Session& session )
227{
228    HIG * hig = new HIG( this );
229    hig->addSectionTitle( tr( "Web Client" ) );
230    QWidget * w;
231    QHBoxLayout * h = new QHBoxLayout( );
232    QIcon i( style()->standardIcon( QStyle::StandardPixmap( QStyle::SP_DirOpenIcon ) ) );
233    QPushButton * b = new QPushButton( i, tr( "&Open web client" ) );
234    connect( b, SIGNAL(clicked()), &session, SLOT(launchWebInterface()) );
235    h->addWidget( b, 0, Qt::AlignRight );
236    QWidget * l = checkBoxNew( tr( "&Enable web client" ), Prefs::RPC_ENABLED );
237    myUnsupportedWhenRemote << l;
238    hig->addRow( l, h, 0 );
239    l = hig->addRow( tr( "Listening &port:" ), w = spinBoxNew( Prefs::RPC_PORT, 0, 65535, 1 ) );
240    myWebWidgets << l << w;
241    hig->addWideControl( w = checkBoxNew( tr( "Use &authentication" ), Prefs::RPC_AUTH_REQUIRED ) );
242    myWebWidgets << w;
243    l = hig->addRow( tr( "&Username:" ), w = lineEditNew( Prefs::RPC_USERNAME ) );
244    myWebAuthWidgets << l << w;
245    l = hig->addRow( tr( "Pass&word:" ), w = lineEditNew( Prefs::RPC_PASSWORD, QLineEdit::Password ) );
246    myWebAuthWidgets << l << w;
247    hig->addWideControl( w = checkBoxNew( tr( "Only allow these IP a&ddresses to connect:" ), Prefs::RPC_WHITELIST_ENABLED ) );
248    myWebWidgets << w;
249    l = hig->addRow( tr( "Addresses:" ), w = lineEditNew( Prefs::RPC_WHITELIST ) );
250    myWebWhitelistWidgets << l << w;
251    myUnsupportedWhenRemote << myWebWidgets << myWebAuthWidgets << myWebWhitelistWidgets;
252    hig->finish( );
253    return hig;
254}
255
256/***
257****
258***/
259
260void
261PrefsDialog :: altSpeedDaysEdited( int i )
262{
263    const int value = qobject_cast<QComboBox*>(sender())->itemData(i).toInt();
264    myPrefs.set( Prefs::ALT_SPEED_LIMIT_TIME_DAY, value );
265}
266
267
268QWidget *
269PrefsDialog :: createSpeedTab( )
270{
271    QWidget *l, *r;
272    HIG * hig = new HIG( this );
273    hig->addSectionTitle( tr( "Speed Limits" ) );
274
275        l = checkBoxNew( tr( "Limit &download speed (%1):" ).arg( Units::speed_K_str ), Prefs::DSPEED_ENABLED );
276        r = spinBoxNew( Prefs::DSPEED, 0, INT_MAX, 5, Units::speed_K );
277        hig->addRow( l, r );
278        enableBuddyWhenChecked( qobject_cast<QCheckBox*>(l), r );
279
280        l = checkBoxNew( tr( "Limit &upload speed (%1):" ).arg( Units::speed_K_str ), Prefs::USPEED_ENABLED );
281        r = spinBoxNew( Prefs::USPEED, 0, INT_MAX, 5, Units::speed_K );
282        hig->addRow( l, r );
283        enableBuddyWhenChecked( qobject_cast<QCheckBox*>(l), r );
284
285    hig->addSectionDivider( );
286    QHBoxLayout * h = new QHBoxLayout;
287    h->setSpacing( HIG :: PAD );
288    QLabel * label = new QLabel;
289    label->setPixmap( QPixmap( ":/icons/alt-limit-off.png" ) );
290    label->setAlignment( Qt::AlignLeft|Qt::AlignVCenter );
291    h->addWidget( label );
292    label = new QLabel( tr( "Temporary Speed Limits" ) );
293    label->setStyleSheet( "font: bold" );
294    label->setAlignment( Qt::AlignLeft|Qt::AlignVCenter );
295    h->addWidget( label );
296    hig->addSectionTitle( h );
297
298        QString s = tr( "<small>Override normal speed limits manually or at scheduled times</small>" );
299        hig->addWideControl( new QLabel( s ) );
300
301        s = tr( "Limit d&ownload speed (%1):" ).arg( Units::speed_K_str );
302        r = spinBoxNew( Prefs :: ALT_SPEED_LIMIT_DOWN, 0, INT_MAX, 5, Units::speed_K );
303        hig->addRow( s, r );
304
305        s = tr( "Limit u&pload speed (%1):" ).arg( Units::speed_K_str );
306        r = spinBoxNew( Prefs :: ALT_SPEED_LIMIT_UP, 0, INT_MAX, 5, Units::speed_K );
307        hig->addRow( s, r );
308
309        QCheckBox * c = checkBoxNew( tr( "&Scheduled times:" ), Prefs::ALT_SPEED_LIMIT_TIME_ENABLED );
310        h = new QHBoxLayout( );
311        h->setSpacing( HIG::PAD );
312        QWidget * w = timeEditNew( Prefs :: ALT_SPEED_LIMIT_TIME_BEGIN );
313        h->addWidget( w, 1 );
314        mySchedWidgets << w;
315        QLabel * nd = new QLabel( "&to" );
316        h->addWidget( nd );
317        mySchedWidgets << nd;
318        w = timeEditNew( Prefs :: ALT_SPEED_LIMIT_TIME_END );
319        nd->setBuddy( w );
320        h->addWidget( w, 1 );
321        mySchedWidgets << w;
322        hig->addRow( c, h, 0 );
323
324        s = tr( "&On days:" );
325        QComboBox * box = new QComboBox;
326        const QIcon noIcon;
327        box->addItem( noIcon, tr( "Every Day" ), QVariant( TR_SCHED_ALL ) );
328        box->addItem( noIcon, tr( "Weekdays" ),  QVariant( TR_SCHED_WEEKDAY ) );
329        box->addItem( noIcon, tr( "Weekends" ),  QVariant( TR_SCHED_WEEKEND ) );
330        box->addItem( noIcon, tr( "Sunday" ),    QVariant( TR_SCHED_SUN ) );
331        box->addItem( noIcon, tr( "Monday" ),    QVariant( TR_SCHED_MON ) );
332        box->addItem( noIcon, tr( "Tuesday" ),   QVariant( TR_SCHED_TUES ) );
333        box->addItem( noIcon, tr( "Wednesday" ), QVariant( TR_SCHED_WED ) );
334        box->addItem( noIcon, tr( "Thursday" ),  QVariant( TR_SCHED_THURS ) );
335        box->addItem( noIcon, tr( "Friday" ),    QVariant( TR_SCHED_FRI ) );
336        box->addItem( noIcon, tr( "Saturday" ),  QVariant( TR_SCHED_SAT ) );
337        box->setCurrentIndex( box->findData( myPrefs.getInt( Prefs :: ALT_SPEED_LIMIT_TIME_DAY ) ) );
338        connect( box, SIGNAL(activated(int)), this, SLOT(altSpeedDaysEdited(int)) );
339        w = hig->addRow( s, box );
340        mySchedWidgets << w << box;
341
342    hig->finish( );
343    return hig;
344}
345
346/***
347****
348***/
349
350void
351PrefsDialog :: onPortTested( bool isOpen )
352{
353    myPortButton->setEnabled( true );
354    myWidgets[Prefs::PEER_PORT]->setEnabled( true );
355    myPortLabel->setText( isOpen ? tr( "Port is <b>open</b>" )
356                                 : tr( "Port is <b>closed</b>" ) );
357}
358
359void
360PrefsDialog :: onPortTest( )
361{
362    myPortLabel->setText( tr( "Testing..." ) );
363    myPortButton->setEnabled( false );
364    myWidgets[Prefs::PEER_PORT]->setEnabled( false );
365    mySession.portTest( );
366}
367
368QWidget *
369PrefsDialog :: createNetworkTab( )
370{
371    HIG * hig = new HIG( this );
372    hig->addSectionTitle( tr( "Incoming Peers" ) );
373
374    QSpinBox * s = spinBoxNew( Prefs::PEER_PORT, 1, 65535, 1 );
375    QHBoxLayout * h = new QHBoxLayout( );
376    QPushButton * b = myPortButton = new QPushButton( tr( "&Test Port" ) );
377    QLabel * l = myPortLabel = new QLabel( tr( "Status unknown" ) );
378    h->addWidget( l );
379    h->addSpacing( HIG :: PAD_BIG );
380    h->addWidget( b );
381    h->setStretchFactor( l, 1 );
382    connect( b, SIGNAL(clicked(bool)), this, SLOT(onPortTest()));
383    connect( &mySession, SIGNAL(portTested(bool)), this, SLOT(onPortTested(bool)));
384
385    hig->addRow( tr( "&Port for incoming connections:" ), s );
386    hig->addRow( "", h, 0 );
387    hig->addWideControl( checkBoxNew( tr( "Use UPnP or NAT-PMP port &forwarding from my router" ), Prefs::PORT_FORWARDING ) );
388    hig->addWideControl( checkBoxNew( tr( "Pick a &random port every time Transmission is started" ), Prefs :: PEER_PORT_RANDOM_ON_START ) );
389
390    hig->addSectionDivider( );
391    hig->addSectionTitle( tr( "Limits" ) );
392    hig->addRow( tr( "Maximum peers per &torrent:" ), spinBoxNew( Prefs::PEER_LIMIT_TORRENT, 1, 300, 5 ) );
393    hig->addRow( tr( "Maximum peers &overall:" ), spinBoxNew( Prefs::PEER_LIMIT_GLOBAL, 1, 3000, 5 ) );
394
395    hig->finish( );
396    return hig;
397}
398
399/***
400****
401***/
402
403void
404PrefsDialog :: onBlocklistDialogDestroyed( QObject * o )
405{
406    Q_UNUSED( o );
407
408    myBlocklistDialog = 0;
409}
410
411void
412PrefsDialog :: onUpdateBlocklistCancelled( )
413{
414    disconnect( &mySession, SIGNAL(blocklistUpdated(int)), this, SLOT(onBlocklistUpdated(int))) ;
415    myBlocklistDialog->deleteLater( );
416}
417
418void
419PrefsDialog :: onBlocklistUpdated( int n )
420{
421    myBlocklistDialog->setText( tr( "<b>Update succeeded!</b><p>Blocklist now has %Ln rules.", 0, n ) );
422    myBlocklistDialog->setTextFormat( Qt::RichText );
423}
424
425void
426PrefsDialog :: onUpdateBlocklistClicked( )
427{
428    myBlocklistDialog = new QMessageBox( QMessageBox::Information,
429                                         "",
430                                         tr( "<b>Update Blocklist</b><p>Getting new blocklist..." ),
431                                         QMessageBox::Close,
432                                         this );
433    QPixmap pixmap;
434    QIcon icon = QtIconLoader :: icon( "dialog-information" );
435    if( !icon.isNull( ) ) {
436        const int size = style()->pixelMetric( QStyle::PM_LargeIconSize );
437        myBlocklistDialog->setIconPixmap( icon.pixmap( size, size ) );
438    }
439    connect( myBlocklistDialog, SIGNAL(rejected()), this, SLOT(onUpdateBlocklistCancelled()) );
440    connect( &mySession, SIGNAL(blocklistUpdated(int)), this, SLOT(onBlocklistUpdated(int))) ;
441    myBlocklistDialog->show( );
442    mySession.updateBlocklist( );
443}
444
445void
446PrefsDialog :: encryptionEdited( int i )
447{
448    const int value( qobject_cast<QComboBox*>(sender())->itemData(i).toInt( ) );
449    myPrefs.set( Prefs::ENCRYPTION, value );
450}
451
452QWidget *
453PrefsDialog :: createPrivacyTab( )
454{
455    HIG * hig = new HIG( this );
456    hig->addSectionTitle( tr( "Blocklist" ) );
457    QHBoxLayout * h = new QHBoxLayout( );
458    QIcon i( style()->standardIcon( QStyle::StandardPixmap( QStyle::SP_BrowserReload ) ) );
459    QWidget * w = new QPushButton( i, tr( "&Update blocklist" ) );
460    connect( w, SIGNAL(clicked(bool)), this, SLOT(onUpdateBlocklistClicked()));
461    myBlockWidgets << w;
462    QWidget * l = checkBoxNew( "", Prefs::BLOCKLIST_ENABLED );
463    h->addWidget( l );
464    h->addStretch( 1 );
465    h->addWidget( w );
466    hig->addWideControl( h );
467    l = checkBoxNew( tr( "Enable &automatic updates" ), Prefs::BLOCKLIST_UPDATES_ENABLED );
468    myBlockWidgets << l;
469    hig->addWideControl( l );
470
471    QComboBox * box = new QComboBox( );
472    box->addItem( tr( "Allow encryption" ), 0 );
473    box->addItem( tr( "Prefer encryption" ), 1 );
474    box->addItem( tr( "Require encryption" ), 2 );
475    myWidgets.insert( Prefs :: ENCRYPTION, box );
476    connect( box, SIGNAL(activated(int)), this, SLOT(encryptionEdited(int)));
477
478    hig->addSectionDivider( );
479    hig->addSectionTitle( tr( "Privacy" ) );
480    hig->addRow( tr( "&Encryption mode:" ), box );
481    hig->addWideControl( w = checkBoxNew( tr( "Use PE&X to find more peers" ), Prefs::PEX_ENABLED ) );
482    w->setToolTip( tr( "PEX is a tool for exchanging peer lists with the peers you're connected to." ) );
483    hig->addWideControl( w = checkBoxNew( tr( "Use &DHT to find more peers" ), Prefs::DHT_ENABLED ) );
484    w->setToolTip( tr( "DHT is a tool for finding peers without a tracker." ) );
485    hig->addWideControl( w = checkBoxNew( tr( "Use &Local Peer Discovery to find more peers" ), Prefs::LPD_ENABLED ) );
486    w->setToolTip( tr( "LPD is a tool for finding peers on your local network." ) );
487
488    hig->finish( );
489    updateBlocklistCheckBox( );
490    return hig;
491}
492
493/***
494****
495***/
496
497void
498PrefsDialog :: onScriptClicked( void )
499{
500    const QString title = tr( "Select \"Torrent Done\" Script" );
501    const QString myPath = myPrefs.getString( Prefs::SCRIPT_TORRENT_DONE_FILENAME );
502    const QString path = Utils::remoteFileChooser( this, title, myPath, false, mySession.isServer() );
503
504    if( !path.isEmpty() )
505        onLocationSelected( path, Prefs::SCRIPT_TORRENT_DONE_FILENAME );
506}
507
508void
509PrefsDialog :: onIncompleteClicked( void )
510{
511    const QString title = tr( "Select Incomplete Directory" );
512    const QString myPath = myPrefs.getString( Prefs::INCOMPLETE_DIR );
513    const QString path = Utils::remoteFileChooser( this, title, myPath, true, mySession.isServer() );
514
515    if( !path.isEmpty() )
516        onLocationSelected( path, Prefs::INCOMPLETE_DIR );
517}
518
519void
520PrefsDialog :: onWatchClicked( void )
521{
522    const QString title = tr( "Select Watch Directory" );
523    const QString myPath = myPrefs.getString( Prefs::DIR_WATCH );
524    const QString path = Utils::remoteFileChooser( this, title, myPath, true, true );
525
526    if( !path.isEmpty() )
527        onLocationSelected( path, Prefs::DIR_WATCH );
528}
529
530void
531PrefsDialog :: onDestinationClicked( void )
532{
533    const QString title = tr( "Select Destination" );
534    const QString myPath = myPrefs.getString( Prefs::DOWNLOAD_DIR );
535    const QString path = Utils::remoteFileChooser( this, title, myPath, true, mySession.isServer() );
536
537    if( !path.isEmpty() )
538        onLocationSelected( path, Prefs::DOWNLOAD_DIR );
539}
540
541void
542PrefsDialog :: onLocationSelected( const QString& path, int key )
543{
544    myPrefs.set( key, path );
545    updatePref( key );
546}
547
548QWidget *
549PrefsDialog :: createTorrentsTab( )
550{
551    const int iconSize( style( )->pixelMetric( QStyle :: PM_SmallIconSize ) );
552    const QFileIconProvider iconProvider;
553    const QIcon folderIcon = iconProvider.icon( QFileIconProvider::Folder );
554    const QPixmap folderPixmap = folderIcon.pixmap( iconSize );
555    const QIcon fileIcon = iconProvider.icon( QFileIconProvider::File );
556    const QPixmap filePixmap = fileIcon.pixmap( iconSize );
557
558    QWidget *l, *r;
559    HIG * hig = new HIG( this );
560    hig->addSectionTitle( tr( "Adding" ) );
561
562        l = checkBoxNew( tr( "Automatically &add torrents from:" ), Prefs::DIR_WATCH_ENABLED );
563        QPushButton * b = myWatchButton = new QPushButton;
564        b->setIcon( folderPixmap );
565        b->setStyleSheet( "text-align: left; padding-left: 5; padding-right: 5" );
566        connect( b, SIGNAL(clicked(bool)), this, SLOT(onWatchClicked(void)) );
567        hig->addRow( l, b );
568        enableBuddyWhenChecked( qobject_cast<QCheckBox*>(l), b );
569
570        hig->addWideControl( checkBoxNew( tr( "Show &options dialog" ), Prefs::OPTIONS_PROMPT ) );
571        hig->addWideControl( checkBoxNew( tr( "&Start when added" ), Prefs::START ) );
572        hig->addWideControl( checkBoxNew( tr( "Mo&ve .torrent file to the trash" ), Prefs::TRASH_ORIGINAL ) );
573
574    hig->addSectionDivider( );
575    hig->addSectionTitle( tr( "Downloading" ) );
576
577        hig->addWideControl( checkBoxNew( tr( "Append \".&part\" to incomplete files' names" ), Prefs::RENAME_PARTIAL_FILES ) );
578
579        l = myIncompleteCheckbox = checkBoxNew( tr( "Keep &incomplete files in:" ), Prefs::INCOMPLETE_DIR_ENABLED );
580        b = myIncompleteButton = new QPushButton;
581        b->setIcon( folderPixmap );
582        b->setStyleSheet( "text-align: left; padding-left: 5; padding-right: 5" );
583        connect( b, SIGNAL(clicked(bool)), this, SLOT(onIncompleteClicked(void)) );
584        hig->addRow( myIncompleteCheckbox, b );
585        enableBuddyWhenChecked( qobject_cast<QCheckBox*>(l), b );
586
587        l = myTorrentDoneScriptCheckbox = checkBoxNew( tr( "Call scrip&t when torrent is completed" ), Prefs::SCRIPT_TORRENT_DONE_ENABLED );
588        b = myTorrentDoneScriptButton = new QPushButton;
589        b->setIcon( filePixmap );
590        b->setStyleSheet( "text-align: left; padding-left: 5; padding-right: 5" );
591        connect( b, SIGNAL(clicked(bool)), this, SLOT(onScriptClicked(void)) );
592        hig->addRow( myTorrentDoneScriptCheckbox, b );
593        enableBuddyWhenChecked( qobject_cast<QCheckBox*>(l), b );
594
595        b = myDestinationButton = new QPushButton;
596        b->setIcon( folderPixmap );
597        b->setStyleSheet( "text-align: left; padding-left: 5; padding-right: 5" );
598        connect( b, SIGNAL(clicked(bool)), this, SLOT(onDestinationClicked(void)) );
599        hig->addRow( tr( "Save to &Location:" ), b );
600
601    hig->addSectionDivider( );
602    hig->addSectionTitle( tr( "Seeding" ) );
603
604        l = checkBoxNew( tr( "&Seed torrent until its ratio reaches:" ), Prefs::RATIO_ENABLED );
605        r = doubleSpinBoxNew( Prefs::RATIO, 0, INT_MAX, 0.5, 2 );
606        hig->addRow( l, r );
607        enableBuddyWhenChecked( qobject_cast<QCheckBox*>(l), r );
608
609    hig->finish( );
610    return hig;
611}
612
613/***
614****
615***/
616
617PrefsDialog :: PrefsDialog( Session& session, Prefs& prefs, QWidget * parent ):
618    QDialog( parent ),
619    myIsServer( session.isServer( ) ),
620    mySession( session ),
621    myPrefs( prefs ),
622    myLayout( new QVBoxLayout( this ) )
623{
624    setWindowTitle( tr( "Transmission Preferences" ) );
625
626    QTabWidget * t = new QTabWidget( this );
627    t->addTab( createTorrentsTab( ),     tr( "Torrents" ) );
628    t->addTab( createSpeedTab( ),        tr( "Speed" ) );
629    t->addTab( createPrivacyTab( ),      tr( "Privacy" ) );
630    t->addTab( createNetworkTab( ),      tr( "Network" ) );
631    t->addTab( createWebTab( session ),  tr( "Web" ) );
632    //t->addTab( createTrackerTab( ),    tr( "Trackers" ) );
633    myLayout->addWidget( t );
634
635    QDialogButtonBox * buttons = new QDialogButtonBox( QDialogButtonBox::Close, Qt::Horizontal, this );
636    connect( buttons, SIGNAL(rejected()), this, SLOT(close()) ); // "close" triggers rejected
637    myLayout->addWidget( buttons );
638    QWidget::setAttribute( Qt::WA_DeleteOnClose, true );
639
640    connect( &mySession, SIGNAL(sessionUpdated()), this, SLOT(sessionUpdated()));
641
642    QList<int> keys;
643    keys << Prefs :: RPC_ENABLED
644         << Prefs :: PROXY_ENABLED
645         << Prefs :: ALT_SPEED_LIMIT_ENABLED
646         << Prefs :: ALT_SPEED_LIMIT_TIME_ENABLED
647         << Prefs :: ENCRYPTION
648         << Prefs :: BLOCKLIST_ENABLED
649         << Prefs :: DIR_WATCH
650         << Prefs :: DOWNLOAD_DIR
651         << Prefs :: INCOMPLETE_DIR
652         << Prefs :: INCOMPLETE_DIR_ENABLED;
653    foreach( int key, keys )
654        updatePref( key );
655
656    // if it's a remote session, disable the preferences
657    // that don't work in remote sessions
658    if( !myIsServer )  {
659        foreach( QWidget * w, myUnsupportedWhenRemote ) {
660            w->setToolTip( tr( "Not supported by remote sessions" ) );
661            w->setEnabled( false );
662        }
663    }
664}
665
666PrefsDialog :: ~PrefsDialog( )
667{
668}
669
670/***
671****
672***/
673
674void
675PrefsDialog :: sessionUpdated( )
676{
677    updateBlocklistCheckBox( );
678}
679
680void
681PrefsDialog :: updateBlocklistCheckBox( )
682{
683    QCheckBox * box = qobject_cast<QCheckBox*>( myWidgets[Prefs::BLOCKLIST_ENABLED] );
684    const int n = mySession.blocklistSize( );
685    if( n < 0 ) // unknown
686        box->setText( tr( "Enable &blocklist" ) );
687    else
688        box->setText( tr( "Enable &blocklist (%Ln rules)", 0, n ) );
689}
690
691void
692PrefsDialog :: updatePref( int key )
693{
694    switch( key )
695    {
696        case Prefs :: RPC_ENABLED:
697        case Prefs :: RPC_WHITELIST_ENABLED:
698        case Prefs :: RPC_AUTH_REQUIRED: {
699            const bool enabled( myPrefs.getBool( Prefs::RPC_ENABLED ) );
700            const bool whitelist( myPrefs.getBool( Prefs::RPC_WHITELIST_ENABLED ) );
701            const bool auth( myPrefs.getBool( Prefs::RPC_AUTH_REQUIRED ) );
702            foreach( QWidget * w, myWebWhitelistWidgets ) w->setEnabled( enabled && whitelist );
703            foreach( QWidget * w, myWebAuthWidgets ) w->setEnabled( enabled && auth );
704            foreach( QWidget * w, myWebWidgets ) w->setEnabled( enabled );
705            break;
706        }
707
708        case Prefs :: PROXY_ENABLED:
709        case Prefs :: PROXY_AUTH_ENABLED: {
710            const bool enabled( myPrefs.getBool( Prefs::PROXY_ENABLED ) );
711            const bool auth( myPrefs.getBool( Prefs::PROXY_AUTH_ENABLED ) );
712            foreach( QWidget * w, myProxyAuthWidgets ) w->setEnabled( enabled && auth );
713            foreach( QWidget * w, myProxyWidgets ) w->setEnabled( enabled );
714            break;
715        }
716
717        case Prefs :: ALT_SPEED_LIMIT_TIME_ENABLED: {
718            const bool enabled = myPrefs.getBool( key );
719            foreach( QWidget * w, mySchedWidgets ) w->setEnabled( enabled );
720            break;
721        }
722
723        case Prefs :: BLOCKLIST_ENABLED: {
724            const bool enabled = myPrefs.getBool( key );
725            foreach( QWidget * w, myBlockWidgets ) w->setEnabled( enabled );
726            break;
727        }
728
729        case Prefs :: DIR_WATCH:
730            myWatchButton->setText( QFileInfo(myPrefs.getString(Prefs::DIR_WATCH)).fileName() );
731            break;
732
733        case Prefs :: PEER_PORT:
734            myPortLabel->setText( tr( "Status unknown" ) );
735            myPortButton->setEnabled( true );
736            break;
737
738        case Prefs :: DOWNLOAD_DIR: {
739            QString path( myPrefs.getString( key ) );
740            myDestinationButton->setText( QFileInfo(path).fileName() );
741            break;
742        }
743
744        case Prefs :: INCOMPLETE_DIR: {
745            QString path( myPrefs.getString( key ) );
746            myIncompleteButton->setText( QFileInfo(path).fileName() );
747            break;
748        }
749
750        case Prefs :: INCOMPLETE_DIR_ENABLED: {
751            const bool enabled = myPrefs.getBool( key );
752            myIncompleteButton->setEnabled( enabled );
753            break;
754        }
755
756        default:
757            break;
758    }
759
760    key2widget_t::iterator it( myWidgets.find( key ) );
761    if( it != myWidgets.end( ) )
762    {
763        QWidget * w( it.value( ) );
764        QCheckBox * checkBox;
765        QSpinBox * spin;
766        QDoubleSpinBox * doubleSpin;
767        QTimeEdit * timeEdit;
768        QLineEdit * lineEdit;
769
770        if(( checkBox = qobject_cast<QCheckBox*>(w)))
771        {
772            checkBox->setChecked( myPrefs.getBool( key ) );
773        }
774        else if(( spin = qobject_cast<QSpinBox*>(w)))
775        {
776            spin->setValue( myPrefs.getInt( key ) );
777        }
778        else if(( doubleSpin = qobject_cast<QDoubleSpinBox*>(w)))
779        {
780            doubleSpin->setValue( myPrefs.getDouble( key ) );
781        }
782        else if(( timeEdit = qobject_cast<QTimeEdit*>(w)))
783        {
784            const int minutes( myPrefs.getInt( key ) );
785            timeEdit->setTime( QTime().addSecs( minutes * 60 ) );
786        }
787        else if(( lineEdit = qobject_cast<QLineEdit*>(w)))
788        {
789            lineEdit->setText( myPrefs.getString( key ) );
790        }
791        else if( key == Prefs::ENCRYPTION )
792        {
793            QComboBox * comboBox( qobject_cast<QComboBox*>( w ) );
794            const int index = comboBox->findData( myPrefs.getInt( key ) );
795            comboBox->setCurrentIndex( index );
796        }
797    }
798}
799
800bool
801PrefsDialog :: isAllowed( int key ) const
802{
803    Q_UNUSED( key );
804
805    return true;
806}
Note: See TracBrowser for help on using the repository browser.