File indexing completed on 2024-05-19 04:49:40
0001 /**************************************************************************************** 0002 * Copyright (c) 2011 Ralf Engels <ralf-engels@gmx.de> * 0003 * * 0004 * This program is free software; you can redistribute it and/or modify it under * 0005 * the terms of the GNU General Public License as published by the Free Software * 0006 * Foundation; either version 2 of the License, or (at your option) version 3 or * 0007 * any later version accepted by the membership of KDE e.V. (or its successor approved * 0008 * by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of * 0009 * version 3 of the license. * 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 #define DEBUG_PREFIX "AlbumPlayBias" 0020 0021 #include "AlbumPlayBias.h" 0022 0023 #include "core/meta/Meta.h" 0024 #include "core/support/Debug.h" 0025 #include "dynamic/TrackSet.h" 0026 0027 #include <KLocalizedString> 0028 0029 #include <QComboBox> 0030 #include <QFormLayout> 0031 #include <QXmlStreamReader> 0032 #include <QXmlStreamWriter> 0033 0034 QString 0035 Dynamic::AlbumPlayBiasFactory::i18nName() const 0036 { return i18nc("Name of the \"AlbumPlay\" bias", "Album play"); } 0037 0038 QString 0039 Dynamic::AlbumPlayBiasFactory::name() const 0040 { return Dynamic::AlbumPlayBias::sName(); } 0041 0042 QString 0043 Dynamic::AlbumPlayBiasFactory::i18nDescription() const 0044 { return i18nc("Description of the \"AlbumPlay\" bias", 0045 "The \"AlbumPlay\" bias adds tracks that belong to one album."); } 0046 0047 Dynamic::BiasPtr 0048 Dynamic::AlbumPlayBiasFactory::createBias() 0049 { return Dynamic::BiasPtr( new Dynamic::AlbumPlayBias() ); } 0050 0051 0052 0053 0054 Dynamic::AlbumPlayBias::AlbumPlayBias() 0055 : m_follow( DirectlyFollow ) 0056 { } 0057 0058 void 0059 Dynamic::AlbumPlayBias::fromXml( QXmlStreamReader *reader ) 0060 { 0061 while (!reader->atEnd()) { 0062 reader->readNext(); 0063 0064 if( reader->isStartElement() ) 0065 { 0066 QStringRef name = reader->name(); 0067 if( name == "follow" ) 0068 m_follow = followForName( reader->readElementText(QXmlStreamReader::SkipChildElements) ); 0069 else 0070 { 0071 debug()<<"Unexpected xml start element"<<reader->name()<<"in input"; 0072 reader->skipCurrentElement(); 0073 } 0074 } 0075 else if( reader->isEndElement() ) 0076 { 0077 break; 0078 } 0079 } 0080 } 0081 0082 void 0083 Dynamic::AlbumPlayBias::toXml( QXmlStreamWriter *writer ) const 0084 { 0085 writer->writeTextElement( QStringLiteral("follow"), nameForFollow( m_follow ) ); 0086 } 0087 0088 QString 0089 Dynamic::AlbumPlayBias::sName() 0090 { 0091 return QStringLiteral( "albumPlayBias" ); 0092 } 0093 0094 QString 0095 Dynamic::AlbumPlayBias::name() const 0096 { 0097 return Dynamic::AlbumPlayBias::sName(); 0098 } 0099 0100 QString 0101 Dynamic::AlbumPlayBias::toString() const 0102 { 0103 switch( m_follow ) 0104 { 0105 case DirectlyFollow: 0106 return i18nc("AlbumPlay bias representation", 0107 "The next track from the album"); 0108 case Follow: 0109 return i18nc("AlbumPlay bias representation", 0110 "Any later track from the album"); 0111 case DontCare: 0112 return i18nc("AlbumPlay bias representation", 0113 "Tracks from the same album"); 0114 } 0115 return QString(); 0116 } 0117 0118 0119 QWidget* 0120 Dynamic::AlbumPlayBias::widget( QWidget* parent ) 0121 { 0122 QComboBox *combo = new QComboBox( parent ); 0123 combo->addItem( i18n( "Track directly follows previous track in album" ), 0124 nameForFollow( DirectlyFollow ) ); 0125 combo->addItem( i18n( "Track comes after previous track in album" ), 0126 nameForFollow( Follow ) ); 0127 combo->addItem( i18n( "Track is in the same album as previous track" ), 0128 nameForFollow( DontCare ) ); 0129 switch( m_follow ) 0130 { 0131 case DirectlyFollow: combo->setCurrentIndex(0); break; 0132 case Follow: combo->setCurrentIndex(1); break; 0133 case DontCare: combo->setCurrentIndex(2); break; 0134 } 0135 connect( combo, QOverload<int>::of(&QComboBox::currentIndexChanged), 0136 this, &AlbumPlayBias::selectionChanged ); 0137 0138 return combo; 0139 } 0140 0141 Dynamic::TrackSet 0142 Dynamic::AlbumPlayBias::matchingTracks( const Meta::TrackList& playlist, 0143 int contextCount, int finalCount, 0144 const Dynamic::TrackCollectionPtr &universe ) const 0145 { 0146 Q_UNUSED( contextCount ); 0147 Q_UNUSED( finalCount ); 0148 0149 if( playlist.isEmpty() ) // no track means we can't find any tracks in the same album 0150 return Dynamic::TrackSet( universe, false ); 0151 0152 Meta::TrackPtr track = playlist.last(); 0153 Meta::AlbumPtr album = track->album(); 0154 0155 if( !album ) // no album means we can't find any tracks in the same album 0156 return Dynamic::TrackSet( universe, false ); 0157 0158 Meta::TrackList albumTracks = album->tracks(); 0159 0160 if( ( albumTracks.count() <= 1 ) || // the album has only one track (or even less) so there can't be any other tracks in the same album 0161 ( m_follow != DontCare && sameTrack( track, albumTracks.last() ) ) ) // track is the last one and we want to find a later one. 0162 return Dynamic::TrackSet( universe, false ); 0163 0164 // we assume that the album tracks are sorted by cd and track number which 0165 // is at least true for the SqlCollection 0166 TrackSet result( universe, false ); 0167 if( m_follow == DirectlyFollow ) 0168 { 0169 for( int i = 1; i < albumTracks.count(); i++ ) 0170 if( sameTrack( albumTracks[i-1], track ) ) 0171 result.unite( albumTracks[i] ); 0172 } 0173 else if( m_follow == Follow ) 0174 { 0175 bool found = false; 0176 for( int i = 0; i < albumTracks.count(); i++ ) 0177 { 0178 if( found ) 0179 result.unite( albumTracks[i] ); 0180 if( sameTrack( albumTracks[i], track ) ) 0181 found = true; 0182 } 0183 } 0184 else if( m_follow == DontCare ) 0185 { 0186 for( int i = 0; i < albumTracks.count(); i++ ) 0187 { 0188 if( !sameTrack( albumTracks[i], track ) ) 0189 result.unite( albumTracks[i] ); 0190 } 0191 } 0192 0193 return result; 0194 } 0195 0196 bool 0197 Dynamic::AlbumPlayBias::trackMatches( int position, 0198 const Meta::TrackList& playlist, 0199 int contextCount ) const 0200 { 0201 Q_UNUSED( contextCount ); 0202 0203 if( position <= 0 || playlist.count() <= position ) 0204 return true; 0205 0206 Meta::TrackPtr track = playlist[position-1]; 0207 Meta::AlbumPtr album = track->album(); 0208 Meta::TrackPtr currentTrack = playlist[position]; 0209 Meta::AlbumPtr currentAlbum = currentTrack->album(); 0210 0211 if( !album || album->tracks().isEmpty() ) 0212 return false; 0213 0214 Meta::TrackList albumTracks = album->tracks(); 0215 if( sameTrack( track, albumTracks.last() ) && m_follow != DontCare ) 0216 return false; 0217 0218 // we assume that the album tracks are sorted by cd and track number which 0219 // is at least true for the SqlCollection 0220 if( m_follow == DirectlyFollow ) 0221 { 0222 for( int i = 1; i < albumTracks.count(); i++ ) 0223 if( sameTrack( albumTracks[i-1], track ) ) 0224 return sameTrack( albumTracks[i], currentTrack ); 0225 return false; 0226 } 0227 else if( m_follow == Follow ) 0228 { 0229 bool found = false; 0230 for( int i = 0; i < albumTracks.count(); i++ ) 0231 { 0232 if( found && sameTrack( albumTracks[i], currentTrack ) ) 0233 return true; 0234 if( sameTrack( albumTracks[i], track ) ) 0235 found = true; 0236 } 0237 return false; 0238 } 0239 else if( m_follow == DontCare ) 0240 { 0241 return album == currentAlbum; 0242 } 0243 return false; 0244 } 0245 0246 0247 Dynamic::AlbumPlayBias::FollowType 0248 Dynamic::AlbumPlayBias::follow() const 0249 { 0250 return m_follow; 0251 } 0252 0253 void 0254 Dynamic::AlbumPlayBias::setFollow( Dynamic::AlbumPlayBias::FollowType value ) 0255 { 0256 m_follow = value; 0257 invalidate(); 0258 Q_EMIT changed( BiasPtr(this) ); 0259 } 0260 0261 void 0262 Dynamic::AlbumPlayBias::selectionChanged( int which ) 0263 { 0264 if( QComboBox *box = qobject_cast<QComboBox*>(sender()) ) 0265 setFollow( followForName( box->itemData( which ).toString() ) ); 0266 } 0267 0268 QString 0269 Dynamic::AlbumPlayBias::nameForFollow( Dynamic::AlbumPlayBias::FollowType match ) 0270 { 0271 switch( match ) 0272 { 0273 case Dynamic::AlbumPlayBias::DirectlyFollow: return QStringLiteral("directlyFollow"); 0274 case Dynamic::AlbumPlayBias::Follow: return QStringLiteral("follow"); 0275 case Dynamic::AlbumPlayBias::DontCare: return QStringLiteral("dontCare"); 0276 } 0277 return QString(); 0278 } 0279 0280 Dynamic::AlbumPlayBias::FollowType 0281 Dynamic::AlbumPlayBias::followForName( const QString &name ) 0282 { 0283 if( name == QLatin1String("directlyFollow") ) return DirectlyFollow; 0284 else if( name == QLatin1String("follow") ) return Follow; 0285 else if( name == QLatin1String("dontCare") ) return DontCare; 0286 else return DontCare; 0287 } 0288 0289 bool 0290 Dynamic::AlbumPlayBias::sameTrack( Meta::TrackPtr track1, Meta::TrackPtr track2 ) const 0291 { 0292 // We compare items which may be MetaProxy::Track or Meta::Track. For the 0293 // same underlying track, MetaProxy::Track == Meta;:Track will be true, but 0294 // Meta::Track == MetaProxy::Track false. Check both ways, and if either 0295 // returns true, it's the same track. 0296 return ( *track1 == *track2 ) || ( *track2 == *track1 ); 0297 } 0298 0299 0300