PageRenderTime 118ms CodeModel.GetById 17ms app.highlight 91ms RepoModel.GetById 1ms app.codeStats 1ms

/src/tomahawkwindow.cpp

http://github.com/tomahawk-player/tomahawk
C++ | 1346 lines | 1049 code | 237 blank | 60 comment | 74 complexity | 60eb4ffa9d58b54ca70a52ffa77b94b2 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-2012, Leo Franchi <lfranchi@kde.org>
   5 *   Copyright 2010-2012, Jeff Mitchell <jeff@tomahawk-player.org>
   6 *   Copyright 2012,      Teo Mrnjavac <teo@kde.org>
   7 *
   8 *   Tomahawk is free software: you can redistribute it and/or modify
   9 *   it under the terms of the GNU General Public License as published by
  10 *   the Free Software Foundation, either version 3 of the License, or
  11 *   (at your option) any later version.
  12 *
  13 *   Tomahawk is distributed in the hope that it will be useful,
  14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16 *   GNU General Public License for more details.
  17 *
  18 *   You should have received a copy of the GNU General Public License
  19 *   along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
  20 */
  21
  22#include "TomahawkWindow.h"
  23#include "ui_TomahawkWindow.h"
  24
  25#include "accounts/AccountManager.h"
  26#include "sourcetree/SourceTreeView.h"
  27#include "network/Servent.h"
  28#include "utils/TomahawkUtilsGui.h"
  29#include "utils/ProxyStyle.h"
  30#include "utils/WidgetDragFilter.h"
  31#include "widgets/AccountsToolButton.h"
  32#include "widgets/AnimatedSplitter.h"
  33#include "widgets/NewPlaylistWidget.h"
  34#include "widgets/SearchWidget.h"
  35#include "widgets/PlaylistTypeSelectorDialog.h"
  36#include "thirdparty/Qocoa/qsearchfield.h"
  37#include "playlist/dynamic/GeneratorInterface.h"
  38#include "playlist/PlaylistModel.h"
  39#include "playlist/PlaylistView.h"
  40#include "playlist/QueueView.h"
  41#include "jobview/JobStatusView.h"
  42#include "jobview/JobStatusModel.h"
  43#include "jobview/ErrorStatusMessage.h"
  44#include "jobview/JobStatusModel.h"
  45#include "sip/SipPlugin.h"
  46
  47#include "Playlist.h"
  48#include "Query.h"
  49#include "Artist.h"
  50#include "ViewManager.h"
  51#include "ActionCollection.h"
  52#include "AudioControls.h"
  53#include "SettingsDialog.h"
  54#include "DiagnosticsDialog.h"
  55#include "TomahawkSettings.h"
  56#include "SourceList.h"
  57#include "TomahawkTrayIcon.h"
  58#include "libtomahawk/filemetadata/ScanManager.h"
  59#include "TomahawkApp.h"
  60#include "LoadXSPFDialog.h"
  61#include "widgets/ContainedMenuButton.h"
  62#include "utils/Logger.h"
  63
  64#include "config.h"
  65
  66#include <QAction>
  67#include <QCloseEvent>
  68#include <QDesktopServices>
  69#include <QShowEvent>
  70#include <QHideEvent>
  71#include <QInputDialog>
  72#include <QPixmap>
  73#include <QPropertyAnimation>
  74#include <QLineEdit>
  75#include <QMessageBox>
  76#include <QNetworkAccessManager>
  77#include <QNetworkReply>
  78#include <QTimer>
  79#include <QToolBar>
  80#include <QToolButton>
  81
  82#if defined( Q_WS_WIN )
  83    #if defined ( WITH_QtSparkle )
  84        #include <qtsparkle/Updater>
  85    #endif
  86    #ifndef THBN_CLICKED
  87        #define THBN_CLICKED    0x1800
  88    #endif
  89#endif
  90
  91using namespace Tomahawk;
  92using namespace Accounts;
  93
  94
  95TomahawkWindow::TomahawkWindow( QWidget* parent )
  96    : QMainWindow( parent )
  97#ifdef Q_OS_WIN
  98    , m_buttonCreatedID( RegisterWindowMessage( L"TaskbarButtonCreated" ) )
  99  #ifdef HAVE_THUMBBUTTON
 100    , m_taskbarList( 0 )
 101  #endif
 102#endif
 103    , ui( new Ui::TomahawkWindow )
 104    , m_searchWidget( 0 )
 105    , m_audioControls( new AudioControls( this ) )
 106    , m_trayIcon( new TomahawkTrayIcon( this ) )
 107    , m_settingsDialog( 0 )
 108    , m_audioRetryCounter( 0 )
 109{
 110    setWindowIcon( QIcon( RESPATH "icons/tomahawk-icon-128x128.png" ) );
 111
 112    ViewManager* vm = new ViewManager( this );
 113    connect( vm, SIGNAL( showQueueRequested() ), SLOT( showQueue() ) );
 114    connect( vm, SIGNAL( hideQueueRequested() ), SLOT( hideQueue() ) );
 115    connect( APP, SIGNAL( tomahawkLoaded() ), vm, SLOT( setTomahawkLoaded() ) ); // Pass loaded signal into libtomahawk so components in there can connect to ViewManager
 116
 117#ifdef Q_OS_WIN
 118    connect( AudioEngine::instance(), SIGNAL( stateChanged( AudioState, AudioState) ), SLOT( audioStateChanged( AudioState, AudioState) ) );
 119#endif
 120    ui->setupUi( this );
 121
 122    applyPlatformTweaks();
 123
 124    ui->centralWidget->setContentsMargins( 0, 0, 0, 0 );
 125    TomahawkUtils::unmarginLayout( ui->centralWidget->layout() );
 126
 127    setupMenuBar();
 128    setupToolBar();
 129    setupSideBar();
 130    statusBar()->addPermanentWidget( m_audioControls, 1 );
 131
 132    setupUpdateCheck();
 133    loadSettings();
 134    setupSignals();
 135
 136    if ( qApp->arguments().contains( "--debug" ) )
 137    {
 138        connect( ActionCollection::instance()->getAction( "crashNow" ), SIGNAL( triggered() ),
 139                 this, SLOT( crashNow() ) );
 140    }
 141
 142    // set initial state
 143    audioStopped();
 144
 145    vm->setQueue( m_queueView );
 146    vm->showWelcomePage();
 147}
 148
 149
 150TomahawkWindow::~TomahawkWindow()
 151{
 152    saveSettings();
 153    delete ui;
 154}
 155
 156
 157void
 158TomahawkWindow::loadSettings()
 159{
 160    TomahawkSettings* s = TomahawkSettings::instance();
 161
 162    // Workaround for broken window geometry restoring on Qt Cocoa when setUnifiedTitleAndToolBarOnMac is true.
 163    // See http://bugreports.qt.nokia.com/browse/QTBUG-3116 and
 164    // http://lists.qt.nokia.com/pipermail/qt-interest/2009-August/011491.html
 165    // for the 'fix'
 166#ifdef QT_MAC_USE_COCOA
 167     bool workaround = isVisible();
 168     if ( workaround )
 169     {
 170       // make "invisible"
 171       setWindowOpacity( 0 );
 172       // let Qt update its frameStruts
 173       show();
 174     }
 175#endif
 176
 177    if ( !s->mainWindowGeometry().isEmpty() )
 178        restoreGeometry( s->mainWindowGeometry() );
 179    if ( !s->mainWindowState().isEmpty() )
 180        restoreState( s->mainWindowState() );
 181    if ( !s->mainWindowSplitterState().isEmpty() )
 182        ui->splitter->restoreState( s->mainWindowSplitterState() );
 183
 184    // Always set stretch factor. If user hasn't manually set splitter sizes,
 185    // this will ensure a sane default on all startups. If the user has, the manual
 186    // size will override the default stretching
 187    ui->splitter->setStretchFactor( 0, 0 );
 188    ui->splitter->setStretchFactor( 1, 1 );
 189
 190#ifdef QT_MAC_USE_COCOA
 191     if ( workaround )
 192     {
 193       // Make it visible again
 194       setWindowOpacity( 1 );
 195     }
 196#endif
 197
 198#ifndef Q_OS_MAC
 199    bool mbVisible = s->menuBarVisible();
 200    menuBar()->setVisible( mbVisible );
 201    m_compactMenuAction->setVisible( !mbVisible );
 202    ActionCollection::instance()->getAction( "toggleMenuBar" )->setText( mbVisible ? tr( "Hide Menu Bar" ) : tr( "Show Menu Bar" ) );
 203#endif
 204}
 205
 206
 207void
 208TomahawkWindow::saveSettings()
 209{
 210    TomahawkSettings* s = TomahawkSettings::instance();
 211    s->setMainWindowGeometry( saveGeometry() );
 212    s->setMainWindowState( saveState() );
 213    s->setMainWindowSplitterState( ui->splitter->saveState() );
 214    s->setMenuBarVisible( menuBar()->isVisible() );
 215}
 216
 217
 218void
 219TomahawkWindow::applyPlatformTweaks()
 220{
 221    // HACK: QtCurve causes an infinite loop on startup. This is because
 222    //       setStyle calls setPalette, which calls ensureBaseStyle, which loads
 223    //       QtCurve. QtCurve calls setPalette, which creates an infinite loop.
 224    //       We could simply not use ProxyStyle under QtCurve, but that would
 225    //       make the whole UI look like crap.
 226    //       Instead, we tell ProxyStyle that it's running under QtCurve, so it
 227    //       can intercept QStyle::polish (which in the base implementation does
 228    //       nothing and in QtCurve does evil things), and avoid forwarding it
 229    //       to QtCurve.
 230    bool isQtCurve = false;
 231    if( QString( qApp->style()->metaObject()->className() ).toLower().contains( "qtcurve" ) )
 232        isQtCurve = true;
 233    qApp->setStyle( new ProxyStyle( isQtCurve ) );
 234
 235#ifdef Q_OS_MAC
 236    setUnifiedTitleAndToolBarOnMac( true );
 237    delete ui->hline1;
 238    delete ui->hline2;
 239#else
 240    ui->hline1->setStyleSheet( "border: 1px solid gray;" );
 241    ui->hline2->setStyleSheet( "border: 1px solid gray;" );
 242#endif
 243}
 244
 245
 246void
 247TomahawkWindow::setupToolBar()
 248{
 249    m_toolbar = addToolBar( "TomahawkToolbar" );
 250    m_toolbar->setObjectName( "TomahawkToolbar" );
 251    m_toolbar->setMovable( false );
 252    m_toolbar->setFloatable( false );
 253    m_toolbar->setIconSize( QSize( 22, 22 ) );
 254    m_toolbar->setToolButtonStyle( Qt::ToolButtonIconOnly );
 255    m_toolbar->setStyleSheet( "border-bottom: 0px" );
 256    // If the toolbar is hidden accidentally it causes trouble on Unity because the user can't
 257    // easily bring it back (TWK-1046). So we just prevent the user from hiding the toolbar.
 258    // This should not affect Mac users.
 259    m_toolbar->setContextMenuPolicy( Qt::PreventContextMenu );
 260
 261#ifdef Q_OS_MAC
 262    m_toolbar->installEventFilter( new WidgetDragFilter( m_toolbar ) );
 263#endif
 264
 265    m_backAction = m_toolbar->addAction( QIcon( RESPATH "images/back.png" ), tr( "Back" ), ViewManager::instance(), SLOT( historyBack() ) );
 266    m_backAction->setToolTip( tr( "Go back one page" ) );
 267    m_forwardAction = m_toolbar->addAction( QIcon( RESPATH "images/forward.png" ), tr( "Forward" ), ViewManager::instance(), SLOT( historyForward() ) );
 268    m_forwardAction->setToolTip( tr( "Go forward one page" ) );
 269
 270    m_toolbarLeftBalancer = new QWidget( this );
 271    m_toolbarLeftBalancer->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Preferred );
 272    m_toolbarLeftBalancer->setFixedWidth( 0 );
 273    m_toolbar->addWidget( m_toolbarLeftBalancer )->setProperty( "kind", QString( "spacer" ) );
 274
 275    QWidget* toolbarLeftSpacer = new QWidget( this );
 276    toolbarLeftSpacer->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred );
 277    m_toolbar->addWidget( toolbarLeftSpacer )->setProperty( "kind", QString( "spacer" ) );
 278
 279    m_searchWidget = new QSearchField( this );
 280    m_searchWidget->setPlaceholderText( tr( "Global Search..." ) );
 281    m_searchWidget->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Preferred );
 282    m_searchWidget->setFixedWidth( 340 );
 283    connect( m_searchWidget, SIGNAL( returnPressed() ), this, SLOT( onFilterEdited() ) );
 284
 285    m_toolbar->addWidget( m_searchWidget )->setProperty( "kind", QString( "search" ) );
 286
 287    QWidget* rightSpacer = new QWidget( this );
 288    rightSpacer->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred );
 289    m_toolbar->addWidget( rightSpacer )->setProperty( "kind", QString( "spacer" ) );
 290
 291    m_toolbarRightBalancer = new QWidget( this );
 292    m_toolbarRightBalancer->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Preferred );
 293    m_toolbarRightBalancer->setFixedWidth( 0 );
 294    m_toolbar->addWidget( m_toolbarRightBalancer )->setProperty( "kind", QString( "spacer" ) );
 295
 296    m_accountsButton = new AccountsToolButton( m_toolbar );
 297    m_toolbar->addWidget( m_accountsButton );
 298    connect( m_accountsButton, SIGNAL( widthChanged() ),
 299             this, SLOT( balanceToolbar() ) );
 300
 301#ifndef Q_OS_MAC
 302    ContainedMenuButton* compactMenuButton = new ContainedMenuButton( m_toolbar );
 303    compactMenuButton->setIcon( QIcon( RESPATH "images/configure.png" ) );
 304    compactMenuButton->setText( tr( "&Main Menu" ) );
 305    compactMenuButton->setMenu( m_compactMainMenu );
 306    compactMenuButton->setToolButtonStyle( Qt::ToolButtonIconOnly );
 307    m_compactMenuAction = m_toolbar->addWidget( compactMenuButton );
 308    //HACK: adding the toggle action to the window, otherwise the shortcut keys
 309    //      won't be picked up when the menu is hidden.
 310    //      This must be done for all menu bar actions that have shortcut keys :(
 311    //      Does not apply to Mac which always shows the menu bar.
 312    addAction( ActionCollection::instance()->getAction( "playPause" ) );
 313    addAction( ActionCollection::instance()->getAction( "toggleMenuBar" ) );
 314    addAction( ActionCollection::instance()->getAction( "quit" ) );
 315#endif
 316    balanceToolbar();
 317}
 318
 319
 320void
 321TomahawkWindow::balanceToolbar()
 322{
 323    int leftActionsWidth = 0;
 324    int rightActionsWidth = 0;
 325    bool flip = false;
 326    foreach ( QAction* action, m_toolbar->actions() )
 327    {
 328        if ( action->property( "kind" ) == QString( "spacer" ) ||
 329            !action->isVisible() )
 330            continue;
 331        else if ( action->property( "kind" ) == QString( "search" ) )
 332        {
 333            flip = true;
 334            continue;
 335        }
 336
 337        QWidget* widget = m_toolbar->widgetForAction( action );
 338
 339        if ( !flip ) //we accumulate on the left
 340        {
 341            leftActionsWidth += widget->sizeHint().width()
 342                             +  m_toolbar->layout()->spacing();
 343        }
 344        else //then, on the right
 345        {
 346            rightActionsWidth += widget->sizeHint().width()
 347                              +  m_toolbar->layout()->spacing();
 348        }
 349    }
 350
 351    if ( leftActionsWidth > rightActionsWidth )
 352    {
 353        m_toolbarLeftBalancer->setFixedWidth( 0 );
 354        m_toolbarRightBalancer->setFixedWidth( leftActionsWidth - rightActionsWidth );
 355    }
 356    else
 357    {
 358        m_toolbarLeftBalancer->setFixedWidth( rightActionsWidth - leftActionsWidth );
 359        m_toolbarRightBalancer->setFixedWidth( 0 );
 360    }
 361}
 362
 363
 364void
 365TomahawkWindow::setupSideBar()
 366{
 367    // Delete fake designer widgets
 368    delete ui->sidebarWidget;
 369    delete ui->playlistWidget;
 370
 371    QWidget* sidebarWidget = new QWidget();
 372    sidebarWidget->setLayout( new QVBoxLayout() );
 373
 374    m_sidebar = new AnimatedSplitter();
 375    m_sidebar->setOrientation( Qt::Vertical );
 376    m_sidebar->setChildrenCollapsible( false );
 377
 378    m_sourcetree = new SourceTreeView( this );
 379    JobStatusView* jobsView = new JobStatusView( m_sidebar );
 380    JobStatusModel* sourceModel = new JobStatusModel( jobsView );
 381    m_jobsModel = new JobStatusSortModel( jobsView );
 382    m_jobsModel->setJobModel( sourceModel );
 383    jobsView->setModel( m_jobsModel );
 384
 385    m_queueView = new QueueView( m_sidebar );
 386    AudioEngine::instance()->setQueue( m_queueView->queue()->proxyModel()->playlistInterface() );
 387
 388    m_sidebar->addWidget( m_sourcetree );
 389    m_sidebar->addWidget( jobsView );
 390    m_sidebar->addWidget( m_queueView );
 391
 392//    m_sidebar->setGreedyWidget( 1 );
 393    m_sidebar->hide( 1, false );
 394    m_sidebar->hide( 2, false );
 395    m_sidebar->hide( 3, false );
 396
 397    sidebarWidget->layout()->addWidget( m_sidebar );
 398    sidebarWidget->setContentsMargins( 0, 0, 0, 0 );
 399    sidebarWidget->layout()->setContentsMargins( 0, 0, 0, 0 );
 400    sidebarWidget->layout()->setMargin( 0 );
 401
 402#ifndef Q_OS_MAC
 403    sidebarWidget->layout()->setSpacing( 0 );
 404#endif
 405
 406    ui->splitter->addWidget( sidebarWidget );
 407    ui->splitter->addWidget( ViewManager::instance()->widget() );
 408    ui->splitter->setCollapsible( 1, false );
 409
 410    ActionCollection::instance()->getAction( "showOfflineSources" )
 411            ->setChecked( TomahawkSettings::instance()->showOfflineSources() );
 412}
 413
 414
 415void
 416TomahawkWindow::setupUpdateCheck()
 417{
 418#if defined( Q_OS_MAC ) && defined( HAVE_SPARKLE )
 419    connect( ActionCollection::instance()->getAction( "checkForUpdates" ), SIGNAL( triggered( bool ) ),
 420             SLOT( checkForUpdates() ) );
 421    #elif defined( Q_WS_WIN ) && defined( WITH_QtSparkle )
 422    QUrl updaterUrl;
 423
 424    if ( qApp->arguments().contains( "--debug" ) )
 425        updaterUrl.setUrl( "http://download.tomahawk-player.org/sparklewin-debug" );
 426    else
 427        updaterUrl.setUrl( "http://download.tomahawk-player.org/sparklewin" );
 428
 429    qtsparkle::Updater* updater = new qtsparkle::Updater( updaterUrl, this );
 430    Q_ASSERT( TomahawkUtils::nam() != 0 );
 431    updater->SetNetworkAccessManager( TomahawkUtils::nam() );
 432    updater->SetVersion( TomahawkUtils::appFriendlyVersion() );
 433
 434    connect( ActionCollection::instance()->getAction( "checkForUpdates" ), SIGNAL( triggered() ),
 435             updater, SLOT( CheckNow() ) );
 436#endif
 437}
 438
 439
 440#ifdef Q_OS_WIN
 441bool
 442TomahawkWindow::setupWindowsButtons()
 443{
 444#ifdef HAVE_THUMBBUTTON
 445    const GUID IID_ITaskbarList3 = { 0xea1afb91,0x9e28,0x4b86, { 0x90,0xe9,0x9e,0x9f,0x8a,0x5e,0xef,0xaf } };
 446    HRESULT hr = S_OK;
 447
 448    QPixmap play( RESPATH "images/play-rest.png" );
 449    QPixmap back( RESPATH "images/back-rest.png" );
 450    QPixmap love( RESPATH "images/not-loved.png" );
 451
 452    QTransform transform;
 453    transform.rotate( 180 );
 454    QPixmap next( back.transformed( transform ) );
 455
 456    THUMBBUTTONMASK dwMask = THUMBBUTTONMASK( THB_ICON | THB_TOOLTIP | THB_FLAGS );
 457    m_thumbButtons[TP_PREVIOUS].dwMask = dwMask;
 458    m_thumbButtons[TP_PREVIOUS].iId = TP_PREVIOUS;
 459    m_thumbButtons[TP_PREVIOUS].hIcon = back.toWinHICON();
 460    m_thumbButtons[TP_PREVIOUS].dwFlags = THBF_ENABLED;
 461    m_thumbButtons[TP_PREVIOUS].szTip[ tr( "Back" ).toWCharArray( m_thumbButtons[TP_PREVIOUS].szTip ) ] = 0;
 462
 463    m_thumbButtons[TP_PLAY_PAUSE].dwMask = dwMask;
 464    m_thumbButtons[TP_PLAY_PAUSE].iId = TP_PLAY_PAUSE;
 465    m_thumbButtons[TP_PLAY_PAUSE].hIcon = play.toWinHICON();
 466    m_thumbButtons[TP_PLAY_PAUSE].dwFlags = THBF_ENABLED;
 467    m_thumbButtons[TP_PLAY_PAUSE].szTip[ tr( "Play" ).toWCharArray( m_thumbButtons[TP_PLAY_PAUSE].szTip ) ] = 0;
 468
 469    m_thumbButtons[TP_NEXT].dwMask = dwMask;
 470    m_thumbButtons[TP_NEXT].iId = TP_NEXT;
 471    m_thumbButtons[TP_NEXT].hIcon = next.toWinHICON();
 472    m_thumbButtons[TP_NEXT].dwFlags = THBF_ENABLED;
 473    m_thumbButtons[TP_NEXT].szTip[ tr( "Next" ).toWCharArray( m_thumbButtons[TP_NEXT].szTip ) ] = 0;
 474
 475    m_thumbButtons[3].dwMask = dwMask;
 476    m_thumbButtons[3].iId = -1;
 477    m_thumbButtons[3].hIcon = 0;
 478    m_thumbButtons[3].dwFlags = THBF_NOBACKGROUND | THBF_DISABLED;
 479    m_thumbButtons[3].szTip[0] = 0;
 480
 481    m_thumbButtons[TP_LOVE].dwMask = dwMask;
 482    m_thumbButtons[TP_LOVE].iId = TP_LOVE;
 483    m_thumbButtons[TP_LOVE].hIcon = love.toWinHICON();
 484    m_thumbButtons[TP_LOVE].dwFlags = THBF_DISABLED;
 485    m_thumbButtons[TP_LOVE].szTip[ tr( "Love" ).toWCharArray( m_thumbButtons[TP_LOVE].szTip ) ] = 0;
 486
 487    if ( S_OK == CoCreateInstance( CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_ITaskbarList3, (void **)&m_taskbarList ) )
 488    {
 489        hr = m_taskbarList->HrInit();
 490        if ( SUCCEEDED( hr ) )
 491        {
 492            hr = m_taskbarList->ThumbBarAddButtons( winId(), ARRAYSIZE( m_thumbButtons ), m_thumbButtons );
 493        }
 494        else
 495        {
 496            m_taskbarList->Release();
 497            m_taskbarList = 0;
 498        }
 499    }
 500
 501    return SUCCEEDED( hr );
 502#else // HAVE_THUMBBUTTON
 503    return false;
 504#endif
 505}
 506#endif
 507
 508
 509void
 510TomahawkWindow::setupSignals()
 511{
 512    // <From PlaylistManager>
 513    connect( ViewManager::instance(), SIGNAL( repeatModeChanged( Tomahawk::PlaylistModes::RepeatMode ) ),
 514             m_audioControls,           SLOT( onRepeatModeChanged( Tomahawk::PlaylistModes::RepeatMode ) ) );
 515    connect( ViewManager::instance(), SIGNAL( shuffleModeChanged( bool ) ),
 516             m_audioControls,           SLOT( onShuffleModeChanged( bool ) ) );
 517
 518    // <From AudioEngine>
 519    connect( AudioEngine::instance(), SIGNAL( error( AudioEngine::AudioErrorCode ) ), SLOT( onAudioEngineError( AudioEngine::AudioErrorCode ) ) );
 520    connect( AudioEngine::instance(), SIGNAL( loading( const Tomahawk::result_ptr& ) ), SLOT( onPlaybackLoading( const Tomahawk::result_ptr& ) ) );
 521    connect( AudioEngine::instance(), SIGNAL( started( Tomahawk::result_ptr ) ), SLOT( audioStarted() ) );
 522    connect( AudioEngine::instance(), SIGNAL( finished(Tomahawk::result_ptr) ), SLOT( audioFinished() ) );
 523    connect( AudioEngine::instance(), SIGNAL( resumed()), SLOT( audioStarted() ) );
 524    connect( AudioEngine::instance(), SIGNAL( paused() ), SLOT( audioPaused() ) );
 525    connect( AudioEngine::instance(), SIGNAL( stopped() ), SLOT( audioStopped() ) );
 526
 527    // <Menu Items>
 528    ActionCollection *ac = ActionCollection::instance();
 529    //    connect( ui->actionAddPeerManually, SIGNAL( triggered() ), SLOT( addPeerManually() ) );
 530    connect( ac->getAction( "preferences" ), SIGNAL( triggered() ), SLOT( showSettingsDialog() ) );
 531    connect( ac->getAction( "diagnostics" ), SIGNAL( triggered() ), SLOT( showDiagnosticsDialog() ) );
 532    connect( ac->getAction( "legalInfo" ), SIGNAL( triggered() ), SLOT( legalInfo() ) );
 533    connect( ac->getAction( "updateCollection" ), SIGNAL( triggered() ), SLOT( updateCollectionManually() ) );
 534    connect( ac->getAction( "rescanCollection" ), SIGNAL( triggered() ), SLOT( rescanCollectionManually() ) );
 535    connect( ac->getAction( "loadXSPF" ), SIGNAL( triggered() ), SLOT( loadSpiff() ));
 536    connect( ac->getAction( "aboutTomahawk" ), SIGNAL( triggered() ), SLOT( showAboutTomahawk() ) );
 537    connect( ac->getAction( "quit" ), SIGNAL( triggered() ), qApp, SLOT( quit() ) );
 538    connect( ac->getAction( "showOfflineSources" ), SIGNAL( triggered() ), SLOT( showOfflineSources() ) );
 539
 540#if defined( Q_OS_MAC )
 541    connect( ac->getAction( "minimize" ), SIGNAL( triggered() ), SLOT( minimize() ) );
 542    connect( ac->getAction( "zoom" ), SIGNAL( triggered() ), SLOT( maximize() ) );
 543#else
 544    connect( ac->getAction( "toggleMenuBar" ), SIGNAL( triggered() ), SLOT( toggleMenuBar() ) );
 545#endif
 546
 547    // <AccountHandler>
 548    connect( AccountManager::instance(), SIGNAL( authError( Tomahawk::Accounts::Account* ) ), SLOT( onAccountError() ) );
 549
 550    connect( ViewManager::instance(), SIGNAL( historyBackAvailable( bool ) ), SLOT( onHistoryBackAvailable( bool ) ) );
 551    connect( ViewManager::instance(), SIGNAL( historyForwardAvailable( bool ) ), SLOT( onHistoryForwardAvailable( bool ) ) );
 552}
 553
 554
 555void
 556TomahawkWindow::setupMenuBar()
 557{
 558    // Always create a menubar, but only create a compactMenu on Windows and X11
 559    m_menuBar = ActionCollection::instance()->createMenuBar( this );
 560    setMenuBar( m_menuBar );
 561#ifndef Q_OS_MAC
 562    m_compactMainMenu = ActionCollection::instance()->createCompactMenu( this );
 563#endif
 564}
 565
 566void
 567TomahawkWindow::changeEvent( QEvent* e )
 568{
 569    QMainWindow::changeEvent( e );
 570
 571    switch ( e->type() )
 572    {
 573        case QEvent::LanguageChange:
 574            ui->retranslateUi( this );
 575            break;
 576
 577        default:
 578            break;
 579    }
 580}
 581
 582
 583void
 584TomahawkWindow::closeEvent( QCloseEvent* e )
 585{
 586#ifndef Q_OS_MAC
 587    if ( e->spontaneous() && QSystemTrayIcon::isSystemTrayAvailable() )
 588    {
 589        hide();
 590        e->ignore();
 591        return;
 592    }
 593#else
 594    m_trayIcon->setShowHideWindow( false );
 595#endif
 596
 597    e->accept();
 598}
 599
 600
 601void
 602TomahawkWindow::showEvent( QShowEvent* e )
 603{
 604    QMainWindow::showEvent( e );
 605
 606#if defined( Q_OS_MAC )
 607    ActionCollection::instance()->getAction( "minimize" )->setDisabled( false );
 608    ActionCollection::instance()->getAction( "zoom" )->setDisabled( false );
 609#endif
 610}
 611
 612
 613void
 614TomahawkWindow::hideEvent( QHideEvent* e )
 615{
 616    QMainWindow::hideEvent( e );
 617
 618#if defined( Q_OS_MAC )
 619    ActionCollection::instance()->getAction( "minimize" )->setDisabled( true );
 620    ActionCollection::instance()->getAction( "zoom" )->setDisabled( true );
 621#endif
 622}
 623
 624
 625void
 626TomahawkWindow::keyPressEvent( QKeyEvent* e )
 627{
 628    bool accept = true;
 629
 630#if ! defined ( Q_OS_MAC )
 631#define KEY_PRESSED Q_FUNC_INFO << "Multimedia Key Pressed:"
 632    switch( e->key() )
 633    {
 634        case Qt::Key_MediaPlay:
 635            tLog() << KEY_PRESSED << "Play";
 636            AudioEngine::instance()->playPause();
 637            break;
 638        case Qt::Key_MediaStop:
 639            tLog() << KEY_PRESSED << "Stop";
 640            AudioEngine::instance()->stop();
 641            break;
 642        case Qt::Key_MediaPrevious:
 643            tLog() << KEY_PRESSED << "Previous";
 644            AudioEngine::instance()->previous();
 645            break;
 646        case Qt::Key_MediaNext:
 647            tLog() << KEY_PRESSED << "Next";
 648            AudioEngine::instance()->next();
 649            break;
 650        case Qt::Key_MediaPause:
 651            tLog() << KEY_PRESSED << "Pause";
 652            AudioEngine::instance()->pause();
 653            break;
 654        case Qt::Key_MediaTogglePlayPause:
 655            tLog() << KEY_PRESSED << "PlayPause";
 656            AudioEngine::instance()->playPause();
 657            break;
 658        case Qt::Key_MediaRecord:
 659        default:
 660            accept = false;
 661    }
 662#else
 663    accept = false;
 664#endif
 665
 666    if ( accept )
 667        e->accept();
 668
 669    QMainWindow::keyPressEvent( e );
 670}
 671
 672
 673#ifdef Q_OS_WIN
 674bool
 675TomahawkWindow::winEvent( MSG* msg, long* result )
 676{
 677    #define TB_PRESSED Q_FUNC_INFO << "Taskbar Button Pressed:"
 678
 679    switch( msg->message )
 680    {
 681    case WM_COMMAND:
 682        if ( HIWORD( msg->wParam ) == THBN_CLICKED )
 683        {
 684            switch( TB_STATES(LOWORD( msg->wParam )) )
 685            {
 686            case TP_PREVIOUS:
 687                tLog() << TB_PRESSED << "Previous";
 688                AudioEngine::instance()->previous();
 689                break;
 690            case TP_PLAY_PAUSE:
 691                tLog() << TB_PRESSED << "Play/Pause";
 692                AudioEngine::instance()->playPause();
 693                break;
 694            case TP_NEXT:
 695                tLog() << TB_PRESSED << "Next";
 696                AudioEngine::instance()->next();
 697                break;
 698            case TP_LOVE:
 699                tLog() << TB_PRESSED << "Love";
 700                if ( !AudioEngine::instance()->currentTrack().isNull() )
 701                {
 702                    AudioEngine::instance()->currentTrack()->toQuery()->setLoved( !AudioEngine::instance()->currentTrack()->toQuery()->loved() );
 703                    updateWindowsLoveButton();
 704                }
 705                break;
 706            }
 707            return true;
 708        }
 709        break;
 710    }
 711
 712    if ( msg->message == m_buttonCreatedID )
 713        return setupWindowsButtons();
 714
 715    return false;
 716}
 717
 718
 719void
 720TomahawkWindow::audioStateChanged( AudioState newState, AudioState oldState )
 721{
 722#ifdef HAVE_THUMBBUTTON
 723    if ( m_taskbarList == 0 )
 724        return;
 725
 726    switch ( newState )
 727    {
 728        case AudioEngine::Playing:
 729        {
 730            QPixmap pause( RESPATH "images/pause-rest.png" );
 731            m_thumbButtons[TP_PLAY_PAUSE].hIcon = pause.toWinHICON();
 732            m_thumbButtons[TP_PLAY_PAUSE].szTip[ tr( "Pause" ).toWCharArray( m_thumbButtons[TP_PLAY_PAUSE].szTip ) ] = 0;
 733            updateWindowsLoveButton();
 734
 735        }
 736        break;
 737
 738        case AudioEngine::Paused:
 739        {
 740            QPixmap play( RESPATH "images/play-rest.png" );
 741            m_thumbButtons[TP_PLAY_PAUSE].hIcon = play.toWinHICON();
 742            m_thumbButtons[TP_PLAY_PAUSE].szTip[ tr( "Play" ).toWCharArray( m_thumbButtons[TP_PLAY_PAUSE].szTip ) ] = 0;
 743        }
 744        break;
 745
 746        case AudioEngine::Stopped:
 747        {
 748            if ( !AudioEngine::instance()->currentTrack().isNull() )
 749            {
 750                disconnect( AudioEngine::instance()->currentTrack()->toQuery().data(), SIGNAL( socialActionsLoaded() ), this, SLOT( updateWindowsLoveButton() ) );
 751            }
 752
 753            QPixmap play( RESPATH "images/play-rest.png" );
 754            m_thumbButtons[TP_PLAY_PAUSE].hIcon = play.toWinHICON();
 755            m_thumbButtons[TP_PLAY_PAUSE].szTip[ tr( "Play" ).toWCharArray( m_thumbButtons[TP_PLAY_PAUSE].szTip ) ] = 0;
 756
 757            QPixmap not_loved( RESPATH "images/not-loved.png" );
 758            m_thumbButtons[TP_LOVE].hIcon = not_loved.toWinHICON();
 759            m_thumbButtons[TP_LOVE].dwFlags = THBF_DISABLED;
 760        }
 761        break;
 762
 763        default:
 764            return;
 765    }
 766
 767    m_taskbarList->ThumbBarUpdateButtons( winId(), ARRAYSIZE( m_thumbButtons ), m_thumbButtons );
 768#endif // HAVE_THUMBBUTTON
 769}
 770
 771
 772void
 773TomahawkWindow::updateWindowsLoveButton()
 774{
 775#ifdef HAVE_THUMBBUTTON
 776    if ( !AudioEngine::instance()->currentTrack().isNull() && AudioEngine::instance()->currentTrack()->toQuery()->loved() )
 777    {
 778        QPixmap loved( RESPATH "images/loved.png" );
 779        m_thumbButtons[TP_LOVE].hIcon = loved.toWinHICON();
 780        m_thumbButtons[TP_LOVE].szTip[ tr( "Unlove" ).toWCharArray( m_thumbButtons[TP_LOVE].szTip ) ] = 0;
 781    }
 782    else
 783    {
 784        QPixmap not_loved( RESPATH "images/not-loved.png" );
 785        m_thumbButtons[TP_LOVE].hIcon = not_loved.toWinHICON();
 786        m_thumbButtons[TP_LOVE].szTip[ tr( "Love" ).toWCharArray( m_thumbButtons[TP_LOVE].szTip ) ] = 0;
 787    }
 788
 789    m_thumbButtons[TP_LOVE].dwFlags = THBF_ENABLED;
 790    m_taskbarList->ThumbBarUpdateButtons( winId(), ARRAYSIZE( m_thumbButtons ), m_thumbButtons );
 791#endif // HAVE_THUMBBUTTON
 792}
 793
 794#endif
 795
 796
 797void
 798TomahawkWindow::onHistoryBackAvailable( bool avail )
 799{
 800    m_backAction->setEnabled( avail );
 801}
 802
 803
 804void
 805TomahawkWindow::onHistoryForwardAvailable( bool avail )
 806{
 807    m_forwardAction->setEnabled( avail );
 808}
 809
 810
 811void
 812TomahawkWindow::showSettingsDialog()
 813{
 814    if ( !m_settingsDialog )
 815        m_settingsDialog = new SettingsDialog;
 816
 817    m_settingsDialog->show();
 818}
 819
 820
 821void
 822TomahawkWindow::showDiagnosticsDialog()
 823{
 824    DiagnosticsDialog win;
 825    win.exec();
 826}
 827
 828
 829void
 830TomahawkWindow::legalInfo()
 831{
 832    QDesktopServices::openUrl( QUrl( "http://www.tomahawk-player.org/legal.html" ) );
 833}
 834
 835
 836void
 837TomahawkWindow::updateCollectionManually()
 838{
 839    if ( TomahawkSettings::instance()->hasScannerPaths() )
 840        ScanManager::instance()->runNormalScan();
 841}
 842
 843
 844void
 845TomahawkWindow::rescanCollectionManually()
 846{
 847    if ( TomahawkSettings::instance()->hasScannerPaths() )
 848        ScanManager::instance()->runFullRescan();
 849}
 850
 851
 852void
 853TomahawkWindow::addPeerManually()
 854{
 855    TomahawkSettings* s = TomahawkSettings::instance();
 856    bool ok;
 857    QString addr = QInputDialog::getText( this, tr( "Connect To Peer" ),
 858                                                tr( "Enter peer address:" ), QLineEdit::Normal,
 859                                                s->value( "connip" ).toString(), &ok ); // FIXME
 860    if ( !ok )
 861        return;
 862
 863    s->setValue( "connip", addr );
 864    QString ports = QInputDialog::getText( this, tr( "Connect To Peer" ),
 865                                                 tr( "Enter peer port:" ), QLineEdit::Normal,
 866                                                 s->value( "connport", "50210" ).toString(), &ok );
 867    if ( !ok )
 868        return;
 869
 870    s->setValue( "connport", ports );
 871    int port = ports.toInt();
 872    QString key = QInputDialog::getText( this, tr( "Connect To Peer" ),
 873                                               tr( "Enter peer key:" ), QLineEdit::Normal,
 874                                               "whitelist", &ok );
 875    if ( !ok )
 876        return;
 877
 878    qDebug() << "Attempting to connect to" << addr;
 879    Servent::instance()->connectToPeer( addr, port, key );
 880}
 881
 882
 883void
 884TomahawkWindow::showOfflineSources()
 885{
 886    m_sourcetree->showOfflineSources( ActionCollection::instance()
 887                                      ->getAction( "showOfflineSources" )->isChecked() );
 888    TomahawkSettings::instance()->setShowOfflineSources( ActionCollection::instance()
 889                                                         ->getAction( "showOfflineSources" )->isChecked() );
 890}
 891
 892
 893void
 894TomahawkWindow::fullScreenEntered()
 895{
 896    statusBar()->setSizeGripEnabled( false );
 897}
 898
 899
 900void
 901TomahawkWindow::fullScreenExited()
 902{
 903    statusBar()->setSizeGripEnabled( true );
 904}
 905
 906
 907void
 908TomahawkWindow::loadSpiff()
 909{
 910    LoadXSPFDialog* diag = new LoadXSPFDialog( this, Qt::Sheet );
 911#ifdef Q_OS_MAC
 912    connect( diag, SIGNAL( finished( int ) ), this, SLOT( loadXspfFinished( int ) ) );
 913    diag->show();
 914#else
 915    QWeakPointer< LoadXSPFDialog > safe( diag );
 916
 917    int ret = diag->exec();
 918    if ( !safe.isNull() && ret == QDialog::Accepted )
 919    {
 920        QUrl url = QUrl::fromUserInput( safe.data()->xspfUrl() );
 921        bool autoUpdate = safe.data()->autoUpdate();
 922
 923        XSPFLoader* loader = new XSPFLoader( true, autoUpdate );
 924        connect( loader, SIGNAL( error( XSPFLoader::XSPFErrorCode ) ), SLOT( onXSPFError( XSPFLoader::XSPFErrorCode ) ) );
 925        connect( loader, SIGNAL( ok( Tomahawk::playlist_ptr ) ), SLOT( onXSPFOk( Tomahawk::playlist_ptr ) ) );
 926        loader->load( url );
 927    }
 928#endif
 929}
 930
 931
 932void
 933TomahawkWindow::loadXspfFinished( int ret )
 934{
 935    LoadXSPFDialog* d = qobject_cast< LoadXSPFDialog* >( sender() );
 936    Q_ASSERT( d );
 937    if ( ret == QDialog::Accepted )
 938    {
 939        QUrl url = QUrl::fromUserInput( d->xspfUrl() );
 940        bool autoUpdate = d->autoUpdate();
 941
 942        XSPFLoader* loader = new XSPFLoader( true, autoUpdate );
 943        connect( loader, SIGNAL( error( XSPFLoader::XSPFErrorCode ) ), SLOT( onXSPFError( XSPFLoader::XSPFErrorCode ) ) );
 944        connect( loader, SIGNAL( ok( Tomahawk::playlist_ptr ) ), SLOT( onXSPFOk( Tomahawk::playlist_ptr ) ) );
 945        loader->load( url );
 946    }
 947    d->deleteLater();
 948}
 949
 950
 951void
 952TomahawkWindow::onXSPFOk( const Tomahawk::playlist_ptr& pl )
 953{
 954    ViewManager::instance()->show( pl );
 955}
 956
 957
 958void
 959TomahawkWindow::onXSPFError( XSPFLoader::XSPFErrorCode error )
 960{
 961    switch ( error )
 962    {
 963        case XSPFLoader::ParseError:
 964            QMessageBox::critical( this, tr( "XSPF Error" ), tr( "This is not a valid XSPF playlist." ) );
 965            break;
 966
 967        case XSPFLoader::InvalidTrackError:
 968            QMessageBox::warning( this, tr( "Failed to save tracks" ), tr( "Some tracks in the playlist do not contain an artist and a title. They will be ignored." ), QMessageBox::Ok );
 969            break;
 970        default:
 971            //FIXME: This includes FetchError
 972            break;
 973    }
 974}
 975
 976
 977void
 978TomahawkWindow::onAudioEngineError( AudioEngine::AudioErrorCode /* error */ )
 979{
 980    QString msg;
 981#ifdef Q_WS_X11
 982    msg = tr( "Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed." );
 983#else
 984    msg = tr( "Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped." );
 985#endif
 986    JobStatusView::instance()->model()->addJob( new ErrorStatusMessage( msg, 15 ) );
 987
 988    if ( m_audioRetryCounter < 3 )
 989        AudioEngine::instance()->play();
 990    m_audioRetryCounter++;
 991}
 992
 993
 994void
 995TomahawkWindow::createAutomaticPlaylist( QString playlistName )
 996{
 997    if ( playlistName.isEmpty() )
 998        return;
 999
1000    source_ptr author = SourceList::instance()->getLocal();
1001    QString id = uuid();
1002    QString info  = ""; // FIXME
1003    QString creator = "someone"; // FIXME
1004
1005    dynplaylist_ptr playlist = DynamicPlaylist::create( author, id, playlistName, info, creator, Static, false );
1006    playlist->setMode( Static );
1007    playlist->createNewRevision( uuid(), playlist->currentrevision(), playlist->type(), playlist->generator()->controls(), playlist->entries() );
1008
1009    ViewManager::instance()->show( playlist );
1010}
1011
1012
1013void
1014TomahawkWindow::createStation()
1015{
1016    QString title = tr( "Station" );
1017    bool ok;
1018    QString playlistName = QInputDialog( this, Qt::Sheet ).getText( this, tr( "Create New Station" ), tr( "Name:" ), QLineEdit::Normal, title, &ok );
1019    if ( !ok )
1020        return;
1021
1022    if ( playlistName.isEmpty() || playlistName == title )
1023    {
1024        QList< dynplaylist_ptr > pls = SourceList::instance()->getLocal()->collection()->stations();
1025        QStringList titles;
1026        foreach ( const playlist_ptr& pl, pls )
1027            titles << pl->title();
1028
1029        playlistName = title;
1030        int i = 2;
1031        while ( titles.contains( playlistName ) )
1032        {
1033            playlistName = QString( "%1 (%2)" ).arg( title ).arg( i++ );
1034        }
1035    }
1036
1037    source_ptr author = SourceList::instance()->getLocal();
1038    QString id = uuid();
1039    QString info  = ""; // FIXME
1040    QString creator = "someone"; // FIXME
1041
1042    dynplaylist_ptr playlist = DynamicPlaylist::create( author, id, playlistName, info, creator, OnDemand, false );
1043    playlist->setMode( OnDemand );
1044    playlist->createNewRevision( uuid(), playlist->currentrevision(), playlist->type(), playlist->generator()->controls() );
1045
1046    ViewManager::instance()->show( playlist );
1047}
1048
1049
1050void
1051TomahawkWindow::createPlaylist()
1052{
1053    PlaylistTypeSelectorDlg* playlistSelectorDlg = new PlaylistTypeSelectorDlg( TomahawkApp::instance()->mainWindow(), Qt::Sheet );
1054
1055#ifndef Q_OS_MAC
1056    playlistSelectorDlg->setModal( true );
1057#endif
1058
1059    connect( playlistSelectorDlg, SIGNAL( finished( int ) ), SLOT( playlistCreateDialogFinished( int ) ) );
1060    playlistSelectorDlg->show();
1061}
1062
1063
1064void
1065TomahawkWindow::playlistCreateDialogFinished( int ret )
1066{
1067    PlaylistTypeSelectorDlg* playlistSelectorDlg = qobject_cast< PlaylistTypeSelectorDlg* >( sender() );
1068    Q_ASSERT( playlistSelectorDlg );
1069
1070    QString playlistName = playlistSelectorDlg->playlistName();
1071
1072    if ( !playlistSelectorDlg->playlistTypeIsAuto() && ret )
1073    {
1074        if ( playlistName.isEmpty() )
1075        {
1076            QList< playlist_ptr > pls = SourceList::instance()->getLocal()->collection()->playlists();
1077            QStringList titles;
1078            foreach ( const playlist_ptr& pl, pls )
1079                titles << pl->title();
1080
1081            QString title = tr( "Playlist" );
1082            playlistName = title;
1083            int i = 2;
1084            while ( titles.contains( playlistName ) )
1085            {
1086                playlistName = QString( "%1 (%2)" ).arg( title ).arg( i++ );
1087            }
1088        }
1089
1090        playlist_ptr playlist = Tomahawk::Playlist::create( SourceList::instance()->getLocal(), uuid(), playlistName, "", "", false, QList< query_ptr>() );
1091        ViewManager::instance()->show( playlist );
1092    }
1093    else if ( playlistSelectorDlg->playlistTypeIsAuto() && ret )
1094    {
1095       // create Auto Playlist
1096        if ( playlistName.isEmpty() )
1097        {
1098            QList< dynplaylist_ptr > pls = SourceList::instance()->getLocal()->collection()->autoPlaylists();
1099            QStringList titles;
1100            foreach ( const dynplaylist_ptr& pl, pls )
1101                titles << pl->title();
1102
1103            QString title = tr( "Automatic Playlist" );
1104            playlistName = title;
1105            int i = 2;
1106            while ( titles.contains( playlistName ) )
1107            {
1108                playlistName = QString( "%1 (%2)" ).arg( title ).arg( i++ );
1109            }
1110        }
1111
1112       createAutomaticPlaylist( playlistName );
1113    }
1114
1115    playlistSelectorDlg->deleteLater();
1116}
1117
1118
1119void
1120TomahawkWindow::audioStarted()
1121{
1122    m_audioRetryCounter = 0;
1123
1124    ActionCollection::instance()->getAction( "playPause" )->setIcon( QIcon( RESPATH "images/pause-rest.png" ) );
1125    ActionCollection::instance()->getAction( "playPause" )->setText( tr( "Pause" ) );
1126    ActionCollection::instance()->getAction( "stop" )->setEnabled( true );
1127
1128#ifdef Q_OS_WIN
1129    connect( AudioEngine::instance()->currentTrack()->toQuery().data(), SIGNAL( socialActionsLoaded() ), SLOT( updateWindowsLoveButton() ) );
1130#endif
1131}
1132
1133
1134void
1135TomahawkWindow::audioFinished()
1136{
1137#ifdef Q_OS_WIN
1138    disconnect( AudioEngine::instance()->currentTrack()->toQuery().data(), SIGNAL( socialActionsLoaded() ), this, SLOT( updateWindowsLoveButton() ) );
1139#endif
1140}
1141
1142
1143void
1144TomahawkWindow::audioPaused()
1145{
1146    ActionCollection::instance()->getAction( "playPause" )->setIcon( QIcon( RESPATH "images/play-rest.png" ) );
1147    ActionCollection::instance()->getAction( "playPause" )->setText( tr( "&Play" ) );
1148}
1149
1150
1151void
1152TomahawkWindow::audioStopped()
1153{
1154    audioPaused();
1155    ActionCollection::instance()->getAction( "stop" )->setEnabled( false );
1156
1157    m_currentTrack = result_ptr();
1158    setWindowTitle( m_windowTitle );
1159}
1160
1161
1162void
1163TomahawkWindow::onPlaybackLoading( const Tomahawk::result_ptr& result )
1164{
1165    m_currentTrack = result;
1166    setWindowTitle( m_windowTitle );
1167}
1168
1169
1170void
1171TomahawkWindow::onAccountError()
1172{
1173    // TODO fix.
1174//     onAccountDisconnected();
1175
1176    // TODO real error message from plugin kthxbbq
1177    QMessageBox::warning( this,
1178                          tr( "Authentication Error" ),
1179                          tr( "Error connecting to SIP: Authentication failed!" ),
1180                          QMessageBox::Ok );
1181}
1182
1183
1184void
1185TomahawkWindow::setWindowTitle( const QString& title )
1186{
1187    m_windowTitle = title;
1188
1189    if ( m_currentTrack.isNull() )
1190        QMainWindow::setWindowTitle( title );
1191    else
1192    {
1193        QString s = tr( "%1 by %2", "track, artist name" ).arg( m_currentTrack->track(), m_currentTrack->artist()->name() );
1194        QMainWindow::setWindowTitle( tr( "%1 - %2", "current track, some window title" ).arg( s, title ) );
1195    }
1196}
1197
1198
1199void
1200TomahawkWindow::showAboutTomahawk()
1201{
1202    QString head, desc;
1203
1204#ifdef DEBUG_BUILD
1205    head = tr( "<h2><b>Tomahawk %1<br/>(%2)</h2>" )
1206         .arg( TomahawkUtils::appFriendlyVersion() )
1207         .arg( qApp->applicationVersion() );
1208#else
1209    head = tr( "<h2><b>Tomahawk %1</h2>" )
1210         .arg( TomahawkUtils::appFriendlyVersion() );
1211#endif
1212
1213    const QString copyright( tr( "Copyright 2010 - 2012" ) );
1214    const QString thanksto( tr( "Thanks to:" ) );
1215
1216    desc = QString( "%1<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>"
1217                    "%2 Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Syd Lawrence, Michael Zanetti, Harald Sitter, Steve Robertson" )
1218              .arg( copyright )
1219              .arg( thanksto );
1220
1221    QMessageBox::about( this, tr( "About Tomahawk" ), head + desc );
1222}
1223
1224
1225void
1226TomahawkWindow::checkForUpdates()
1227{
1228#ifdef Q_OS_MAC
1229    Tomahawk::checkForUpdates();
1230#endif
1231}
1232
1233
1234void
1235TomahawkWindow::onSearch( const QString& search )
1236{
1237    if ( !search.trimmed().isEmpty() )
1238        ViewManager::instance()->show( new SearchWidget( search, this ) );
1239}
1240
1241
1242void
1243TomahawkWindow::onFilterEdited()
1244{
1245    onSearch( m_searchWidget->text() );
1246    m_searchWidget->clear();
1247}
1248
1249
1250void
1251TomahawkWindow::showQueue()
1252{
1253    if ( QThread::currentThread() != thread() )
1254    {
1255        qDebug() << "Reinvoking in correct thread:" << Q_FUNC_INFO;
1256        QMetaObject::invokeMethod( this, "showQueue", Qt::QueuedConnection );
1257        return;
1258    }
1259
1260    m_queueView->show();
1261}
1262
1263
1264void
1265TomahawkWindow::hideQueue()
1266{
1267    if ( QThread::currentThread() != thread() )
1268    {
1269        qDebug() << "Reinvoking in correct thread:" << Q_FUNC_INFO;
1270        QMetaObject::invokeMethod( this, "hideQueue", Qt::QueuedConnection );
1271        return;
1272    }
1273
1274    m_queueView->hide();
1275}
1276
1277
1278void
1279TomahawkWindow::minimize()
1280{
1281    if ( isMinimized() )
1282    {
1283        showNormal();
1284    }
1285    else
1286    {
1287        showMinimized();
1288    }
1289}
1290
1291
1292void
1293TomahawkWindow::maximize()
1294{
1295    if ( isMaximized() )
1296    {
1297        showNormal();
1298    }
1299    else
1300    {
1301        showMaximized();
1302    }
1303}
1304
1305
1306void
1307TomahawkWindow::crashNow()
1308{
1309    TomahawkUtils::crash();
1310}
1311
1312
1313void
1314TomahawkWindow::toggleMenuBar() //SLOT
1315{
1316#ifndef Q_OS_MAC
1317    if( menuBar()->isVisible() )
1318    {
1319        menuBar()->setVisible( false );
1320        ActionCollection::instance()->getAction( "toggleMenuBar" )->setText( tr( "Show Menu Bar" ) );
1321        m_compactMenuAction->setVisible( true );
1322    }
1323    else
1324    {
1325        m_compactMenuAction->setVisible( false );
1326        ActionCollection::instance()->getAction( "toggleMenuBar" )->setText( tr( "Hide Menu Bar" ) );
1327        menuBar()->setVisible( true );
1328    }
1329    balanceToolbar();
1330    saveSettings();
1331#endif
1332}
1333
1334
1335AudioControls*
1336TomahawkWindow::audioControls()
1337{
1338    return m_audioControls;
1339}
1340
1341
1342SourceTreeView*
1343TomahawkWindow::sourceTreeView() const
1344{
1345    return m_sourcetree;
1346}