1 /****************************************************************************************
2 * Copyright (c) 2008 Bonne Eggleston <b.eggleston@gmail.com> *
3 * Copyright (c) 2009 Seb Ruiz <ruiz@kde.org> *
4 * Copyright (c) 2009 Louis Bayle <louis.bayle@gmail.com> *
5 * Copyright (c) 2010 Nikolaj Hald Nielsen <nhn@kde.org> *
6 * *
7 * This program is free software; you can redistribute it and/or modify it under *
8 * the terms of the GNU General Public License as published by the Free Software *
9 * Foundation; either version 2 of the License, or (at your option) version 3 or *
10 * any later version accepted by the membership of KDE e.V. (or its successor approved *
11 * by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of *
12 * version 3 of the license. *
13 * *
14 * This program is distributed in the hope that it will be useful, but WITHOUT ANY *
15 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A *
16 * PARTICULAR PURPOSE. See the GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License along with *
19 * this program. If not, see <http://www.gnu.org/licenses/>. *
20 ****************************************************************************************/
21
22 #include "PlaylistViewCommon.h"
23
24 #include "EngineController.h"
25 #include "GlobalCurrentTrackActions.h"
26 #include "core/capabilities/ActionsCapability.h"
27 #include "core/capabilities/FindInSourceCapability.h"
28 #include "core/meta/Meta.h"
29 #include "core/support/Debug.h"
30 #include "covermanager/CoverFetchingActions.h"
31 #include "dialogs/TagDialog.h"
32 #include "playlist/proxymodels/GroupingProxy.h"
33 #include "playlist/view/listview/PrettyListView.h"
34
35 #include <QMenu>
36
37 #include <QObject>
38 #include <QModelIndex>
39
ViewCommon()40 Playlist::ViewCommon::ViewCommon()
41 : m_stopAfterTrackAction( 0 )
42 , m_cueTrackAction( 0 )
43 , m_removeTracTrackAction( 0 )
44 , m_findInSourceAction( 0 )
45 {}
46
~ViewCommon()47 Playlist::ViewCommon::~ViewCommon()
48 {}
49
50
51 void
trackMenu(QWidget * parent,const QModelIndex * index,const QPoint & pos)52 Playlist::ViewCommon::trackMenu( QWidget *parent, const QModelIndex *index, const QPoint &pos )
53 {
54 DEBUG_BLOCK
55
56 QMenu *menu = new QMenu( parent );
57
58 menu->addActions( parentCheckActions( parent, trackActionsFor( parent, index ) ) );
59 menu->addSeparator();
60
61 QList<QAction *> albumActionsList = parentCheckActions( parent, albumActionsFor( index ) );
62 if( !albumActionsList.isEmpty() )
63 {
64 // there are no cover actions if the song/album is not in the collection
65 QMenu *menuCover = new QMenu( i18n( "Album" ), menu );
66 menuCover->addActions( albumActionsList );
67 menuCover->setIcon( QIcon::fromTheme( QStringLiteral("filename-album-amarok") ) );
68 menu->addMenu( menuCover );
69 menu->addSeparator();
70 }
71
72 menu->addActions( parentCheckActions( parent, multiSourceActionsFor( parent, index ) ) );
73 menu->addSeparator();
74 menu->addActions( parentCheckActions( parent, editActionsFor( parent, index ) ) );
75
76 menu->exec( pos );
77 delete menu;
78 }
79
80
81 QList<QAction *>
actionsFor(QWidget * parent,const QModelIndex * index)82 Playlist::ViewCommon::actionsFor( QWidget *parent, const QModelIndex *index )
83 {
84 QList<QAction *> actions;
85
86 QAction *separator = new QAction( parent );
87 separator->setSeparator( true );
88
89 actions << parentCheckActions( parent, trackActionsFor( parent, index ) );
90 actions << separator;
91
92 QList<QAction *> albumActionsList = parentCheckActions( parent, albumActionsFor( index ) );
93 if( !albumActionsList.isEmpty() )
94 {
95 actions << albumActionsList;
96 actions << separator;
97 }
98
99 actions << parentCheckActions( parent, multiSourceActionsFor( parent, index ) );
100 actions << separator;
101 actions << parentCheckActions( parent, editActionsFor( parent, index ) );
102
103 return actions;
104 }
105
106
107 QList<QAction *>
trackActionsFor(QWidget * parent,const QModelIndex * index)108 Playlist::ViewCommon::trackActionsFor( QWidget *parent, const QModelIndex *index )
109 {
110 QList<QAction *> actions;
111
112 Meta::TrackPtr track = index->data( Playlist::TrackRole ).value< Meta::TrackPtr >();
113
114 QAction *separator = new QAction( parent );
115 separator->setSeparator( true );
116 const bool isQueued = index->data( Playlist::QueuePositionRole ).toInt() != 0;
117 const QString queueText = !isQueued ? i18n( "Queue Track" ) : i18n( "Dequeue Track" );
118
119 //display "Queue track" option only if the track is playable
120 if( track->isPlayable() )
121 {
122
123 if( m_cueTrackAction == 0 )
124 {
125 m_cueTrackAction = new QAction( QIcon::fromTheme( QStringLiteral("media-track-queue-amarok") ), queueText, parent );
126 }
127 else
128 {
129 m_cueTrackAction->disconnect();
130 m_cueTrackAction->setText( queueText );
131 }
132
133 if( auto p = static_cast<Playlist::PrettyListView*>(parent))
134 {
135 if( isQueued )
136 QObject::connect( m_cueTrackAction, &QAction::triggered,
137 p, &Playlist::PrettyListView::dequeueSelection );
138 else
139 QObject::connect( m_cueTrackAction, &QAction::triggered,
140 p, &Playlist::PrettyListView::queueSelection );
141 }
142
143 actions << m_cueTrackAction;
144
145 }
146
147 //actions << separator;
148
149 const bool isCurrentTrack = index->data( Playlist::ActiveTrackRole ).toBool();
150
151 //display "Stop after this track" option only if track is playable. not sure if this check is really needed
152 if( track->isPlayable() )
153 {
154 if( m_stopAfterTrackAction == 0 )
155 {
156 m_stopAfterTrackAction = new QAction( QIcon::fromTheme( QStringLiteral("media-playback-stop-amarok") ),
157 i18n( "Stop Playing After This Track" ), parent );
158
159 if ( auto p = static_cast<Playlist::PrettyListView*>(parent) )
160 QObject::connect( m_stopAfterTrackAction, &QAction::triggered,
161 p, &Playlist::PrettyListView::stopAfterTrack );
162 }
163 actions << m_stopAfterTrackAction;
164 }
165
166 //actions << separator;
167
168 if( m_removeTracTrackAction == 0 )
169 {
170 m_removeTracTrackAction = new QAction( QIcon::fromTheme( QStringLiteral("media-track-remove-amarok") ),
171 i18n( "Remove From Playlist" ), parent );
172
173 if ( auto p = static_cast<Playlist::PrettyListView*>(parent) )
174 QObject::connect( m_removeTracTrackAction, &QAction::triggered,
175 p, &Playlist::PrettyListView::removeSelection );
176 }
177 actions << m_removeTracTrackAction;
178
179 //lets see if parent is the currently playing tracks, and if it has CurrentTrackActionsCapability
180 if( isCurrentTrack )
181 {
182 //actions << separator;
183
184 QList<QAction *> globalCurrentTrackActions = The::globalCurrentTrackActions()->actions();
185 foreach( QAction *action, globalCurrentTrackActions )
186 actions << action;
187
188 if( track->has<Capabilities::ActionsCapability>() )
189 {
190 QScopedPointer<Capabilities::ActionsCapability>
191 ac( track->create<Capabilities::ActionsCapability>() );
192 if ( ac )
193 actions.append( ac->actions() );
194 }
195 }
196
197 if( track->has<Capabilities::FindInSourceCapability>() )
198 {
199 if( m_findInSourceAction == 0 )
200 {
201 m_findInSourceAction = new QAction( QIcon::fromTheme( QStringLiteral("edit-find") ),
202 i18n( "Show in Media Sources" ), parent );
203
204 if( auto p = static_cast<Playlist::PrettyListView*>(parent) )
205 QObject::connect( m_findInSourceAction, &QAction::triggered,
206 p, &Playlist::PrettyListView::findInSource );
207 }
208 actions << m_findInSourceAction;
209 }
210
211 return actions;
212 }
213
214 QList<QAction *>
albumActionsFor(const QModelIndex * index)215 Playlist::ViewCommon::albumActionsFor( const QModelIndex *index )
216 {
217 QList<QAction *> actions;
218
219 Meta::TrackPtr track = index->data( Playlist::TrackRole ).value< Meta::TrackPtr >();
220
221 Meta::AlbumPtr album = track->album();
222 if( album )
223 {
224 QScopedPointer<Capabilities::ActionsCapability>
225 ac( album->create<Capabilities::ActionsCapability>() );
226 if( ac )
227 actions.append( ac->actions() );
228 }
229
230 return actions;
231 }
232
233
234 QList<QAction *>
multiSourceActionsFor(QWidget * parent,const QModelIndex * index)235 Playlist::ViewCommon::multiSourceActionsFor( QWidget *parent, const QModelIndex *index )
236 {
237 QList<QAction *> actions;
238 Meta::TrackPtr track = index->data( Playlist::TrackRole ).value< Meta::TrackPtr >();
239
240 const bool isMultiSource = index->data( Playlist::MultiSourceRole ).toBool();
241
242 if( isMultiSource )
243 {
244 QAction *selectSourceAction = new QAction( QIcon::fromTheme( QStringLiteral("media-playlist-repeat") ),
245 i18n( "Select Source" ), parent );
246
247 if( auto p = static_cast<Playlist::PrettyListView*>(parent) )
248 QObject::connect( selectSourceAction, &QAction::triggered, p, &Playlist::PrettyListView::selectSource );
249
250 actions << selectSourceAction;
251 }
252
253 return actions;
254 }
255
256
257 QList<QAction *>
editActionsFor(QWidget * parent,const QModelIndex * index)258 Playlist::ViewCommon::editActionsFor( QWidget *parent, const QModelIndex *index )
259 {
260 QList<QAction *> actions;
261
262 Meta::TrackPtr track = index->data( Playlist::TrackRole ).value< Meta::TrackPtr >();
263
264 QAction *editAction = new QAction( QIcon::fromTheme( QStringLiteral("media-track-edit-amarok") ),
265 i18n( "Edit Track Details" ), parent );
266 editAction->setProperty( "popupdropper_svg_id", "edit" );
267
268 if( auto p = static_cast<Playlist::PrettyListView*>(parent) )
269 QObject::connect( editAction, &QAction::triggered, p, &Playlist::PrettyListView::editTrackInformation );
270
271 actions << editAction;
272
273 return actions;
274 }
275
276 QList<QAction *>
parentCheckActions(QObject * parent,QList<QAction * > actions)277 Playlist::ViewCommon::parentCheckActions( QObject *parent, QList<QAction *> actions )
278 {
279 foreach( QAction *action, actions )
280 {
281 if( !action->parent() )
282 action->setParent( parent );
283 }
284
285 return actions;
286 }
287