PageRenderTime 452ms CodeModel.GetById 81ms app.highlight 291ms RepoModel.GetById 71ms app.codeStats 0ms

/src/tomahawkapp.cpp

http://github.com/tomahawk-player/tomahawk
C++ | 808 lines | 619 code | 144 blank | 45 comment | 63 complexity | 05bd4019927211da160327fb64dcf0bc MD5 | raw file
  1/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
  2 *
  3 *   Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
  4 *   Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
  5 *   Copyright 2010-2012, Jeff Mitchell <jeff@tomahawk-player.org>
  6 *
  7 *   Tomahawk is free software: you can redistribute it and/or modify
  8 *   it under the terms of the GNU General Public License as published by
  9 *   the Free Software Foundation, either version 3 of the License, or
 10 *   (at your option) any later version.
 11 *
 12 *   Tomahawk is distributed in the hope that it will be useful,
 13 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 14 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 15 *   GNU General Public License for more details.
 16 *
 17 *   You should have received a copy of the GNU General Public License
 18 *   along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
 19 */
 20
 21#include "TomahawkApp.h"
 22
 23#include "TomahawkVersion.h"
 24#include "AclRegistryImpl.h"
 25#include "Album.h"
 26#include "Artist.h"
 27#include "Collection.h"
 28#include "infosystem/InfoSystem.h"
 29#include "accounts/AccountManager.h"
 30#include "accounts/spotify/SpotifyAccount.h"
 31#include "accounts/lastfm/LastFmAccount.h"
 32#include "database/Database.h"
 33#include "database/DatabaseCollection.h"
 34#include "database/DatabaseCommand_CollectionStats.h"
 35#include "database/DatabaseResolver.h"
 36#include "playlist/dynamic/GeneratorFactory.h"
 37#include "playlist/dynamic/echonest/EchonestGenerator.h"
 38#include "playlist/dynamic/database/DatabaseGenerator.h"
 39#include "playlist/XspfUpdater.h"
 40#include "network/Servent.h"
 41#include "web/Api_v1.h"
 42#include "SourceList.h"
 43#include "ShortcutHandler.h"
 44#include "libtomahawk/filemetadata/ScanManager.h"
 45#include "TomahawkSettings.h"
 46#include "GlobalActionManager.h"
 47#include "database/LocalCollection.h"
 48#include "Pipeline.h"
 49#include "DropJob.h"
 50#include "EchonestCatalogSynchronizer.h"
 51
 52#include "audio/AudioEngine.h"
 53#include "utils/XspfLoader.h"
 54#include "utils/JspfLoader.h"
 55#include "utils/Logger.h"
 56#include "utils/TomahawkUtilsGui.h"
 57#include "accounts/lastfm/LastFmAccount.h"
 58#include "accounts/spotify/SpotifyAccount.h"
 59#include "accounts/spotify/SpotifyPlaylistUpdater.h"
 60#include "utils/TomahawkCache.h"
 61
 62#ifndef ENABLE_HEADLESS
 63    #include "resolvers/QtScriptResolver.h"
 64    #include "resolvers/ScriptResolver.h"
 65    #include "utils/SpotifyParser.h"
 66    #include "AtticaManager.h"
 67    #include "TomahawkWindow.h"
 68    #include "SettingsDialog.h"
 69    #include "ActionCollection.h"
 70    #include "widgets/HeaderLabel.h"
 71    #include "TomahawkSettingsGui.h"
 72#endif
 73
 74#include "config.h"
 75
 76#ifndef ENABLE_HEADLESS
 77    #include <QMessageBox>
 78#endif
 79
 80#ifdef Q_WS_MAC
 81#include "mac/MacShortcutHandler.h"
 82
 83#include <sys/resource.h>
 84#include <sys/sysctl.h>
 85#endif
 86
 87#include <QPluginLoader>
 88#include <QDir>
 89#include <QMetaType>
 90#include <QTime>
 91#include <QNetworkReply>
 92#include <QFile>
 93#include <QFileInfo>
 94#include <QTranslator>
 95
 96#include <iostream>
 97
 98
 99const char* enApiSecret = "BNvTzfthHr/d1eNhHLvL1Jo=";
100
101void
102increaseMaxFileDescriptors()
103{
104#ifdef Q_WS_MAC
105    /// Following code taken from Clementine project, main.cpp. Thanks!
106    // Bump the soft limit for the number of file descriptors from the default of 256 to
107    // the maximum (usually 1024).
108    struct rlimit limit;
109    getrlimit( RLIMIT_NOFILE, &limit );
110
111    // getrlimit() lies about the hard limit so we have to check sysctl.
112    int max_fd = 0;
113    size_t len = sizeof( max_fd );
114    sysctlbyname( "kern.maxfilesperproc", &max_fd, &len, NULL, 0 );
115
116    limit.rlim_cur = max_fd;
117    int ret = setrlimit( RLIMIT_NOFILE, &limit );
118
119    if ( ret == 0 )
120      qDebug() << "Max fd:" << max_fd;
121#endif
122}
123
124
125using namespace Tomahawk;
126
127TomahawkApp::TomahawkApp( int& argc, char *argv[] )
128    : TOMAHAWK_APPLICATION( argc, argv )
129#ifndef ENABLE_HEADLESS
130    , m_mainwindow( 0 )
131#endif
132    , m_headless( false )
133    , m_loaded( false )
134{
135    setOrganizationName( QLatin1String( TOMAHAWK_ORGANIZATION_NAME ) );
136    setOrganizationDomain( QLatin1String( TOMAHAWK_ORGANIZATION_DOMAIN ) );
137    setApplicationName( QLatin1String( TOMAHAWK_APPLICATION_NAME ) );
138    setApplicationVersion( QLatin1String( TOMAHAWK_VERSION ) );
139
140    registerMetaTypes();
141    installTranslator();
142}
143
144
145void
146TomahawkApp::installTranslator()
147{
148    QString locale = QLocale::system().name();
149    if ( locale == "C" )
150        locale = "en";
151
152    // Tomahawk translations
153    QTranslator* translator = new QTranslator( this );
154    if ( translator->load( QString( ":/lang/tomahawk_" ) + locale ) )
155    {
156        tDebug( LOGVERBOSE ) << "Translation: Tomahawk: Using system locale:" << locale;
157    }
158    else
159    {
160        tDebug( LOGVERBOSE ) << "Translation: Tomahawk: Using default locale, system locale one not found:" << locale;
161        translator->load( QString( ":/lang/tomahawk_en" ) );
162    }
163
164    TOMAHAWK_APPLICATION::installTranslator( translator );
165
166    // Qt translations
167    translator = new QTranslator( this );
168    if ( translator->load( QString( ":/lang/qt_" ) + locale ) )
169    {
170        tDebug( LOGVERBOSE ) << "Translation: Qt: Using system locale:" << locale;
171    }
172    else
173    {
174        tDebug( LOGVERBOSE ) << "Translation: Qt: Using default locale, system locale one not found:" << locale;
175    }
176
177    TOMAHAWK_APPLICATION::installTranslator( translator );
178}
179
180
181void
182TomahawkApp::init()
183{
184    if ( arguments().contains( "--help" ) || arguments().contains( "-h" ) )
185    {
186        printHelp();
187        ::exit( 0 );
188    }
189
190    qDebug() << "TomahawkApp thread:" << thread();
191    Logger::setupLogfile();
192    qsrand( QTime( 0, 0, 0 ).secsTo( QTime::currentTime() ) );
193
194    tLog() << "Starting Tomahawk...";
195
196#ifdef ENABLE_HEADLESS
197    m_headless = true;
198#else
199    m_headless = arguments().contains( "--headless" );
200    setWindowIcon( QIcon( RESPATH "icons/tomahawk-icon-128x128.png" ) );
201    setQuitOnLastWindowClosed( false );
202
203    QFont f = font();
204#ifdef Q_OS_MAC
205    f.setPointSize( f.pointSize() - 2 );
206    setFont( f );
207#endif
208
209    tDebug() << "Default font:" << f.pixelSize() << f.pointSize() << f.pointSizeF() << f.family();
210    tDebug() << "Font height:" << QFontMetrics( f ).height();
211    TomahawkUtils::setDefaultFontSize( f.pointSize() );
212#endif
213
214    TomahawkUtils::setHeadless( m_headless );
215    TomahawkSettings* s = TomahawkSettings::instance();
216    new ACLRegistryImpl( this );
217
218    tDebug( LOGINFO ) << "Setting NAM.";
219    // Cause the creation of the nam, but don't need to address it directly, so prevent warning
220    Q_UNUSED( TomahawkUtils::nam() );
221
222    m_audioEngine = QWeakPointer<AudioEngine>( new AudioEngine );
223
224    // init pipeline and resolver factories
225    new Pipeline();
226
227    m_servent = QWeakPointer<Servent>( new Servent( this ) );
228    connect( m_servent.data(), SIGNAL( ready() ), SLOT( initSIP() ) );
229
230    tDebug() << "Init Database.";
231    initDatabase();
232
233    m_scanManager = QWeakPointer<ScanManager>( new ScanManager( this ) );
234
235#ifndef ENABLE_HEADLESS
236    Pipeline::instance()->addExternalResolverFactory( boost::bind( &QtScriptResolver::factory, _1 ) );
237    Pipeline::instance()->addExternalResolverFactory( boost::bind( &ScriptResolver::factory, _1 ) );
238
239    new ActionCollection( this );
240    connect( ActionCollection::instance()->getAction( "quit" ), SIGNAL( triggered() ), SLOT( quit() ), Qt::UniqueConnection );
241#endif
242
243    QByteArray magic = QByteArray::fromBase64( enApiSecret );
244    QByteArray wand = QByteArray::fromBase64( QCoreApplication::applicationName().toLatin1() );
245    int length = magic.length(), n2 = wand.length();
246    for ( int i=0; i<length; i++ ) magic[i] = magic[i] ^ wand[i%n2];
247    Echonest::Config::instance()->setAPIKey( magic );
248
249#ifndef ENABLE_HEADLESS
250    tDebug() << "Init Echonest Factory.";
251    GeneratorFactory::registerFactory( "echonest", new EchonestFactory );
252#endif
253    tDebug() << "Init Database Factory.";
254    GeneratorFactory::registerFactory( "database", new DatabaseFactory );
255
256    // Register shortcut handler for this platform
257#ifdef Q_WS_MAC
258    m_shortcutHandler = QWeakPointer<Tomahawk::ShortcutHandler>( new MacShortcutHandler( this ) );
259    Tomahawk::setShortcutHandler( static_cast<MacShortcutHandler*>( m_shortcutHandler.data() ) );
260
261    Tomahawk::setApplicationHandler( this );
262    increaseMaxFileDescriptors();
263#endif
264
265    // Connect up shortcuts
266    if ( !m_shortcutHandler.isNull() )
267    {
268        connect( m_shortcutHandler.data(), SIGNAL( playPause() ), m_audioEngine.data(), SLOT( playPause() ) );
269        connect( m_shortcutHandler.data(), SIGNAL( pause() ), m_audioEngine.data(), SLOT( pause() ) );
270        connect( m_shortcutHandler.data(), SIGNAL( stop() ), m_audioEngine.data(), SLOT( stop() ) );
271        connect( m_shortcutHandler.data(), SIGNAL( previous() ), m_audioEngine.data(), SLOT( previous() ) );
272        connect( m_shortcutHandler.data(), SIGNAL( next() ), m_audioEngine.data(), SLOT( next() ) );
273        connect( m_shortcutHandler.data(), SIGNAL( volumeUp() ), m_audioEngine.data(), SLOT( raiseVolume() ) );
274        connect( m_shortcutHandler.data(), SIGNAL( volumeDown() ), m_audioEngine.data(), SLOT( lowerVolume() ) );
275        connect( m_shortcutHandler.data(), SIGNAL( mute() ), m_audioEngine.data(), SLOT( mute() ) );
276    }
277
278    tDebug() << "Init InfoSystem.";
279    m_infoSystem = QWeakPointer<Tomahawk::InfoSystem::InfoSystem>( Tomahawk::InfoSystem::InfoSystem::instance() );
280
281    tDebug() << "Init AccountManager.";
282    m_accountManager = QWeakPointer< Tomahawk::Accounts::AccountManager >( new Tomahawk::Accounts::AccountManager( this ) );
283    connect( m_accountManager.data(), SIGNAL( ready() ), SLOT( accountManagerReady() ) );
284
285    Echonest::Config::instance()->setNetworkAccessManager( TomahawkUtils::nam() );
286#ifndef ENABLE_HEADLESS
287    EchonestGenerator::setupCatalogs();
288
289    if ( !m_headless )
290    {
291        tDebug() << "Init MainWindow.";
292        m_mainwindow = new TomahawkWindow();
293        m_mainwindow->setWindowTitle( "Tomahawk" );
294        m_mainwindow->setObjectName( "TH_Main_Window" );
295        if ( !arguments().contains( "--hide" ) )
296        {
297            m_mainwindow->show();
298        }
299    }
300#endif
301
302    tDebug() << "Init Local Collection.";
303    initLocalCollection();
304    tDebug() << "Init Pipeline.";
305    initPipeline();
306
307#ifndef ENABLE_HEADLESS
308    // load remote list of resolvers able to be installed
309    AtticaManager::instance();
310#endif
311
312    if ( arguments().contains( "--http" ) || TomahawkSettings::instance()->value( "network/http", true ).toBool() )
313    {
314        initHTTP();
315    }
316    connect( TomahawkSettings::instance(), SIGNAL( changed() ), SLOT( initHTTP() ) );
317
318#ifndef ENABLE_HEADLESS
319    if ( !s->hasScannerPaths() )
320    {
321        m_mainwindow->showSettingsDialog();
322    }
323#endif
324
325#ifdef LIBLASTFM_FOUND
326    tDebug() << "Init Scrobbler.";
327    m_scrobbler = new Scrobbler( this );
328#endif
329
330    if ( arguments().contains( "--filescan" ) )
331    {
332        m_scanManager.data()->runFullRescan();
333    }
334
335    // Set up echonest catalog synchronizer
336    Tomahawk::EchonestCatalogSynchronizer::instance();
337
338    PlaylistUpdaterInterface::registerUpdaterFactory( new XspfUpdaterFactory );
339    PlaylistUpdaterInterface::registerUpdaterFactory( new SpotifyUpdaterFactory );
340
341    // Following work-around/fix taken from Clementine rev. 13e13ccd9a95 and courtesy of David Sansome
342    // A bug in Qt means the wheel_scroll_lines setting gets ignored and replaced
343    // with the default value of 3 in QApplicationPrivate::initialize.
344    {
345        QSettings qt_settings( QSettings::UserScope, "Trolltech" );
346        qt_settings.beginGroup( "Qt" );
347        QApplication::setWheelScrollLines( qt_settings.value( "wheelScrollLines", QApplication::wheelScrollLines() ).toInt() );
348    }
349
350#ifndef ENABLE_HEADLESS
351    // Make sure to init GAM in the gui thread
352    GlobalActionManager::instance();
353
354    // check if our spotify playlist api server is up and running, and enable spotify playlist drops if so
355    QNetworkReply* r = TomahawkUtils::nam()->get( QNetworkRequest( QUrl( SPOTIFY_PLAYLIST_API_URL "/pong" ) ) );
356    connect( r, SIGNAL( finished() ), this, SLOT( spotifyApiCheckFinished() ) );
357#endif
358
359#ifdef Q_OS_MAC
360    // Make sure to do this after main window is inited
361    Tomahawk::enableFullscreen( m_mainwindow );
362#endif
363}
364
365
366TomahawkApp::~TomahawkApp()
367{
368    tLog() << "Shutting down Tomahawk...";
369
370    if ( !m_session.isNull() )
371        delete m_session.data();
372    if ( !m_connector.isNull() )
373        delete m_connector.data();
374
375    if ( Pipeline::instance() )
376        Pipeline::instance()->stop();
377
378    if ( !m_servent.isNull() )
379        delete m_servent.data();
380
381    delete dynamic_cast< ACLRegistryImpl* >( ACLRegistry::instance() );
382
383    if ( !m_scanManager.isNull() )
384        delete m_scanManager.data();
385
386    if ( !m_audioEngine.isNull() )
387        delete m_audioEngine.data();
388
389    delete Tomahawk::Accounts::AccountManager::instance();
390
391#ifndef ENABLE_HEADLESS
392    delete AtticaManager::instance();
393    delete m_mainwindow;
394#endif
395
396    if ( !m_database.isNull() )
397        delete m_database.data();
398
399    delete Pipeline::instance();
400
401    if ( !m_infoSystem.isNull() )
402        delete m_infoSystem.data();
403
404    delete TomahawkUtils::Cache::instance();
405
406    tLog() << "Finished shutdown.";
407}
408
409
410TomahawkApp*
411TomahawkApp::instance()
412{
413    return (TomahawkApp*)TOMAHAWK_APPLICATION::instance();
414}
415
416
417void
418TomahawkApp::printHelp()
419{
420    #define echo( X ) std::cout << QString( X ).toAscii().data() << "\n"
421
422    echo( "Usage: " + arguments().at( 0 ) + " [options] [url]" );
423    echo( "Options are:" );
424    echo( "  --help         Show this help" );
425    echo( "  --http         Initialize HTTP server" );
426    echo( "  --filescan     Scan files on startup" );
427//    echo( "  --headless     Run without a GUI" );
428    echo( "  --hide         Hide main window on startup" );
429    echo( "  --testdb       Use a test database instead of real collection" );
430    echo( "  --noupnp       Disable UPnP" );
431    echo( "  --nosip        Disable SIP" );
432    echo();
433    echo( "Playback Controls:" );
434    echo( "  --play         Start/resume playback" );
435    echo( "  --pause        Pause playback" );
436    echo( "  --playpause    Toggle playing/paused state" );
437    echo( "  --stop         Stop playback" );
438    echo( "  --prev         Returns to the previous track (if available)" );
439    echo( "  --next         Advances to the next track (if available)" );
440    echo( "  --voldown      Decrease the volume" );
441    echo( "  --volup        Increase the volume" );
442    echo();
443    echo( "url is a tomahawk:// command or alternatively a url that Tomahawk can recognize." );
444    echo( "For more documentation, see http://wiki.tomahawk-player.org/index.php/Tomahawk://_Links" );
445}
446
447
448#ifndef ENABLE_HEADLESS
449AudioControls*
450TomahawkApp::audioControls()
451{
452    return m_mainwindow->audioControls();
453}
454#endif
455
456
457void
458TomahawkApp::registerMetaTypes()
459{
460    qRegisterMetaType< QSharedPointer<DatabaseCommand> >("QSharedPointer<DatabaseCommand>");
461    qRegisterMetaType< DBSyncConnection::State >("DBSyncConnection::State");
462    qRegisterMetaType< msg_ptr >("msg_ptr");
463    qRegisterMetaType< QList<dbop_ptr> >("QList<dbop_ptr>");
464    qRegisterMetaType< QList<QVariantMap> >("QList<QVariantMap>");
465    qRegisterMetaType< QList<QString> >("QList<QString>");
466    qRegisterMetaType< QList<uint> >("QList<uint>");
467    qRegisterMetaType< Connection* >("Connection*");
468    qRegisterMetaType< QAbstractSocket::SocketError >("QAbstractSocket::SocketError");
469    qRegisterMetaType< QTcpSocket* >("QTcpSocket*");
470    qRegisterMetaType< QSharedPointer<QIODevice> >("QSharedPointer<QIODevice>");
471    qRegisterMetaType< QFileInfo >("QFileInfo");
472    qRegisterMetaType< QDir >("QDir");
473    qRegisterMetaType< QHostAddress >("QHostAddress");
474    qRegisterMetaType< QMap<QString, unsigned int> >("QMap<QString, unsigned int>");
475    qRegisterMetaType< QMap< QString, plentry_ptr > >("QMap< QString, plentry_ptr >");
476    qRegisterMetaType< QHash< QString, QMap<quint32, quint16> > >("QHash< QString, QMap<quint32, quint16> >");
477    qRegisterMetaType< QMap< QString, QMap< unsigned int, unsigned int > > >("QMap< QString, QMap< unsigned int, unsigned int > >");
478    qRegisterMetaType< PairList >("PairList");
479
480    qRegisterMetaType<GeneratorMode>("GeneratorMode");
481    qRegisterMetaType<Tomahawk::GeneratorMode>("Tomahawk::GeneratorMode");
482    qRegisterMetaType<ModelMode>("Tomahawk::ModelMode");
483    qRegisterMetaType<Tomahawk::ModelMode>("Tomahawk::ModelMode");
484
485    // Extra definition for namespaced-versions of signals/slots required
486    qRegisterMetaType< Tomahawk::Resolver* >("Tomahawk::Resolver*");
487    qRegisterMetaType< Tomahawk::source_ptr >("Tomahawk::source_ptr");
488    qRegisterMetaType< Tomahawk::collection_ptr >("Tomahawk::collection_ptr");
489    qRegisterMetaType< Tomahawk::result_ptr >("Tomahawk::result_ptr");
490    qRegisterMetaType< Tomahawk::query_ptr >("Tomahawk::query_ptr");
491    qRegisterMetaType< Tomahawk::album_ptr >("Tomahawk::album_ptr");
492    qRegisterMetaType< Tomahawk::artist_ptr >("Tomahawk::artist_ptr");
493    qRegisterMetaType< Tomahawk::source_ptr >("Tomahawk::source_ptr");
494    qRegisterMetaType< Tomahawk::dyncontrol_ptr >("Tomahawk::dyncontrol_ptr");
495    qRegisterMetaType< Tomahawk::playlist_ptr >("Tomahawk::playlist_ptr");
496    qRegisterMetaType< Tomahawk::playlistinterface_ptr >("Tomahawk::playlistinterface_ptr");
497    qRegisterMetaType< Tomahawk::dynplaylist_ptr >("Tomahawk::dynplaylist_ptr");
498    qRegisterMetaType< Tomahawk::geninterface_ptr >("Tomahawk::geninterface_ptr");
499    qRegisterMetaType< QList<Tomahawk::playlist_ptr> >("QList<Tomahawk::playlist_ptr>");
500    qRegisterMetaType< QList<Tomahawk::dynplaylist_ptr> >("QList<Tomahawk::dynplaylist_ptr>");
501    qRegisterMetaType< QList<Tomahawk::dyncontrol_ptr> >("QList<Tomahawk::dyncontrol_ptr>");
502    qRegisterMetaType< QList<Tomahawk::geninterface_ptr> >("QList<Tomahawk::geninterface_ptr>");
503    qRegisterMetaType< QList<Tomahawk::plentry_ptr> >("QList<Tomahawk::plentry_ptr>");
504    qRegisterMetaType< QList<Tomahawk::query_ptr> >("QList<Tomahawk::query_ptr>");
505    qRegisterMetaType< QList<Tomahawk::result_ptr> >("QList<Tomahawk::result_ptr>");
506    qRegisterMetaType< QList<Tomahawk::artist_ptr> >("QList<Tomahawk::artist_ptr>");
507    qRegisterMetaType< QList<Tomahawk::album_ptr> >("QList<Tomahawk::album_ptr>");
508    qRegisterMetaType< QList<Tomahawk::source_ptr> >("QList<Tomahawk::source_ptr>");
509    qRegisterMetaType< QMap< QString, Tomahawk::plentry_ptr > >("QMap< QString, Tomahawk::plentry_ptr >");
510    qRegisterMetaType< Tomahawk::PlaylistRevision >("Tomahawk::PlaylistRevision");
511    qRegisterMetaType< Tomahawk::DynamicPlaylistRevision >("Tomahawk::DynamicPlaylistRevision");
512    qRegisterMetaType< Tomahawk::QID >("Tomahawk::QID");
513
514    qRegisterMetaType< AudioErrorCode >("AudioErrorCode");
515
516    qRegisterMetaType< Tomahawk::InfoSystem::InfoStringHash >( "Tomahawk::InfoSystem::InfoStringHash" );
517    qRegisterMetaType< Tomahawk::InfoSystem::InfoType >( "Tomahawk::InfoSystem::InfoType" );
518    qRegisterMetaType< Tomahawk::InfoSystem::PushInfoFlags >( "Tomahawk::InfoSystem::PushInfoFlags" );
519    qRegisterMetaType< Tomahawk::InfoSystem::PushInfoPair >( "Tomahawk::InfoSystem::PushInfoPair" );
520    qRegisterMetaType< Tomahawk::InfoSystem::InfoRequestData >( "Tomahawk::InfoSystem::InfoRequestData" );
521    qRegisterMetaType< Tomahawk::InfoSystem::InfoPushData >( "Tomahawk::InfoSystem::InfoPushData" );
522    qRegisterMetaType< Tomahawk::InfoSystem::InfoSystemCache* >( "Tomahawk::InfoSystem::InfoSystemCache*" );
523    qRegisterMetaType< Tomahawk::InfoSystem::InfoPluginPtr >( "Tomahawk::InfoSystem::InfoPluginPtr" );
524    qRegisterMetaType< Tomahawk::InfoSystem::InfoPlugin* >( "Tomahawk::InfoSystem::InfoPlugin*" );
525    qRegisterMetaType< QList< Tomahawk::InfoSystem::InfoStringHash > >("QList< Tomahawk::InfoSystem::InfoStringHash > ");
526
527    qRegisterMetaType< TomahawkSettings::PrivateListeningMode >( "TomahawkSettings::PrivateListeningMode" );
528
529    qRegisterMetaTypeStreamOperators< QList< Tomahawk::InfoSystem::InfoStringHash > >("QList< Tomahawk::InfoSystem::InfoStringHash > ");
530    qRegisterMetaType< QPersistentModelIndex >( "QPersistentModelIndex" );
531
532    qRegisterMetaType< Tomahawk::PlaylistModes::LatchMode >( "Tomahawk::PlaylistModes::LatchMode" );
533    qRegisterMetaType< Tomahawk::PlaylistModes::RepeatMode >( "Tomahawk::PlaylistModes::RepeatMode" );
534
535    qRegisterMetaType< TomahawkUtils::CacheData >( "TomahawkUtils::CacheData" );
536    qRegisterMetaTypeStreamOperators< TomahawkUtils::CacheData >( "TomahawkUtils::CacheData" );
537}
538
539
540void
541TomahawkApp::initDatabase()
542{
543    QString dbpath;
544    if ( arguments().contains( "--testdb" ) )
545    {
546        dbpath = QDir::currentPath() + "/test.db";
547    }
548    else
549    {
550        dbpath = TomahawkUtils::appDataDir().absoluteFilePath( "tomahawk.db" );
551    }
552
553    tDebug( LOGEXTRA ) << "Using database:" << dbpath;
554    m_database = QWeakPointer<Database>( new Database( dbpath, this ) );
555    Pipeline::instance()->databaseReady();
556}
557
558
559void
560TomahawkApp::initHTTP()
561{
562    if ( !TomahawkSettings::instance()->httpEnabled() )
563    {
564        tLog() << "Stopping HTTPd, not enabled";
565        if ( !m_session.isNull() )
566            delete m_session.data();
567        if ( !m_connector.isNull() )
568            delete m_connector.data();
569        return;
570    }
571
572    if ( m_session )
573    {
574        tLog() << "HTTPd session already exists, returning";
575        return;
576    }
577
578    m_session = QWeakPointer< QxtHttpSessionManager >( new QxtHttpSessionManager() );
579    m_connector = QWeakPointer< QxtHttpServerConnector >( new QxtHttpServerConnector );
580    if ( m_session.isNull() || m_connector.isNull() )
581    {
582        if ( !m_session.isNull() )
583            delete m_session.data();
584        if ( !m_connector.isNull() )
585            delete m_connector.data();
586        tLog() << "Failed to start HTTPd, could not create object";
587        return;
588    }
589
590    m_session.data()->setPort( 60210 ); //TODO config
591    m_session.data()->setListenInterface( QHostAddress::LocalHost );
592    m_session.data()->setConnector( m_connector.data() );
593
594    Api_v1* api = new Api_v1( m_session.data() );
595    m_session.data()->setStaticContentService( api );
596
597    tLog() << "Starting HTTPd on" << m_session.data()->listenInterface().toString() << m_session.data()->port();
598    m_session.data()->start();
599}
600
601
602void
603TomahawkApp::initPipeline()
604{
605    // setup resolvers for local content, and (cached) remote collection content
606    Pipeline::instance()->addResolver( new DatabaseResolver( 100 ) );
607}
608
609
610void
611TomahawkApp::initLocalCollection()
612{
613    connect( SourceList::instance(), SIGNAL( ready() ), SLOT( initServent() ) );
614
615    source_ptr src( new Source( 0, tr( "My Collection" ) ) );
616    collection_ptr coll( new LocalCollection( src ) );
617
618    src->addCollection( coll );
619    SourceList::instance()->setLocal( src );
620    SourceList::instance()->loadSources();
621
622    // to make the stats signal be emitted by our local source
623    // this will update the sidebar, etc.
624    DatabaseCommand_CollectionStats* cmd = new DatabaseCommand_CollectionStats( src );
625    connect( cmd,       SIGNAL( done( const QVariantMap& ) ),
626             src.data(),  SLOT( setStats( const QVariantMap& ) ), Qt::QueuedConnection );
627    Database::instance()->enqueue( QSharedPointer<DatabaseCommand>( cmd ) );
628}
629
630
631void
632TomahawkApp::initServent()
633{
634    tDebug() << "Init Servent.";
635
636    bool upnp = !arguments().contains( "--noupnp" );
637    int port = TomahawkSettings::instance()->externalPort();
638    if ( !Servent::instance()->startListening( QHostAddress( QHostAddress::Any ), upnp, port ) )
639    {
640        tLog() << "Failed to start listening with servent";
641        exit( 1 );
642    }
643}
644
645
646// Called after Servent emits ready()
647void
648TomahawkApp::initSIP()
649{
650    tDebug() << Q_FUNC_INFO;
651    //FIXME: jabber autoconnect is really more, now that there is sip -- should be renamed and/or split out of jabber-specific settings
652    if ( !arguments().contains( "--nosip" ) )
653    {
654        tDebug( LOGINFO ) << "Connecting SIP classes";
655        Accounts::AccountManager::instance()->initSIP();
656    }
657
658    m_loaded = true;
659    emit tomahawkLoaded();
660}
661
662
663void
664TomahawkApp::spotifyApiCheckFinished()
665{
666#ifndef ENABLE_HEADLESS
667    QNetworkReply* reply = qobject_cast< QNetworkReply* >( sender() );
668    Q_ASSERT( reply );
669
670    DropJob::setCanParseSpotifyPlaylists( !reply->error() );
671#endif
672}
673
674
675void
676TomahawkApp::accountManagerReady()
677{
678    Tomahawk::Accounts::LastFmAccountFactory* lastfmFactory = new Tomahawk::Accounts::LastFmAccountFactory();
679    m_accountManager.data()->addAccountFactory( lastfmFactory );
680
681    Tomahawk::Accounts::SpotifyAccountFactory* spotifyFactory = new Tomahawk::Accounts::SpotifyAccountFactory;
682    m_accountManager.data()->addAccountFactory( spotifyFactory );
683    m_accountManager.data()->registerAccountFactoryForFilesystem( spotifyFactory );
684
685    Tomahawk::Accounts::AccountManager::instance()->loadFromConfig();
686}
687
688
689void
690TomahawkApp::activate()
691{
692#ifndef ENABLE_HEADLESS
693    TomahawkUtils::bringToFront();
694#endif
695}
696
697
698bool
699TomahawkApp::loadUrl( const QString& url )
700{
701#ifndef ENABLE_HEADLESS
702    if ( url.startsWith( "tomahawk://" ) )
703        return GlobalActionManager::instance()->parseTomahawkLink( url );
704    else if ( url.contains( "open.spotify.com" ) || url.contains( "spotify:track" ) )
705        return GlobalActionManager::instance()->openSpotifyLink( url );
706    else if ( url.contains( "www.rdio.com" ) )
707        return GlobalActionManager::instance()->openRdioLink( url );
708    else
709    {
710        QFile f( url );
711        QFileInfo info( f );
712        if ( info.suffix() == "xspf" )
713        {
714            XSPFLoader* l = new XSPFLoader( true, this );
715            tDebug( LOGINFO ) << "Loading spiff:" << url;
716            l->load( QUrl::fromUserInput( url ) );
717
718            return true;
719        }
720        else if ( info.suffix() == "jspf" )
721        {
722            JSPFLoader* l = new JSPFLoader( true, this );
723            tDebug( LOGINFO ) << "Loading j-spiff:" << url;
724            l->load( QUrl::fromUserInput( url ) );
725
726            return true;
727        }
728    }
729#endif
730    return false;
731}
732
733
734bool
735TomahawkApp::notify( QObject *receiver, QEvent *e )
736{
737    try
738    {
739        return TOMAHAWK_APPLICATION::notify( receiver, e );
740    }
741    catch ( const std::exception& e )
742    {
743        qWarning( "TomahawkApp::notify caught a std exception in a Qt event handler: " );
744
745        // the second parameter surpresses a format-security warning
746        qFatal( e.what(), "" );
747    }
748    catch ( ... )
749    {
750        qFatal( "TomahawkApp::notify caught a non-std-exception from a Qt event handler. Aborting." );
751    }
752
753    return false;
754}
755
756
757void
758TomahawkApp::instanceStarted( KDSingleApplicationGuard::Instance instance )
759{
760    tDebug( LOGINFO ) << "Instance started!" << instance.pid() << instance.arguments();
761    const QStringList arguments = instance.arguments();
762
763    if ( arguments.size() < 2 )
764    {
765        activate();
766        return;
767    }
768
769    QString arg1 = arguments[ 1 ];
770    if ( loadUrl( arg1 ) )
771    {
772        activate();
773        return;
774    }
775
776    if ( arguments.contains( "--next" ) )
777        AudioEngine::instance()->next();
778    else if ( arguments.contains( "--prev" ) )
779        AudioEngine::instance()->previous();
780    else if ( arguments.contains( "--playpause" ) )
781        AudioEngine::instance()->playPause();
782    else if ( arguments.contains( "--play" ) )
783        AudioEngine::instance()->play();
784    else if ( arguments.contains( "--pause" ) )
785        AudioEngine::instance()->pause();
786    else if ( arguments.contains( "--stop" ) )
787        AudioEngine::instance()->stop();
788    else if ( arguments.contains( "--voldown" ) )
789        AudioEngine::instance()->lowerVolume();
790    else if ( arguments.contains( "--volup" ) )
791        AudioEngine::instance()->raiseVolume();
792    else
793        activate();
794}
795
796
797TomahawkWindow*
798TomahawkApp::mainWindow() const
799{
800    return m_mainwindow;
801}
802
803
804bool
805TomahawkApp::isTomahawkLoaded() const
806{
807    return m_loaded;
808}