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

0001 /****************************************************************************************
0002  * Copyright (c) 2007 Ian Monroe <ian@monroe.nu>                                        *
0003  * Copyright (c) 2008 Soren Harward <stharward@gmail.com>                               *
0004  * Copyright (c) 2008 Nikolaj Hald Nielsen <nhn@kde.org>                                *
0005  * Copyright (c) 2009 Téo Mrnjavac <teo@kde.org>                                        *
0006  * Copyright (c) 2010 Nanno Langstraat <langstr@gmail.com>                              *
0007  * Copyright (c) 2011 Sandeep Raghuraman <sandy.8925@gmail.com>                         *
0008  *                                                                                      *
0009  * This program is free software; you can redistribute it and/or modify it under        *
0010  * the terms of the GNU General Public License as published by the Free Software        *
0011  * Foundation; either version 2 of the License, or (at your option) version 3 or        *
0012  * any later version accepted by the membership of KDE e.V. (or its successor approved  *
0013  * by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of  *
0014  * version 3 of the license.                                                            *
0015  *                                                                                      *
0016  * This program is distributed in the hope that it will be useful, but WITHOUT ANY      *
0017  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A      *
0018  * PARTICULAR PURPOSE. See the GNU General Public License for more details.             *
0019  *                                                                                      *
0020  * You should have received a copy of the GNU General Public License along with         *
0021  * this program.  If not, see <http://www.gnu.org/licenses/>.                           *
0022  ****************************************************************************************/
0023 
0024 #include "StandardTrackNavigator.h"
0025 
0026 #include "amarokconfig.h"
0027 #include "core/meta/Meta.h"
0028 #include "core/support/Amarok.h"
0029 #include "playlist/PlaylistModelStack.h"
0030 
0031 Playlist::StandardTrackNavigator::StandardTrackNavigator()
0032 {
0033     m_repeatPlaylist = ( AmarokConfig::trackProgression() == AmarokConfig::EnumTrackProgression::RepeatPlaylist );
0034     m_onlyQueue = ( AmarokConfig::trackProgression() == AmarokConfig::EnumTrackProgression::OnlyQueue );
0035 }
0036 
0037 quint64
0038 Playlist::StandardTrackNavigator::chooseLastTrack( bool repeatPlaylist )
0039 {
0040     Meta::TrackPtr track;
0041     bool playableTrackFound = false;
0042     int lastRow;
0043 
0044     // reminder: if that function is modified, it's important to research if changes must also
0045     // be applied to similar code in `Playlist::StandardTrackNavigator::chooseNextTrack()`
0046 
0047     // search for a playable track in order from right before the currently active track till the start
0048     for ( lastRow = m_model->activeRow() - 1  ; lastRow >= 0 ; lastRow-- ) // 'activeRow()' may be -1
0049     {
0050         track = m_model->trackAt(lastRow);
0051         if ( track->isPlayable() )
0052         {
0053             playableTrackFound = true;
0054             break;
0055         }
0056     }
0057 
0058     // Even though the user is explicitly asking us to go back, still only do wrap-around
0059     // in mode 'm_repeatPlaylist'. Reason: many users of the standard navigator like to
0060     // move to the start of the playlist by blindly pressing "Prev" a lot of times.
0061     // If no playable track was found, the playlist needs to be repeated, it's not empty
0062     // and there's an active track: search from end of playlist till currently active track.
0063     if ( !playableTrackFound && repeatPlaylist && m_model->qaim()->rowCount() > 0 && m_model->activeRow() >= 0)
0064     {
0065         for ( lastRow = m_model->qaim()->rowCount() - 1 ; lastRow >= m_model->activeRow() ; lastRow--)
0066         {
0067             track = m_model->trackAt( lastRow );
0068             if ( track->isPlayable() )
0069             {
0070                 playableTrackFound = true;
0071                 break;
0072             }
0073         }
0074     }
0075 
0076     if ( playableTrackFound && m_model->rowExists( lastRow ) )
0077         return m_model->idAt( lastRow );
0078     else
0079         return 0;
0080 }
0081 
0082 quint64
0083 Playlist::StandardTrackNavigator::requestNextTrack()
0084 {
0085     if( !m_queue.isEmpty() ) {
0086         quint64 ret = m_queue.takeFirst();
0087         Playlist::ModelStack::instance()->bottom()->emitQueueChanged();
0088         return ret;
0089     }
0090 
0091     return chooseNextTrack( m_repeatPlaylist );
0092 }
0093 
0094 quint64
0095 Playlist::StandardTrackNavigator::requestUserNextTrack()
0096 {
0097     if( !m_queue.isEmpty() ) {
0098         quint64 ret = m_queue.takeFirst();
0099         Playlist::ModelStack::instance()->bottom()->emitQueueChanged();
0100         return ret;
0101     }
0102 
0103     // Don't make wrap-around conditional on 'm_repeatPlaylist': the user is explicitly asking for this.
0104     return chooseNextTrack( true );
0105 }
0106 
0107 quint64
0108 Playlist::StandardTrackNavigator::requestLastTrack()
0109 {
0110     if( !m_queue.isEmpty() ) {
0111         quint64 ret = m_queue.takeFirst();
0112         Playlist::ModelStack::instance()->bottom()->emitQueueChanged();
0113         return ret;
0114     }
0115 
0116     return chooseLastTrack( m_repeatPlaylist );
0117 }
0118 
0119 quint64
0120 Playlist::StandardTrackNavigator::chooseNextTrack( bool repeatPlaylist )
0121 {
0122     if( !m_queue.isEmpty() )
0123         return m_queue.first();
0124 
0125     if( m_onlyQueue )
0126         return 0;
0127 
0128     Meta::TrackPtr track;
0129     bool playableTrackFound = false;
0130     int nextRow;
0131 
0132     // reminder: if that function is modified, it's important to research if changes must also
0133     // be applied to similar code in `Playlist::StandardTrackNavigator::chooseLastTrack()`
0134 
0135     //search for a playable track in order from right after the currently active track till the end
0136     for( nextRow = m_model->activeRow() + 1  ; nextRow < m_model->qaim()->rowCount() ; nextRow++ ) // 'activeRow()' may be -1.
0137     {
0138         track = m_model->trackAt(nextRow);
0139         if( track->isPlayable() )
0140         {
0141             playableTrackFound = true;
0142             break;
0143         }
0144     }
0145 
0146     //if no playable track was found and the playlist needs to be repeated, search from top of playlist till currently active track
0147     if( !playableTrackFound && repeatPlaylist )
0148     {
0149         //nextRow=0; This row is still invalid if 'rowCount() == 0'.
0150         for( nextRow = 0 ; nextRow <= m_model->activeRow() ; nextRow++)
0151         {
0152             track = m_model->trackAt( nextRow );
0153             if( track->isPlayable() )
0154             {
0155                 playableTrackFound = true;
0156                 break;
0157             }
0158         }
0159     }
0160 
0161     if( playableTrackFound && m_model->rowExists( nextRow ) )
0162         return m_model->idAt( nextRow );
0163     else
0164         return 0;
0165 }