source: trunk/qt/app.cc @ 9237

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

(trunk, gtk, qt) #2478: popup dialog for first-time users

  • Property svn:keywords set to Date Rev Author Id
File size: 9.4 KB
Line 
1/*
2 * This file Copyright (C) 2009 Charles Kerr <charles@transmissionbt.com>
3 *
4 * This file is licensed by the GPL version 2.  Works owned by the
5 * Transmission project are granted a special exemption to clause 2(b)
6 * so that the bulk of its code can remain under the MIT license.
7 * This exemption does not extend to derived works not owned by
8 * the Transmission project.
9 *
10 * $Id: app.cc 9237 2009-10-02 22:53:19Z charles $
11 */
12
13#include <cassert>
14#include <ctime>
15#include <iostream>
16
17#include <QDialogButtonBox>
18#include <QIcon>
19#include <QLibraryInfo>
20#include <QLabel>
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        { 'v', "version", "Show version number and exit", "v", 0, NULL },
47        { 0, NULL, NULL, NULL, 0, NULL }
48    };
49
50    const char*
51    getUsage( void )
52    {
53        return "Usage:\n"
54               "  transmission [OPTIONS...] [torrent files]";
55    }
56
57    void
58    showUsage( void )
59    {
60        tr_getopt_usage( MY_NAME, getUsage( ), opts );
61        exit( 0 );
62    }
63
64    enum
65    {
66        STATS_REFRESH_INTERVAL_MSEC = 3000,
67        SESSION_REFRESH_INTERVAL_MSEC = 3000,
68        MODEL_REFRESH_INTERVAL_MSEC = 3000
69    };
70}
71
72MyApp :: MyApp( int& argc, char ** argv ):
73    QApplication( argc, argv ),
74    myLastFullUpdateTime( 0 )
75{
76    setApplicationName( MY_NAME );
77
78    // install the qt translator
79    QTranslator * t = new QTranslator( );
80    t->load( "qt_" + QLocale::system().name(), QLibraryInfo::location(QLibraryInfo::TranslationsPath));
81    installTranslator( t );
82
83    // install the transmission translator
84    t = new QTranslator( );
85    t->load( QString(MY_NAME) + "_" + QLocale::system().name() );
86    installTranslator( t );
87
88    // set the default icon
89    QIcon icon;
90    icon.addPixmap( QPixmap( ":/icons/transmission-16.png" ) );
91    icon.addPixmap( QPixmap( ":/icons/transmission-22.png" ) );
92    icon.addPixmap( QPixmap( ":/icons/transmission-24.png" ) );
93    icon.addPixmap( QPixmap( ":/icons/transmission-32.png" ) );
94    icon.addPixmap( QPixmap( ":/icons/transmission-48.png" ) );
95    setWindowIcon( icon );
96
97    // parse the command-line arguments
98    int c;
99    bool minimized = false;
100    const char * optarg;
101    const char * configDir = 0;
102    QStringList filenames;
103    while( ( c = tr_getopt( getUsage( ), argc, (const char**)argv, opts, &optarg ) ) ) {
104        switch( c ) {
105            case 'g': configDir = optarg; break;
106            case 'm': minimized = true; break;
107            case 'v':        Utils::toStderr( QObject::tr( "transmission %1" ).arg( LONG_VERSION_STRING ) ); exit( 0 ); break;
108            case TR_OPT_ERR: Utils::toStderr( QObject::tr( "Invalid option" ) ); showUsage( ); break;
109            default:         filenames.append( optarg ); break;
110        }
111    }
112
113    // set the fallback config dir
114    if( configDir == 0 )
115        configDir = tr_getDefaultConfigDir( MY_NAME );
116
117    // is this the first time we've run transmission?
118    const bool firstTime = !QFile(QDir(configDir).absoluteFilePath("settings.json")).exists();
119
120    myPrefs = new Prefs ( configDir );
121    mySession = new Session( configDir, *myPrefs );
122    myModel = new TorrentModel( *myPrefs );
123    myWindow = new TrMainWindow( *mySession, *myPrefs, *myModel, minimized );
124    myWatchDir = new WatchDir( *myModel );
125
126    // when the session gets torrent info, update the model
127    connect( mySession, SIGNAL(torrentsUpdated(tr_benc*,bool)), myModel, SLOT(updateTorrents(tr_benc*,bool)) );
128    connect( mySession, SIGNAL(torrentsUpdated(tr_benc*,bool)), myWindow, SLOT(refreshActionSensitivity()) );
129    connect( mySession, SIGNAL(torrentsRemoved(tr_benc*)), myModel, SLOT(removeTorrents(tr_benc*)) );
130    // when the model sees a torrent for the first time, ask the session for full info on it
131    connect( myModel, SIGNAL(torrentsAdded(QSet<int>)), mySession, SLOT(initTorrents(QSet<int>)) );
132
133    mySession->initTorrents( );
134    mySession->refreshSessionStats( );
135
136    // when torrents are added to the watch directory, tell the session
137    connect( myWatchDir, SIGNAL(torrentFileAdded(QString)), this, SLOT(addTorrent(QString)) );
138
139    // init from preferences
140    QList<int> initKeys;
141    initKeys << Prefs::DIR_WATCH;
142    foreach( int key, initKeys )
143        refreshPref( key );
144    connect( myPrefs, SIGNAL(changed(int)), this, SLOT(refreshPref(const int)) );
145
146    QTimer * timer = &myModelTimer;
147    connect( timer, SIGNAL(timeout()), this, SLOT(refreshTorrents()) );
148    timer->setSingleShot( false );
149    timer->setInterval( MODEL_REFRESH_INTERVAL_MSEC );
150    timer->start( );
151
152    timer = &myStatsTimer;
153    connect( timer, SIGNAL(timeout()), mySession, SLOT(refreshSessionStats()) );
154    timer->setSingleShot( false );
155    timer->setInterval( STATS_REFRESH_INTERVAL_MSEC );
156    timer->start( );
157
158    timer = &mySessionTimer;
159    connect( timer, SIGNAL(timeout()), mySession, SLOT(refreshSessionInfo()) );
160    timer->setSingleShot( false );
161    timer->setInterval( SESSION_REFRESH_INTERVAL_MSEC );
162    timer->start( );
163
164    maybeUpdateBlocklist( );
165
166    if( !firstTime )
167        mySession->restart( );
168    else {
169        QDialog * d = new SessionDialog( *mySession, *myPrefs, myWindow );
170        d->show( );
171    }
172
173    if( !myPrefs->getBool( Prefs::USER_HAS_GIVEN_INFORMED_CONSENT ))
174    {
175        QDialog * dialog = new QDialog( myWindow );
176        dialog->setModal( true );
177        QVBoxLayout * v = new QVBoxLayout( dialog );
178        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." ) );
179        l->setWordWrap( true );
180        v->addWidget( l );
181        QDialogButtonBox * box = new QDialogButtonBox;
182        box->addButton( new QPushButton( tr( "&Cancel" ) ), QDialogButtonBox::RejectRole );
183        QPushButton * agree = new QPushButton( tr( "I &Agree" ) );
184        agree->setDefault( true );
185        box->addButton( agree, QDialogButtonBox::AcceptRole );
186        box->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed );
187        box->setOrientation( Qt::Horizontal );
188        v->addWidget( box );
189        connect( box, SIGNAL(rejected()), this, SLOT(quit()) );
190        connect( box, SIGNAL(accepted()), dialog, SLOT(deleteLater()) );
191        connect( box, SIGNAL(accepted()), this, SLOT(consentGiven()) );
192        dialog->show();
193    }
194
195    for( QStringList::const_iterator it=filenames.begin(), end=filenames.end(); it!=end; ++it )
196        mySession->addTorrent( *it );
197}
198
199void
200MyApp :: consentGiven( )
201{
202    myPrefs->set<bool>( Prefs::USER_HAS_GIVEN_INFORMED_CONSENT, true );
203}
204
205MyApp :: ~MyApp( )
206{
207    const QRect mainwinRect( myWindow->geometry( ) );
208    delete myWatchDir;
209    delete myWindow;
210    delete myModel;
211    delete mySession;
212
213    myPrefs->set( Prefs :: MAIN_WINDOW_HEIGHT, std::max( 100, mainwinRect.height( ) ) );
214    myPrefs->set( Prefs :: MAIN_WINDOW_WIDTH, std::max( 100, mainwinRect.width( ) ) );
215    myPrefs->set( Prefs :: MAIN_WINDOW_X, mainwinRect.x( ) );
216    myPrefs->set( Prefs :: MAIN_WINDOW_Y, mainwinRect.y( ) );
217    delete myPrefs;
218}
219
220/***
221****
222***/
223
224void
225MyApp :: refreshPref( int key )
226{
227    switch( key )
228    {
229        case Prefs :: BLOCKLIST_UPDATES_ENABLED:
230            maybeUpdateBlocklist( );
231            break;
232
233        case Prefs :: DIR_WATCH:
234        case Prefs :: DIR_WATCH_ENABLED: {
235            const QString path( myPrefs->getString( Prefs::DIR_WATCH ) );
236            const bool isEnabled( myPrefs->getBool( Prefs::DIR_WATCH_ENABLED ) );
237            myWatchDir->setPath( path, isEnabled );
238            break;
239        }
240
241        default:
242            break;
243    }
244}
245
246void
247MyApp :: maybeUpdateBlocklist( )
248{
249    if( !myPrefs->getBool( Prefs :: BLOCKLIST_UPDATES_ENABLED ) )
250        return;
251
252     const QDateTime lastUpdatedAt = myPrefs->getDateTime( Prefs :: BLOCKLIST_DATE );
253     const QDateTime nextUpdateAt = lastUpdatedAt.addDays( 7 );
254     const QDateTime now = QDateTime::currentDateTime( );
255     if( now < nextUpdateAt )
256     {
257         mySession->updateBlocklist( );
258         myPrefs->set( Prefs :: BLOCKLIST_DATE, now );
259     }
260}
261
262void
263MyApp :: refreshTorrents( )
264{
265    // usually we just poll the torrents that have shown recent activity,
266    // but we also periodically ask for updates on the others to ensure
267    // nothing's falling through the cracks.
268    const time_t now = time( NULL );
269    if( myLastFullUpdateTime + 60 >= now )
270        mySession->refreshActiveTorrents( );
271    else {
272        myLastFullUpdateTime = now;
273        mySession->refreshAllTorrents( );
274    }
275}
276
277void
278MyApp :: addTorrent( const QString& filename )
279{
280    if( myPrefs->getBool( Prefs :: OPTIONS_PROMPT ) ) {
281        Options * o = new Options( *mySession, *myPrefs, filename, myWindow );
282        o->show( );
283        QApplication :: alert( o );
284    } else {
285        mySession->addTorrent( filename );
286        QApplication :: alert ( myWindow );
287    }
288}
289
290
291/***
292****
293***/
294
295int
296main( int argc, char * argv[] )
297{
298    MyApp app( argc, argv );
299    return app.exec( );
300}
Note: See TracBrowser for help on using the repository browser.