PageRenderTime 440ms CodeModel.GetById 81ms app.highlight 292ms RepoModel.GetById 50ms app.codeStats 1ms

/src/libtomahawk/TomahawkSettings.cpp

http://github.com/tomahawk-player/tomahawk
C++ | 1764 lines | 1323 code | 386 blank | 55 comment | 123 complexity | dfe280214602c850b81f1dd9c9da8477 MD5 | raw file
   1/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
   2 *
   3 *   Copyright 2010-2015, 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 "TomahawkSettings.h"
  22
  23#include "collection/Collection.h"
  24#include "database/DatabaseCommand_UpdateSearchIndex.h"
  25#include "database/Database.h"
  26#include "database/fuzzyindex/DatabaseFuzzyIndex.h"
  27#include "infosystem/InfoSystemCache.h"
  28#include "playlist/PlaylistUpdaterInterface.h"
  29#include "utils/Logger.h"
  30#include "utils/Json.h"
  31#include "utils/TomahawkUtils.h"
  32
  33#include "PlaylistEntry.h"
  34#include "PlaylistInterface.h"
  35#include "Source.h"
  36
  37#include <qt5keychain/keychain.h>
  38#include <QStandardPaths>
  39#include <QDir>
  40
  41using namespace Tomahawk;
  42
  43TomahawkSettings* TomahawkSettings::s_instance = 0;
  44
  45
  46inline QDataStream&
  47operator<<(QDataStream& out, const SerializedUpdaters& updaters)
  48{
  49    out <<  TOMAHAWK_SETTINGS_VERSION;
  50    out << (quint32)updaters.count();
  51    SerializedUpdaters::const_iterator iter = updaters.begin();
  52    int count = 0;
  53    for ( ; iter != updaters.end(); ++iter )
  54    {
  55        out << iter.key() << iter->type << iter->customData;
  56        count++;
  57    }
  58    Q_ASSERT( count == updaters.count() );
  59    return out;
  60}
  61
  62
  63inline QDataStream&
  64operator>>(QDataStream& in, SerializedUpdaters& updaters)
  65{
  66    quint32 count = 0, version = 0;
  67    in >> version;
  68    in >> count;
  69
  70    for ( uint i = 0; i < count; i++ )
  71    {
  72        QString key, type;
  73        QVariantHash customData;
  74        in >> key;
  75        in >> type;
  76        in >> customData;
  77        updaters.insert( key, SerializedUpdater( type, customData ) );
  78    }
  79
  80    return in;
  81}
  82
  83
  84TomahawkSettings*
  85TomahawkSettings::instance()
  86{
  87    return s_instance;
  88}
  89
  90
  91TomahawkSettings::TomahawkSettings( QObject* parent )
  92    : QSettings( parent )
  93{
  94    s_instance = this;
  95
  96    #if !(defined(Q_OS_MAC) && defined(Q_OS_WIN))
  97        QFile file( fileName() );
  98        file.setPermissions( file.permissions() & ~( QFile::ReadGroup | QFile::WriteGroup | QFile::ExeGroup | QFile::ReadOther | QFile::WriteOther | QFile::ExeOther ) );
  99    #endif
 100
 101    if ( !contains( "configversion" ) )
 102    {
 103        setValue( "configversion", TOMAHAWK_SETTINGS_VERSION );
 104        doInitialSetup();
 105    }
 106    else if ( value( "configversion" ).toUInt() != TOMAHAWK_SETTINGS_VERSION )
 107    {
 108        qDebug() << "Config version outdated, old:" << value( "configversion" ).toUInt()
 109                 << "new:" << TOMAHAWK_SETTINGS_VERSION
 110                 << "Doing upgrade, if any, and backing up";
 111
 112//         QString newname = QString( "%1.v%2" ).arg( dbname ).arg( version );
 113        if ( format() == IniFormat ||
 114             ( format() == NativeFormat
 115#ifdef Q_OS_WIN
 116               && false
 117#endif
 118             ) )
 119        {
 120            qDebug() << "Backing up old ini-style config file";
 121            const QString path = fileName();
 122            const QString newname = path + QString( ".v%1" ).arg( value( "configversion" ).toString() );
 123            QFile::copy( path, newname );
 124
 125        }
 126        int current = value( "configversion" ).toUInt();
 127        while ( current < TOMAHAWK_SETTINGS_VERSION )
 128        {
 129            doUpgrade( current, current + 1 );
 130
 131            current++;
 132        }
 133        // insert upgrade code here as required
 134        setValue( "configversion", TOMAHAWK_SETTINGS_VERSION );
 135    }
 136
 137    // Ensure last.fm and spotify accounts always exist
 138    QString spotifyAcct, lastfmAcct;
 139    foreach ( const QString& acct, value( "accounts/allaccounts" ).toStringList() )
 140    {
 141        if ( acct.startsWith( "lastfmaccount_" ) )
 142            lastfmAcct = acct;
 143        else if ( acct.startsWith( "spotifyaccount_" ) )
 144            spotifyAcct = acct;
 145    }
 146
 147    if ( spotifyAcct.isEmpty() )
 148        createSpotifyAccount();
 149    if ( lastfmAcct.isEmpty() )
 150        createLastFmAccount();
 151}
 152
 153
 154TomahawkSettings::~TomahawkSettings()
 155{
 156    s_instance = 0;
 157}
 158
 159
 160void
 161TomahawkSettings::doInitialSetup()
 162{
 163    // by default we add a local network resolver
 164    addAccount( "sipzeroconf_autocreated" );
 165
 166    createLastFmAccount();
 167    createSpotifyAccount();
 168}
 169
 170
 171void
 172TomahawkSettings::createLastFmAccount()
 173{
 174    // Add a last.fm account for scrobbling and infosystem
 175    const QString accountKey = QString( "lastfmaccount_%1" ).arg( QUuid::createUuid().toString().mid( 1, 8 ) );
 176    addAccount( accountKey );
 177
 178    beginGroup( "accounts/" + accountKey );
 179    setValue( "enabled", false );
 180    setValue( "autoconnect", true );
 181    setValue( "types", QStringList() << "ResolverType" << "StatusPushType" );
 182    endGroup();
 183
 184    QStringList allAccounts = value( "accounts/allaccounts" ).toStringList();
 185    allAccounts << accountKey;
 186    setValue( "accounts/allaccounts", allAccounts );
 187}
 188
 189
 190void
 191TomahawkSettings::createSpotifyAccount()
 192{
 193    const QString accountKey = QString( "spotifyaccount_%1" ).arg( QUuid::createUuid().toString().mid( 1, 8 ) );
 194    beginGroup( "accounts/" + accountKey );
 195    setValue( "enabled", false );
 196    setValue( "types", QStringList() << "ResolverType" );
 197    setValue( "configuration", QVariantHash() );
 198    setValue( "accountfriendlyname", "Spotify" );
 199    endGroup();
 200
 201    QStringList allAccounts = value( "accounts/allaccounts" ).toStringList();
 202    allAccounts << accountKey;
 203    setValue( "accounts/allaccounts", allAccounts );
 204}
 205
 206
 207void
 208TomahawkSettings::doUpgrade( int oldVersion, int newVersion )
 209{
 210    Q_UNUSED( newVersion );
 211
 212    if ( oldVersion == 1 )
 213    {
 214        qDebug() << "Migrating config from version 1 to 2: script resolver config name";
 215        if( contains( "script/resolvers" ) ) {
 216            setValue( "script/loadedresolvers", value( "script/resolvers" ) );
 217            remove( "script/resolvers" );
 218        }
 219    }
 220    else if ( oldVersion == 2 )
 221    {
 222        qDebug() << "Migrating config from version 2 to 3: Converting jabber and twitter accounts to new SIP Factory approach";
 223        // migrate old accounts to new system. only jabber and twitter, and max one each. create a new plugin for each if needed
 224        // not pretty as we hardcode a plugin id and assume that we know how the config layout is, but hey, this is migration after all
 225        if ( contains( "jabber/username" ) && contains( "jabber/password" ) )
 226        {
 227            QString sipName = "sipjabber";
 228            if ( value( "jabber/username" ).toString().contains( "@gmail" ) )
 229                sipName = "sipgoogle";
 230
 231            setValue( QString( "%1_legacy/username" ).arg( sipName ), value( "jabber/username" ) );
 232            setValue( QString( "%1_legacy/password" ).arg( sipName ), value( "jabber/password" ) );
 233            setValue( QString( "%1_legacy/autoconnect" ).arg( sipName ), value( "jabber/autoconnect" ) );
 234            setValue( QString( "%1_legacy/port" ).arg( sipName ), value( "jabber/port" ) );
 235            setValue( QString( "%1_legacy/server" ).arg( sipName ), value( "jabber/server" ) );
 236
 237            addSipPlugin( QString( "%1_legacy" ).arg( sipName ) );
 238
 239            remove( "jabber/username" );
 240            remove( "jabber/password" );
 241            remove( "jabber/autoconnect" );
 242            remove( "jabber/server" );
 243            remove( "jabber/port" );
 244        }
 245        if ( contains( "twitter/ScreenName" ) && contains( "twitter/OAuthToken" ) )
 246        {
 247            setValue( "siptwitter_legacy/ScreenName", value( "twitter/ScreenName" ) );
 248            setValue( "siptwitter_legacy/OAuthToken", value( "twitter/OAuthToken" ) );
 249            setValue( "siptwitter_legacy/OAuthTokenSecret", value( "twitter/OAuthTokenSecret" ) );
 250            setValue( "siptwitter_legacy/CachedFriendsSinceID", value( "twitter/CachedFriendsSinceID" ) );
 251            setValue( "siptwitter_legacy/CachedMentionsSinceID", value( "twitter/CachedMentionsSinceID" ) );
 252            setValue( "siptwitter_legacy/CachedDirectMessagesSinceID", value( "twitter/CachedDirectMessagesSinceID" ) );
 253            setValue( "siptwitter_legacy/CachedPeers", value( "twitter/CachedPeers" ) );
 254            setValue( "siptwitter_legacy/AutoConnect", value( "jabber/autoconnect" ) );
 255
 256            addSipPlugin( "siptwitter_legacy" );
 257            remove( "twitter/ScreenName" );
 258            remove( "twitter/OAuthToken" );
 259            remove( "twitter/OAuthTokenSecret" );
 260            remove( "twitter/CachedFriendsSinceID" );
 261            remove( "twitter/CachedMentionsSinceID" );
 262            remove( "twitter/CachedDirectMessagesSinceID" );
 263        }
 264        // create a zeroconf plugin too
 265        addSipPlugin( "sipzeroconf_legacy" );
 266    }
 267    else if ( oldVersion == 3 )
 268    {
 269        if ( contains( "script/atticaresolverstates" ) )
 270        {
 271            // Do messy binary upgrade. remove attica resolvers :(
 272            setValue( "script/atticaresolverstates", QVariant() );
 273
 274            QDir resolverDir = TomahawkUtils::appDataDir();
 275            if ( !resolverDir.cd( QString( "atticaresolvers" ) ) )
 276                return;
 277
 278            QStringList toremove;
 279            QStringList resolvers = resolverDir.entryList( QDir::Dirs | QDir::NoDotAndDotDot );
 280            QStringList listedResolvers = value( "script/resolvers" ).toStringList();
 281            QStringList enabledResolvers = value( "script/loadedresolvers" ).toStringList();
 282            foreach ( const QString& resolver, resolvers )
 283            {
 284                foreach ( const QString& r, listedResolvers )
 285                {
 286                    if ( r.contains( resolver ) )
 287                    {
 288                        tDebug() << "Deleting listed resolver:" << r;
 289                        listedResolvers.removeAll( r );
 290                    }
 291                }
 292                foreach ( const QString& r, enabledResolvers )
 293                {
 294                    if ( r.contains( resolver ) )
 295                    {
 296                        tDebug() << "Deleting enabled resolver:" << r;
 297                        enabledResolvers.removeAll( r );
 298                    }
 299                }
 300            }
 301            setValue( "script/resolvers", listedResolvers );
 302            setValue( "script/loadedresolvers", enabledResolvers );
 303            tDebug() << "UPGRADING AND DELETING:" << resolverDir.absolutePath();
 304            TomahawkUtils::removeDirectory( resolverDir.absolutePath() );
 305        }
 306    }
 307    else if ( oldVersion == 4 || oldVersion == 5 )
 308    {
 309        // 0.3.0 contained a bug which prevent indexing local files. Force a reindex.
 310        Tomahawk::DatabaseFuzzyIndex::wipeIndex();
 311        updateIndex();
 312    }
 313    else if ( oldVersion == 6 )
 314    {
 315        // Migrate to accounts from sipplugins.
 316        // collect old connected and enabled sip plugins
 317        const QStringList allSip = sipPlugins();
 318        const QStringList enabledSip = enabledSipPlugins();
 319
 320        QStringList accounts;
 321        foreach ( const QString& sipPlugin, allSip )
 322        {
 323            const QStringList parts = sipPlugin.split( "_" );
 324            Q_ASSERT( parts.size() == 2 );
 325
 326            const QString pluginName = parts[ 0 ];
 327            const QString pluginId = parts[ 1 ];
 328
 329            // new key, <plugin>account_<id>
 330            QString rawpluginname = pluginName;
 331            rawpluginname.replace( "sip", "" );
 332            if ( rawpluginname.contains( "jabber" ) )
 333                rawpluginname.replace( "jabber", "xmpp" );
 334
 335            QString accountKey = QString( "%1account_%2" ).arg( rawpluginname ).arg( pluginId );
 336
 337            if ( pluginName == "sipjabber" || pluginName == "sipgoogle" )
 338            {
 339                QVariantHash credentials;
 340                credentials[ "username" ] = value( sipPlugin + "/username" );
 341                credentials[ "password" ] = value( sipPlugin + "/password" );
 342
 343                QVariantHash configuration;
 344                configuration[ "port" ] = value( sipPlugin + "/port" );
 345                configuration[ "server" ] = value( sipPlugin + "/server" );
 346
 347                setValue( QString( "accounts/%1/credentials" ).arg( accountKey ), credentials );
 348                setValue( QString( "accounts/%1/configuration" ).arg( accountKey ), configuration );
 349                setValue( QString( "accounts/%1/accountfriendlyname" ).arg( accountKey ), value( sipPlugin + "/username" ) );
 350
 351            }
 352            else if ( pluginName == "siptwitter" )
 353            {
 354                // Only port twitter plugin if there's a valid twitter config
 355                if ( value( sipPlugin + "/oauthtokensecret" ).toString().isEmpty() &&
 356                     value( sipPlugin + "/oauthtoken" ).toString().isEmpty() &&
 357                     value( sipPlugin + "/screenname" ).toString().isEmpty() )
 358                    continue;
 359
 360                QVariantMap credentials;
 361                credentials[ "oauthtoken" ] = value( sipPlugin + "/oauthtoken" );
 362                credentials[ "oauthtokensecret" ] = value( sipPlugin + "/oauthtokensecret" );
 363                credentials[ "username" ] = value( sipPlugin + "/screenname" );
 364
 365                QVariantHash configuration;
 366                configuration[ "cachedfriendssinceid" ] = value( sipPlugin + "/cachedfriendssinceid" );
 367                configuration[ "cacheddirectmessagessinceid" ] = value( sipPlugin + "/cacheddirectmessagessinceid" );
 368                configuration[ "cachedpeers" ] = value( sipPlugin + "/cachedpeers" );
 369                qDebug() << "FOUND CACHED PEERS:" << value( sipPlugin + "/cachedpeers" ).toHash();
 370                configuration[ "cachedmentionssinceid" ] = value( sipPlugin + "/cachedmentionssinceid" );
 371                configuration[ "saveddbid" ] = value( sipPlugin + "/saveddbid" );
 372
 373                setValue( QString( "accounts/%1/credentials" ).arg( accountKey ), credentials );
 374                setValue( QString( "accounts/%1/configuration" ).arg( accountKey ), configuration );
 375                setValue( QString( "accounts/%1/accountfriendlyname" ).arg( accountKey ), "@" + value( sipPlugin + "/screenname" ).toString() );
 376                sync();
 377            }
 378            else if ( pluginName == "sipzeroconf" )
 379            {
 380                setValue( QString( "accounts/%1/accountfriendlyname" ).arg( accountKey ), tr( "Local Network" ) );
 381            }
 382
 383            beginGroup( "accounts/" + accountKey );
 384            setValue( "enabled", enabledSip.contains( sipPlugin ) == true );
 385            setValue( "autoconnect", true );
 386            setValue( "acl", QVariantHash() );
 387            setValue( "types", QStringList() << "SipType" );
 388            endGroup();
 389            accounts << accountKey;
 390
 391            remove( sipPlugin );
 392        }
 393        remove( "sip" );
 394
 395        // Migrate all resolvers from old resolvers settings to new accounts system
 396        const QStringList allResolvers = value( "script/resolvers" ).toStringList();
 397        const QStringList enabledResolvers = value( "script/loadedresolvers" ).toStringList();
 398
 399        foreach ( const QString& resolver, allResolvers )
 400        {
 401            // We handle last.fm resolvers differently.
 402            if ( resolver.contains( "lastfm" ) )
 403                continue;
 404
 405            const QString accountKey = QString( "resolveraccount_%1" ).arg( QUuid::createUuid().toString().mid( 1, 8 ) );
 406            accounts << accountKey;
 407
 408            beginGroup( "accounts/" + accountKey );
 409            setValue( "accountfriendlyname", resolver );
 410            setValue( "enabled", enabledResolvers.contains( resolver ) == true );
 411            setValue( "autoconnect", true );
 412            setValue( "types", QStringList() << "ResolverType" );
 413
 414            QVariantHash configuration;
 415            configuration[ "path" ] = resolver;
 416
 417            // reasonably ugly check for attica resolvers
 418            if ( resolver.contains( "atticaresolvers" ) && resolver.contains( "code" ) )
 419            {
 420                setValue( "atticaresolver", true );
 421
 422                QFileInfo info( resolver );
 423                configuration[ "atticaId" ] = info.baseName();
 424            }
 425
 426            setValue( "configuration", configuration );
 427            endGroup();
 428        }
 429
 430        // Add a Last.Fm account since we now moved the infoplugin into the account
 431        const QString accountKey = QString( "lastfmaccount_%1" ).arg( QUuid::createUuid().toString().mid( 1, 8 ) );
 432        accounts << accountKey;
 433        const QString lfmUsername = value( "lastfm/username" ).toString();
 434        const QString lfmPassword = value( "lastfm/password" ).toString();
 435        const bool scrobble = value( "lastfm/enablescrobbling", false ).toBool();
 436        beginGroup( "accounts/" + accountKey );
 437        bool hasLastFmEnabled = false;
 438        foreach ( const QString& r, enabledResolvers )
 439        {
 440            if ( r.contains( "lastfm" ) )
 441            {
 442                hasLastFmEnabled = true;
 443                break;
 444            }
 445        }
 446        setValue( "enabled", hasLastFmEnabled );
 447        setValue( "autoconnect", true );
 448        setValue( "types", QStringList() << "ResolverType" << "StatusPushType" );
 449        QVariantMap credentials;
 450        credentials[ "username" ] = lfmUsername;
 451        credentials[ "password" ] = lfmPassword;
 452        credentials[ "session" ] = value( "lastfm/session" ).toString();
 453        setValue( "credentials", credentials );
 454        QVariantHash configuration;
 455        configuration[ "scrobble" ] = scrobble;
 456        setValue( "configuration", configuration );
 457        endGroup();
 458
 459        remove( "lastfm" );
 460
 461        remove( "script/resolvers" );
 462        remove( "script/loadedresolvers" );
 463
 464        setValue( "accounts/allaccounts", accounts );
 465    }
 466    else if ( oldVersion == 7 )
 467    {
 468        // Upgrade spotify resolver to standalone account, if one exists
 469        beginGroup( "accounts" );
 470        QStringList allAccounts = value( "allaccounts" ).toStringList();
 471        foreach ( const QString& account, allAccounts )
 472        {
 473            if ( account.startsWith( "resolveraccount_" ) && value( QString( "%1/accountfriendlyname" ).arg( account ) ).toString().endsWith( "spotify_tomahawkresolver" ) )
 474            {
 475                // This is a spotify resolver, convert!
 476                const QVariantHash configuration = value( QString( "%1/configuration" ).arg( account ) ).toHash();
 477                const bool enabled = value( QString( "%1/enabled" ).arg( account ) ).toBool();
 478                const bool autoconnect = value( QString( "%1/autoconnect" ).arg( account ) ).toBool();
 479
 480                qDebug() << "Migrating Spotify resolver from legacy resolver type, path is:" << configuration[ "path" ].toString();
 481
 482                remove( account );
 483
 484                // Create new account
 485                QString newAccount = account;
 486                newAccount.replace( "resolveraccount_", "spotifyaccount_" );
 487                beginGroup( newAccount );
 488                setValue( "enabled", enabled );
 489                setValue( "autoconnect", autoconnect );
 490                setValue( "types", QStringList() << "ResolverType" );
 491                setValue( "accountfriendlyname", "Spotify" );
 492                setValue( "configuration", configuration );
 493                endGroup();
 494
 495                allAccounts.replace( allAccounts.indexOf( account ), newAccount );
 496            }
 497        }
 498
 499        setValue( "allaccounts", allAccounts );
 500        endGroup();
 501    }
 502    else if ( oldVersion == 8 )
 503    {
 504        // Some users got duplicate accounts for some reason, so make them unique if we can
 505        QSet< QString > uniqueFriendlyNames;
 506        beginGroup("accounts");
 507        const QStringList accounts = childGroups();
 508        QStringList allAccounts = value( "allaccounts" ).toStringList();
 509
 510//        qDebug() << "Got accounts to migrate:" << accounts;
 511        foreach ( const QString& account, accounts )
 512        {
 513            if ( !allAccounts.contains( account ) ) // orphan
 514            {
 515                qDebug() << "Found account not in allaccounts list!" << account << "is a dup!";
 516                remove( account );
 517                continue;
 518            }
 519
 520            const QString friendlyName = value( QString( "%1/accountfriendlyname" ).arg( account ) ).toString();
 521            if ( !uniqueFriendlyNames.contains( friendlyName ) )
 522            {
 523                uniqueFriendlyNames.insert( friendlyName );
 524                continue;
 525            }
 526            else
 527            {
 528                // Duplicate..?
 529                qDebug() << "Found duplicate account friendly name:" << account << friendlyName << "is a dup!";
 530                remove( account );
 531                allAccounts.removeAll( account );
 532            }
 533        }
 534        qDebug() << "Ended up with all accounts list:" << allAccounts << "and all accounts:" << childGroups();
 535        setValue( "allaccounts", allAccounts );
 536        endGroup();
 537    }
 538    else if ( oldVersion == 9 )
 539    {
 540        // Upgrade single-updater-per-playlist to list-per-playlist
 541        beginGroup( "playlistupdaters" );
 542        const QStringList playlists = childGroups();
 543
 544        SerializedUpdaters updaters;
 545        foreach ( const QString& playlist, playlists )
 546        {
 547            beginGroup( playlist );
 548            const QString type = value( "type" ).toString();
 549
 550            QVariantHash extraData;
 551            foreach ( const QString& key, childKeys() )
 552            {
 553                if ( key == "type" )
 554                    continue;
 555
 556                extraData[ key ] = value( key );
 557            }
 558
 559            updaters.insert( playlist, SerializedUpdater( type, extraData ) );
 560
 561            endGroup();
 562        }
 563
 564        endGroup();
 565        remove( "playlistupdaters" );
 566
 567        setValue( "playlists/updaters", QVariant::fromValue< SerializedUpdaters >( updaters ) );
 568
 569    }
 570    else if ( oldVersion == 11 )
 571    {
 572        // If the user doesn't have a spotify account, create one, since now it
 573        // is like the last.fm account and always exists
 574        QStringList allAccounts = value( "accounts/allaccounts" ).toStringList();
 575        QString acct;
 576        foreach ( const QString& account, allAccounts )
 577        {
 578            if ( account.startsWith( "spotifyaccount_" ) )
 579            {
 580                acct = account;
 581                break;
 582            }
 583        }
 584
 585        if ( !acct.isEmpty() )
 586        {
 587            beginGroup( "accounts/" + acct );
 588            QVariantHash conf = value( "configuration" ).toHash();
 589            foreach ( const QString& key, conf.keys() )
 590                qDebug() << key << conf[ key ].toString();
 591            endGroup();
 592        }
 593        else
 594        {
 595            createSpotifyAccount();
 596        }
 597    }
 598    else if ( oldVersion == 12 )
 599    {
 600        // Force attica resolver pixmap cache refresh
 601        QDir cacheDir = TomahawkUtils::appDataDir();
 602        if ( cacheDir.cd( "atticacache" ) )
 603        {
 604            QStringList files = cacheDir.entryList( QStringList() << "*.png" );
 605            foreach ( const QString& file, files )
 606            {
 607                const bool removed = cacheDir.remove( file );
 608                tDebug() << "Tried to remove cached image, succeeded?" << removed << cacheDir.filePath( file );
 609            }
 610        }
 611    }
 612    else if ( oldVersion == 13 )
 613    {
 614        //Delete old echonest_stylesandmoods.dat file
 615        QFile dataFile( TomahawkUtils::appDataDir().absoluteFilePath( "echonest_stylesandmoods.dat" ) );
 616        const bool removed = dataFile.remove();
 617        tDebug() << "Tried to remove echonest_stylesandmoods.dat, succeeded?" << removed;
 618    }
 619    else if ( oldVersion == 14 )
 620    {
 621        //No upgrade on OSX: we keep storing credentials in TomahawkSettings
 622        //because QtKeychain and/or OSX Keychain is flaky. --Teo 12/2013
 623#ifndef Q_OS_MAC
 624        const QStringList accounts = value( "accounts/allaccounts" ).toStringList();
 625        tDebug() << "About to move these accounts to QtKeychain:" << accounts;
 626
 627        //Move storage of Credentials from QSettings to QtKeychain
 628        foreach ( const QString& account, accounts )
 629        {
 630            tDebug() << "beginGroup" << QString( "accounts/%1" ).arg( account );
 631            beginGroup( QString( "accounts/%1" ).arg( account ) );
 632            const QVariantHash hash = value( "credentials" ).toHash();
 633            tDebug() << hash[ "username" ]
 634                     << ( hash[ "password" ].isNull() ? ", no password" : ", has password" );
 635
 636            QVariantMap creds;
 637            for ( QVariantHash::const_iterator it = hash.constBegin(); it != hash.constEnd(); ++it )
 638            {
 639                creds.insert( it.key(), it.value() );
 640
 641            }
 642            if ( !creds.isEmpty() )
 643            {
 644                QKeychain::WritePasswordJob* j = new QKeychain::WritePasswordJob( QLatin1String( "Tomahawk" ), this );
 645                j->setKey( account );
 646                j->setAutoDelete( true );
 647#if defined( Q_OS_UNIX ) && !defined( Q_OS_MAC )
 648                j->setInsecureFallback( true );
 649#endif
 650                bool ok;
 651                QByteArray data = TomahawkUtils::toJson( creds, &ok );
 652
 653                if ( ok )
 654                {
 655                    tDebug() << "Performing upgrade for account" << account;
 656                }
 657                else
 658                {
 659                    tDebug() << "Upgrade error: cannot serialize credentials to JSON for account" << account;
 660                }
 661
 662                j->setTextData( data );
 663                j->start();
 664            }
 665
 666            remove( "credentials" );
 667
 668            endGroup();
 669        }
 670#endif //Q_OS_MAC
 671    }
 672    else if ( oldVersion == 15 )
 673    {
 674        // 0.8.0 switches to Lucene++. Force a reindex.
 675        // (obsoleted by version 16 update)
 676    }
 677    else if ( oldVersion == 16 )
 678    {
 679        Tomahawk::DatabaseFuzzyIndex::wipeIndex();
 680        updateIndex();
 681    }
 682}
 683
 684
 685void
 686TomahawkSettings::setAcceptedLegalWarning( bool accept )
 687{
 688    setValue( "acceptedLegalWarning", accept );
 689}
 690
 691
 692bool
 693TomahawkSettings::acceptedLegalWarning() const
 694{
 695    return value( "acceptedLegalWarning", false ).toBool();
 696}
 697
 698
 699void
 700TomahawkSettings::setInfoSystemCacheVersion( uint version )
 701{
 702    setValue( "infosystemcacheversion", version );
 703}
 704
 705
 706uint
 707TomahawkSettings::infoSystemCacheVersion() const
 708{
 709    return value( "infosystemcacheversion", 0 ).toUInt();
 710}
 711
 712
 713void
 714TomahawkSettings::setGenericCacheVersion( uint version )
 715{
 716    setValue( "genericcacheversion", version );
 717}
 718
 719
 720uint
 721TomahawkSettings::genericCacheVersion() const
 722{
 723    return value( "genericcacheversion", 0 ).toUInt();
 724}
 725
 726
 727QString
 728TomahawkSettings::storageCacheLocation() const
 729{
 730    return QStandardPaths::writableLocation( QStandardPaths::CacheLocation );
 731}
 732
 733
 734QStringList
 735TomahawkSettings::scannerPaths() const
 736{
 737    QString musicLocation;
 738
 739    musicLocation = QStandardPaths::writableLocation( QStandardPaths::MusicLocation );
 740
 741    return value( "scanner/paths", musicLocation ).toStringList();
 742}
 743
 744
 745void
 746TomahawkSettings::setScannerPaths( const QStringList& paths )
 747{
 748    setValue( "scanner/paths", paths );
 749}
 750
 751
 752bool
 753TomahawkSettings::hasScannerPaths() const
 754{
 755    //FIXME: After enough time, remove this hack
 756    return contains( "scanner/paths" ) || contains( "scannerpath" ) || contains( "scannerpaths" );
 757}
 758
 759
 760uint
 761TomahawkSettings::scannerTime() const
 762{
 763    return value( "scanner/intervaltime", 60 ).toUInt();
 764}
 765
 766
 767void
 768TomahawkSettings::setScannerTime( uint time )
 769{
 770    setValue( "scanner/intervaltime", time );
 771}
 772
 773
 774bool
 775TomahawkSettings::watchForChanges() const
 776{
 777    return value( "scanner/watchforchanges", false ).toBool();
 778}
 779
 780
 781void
 782TomahawkSettings::setWatchForChanges( bool watch )
 783{
 784    setValue( "scanner/watchforchanges", watch );
 785}
 786
 787
 788QString
 789TomahawkSettings::downloadsPreferredFormat() const
 790{
 791    return value( "downloadmanager/preferredFormat", "MP3" ).toString();
 792}
 793
 794
 795void
 796TomahawkSettings::setDownloadsPreferredFormat( const QString& format )
 797{
 798    setValue( "downloadmanager/preferredFormat", format );
 799}
 800
 801
 802QString
 803TomahawkSettings::downloadsPath() const
 804{
 805    QString musicLocation;
 806    if ( !scannerPaths().isEmpty() )
 807        musicLocation = scannerPaths().first();
 808
 809    return value( "downloadmanager/path", musicLocation ).toString();
 810}
 811
 812
 813void
 814TomahawkSettings::setDownloadsPath( const QString& path )
 815{
 816    setValue( "downloadmanager/path", path );
 817}
 818
 819
 820QVariantList
 821TomahawkSettings::downloadStates() const
 822{
 823    return value( "downloadmanager/states", QVariantList() ).toList();
 824}
 825
 826
 827void
 828TomahawkSettings::setDownloadStates( const QVariantList& downloads )
 829{
 830    setValue( "downloadmanager/states", downloads );
 831}
 832
 833
 834bool
 835TomahawkSettings::httpEnabled() const
 836{
 837    return value( "network/http", true ).toBool();
 838}
 839
 840
 841void
 842TomahawkSettings::setHttpEnabled( bool enable )
 843{
 844    setValue( "network/http", enable );
 845}
 846
 847
 848bool
 849TomahawkSettings::httpBindAll() const
 850{
 851    return value ( "network/httpbindall", false ).toBool();
 852}
 853
 854
 855void
 856TomahawkSettings::setHttpBindAll( bool bindAll )
 857{
 858    setValue( "network/httpbindall", bindAll );
 859}
 860
 861
 862bool
 863TomahawkSettings::crashReporterEnabled() const
 864{
 865    return value( "ui/crashReporter", true ).toBool();
 866}
 867
 868
 869void
 870TomahawkSettings::setCrashReporterEnabled( bool enable )
 871{
 872    setValue( "ui/crashReporter", enable );
 873}
 874
 875
 876bool
 877TomahawkSettings::songChangeNotificationEnabled() const
 878{
 879    return value( "ui/songChangeNotification", true ).toBool();
 880}
 881
 882
 883void
 884TomahawkSettings::setSongChangeNotificationEnabled(bool enable)
 885{
 886    setValue( "ui/songChangeNotification", enable );
 887}
 888
 889
 890bool
 891TomahawkSettings::autoDetectExternalIp() const
 892{
 893    return value( "network/auto-detect-external-ip" ).toBool();
 894}
 895
 896
 897void
 898TomahawkSettings::setAutoDetectExternalIp( bool autoDetect )
 899{
 900    setValue( "network/auto-detect-external-ip", autoDetect );
 901}
 902
 903
 904unsigned int
 905TomahawkSettings::volume() const
 906{
 907    return value( "audio/volume", 75 ).toUInt();
 908}
 909
 910
 911void
 912TomahawkSettings::setVolume( unsigned int volume )
 913{
 914    setValue( "audio/volume", volume );
 915}
 916
 917
 918bool
 919TomahawkSettings::muted() const
 920{
 921    return value( "audio/muted" ).toBool();
 922}
 923
 924
 925void
 926TomahawkSettings::setMuted( bool muted )
 927{
 928    setValue( "audio/muted", muted );
 929}
 930
 931
 932QString
 933TomahawkSettings::proxyHost() const
 934{
 935    return value( "network/proxy/host", QString() ).toString();
 936}
 937
 938
 939void
 940TomahawkSettings::setProxyHost( const QString& host )
 941{
 942    setValue( "network/proxy/host", host );
 943}
 944
 945
 946QString
 947TomahawkSettings::proxyNoProxyHosts() const
 948{
 949    return value( "network/proxy/noproxyhosts", QString() ).toString();
 950}
 951
 952
 953void
 954TomahawkSettings::setProxyNoProxyHosts( const QString& hosts )
 955{
 956    setValue( "network/proxy/noproxyhosts", hosts );
 957}
 958
 959
 960qulonglong
 961TomahawkSettings::proxyPort() const
 962{
 963    return value( "network/proxy/port", 1080 ).toULongLong();
 964}
 965
 966
 967void
 968TomahawkSettings::setProxyPort( const qulonglong port )
 969{
 970    setValue( "network/proxy/port", port );
 971}
 972
 973
 974QString
 975TomahawkSettings::proxyUsername() const
 976{
 977    return value( "network/proxy/username", QString() ).toString();
 978}
 979
 980
 981void
 982TomahawkSettings::setProxyUsername( const QString& username )
 983{
 984    setValue( "network/proxy/username", username );
 985}
 986
 987
 988QString
 989TomahawkSettings::proxyPassword() const
 990{
 991    return value( "network/proxy/password", QString() ).toString();
 992}
 993
 994
 995void
 996TomahawkSettings::setProxyPassword( const QString& password )
 997{
 998    setValue( "network/proxy/password", password );
 999}
1000
1001
1002QNetworkProxy::ProxyType
1003TomahawkSettings::proxyType() const
1004{
1005    return static_cast< QNetworkProxy::ProxyType>( value( "network/proxy/type", QNetworkProxy::NoProxy ).toInt() );
1006}
1007
1008
1009void
1010TomahawkSettings::setProxyType( const QNetworkProxy::ProxyType type )
1011{
1012    setValue( "network/proxy/type", static_cast< uint >( type ) );
1013}
1014
1015
1016bool
1017TomahawkSettings::proxyDns() const
1018{
1019    return value( "network/proxy/dns", false ).toBool();
1020}
1021
1022
1023void
1024TomahawkSettings::setProxyDns( bool lookupViaProxy )
1025{
1026    setValue( "network/proxy/dns", lookupViaProxy );
1027}
1028
1029
1030QVariantList
1031TomahawkSettings::aclEntries() const
1032{
1033    QVariant retVal = value( "acl/entries", QVariantList() );
1034    if ( retVal.isValid() && retVal.canConvert< QVariantList >() )
1035        return retVal.toList();
1036
1037    return QVariantList();
1038}
1039
1040
1041void
1042TomahawkSettings::setAclEntries( const QVariantList &entries )
1043{
1044    tDebug() << "Setting entries";
1045    setValue( "acl/entries", entries );
1046    sync();
1047    tDebug() << "Done setting entries";
1048}
1049
1050
1051bool
1052TomahawkSettings::isSslCertKnown( const QByteArray& sslDigest ) const
1053{
1054    return value( "network/ssl/certs" ).toMap().contains( sslDigest );
1055}
1056
1057
1058bool
1059TomahawkSettings::isSslCertTrusted( const QByteArray& sslDigest ) const
1060{
1061    return value( "network/ssl/certs" ).toMap().value( sslDigest, false ).toBool();
1062}
1063
1064
1065void
1066TomahawkSettings::setSslCertTrusted( const QByteArray& sslDigest, bool trusted )
1067{
1068    QVariantMap map = value( "network/ssl/certs" ).toMap();
1069    map[ sslDigest ] = trusted;
1070
1071    setValue( "network/ssl/certs", map );
1072}
1073
1074
1075QByteArray
1076TomahawkSettings::mainWindowGeometry() const
1077{
1078    return value( "ui/mainwindow/geometry" ).toByteArray();
1079}
1080
1081
1082void
1083TomahawkSettings::setMainWindowGeometry( const QByteArray& geom )
1084{
1085    setValue( "ui/mainwindow/geometry", geom );
1086}
1087
1088
1089QByteArray
1090TomahawkSettings::mainWindowState() const
1091{
1092    return value( "ui/mainwindow/state" ).toByteArray();
1093}
1094
1095
1096void
1097TomahawkSettings::setMainWindowState( const QByteArray& state )
1098{
1099    setValue( "ui/mainwindow/state", state );
1100}
1101
1102
1103QByteArray
1104TomahawkSettings::mainWindowSplitterState() const
1105{
1106    return value( "ui/mainwindow/splitterState" ).toByteArray();
1107}
1108
1109
1110void
1111TomahawkSettings::setMainWindowSplitterState( const QByteArray& state )
1112{
1113    setValue( "ui/mainwindow/splitterState", state );
1114}
1115
1116
1117bool
1118TomahawkSettings::verboseNotifications() const
1119{
1120    return value( "ui/notifications/verbose", false ).toBool();
1121}
1122
1123
1124void
1125TomahawkSettings::setVerboseNotifications( bool notifications )
1126{
1127    setValue( "ui/notifications/verbose", notifications );
1128}
1129
1130
1131bool
1132TomahawkSettings::menuBarVisible() const
1133{
1134#ifndef Q_OS_MAC
1135    return value( "ui/mainwindow/menuBarVisible", true ).toBool();
1136#else
1137    return true;
1138#endif
1139}
1140
1141
1142void
1143TomahawkSettings::setMenuBarVisible( bool visible )
1144{
1145#ifndef Q_OS_MAC
1146    setValue( "ui/mainwindow/menuBarVisible", visible );
1147#endif
1148}
1149
1150
1151bool
1152TomahawkSettings::fullscreenEnabled() const
1153{
1154    return value( "ui/mainwindow/fullscreenEnabled", false ).toBool();
1155}
1156
1157
1158void
1159TomahawkSettings::setFullscreenEnabled( bool enabled )
1160{
1161    setValue( "ui/mainwindow/fullscreenEnabled", enabled );
1162}
1163
1164
1165bool
1166TomahawkSettings::showOfflineSources() const
1167{
1168    return value( "collection/sources/showoffline", false ).toBool();
1169}
1170
1171
1172void
1173TomahawkSettings::setShowOfflineSources( bool show )
1174{
1175    setValue( "collection/sources/showoffline", show );
1176}
1177
1178
1179bool
1180TomahawkSettings::enableEchonestCatalogs() const
1181{
1182    return value( "collection/enable_catalogs", false ).toBool();
1183}
1184
1185
1186void
1187TomahawkSettings::setEnableEchonestCatalogs( bool enable )
1188{
1189    setValue( "collection/enable_catalogs", enable );
1190}
1191
1192
1193QByteArray
1194TomahawkSettings::playlistColumnSizes( const QString& playlistid ) const
1195{
1196    return value( QString( "ui/playlist/%1/columnSizes" ).arg( playlistid ) ).toByteArray();
1197}
1198
1199
1200void
1201TomahawkSettings::setPlaylistColumnSizes( const QString& playlistid, const QByteArray& state )
1202{
1203    if ( playlistid.isEmpty() )
1204        return;
1205
1206    setValue( QString( "ui/playlist/%1/columnSizes" ).arg( playlistid ), state );
1207}
1208
1209
1210bool
1211TomahawkSettings::shuffleState( const QString& playlistid ) const
1212{
1213    return value( QString( "ui/playlist/%1/shuffleState" ).arg( playlistid ) ).toBool();
1214}
1215
1216
1217void
1218TomahawkSettings::setShuffleState( const QString& playlistid, bool state)
1219{
1220    setValue( QString( "ui/playlist/%1/shuffleState" ).arg( playlistid ), state );
1221}
1222
1223
1224void
1225TomahawkSettings::removePlaylistSettings( const QString& playlistid )
1226{
1227    remove( QString( "ui/playlist/%1/shuffleState" ).arg( playlistid ) );
1228    remove( QString( "ui/playlist/%1/repeatMode" ).arg( playlistid ) );
1229}
1230
1231
1232QVariant
1233TomahawkSettings::queueState() const
1234{
1235    return value( QString( "playlists/queue/state" ) );
1236}
1237
1238
1239void
1240TomahawkSettings::setQueueState( const QVariant& state )
1241{
1242    setValue( QString( "playlists/queue/state" ), state );
1243}
1244
1245
1246void
1247TomahawkSettings::setRepeatMode( const QString& playlistid, Tomahawk::PlaylistModes::RepeatMode mode )
1248{
1249    setValue( QString( "ui/playlist/%1/repeatMode" ).arg( playlistid ), (int)mode );
1250}
1251
1252
1253Tomahawk::PlaylistModes::RepeatMode
1254TomahawkSettings::repeatMode( const QString& playlistid )
1255{
1256    return (PlaylistModes::RepeatMode)value( QString( "ui/playlist/%1/repeatMode" ).arg( playlistid ) ).toInt();
1257}
1258
1259
1260QStringList
1261TomahawkSettings::recentlyPlayedPlaylistGuids( unsigned int amount ) const
1262{
1263    QStringList p = value( "playlists/recentlyPlayed" ).toStringList();
1264
1265    while ( amount && p.count() > (int)amount )
1266        p.removeAt( 0 );
1267
1268    return p;
1269}
1270
1271
1272void
1273TomahawkSettings::appendRecentlyPlayedPlaylist( const QString& playlistguid, int sourceId )
1274{
1275    QStringList playlist_guids = value( "playlists/recentlyPlayed" ).toStringList();
1276
1277    playlist_guids.removeAll( playlistguid );
1278    playlist_guids.append( playlistguid );
1279
1280    setValue( "playlists/recentlyPlayed", playlist_guids );
1281
1282    emit recentlyPlayedPlaylistAdded( playlistguid, sourceId );
1283}
1284
1285
1286QString
1287TomahawkSettings::bookmarkPlaylist() const
1288{
1289    return value( "playlists/bookmark", QString() ).toString();
1290}
1291
1292
1293void
1294TomahawkSettings::setBookmarkPlaylist( const QString& guid )
1295{
1296    setValue( "playlists/bookmark", guid );
1297}
1298
1299
1300QStringList
1301TomahawkSettings::sipPlugins() const
1302{
1303    return value( "sip/allplugins", QStringList() ).toStringList();
1304}
1305
1306
1307void
1308TomahawkSettings::setSipPlugins( const QStringList& plugins )
1309{
1310    setValue( "sip/allplugins", plugins );
1311}
1312
1313
1314QStringList
1315TomahawkSettings::enabledSipPlugins() const
1316{
1317    return value( "sip/enabledplugins", QStringList() ).toStringList();
1318}
1319
1320
1321void
1322TomahawkSettings::setEnabledSipPlugins( const QStringList& list )
1323{
1324    setValue( "sip/enabledplugins", list );
1325}
1326
1327
1328void
1329TomahawkSettings::enableSipPlugin( const QString& pluginId )
1330{
1331    QStringList list = enabledSipPlugins();
1332    list << pluginId;
1333    setEnabledSipPlugins( list );
1334}
1335
1336
1337void
1338TomahawkSettings::disableSipPlugin( const QString& pluginId )
1339{
1340    QStringList list = enabledSipPlugins();
1341    list.removeAll( pluginId );
1342    setEnabledSipPlugins( list );
1343}
1344
1345
1346void
1347TomahawkSettings::addSipPlugin( const QString& pluginId, bool enable )
1348{
1349    QStringList list = sipPlugins();
1350    list << pluginId;
1351    setSipPlugins( list );
1352
1353    if ( enable )
1354        enableSipPlugin( pluginId );
1355}
1356
1357
1358void
1359TomahawkSettings::removeSipPlugin( const QString& pluginId )
1360{
1361    QStringList list = sipPlugins();
1362    list.removeAll( pluginId );
1363    setSipPlugins( list );
1364
1365    if( enabledSipPlugins().contains( pluginId ) )
1366        disableSipPlugin( pluginId );
1367}
1368
1369
1370QStringList
1371TomahawkSettings::accounts() const
1372{
1373    QStringList accounts = value( "accounts/allaccounts", QStringList() ).toStringList();
1374    accounts.removeDuplicates();
1375
1376    return accounts;
1377}
1378
1379
1380void
1381TomahawkSettings::setAccounts( const QStringList& accountIds )
1382{
1383    QStringList accounts = accountIds;
1384    accounts.removeDuplicates();
1385
1386    setValue( "accounts/allaccounts", accounts );
1387}
1388
1389
1390void
1391TomahawkSettings::addAccount( const QString& accountId )
1392{
1393    QStringList list = accounts();
1394    list << accountId;
1395    setAccounts( list );
1396}
1397
1398
1399void
1400TomahawkSettings::removeAccount( const QString& accountId )
1401{
1402    QStringList list = accounts();
1403    list.removeAll( accountId );
1404    setAccounts( list );
1405}
1406
1407
1408Tomahawk::Network::ExternalAddress::Mode
1409TomahawkSettings::externalAddressMode()
1410{
1411    if ( value( "network/prefer-static-host-and-port", false ).toBool() )
1412    {
1413        remove( "network/prefer-static-host-and-port" );
1414        setValue( "network/external-address-mode", Tomahawk::Network::ExternalAddress::Static );
1415    }
1416    return (Tomahawk::Network::ExternalAddress::Mode) value( "network/external-address-mode", Tomahawk::Network::ExternalAddress::Upnp ).toInt();
1417}
1418
1419
1420void
1421TomahawkSettings::setExternalAddressMode( Tomahawk::Network::ExternalAddress::Mode externalAddressMode )
1422{
1423    setValue( "network/external-address-mode", externalAddressMode );
1424}
1425
1426
1427QString
1428TomahawkSettings::externalHostname() const
1429{
1430    return value( "network/external-hostname" ).toString();
1431}
1432
1433
1434void
1435TomahawkSettings::setExternalHostname(const QString& externalHostname)
1436{
1437    setValue( "network/external-hostname", externalHostname );
1438}
1439
1440
1441int
1442TomahawkSettings::defaultPort() const
1443{
1444    return 50210;
1445}
1446
1447
1448int
1449TomahawkSettings::externalPort() const
1450{
1451    return value( "network/external-port", 50210 ).toInt();
1452}
1453
1454
1455void
1456TomahawkSettings::setExternalPort(int externalPort)
1457{
1458    if ( externalPort == 0 )
1459        setValue( "network/external-port", 50210);
1460    else
1461        setValue( "network/external-port", externalPort);
1462}
1463
1464
1465QString
1466TomahawkSettings::xmppBotServer() const
1467{
1468    return value( "xmppBot/server", QString() ).toString();
1469}
1470
1471
1472void
1473TomahawkSettings::setXmppBotServer( const QString& server )
1474{
1475    setValue( "xmppBot/server", server );
1476}
1477
1478
1479QString
1480TomahawkSettings::xmppBotJid() const
1481{
1482    return value( "xmppBot/jid", QString() ).toString();
1483}
1484
1485
1486void
1487TomahawkSettings::setXmppBotJid( const QString& component )
1488{
1489    setValue( "xmppBot/jid", component );
1490}
1491
1492
1493QString
1494TomahawkSettings::xmppBotPassword() const
1495{
1496    return value( "xmppBot/password", QString() ).toString();
1497}
1498
1499
1500void
1501TomahawkSettings::setXmppBotPassword( const QString& password )
1502{
1503    setValue( "xmppBot/password", password );
1504}
1505
1506
1507int
1508TomahawkSettings::xmppBotPort() const
1509{
1510    return value( "xmppBot/port", -1 ).toInt();
1511}
1512
1513
1514void
1515TomahawkSettings::setXmppBotPort( const int port )
1516{
1517    setValue( "xmppBot/port", port );
1518}
1519
1520
1521QString
1522TomahawkSettings::scriptDefaultPath() const
1523{
1524    return value( "script/defaultpath", QDir::homePath() ).toString();
1525}
1526
1527
1528void
1529TomahawkSettings::setScriptDefaultPath( const QString& path )
1530{
1531    setValue( "script/defaultpath", path );
1532}
1533
1534
1535QString
1536TomahawkSettings::playlistDefaultPath() const
1537{
1538    return value( "playlists/defaultpath", QDir::homePath() ).toString();
1539}
1540
1541
1542void
1543TomahawkSettings::setPlaylistDefaultPath( const QString& path )
1544{
1545    setValue( "playlists/defaultpath", path );
1546}
1547
1548
1549bool
1550TomahawkSettings::nowPlayingEnabled() const
1551{
1552    return value( "adium/enablenowplaying", false ).toBool();
1553}
1554
1555
1556void
1557TomahawkSettings::setNowPlayingEnabled( bool enable )
1558{
1559    setValue( "adium/enablenowplaying", enable );
1560}
1561
1562
1563TomahawkSettings::PrivateListeningMode
1564TomahawkSettings::privateListeningMode() const
1565{
1566    return ( TomahawkSettings::PrivateListeningMode ) value( "privatelisteningmode", TomahawkSettings::PublicListening ).toInt();
1567}
1568
1569
1570void
1571TomahawkSettings::setPrivateListeningMode( TomahawkSettings::PrivateListeningMode mode )
1572{
1573    setValue( "privatelisteningmode", mode );
1574}
1575
1576
1577void
1578TomahawkSettings::updateIndex()
1579{
1580    if ( !Database::instance() || !Database::instance()->isReady() )
1581    {
1582        QTimer::singleShot( 0, this, SLOT( updateIndex() ) );
1583        return;
1584    }
1585
1586    tDebug() << Q_FUNC_INFO << "Updating fuzzy index.";
1587
1588    Tomahawk::DatabaseCommand* cmd = new Tomahawk::DatabaseCommand_UpdateSearchIndex();
1589    Database::instance()->enqueue( QSharedPointer<Tomahawk::DatabaseCommand>( cmd ) );
1590}
1591
1592
1593QString
1594TomahawkSettings::importPlaylistPath() const
1595{
1596    if ( contains( "importPlaylistPath" ) )
1597        return value( "importPlaylistPath" ).toString();
1598    else
1599        return QDir::homePath();
1600}
1601
1602
1603void
1604TomahawkSettings::setImportPlaylistPath( const QString& path )
1605{
1606    setValue( "importPlaylistPath", path );
1607}
1608
1609
1610SerializedUpdaters
1611TomahawkSettings::playlistUpdaters() const
1612{
1613    return value( "playlists/updaters" ).value< SerializedUpdaters >();
1614}
1615
1616
1617void
1618TomahawkSettings::setPlaylistUpdaters( const SerializedUpdaters& updaters )
1619{
1620    setValue( "playlists/updaters", QVariant::fromValue< SerializedUpdaters >( updaters ) );
1621}
1622
1623
1624void
1625TomahawkSettings::setLastChartIds( const QMap<QString, QVariant>& ids ){
1626
1627    setValue( "chartIds", QVariant::fromValue<QMap<QString, QVariant> >( ids ) );
1628}
1629
1630
1631QMap<QString, QVariant> TomahawkSettings::lastChartIds(){
1632
1633    return value( "chartIds" ).value<QMap<QString, QVariant> >();
1634}
1635
1636
1637inline QDataStream&
1638operator<<( QDataStream& out, const AtticaManager::StateHash& states )
1639{
1640    out <<  TOMAHAWK_SETTINGS_VERSION;
1641    out << (quint32)states.count();
1642    foreach( const QString& key, states.keys() )
1643    {
1644        AtticaManager::Resolver resolver = states[ key ];
1645        out << key << resolver.version << resolver.scriptPath << (qint32)resolver.state << resolver.userRating << resolver.binary;
1646    }
1647    return out;
1648}
1649
1650
1651inline QDataStream&
1652operator>>( QDataStream& in, AtticaManager::StateHash& states )
1653{
1654    quint32 count = 0, configVersion = 0;
1655    in >> configVersion;
1656    in >> count;
1657    for ( uint i = 0; i < count; i++ )
1658    {
1659        QString key, version, scriptPath;
1660        qint32 state, userRating;
1661        bool binary = false;
1662        in >> key;
1663        in >> version;
1664        in >> scriptPath;
1665        in >> state;
1666        in >> userRating;
1667        if ( configVersion > 10 )
1668        {
1669            // V11 includes 'bool binary' flag
1670            in >> binary;
1671        }
1672        states[ key ] = AtticaManager::Resolver( version, scriptPath, userRating, (AtticaManager::ResolverState)state, binary );
1673    }
1674    return in;
1675}
1676
1677
1678void
1679TomahawkSettings::registerCustomSettingsHandlers()
1680{
1681    qRegisterMetaType< Tomahawk::SerializedUpdater >( "Tomahawk::SerializedUpdater" );
1682    qRegisterMetaType< Tomahawk::SerializedUpdaters >( "Tomahawk::SerializedUpdaters" );
1683    qRegisterMetaTypeStreamOperators< Tomahawk::SerializedUpdaters >( "Tomahawk::SerializedUpdaters" );
1684
1685    qRegisterMetaType< AtticaManager::StateHash >( "AtticaManager::StateHash" );
1686    qRegisterMetaTypeStreamOperators< AtticaManager::StateHash >( "AtticaManager::StateHash" );
1687}
1688
1689
1690void
1691TomahawkSettings::setAtticaResolverState( const QString& resolver, AtticaManager::ResolverState state )
1692{
1693    AtticaManager::StateHash resolvers = value( "script/atticaresolverstates" ).value< AtticaManager::StateHash >();
1694    AtticaManager::Resolver r = resolvers.value( resolver );
1695    r.state = state;
1696    resolvers.insert( resolver, r );
1697    setValue( "script/atticaresolverstates", QVariant::fromValue< AtticaManager::StateHash >( resolvers ) );
1698
1699    sync();
1700}
1701
1702
1703AtticaManager::StateHash
1704TomahawkSettings::atticaResolverStates() const
1705{
1706    return value( "script/atticaresolverstates" ).value< AtticaManager::StateHash >();
1707}
1708
1709
1710void
1711TomahawkSettings::setAtticaResolverStates( const AtticaManager::StateHash states )
1712{
1713    setValue( "script/atticaresolverstates", QVariant::fromValue< AtticaManager::StateHash >( states ) );
1714}
1715
1716
1717void
1718TomahawkSettings::removeAtticaResolverState ( const QString& resolver )
1719{
1720    AtticaManager::StateHash resolvers = value( "script/atticaresolverstates" ).value< AtticaManager::StateHash >();
1721    resolvers.remove( resolver );
1722    setValue( "script/atticaresolverstates", QVariant::fromValue< AtticaManager::StateHash >( resolvers ) );
1723}
1724
1725
1726QByteArray
1727TomahawkSettings::playdarCertificate() const
1728{
1729    return value( "playdar/certificate").value< QByteArray >();
1730}
1731
1732
1733void
1734TomahawkSettings::setPlaydarCertificate( const QByteArray& cert )
1735{
1736    setValue( "playdar/certificate", cert );
1737}
1738
1739
1740QByteArray
1741TomahawkSettings::playdarKey() const
1742{
1743    return value( "playdar/key" ).value< QByteArray >();
1744}
1745
1746
1747void
1748TomahawkSettings::setPlaydarKey( const QByteArray& key )
1749{
1750    setValue( "playdar/key", key );
1751}
1752
1753QString
1754TomahawkSettings::vlcArguments() const
1755{
1756    return value( "vlc/cmdline_args" ).value< QString >();
1757}
1758
1759void
1760TomahawkSettings::setVlcArguments( const QString& args )
1761{
1762    setValue( "vlc/cmdline_args", args);
1763}
1764