File indexing completed on 2024-04-21 04:47:48
0001 /**************************************************************************************** 0002 * Copyright (c) 2004 Max Howell <max.howell@methylblue.com> * 0003 * Copyright (c) 2008 Mark Kretschmann <kretschmann@kde.org> * 0004 * Copyright (c) 2009 Artur Szymiec <artur.szymiec@gmail.com> * 0005 * * 0006 * This program is free software; you can redistribute it and/or modify it under * 0007 * the terms of the GNU General Public License as published by the Free Software * 0008 * Foundation; either version 2 of the License, or (at your option) any later * 0009 * version. * 0010 * * 0011 * This program is distributed in the hope that it will be useful, but WITHOUT ANY * 0012 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * 0013 * PARTICULAR PURPOSE. See the GNU General Public License for more details. * 0014 * * 0015 * You should have received a copy of the GNU General Public License along with * 0016 * this program. If not, see <http://www.gnu.org/licenses/>. * 0017 ****************************************************************************************/ 0018 0019 #define DEBUG_PREFIX "ActionClasses" 0020 0021 #include "ActionClasses.h" 0022 0023 #include "App.h" 0024 #include "EngineController.h" 0025 #include "KNotificationBackend.h" 0026 #include "MainWindow.h" 0027 #include "aboutdialog/OcsData.h" 0028 #include "amarokconfig.h" 0029 #include <config.h> 0030 #include "core/support/Amarok.h" 0031 #include "core/support/Debug.h" 0032 #include "playlist/PlaylistActions.h" 0033 #include "playlist/PlaylistModelStack.h" 0034 #include "widgets/Osd.h" 0035 0036 #include <QKeySequence> 0037 0038 #include <KAuthorized> 0039 #include <KHelpMenu> 0040 #include <KLocalizedString> 0041 #include <KToolBar> 0042 #include <KGlobalAccel> 0043 0044 extern OcsData ocsData; 0045 0046 namespace Amarok 0047 { 0048 bool favorNone() { return AmarokConfig::favorTracks() == AmarokConfig::EnumFavorTracks::Off; } 0049 bool favorScores() { return AmarokConfig::favorTracks() == AmarokConfig::EnumFavorTracks::HigherScores; } 0050 bool favorRatings() { return AmarokConfig::favorTracks() == AmarokConfig::EnumFavorTracks::HigherRatings; } 0051 bool favorLastPlay() { return AmarokConfig::favorTracks() == AmarokConfig::EnumFavorTracks::LessRecentlyPlayed; } 0052 0053 0054 bool entireAlbums() { return AmarokConfig::trackProgression() == AmarokConfig::EnumTrackProgression::RepeatAlbum || 0055 AmarokConfig::trackProgression() == AmarokConfig::EnumTrackProgression::RandomAlbum; } 0056 0057 bool repeatEnabled() { return AmarokConfig::trackProgression() == AmarokConfig::EnumTrackProgression::RepeatTrack || 0058 AmarokConfig::trackProgression() == AmarokConfig::EnumTrackProgression::RepeatAlbum || 0059 AmarokConfig::trackProgression() == AmarokConfig::EnumTrackProgression::RepeatPlaylist; } 0060 0061 bool randomEnabled() { return AmarokConfig::trackProgression() == AmarokConfig::EnumTrackProgression::RandomTrack || 0062 AmarokConfig::trackProgression() == AmarokConfig::EnumTrackProgression::RandomAlbum; } 0063 } 0064 0065 using namespace Amarok; 0066 0067 KHelpMenu *Menu::s_helpMenu = nullptr; 0068 0069 static void 0070 safePlug( KActionCollection *ac, const char *name, QWidget *w ) 0071 { 0072 if( ac ) 0073 { 0074 QAction *a = (QAction*) ac->action( name ); 0075 if( a && w ) w->addAction( a ); 0076 } 0077 } 0078 0079 0080 ////////////////////////////////////////////////////////////////////////////////////////// 0081 // MenuAction && Menu 0082 // KActionMenu doesn't work very well, so we derived our own 0083 ////////////////////////////////////////////////////////////////////////////////////////// 0084 0085 MenuAction::MenuAction( KActionCollection *ac, QObject *parent ) 0086 : QAction( parent ) 0087 { 0088 setText(i18n( "Amarok Menu" )); 0089 ac->addAction(QStringLiteral("amarok_menu"), this); 0090 setShortcutConfigurable ( false ); //FIXME disabled as it doesn't work, should use QCursor::pos() 0091 } 0092 0093 void MenuAction::setShortcutConfigurable(bool b) 0094 { 0095 setProperty("isShortcutConfigurable", b); 0096 } 0097 0098 Menu* Menu::s_instance = nullptr; 0099 0100 Menu::Menu( QWidget* parent ) 0101 : QMenu( parent ) 0102 { 0103 s_instance = this; 0104 0105 KActionCollection *ac = Amarok::actionCollection(); 0106 0107 safePlug( ac, "repeat", this ); 0108 safePlug( ac, "random_mode", this ); 0109 0110 addSeparator(); 0111 0112 safePlug( ac, "playlist_playmedia", this ); 0113 0114 addSeparator(); 0115 0116 safePlug( ac, "cover_manager", this ); 0117 safePlug( ac, "queue_manager", this ); 0118 safePlug( ac, "script_manager", this ); 0119 0120 addSeparator(); 0121 0122 safePlug( ac, "update_collection", this ); 0123 safePlug( ac, "rescan_collection", this ); 0124 0125 #ifndef Q_WS_MAC 0126 addSeparator(); 0127 0128 safePlug( ac, KStandardAction::name(KStandardAction::ShowMenubar), this ); 0129 #endif 0130 0131 addSeparator(); 0132 0133 safePlug( ac, KStandardAction::name(KStandardAction::ConfigureToolbars), this ); 0134 safePlug( ac, KStandardAction::name(KStandardAction::KeyBindings), this ); 0135 // safePlug( ac, "options_configure_globals", this ); //we created this one 0136 safePlug( ac, KStandardAction::name(KStandardAction::Preferences), this ); 0137 0138 addSeparator(); 0139 0140 addMenu( helpMenu( this ) ); 0141 0142 addSeparator(); 0143 0144 safePlug( ac, KStandardAction::name(KStandardAction::Quit), this ); 0145 } 0146 0147 Menu* 0148 Menu::instance() 0149 { 0150 return s_instance ? s_instance : new Menu( The::mainWindow() ); 0151 } 0152 0153 QMenu* 0154 Menu::helpMenu( QWidget *parent ) //STATIC 0155 { 0156 if ( s_helpMenu == nullptr ) 0157 s_helpMenu = new KHelpMenu( parent, KAboutData::applicationData(), Amarok::actionCollection() ); 0158 0159 QMenu* menu = s_helpMenu->menu(); 0160 0161 // "What's This" isn't currently defined for anything in Amarok, so let's remove it 0162 s_helpMenu->action( KHelpMenu::menuWhatsThis )->setVisible( false ); 0163 0164 // Hide the default "About App" dialog, as we replace it with a custom one 0165 s_helpMenu->action( KHelpMenu::menuAboutApp )->setVisible( false ); 0166 0167 return menu; 0168 } 0169 0170 ////////////////////////////////////////////////////////////////////////////////////////// 0171 // PlayPauseAction 0172 ////////////////////////////////////////////////////////////////////////////////////////// 0173 0174 PlayPauseAction::PlayPauseAction( KActionCollection *ac, QObject *parent ) 0175 : KToggleAction( parent ) 0176 { 0177 0178 ac->addAction( QStringLiteral("play_pause"), this ); 0179 setText( i18n( "Play/Pause" ) ); 0180 setShortcut( Qt::Key_Space ); 0181 KGlobalAccel::setGlobalShortcut( this, QKeySequence() ); 0182 0183 EngineController *engine = The::engineController(); 0184 0185 if( engine->isPaused() ) 0186 paused(); 0187 else if( engine->isPlaying() ) 0188 playing(); 0189 else 0190 stopped(); 0191 0192 connect( this, &PlayPauseAction::triggered, 0193 engine, &EngineController::playPause ); 0194 0195 connect( engine, &EngineController::stopped, 0196 this, &PlayPauseAction::stopped ); 0197 connect( engine, &EngineController::paused, 0198 this, &PlayPauseAction::paused ); 0199 connect( engine, &EngineController::trackPlaying, 0200 this, &PlayPauseAction::playing ); 0201 } 0202 0203 void 0204 PlayPauseAction::stopped() 0205 { 0206 setChecked( false ); 0207 setIcon( QIcon::fromTheme(QStringLiteral("media-playback-start-amarok")) ); 0208 } 0209 0210 void 0211 PlayPauseAction::paused() 0212 { 0213 setChecked( true ); 0214 setIcon( QIcon::fromTheme(QStringLiteral("media-playback-start-amarok")) ); 0215 } 0216 0217 void 0218 PlayPauseAction::playing() 0219 { 0220 setChecked( false ); 0221 setIcon( QIcon::fromTheme(QStringLiteral("media-playback-pause-amarok")) ); 0222 } 0223 0224 0225 ////////////////////////////////////////////////////////////////////////////////////////// 0226 // ToggleAction 0227 ////////////////////////////////////////////////////////////////////////////////////////// 0228 0229 ToggleAction::ToggleAction( const QString &text, void ( *f ) ( bool ), KActionCollection* const ac, const char *name, QObject *parent ) 0230 : KToggleAction( parent ) 0231 , m_function( f ) 0232 { 0233 setText(text); 0234 ac->addAction(name, this); 0235 } 0236 0237 void ToggleAction::setChecked( bool b ) 0238 { 0239 const bool announce = b != isChecked(); 0240 0241 m_function( b ); 0242 KToggleAction::setChecked( b ); 0243 AmarokConfig::self()->save(); //So we don't lose the setting when crashing 0244 if( announce ) Q_EMIT toggled( b ); //KToggleAction doesn't do this for us. How gay! 0245 } 0246 0247 void ToggleAction::setEnabled( bool b ) 0248 { 0249 const bool announce = b != isEnabled(); 0250 0251 KToggleAction::setEnabled( b ); 0252 AmarokConfig::self()->save(); //So we don't lose the setting when crashing 0253 if( announce ) Q_EMIT QAction::triggered( b ); 0254 } 0255 0256 ////////////////////////////////////////////////////////////////////////////////////////// 0257 // SelectAction 0258 ////////////////////////////////////////////////////////////////////////////////////////// 0259 0260 SelectAction::SelectAction( const QString &text, void ( *f ) ( int ), KActionCollection* const ac, const char *name, QObject *parent ) 0261 : KSelectAction( parent ) 0262 , m_function( f ) 0263 { 0264 PERF_LOG( "In SelectAction" ); 0265 setText(text); 0266 ac->addAction(name, this); 0267 } 0268 0269 void SelectAction::setCurrentItem( int n ) 0270 { 0271 const bool announce = n != currentItem(); 0272 0273 debug() << "setCurrentItem: " << n; 0274 0275 m_function( n ); 0276 KSelectAction::setCurrentItem( n ); 0277 AmarokConfig::self()->save(); //So we don't lose the setting when crashing 0278 if( announce ) Q_EMIT indexTriggered( n ); 0279 } 0280 0281 void SelectAction::actionTriggered( QAction *a ) 0282 { 0283 m_function( currentItem() ); 0284 AmarokConfig::self()->save(); 0285 KSelectAction::actionTriggered( a ); 0286 } 0287 0288 void SelectAction::setEnabled( bool b ) 0289 { 0290 const bool announce = b != isEnabled(); 0291 0292 KSelectAction::setEnabled( b ); 0293 AmarokConfig::self()->save(); //So we don't lose the setting when crashing 0294 if( announce ) Q_EMIT QAction::triggered( b ); 0295 } 0296 0297 void SelectAction::setIcons( QStringList icons ) 0298 { 0299 m_icons = icons; 0300 foreach( QAction *a, selectableActionGroup()->actions() ) 0301 { 0302 a->setIcon( QIcon::fromTheme(icons.takeFirst()) ); 0303 } 0304 } 0305 0306 QStringList SelectAction::icons() const { return m_icons; } 0307 0308 QString SelectAction::currentIcon() const 0309 { 0310 if( m_icons.count() ) 0311 return m_icons.at( currentItem() ); 0312 return QString(); 0313 } 0314 0315 QString SelectAction::currentText() const { 0316 return KSelectAction::currentText() + "<br /><br />" + i18n("Click to change"); 0317 } 0318 0319 0320 void 0321 RandomAction::setCurrentItem( int n ) 0322 { 0323 // Porting 0324 //if( QAction *a = parentCollection()->action( "favor_tracks" ) ) 0325 // a->setEnabled( n ); 0326 SelectAction::setCurrentItem( n ); 0327 } 0328 0329 ////////////////////////////////////////////////////////////////////////////////////////// 0330 // ReplayGainModeAction 0331 ////////////////////////////////////////////////////////////////////////////////////////// 0332 ReplayGainModeAction::ReplayGainModeAction( KActionCollection *ac, QObject *parent ) : 0333 SelectAction( i18n( "&Replay Gain Mode" ), &AmarokConfig::setReplayGainMode, ac, "replay_gain_mode", parent ) 0334 { 0335 setItems( QStringList() << i18nc( "Replay Gain state, as in, disabled", "&Off" ) 0336 << i18nc( "Item, as in, music", "&Track" ) 0337 << i18n( "&Album" ) ); 0338 EngineController *engine = EngineController::instance(); 0339 Q_ASSERT( engine ); 0340 if( engine->supportsGainAdjustments() ) 0341 setCurrentItem( AmarokConfig::replayGainMode() ); 0342 else 0343 { 0344 // Note: it would be nice to set a tooltip that would explain why this is disabled 0345 // to users, but tooltips aren't shown in menu anyway :-( 0346 actions().at( 1 )->setEnabled( false ); 0347 actions().at( 2 )->setEnabled( false ); 0348 } 0349 } 0350 0351 ////////////////////////////////////////////////////////////////////////////////////////// 0352 // BurnMenuAction 0353 ////////////////////////////////////////////////////////////////////////////////////////// 0354 BurnMenuAction::BurnMenuAction( KActionCollection *ac, QObject *parent ) 0355 : QAction( parent ) 0356 { 0357 setText(i18n( "Burn" )); 0358 ac->addAction(QStringLiteral("burn_menu"), this); 0359 } 0360 0361 QWidget* 0362 BurnMenuAction::createWidget( QWidget *w ) 0363 { 0364 KToolBar *bar = dynamic_cast<KToolBar*>(w); 0365 0366 if( bar && KAuthorized::authorizeAction( objectName() ) ) 0367 { 0368 //const int id = QAction::getToolButtonID(); 0369 0370 //addContainer( bar, id ); 0371 w->addAction( this ); 0372 //connect( bar, &KToolBar::destroyed, this, &BurnMenuAction::slotDestroyed ); 0373 0374 //bar->insertButton( QString::null, id, true, i18n( "Burn" ), index ); 0375 0376 //KToolBarButton* button = bar->getButton( id ); 0377 //button->setPopup( Amarok::BurnMenu::instance() ); 0378 //button->setObjectName( "toolbutton_burn_menu" ); 0379 //button->setIcon( "k3b" ); 0380 0381 //return associatedWidgets().count() - 1; 0382 return nullptr; 0383 } 0384 //else return -1; 0385 else return nullptr; 0386 } 0387 0388 0389 BurnMenu* BurnMenu::s_instance = nullptr; 0390 0391 BurnMenu::BurnMenu( QWidget* parent ) 0392 : QMenu( parent ) 0393 { 0394 s_instance = this; 0395 0396 addAction( i18n("Current Playlist"), this, &BurnMenu::slotBurnCurrentPlaylist ); 0397 addAction( i18n("Selected Tracks"), this, &BurnMenu::slotBurnSelectedTracks ); 0398 //TODO add "album" and "all tracks by artist" 0399 } 0400 0401 QMenu* 0402 BurnMenu::instance() 0403 { 0404 return s_instance ? s_instance : new BurnMenu( The::mainWindow() ); 0405 } 0406 0407 void 0408 BurnMenu::slotBurnCurrentPlaylist() //SLOT 0409 { 0410 //K3bExporter::instance()->exportCurrentPlaylist(); 0411 } 0412 0413 void 0414 BurnMenu::slotBurnSelectedTracks() //SLOT 0415 { 0416 //K3bExporter::instance()->exportSelectedTracks(); 0417 } 0418 0419 0420 ////////////////////////////////////////////////////////////////////////////////////////// 0421 // StopAction 0422 ////////////////////////////////////////////////////////////////////////////////////////// 0423 0424 StopAction::StopAction( KActionCollection *ac, QObject *parent ) 0425 : QAction( parent ) 0426 { 0427 ac->addAction( QStringLiteral("stop"), this ); 0428 setText( i18n( "Stop" ) ); 0429 setIcon( QIcon::fromTheme(QStringLiteral("media-playback-stop-amarok")) ); 0430 KGlobalAccel::setGlobalShortcut(this, QKeySequence() ); 0431 connect( this, &StopAction::triggered, this, &StopAction::stop ); 0432 0433 EngineController *engine = The::engineController(); 0434 0435 if( engine->isStopped() ) 0436 stopped(); 0437 else 0438 playing(); 0439 0440 connect( engine, &EngineController::stopped, 0441 this, &StopAction::stopped ); 0442 connect( engine, &EngineController::trackPlaying, 0443 this, &StopAction::playing ); 0444 } 0445 0446 void 0447 StopAction::stopped() 0448 { 0449 setEnabled( false ); 0450 } 0451 0452 void 0453 StopAction::playing() 0454 { 0455 setEnabled( true ); 0456 } 0457 0458 void 0459 StopAction::stop() 0460 { 0461 The::engineController()->stop(); 0462 } 0463 0464 ////////////////////////////////////////////////////////////////////////////////////////// 0465 // StopPlayingAfterCurrentTrackAction 0466 ////////////////////////////////////////////////////////////////////////////////////////// 0467 0468 StopPlayingAfterCurrentTrackAction::StopPlayingAfterCurrentTrackAction( KActionCollection *ac, QObject *parent ) 0469 : QAction( parent ) 0470 { 0471 ac->addAction( QStringLiteral("stop_after_current"), this ); 0472 setText( i18n( "Stop after current Track" ) ); 0473 setIcon( QIcon::fromTheme(QStringLiteral("media-playback-stop-amarok")) ); 0474 KGlobalAccel::setGlobalShortcut(this, QKeySequence( Qt::META + Qt::SHIFT + Qt::Key_V ) ); 0475 connect( this, &StopPlayingAfterCurrentTrackAction::triggered, this, &StopPlayingAfterCurrentTrackAction::stopPlayingAfterCurrentTrack ); 0476 } 0477 0478 void 0479 StopPlayingAfterCurrentTrackAction::stopPlayingAfterCurrentTrack() 0480 { 0481 QString text; 0482 0483 quint64 activeTrack = Playlist::ModelStack::instance()->bottom()->activeId(); 0484 if( activeTrack ) 0485 { 0486 if( The::playlistActions()->willStopAfterTrack( activeTrack ) ) 0487 { 0488 The::playlistActions()->stopAfterPlayingTrack( 0 ); 0489 text = i18n( "Stop after current track: Off" ); 0490 } 0491 else 0492 { 0493 The::playlistActions()->stopAfterPlayingTrack( activeTrack ); 0494 text = i18n( "Stop after current track: On" ); 0495 } 0496 } 0497 else 0498 text = i18n( "No track playing" ); 0499 0500 Amarok::OSD::instance()->OSDWidget::show( text ); 0501 if( Amarok::KNotificationBackend::instance()->isEnabled() ) 0502 Amarok::KNotificationBackend::instance()->show( i18n( "Amarok" ), text ); 0503 }