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 }