source: trunk/qt/app.cc @ 10489

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

(trunk qt) #3148 "command-line password argument isn't parsed correctly" -- fixed in trunk for 2.00. added backport-1.9x if/when we do 1.93.

  • Property svn:keywords set to Date Rev Author Id
File size: 10.6 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: app.cc 10489 2010-04-16 20:17:52Z charles $
11 */
12
13#include <cassert>
14#include <ctime>
15#include <iostream>
16
17#include <QDialogButtonBox>
18#include <QIcon>
19#include <QLabel>
20#include <QLibraryInfo>
21#include <QRect>
22#include <QTranslator>
23
24#include <libtransmission/transmission.h>
25#include <libtransmission/tr-getopt.h>
26#include <libtransmission/version.h>
27
28#include "app.h"
29#include "mainwin.h"
30#include "options.h"
31#include "prefs.h"
32#include "session.h"
33#include "session-dialog.h"
34#include "torrent-model.h"
35#include "utils.h"
36#include "watchdir.h"
37
38namespace
39{
40    const char * MY_NAME( "transmission" );
41
42    const tr_option opts[] =
43    {
44        { 'g', "config-dir", "Where to look for configuration files", "g", 1, "<path>" },
45        { 'm', "minimized",  "Start minimized in system tray", "m", 0, NULL },
46        { 'p', "port",  "Port to use when connecting to an existing session", "p", 1, "<port>" },
47        { 'r', "remote",  "Connect to an existing session at the specified hostname", "r", 1, "<host>" },
48        { 'u', "username", "Username to use when connecting to an existing session", "v", 1, "<username>" },
49        { 'v', "version", "Show version number and exit", "v", 0, NULL },
50        { 'w', "password", "Password to use when connecting to an existing session", "w", 1, "<password>" },
51        { 0, NULL, NULL, NULL, 0, NULL }
52    };
53
54    const char*
55    getUsage( void )
56    {
57        return "Usage:\n"
58               "  transmission [OPTIONS...] [torrent files]";
59    }
60
61    void
62    showUsage( void )
63    {
64        tr_getopt_usage( MY_NAME, getUsage( ), opts );
65        exit( 0 );
66    }
67
68    enum
69    {
70        STATS_REFRESH_INTERVAL_MSEC = 3000,
71        SESSION_REFRESH_INTERVAL_MSEC = 3000,
72        MODEL_REFRESH_INTERVAL_MSEC = 3000
73    };
74}
75
76MyApp :: MyApp( int& argc, char ** argv ):
77    QApplication( argc, argv ),
78    myLastFullUpdateTime( 0 )
79{
80    setApplicationName( MY_NAME );
81
82    // install the qt translator
83    QTranslator * t = new QTranslator( );
84    t->load( "qt_" + QLocale::system().name(), QLibraryInfo::location(QLibraryInfo::TranslationsPath));
85    installTranslator( t );
86
87    // install the transmission translator
88    t = new QTranslator( );
89    t->load( QString(MY_NAME) + "_" + QLocale::system().name() );
90    installTranslator( t );
91
92    // set the default icon
93    QIcon icon;
94    icon.addPixmap( QPixmap( ":/icons/transmission-16.png" ) );
95    icon.addPixmap( QPixmap( ":/icons/transmission-22.png" ) );
96    icon.addPixmap( QPixmap( ":/icons/transmission-24.png" ) );
97    icon.addPixmap( QPixmap( ":/icons/transmission-32.png" ) );
98    icon.addPixmap( QPixmap( ":/icons/transmission-48.png" ) );
99    setWindowIcon( icon );
100
101    // parse the command-line arguments
102    int c;
103    bool minimized = false;
104    const char * optarg;
105    const char * host = 0;
106    const char * port = 0;
107    const char * username = 0;
108    const char * password = 0;
109    const char * configDir = 0;
110    QStringList filenames;
111    while( ( c = tr_getopt( getUsage( ), argc, (const char**)argv, opts, &optarg ) ) ) {
112        switch( c ) {
113            case 'g': configDir = optarg; break;
114            case 'p': port = optarg; break;
115            case 'r': host = optarg; break;
116            case 'u': username = optarg; break;
117            case 'w': password = optarg; break;
118            case 'm': minimized = true; break;
119            case 'v':        Utils::toStderr( QObject::tr( "transmission %1" ).arg( LONG_VERSION_STRING ) ); exit( 0 ); break;
120            case TR_OPT_ERR: Utils::toStderr( QObject::tr( "Invalid option" ) ); showUsage( ); break;
121            default:         filenames.append( optarg ); break;
122        }
123    }
124
125    // set the fallback config dir
126    if( configDir == 0 )
127        configDir = tr_getDefaultConfigDir( MY_NAME );
128
129    // is this the first time we've run transmission?
130    const bool firstTime = !QFile(QDir(configDir).absoluteFilePath("settings.json")).exists();
131
132    // initialize the prefs
133    myPrefs = new Prefs ( configDir );
134    if( host != 0 )
135        myPrefs->set( Prefs::SESSION_REMOTE_HOST, host );
136    if( port != 0 )
137        myPrefs->set( Prefs::SESSION_REMOTE_PORT, port );
138    if( username != 0 )
139        myPrefs->set( Prefs::SESSION_REMOTE_USERNAME, username );
140    if( password != 0 )
141        myPrefs->set( Prefs::SESSION_REMOTE_PASSWORD, password );
142    if( ( host != 0 ) || ( port != 0 ) || ( username != 0 ) || ( password != 0 ) )
143        myPrefs->set( Prefs::SESSION_IS_REMOTE, true );
144
145    mySession = new Session( configDir, *myPrefs );
146    myModel = new TorrentModel( *myPrefs );
147    myWindow = new TrMainWindow( *mySession, *myPrefs, *myModel, minimized );
148    myWatchDir = new WatchDir( *myModel );
149
150    // when the session gets torrent info, update the model
151    connect( mySession, SIGNAL(torrentsUpdated(tr_benc*,bool)), myModel, SLOT(updateTorrents(tr_benc*,bool)) );
152    connect( mySession, SIGNAL(torrentsUpdated(tr_benc*,bool)), myWindow, SLOT(refreshActionSensitivity()) );
153    connect( mySession, SIGNAL(torrentsRemoved(tr_benc*)), myModel, SLOT(removeTorrents(tr_benc*)) );
154    // when the model sees a torrent for the first time, ask the session for full info on it
155    connect( myModel, SIGNAL(torrentsAdded(QSet<int>)), mySession, SLOT(initTorrents(QSet<int>)) );
156
157    mySession->initTorrents( );
158    mySession->refreshSessionStats( );
159
160    // when torrents are added to the watch directory, tell the session
161    connect( myWatchDir, SIGNAL(torrentFileAdded(QString)), this, SLOT(addTorrent(QString)) );
162
163    // init from preferences
164    QList<int> initKeys;
165    initKeys << Prefs::DIR_WATCH;
166    foreach( int key, initKeys )
167        refreshPref( key );
168    connect( myPrefs, SIGNAL(changed(int)), this, SLOT(refreshPref(const int)) );
169
170    QTimer * timer = &myModelTimer;
171    connect( timer, SIGNAL(timeout()), this, SLOT(refreshTorrents()) );
172    timer->setSingleShot( false );
173    timer->setInterval( MODEL_REFRESH_INTERVAL_MSEC );
174    timer->start( );
175
176    timer = &myStatsTimer;
177    connect( timer, SIGNAL(timeout()), mySession, SLOT(refreshSessionStats()) );
178    timer->setSingleShot( false );
179    timer->setInterval( STATS_REFRESH_INTERVAL_MSEC );
180    timer->start( );
181
182    timer = &mySessionTimer;
183    connect( timer, SIGNAL(timeout()), mySession, SLOT(refreshSessionInfo()) );
184    timer->setSingleShot( false );
185    timer->setInterval( SESSION_REFRESH_INTERVAL_MSEC );
186    timer->start( );
187
188    maybeUpdateBlocklist( );
189
190    if( !firstTime )
191        mySession->restart( );
192    else {
193        QDialog * d = new SessionDialog( *mySession, *myPrefs, myWindow );
194        d->show( );
195    }
196
197    if( !myPrefs->getBool( Prefs::USER_HAS_GIVEN_INFORMED_CONSENT ))
198    {
199        QDialog * dialog = new QDialog( myWindow );
200        dialog->setModal( true );
201        QVBoxLayout * v = new QVBoxLayout( dialog );
202        QLabel * l = new QLabel( tr( "Transmission is a file sharing program.  When you run a torrent, its data will be made available to others by means of upload.  And of course, any content you share is your sole responsibility.\n\nYou probably knew this, so we won't tell you again." ) );
203        l->setWordWrap( true );
204        v->addWidget( l );
205        QDialogButtonBox * box = new QDialogButtonBox;
206        box->addButton( new QPushButton( tr( "&Cancel" ) ), QDialogButtonBox::RejectRole );
207        QPushButton * agree = new QPushButton( tr( "I &Agree" ) );
208        agree->setDefault( true );
209        box->addButton( agree, QDialogButtonBox::AcceptRole );
210        box->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed );
211        box->setOrientation( Qt::Horizontal );
212        v->addWidget( box );
213        connect( box, SIGNAL(rejected()), this, SLOT(quit()) );
214        connect( box, SIGNAL(accepted()), dialog, SLOT(deleteLater()) );
215        connect( box, SIGNAL(accepted()), this, SLOT(consentGiven()) );
216        dialog->show();
217    }
218
219    for( QStringList::const_iterator it=filenames.begin(), end=filenames.end(); it!=end; ++it )
220        mySession->addTorrent( *it );
221}
222
223void
224MyApp :: consentGiven( )
225{
226    myPrefs->set<bool>( Prefs::USER_HAS_GIVEN_INFORMED_CONSENT, true );
227}
228
229MyApp :: ~MyApp( )
230{
231    const QRect mainwinRect( myWindow->geometry( ) );
232    delete myWatchDir;
233    delete myWindow;
234    delete myModel;
235    delete mySession;
236
237    myPrefs->set( Prefs :: MAIN_WINDOW_HEIGHT, std::max( 100, mainwinRect.height( ) ) );
238    myPrefs->set( Prefs :: MAIN_WINDOW_WIDTH, std::max( 100, mainwinRect.width( ) ) );
239    myPrefs->set( Prefs :: MAIN_WINDOW_X, mainwinRect.x( ) );
240    myPrefs->set( Prefs :: MAIN_WINDOW_Y, mainwinRect.y( ) );
241    delete myPrefs;
242}
243
244/***
245****
246***/
247
248void
249MyApp :: refreshPref( int key )
250{
251    switch( key )
252    {
253        case Prefs :: BLOCKLIST_UPDATES_ENABLED:
254            maybeUpdateBlocklist( );
255            break;
256
257        case Prefs :: DIR_WATCH:
258        case Prefs :: DIR_WATCH_ENABLED: {
259            const QString path( myPrefs->getString( Prefs::DIR_WATCH ) );
260            const bool isEnabled( myPrefs->getBool( Prefs::DIR_WATCH_ENABLED ) );
261            myWatchDir->setPath( path, isEnabled );
262            break;
263        }
264
265        default:
266            break;
267    }
268}
269
270void
271MyApp :: maybeUpdateBlocklist( )
272{
273    if( !myPrefs->getBool( Prefs :: BLOCKLIST_UPDATES_ENABLED ) )
274        return;
275
276     const QDateTime lastUpdatedAt = myPrefs->getDateTime( Prefs :: BLOCKLIST_DATE );
277     const QDateTime nextUpdateAt = lastUpdatedAt.addDays( 7 );
278     const QDateTime now = QDateTime::currentDateTime( );
279     if( now < nextUpdateAt )
280     {
281         mySession->updateBlocklist( );
282         myPrefs->set( Prefs :: BLOCKLIST_DATE, now );
283     }
284}
285
286void
287MyApp :: refreshTorrents( )
288{
289    // usually we just poll the torrents that have shown recent activity,
290    // but we also periodically ask for updates on the others to ensure
291    // nothing's falling through the cracks.
292    const time_t now = time( NULL );
293    if( myLastFullUpdateTime + 60 >= now )
294        mySession->refreshActiveTorrents( );
295    else {
296        myLastFullUpdateTime = now;
297        mySession->refreshAllTorrents( );
298    }
299}
300
301void
302MyApp :: addTorrent( const QString& filename )
303{
304    if( myPrefs->getBool( Prefs :: OPTIONS_PROMPT ) ) {
305        Options * o = new Options( *mySession, *myPrefs, filename, myWindow );
306        o->show( );
307        QApplication :: alert( o );
308    } else {
309        mySession->addTorrent( filename );
310        QApplication :: alert ( myWindow );
311    }
312}
313
314
315/***
316****
317***/
318
319int
320main( int argc, char * argv[] )
321{
322    MyApp app( argc, argv );
323    return app.exec( );
324}
Note: See TracBrowser for help on using the repository browser.