1
/***************************************************************************
2
 *   Copyright (C) 2004 by Max Howell <max.howell@methylblue.com>          *
3
 *   Copyright (C) 2008 by Mark Kretschmann <kretschmann@kde.org>          *
4
 *                                                                         *
5
 *   This program is free software; you can redistribute it and/or modify  *
6
 *   it under the terms of the GNU General Public License as published by  *
7
 *   the Free Software Foundation; either version 2 of the License, or     *
8
 *   (at your option) any later version.                                   *
9
 *                                                                         *
10
 ***************************************************************************/
11
12
#include "ActionClasses.h"
13
14
#include <config-amarok.h>
15
16
#include "Amarok.h"
17
#include "App.h"
18
#include "Debug.h"
19
#include "EngineController.h"
20
#include "MainWindow.h"
21
#include "statusbar/StatusBar.h"
22
#include "amarokconfig.h"
23
#include "covermanager/CoverManager.h"
24
#include "playlist/PlaylistActions.h"
25
26
#include <KAuthorized>
27
#include <KHelpMenu>
28
#include <KLocale>
29
#include <KToolBar>
30
31
32
extern KAboutData aboutData;
33
34
namespace Amarok
35
{
36
    bool repeatNone()     { return AmarokConfig::repeat() == AmarokConfig::EnumRepeat::Off; }
37
    bool repeatTrack()    { return AmarokConfig::repeat() == AmarokConfig::EnumRepeat::Track; }
38
    bool repeatAlbum()    { return AmarokConfig::repeat() == AmarokConfig::EnumRepeat::Album; }
39
    bool repeatPlaylist() { return AmarokConfig::repeat() == AmarokConfig::EnumRepeat::Playlist; }
40
    bool randomOff()      { return AmarokConfig::randomMode() == AmarokConfig::EnumRandomMode::Off; }
41
    bool randomTracks()   { return AmarokConfig::randomMode() == AmarokConfig::EnumRandomMode::Tracks; }
42
    bool randomAlbums()   { return AmarokConfig::randomMode() == AmarokConfig::EnumRandomMode::Albums; }
43
    bool favorNone()      { return AmarokConfig::favorTracks() == AmarokConfig::EnumFavorTracks::Off; }
44
    bool favorScores()    { return AmarokConfig::favorTracks() == AmarokConfig::EnumFavorTracks::HigherScores; }
45
    bool favorRatings()   { return AmarokConfig::favorTracks() == AmarokConfig::EnumFavorTracks::HigherRatings; }
46
    bool favorLastPlay()  { return AmarokConfig::favorTracks() == AmarokConfig::EnumFavorTracks::LessRecentlyPlayed; }
47
48
    bool entireAlbums()   { return repeatAlbum()  || randomAlbums(); }
49
    bool repeatEnabled()  { return repeatTrack()  || repeatAlbum() || repeatPlaylist(); }
50
    bool randomEnabled()  { return randomTracks() || randomAlbums(); }
51
}
52
53
using namespace Amarok;
54
55
KHelpMenu *Menu::s_helpMenu = 0;
56
57
static void
58
safePlug( KActionCollection *ac, const char *name, QWidget *w )
59
{
60
    if( ac )
61
    {
62
        KAction *a = (KAction*) ac->action( name );
63
        if( a && w ) w->addAction( a );
64
    }
65
}
66
67
68
//////////////////////////////////////////////////////////////////////////////////////////
69
// MenuAction && Menu
70
// KActionMenu doesn't work very well, so we derived our own
71
//////////////////////////////////////////////////////////////////////////////////////////
72
73
MenuAction::MenuAction( KActionCollection *ac, QObject *parent )
74
  : KAction( parent )
75
{
76
    setText(i18n( "Amarok Menu" ));
77
    ac->addAction("amarok_menu", this);
78
    setShortcutConfigurable ( false ); //FIXME disabled as it doesn't work, should use QCursor::pos()
79
}
80
81
82
Menu* Menu::s_instance = 0;
83
84
Menu::Menu( QWidget* parent )
85
    : KMenu( parent )
86
{
87
    s_instance = this;
88
89
    KActionCollection *ac = Amarok::actionCollection();
90
91
    safePlug( ac, "repeat", this );
92
    safePlug( ac, "random_mode", this );
93
94
    addSeparator();
95
96
    safePlug( ac, "playlist_playmedia", this );
97
#if 0
98
    // Audio CD is not currently supported
99
    safePlug( ac, "play_audiocd", this );
100
#endif
101
102
    addSeparator();
103
104
    safePlug( ac, "cover_manager", this );
105
    safePlug( ac, "queue_manager", this );
106
    safePlug( ac, "equalizer", this );
107
    safePlug( ac, "script_manager", this );
108
109
    addSeparator();
110
111
    safePlug( ac, "update_collection", this );
112
    safePlug( ac, "rescan_collection", this );
113
114
#ifndef Q_WS_MAC
115
    addSeparator();
116
117
    safePlug( ac, KStandardAction::name(KStandardAction::ShowMenubar), this );
118
#endif
119
120
    addSeparator();
121
122
    safePlug( ac, KStandardAction::name(KStandardAction::ConfigureToolbars), this );
123
    safePlug( ac, KStandardAction::name(KStandardAction::KeyBindings), this );
124
//    safePlug( ac, "options_configure_globals", this ); //we created this one
125
    safePlug( ac, KStandardAction::name(KStandardAction::Preferences), this );
126
127
    addSeparator();
128
129
    addMenu( helpMenu( this ) );
130
131
    addSeparator();
132
133
    safePlug( ac, KStandardAction::name(KStandardAction::Quit), this );
134
}
135
136
Menu*
137
Menu::instance()
138
{
139
    return s_instance ? s_instance : new Menu( The::mainWindow() );
140
}
141
142
KMenu*
143
Menu::helpMenu( QWidget *parent ) //STATIC
144
{
145
    if ( s_helpMenu == 0 )
146
        s_helpMenu = new KHelpMenu( parent, &aboutData, Amarok::actionCollection() );
147
148
    KMenu* menu = s_helpMenu->menu();
149
150
151
    // NOTE: We hide the "Amarok Handbook" entry until the handbook actually exists (WIP)
152
    s_helpMenu->action( KHelpMenu::menuHelpContents )->setVisible( false );
153
154
    // NOTE: "What's This" isn't currently defined for anything in Amarok, so let's remove that too
155
    s_helpMenu->action( KHelpMenu::menuWhatsThis )->setVisible( false );
156
157
158
    return menu;
159
}
160
161
//////////////////////////////////////////////////////////////////////////////////////////
162
// PlayPauseAction
163
//////////////////////////////////////////////////////////////////////////////////////////
164
165
PlayPauseAction::PlayPauseAction( KActionCollection *ac, QObject *parent )
166
        : KToggleAction( parent )
167
        , EngineObserver( The::engineController() )
168
{
169
    ac->addAction( "play_pause", this );
170
    setText( i18n( "Play/Pause" ) );
171
    setShortcut( Qt::Key_Space );
172
    setGlobalShortcut( KShortcut( Qt::META + Qt::Key_C ) );
173
    PERF_LOG( "PlayPauseAction: before engineStateChanged" )
174
    engineStateChanged( The::engineController()->state() );
175
    PERF_LOG( "PlayPauseAction: after engineStateChanged" )
176
177
    connect( this, SIGNAL(triggered()), The::engineController(), SLOT(playPause()) );
178
}
179
180
void
181
PlayPauseAction::engineStateChanged( Phonon::State state,  Phonon::State oldState )
182
{
183
    DEBUG_BLOCK
184
    debug() << "NEWSTATE: " << state << "OLDSTATE: " << oldState;
185
    switch( state )
186
    {
187
    case Phonon::PlayingState:
188
        setChecked( false );
189
        setIcon( KIcon("media-playback-pause-amarok") );
190
        break;
191
    case Phonon::PausedState:
192
        setChecked( true );
193
        setIcon( KIcon("media-playback-start-amarok") );
194
        break;
195
    case Phonon::StoppedState:
196
    case Phonon::LoadingState:
197
        setChecked( false );
198
        setIcon( KIcon("media-playback-start-amarok") );
199
        break;
200
    case Phonon::ErrorState:
201
    case Phonon::BufferingState:
202
        break;
203
    }
204
}
205
206
//////////////////////////////////////////////////////////////////////////////////////////
207
// ToggleAction
208
//////////////////////////////////////////////////////////////////////////////////////////
209
210
ToggleAction::ToggleAction( const QString &text, void ( *f ) ( bool ), KActionCollection* const ac, const char *name, QObject *parent )
211
        : KToggleAction( parent )
212
        , m_function( f )
213
{
214
    setText(text);
215
    ac->addAction(name, this);
216
}
217
218
void ToggleAction::setChecked( bool b )
219
{
220
    const bool announce = b != isChecked();
221
222
    m_function( b );
223
    KToggleAction::setChecked( b );
224
    AmarokConfig::self()->writeConfig(); //So we don't lose the setting when crashing
225
    if( announce ) emit toggled( b ); //KToggleAction doesn't do this for us. How gay!
226
}
227
228
void ToggleAction::setEnabled( bool b )
229
{
230
    const bool announce = b != isEnabled();
231
232
    if( !b )
233
        setChecked( false );
234
    KToggleAction::setEnabled( b );
235
    AmarokConfig::self()->writeConfig(); //So we don't lose the setting when crashing
236
    if( announce ) emit QAction::triggered( b );
237
}
238
239
//////////////////////////////////////////////////////////////////////////////////////////
240
// SelectAction
241
//////////////////////////////////////////////////////////////////////////////////////////
242
243
SelectAction::SelectAction( const QString &text, void ( *f ) ( int ), KActionCollection* const ac, const char *name, QObject *parent )
244
        : KSelectAction( parent )
245
        , m_function( f )
246
{
247
    PERF_LOG( "In SelectAction" );
248
    setText(text);
249
    ac->addAction(name, this);
250
}
251
252
void SelectAction::setCurrentItem( int n )
253
{
254
    const bool announce = n != currentItem();
255
256
    debug() << "setCurrentItem: " << n;
257
258
    m_function( n );
259
    KSelectAction::setCurrentItem( n );
260
    AmarokConfig::self()->writeConfig(); //So we don't lose the setting when crashing
261
    if( announce ) emit triggered( n );
262
}
263
264
void SelectAction::actionTriggered( QAction *a )
265
{
266
    m_function( currentItem() );
267
    AmarokConfig::self()->writeConfig();
268
    KSelectAction::actionTriggered( a );
269
}
270
271
void SelectAction::setEnabled( bool b )
272
{
273
    const bool announce = b != isEnabled();
274
275
    if( !b )
276
        setCurrentItem( 0 );
277
    KSelectAction::setEnabled( b );
278
    AmarokConfig::self()->writeConfig(); //So we don't lose the setting when crashing
279
    if( announce ) emit QAction::triggered( b );
280
}
281
282
void SelectAction::setIcons( QStringList icons )
283
{
284
    m_icons = icons;
285
    foreach( QAction *a, selectableActionGroup()->actions() )
286
    {
287
        a->setIcon( KIcon(icons.takeFirst()) );
288
    }
289
}
290
291
QStringList SelectAction::icons() const { return m_icons; }
292
293
QString SelectAction::currentIcon() const
294
{
295
    if( m_icons.count() )
296
        return m_icons.at( currentItem() );
297
    return QString();
298
}
299
300
QString SelectAction::currentText() const {
301
    return KSelectAction::currentText() + "<br /><br />" + i18n("Click to change");
302
}
303
304
//////////////////////////////////////////////////////////////////////////////////////////
305
// RandomAction
306
//////////////////////////////////////////////////////////////////////////////////////////
307
RandomAction::RandomAction( KActionCollection *ac, QObject *parent ) :
308
    SelectAction( i18n( "Ra&ndom" ), &AmarokConfig::setRandomMode, ac, "random_mode", parent )
309
{
310
    QStringList items;
311
    items << i18nc( "State, as in disabled", "&Off" )
312
          << i18nc( "Items, as in music"   , "&Tracks" )
313
          << i18n( "&Albums" );
314
    setItems( items );
315
316
    setCurrentItem( AmarokConfig::randomMode() );
317
318
    QStringList icons;
319
    icons << "media-playlist-shuffle-off-amarok"
320
          << "media-playlist-shuffle-amarok"
321
          << "media-album-shuffle-amarok";
322
    setIcons( icons );
323
324
    connect( this, SIGNAL( triggered( int ) ), The::playlistActions(), SLOT( playlistModeChanged() ) );
325
}
326
327
void
328
RandomAction::setCurrentItem( int n )
329
{
330
    // Porting
331
    //if( KAction *a = parentCollection()->action( "favor_tracks" ) )
332
    //    a->setEnabled( n );
333
    SelectAction::setCurrentItem( n );
334
}
335
336
337
//////////////////////////////////////////////////////////////////////////////////////////
338
// FavorAction
339
//////////////////////////////////////////////////////////////////////////////////////////
340
FavorAction::FavorAction( KActionCollection *ac, QObject *parent ) :
341
    SelectAction( i18n( "&Favor" ), &AmarokConfig::setFavorTracks, ac, "favor_tracks", parent )
342
{
343
    setItems( QStringList() << i18nc( "State, as in disabled", "Off" )
344
                            << i18n( "Higher &Scores" )
345
                            << i18n( "Higher &Ratings" )
346
                            << i18n( "Not Recently &Played" ) );
347
348
    setCurrentItem( AmarokConfig::favorTracks() );
349
    setEnabled( AmarokConfig::randomMode() );
350
}
351
352
//////////////////////////////////////////////////////////////////////////////////////////
353
// RepeatAction
354
//////////////////////////////////////////////////////////////////////////////////////////
355
RepeatAction::RepeatAction( KActionCollection *ac, QObject *parent ) :
356
    SelectAction( i18n( "&Repeat" ), &AmarokConfig::setRepeat, ac, "repeat", parent )
357
{
358
    setItems( QStringList() << i18nc( "State, as in, disabled", "&Off" ) << i18nc( "Item, as in, music", "&Track" )
359
                            << i18n( "&Album" ) << i18n( "&Playlist" ) );
360
    setIcons( QStringList() << "media-playlist-repeat-off-amarok" << "media-track-repeat-amarok" << "media-album-repeat-amarok" << "media-playlist-repeat-amarok" );
361
    setCurrentItem( AmarokConfig::repeat() );
362
363
    connect( this, SIGNAL( triggered( int ) ), The::playlistActions(), SLOT( playlistModeChanged() ) );
364
}
365
366
//////////////////////////////////////////////////////////////////////////////////////////
367
// ReplayGainModeAction
368
//////////////////////////////////////////////////////////////////////////////////////////
369
ReplayGainModeAction::ReplayGainModeAction( KActionCollection *ac, QObject *parent ) :
370
    SelectAction( i18n( "&Replay Gain Mode" ), &AmarokConfig::setReplayGainMode, ac, "replay_gain_mode", parent )
371
{
372
    setItems( QStringList() << i18nc( "State, as in, disabled", "&Off" ) << i18nc( "Item, as in, music", "&Track" )
373
                            << i18n( "&Album" ) );
374
    //setIcons( QStringList() << "media-playlist-replaygain-off-amarok" << "media-track-replaygain-amarok" << "media-album-replaygain-amarok" );
375
    setCurrentItem( AmarokConfig::replayGainMode() );
376
}
377
378
//////////////////////////////////////////////////////////////////////////////////////////
379
// BurnMenuAction
380
//////////////////////////////////////////////////////////////////////////////////////////
381
BurnMenuAction::BurnMenuAction( KActionCollection *ac, QObject *parent )
382
  : KAction( parent )
383
{
384
    setText(i18n( "Burn" ));
385
    ac->addAction("burn_menu", this);
386
}
387
388
QWidget*
389
BurnMenuAction::createWidget( QWidget *w )
390
{
391
    KToolBar *bar = dynamic_cast<KToolBar*>(w);
392
393
    if( bar && KAuthorized::authorizeKAction( objectName() ) )
394
    {
395
        //const int id = KAction::getToolButtonID();
396
397
        //addContainer( bar, id );
398
        w->addAction( this );
399
        connect( bar, SIGNAL( destroyed() ), SLOT( slotDestroyed() ) );
400
401
        //bar->insertButton( QString::null, id, true, i18n( "Burn" ), index );
402
403
        //KToolBarButton* button = bar->getButton( id );
404
        //button->setPopup( Amarok::BurnMenu::instance() );
405
        //button->setObjectName( "toolbutton_burn_menu" );
406
        //button->setIcon( "k3b" );
407
408
        //return associatedWidgets().count() - 1;
409
        return 0;
410
    }
411
    //else return -1;
412
    else return 0;
413
}
414
415
416
BurnMenu* BurnMenu::s_instance = 0;
417
418
BurnMenu::BurnMenu( QWidget* parent )
419
    : KMenu( parent )
420
{
421
    s_instance = this;
422
423
    addAction( i18n("Current Playlist"), this, SLOT( slotBurnCurrentPlaylist() ) );
424
    addAction( i18n("Selected Tracks"), this, SLOT( slotBurnSelectedTracks() ) );
425
    //TODO add "album" and "all tracks by artist"
426
}
427
428
KMenu*
429
BurnMenu::instance()
430
{
431
    return s_instance ? s_instance : new BurnMenu( The::mainWindow() );
432
}
433
434
void
435
BurnMenu::slotBurnCurrentPlaylist() //SLOT
436
{
437
    //K3bExporter::instance()->exportCurrentPlaylist();
438
}
439
440
void
441
BurnMenu::slotBurnSelectedTracks() //SLOT
442
{
443
    //K3bExporter::instance()->exportSelectedTracks();
444
}
445
446
447
//////////////////////////////////////////////////////////////////////////////////////////
448
// StopAction
449
//////////////////////////////////////////////////////////////////////////////////////////
450
451
StopAction::StopAction( KActionCollection *ac, QObject *parent )
452
  : KAction( parent )
453
  , EngineObserver( The::engineController() )
454
{
455
    ac->addAction( "stop", this );
456
    setText( i18n( "Stop" ) );
457
    setIcon( KIcon("media-playback-stop-amarok") );
458
    setGlobalShortcut( KShortcut( Qt::META + Qt::Key_V ) );
459
    connect( this, SIGNAL( triggered() ), The::engineController(), SLOT( stop() ) );
460
    setEnabled( false );  // Disable action at startup
461
}
462
463
void
464
StopAction::engineStateChanged( Phonon::State state,  Phonon::State /*oldState*/ )
465
{
466
    switch( state ) {
467
    case Phonon::PlayingState:
468
    case Phonon::PausedState:
469
        setEnabled( true );
470
        break;
471
    case Phonon::StoppedState:
472
    case Phonon::LoadingState:
473
        setDisabled( true );
474
        break;
475
    case Phonon::ErrorState:
476
    case Phonon::BufferingState:
477
        break;
478
    }
479
}
480
481
482
#include "ActionClasses.moc"