File indexing completed on 2024-05-19 04:50:16

0001 /****************************************************************************************
0002  * Copyright (c) 2009 Casey Link <unnamedrambler@gmail.com>                             *
0003  * Copyright (c) 2005-2007 Christian Muehlhaeuser, Last.fm Ltd <chris@last.fm>          *
0004  * Copyright (c) 2005-2007 Max Howell, Last.fm Ltd <max@last.fm>                        *
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 #include "LastFmTreeView.h"
0020 
0021 #include "PopupDropperFactory.h"
0022 #include "context/ContextView.h"
0023 #include "core/meta/Meta.h"
0024 #include "core/support/Debug.h"
0025 #include "services/lastfm/LastFmTreeModel.h" // FIXME just for enums
0026 
0027 #include <QContextMenuEvent>
0028 #include <QHeaderView>
0029 #include <QMenu>
0030 
0031 #include <KLocalizedString>
0032 
0033 #include <algorithm>
0034 
0035 
0036 LastFmTreeView::LastFmTreeView ( QWidget* parent )
0037         : Amarok::PrettyTreeView ( parent )
0038         , m_timer ( nullptr )
0039         , m_pd( nullptr )
0040         , m_appendAction ( nullptr )
0041         , m_loadAction ( nullptr )
0042         , m_dragMutex()
0043         , m_ongoingDrag( false )
0044 {
0045 //     connect ( this, SIGNAL (activated(QModelIndex)), SLOT (onActivated(QModelIndex)) );
0046 
0047     header()->hide();
0048 //     setRootIsDecorated( false );
0049 }
0050 
0051 
0052 LastFmTreeView::~LastFmTreeView()
0053 {}
0054 
0055 void
0056 LastFmTreeView::contextMenuEvent ( QContextMenuEvent* event )
0057 {
0058     m_currentItems.clear();
0059     foreach ( const QModelIndex &i, selectedIndexes() )
0060     {
0061         if ( i.isValid() )
0062             m_currentItems << i;
0063     }
0064     if ( m_currentItems.isEmpty() )
0065         return;
0066     QAction separator ( this );
0067     separator.setSeparator ( true );
0068 
0069     QActionList actions = createBasicActions( m_currentItems );
0070 
0071     actions += &separator;
0072     QMenu menu;
0073     foreach ( QAction * action, actions )
0074         menu.addAction ( action );
0075 
0076     menu.exec ( event->globalPos() );
0077 }
0078 
0079 QActionList LastFmTreeView::createBasicActions( const QModelIndexList & indices )
0080 {
0081     Q_UNUSED( indices )
0082     QActionList actions;
0083     QModelIndex index = currentIndex();
0084     QVariant type = model()->data(index, LastFm::TypeRole);
0085     switch ( type.toInt() )
0086     {
0087         case LastFm::MyRecommendations:
0088         case LastFm::PersonalRadio:
0089         case LastFm::MixRadio:
0090         case LastFm::FriendsChild:
0091         case LastFm::MyTagsChild:
0092         case LastFm::ArtistsChild:
0093         case LastFm::UserChildPersonal:
0094         {
0095             if ( m_appendAction == nullptr )
0096             {
0097                 m_appendAction = new QAction ( QIcon::fromTheme( "media-track-add-amarok" ), i18n ( "&Add to Playlist" ), this );
0098                 m_appendAction->setProperty( "popupdropper_svg_id", "append" );
0099                 connect ( m_appendAction, &QAction::triggered, this, &LastFmTreeView::slotAppendChildTracks );
0100             }
0101 
0102             actions.append ( m_appendAction );
0103 
0104             if ( m_loadAction == nullptr )
0105             {
0106                 m_loadAction = new QAction ( QIcon::fromTheme( "folder-open" ), i18nc ( "Replace the currently loaded tracks with these", "&Replace Playlist" ), this );
0107                 m_appendAction->setProperty( "popupdropper_svg_id", "load" );
0108                 connect ( m_loadAction, &QAction::triggered, this, &LastFmTreeView::slotReplacePlaylistByChildTracks );
0109             }
0110             actions.append ( m_loadAction );
0111         }
0112         default:
0113             break;
0114     }
0115     return actions;
0116 }
0117 
0118 void LastFmTreeView::mouseDoubleClickEvent( QMouseEvent *event )
0119 {
0120     QModelIndex index;
0121     index = indexAt( event->pos() );
0122 
0123     if( index.isValid() && index.internalPointer() )
0124     {
0125         playChildTracks( index, Playlist::OnDoubleClickOnSelectedItems );
0126     }
0127 }
0128 
0129 void
0130 LastFmTreeView::startDrag(Qt::DropActions supportedActions)
0131 {
0132     DEBUG_BLOCK
0133 
0134     //setSelectionMode( QAbstractItemView::NoSelection );
0135 
0136     // When a parent item is dragged, startDrag() is called a bunch of times. Here we prevent that:
0137     m_dragMutex.lock();
0138     if( m_ongoingDrag )
0139     {
0140         m_dragMutex.unlock();
0141         return;
0142     }
0143     m_ongoingDrag = true;
0144     m_dragMutex.unlock();
0145 
0146     if( !m_pd )
0147         m_pd = The::popupDropperFactory()->createPopupDropper( Context::ContextView::self() );
0148 
0149     if( m_pd && m_pd->isHidden() )
0150     {
0151 
0152         QModelIndexList indices = selectedIndexes();
0153 
0154         QActionList actions = createBasicActions( indices );
0155 
0156         QFont font;
0157         font.setPointSize( 16 );
0158         font.setBold( true );
0159 
0160         foreach( QAction * action, actions )
0161             m_pd->addItem( The::popupDropperFactory()->createItem( action ) );
0162 
0163 
0164         m_currentItems.clear();
0165         foreach( const QModelIndex &index, indices )
0166         {
0167             if( index.isValid() && index.internalPointer() )
0168                 m_currentItems << index;
0169         }
0170 
0171         PopupDropperItem* subItem;
0172 
0173         PopupDropper * morePud = nullptr;
0174         if ( actions.count() > 1 )
0175         {
0176             morePud = The::popupDropperFactory()->createPopupDropper( nullptr, true );
0177 
0178             foreach( QAction * action, actions )
0179                 morePud->addItem( The::popupDropperFactory()->createItem( action ) );
0180         }
0181         else
0182             m_pd->addItem( The::popupDropperFactory()->createItem( actions[0] ) );
0183 
0184         //TODO: Keep bugging i18n team about problems with 3 dots
0185         if ( actions.count() > 1 )
0186         {
0187             subItem = m_pd->addSubmenu( &morePud, i18n( "More..." )  );
0188             The::popupDropperFactory()->adjustItem( subItem );
0189         }
0190 
0191         m_pd->show();
0192     }
0193 
0194     QTreeView::startDrag( supportedActions );
0195     debug() << "After the drag!";
0196 
0197     if( m_pd )
0198     {
0199         debug() << "clearing PUD";
0200         connect( m_pd, &PopupDropper::fadeHideFinished, m_pd, &PopupDropper::clear );
0201         m_pd->hide();
0202     }
0203 
0204     m_dragMutex.lock();
0205     m_ongoingDrag = false;
0206     m_dragMutex.unlock();
0207 }
0208 
0209 void
0210 LastFmTreeView::slotReplacePlaylistByChildTracks()
0211 {
0212     playChildTracks( m_currentItems, Playlist::OnReplacePlaylistAction );
0213 }
0214 
0215 void
0216 LastFmTreeView::slotAppendChildTracks()
0217 {
0218     playChildTracks( m_currentItems, Playlist::OnAppendToPlaylistAction );
0219 }
0220 
0221 void
0222 LastFmTreeView::playChildTracks( const QModelIndex &item, Playlist::AddOptions insertMode)
0223 {
0224     QModelIndexList items;
0225     items << item;
0226 
0227     playChildTracks( items, insertMode );
0228 }
0229 void
0230 LastFmTreeView::playChildTracks ( const QModelIndexList &items, Playlist::AddOptions insertMode )
0231 {
0232     debug() << "LASTFM current items : " << items.size();
0233     Meta::TrackList list;
0234     foreach ( const QModelIndex &item, items )
0235     {
0236         Meta::TrackPtr track = model()->data(item, LastFm::TrackRole).value< Meta::TrackPtr >();
0237         if ( track )
0238             list << track;
0239     }
0240     std::stable_sort ( list.begin(), list.end(), Meta::Track::lessThan );
0241     The::playlistController()->insertOptioned( list, insertMode );
0242 }