17
18
* You should have received a copy of the GNU General Public License *
18
19
* along with this program; if not, write to the *
19
20
* Free Software Foundation, Inc., *
20
* 51 Franklin Steet, Fifth Floor, Boston, MA 02111-1307, USA. *
21
* 51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA. *
21
22
***************************************************************************/
24
#include "container.h"
23
26
#include "aboutdialog.h"
24
27
#include "autoupdater.h"
25
#include "browserthread.h"
26
28
#include "configwizard.h"
27
29
#include "confirmdialog.h"
28
#include "container.h"
29
#include "containerutils.h"
30
#include "controlinterface.h"
30
#include "MooseCommon.h"
31
31
#include "deleteuserdialog.h"
32
#include "failedlogindialog.h"
32
33
#include "interfaces/ExtensionInterface.h"
33
34
#include "iconshack.h"
34
#include "interfaces/InputInterface.h"
35
#include "itunesscript.h"
36
#include "logindialog.h"
37
#include "macstyleoverrides.h"
38
#include "mediadevices/mediadevice.h"
35
#include "lastfmapplication.h"
36
#include "LastMessageBox.h"
38
#include "loginwidget.h"
39
#include "mediadevices/ipod/IpodDevice.h"
39
40
#include "metadata.h"
40
#include "interfaces/InputInterface.h"
41
#include "MetaDataWidget.h"
41
42
#include "playerlistener.h"
43
#include "recommenddialog.h"
44
#include "ShareDialog.h"
44
45
#include "settingsdialog.h"
46
#include "DiagnosticsDialog.h"
45
47
#include "Scrobbler-1.2.h"
48
#include "LastFmSettings.h"
49
#include "SideBarView.h"
47
50
#include "systray.h"
48
51
#include "tagdialog.h"
49
#include "interfaces/TranscodeInterface.h"
50
#include "recommenddialog.h"
51
52
#include "RestStateWidget.h"
52
53
#include "updatewizard.h"
53
55
#include "volumeslider.h"
54
56
#include "WebService.h"
55
57
#include "WebService/Request.h"
56
#include "winstyleoverrides.h"
59
#include "LastMessageBox.h"
61
#include "sidebarextension/sidebartree.h"
62
#include "searchextension/searchextension.h"
63
#include "metadataextension/metadataextension.h"
65
Container *Container::s_instance = 0;
66
static const int k_statusBarFontSizeMac = 10;
68
// Station bar grey bg colour
69
static const QColor k_stationBarGreyTop = QColor( 0xba, 0xba, 0xba, 0xff );
70
static const QColor k_stationBarGreyMiddle = QColor( 0xe2, 0xe2, 0xe2, 0xff );
71
static const QColor k_stationBarGreyBottom = QColor( 0xff, 0xff, 0xff, 0xff );
73
// Track bar blue bg colour
74
static const QColor k_trackBarBkgrBlueTop = QColor( 0xeb, 0xf0, 0xf2, 0xff );
75
static const QColor k_trackBarBkgrBlueMiddle = QColor( 0xe5, 0xe9, 0xec, 0xff );
76
static const QColor k_trackBarBkgrBlueBottom = QColor( 0xdc, 0xe2, 0xe5, 0xff );
78
// Track bar progress bar colour
79
static const QColor k_trackBarProgressTop = QColor( 0xd6, 0xde, 0xe6, 0xff );
80
static const QColor k_trackBarProgressMiddle = QColor( 0xd0, 0xd9, 0xe2, 0xff );
81
static const QColor k_trackBarProgressBottom = QColor( 0xca, 0xd4, 0xdc, 0xff );
83
// Track bar scrobbled colour
84
static const QColor k_trackBarScrobbledTop = QColor( 0xba, 0xc7, 0xd7, 0xff );
85
static const QColor k_trackBarScrobbledMiddle = QColor( 0xb8, 0xc4, 0xd5, 0xff );
86
static const QColor k_trackBarScrobbledBottom = QColor( 0xb5, 0xc1, 0xd2, 0xff );
61
#include <QCloseEvent>
62
#include <QDragMoveEvent>
63
#include <QDesktopServices>
64
#include <QFileDialog>
67
#include "winstyleoverrides.h"
69
#include "macstyleoverrides.h"
72
Container* Container::s_instance = 0;
89
75
Container::Container()
92
, m_recommendDlg( new RecommendDialog( this ) )
93
, m_userCheck( false )
94
, m_sidebarEnabled( false )
96
, m_closingDown( false )
78
m_sidebarEnabled( false ),
81
, m_styleOverrides( 0 )
98
//TODO REFACTOR! The size of this monster is scary.
100
// HACK: this is just to make sure the web service gets created as part of
101
// the main GUI thread. If we don't do this, it will get created as part
102
// of the HttpInput initialisation and then it won't work because it's
103
// done from a different thread.
106
84
s_instance = this;
108
m_iControl = new ControlInterface( this );
109
m_listener = new CPlayerListener( this );
85
m_shareDialog = new ShareDialog( this );
110
86
m_settingsDialog = new SettingsDialog( this );
87
m_diagnosticsDialog = new DiagnosticsDialog( this );
111
88
m_updater = new CAutoUpdater( this );
113
m_scrobbler = new ScrobblerManager( this );
114
connect( m_scrobbler, SIGNAL(status( int, QVariant )), SLOT(onScrobblerStatusChange( int, QVariant )) );
116
#if QT_VERSION >= 0x040300
117
setUnifiedTitleAndToolBarOnMac( true );
120
setWindowTitle( "Last.fm" ); //don't translate this!
121
m_radio = new Radio( this );
94
applyPlatformSpecificTweaks();
123
104
ui.setupUi( this );
125
setWindowIcon( QIcon( dataPath( "icons/as.png" ) ) );
127
setMinimumSize( 551, 400 );
128
setAcceptDrops( true );
130
// Start helper daemon _before_ we bind any sockets, otherwise they might
131
// end up being blocked by the child-process.
135
// don't use CTRL as that varies by platform, it is easier to have a single
136
// shortcut to tell all users
137
QObject* openL = new QShortcut( QKeySequence( "Alt+Shift+L" ), this );
138
QObject* openH = new QShortcut( QKeySequence( "Alt+Shift+H" ), this );
139
QObject* openF = new QShortcut( QKeySequence( "Alt+Shift+F" ), this );
141
connect( openL, SIGNAL(activated()), SLOT(onAltShiftL()) );
142
connect( openH, SIGNAL(activated()), SLOT(onAltShiftH()) );
143
connect( openF, SIGNAL(activated()), SLOT(onAltShiftF()) );
150
QToolBar* toolbar = ui.toolbar = addToolBar( "Last.fm" );
151
toolbar->setObjectName( "Lastfm_Main_Toolbar" );
152
toolbar->setMovable( false );
153
toolbar->setContextMenuPolicy( Qt::CustomContextMenu );
154
toolbar->setToolButtonStyle( Qt::ToolButtonTextUnderIcon );
155
#if defined( Q_WS_MAC ) && QT_VERSION >= 0x040300
156
// using unified toolbar so don't do this
158
toolbar->setAutoFillBackground( true );
162
// Can't use 32 for height as labels get truncated on Win classic
163
toolbar->setIconSize( QSize( 50, 34 ) );
165
toolbar->setIconSize( QSize( 32, 32 ) );
168
ui.actionSidebar->setShortcut( tr( "Ctrl+F" ) );
169
ui.actionSidebar->setToolTip( tr( "Show/hide my profile" ) );
171
ui.actionSidebar->setCheckable( true );
173
connect( ui.actionSidebar, SIGNAL(triggered()), SLOT(toggleSidebar()) );
175
// Copy the menu action and add the icon to it. Don't want the icon in the
176
// menu as it will obscure the tick.
177
m_sidebarActionWithIcon = new QAction( toolbar );
178
m_sidebarActionWithIcon->setIcon( QIcon( dataPath( "buttons/myprofile.png" ) ) );
179
m_sidebarActionWithIcon->setText( tr( "My Profile" ) );
180
m_sidebarActionWithIcon->setToolTip( tr( "Show/hide my profile" ) );
182
m_sidebarActionWithIcon->setCheckable( true );
184
connect( m_sidebarActionWithIcon, SIGNAL(triggered()), SLOT(toggleSidebar()) );
186
toolbar->addAction( m_sidebarActionWithIcon );
187
toolbar->addSeparator();
189
//m_recommendAction = toolbar->addAction( QIcon( dataPath( "buttons/recommend.png" ) ), tr( "Recommend" ), this, SLOT( showRecommendDialog() ) );
190
ui.actionRecommend->setIcon( QIcon( dataPath( "buttons/recommend.png" ) ) );
191
ui.actionRecommend->setShortcut( tr( "Ctrl+R" ) );
192
ui.actionRecommend->setToolTip( tr( "Share what's currently playing with someone" ) );
193
toolbar->addAction( ui.actionRecommend );
194
connect( ui.actionRecommend, SIGNAL(triggered()), SLOT(showRecommendDialog()) );
196
//m_tagAction = toolbar->addAction( QIcon( dataPath( "buttons/tag.png" ) ), tr( "Tag" ), this, SLOT( showTagDialog() ) );
197
ui.actionTag->setIcon( QIcon( dataPath( "buttons/tag.png" ) ) );
198
ui.actionTag->setShortcut( tr( "Ctrl+T" ) );
199
ui.actionTag->setToolTip( tr( "Tag what's currently playing" ) );
200
toolbar->addAction( ui.actionTag );
201
connect( ui.actionTag, SIGNAL(triggered()), SLOT(showTagDialog()) );
203
ui.actionAddToMyPlaylist->setIcon( QIcon( dataPath( "buttons/addToMyPlaylist.png" ) ) );
204
ui.actionAddToMyPlaylist->setShortcut( tr( "Ctrl+P" ) );
205
ui.actionAddToMyPlaylist->setToolTip( tr( "Add what's currently playing to your playlist" ) );
206
toolbar->addAction( ui.actionAddToMyPlaylist );
207
connect( ui.actionAddToMyPlaylist, SIGNAL( triggered() ),
208
this, SLOT( addToMyPlaylist() ) );
210
toolbar->addSeparator();
212
//m_loveAction = toolbar->addAction( QIcon( dataPath( "buttons/love.png" ) ), tr( "Love" ), this, SLOT( love() ) );
213
ui.actionLove->setIcon( QIcon( dataPath( "buttons/love.png" ) ) );
214
ui.actionLove->setShortcut( tr( "Ctrl+L" ) );
215
ui.actionLove->setToolTip( tr( "Express your love for the track that's playing" ) );
216
toolbar->addAction( ui.actionLove );
217
connect( ui.actionLove, SIGNAL( triggered() ),
218
this, SLOT( love() ) );
220
//m_banAction = toolbar->addAction( QIcon( dataPath( "buttons/ban.png" ) ), tr( "Ban" ), this, SLOT( ban() ) );
221
ui.actionBan->setIcon( QIcon( dataPath( "buttons/ban.png" ) ) );
222
ui.actionBan->setShortcut( tr( "Ctrl+B" ) );
223
ui.actionBan->setToolTip( tr( "Don't ever play me this again" ) );
224
toolbar->addAction( ui.actionBan );
225
connect( ui.actionBan, SIGNAL( triggered() ),
226
this, SLOT( ban() ) );
228
//m_skipAction = new QAction( QIcon( dataPath( "buttons/skip.png" ) ), tr( "Skip" ), this );
229
ui.actionSkip->setIcon( QIcon( dataPath( "buttons/skip.png" ) ) );
230
ui.actionSkip->setShortcut( QKeySequence( Qt::CTRL + Qt::Key_Right ) ); //NOTE don't translate
231
ui.actionSkip->setToolTip( tr( "Skip track" ) );
233
//m_playAction = new QAction( QIcon( dataPath( "buttons/play.png" ) ), tr( "Play" ), this );
234
ui.actionPlay->setIcon( QIcon( dataPath( "buttons/play.png" ) ) );
235
ui.actionPlay->setShortcut( Qt::Key_Space );
236
ui.actionPlay->setToolTip( tr( "Resume last radio station" ) );
238
//m_stopAction = new QAction( QIcon( dataPath( "buttons/stop.png" ) ), tr( "Stop" ), this );
239
ui.actionStop->setIcon( QIcon( dataPath( "buttons/stop.png" ) ) );
240
ui.actionStop->setToolTip( tr( "Stop radio" ) );
242
toolbar->addSeparator();
244
toolbar->addAction( ui.actionPlay );
245
toolbar->addAction( ui.actionStop );
246
toolbar->addAction( ui.actionSkip );
249
//ui.actionSettings->setText( tr( "Options" ) );
251
ui.actionSettings->setMenuRole( QAction::PreferencesRole );
252
ui.actionSettings->setShortcut( tr( "Ctrl+O" ) );
253
ui.actionToggleScrobbling->setShortcut( tr( "Ctrl+E" ) );
257
ui.actionFAQ->setShortcut( tr( "Ctrl+?" ) );
259
ui.actionFAQ->setShortcut( tr( "F1") );
262
// Workaround for showing "Space" shortcut in the Mac menu
264
ui.actionPlay->setIconText( ui.actionPlay->text().replace( "&", "" ) );
265
ui.actionStop->setIconText( ui.actionStop->text().replace( "&", "" ) );
267
// For Systray we don't want to display the hotkey in the menu
268
m_sysTrayActionPlay = new QAction( this );
269
m_sysTrayActionStop = new QAction( this );
270
m_sysTrayActions = new QActionGroup( this );
272
m_sysTrayActions->addAction( m_sysTrayActionPlay );
273
m_sysTrayActions->addAction( m_sysTrayActionStop );
275
connect( m_sysTrayActionPlay, SIGNAL( triggered() ),
276
this, SLOT( play() ) );
277
connect( m_sysTrayActionStop, SIGNAL( triggered() ),
278
this, SLOT( stop() ) );
280
m_sysTrayActionPlay->setText( ui.actionPlay->text() );
281
m_sysTrayActionStop->setText( ui.actionStop->text() );
282
m_sysTrayActionPlay->setIcon( ui.actionPlay->icon() );
283
m_sysTrayActionStop->setIcon( ui.actionStop->icon() );
285
// the spaces align the word space to the right of the menu, there is apparently
286
// no alternative on mac osx 10.4 and below. Without the extra text the space
287
// shortcut is rendered as ' '. Sweet!
288
ui.actionPlay->setText( ui.actionPlay->text() + " " + tr("Space" ) );
289
ui.actionStop->setText( ui.actionStop->text() + " " + tr("Space" ) );
292
106
ui.actionCheckForUpdates->setMenuRole( QAction::ApplicationSpecificRole );
293
107
ui.actionAboutLastfm->setMenuRole( QAction::AboutRole );
296
ui.menuHelp->insertAction( ui.actionCheckForUpdates, ui.actionAboutLastfm ); // Change the order of these 2 entries on the mac
298
//This menu item will not actually be displayed in the tools menu but will be inserted in the mac application menu.
299
//This is done automatically by QT with any menu item named Exit or Quit
300
ui.menuTools->addAction( tr( "Exit" ), this, SLOT( actualClose( ) ) );
302
// Additional seperators for menu entries for the other platforms
303
ui.menuHelp->insertSeparator( ui.actionCheckForUpdates );
304
ui.menuHelp->insertSeparator( ui.actionAboutLastfm );
307
//NOTE don't translate these! It breaks the shortcut due to the arrow key string getting translated
308
ui.actionVolumeUp->setShortcut( QKeySequence( Qt::CTRL + Qt::Key_Up ) );
309
ui.actionVolumeDown->setShortcut( Qt::CTRL + Qt::Key_Down );
311
ui.actionMute->setShortcut( Qt::CTRL + Qt::ALT + Qt::Key_Down );
313
ui.actionMute->setShortcut( tr( "Ctrl+M" ) );
317
delete ui.actionCheckForUpdates;
320
statusBar()->addPermanentWidget( ui.scrobbleLabel = new ScrobbleLabel );
322
ui.actionToggleScrobbling->setCheckable( true );
323
ui.actionToggleDiscoveryMode->setCheckable( true );
326
QWidget *playControls = new QWidget( toolbar );
327
ui_playcontrols.setupUi( playControls );
329
QAction *playControlsAction = toolbar->addWidget( playControls );
330
playControlsAction->setVisible( true );
336
QMenu* fileMenu = new QMenu( tr( "&File" ), this );
337
QAction* a = fileMenu->addAction( tr( "&Send to Tray" ), this, SLOT( close() ) );
338
a->setToolTip( tr( "Send application to system tray" ) );
339
fileMenu->addSeparator();
340
QAction* exitAction = fileMenu->addAction( tr( "E&xit" ), this, SLOT( actualClose() ) );
342
setAttribute( Qt::WA_MacNoClickThrough );
344
exitAction->setShortcut( tr( "CTRL+Q" ) );
345
exitAction->setText( tr("&Quit") );
347
menuBar()->insertMenu( menuBar()->actions().at( 0 ), fileMenu );
350
QShortcut *s = new QShortcut( this );
351
s->setKey( QKeySequence( "CTRL+W" ) );
352
connect( s, SIGNAL(activated()), SLOT(hide()) );
354
ui.actionTag->setEnabled( false );
355
ui.actionRecommend->setEnabled( false );
356
ui.actionLove->setEnabled( false );
357
ui.actionBan->setEnabled( false );
358
ui.actionAddToMyPlaylist->setEnabled( false );
359
ui.actionSkip->setEnabled( false );
360
ui.actionStop->setEnabled( false );
361
ui.actionStop->setVisible( false );
363
ui.stack->setAcceptDrops( false );
367
QApplication::setStyle( new MacStyleOverrides() );
369
QPalette p = ui.centralwidget->palette();
370
p.setColor( QPalette::Window, QColor( 0xe9, 0xe9, 0xe9 ) );
371
ui.centralwidget->setPalette( p );
372
p.setColor( QPalette::Button, QColor( 0xe9, 0xe9, 0xe9 ) );
374
// Hacky hackety McHackerson
375
QLinearGradient grad( 0.5, 0.0, 0.5, 20.0 );
376
grad.setColorAt( 0.0, QColor( 0x8c, 0x8c, 0x8c ) );
377
grad.setColorAt( 0.05, QColor( 0xf7, 0xf7, 0xf7 ) );
378
grad.setColorAt( 1.0, QColor( 0xe4, 0xe4, 0xe4 ) );
380
p = statusBar()->palette();
381
p.setBrush( QPalette::Window, b );
382
p.setBrush( QPalette::Base, b );
383
p.setColor( QPalette::Text, QColor( 0x59, 0x59, 0x59 ) );
384
p.setColor( QPalette::WindowText, QColor( 0x59, 0x59, 0x59 ) );
385
statusBar()->setPalette( p );
386
ui.scrobbleLabel->label()->setPalette( p );
388
// mac specific mainwindow adjustments
389
QFrame *hline = new QFrame;
390
hline->setFrameStyle( QFrame::HLine | QFrame::Plain );
391
p.setColor( QPalette::WindowText, QColor( 140, 140, 140 ) );
392
hline->setPalette( p );
393
ui.vboxLayout1->insertWidget( ui.vboxLayout1->indexOf( ui.stack ), hline );
394
ui.stack->setFrameStyle( QFrame::NoFrame );
396
//alter the spacings and that
397
ui.vboxLayout2->setMargin( 14 );
398
for (int x = 0; x < ui.vboxLayout1->count(); ++x)
399
if (ui.vboxLayout1->itemAt( x )->spacerItem())
400
delete ui.vboxLayout1->takeAt( x );
402
QFont f = statusBar()->font();
403
f.setPixelSize( k_statusBarFontSizeMac );
404
statusBar()->setFont( f );
405
ui.scrobbleLabel->label()->setFont( f );
409
// This is in order to remove the borders around the status bar widgets
410
QString styleName = QApplication::style()->objectName();
411
if( styleName == "windowsxp" )
413
statusBar()->setStyle( new WinXPStyleOverrides() );
417
statusBar()->setStyle( new WinStyleOverrides() );
419
ui.stack->layout()->setMargin( 1 );
422
#elif defined Q_WS_X11
423
statusBar()->setStyle( new WinXPStyleOverrides() );
425
//aesthetics, separates the statusbar and central widget slightly
426
static_cast<QVBoxLayout*>(ui.centralwidget->layout())->addSpacing( 2 );
108
ui.actionSettings->setMenuRole( QAction::PreferencesRole );
109
ui.actionStop->setVisible( false );
110
ui.statusbar->addPermanentWidget( ui.scrobbleLabel = new ScrobbleLabel );
113
QWidget *playControls = new QWidget;
114
ui.playcontrols.setupUi( playControls );
115
ui.toolbar->addWidget( playControls );
118
ui.splitter->setCollapsible( 0, false );
119
ui.splitter->setCollapsible( 1, false );
120
ui.splitter->setStretchFactor( 0, 0 );
121
ui.splitter->setStretchFactor( 1, 1 );
123
////// force a white background as we don't support colour variants, soz
124
QPalette p = centralWidget()->palette();
125
p.setBrush( QPalette::Base, Qt::white );
126
p.setBrush( QPalette::Text, Qt::black );
127
centralWidget()->setPalette( p );
130
ui.restStateWidget = new RestStateWidget( this );
131
ui.metaDataWidget = new MetaDataWidget( this );
134
ui.sidebar = new SideBarTree( this );
135
ui.sidebarFrame->layout()->addWidget( ui.sidebar );
136
connect( ui.sidebar, SIGNAL(statusMessage( QString )), SLOT(statusMessage( QString )) );
137
connect( ui.sidebar, SIGNAL(plsShowRestState()), SLOT(showRestState()) );
138
connect( ui.sidebar, SIGNAL(plsShowNowPlaying()), SLOT(showMetaDataWidget()) );
141
ui.stack->setBackgroundRole( QPalette::Base );
142
ui.stack->addWidget( ui.restStateWidget );
143
ui.stack->addWidget( ui.metaDataWidget );
146
ui.playcontrols.volume->setVisible( false );
147
ui.menuControls->menuAction()->setVisible( false );
148
ui.actionPlay->setVisible( false );
149
ui.actionStop->setVisible( false );
150
ui.actionSkip->setVisible( false );
151
ui.actionBan->setVisible( false );
152
ui.actionPlaylist->setVisible( false );
153
ui.actionToggleDiscoveryMode->setVisible( false );
154
ui.actionVolumeUp->setVisible( false );
155
ui.actionVolumeDown->setVisible( false );
156
ui.actionMute->setVisible( false );
158
ui.stack->removeWidget( ui.restStateWidget );
161
if (qApp->arguments().contains( "--debug" ))
162
ui.menuHelp->addAction( "kr4sh pls, kthxbai", this, SLOT(crash()) );
164
ui.restStateWidget->setFocus();
169
Container::setupTimeBar()
171
// Station bar grey bg colour
172
const QColor k_stationBarGreyTop( 0xba, 0xba, 0xba, 0xff );
173
const QColor k_stationBarGreyMiddle( 0xe2, 0xe2, 0xe2, 0xff );
174
const QColor k_stationBarGreyBottom( 0xff, 0xff, 0xff, 0xff );
176
// Track bar blue bg colour
177
const QColor k_trackBarBkgrBlueTop( 0xeb, 0xf0, 0xf2, 0xff );
178
const QColor k_trackBarBkgrBlueMiddle( 0xe5, 0xe9, 0xec, 0xff );
179
const QColor k_trackBarBkgrBlueBottom( 0xdc, 0xe2, 0xe5, 0xff );
181
// Track bar progress bar colour
182
const QColor k_trackBarProgressTop( 0xd6, 0xde, 0xe6, 0xff );
183
const QColor k_trackBarProgressMiddle( 0xd0, 0xd9, 0xe2, 0xff );
184
const QColor k_trackBarProgressBottom( 0xca, 0xd4, 0xdc, 0xff );
186
// Track bar scrobbled colour
187
const QColor k_trackBarScrobbledTop( 0xba, 0xc7, 0xd7, 0xff );
188
const QColor k_trackBarScrobbledMiddle( 0xb8, 0xc4, 0xd5, 0xff );
189
const QColor k_trackBarScrobbledBottom( 0xb5, 0xc1, 0xd2, 0xff );
191
////// song bar and scrobble bar
429
192
ui.songTimeBar->setEnabled( false );
430
ui.songTimeBar->setItemType( ItemTrack );
193
ui.songTimeBar->setItemType( UnicornEnums::ItemTrack );
432
195
QLinearGradient trackBarBkgrGradient( 0, 0, 0, ui.songTimeBar->height() );
433
196
trackBarBkgrGradient.setColorAt( 0, k_trackBarBkgrBlueTop );
464
224
stationBarGradient.setColorAt( 0.14, k_stationBarGreyBottom );
465
225
stationBarGradient.setColorAt( 1, k_stationBarGreyBottom );
227
ui.stationTimeBar->setBackgroundGradient( stationBarGradient );
228
ui.stationTimeBar->setStopWatch( &The::radio().stationStopWatch() );
467
230
if ( qApp->arguments().contains( "--sanity" ) )
468
231
stationBarGradient = trackBarBkgrGradient;
469
ui.stationTimeBar->setBackgroundGradient( stationBarGradient );
470
ui.stationTimeBar->setStopWatch( &m_radio->stationStopWatch() );
474
// on mac qt returns height without unified toolbar height included :(
475
QByteArray geometry = The::settings().containerGeometry();
476
if (geometry.isEmpty())
477
resize( width(), 496 );
236
Container::setupTrayIcon()
240
QMenu *menu = new QMenu( this );
241
menu->addAction( tr("Open"), this, SLOT(restoreWindow()) );
244
menu->addSeparator();
245
menu->addAction( ui.actionSettings );
247
menu->addSeparator();
248
menu->addAction( ui.actionDashboard );
249
menu->addAction( ui.actionToggleScrobbling );
250
(menu->addAction( tr("Change User") ))->setMenu( ui.menuUser );
251
menu->addSeparator();
252
menu->addAction( ui.actionShare );
253
menu->addAction( ui.actionTag );
254
menu->addAction( ui.actionPlaylist );
255
menu->addSeparator();
256
menu->addAction( ui.actionLove );
257
menu->addAction( ui.actionBan );
259
menu->addSeparator();
260
menu->addAction( ui.actionPlay );
261
menu->addAction( ui.actionStop );
262
menu->addAction( ui.actionSkip );
264
menu->addSeparator();
265
menu->addAction( ui.actionQuit );
268
// strangely text is amended in Application menu, but nowhere else
269
ui.actionSettings->setText( tr("Preferences...") );
270
ui.actionQuit->setText( tr("Quit Last.fm") );
273
m_trayIcon = new TrayIcon( this );
274
m_trayIcon->setContextMenu( menu );
277
SIGNAL(activated( QSystemTrayIcon::ActivationReason )),
278
SLOT(onTrayIconActivated( QSystemTrayIcon::ActivationReason )) );
280
connect( &The::settings(),
281
SIGNAL(userSettingsChanged( LastFmUserSettings& )),
283
SLOT(setUser( LastFmUserSettings& )) );
286
// FIXME this is due to a Qt bug (presumably) on Mac that doesn't raise the
287
// application even if you show a dialog via an action in your application
288
connect( menu, SIGNAL(triggered( QAction* )), SLOT(raise()) );
294
Container::applyPlatformSpecificTweaks()
297
ui.actionCheckForUpdates->setVisible( false );
298
ui.actionQuit->setShortcut( tr( "CTRL+Q" ) );
299
ui.actionQuit->setText( tr("&Quit") );
301
m_styleOverrides = new WinXPStyleOverrides();
302
ui.statusbar->setStyle( m_styleOverrides ); //no ugly surrounding lines
304
setWindowIcon( QIcon( MooseUtils::dataPath( "icons/as.png" ) ) );
305
//aesthetics, separates the statusbar and central widget slightly
306
static_cast<QVBoxLayout*>(ui.centralwidget->layout())->addSpacing( 2 );
308
ui.actionScrobbleManualIPod->setVisible( false );
312
// Can't use 32 for height as labels get truncated on Win classic
313
ui.toolbar->setIconSize( QSize( 50, 34 ) );
314
ui.menuTools->insertSeparator( ui.actionPlaylist );
316
// This is in order to remove the borders around the status bar widgets
317
if ( qApp->style()->objectName() != "windowsxp" )
319
m_styleOverrides = new WinStyleOverrides();
320
statusBar()->setStyle( m_styleOverrides );
321
ui.stack->layout()->setMargin( 1 );
479
restoreGeometry( geometry );
481
restoreGeometry( The::settings().containerGeometry() );
483
setWindowState( The::settings().containerWindowState() );
325
m_styleOverrides = new WinXPStyleOverrides();
326
statusBar()->setStyle( m_styleOverrides );
331
setUnifiedTitleAndToolBarOnMac( true );
332
ui.toolbar->setAttribute( Qt::WA_MacNoClickThrough );
333
ui.actionFAQ->setShortcut( tr( "Ctrl+?" ) );
487
334
ui.splitter->setHandleWidth( 1 );
490
ui.splitter->setCollapsible( 0, false );
491
ui.splitter->setCollapsible( 1, false );
492
ui.splitter->setStretchFactor( 0, 0 );
493
ui.splitter->setStretchFactor( 1, 1 );
335
ui.actionMute->setShortcut( QKeySequence( Qt::CTRL + Qt::ALT + Qt::Key_Down ) );
336
ui.menuFile->menuAction()->setVisible( false );
338
// Qt 4.3.1, setSeparatorsCollapsible doesn't work as advertised :(
339
foreach (QAction* a, ui.menuHelp->findChildren<QAction*>())
340
if (a->isSeparator())
343
qApp->setStyle( new MacStyleOverrides() );
345
QPalette p = ui.centralwidget->palette();
346
p.setColor( QPalette::Window, QColor( 0xe9, 0xe9, 0xe9 ) );
347
ui.centralwidget->setPalette( p );
349
p = statusBar()->palette();
350
p.setColor( QPalette::WindowText, QColor( 0x59, 0x59, 0x59 ) );
351
ui.scrobbleLabel->label()->setPalette( p );
353
QLinearGradient g( 0.5, 0.0, 0.5, 20.0 );
354
g.setColorAt( 0.0, QColor( 0x8c, 0x8c, 0x8c ) );
355
g.setColorAt( 0.05, QColor( 0xf7, 0xf7, 0xf7 ) );
356
g.setColorAt( 1.0, QColor( 0xe4, 0xe4, 0xe4 ) );
357
p.setBrush( QPalette::Window, QBrush( g ) );
358
ui.statusbar->setPalette( p );
360
// mac specific mainwindow adjustments
361
QFrame *hline = new QFrame;
362
hline->setFrameStyle( QFrame::HLine | QFrame::Plain );
363
p.setColor( QPalette::WindowText, QColor( 140, 140, 140 ) );
364
hline->setPalette( p );
365
ui.vboxLayout1->insertWidget( ui.vboxLayout1->indexOf( ui.stack ), hline );
366
ui.stack->setFrameStyle( QFrame::NoFrame );
368
//alter the spacings and that
369
ui.vboxLayout2->setMargin( 14 );
370
for (int x = 0; x < ui.vboxLayout1->count(); ++x)
371
if (ui.vboxLayout1->itemAt( x )->spacerItem())
372
delete ui.vboxLayout1->takeAt( x );
374
QFont f = ui.statusbar->font();
375
f.setPixelSize( 10 );
376
ui.statusbar->setFont( f );
377
ui.scrobbleLabel->label()->setFont( f );
381
ui.actionGetPlugin->setEnabled( false );
382
ui.actionGetPlugin->setVisible( false );
388
Container::setupConnections()
390
connect( ui.actionDashboard, SIGNAL(triggered()), SLOT(gotoProfile()) );
391
connect( ui.actionSettings, SIGNAL(triggered()), SLOT(showSettingsDialog()) );
392
connect( ui.actionGetPlugin, SIGNAL(triggered()), SLOT(getPlugin()) );
393
connect( ui.actionCheckForUpdates, SIGNAL(triggered()), SLOT(checkForUpdates()) );
394
connect( ui.actionAddUser, SIGNAL(triggered()), SLOT(addUser()) );
395
connect( ui.actionDeleteUser, SIGNAL(triggered()), SLOT(deleteUser()) );
396
connect( ui.actionToggleScrobbling, SIGNAL(triggered()), SLOT(toggleScrobbling()) );
397
connect( ui.actionToggleDiscoveryMode, SIGNAL(triggered()), SLOT(toggleDiscoveryMode()) );
398
connect( ui.actionAboutLastfm, SIGNAL(triggered()), SLOT(about()) );
399
connect( ui.menuUser, SIGNAL(aboutToShow()), SLOT(onAboutToShowUserMenu()) );
400
connect( ui.menuUser, SIGNAL(triggered( QAction* )), SLOT(onUserSelected( QAction* )) );
401
connect( ui.actionSkip, SIGNAL(triggered()), SLOT(skip()) );
402
connect( ui.actionStop, SIGNAL(triggered()), SLOT(stop()) );
403
connect( ui.actionPlay, SIGNAL(triggered()), SLOT(play()) );
404
connect( ui.scrobbleLabel, SIGNAL(clicked()), SLOT(toggleScrobbling()) );
405
connect( ui.actionVolumeUp, SIGNAL(triggered()), SLOT(volumeUp()) );
406
connect( ui.actionVolumeDown, SIGNAL(triggered()), SLOT(volumeDown()) );
407
connect( ui.actionMute, SIGNAL(triggered()), SLOT(mute()) );
408
connect( ui.actionFAQ, SIGNAL(triggered()), SLOT(showFAQ()) );
409
connect( ui.actionForums, SIGNAL(triggered()), SLOT(showForums()) );
410
connect( ui.actionInviteAFriend, SIGNAL(triggered()), SLOT(inviteAFriend()) );
411
connect( ui.actionDiagnostics, SIGNAL(triggered()), SLOT(showDiagnosticsDialog()) );
412
connect( ui.actionSendToTray, SIGNAL(triggered()), SLOT(close()) );
413
connect( ui.actionQuit, SIGNAL(triggered()), SLOT(quit()) );
414
connect( ui.playcontrols.volume, SIGNAL(valueChanged( int )), &The::radio(), SLOT(setVolume( int )) );
415
connect( The::webService(), SIGNAL(success( Request* )), SLOT(webServiceSuccess( Request* )) );
416
connect( The::webService(), SIGNAL(failure( Request* )), SLOT(webServiceFailure( Request* )), Qt::QueuedConnection );
417
connect( &The::settings(), SIGNAL( userSettingsChanged( LastFmUserSettings& ) ), SLOT( updateUserStuff( LastFmUserSettings& ) ) );
418
connect( &The::settings(), SIGNAL( appearanceSettingsChanged() ), SLOT( updateAppearance() ) );
419
connect( m_updater, SIGNAL( updateCheckDone( bool, bool, QString ) ), SLOT( updateCheckDone( bool, bool, QString ) ) );
420
connect( ui.stack, SIGNAL(currentChanged( int )), SIGNAL(stackIndexChanged( int )) );
421
connect( ui.actionMyProfile, SIGNAL(triggered()), SLOT(toggleSidebar()) );
422
connect( ui.actionPlaylist, SIGNAL(triggered()), SLOT(addToMyPlaylist()) );
423
connect( ui.actionTag, SIGNAL(triggered()), SLOT(showTagDialog()) );
424
connect( ui.actionShare, SIGNAL(triggered()), SLOT(showShareDialog()) );
425
connect( ui.actionLove, SIGNAL( triggered() ), SLOT(love()) );
426
connect( ui.actionBan, SIGNAL(triggered()), SLOT(ban()) );
427
connect( ui.metaDataWidget, SIGNAL(tagButtonClicked()), SLOT(showTagDialogMD()) );
428
connect( ui.metaDataWidget, SIGNAL(urlHovered( QString )), SLOT(displayUrlInStatusBar( QString )) );
430
connect( ui.actionScrobbleManualIPod, SIGNAL(triggered()), SLOT(scrobbleManualIpod()) );
432
////// important connections
433
connect( &The::scrobbler(),
434
SIGNAL(status( int, QVariant )),
435
SLOT(onScrobblerStatusChange( int, QVariant )) );
436
connect( &The::radio(),
437
SIGNAL(error( RadioError, QString )),
438
SLOT(onRadioError( RadioError, QString )), Qt::QueuedConnection /* crash if direct connect */ );
439
connect( &The::radio(),
440
SIGNAL(stateChanged( RadioState )),
441
SLOT(onRadioStateChanged( RadioState )) );
442
connect( &The::radio(),
443
SIGNAL( buffering( int, int ) ),
444
SLOT( onRadioBuffering( int, int ) ) );
446
connect( qApp, SIGNAL(event( int, QVariant )), SLOT(onAppEvent( int, QVariant )) );
448
////// we don't use CTRL because that varies by platform, NOTE don't tr()!
449
QObject* hides = new QShortcut( QKeySequence( "Ctrl+W" ), this );
450
QObject* openL = new QShortcut( QKeySequence( "Alt+Shift+L" ), this );
451
QObject* openF = new QShortcut( QKeySequence( "Alt+Shift+F" ), this );
452
connect( hides, SIGNAL(activated()), SLOT(hide()) );
453
connect( openL, SIGNAL(activated()), SLOT(onAltShiftL()) );
454
connect( openF, SIGNAL(activated()), SLOT(onAltShiftF()) );
456
#ifndef Q_WS_X11 // No helper on unix!
457
QObject* openH = new QShortcut( QKeySequence( "Alt+Shift+H" ), this );
458
connect( openH, SIGNAL(activated()), SLOT(onAltShiftH()) );
461
QObject* openP = new QShortcut( QKeySequence( "Alt+Shift+P" ), this );
462
connect( openP, SIGNAL( activated() ), SLOT( onAltShiftP() ) );
468
Container::restoreState()
470
//NOTE it is important that the connections are done first
471
ui.playcontrols.volume->setValue( The::settings().volume() );
494
473
QByteArray state = The::settings().splitterState();
496
476
ui.splitter->restoreState( state );
478
m_sidebarWidth = The::settings().sidebarWidth();
480
if ( m_sidebarWidth > 0 )
482
LOGL( 3, "Restoring sidebar width: " << m_sidebarWidth );
483
ui.splitter->setSizes( QList<int>() << m_sidebarWidth );
488
ui.splitter->setSizes( QList<int>() << 176 );
499
492
//HACK for osx since the splitter is undetectable for most users
500
493
QList<int> sizes = ui.splitter->sizes();
501
494
if (sizes.count() == 2 && sizes[0] < 100)
505
498
ui.splitter->setSizes( sizes );
510
////// force a white background as we don't support colour variants, soz
511
QPalette p = centralWidget()->palette();
512
p.setBrush( QPalette::Base, Qt::white );
513
centralWidget()->setPalette( p );
519
connect( ui.actionDashboard, SIGNAL( triggered() ),
520
this, SLOT( gotoProfile() ) );
521
connect( ui.actionSettings, SIGNAL( triggered() ),
522
this, SLOT( showSettingsDialog() ) );
523
connect( ui.actionGetPlugin, SIGNAL( triggered() ),
524
this, SLOT( getPlugin() ) );
526
connect( ui.actionCheckForUpdates, SIGNAL( triggered() ),
527
this, SLOT( checkForUpdates() ) );
529
connect( ui.actionAddUser, SIGNAL( triggered() ),
530
this, SLOT( addUser() ) );
531
connect( ui.actionDeleteUser, SIGNAL( triggered() ),
532
this, SLOT( deleteUser() ) );
533
connect( ui.actionToggleScrobbling, SIGNAL( triggered() ),
534
this, SLOT( toggleScrobbling() ) );
535
connect( ui.actionToggleDiscoveryMode, SIGNAL( triggered() ),
536
this, SLOT( toggleDiscoveryMode() ) );
537
connect( ui.actionAboutLastfm, SIGNAL( triggered() ),
538
this, SLOT( about() ) );
539
connect( ui.menuUser, SIGNAL( aboutToShow() ),
540
this, SLOT( showUserMenu() ) );
541
connect( ui.menuUser, SIGNAL( triggered( QAction* ) ),
542
this, SLOT( userSelected( QAction* ) ) );
543
connect( ui.actionSkip, SIGNAL( triggered() ),
544
this, SLOT( skip() ) );
545
connect( ui.actionStop, SIGNAL( triggered() ),
546
this, SLOT( stop() ) );
547
connect( ui.actionPlay, SIGNAL( triggered() ),
548
this, SLOT( play() ) );
549
connect( ui_playcontrols.volume, SIGNAL( valueChanged( int ) ),
550
m_radio, SLOT( setVolume( int ) ) );
551
connect( ui.scrobbleLabel, SIGNAL( clicked() ),
552
this, SLOT( toggleScrobbling() ) );
553
connect( ui.actionVolumeUp, SIGNAL( triggered() ),
554
this, SLOT( volumeUp() ) );
555
connect( ui.actionVolumeDown, SIGNAL( triggered() ),
556
this, SLOT( volumeDown() ) );
557
connect( ui.actionMute, SIGNAL( triggered() ),
558
this, SLOT( mute() ) );
559
connect( ui.actionFAQ, SIGNAL( triggered() ),
560
this, SLOT( showFAQ() ) );
561
connect( ui.actionForums, SIGNAL( triggered() ),
562
this, SLOT( showForums() ) );
563
connect( ui.actionInviteAFriend, SIGNAL( triggered() ),
564
this, SLOT( inviteAFriend() ) );
566
// Services & Extensions
567
//connect( The::webService(), SIGNAL(handshakeResult( Handshake* )), SLOT(handshakeResult( Handshake* )) );
568
connect( The::webService(), SIGNAL(success( Request* )), SLOT(webServiceSuccess( Request* )) );
569
connect( The::webService(), SIGNAL(failure( Request* )), SLOT(webServiceFailure( Request* )), Qt::QueuedConnection );
571
connect( m_radio, SIGNAL( buffering( int, int ) ),
572
this, SLOT( onRadioBuffering( int, int ) ) );
573
connect( m_radio, SIGNAL( stateChanged( RadioState ) ),
574
this, SLOT( onRadioStateChange( RadioState ) ) );
575
connect( m_radio, SIGNAL( error( RadioError, const QString& ) ),
576
this, SLOT( onRadioError( RadioError, const QString& ) ), Qt::QueuedConnection );
578
connect( &The::settings(), SIGNAL( userSettingsChanged( UserSettings& ) ),
579
this, SLOT( updateUserStuff( UserSettings& ) ) );
580
connect( &The::settings(), SIGNAL( doReconnect() ),
581
this, SLOT( initServices() ) );
584
connect( m_updater, SIGNAL( updateCheckDone( bool, bool, QString ) ),
585
this, SLOT( updateCheckDone( bool, bool, QString ) ) );
587
// update volume _after_ signals have been connected
588
ui_playcontrols.volume->setValue( The::settings().volume() );
591
ui_playcontrols.volume->setVisible( false );
593
ui.actionPlay->setVisible( false );
594
ui.actionStop->setVisible( false );
595
ui.actionSkip->setVisible( false );
596
ui.actionAddToMyPlaylist->setVisible( false );
597
ui.actionBan->setVisible( false );
598
ui.actionVolumeUp->setVisible( false );
599
ui.actionVolumeDown->setVisible( false );
600
ui.actionMute->setVisible( false );
601
ui.actionToggleDiscoveryMode->setVisible( false );
602
ui.menuControls->menuAction()->setVisible( false );
603
ui.stack->setCurrentIndex( 0 );
606
m_sysTrayActions->setVisible( false );
611
ui.actionGetPlugin->setEnabled( false );
612
ui.actionGetPlugin->setVisible( false );
614
ui.menuTools->insertSeparator( ui.actionAddToMyPlaylist );
618
new ITunesScript( this, m_listener );
622
if (qApp->arguments().contains( "--debug" ))
624
// Add crash option to menu!
625
ui.menuHelp->addAction( "kr4sh pls, kthxbai", this, SLOT(crash()) );
627
#ifdef MONITOR_STREAMING
628
ui.menuHelp->addAction( "Stream Monitor", m_radio, SLOT( activateStreamMonitor() ) );
631
connect( ui.stack, SIGNAL(currentChanged( int )), SIGNAL(stackIndexChanged( int )) );
634
m_showRestStateTimer = new QTimer( this );
635
m_showRestStateTimer->setSingleShot( true );
636
m_showRestStateTimer->setInterval( 200 );
637
connect( m_showRestStateTimer, SIGNAL(timeout()), SLOT(onRestStateTimerTimeout()) );
639
// Remove the path to the app and parse
640
QStringList params = qApp->arguments().mid( 1 );
641
m_iControl->parseCommands( params );
501
// on mac qt returns height without unified toolbar height included :(
502
// so first time we have to do it like this
503
QByteArray geometry = The::settings().containerGeometry();
504
if (geometry.isEmpty())
505
resize( width(), 496 );
507
restoreGeometry( geometry );
509
restoreGeometry( The::settings().containerGeometry() );
511
setWindowState( The::settings().containerWindowState() );
646
Container::initServices()
516
Container::loadExtensions()
650
UserSettings& user = The::settings().currentUser();
651
LOG( 3, "Starting app for user: " << user.username() << "\n" );
653
// we must restore state here as we save it in toggleSidebar in order to get
654
// round the bug in Qt where saveState for the splitter is lost for hidden widgets
655
m_sidebarEnabled = !user.sidebarEnabled();
658
updateUserStuff( user );
659
statusBar()->showMessage( tr( "Connecting to server..." ) );
661
//////// We now have a current user
662
QString username = user.username();
663
QString password = user.password();
664
QString version = The::settings().version();
666
m_radio->init( username, password, version );
668
////// shut down the current listener, this will cause a scrobble if required
669
// also it makes sense as the new user should start with the chance to scrobble
670
// the current track if applicable
671
if (m_listener->GetActivePlayer())
519
// Hack to get it working with VS2005
520
QString path = qApp->applicationDirPath();
522
QString path = qApp->applicationDirPath() + "/extensions";
530
foreach( QString fileName, d.entryList( QDir::Files ) )
673
CPlayerCommand command( PCMD_STOP, m_listener->GetActivePlayer()->GetID(), m_listener->GetNowPlaying() );
674
m_listener->Handle( command );
676
command.mCmd = PCMD_START;
677
m_listener->Handle( command );
532
if ( !fileName.startsWith( EXTENSION_PREFIX ) )
534
if ( !QLibrary::isLibrary( d.absoluteFilePath( fileName ) ) )
537
LOGL( 3, "Trying to load extension: " << fileName );
538
QObject* plugin = QPluginLoader( d.absoluteFilePath( fileName ) ).instance();
540
LOGL( 1, "Failed to load " << fileName );
544
LOGL( 3, "Extension loaded." );
545
ExtensionInterface* iExtension = qobject_cast<ExtensionInterface *>( plugin );
548
if ( iExtension->hasSettingsPane() )
551
LOGL( 3, "Loaded a settings extension" );
552
m_settingsDialog->addExtension( iExtension );
554
QSettings* us = new CurrentUserSettings( this );
555
iExtension->setSettings( us );
681
// initialise the scrobbler to the new user, handshake is delayed until current users scrobble completes
682
Scrobbler::Init init;
683
init.username = username;
684
init.client_version = version;
685
init.password = password;
687
m_scrobbler->handshake( init );
690
// enable again when handshake succeeds
691
ui.actionPlay->setEnabled( false );
694
m_rest_state_widget->setPlayEnabled( false );
696
m_rest_state_widget->updatePlayerNames();
701
561
Container::~Container()
705
delete m_metaDataExtension;
710
Container::initListener()
712
connect( m_listener, SIGNAL( trackChanged( TrackInfo, bool ) ),
713
this, SLOT( setNewSong( TrackInfo, bool ) ), Qt::QueuedConnection );
715
connect( m_listener, SIGNAL( trackScrobbled( const TrackInfo& ) ),
716
this, SLOT( onTrackScrobbled( const TrackInfo& ) ), Qt::QueuedConnection );
718
connect( m_listener, SIGNAL( exceptionThrown( QString ) ),
719
this, SLOT( listenerException( QString ) ) );
721
// Start listener worker thread
727
Container::dragMoveEvent( QDragMoveEvent* event )
730
QString url = event->mimeData()->urls().value( 0 ).toString();
731
if ( url.startsWith( "lastfm://" ) )
733
event->acceptProposedAction();
742
Container::dragEnterEvent( QDragEnterEvent* event )
745
QString url = event->mimeData()->urls().value( 0 ).toString();
746
if ( url.startsWith( "lastfm://" ) )
748
event->acceptProposedAction();
757
Container::dropEvent( QDropEvent* event )
760
QString url = event->mimeData()->urls().value( 0 ).toString();
761
if ( url.startsWith( "lastfm://" ) )
763
m_radio->playStation( StationUrl( url ) );
563
LOGL( 3, "Saving app state" );
565
// don't save if hidden as Qt is shit and this doesn't work, we save
566
// just before hiding too to ensure we always have the state saved correctly
567
if ( m_sidebarEnabled )
569
// HACK: workaround for Qt occasionally returning width 75 when it shouldn't
570
int widthQtThinksItIs = ui.splitter->sizes().first();
571
int actualWidth = widthQtThinksItIs == 75 ? m_sidebarWidth : widthQtThinksItIs;
573
LOGL( 3, "Saving sidebar width: " << actualWidth );
574
The::settings().setSidebarWidth( actualWidth );
576
The::settings().setSplitterState( ui.splitter->saveState() );
579
The::settings().setContainerWindowState( windowState() );
580
The::settings().setVolume( ui.playcontrols.volume->value() );
581
The::currentUser().setSidebarEnabled( m_sidebarEnabled );
583
LOGL( 3, "Saving config" );
587
delete m_styleOverrides;
595
if ( ConfirmDialog::quit( this ) )
770
603
Container::closeEvent( QCloseEvent *event )
773
608
if ( !event->spontaneous() )
775
actualClose( false /*don't confirm with user*/ );
613
// ELSE FOR OSX ABOVE!
614
if ( !The::settings().showTrayIcon() )
617
if ( !ConfirmDialog::hide( this ) )
634
// Just minimise to tray
781
// Just minimise to tray
788
Container::event( QEvent* e )
791
#if QT_VERSION >= 0x00040300
792
//TODO remove when Qt is fixed!
793
if ( e->type() == QEvent::Resize )
795
// hack as Qt 4.3.1 is b0rked for unified toolbars
796
ui.toolbar->setMaximumWidth( width() );
801
if (e->type() == QEvent::Move || e->type() == QEvent::Resize)
803
// Again, Qt is broken, if maximised the saveGeometry function fails to
804
// save the geometry for the non-maximised state. So instead we must save it
805
// for *every* resize and move event. Yay!
807
if (windowState() != Qt::WindowMaximized)
808
The::settings().setContainerGeometry( saveGeometry() );
811
return QMainWindow::event( e );
816
Container::actualClose( bool confirm )
820
bool okToClose = true;
824
QString m = tr( "Really quit Last.fm? Any music you listen to will not be scrobbled "
825
"to your profile." );
826
ConfirmDialog dlg( ConfirmDialog::Quit, m, this );
827
okToClose = dlg.exec() == QDialog::Accepted;
832
hide(); //makes it look like we have closed already to user
834
m_closingDown = true;
836
// This allows any extensions (i.e. Skype) to clear its stuff. Bit of a hack.
837
emit newSong( MetaData() );
839
// EJ TODO FIXME: Can't do this as the radio's stopping is asynchronous
840
// and it will lead to the radio calling the listener after it's died.
841
// If we're not doing this however, we will get an assert about a thread
842
// quitting (the StopWatch inside the radio) improperly.
843
// Need to solve the whole shutdown thing in a more elegant way.
846
LOGL( Logger::Debug, "Radio state at shutdown: " <<
847
CUtils::radioState2String( m_radio->state() ) );
849
// Bottom line here is that we must wait until the radio thread has stopped
850
// and it has dealt with all outstanding events.
853
QApplication::processEvents();
860
while ( m_radio->state() != State_Stopped &&
861
m_radio->state() != State_Uninitialised &&
862
m_radio->state() != State_Handshaking &&
863
m_radio->state() != State_Handshaken );
865
LOG( 3, "Saving appState\n" );
867
// don't save if hidden as Qt is shit and this doesn't work, we save
868
// just before hiding too to ensure we always have the state saved correctly
869
if (m_sidebarEnabled)
870
The::settings().setSplitterState( ui.splitter->saveState() );
872
The::settings().setContainerWindowState( windowState() );
874
The::settings().setVolume( ui_playcontrols.volume->value() );
875
The::currentUser().setSidebarEnabled( m_sidebarEnabled );
877
LOG( 3, "Saving config\n" );
878
The::settings().save();
880
LOG( 3, "Shutting down listener\n" );
881
qDebug() << "Shutting down listener";
884
LOG( 3, "Calling exit\n" );
885
QApplication::exit( 0 );
887
qApp->sendPostedEvents( &The::scrobbler(), 0 /*all event types*/ );
674
Container::dragMoveEvent( QDragMoveEvent* event )
677
QString url = event->mimeData()->urls().value( 0 ).toString();
678
if ( url.startsWith( "lastfm://" ) )
680
event->acceptProposedAction();
689
Container::dragEnterEvent( QDragEnterEvent* event )
692
QString url = event->mimeData()->urls().value( 0 ).toString();
693
if ( url.startsWith( "lastfm://" ) )
695
event->acceptProposedAction();
704
Container::dropEvent( QDropEvent* event )
707
QString url = event->mimeData()->urls().value( 0 ).toString();
708
if ( url.startsWith( "lastfm://" ) )
710
The::radio().playStation( StationUrl( url ) );
717
Container::event( QEvent* e )
720
//TODO remove when Qt is fixed!
721
if ( e->type() == QEvent::Resize )
723
// hack as Qt 4.3.1 is b0rked for unified toolbars
724
ui.toolbar->setMaximumWidth( width() );
728
if ( e->type() == QEvent::Move || e->type() == QEvent::Resize )
730
// Again, Qt is broken, if maximised the saveGeometry function fails to
731
// save the geometry for the non-maximised state. So instead we must save it
732
// for *every* resize and move event. Yay!
734
if (windowState() != Qt::WindowMaximized)
735
The::settings().setContainerGeometry( saveGeometry() );
738
if ( e->type() == QEvent::Show )
740
emit becameVisible();
743
return QMainWindow::event( e );
925
748
Container::toggleDiscoveryMode()
927
750
bool enabled = ui.actionToggleDiscoveryMode->isChecked();
928
m_radio->setDiscoveryMode( enabled );
933
Container::loadExtensions()
935
m_metaDataExtension = 0;
937
m_sidebar = new SideBarTree;
938
ui.sidebarFrame->layout()->addWidget( m_sidebar );
939
connect( m_sidebar, SIGNAL(statusMessage( QString )), SLOT(statusMessage( QString )) );
940
connect( m_sidebar, SIGNAL(plsShowRestState()), SLOT(showRestState()) );
941
connect( m_sidebar, SIGNAL(plsShowNowPlaying()), SLOT(showMetaDataWidget()) );
943
LOGL( 3, "Added sidebar extension to GUI." );
945
ui.stack->setBackgroundRole( QPalette::Base );
948
ui.stack->addWidget( m_rest_state_widget = new RestStateWidget );
949
m_rest_state_widget->setFocus();
951
connect( this, SIGNAL(playStarted()),
952
m_rest_state_widget, SLOT(clear()) );
954
connect( &The::settings(), SIGNAL(userSwitched( UserSettings& )),
955
m_rest_state_widget, SLOT(clear()) );
959
m_metaDataExtension = new MetaDataExtension;
960
m_metaDataExtension->setOwner( ui.stack );
961
ui.stack->addWidget( m_metaDataExtension->gui() );
963
connect( this, SIGNAL( newSong( MetaData ) ),
964
m_metaDataExtension, SLOT( setMetaData( MetaData ) ) );
966
connect( m_metaDataExtension, SIGNAL( trackModerated( MetaData ) ),
967
ui.songTimeBar, SLOT( setNewTrack( MetaData ) ) );
969
connect( m_metaDataExtension, SIGNAL( trackModerated( MetaData ) ),
970
this, SLOT( updateWindowTitle( MetaData ) ) );
972
connect( m_metaDataExtension, SIGNAL( tagButtonClicked() ),
973
this, SLOT( showTagDialogMD() ) );
975
connect( m_metaDataExtension, SIGNAL( urlHovered( QString ) ),
976
this, SLOT( displayUrlInStatusBar( QString ) ) );
978
LOGL( 3, "Added metadata extension to GUI." );
982
// Hack to get it working with VS2005
983
dirPath = qApp->applicationDirPath();
985
dirPath = qApp->applicationDirPath() + "/extensions";
992
QDir extensionsDir( dirPath );
994
foreach ( QString fileName, extensionsDir.entryList( QDir::Files ) )
996
if ( !fileName.startsWith( EXTENSION_PREFIX ) || !QLibrary::isLibrary( extensionsDir.absoluteFilePath( fileName ) ) )
999
LOGL( 3, "Trying to load extension: " << fileName );
1000
QObject* plugin = QPluginLoader( extensionsDir.absoluteFilePath( fileName ) ).instance();
1003
LOGL( 3, "Extension loaded." );
1004
ExtensionInterface *iExtension = qobject_cast<ExtensionInterface *>( plugin );
1007
if ( iExtension->name() == "UserInfo Extension" )
1009
m_eUserInfo = iExtension;
1012
else if ( iExtension->name() == "Growl Notifier Extension" )
1014
// Add it to Options
1015
LOGL( 3, "Loaded a settings extension" );
1016
m_settingsDialog->addExtension( iExtension );
1018
connect( m_metaDataExtension, SIGNAL( metadataFetched( MetaData ) ),
1019
iExtension, SLOT( notify( MetaData ) ) );
1021
m_metaDataExtension->setAlwaysFetchMetaData( true );
1024
else if ( iExtension->hasSettingsPane() )
1026
// Add it to Options
1027
LOGL( 3, "Loaded a settings extension" );
1028
m_settingsDialog->addExtension( iExtension );
1030
connect( this, SIGNAL( newSong( MetaData ) ),
1031
iExtension, SLOT( notify( MetaData ) ) );
1037
LOGL( 1, "Failed to load " << fileName );
751
The::radio().setDiscoveryMode( enabled );
1440
Container::setNewSong( TrackInfo data, bool songStarted )
1442
// The assumption that a new track has just started can't be made here.
1443
// It could just be that the radio was stopped and an underlying local
1444
// track became visible.
1449
ui.songTimeBar->clear();
1450
ui.songTimeBar->setEnabled( false );
1451
ui.songTimeBar->setClockText( "" );
1453
ui.actionTag->setEnabled( false );
1454
ui.actionRecommend->setEnabled( false );
1455
ui.actionLove->setEnabled( false );
1456
ui.actionAddToMyPlaylist->setEnabled( false );
1462
emit newSong( m_metaData ); //empty TrackInfo object
1464
// we disable this sometimes from ChangeStationRequest results
1465
// but enable it again when we stop
1466
ui.actionToggleDiscoveryMode->setEnabled( true );
1468
// we use a timer as some players say they stop before starting a new
1469
// track, which results in us flickering between the two widgets, and
1471
if (ui.stack->currentIndex() != 0)
1472
m_showRestStateTimer->start();
1474
else if ( m_metaData.scrobblableStatus() != TrackInfo::OkToScrobble &&
1475
m_metaData.source() != TrackInfo::Radio )
1477
// Invalid track, all we do is update the song bar
1478
displayUnscrobblableStatus( m_metaData.scrobblableStatus() );
1479
m_metaDataExtension->clear();
1485
if (The::currentUser().isLogToProfile())
1486
The::scrobbler().nowPlaying( data );
1488
// The reason for these extra checks is that one user had
1489
// crashes here (bug #56). This could happen if the player listener
1490
// receives a START, emits a queued signal, then immediately
1491
// receives a STOP. If the first queued signal doesn't get here
1492
// until after the STOP, GetActivePlayer will return NULL.
1493
CPlayerConnection* plyr = m_listener->GetActivePlayer();
1496
LOG( 1, "Caught a NULL player in setNewSong, not setting stopwatch" );
1500
StopWatch& watch = plyr->GetStopWatch();
1501
ui.songTimeBar->setStopWatch( &watch );
1502
ui.songTimeBar->setReverse( true );
1503
//ui.songTimeBar->setMaximum( data.scrobbleTime() );
1504
if ( plyr->IsScrobbled() )
1506
setTrackScrobbled();
1510
ui.songTimeBar->setClockText( "" );
1514
ui.actionTag->setEnabled( true );
1515
ui.actionRecommend->setEnabled( true );
1516
ui.actionLove->setEnabled( true );
1517
ui.actionAddToMyPlaylist->setEnabled( true );
1519
QHash<QString, QString> itemdata;
1520
itemdata.insert( "artist", data.artist() );
1521
itemdata.insert( "track", data.track() );
1522
ui.songTimeBar->setItemData( itemdata );
1524
// Only display scrobble timer if we're logging to profile and the track
1526
bool showScrobbleTimer = The::settings().currentUser().isLogToProfile()
1527
&& m_metaData.scrobblableStatus() == TrackInfo::OkToScrobble;
1528
ui.songTimeBar->setProgressEnabled( showScrobbleTimer );
1529
ui.songTimeBar->setClockEnabled( true );
1530
ui.songTimeBar->setMode( m_metaData.source() );
1537
ui.stack->setCurrentIndex( 1 );
1538
m_showRestStateTimer->stop();
1541
// Clear any status messages on the start of a new track or it will look odd
1542
if ( data.source() != TrackInfo::Radio )
1544
statusBar()->clearMessage();
1547
emit newSong( m_metaData );
1550
updateWindowTitle( m_metaData );
1555
Container::displayUnscrobblableStatus( TrackInfo::ScrobblableStatus status )
1557
Q_ASSERT( status != TrackInfo::OkToScrobble );
1559
QString text = tr( "Can't scrobble: %1" );
1563
case TrackInfo::NoTimeStamp:
1565
text = text.arg( tr( "missing start time" ) );
1569
case TrackInfo::TooShort:
1571
text = text.arg( tr( "track too short" ) );
1575
case TrackInfo::ArtistNameMissing:
1576
case TrackInfo::TrackNameMissing:
1578
text = text.arg( tr( "artist or title missing from ID3 tag" ) );
1582
case TrackInfo::ExcludedDir:
1584
text = tr( "Won't scrobble: track is in directory set to not scrobble" );
1588
case TrackInfo::ArtistInvalid:
1590
text = text.arg( tr( "invalid artist name" ) );
1595
Q_ASSERT( !"Shouldn't happen" );
1598
ui.songTimeBar->setText( text );
1603
1137
Container::onScrobblerStatusChange( int code, const QVariant& data )
1607
1141
case Scrobbler::ErrorBadAuthorisation:
1608
//TODO this can prolly be removed, but is untested and NOW is bug fix branch
1609
m_sysTray->setUser( The::currentUser() );
1611
1142
//NOTE radio is likely to fail auth too, so don't show 2 dialogs
1612
1143
statusBar()->showMessage( tr("Your username and password are incorrect") );
1615
1146
case Scrobbler::Connecting:
1616
statusBar()->showMessage( tr("Connecting to Last.fm...") );
1147
//TODO status system with temp messages or queue or something
1148
//statusBar()->showMessage( tr("Connecting to Last.fm...") );
1619
1151
case Scrobbler::Handshaken:
1620
//FIXME we have to to do this due to BadAuthorisation state
1621
//TODO see above, prolly can be removed?
1622
m_sysTray->setUser( The::currentUser() );
1625
1154
case Scrobbler::Scrobbling:
1626
statusBar()->showMessage( tr( "Scrobbling %n track(s)...", "", data.toInt() ) );
1155
// we say submitting because we say "scrobbled" at 50%
1156
statusBar()->showMessage( tr( "Submitting %n scrobble(s)...", "", data.toInt() ) );
1629
1159
case Scrobbler::TracksScrobbled:
1630
statusBar()->showMessage( tr( "%n track(s) scrobbled", "", data.toInt() ) );
1160
// we say submitting because we say "scrobbled" at 50%
1161
statusBar()->showMessage( tr( "%n scrobble(s) submitted", "", data.toInt() ) );
1633
1164
case Scrobbler::TracksNotScrobbled:
1634
statusBar()->showMessage( tr( "%n track(s) will be scrobbled later", "", data.toInt() ) );
1165
statusBar()->showMessage( tr( "%n scrobble(s) will be submitted later", "", data.toInt() ) );
1637
1168
case Scrobbler::ErrorBannedClient:
1638
LastMessageBox::critical( tr("Error"), tr( "This software is too old, please upgrade." ) );
1169
LastMessageBox::critical( tr("Old Version"), tr( "This software is too old, please upgrade." ) );
1641
1172
case Scrobbler::ErrorBadTime:
1642
LastMessageBox::critical( tr("Error"), tr( "Either your computer's clock is inaccurate or your timezone is set incorrectly. Last.fm cannot authorise any scrobbling. :(" ) );
1173
LastMessageBox::critical( tr("Error"),
1174
tr( "<p>Last.fm cannot authorise any scrobbling! :("
1175
"<p>It appears your computer disagrees with us about what the time is."
1176
"<p>If you are sure the time is right, check the date is correct and check your "
1177
"timezone is not set to something miles away, like Mars."
1178
"<p>We're sorry about this restriction, but we impose it to help prevent "
1179
"scrobble spamming." ) );
1649
Container::onTrackScrobbled( const TrackInfo& track )
1653
//TODO move into sidebar itself
1655
setTrackScrobbled();
1658
t.setArtist( track.artist() );
1659
t.setTitle( track.track() );
1661
m_sidebar->addRecentlyPlayedTrack( t );
1666
Container::setTrackScrobbled()
1668
ui.songTimeBar->pushClockText( tr( "scrobbled" ), 5 );
1673
1186
Container::showTagDialog( int defaultTagType )
1675
TagDialog d( defaultTagType, this );
1676
d.setSong( m_metaData );
1188
TagDialog d( The::app().currentTrack(), this );
1189
if (defaultTagType >= 0)
1190
d.setTaggingType( defaultTagType );
1820
1325
ui.actionSkip->setEnabled( false );
1821
1326
ui.actionLove->setEnabled( false );
1822
1327
ui.actionBan->setEnabled( false );
1823
ui.actionAddToMyPlaylist->setEnabled( false );
1328
ui.actionPlaylist->setEnabled( false );
1825
1330
ui.songTimeBar->clear();
1826
1331
ui.songTimeBar->setEnabled( false );
1827
ui.songTimeBar->setClockText( "" );
1828
1332
ui.songTimeBar->setText( tr( "Skipping..." ) );
1830
////// HACK to allow us to set the skip flag for the scrobble
1831
// See ScrobbleManager::scrobble()
1832
m_metaData.setUserActionFlag( TrackInfo::Skipped );
1833
m_scrobbler->scrobble( m_metaData );
1841
Container::switchPlayButton( bool enabled )
1845
ui.actionStop->setVisible( false );
1846
ui.actionPlay->setVisible( true );
1848
ui.actionPlay->setShortcut( Qt::Key_Space );
1849
ui.actionStop->setShortcut( QKeySequence() );
1853
ui.actionPlay->setVisible( false );
1854
ui.actionStop->setVisible( true );
1856
ui.actionPlay->setShortcut( QKeySequence() );
1857
ui.actionStop->setShortcut( Qt::Key_Space );
1861
m_sysTrayActionPlay->setVisible( ui.actionPlay->isVisible() );
1862
m_sysTrayActionStop->setVisible( ui.actionStop->isVisible() );
1868
Container::onRadioStateChange( RadioState newState )
1874
case State_Uninitialised:
1880
case State_Handshaking:
1882
statusBar()->showMessage( tr( "Contacting radio service..." ) );
1886
case State_Handshaken:
1888
LOGL( 3, "Radio streamer handshake successful." );
1889
statusBar()->showMessage( tr( "Radio service initialised" ) );
1891
// Play is disabled in ctor so enable it when handshake is complete
1892
// to indicate we can now start radio.
1893
switchPlayButton( true );
1894
ui.actionPlay->setEnabled( true );
1897
m_rest_state_widget->setPlayEnabled( true );
1900
// do we have to load a station since we got started with a cli-arg?
1901
m_iControl->setHandshaked();
1902
if ( m_preloadStation.contains( "lastfm://" ) )
1904
m_radio->playStation( m_preloadStation );
1905
m_preloadStation.clear();
1907
else if ( The::settings().currentUser().resumePlayback() &&
1908
!The::settings().currentUser().resumeStation().isEmpty() )
1910
m_radio->playStation( The::settings().currentUser().resumeStation() );
1914
if ( !The::settings().isFirstRun() )
1915
// Don't do this until here as we won't have received a base host
1917
checkForUpdates( false );
1922
case State_ChangingStation:
1924
statusBar()->showMessage( tr("Starting station %1...").arg( m_radio->stationUrl() ) );
1926
showMetaDataWidget();
1927
m_metaDataExtension->displayTuningIn();
1929
if ( m_radio->stationUrl().isPlaylist() )
1930
ui.stationTimeBar->setText( tr( "Connecting to playlist..." ) );
1932
ui.stationTimeBar->setText( tr( "Starting station..." ) );
1934
ui.stationTimeBar->setClockText( "" );
1935
ui.stationTimeBar->setEnabled( true );
1936
ui.stationTimeBar->setVisible( true );
1938
switchPlayButton( false );
1939
ui.actionStop->setEnabled( true );
1943
case State_FetchingPlaylist:
1945
// Need to apply this again in case we ran out of playlist
1946
switchPlayButton( false );
1947
ui.actionStop->setEnabled( true );
1949
showMetaDataWidget();
1950
m_metaDataExtension->displayTuningIn();
1952
statusBar()->showMessage( tr( "Retrieving playlist..." ) );
1956
case State_FetchingStream:
1958
statusBar()->showMessage( tr( "Retrieving stream..." ) );
1960
// We now have a station name. Bit ugly this, maybe change to a signal?
1961
QString stationText = tr( "Station: %1" ).arg( m_radio->stationName() );
1962
ui.stationTimeBar->setText( stationText );
1964
// Need to apply this again in case we resumed
1965
switchPlayButton( false );
1966
ui.actionStop->setEnabled( true );
1968
ui.stationTimeBar->setEnabled( true );
1969
ui.stationTimeBar->setVisible( true );
1973
case State_StreamFetched:
1975
// Resuming not possible until we've fetched a stream for the first time
1976
// TODO: this is actually bollocks because the stream could have been a preview
1977
ui.actionPlay->setEnabled( true );
1979
m_rest_state_widget->setPlayEnabled( true );
1984
case State_Buffering:
1986
// Status bar message handled in onRadioBuffering
1990
case State_Streaming:
1992
ui.actionSkip->setEnabled( true );
1993
ui.actionBan->setEnabled( true );
1997
case State_Skipping:
1999
ui.actionSkip->setEnabled( false );
2000
ui.actionBan->setEnabled( false );
2004
case State_Stopping:
2006
ui.stationTimeBar->clear();
2007
ui.stationTimeBar->setEnabled( false );
2008
ui.stationTimeBar->setVisible( false );
2010
ui.actionStop->setEnabled( false );
2011
ui.actionSkip->setEnabled( false );
2012
ui.actionBan->setEnabled( false );
2014
ui.stack->setCurrentIndex( 0 );
2020
switchPlayButton( true );
2022
statusBar()->showMessage( "" );
2027
Q_ASSERT( !"Undefined state case reached in onRadioStateChanged!" );
2030
#endif // HIDE_RADIO
1334
// HACK: Only reason it's OK to do this is because the scrobbler will
1335
// make sure to not scrobble duplicates.
1336
MetaData track = The::app().currentTrack();
1337
track.setRatingFlag( TrackInfo::Skipped );
1338
The::app().scrobbler().scrobble( track );
1340
The::radio().skip();
2035
1345
Container::gotoProfile()
2037
QString const user = CUtils::UrlEncodeItem( The::settings().currentUsername() );
2038
QString const dashUrl = "http://" + The::settings().localizedHostName() + "/user/" + user;
1347
QByteArray user = QUrl::toPercentEncoding( The::settings().currentUsername() );
2040
new BrowserThread( dashUrl );
1349
// This will redirect to the language version the user last used.
1350
//FIXME actually it doesn't
1351
QDesktopServices::openUrl( "http://" + UnicornUtils::localizedHostName( The::settings().appLanguage() ) + "/user/" + user );
2253
1638
// The QDesktopServices call doesn't work on Windows
2254
QString file = savePath( "" );
1639
QString file = MooseUtils::logPath( "" );
2255
1640
ShellExecuteW(0, 0, (TCHAR*)file.utf16(), 0, 0, SW_SHOWNORMAL);
2257
QDesktopServices::openUrl( QUrl::fromLocalFile( savePath( "" ) ) );
1642
QDesktopServices::openUrl( QUrl::fromLocalFile( MooseUtils::logPath( "" ) ) );
2263
Container::isTuningInOrPlaying() const //TODO REMOVE
2265
if (!m_metaData.isEmpty())
2271
switch (m_radio->state())
1649
#include <shfolder.h>
1651
Container::onAltShiftP()
1653
wchar_t path_[MAX_PATH];
1654
SHGetFolderPath( NULL, CSIDL_COMMON_APPDATA, 0, NULL, path_ );
1656
QString path = QString::fromUtf16( (const ushort*)path_ );
1657
path += "\\Last.fm\\Client";
1659
ShellExecuteW( 0, 0, (TCHAR*)path.utf16(), 0, 0, SW_SHOWNORMAL );
1665
Container::onAppEvent( int event, const QVariant& data )
1667
//Do not respond to any events if there is no user logged in
2273
case State_Uninitialised:
2274
case State_Handshaking:
2275
case State_Handshaken:
2276
case State_Stopping:
2280
case State_ChangingStation:
2281
case State_FetchingPlaylist:
2282
case State_FetchingStream:
2283
case State_StreamFetched:
2284
case State_Buffering:
2285
case State_Streaming:
2286
case State_Skipping:
1673
case Event::UserChanged:
1675
// we must restore state here as we save it in toggleSidebar in order to get
1676
// round the bug in Qt where saveState for the splitter is lost for hidden widgets
1677
m_sidebarEnabled = !The::user().settings().sidebarEnabled();
1680
ui.restStateWidget->clear();
1681
ui.restStateWidget->updatePlayerNames();
1683
// this call is redundant. Settings's userSettingsChanged will be emitted when switching the user!
1684
// updateUserStuff( The::user().settings() );
1687
statusBar()->showMessage( tr( "Contacting radio service..." ) );
1692
case Event::UserHandshaken:
1694
ui.actionToggleDiscoveryMode->setEnabled( The::user().isSubscriber() );
1695
ui.restStateWidget->setPlayEnabled( true );
1696
statusBar()->showMessage( tr( "Radio service initialised" ) );
1699
if ( !The::settings().isFirstRun() )
1700
// Don't do this until here as we won't have received a base host earlier.
1701
checkForUpdates( false );
1706
case Event::TuningIn:
1708
statusBar()->showMessage( tr("Starting station %1...").arg( The::radio().stationUrl() ) );
1710
showMetaDataWidget();
1711
ui.metaDataWidget->displayTuningIn();
1713
ui.restStateWidget->clear();
1715
if ( The::radio().stationUrl().isPlaylist() )
1716
ui.stationTimeBar->setText( tr( "Connecting to playlist..." ) );
1718
ui.stationTimeBar->setText( tr( "Starting station..." ) );
1720
ui.songTimeBar->clear();
1721
ui.stationTimeBar->setClockText( "" );
1722
ui.stationTimeBar->setEnabled( true );
1723
ui.stationTimeBar->setVisible( true );
1727
case Event::PlaybackStarted:
1729
TrackInfo track = data.value<TrackInfo>();
1731
if (track.source() != TrackInfo::Radio)
1733
// with radio we already changed to this, and there is a noticeable
1734
// gap between tuning in and starting playback so the user may have
1735
// already switched back to the change station tab
1736
showMetaDataWidget();
1741
case Event::TrackChanged:
1743
TrackInfo metadata = data.value<TrackInfo>();
1745
LOGL( 4, "Event::TrackChanged " << metadata.toString() << " " << metadata.durationString() );
1746
ui.songTimeBar->setTrack( metadata );
1747
m_trayIcon->setTrack( metadata );
1749
if ( MooseUtils::scrobblableStatus( metadata ) != MooseEnums::OkToScrobble &&
1750
metadata.source() != TrackInfo::Radio )
1752
ui.actionTag->setEnabled( false );
1753
ui.actionShare->setEnabled( false );
1754
ui.actionLove->setEnabled( false );
1758
// The reason for these extra checks is that one user had
1759
// crashes here (bug #56). This could happen if the player listener
1760
// receives a START, emits a queued signal, then immediately
1761
// receives a STOP. If the first queued signal doesn't get here
1762
// until after the STOP, GetActivePlayer will return NULL.
1763
CPlayerConnection* plyr = The::app().listener().GetActivePlayer();
1766
LOG( 1, "Caught a NULL player in setNewSong, not setting stopwatch" );
1770
StopWatch& watch = plyr->GetStopWatch();
1771
ui.songTimeBar->setStopWatch( &watch );
1772
ui.songTimeBar->setReverse( true );
1774
if ( plyr->IsScrobbled() )
1775
ui.songTimeBar->pushClockText( tr( "scrobbled" ), 5 );
1777
ui.songTimeBar->setClockText( "" );
1780
ui.actionShare->setEnabled( true );
1781
ui.actionTag->setEnabled( true );
1782
ui.actionPlaylist->setEnabled( true );
1783
ui.actionLove->setEnabled( true );
1784
ui.songTimeBar->setEnabled( true );
1786
// Clear any status messages on the start of a new track or it will look odd
1787
if ( metadata.source() != TrackInfo::Radio )
1789
statusBar()->clearMessage();
1793
ui.metaDataWidget->setTrackInfo( metadata );
1794
updateWindowTitle( metadata );
1798
case Event::TrackMetaDataAvailable:
1800
MetaData metadata = data.value<MetaData>();
1802
updateWindowTitle( metadata );
1803
ui.metaDataWidget->setTrackMetaData( metadata );
1805
LOGL( 4, "Event::TrackMetaDataAvailable " << metadata.toString() << " " << metadata.durationString() );
1806
ui.songTimeBar->setTrack( metadata );
1810
case Event::ArtistMetaDataAvailable:
1812
ui.metaDataWidget->setArtistMetaData( data.value<MetaData>() );
1816
case Event::PlaybackEnded:
1818
// we disable this sometimes from ChangeStationRequest results
1819
// but enable it again when we stop
1820
ui.actionToggleDiscoveryMode->setEnabled( The::user().isSubscriber() );
1822
statusBar()->clearMessage();
1825
ui.metaDataWidget->displayNotListening();
1828
ui.actionShare->setEnabled( false );
1829
ui.actionTag->setEnabled( false );
1830
ui.actionPlaylist->setEnabled( false );
1831
ui.actionLove->setEnabled( false );
1833
ui.songTimeBar->setEnabled( false );
1834
ui.songTimeBar->setClockText( "" );
1835
ui.songTimeBar->setClockEnabled( false );
1836
ui.songTimeBar->setText( "" );
1838
updateWindowTitle( MetaData() );
1839
m_trayIcon->setTrack( TrackInfo() );
1843
case Event::ScrobblePointReached:
1845
TrackInfo const track = data.value<TrackInfo>();
1847
ui.songTimeBar->pushClockText( tr("scrobbled"), 5 );
1850
t.setArtist( track.artist() );
1851
t.setTitle( track.track() );
1853
ui.sidebar->addRecentlyPlayedTrack( t );
1857
case Event::MediaDeviceTrackScrobbled:
1859
TrackInfo const track = data.value<TrackInfo>();
1862
t.setArtist( track.artist() );
1863
t.setTitle( track.track() );
1865
ui.sidebar->addRecentlyPlayedTrack( t );
1869
case Event::PlaybackPaused:
1871
qDebug() << "Paused";
1875
case Event::PlaybackUnpaused:
1877
qDebug() << "Unpaused";
2290
return false; //--warning for visual studio
2294
1885
Container::restoreWindow()
1893
/** here we control the radio specific ui components */
1895
Container::onRadioStateChanged( RadioState newState )
1897
int const state = (int)newState; //use an int so gcc doesn't give us a warning
1903
ui.stationTimeBar->clear();
1904
ui.stationTimeBar->setEnabled( false );
1905
ui.stationTimeBar->hide();
1908
case State_FetchingStream:
1909
// We now have a station name.
1910
ui.stationTimeBar->setText( tr("Station: %1").arg( The::radio().stationName() ) );
1911
ui.stationTimeBar->setEnabled( true );
1912
ui.stationTimeBar->show();
1914
statusBar()->showMessage( tr( "Retrieving stream..." ) );
1917
case State_FetchingPlaylist:
1918
ui.metaDataWidget->displayTuningIn();
1920
statusBar()->showMessage( tr( "Retrieving playlist..." ) );
1927
case State_Streaming:
1928
ui.actionSkip->setEnabled( true );
1929
ui.actionBan->setEnabled( true );
1933
ui.actionSkip->setEnabled( false );
1934
ui.actionBan->setEnabled( false );
1938
// disable actions during certain transitionary, etc. states
1941
case State_Uninitialised:
1942
case State_Skipping:
1943
case State_Stopping:
1944
case State_Handshaking:
1945
ui.actionPlay->setEnabled( false );
1946
ui.actionStop->setEnabled( false );
1950
ui.actionPlay->setEnabled( true );
1951
ui.actionStop->setEnabled( true );
1955
// set the play/stop actions to the correct states
1958
case State_Uninitialised:
1959
case State_Handshaking:
1960
case State_Handshaken:
1961
case State_Stopping:
1963
ui.actionPlay->setVisible( true );
1964
ui.actionPlay->setShortcut( Qt::Key_Space );
1965
ui.actionStop->setVisible( false );
1966
ui.actionStop->setShortcut( QKeySequence() );
1970
ui.actionPlay->setVisible( false );
1971
ui.actionPlay->setShortcut( QKeySequence() );
1972
ui.actionStop->setVisible( true );
1973
ui.actionStop->setShortcut( Qt::Key_Space );
1977
#endif // HIDE_RADIO
1981
std::vector<CPluginInfo>&
1982
Container::getPluginList()
1984
return m_updater->getPluginList();