Warning, file /multimedia/amarok/src/playlist/PlaylistDock.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /**************************************************************************************** 0002 * Copyright (c) 2007 Ian Monroe <ian@monroe.nu> * 0003 * Copyright (c) 2009 Leo Franchi <lfranchi@kde.org> * 0004 * * 0005 * This program is free software; you can redistribute it and/or modify it under * 0006 * the terms of the GNU General Public License as published by the Free Software * 0007 * Foundation; either version 2 of the License, or (at your option) version 3 or * 0008 * any later version accepted by the membership of KDE e.V. (or its successor approved * 0009 * by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of * 0010 * version 3 of the license. * 0011 * * 0012 * This program is distributed in the hope that it will be useful, but WITHOUT ANY * 0013 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * 0014 * PARTICULAR PURPOSE. See the GNU General Public License for more details. * 0015 * * 0016 * You should have received a copy of the GNU General Public License along with * 0017 * this program. If not, see <http://www.gnu.org/licenses/>. * 0018 ****************************************************************************************/ 0019 0020 #define DEBUG_PREFIX "PlaylistDock" 0021 0022 #include "PlaylistDock.h" 0023 0024 #include "ActionClasses.h" 0025 #include "App.h" 0026 #include "MainWindow.h" 0027 #include "PaletteHandler.h" 0028 #include "amarokconfig.h" 0029 #include "amarokurls/AmarokUrl.h" 0030 #include "core/support/Debug.h" 0031 #include "playlist/PlaylistActions.h" 0032 #include "playlist/PlaylistController.h" 0033 #include "playlist/PlaylistDefines.h" 0034 #include "playlist/PlaylistInfoWidget.h" 0035 #include "playlist/PlaylistModelStack.h" 0036 #include "playlist/PlaylistQueueEditor.h" 0037 #include "playlist/PlaylistToolBar.h" 0038 #include "playlist/ProgressiveSearchWidget.h" 0039 #include "playlist/layouts/LayoutManager.h" 0040 #include "playlist/navigators/NavigatorConfigAction.h" 0041 #include "playlistmanager/PlaylistManager.h" 0042 #include "core-impl/playlists/providers/user/UserPlaylistProvider.h" 0043 #include "widgets/HorizontalDivider.h" 0044 #include "widgets/BoxWidget.h" 0045 0046 #include <QLabel> 0047 #include <QSharedPointer> 0048 #include <QStandardPaths> 0049 #include <QToolBar> 0050 0051 #include <KActionMenu> 0052 #include <KToolBarSpacerAction> 0053 0054 static const QString s_dynMode( QStringLiteral("dynamic_mode") ); 0055 static const QString s_repopulate( QStringLiteral("repopulate") ); 0056 static const QString s_turnOff( QStringLiteral("turn_off") ); 0057 0058 Playlist::Dock::Dock( QWidget* parent ) 0059 : AmarokDockWidget( i18n( "&Playlist" ), parent ) 0060 , m_barBox( nullptr ) 0061 { 0062 setObjectName( QStringLiteral("Playlist dock") ); 0063 setAllowedAreas( Qt::AllDockWidgetAreas ); 0064 } 0065 0066 Playlist::PrettyListView * 0067 Playlist::Dock::currentView() 0068 { 0069 ensurePolish(); 0070 return m_playlistView; 0071 } 0072 0073 Playlist::SortWidget * 0074 Playlist::Dock::sortWidget() 0075 { 0076 ensurePolish(); 0077 return m_sortWidget; 0078 } 0079 0080 Playlist::ProgressiveSearchWidget * 0081 Playlist::Dock::searchWidget() 0082 { 0083 ensurePolish(); 0084 return m_searchWidget; 0085 } 0086 0087 void 0088 Playlist::Dock::polish() 0089 { 0090 m_mainWidget = new BoxWidget( true, this ); 0091 setWidget( m_mainWidget ); 0092 m_mainWidget->setContentsMargins( 0, 0, 0, 0 ); 0093 m_mainWidget->setFrameShape( QFrame::NoFrame ); 0094 m_mainWidget->setMinimumWidth( 200 ); 0095 m_mainWidget->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Ignored ); 0096 m_mainWidget->setFocus( Qt::ActiveWindowFocusReason ); 0097 0098 m_sortWidget = new Playlist::SortWidget( m_mainWidget ); 0099 new HorizontalDivider( m_mainWidget ); 0100 0101 m_searchWidget = new Playlist::ProgressiveSearchWidget( m_mainWidget ); 0102 0103 // show visual indication of dynamic playlists being enabled 0104 connect( The::playlistActions(), &Playlist::Actions::navigatorChanged, 0105 this, &Playlist::Dock::showDynamicHint ); 0106 m_dynamicHintWidget = new QLabel( i18n( "<a href='%1'>Dynamic Mode</a> Enabled. " 0107 "<a href='%2'>Repopulate</a> | <a href='%3'>Turn off</a>", s_dynMode, 0108 s_repopulate, s_turnOff ), m_mainWidget ); 0109 m_dynamicHintWidget->setAlignment( Qt::AlignCenter ); 0110 m_dynamicHintWidget->setTextInteractionFlags( Qt::LinksAccessibleByKeyboard | Qt::LinksAccessibleByMouse ); 0111 m_dynamicHintWidget->setMinimumSize( 1, 1 ); // so that it doesn't prevent playlist from shrinking 0112 connect( m_dynamicHintWidget, &QLabel::linkActivated, this, &Dock::slotDynamicHintLinkActivated ); 0113 0114 QFont dynamicHintWidgetFont = m_dynamicHintWidget->font(); 0115 dynamicHintWidgetFont.setPointSize( dynamicHintWidgetFont.pointSize() + 1 ); 0116 m_dynamicHintWidget->setFont( dynamicHintWidgetFont ); 0117 0118 showDynamicHint(); 0119 0120 paletteChanged( pApp->palette() ); 0121 connect( The::paletteHandler(), &PaletteHandler::newPalette, 0122 this, &Playlist::Dock::paletteChanged ); 0123 0124 QWidget * layoutHolder = new QWidget( m_mainWidget ); 0125 0126 QVBoxLayout* mainPlaylistlayout = new QVBoxLayout( layoutHolder ); 0127 mainPlaylistlayout->setContentsMargins( 0, 0, 0, 0 ); 0128 0129 m_playlistView = new PrettyListView(); 0130 m_playlistView->show(); 0131 0132 connect( m_searchWidget, &Playlist::ProgressiveSearchWidget::filterChanged, 0133 m_playlistView, &Playlist::PrettyListView::find ); 0134 connect( m_searchWidget, &Playlist::ProgressiveSearchWidget::next, 0135 m_playlistView, &Playlist::PrettyListView::findNext ); 0136 connect( m_searchWidget, &Playlist::ProgressiveSearchWidget::previous, 0137 m_playlistView, &Playlist::PrettyListView::findPrevious ); 0138 connect( m_searchWidget, &Playlist::ProgressiveSearchWidget::filterCleared, 0139 m_playlistView, &Playlist::PrettyListView::clearSearchTerm ); 0140 connect( m_searchWidget, &Playlist::ProgressiveSearchWidget::showOnlyMatches, 0141 m_playlistView, &Playlist::PrettyListView::showOnlyMatches ); 0142 connect( m_searchWidget, &Playlist::ProgressiveSearchWidget::activateFilterResult, 0143 m_playlistView, &Playlist::PrettyListView::playFirstSelected ); 0144 connect( m_searchWidget, &Playlist::ProgressiveSearchWidget::downPressed, m_playlistView, &Playlist::PrettyListView::downOneTrack ); 0145 connect( m_searchWidget, &Playlist::ProgressiveSearchWidget::upPressed, m_playlistView, &Playlist::PrettyListView::upOneTrack ); 0146 0147 connect( The::mainWindow(), &MainWindow::switchQueueStateShortcut, 0148 m_playlistView, &Playlist::PrettyListView::switchQueueState ); 0149 0150 KConfigGroup searchConfig = Amarok::config(QStringLiteral("Playlist Search")); 0151 m_playlistView->showOnlyMatches( searchConfig.readEntry( "ShowOnlyMatches", false ) ); 0152 0153 connect( m_playlistView, &Playlist::PrettyListView::found, m_searchWidget, &Playlist::ProgressiveSearchWidget::match ); 0154 connect( m_playlistView, &Playlist::PrettyListView::notFound, m_searchWidget, &Playlist::ProgressiveSearchWidget::noMatch ); 0155 0156 connect( LayoutManager::instance(), &LayoutManager::activeLayoutChanged, 0157 m_playlistView, &Playlist::PrettyListView::reset ); 0158 0159 mainPlaylistlayout->setSpacing( 0 ); 0160 mainPlaylistlayout->addWidget( m_playlistView ); 0161 0162 ModelStack::instance(); //This also creates the Controller. 0163 0164 { // START: Playlist toolbar 0165 // action toolbar 0166 m_barBox = new BoxWidget( false, m_mainWidget ); 0167 m_barBox->setObjectName( QStringLiteral("PlaylistBarBox") ); 0168 m_barBox->setContentsMargins( 0, 0, 4, 0 ); 0169 m_barBox->setFixedHeight( 36 ); 0170 0171 // Use QToolBar instead of KToolBar, see bug 228390 0172 Playlist::ToolBar *plBar = new Playlist::ToolBar( m_barBox ); 0173 plBar->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Preferred ); 0174 plBar->setMovable( false ); 0175 0176 QActionGroup *playlistActions = new QActionGroup( m_mainWidget ); 0177 playlistActions->addAction( Amarok::actionCollection()->action( QStringLiteral("playlist_clear") ) ); 0178 0179 m_savePlaylistMenu = new KActionMenu( QIcon::fromTheme( QStringLiteral("document-save-amarok") ), 0180 i18n("&Save Current Playlist"), m_mainWidget ); 0181 m_savePlaylistMenu->addAction( Amarok::actionCollection()->action( QStringLiteral("playlist_export") ) ); 0182 0183 m_saveActions = new KActionCollection( m_mainWidget ); 0184 0185 connect( m_savePlaylistMenu, &KActionMenu::triggered, 0186 this, &Dock::slotSaveCurrentPlaylist ); 0187 foreach( Playlists::PlaylistProvider *provider, The::playlistManager()->providersForCategory( 0188 PlaylistManager::UserPlaylist ) ) 0189 { 0190 playlistProviderAdded( provider, PlaylistManager::UserPlaylist ); 0191 } 0192 0193 connect( The::playlistManager(), &PlaylistManager::providerAdded, 0194 this, &Dock::playlistProviderAdded ); 0195 connect( The::playlistManager(), &PlaylistManager::providerRemoved, 0196 this, &Dock::playlistProviderRemoved ); 0197 0198 playlistActions->addAction( m_savePlaylistMenu ); 0199 0200 playlistActions->addAction( Amarok::actionCollection()->action( QStringLiteral("playlist_undo") ) ); 0201 //redo action can be accessed from menu > Playlist 0202 0203 playlistActions->addAction( Amarok::actionCollection()->action( QStringLiteral("show_active_track") ) ); 0204 0205 plBar->addCollapsibleActions( playlistActions ); 0206 0207 NavigatorConfigAction *navigatorConfig = new NavigatorConfigAction( m_mainWidget ); 0208 plBar->addAction( navigatorConfig ); 0209 0210 QToolButton *toolButton = 0211 qobject_cast<QToolButton *>(plBar->widgetForAction( navigatorConfig ) ); 0212 if( toolButton ) 0213 toolButton->setPopupMode( QToolButton::InstantPopup ); 0214 0215 plBar->addAction( new KToolBarSpacerAction( m_mainWidget ) ); 0216 0217 // label widget 0218 new PlaylistInfoWidget( m_barBox ); 0219 } // END Playlist Toolbar 0220 0221 //set correct colors 0222 paletteChanged( QApplication::palette() ); 0223 0224 // If it is active, clear the search filter before replacing the playlist. Fixes Bug #200709. 0225 connect( The::playlistController(), &Playlist::Controller::replacingPlaylist, 0226 this, &Playlist::Dock::clearFilterIfActive ); 0227 0228 } 0229 0230 QSize 0231 Playlist::Dock::sizeHint() const 0232 { 0233 return QSize( static_cast<QWidget*>( parent() )->size().width() / 4 , 300 ); 0234 } 0235 0236 void 0237 Playlist::Dock::paletteChanged( const QPalette &palette ) 0238 { 0239 const QString backgroundColor = palette.color( QPalette::Active, QPalette::Mid ).name(); 0240 const QString textColor = palette.color( QPalette::Active, QPalette::HighlightedText ).name(); 0241 const QString linkColor = palette.color( QPalette::Active, QPalette::Link ).name(); 0242 const QString ridgeColor = palette.color( QPalette::Active, QPalette::Window ).name(); 0243 0244 QString hintStyle( "QLabel { background-color: %1; color: %2; border-radius: 3px; } " 0245 "a { color: %3; }" ); 0246 hintStyle = hintStyle.arg( backgroundColor, textColor, linkColor ); 0247 0248 QString barStyle( "QFrame#PlaylistBarBox { border: 1px ridge %1; background-color: %2; " 0249 " color: %3; border-radius: 3px; } " 0250 "QLabel { color: %4; }" ); 0251 barStyle = barStyle.arg( ridgeColor, backgroundColor, textColor, textColor ); 0252 0253 m_dynamicHintWidget->setStyleSheet( hintStyle ); 0254 if( m_barBox ) 0255 m_barBox->setStyleSheet( barStyle ); 0256 0257 } 0258 0259 void 0260 Playlist::Dock::playlistProviderAdded( Playlists::PlaylistProvider *provider, int category ) 0261 { 0262 if( category != PlaylistManager::UserPlaylist ) 0263 return; 0264 0265 debug() << "Adding provider: " << provider->prettyName(); 0266 Playlists::UserPlaylistProvider *userProvider = 0267 dynamic_cast<Playlists::UserPlaylistProvider *>(provider); 0268 if( userProvider == nullptr ) 0269 return; 0270 QAction *action = new QAction( userProvider->icon(), 0271 i18n("&Save playlist to \"%1\"", provider->prettyName() ), 0272 this ); 0273 action->setData( QVariant::fromValue( QPointer<Playlists::UserPlaylistProvider>( userProvider ) ) ); 0274 m_saveActions->addAction( QString::number( (qlonglong) userProvider ), action ); 0275 0276 // insert the playlist provider actions before "export" 0277 QAction* exportAction = Amarok::actionCollection()->action( QStringLiteral("playlist_export") ); 0278 m_savePlaylistMenu->insertAction( exportAction, action ); 0279 connect( action, &QAction::triggered, this, &Playlist::Dock::slotSaveCurrentPlaylist ); 0280 } 0281 0282 void 0283 Playlist::Dock::playlistProviderRemoved( Playlists::PlaylistProvider *provider, int category ) 0284 { 0285 if( category != PlaylistManager::UserPlaylist ) 0286 return; 0287 0288 QAction *action = m_saveActions->action( QString::number( (qlonglong) provider ) ); 0289 if( action ) 0290 m_savePlaylistMenu->removeAction( action ); 0291 else 0292 warning() << __PRETTY_FUNCTION__ << ": no save action for provider" << provider->prettyName(); 0293 } 0294 0295 void 0296 Playlist::Dock::slotSaveCurrentPlaylist() 0297 { 0298 DEBUG_BLOCK 0299 0300 QAction *action = qobject_cast<QAction *>( QObject::sender() ); 0301 if( action == nullptr ) 0302 return; 0303 0304 QWeakPointer<Playlists::UserPlaylistProvider> weakPointer = 0305 action->data().value< QWeakPointer<Playlists::UserPlaylistProvider> >(); 0306 QSharedPointer<Playlists::UserPlaylistProvider> strongPointer = weakPointer.toStrongRef(); 0307 if ( strongPointer ) { 0308 Playlists::UserPlaylistProvider* provider = strongPointer.data(); 0309 0310 const Meta::TrackList tracks = The::playlist()->tracks(); 0311 The::playlistManager()->save( tracks, Amarok::generatePlaylistName( tracks ), provider ); 0312 } 0313 } 0314 0315 void 0316 Playlist::Dock::slotEditQueue() 0317 { 0318 if( m_playlistQueueEditor ) { 0319 m_playlistQueueEditor->raise(); 0320 return; 0321 } 0322 m_playlistQueueEditor = new PlaylistQueueEditor; 0323 m_playlistQueueEditor->setAttribute( Qt::WA_DeleteOnClose ); 0324 m_playlistQueueEditor->show(); 0325 } 0326 0327 void 0328 Playlist::Dock::showActiveTrack() 0329 { 0330 ensurePolish(); 0331 m_playlistView->scrollToActiveTrack(); 0332 } 0333 0334 void 0335 Playlist::Dock::editTrackInfo() 0336 { 0337 m_playlistView->editTrackInformation(); 0338 } 0339 0340 void 0341 Playlist::Dock::showDynamicHint() // slot 0342 { 0343 DEBUG_BLOCK 0344 0345 if( AmarokConfig::dynamicMode() ) 0346 m_dynamicHintWidget->show(); 0347 else 0348 m_dynamicHintWidget->hide(); 0349 } 0350 0351 void 0352 Playlist::Dock::clearFilterIfActive() // slot 0353 { 0354 DEBUG_BLOCK 0355 KConfigGroup config = Amarok::config( QStringLiteral("Playlist Search") ); 0356 bool filterActive = config.readEntry( "ShowOnlyMatches", true ); 0357 0358 if( filterActive ) 0359 m_searchWidget->slotFilterClear(); 0360 } 0361 0362 void 0363 Playlist::Dock::slotDynamicHintLinkActivated( const QString &href ) 0364 { 0365 if( href == s_dynMode ) 0366 AmarokUrl( QStringLiteral("amarok://navigate/playlists/dynamic category") ).run(); 0367 else if( href == s_repopulate ) 0368 The::playlistActions()->repopulateDynamicPlaylist(); 0369 else if( href == s_turnOff ) 0370 The::playlistActions()->enableDynamicMode( false ); 0371 }