File indexing completed on 2024-05-19 04:49:53
0001 /**************************************************************************************** 0002 * Copyright (c) 2008 Bonne Eggleston <b.eggleston@gmail.com> * 0003 * Copyright (c) 2009 Seb Ruiz <ruiz@kde.org> * 0004 * Copyright (c) 2009 Louis Bayle <louis.bayle@gmail.com> * 0005 * Copyright (c) 2010 Nikolaj Hald Nielsen <nhn@kde.org> * 0006 * * 0007 * This program is free software; you can redistribute it and/or modify it under * 0008 * the terms of the GNU General Public License as published by the Free Software * 0009 * Foundation; either version 2 of the License, or (at your option) version 3 or * 0010 * any later version accepted by the membership of KDE e.V. (or its successor approved * 0011 * by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of * 0012 * version 3 of the license. * 0013 * * 0014 * This program is distributed in the hope that it will be useful, but WITHOUT ANY * 0015 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * 0016 * PARTICULAR PURPOSE. See the GNU General Public License for more details. * 0017 * * 0018 * You should have received a copy of the GNU General Public License along with * 0019 * this program. If not, see <http://www.gnu.org/licenses/>. * 0020 ****************************************************************************************/ 0021 0022 #include "PlaylistViewCommon.h" 0023 0024 #include "EngineController.h" 0025 #include "GlobalCurrentTrackActions.h" 0026 #include "core/capabilities/ActionsCapability.h" 0027 #include "core/capabilities/FindInSourceCapability.h" 0028 #include "core/meta/Meta.h" 0029 #include "core/support/Debug.h" 0030 #include "covermanager/CoverFetchingActions.h" 0031 #include "dialogs/TagDialog.h" 0032 #include "playlist/proxymodels/GroupingProxy.h" 0033 #include "playlist/view/listview/PrettyListView.h" 0034 0035 #include <QMenu> 0036 0037 #include <QObject> 0038 #include <QModelIndex> 0039 0040 Playlist::ViewCommon::ViewCommon() 0041 : m_stopAfterTrackAction( nullptr ) 0042 , m_cueTrackAction( nullptr ) 0043 , m_removeTracTrackAction( nullptr ) 0044 , m_findInSourceAction( nullptr ) 0045 {} 0046 0047 Playlist::ViewCommon::~ViewCommon() 0048 {} 0049 0050 0051 void 0052 Playlist::ViewCommon::trackMenu( QWidget *parent, const QModelIndex *index, const QPoint &pos ) 0053 { 0054 DEBUG_BLOCK 0055 0056 QMenu *menu = new QMenu( parent ); 0057 0058 menu->addActions( parentCheckActions( parent, trackActionsFor( parent, index ) ) ); 0059 menu->addSeparator(); 0060 0061 QList<QAction *> albumActionsList = parentCheckActions( parent, albumActionsFor( index ) ); 0062 if( !albumActionsList.isEmpty() ) 0063 { 0064 // there are no cover actions if the song/album is not in the collection 0065 QMenu *menuCover = new QMenu( i18n( "Album" ), menu ); 0066 menuCover->addActions( albumActionsList ); 0067 menuCover->setIcon( QIcon::fromTheme( QStringLiteral("filename-album-amarok") ) ); 0068 menu->addMenu( menuCover ); 0069 menu->addSeparator(); 0070 } 0071 0072 menu->addActions( parentCheckActions( parent, multiSourceActionsFor( parent, index ) ) ); 0073 menu->addSeparator(); 0074 menu->addActions( parentCheckActions( parent, editActionsFor( parent, index ) ) ); 0075 0076 menu->exec( pos ); 0077 delete menu; 0078 } 0079 0080 0081 QList<QAction *> 0082 Playlist::ViewCommon::actionsFor( QWidget *parent, const QModelIndex *index ) 0083 { 0084 QList<QAction *> actions; 0085 0086 QAction *separator = new QAction( parent ); 0087 separator->setSeparator( true ); 0088 0089 actions << parentCheckActions( parent, trackActionsFor( parent, index ) ); 0090 actions << separator; 0091 0092 QList<QAction *> albumActionsList = parentCheckActions( parent, albumActionsFor( index ) ); 0093 if( !albumActionsList.isEmpty() ) 0094 { 0095 actions << albumActionsList; 0096 actions << separator; 0097 } 0098 0099 actions << parentCheckActions( parent, multiSourceActionsFor( parent, index ) ); 0100 actions << separator; 0101 actions << parentCheckActions( parent, editActionsFor( parent, index ) ); 0102 0103 return actions; 0104 } 0105 0106 0107 QList<QAction *> 0108 Playlist::ViewCommon::trackActionsFor( QWidget *parent, const QModelIndex *index ) 0109 { 0110 QList<QAction *> actions; 0111 0112 Meta::TrackPtr track = index->data( Playlist::TrackRole ).value< Meta::TrackPtr >(); 0113 0114 QAction *separator = new QAction( parent ); 0115 separator->setSeparator( true ); 0116 const bool isQueued = index->data( Playlist::QueuePositionRole ).toInt() != 0; 0117 const QString queueText = !isQueued ? i18n( "Queue Track" ) : i18n( "Dequeue Track" ); 0118 0119 //display "Queue track" option only if the track is playable 0120 if( track->isPlayable() ) 0121 { 0122 0123 if( m_cueTrackAction == nullptr ) 0124 { 0125 m_cueTrackAction = new QAction( QIcon::fromTheme( QStringLiteral("media-track-queue-amarok") ), queueText, parent ); 0126 } 0127 else 0128 { 0129 m_cueTrackAction->disconnect(); 0130 m_cueTrackAction->setText( queueText ); 0131 } 0132 0133 if( auto p = static_cast<Playlist::PrettyListView*>(parent)) 0134 { 0135 if( isQueued ) 0136 QObject::connect( m_cueTrackAction, &QAction::triggered, 0137 p, &Playlist::PrettyListView::dequeueSelection ); 0138 else 0139 QObject::connect( m_cueTrackAction, &QAction::triggered, 0140 p, &Playlist::PrettyListView::queueSelection ); 0141 } 0142 0143 actions << m_cueTrackAction; 0144 0145 } 0146 0147 //actions << separator; 0148 0149 const bool isCurrentTrack = index->data( Playlist::ActiveTrackRole ).toBool(); 0150 0151 //display "Stop after this track" option only if track is playable. not sure if this check is really needed 0152 if( track->isPlayable() ) 0153 { 0154 if( m_stopAfterTrackAction == nullptr ) 0155 { 0156 m_stopAfterTrackAction = new QAction( QIcon::fromTheme( QStringLiteral("media-playback-stop-amarok") ), 0157 i18n( "Stop Playing After This Track" ), parent ); 0158 0159 if ( auto p = static_cast<Playlist::PrettyListView*>(parent) ) 0160 QObject::connect( m_stopAfterTrackAction, &QAction::triggered, 0161 p, &Playlist::PrettyListView::stopAfterTrack ); 0162 } 0163 actions << m_stopAfterTrackAction; 0164 } 0165 0166 //actions << separator; 0167 0168 if( m_removeTracTrackAction == nullptr ) 0169 { 0170 m_removeTracTrackAction = new QAction( QIcon::fromTheme( QStringLiteral("media-track-remove-amarok") ), 0171 i18n( "Remove From Playlist" ), parent ); 0172 0173 if ( auto p = static_cast<Playlist::PrettyListView*>(parent) ) 0174 QObject::connect( m_removeTracTrackAction, &QAction::triggered, 0175 p, &Playlist::PrettyListView::removeSelection ); 0176 } 0177 actions << m_removeTracTrackAction; 0178 0179 //lets see if parent is the currently playing tracks, and if it has CurrentTrackActionsCapability 0180 if( isCurrentTrack ) 0181 { 0182 //actions << separator; 0183 0184 QList<QAction *> globalCurrentTrackActions = The::globalCurrentTrackActions()->actions(); 0185 foreach( QAction *action, globalCurrentTrackActions ) 0186 actions << action; 0187 0188 if( track->has<Capabilities::ActionsCapability>() ) 0189 { 0190 QScopedPointer<Capabilities::ActionsCapability> 0191 ac( track->create<Capabilities::ActionsCapability>() ); 0192 if ( ac ) 0193 actions.append( ac->actions() ); 0194 } 0195 } 0196 0197 if( track->has<Capabilities::FindInSourceCapability>() ) 0198 { 0199 if( m_findInSourceAction == nullptr ) 0200 { 0201 m_findInSourceAction = new QAction( QIcon::fromTheme( QStringLiteral("edit-find") ), 0202 i18n( "Show in Media Sources" ), parent ); 0203 0204 if( auto p = static_cast<Playlist::PrettyListView*>(parent) ) 0205 QObject::connect( m_findInSourceAction, &QAction::triggered, 0206 p, &Playlist::PrettyListView::findInSource ); 0207 } 0208 actions << m_findInSourceAction; 0209 } 0210 0211 return actions; 0212 } 0213 0214 QList<QAction *> 0215 Playlist::ViewCommon::albumActionsFor( const QModelIndex *index ) 0216 { 0217 QList<QAction *> actions; 0218 0219 Meta::TrackPtr track = index->data( Playlist::TrackRole ).value< Meta::TrackPtr >(); 0220 0221 Meta::AlbumPtr album = track->album(); 0222 if( album ) 0223 { 0224 QScopedPointer<Capabilities::ActionsCapability> 0225 ac( album->create<Capabilities::ActionsCapability>() ); 0226 if( ac ) 0227 actions.append( ac->actions() ); 0228 } 0229 0230 return actions; 0231 } 0232 0233 0234 QList<QAction *> 0235 Playlist::ViewCommon::multiSourceActionsFor( QWidget *parent, const QModelIndex *index ) 0236 { 0237 QList<QAction *> actions; 0238 Meta::TrackPtr track = index->data( Playlist::TrackRole ).value< Meta::TrackPtr >(); 0239 0240 const bool isMultiSource = index->data( Playlist::MultiSourceRole ).toBool(); 0241 0242 if( isMultiSource ) 0243 { 0244 QAction *selectSourceAction = new QAction( QIcon::fromTheme( QStringLiteral("media-playlist-repeat") ), 0245 i18n( "Select Source" ), parent ); 0246 0247 if( auto p = static_cast<Playlist::PrettyListView*>(parent) ) 0248 QObject::connect( selectSourceAction, &QAction::triggered, p, &Playlist::PrettyListView::selectSource ); 0249 0250 actions << selectSourceAction; 0251 } 0252 0253 return actions; 0254 } 0255 0256 0257 QList<QAction *> 0258 Playlist::ViewCommon::editActionsFor( QWidget *parent, const QModelIndex *index ) 0259 { 0260 QList<QAction *> actions; 0261 0262 Meta::TrackPtr track = index->data( Playlist::TrackRole ).value< Meta::TrackPtr >(); 0263 0264 QAction *editAction = new QAction( QIcon::fromTheme( QStringLiteral("media-track-edit-amarok") ), 0265 i18n( "Edit Track Details" ), parent ); 0266 editAction->setProperty( "popupdropper_svg_id", "edit" ); 0267 0268 if( auto p = static_cast<Playlist::PrettyListView*>(parent) ) 0269 QObject::connect( editAction, &QAction::triggered, p, &Playlist::PrettyListView::editTrackInformation ); 0270 0271 actions << editAction; 0272 0273 return actions; 0274 } 0275 0276 QList<QAction *> 0277 Playlist::ViewCommon::parentCheckActions( QObject *parent, QList<QAction *> actions ) 0278 { 0279 foreach( QAction *action, actions ) 0280 { 0281 if( !action->parent() ) 0282 action->setParent( parent ); 0283 } 0284 0285 return actions; 0286 }