Warning, file /multimedia/amarok/src/dynamic/BiasedPlaylist.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /**************************************************************************************** 0002 * Copyright (c) 2008 Daniel Caleb Jones <danielcjones@gmail.com> * 0003 * Copyright (c) 2013 Ralf Engels <ralf-engels@gmx.de> * 0004 * * 0005 * This program is free software; you can redistribute it and/or modify it under * 0006 * the terms of the GNU General Public License as published by the Free Software * 0007 * Foundation; either version 2 of the License, or (at your option) version 3 or * 0008 * any later version accepted by the membership of KDE e.V. (or its successor approved * 0009 * by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of * 0010 * version 3 of the license. * 0011 * * 0012 * This program is distributed in the hope that it will be useful, but WITHOUT ANY * 0013 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * 0014 * PARTICULAR PURPOSE. See the GNU General Public License for more details. * 0015 * * 0016 * You should have received a copy of the GNU General Public License along with * 0017 * this program. If not, see <http://www.gnu.org/licenses/>. * 0018 ****************************************************************************************/ 0019 0020 #define DEBUG_PREFIX "BiasedPlaylist" 0021 0022 #include "BiasedPlaylist.h" 0023 0024 #include "App.h" 0025 #include "amarokconfig.h" 0026 #include "core/collections/Collection.h" 0027 #include "core/logger/Logger.h" 0028 #include "core/meta/Meta.h" 0029 #include "core/support/Components.h" 0030 #include "core/support/Debug.h" 0031 #include "core-impl/collections/support/CollectionManager.h" 0032 #include "dynamic/BiasSolver.h" 0033 #include "dynamic/BiasFactory.h" 0034 #include "dynamic/DynamicModel.h" 0035 #include "playlist/PlaylistModelStack.h" // for The::playlist 0036 0037 #include <QThread> 0038 #include <QXmlStreamReader> 0039 #include <QXmlStreamWriter> 0040 0041 Dynamic::BiasedPlaylist::BiasedPlaylist( QObject *parent ) 0042 : DynamicPlaylist( parent ) 0043 , m_bias( nullptr ) 0044 , m_solver( nullptr ) 0045 { 0046 m_title = i18nc( "Title for a default dynamic playlist. The default playlist only returns random tracks.", "Random" ); 0047 0048 BiasPtr biasPtr( BiasPtr( new Dynamic::RandomBias() ) ); 0049 biasReplaced( BiasPtr(), biasPtr ); 0050 } 0051 0052 Dynamic::BiasedPlaylist::BiasedPlaylist( QXmlStreamReader *reader, QObject *parent ) 0053 : DynamicPlaylist( parent ) 0054 , m_bias( nullptr ) 0055 , m_solver( nullptr ) 0056 { 0057 while (!reader->atEnd()) { 0058 reader->readNext(); 0059 0060 if( reader->isStartElement() ) 0061 { 0062 QStringRef name = reader->name(); 0063 if( name == "title" ) 0064 m_title = reader->readElementText(QXmlStreamReader::SkipChildElements); 0065 else 0066 { 0067 BiasPtr biasPtr( Dynamic::BiasFactory::fromXml( reader ) ); 0068 if( biasPtr ) 0069 { 0070 biasReplaced( BiasPtr(), biasPtr ); 0071 } 0072 else 0073 { 0074 debug()<<"Unexpected xml start element"<<reader->name()<<"in input"; 0075 reader->skipCurrentElement(); 0076 } 0077 } 0078 } 0079 else if( reader->isEndElement() ) 0080 { 0081 break; 0082 } 0083 } 0084 } 0085 0086 Dynamic::BiasedPlaylist::~BiasedPlaylist() 0087 { 0088 requestAbort(); 0089 } 0090 0091 void 0092 Dynamic::BiasedPlaylist::toXml( QXmlStreamWriter *writer ) const 0093 { 0094 writer->writeTextElement( QStringLiteral("title"), m_title ); 0095 writer->writeStartElement( m_bias->name() ); 0096 m_bias->toXml( writer ); 0097 writer->writeEndElement(); 0098 } 0099 0100 void 0101 Dynamic::BiasedPlaylist::requestAbort() 0102 { 0103 DEBUG_BLOCK 0104 if( m_solver ) { 0105 m_solver->setAutoDelete( true ); 0106 m_solver->requestAbort(); 0107 m_solver = nullptr; 0108 } 0109 } 0110 0111 void 0112 Dynamic::BiasedPlaylist::startSolver( int numRequested ) 0113 { 0114 DEBUG_BLOCK 0115 debug() << "BiasedPlaylist in:" << QThread::currentThreadId(); 0116 0117 if( !m_solver ) 0118 { 0119 debug() << "assigning new m_solver"; 0120 m_solver = new BiasSolver( numRequested, m_bias, getContext() ); 0121 connect( m_solver, &BiasSolver::done, this, &BiasedPlaylist::solverFinished ); 0122 0123 Amarok::Logger::newProgressOperation( m_solver, 0124 i18n( "Generating playlist..." ), 100, 0125 this, &BiasedPlaylist::requestAbort ); 0126 0127 ThreadWeaver::Queue::instance()->enqueue( QSharedPointer<ThreadWeaver::Job>(m_solver) ); 0128 0129 debug() << "called prepareToRun"; 0130 } 0131 else 0132 debug() << "solver already running!"; 0133 } 0134 0135 void 0136 Dynamic::BiasedPlaylist::biasChanged() 0137 { 0138 Q_EMIT changed( this ); 0139 bool inModel = DynamicModel::instance()->index( this ).isValid(); 0140 if( inModel ) 0141 DynamicModel::instance()->biasChanged( m_bias ); 0142 } 0143 0144 void 0145 Dynamic::BiasedPlaylist::biasReplaced( const Dynamic::BiasPtr &oldBias, const Dynamic::BiasPtr &newBias ) 0146 { 0147 if( oldBias && !newBias ) // don't move the last bias away from this playlist without replacement 0148 return; 0149 0150 bool inModel = DynamicModel::instance()->index( this ).isValid(); 0151 if( m_bias ) 0152 { 0153 disconnect( m_bias.data(), nullptr, this, nullptr ); 0154 0155 if( inModel ) 0156 Dynamic::DynamicModel::instance()->beginRemoveBias( this ); 0157 m_bias = nullptr; 0158 if( inModel ) 0159 Dynamic::DynamicModel::instance()->endRemoveBias(); 0160 } 0161 0162 if( inModel ) 0163 Dynamic::DynamicModel::instance()->beginInsertBias( this ); 0164 m_bias = newBias; 0165 if( inModel ) 0166 Dynamic::DynamicModel::instance()->endInsertBias(); 0167 0168 connect( m_bias.data(), &AbstractBias::changed, 0169 this, &BiasedPlaylist::biasChanged ); 0170 connect( m_bias.data(), &AbstractBias::replaced, 0171 this, &BiasedPlaylist::biasReplaced ); 0172 0173 if( oldBias ) // don't Q_EMIT a changed during construction 0174 biasChanged(); 0175 } 0176 0177 void 0178 Dynamic::BiasedPlaylist::requestTracks( int n ) 0179 { 0180 if( n > 0 ) 0181 startSolver( n + 1 ); // we request an additional track so that we don't end up in a position that e.g. does have no "similar" track. 0182 } 0183 0184 Dynamic::BiasPtr 0185 Dynamic::BiasedPlaylist::bias() const 0186 { 0187 return m_bias; 0188 } 0189 0190 void 0191 Dynamic::BiasedPlaylist::solverFinished() 0192 { 0193 DEBUG_BLOCK 0194 0195 if( m_solver != sender() ) 0196 return; // maybe an old solver... aborted solvers should autodelete 0197 0198 Meta::TrackList list = m_solver->solution(); 0199 if( list.count() > 0 ) 0200 { 0201 // remove the additional requested track 0202 if( list.count() > 1 ) 0203 list.removeLast(); 0204 Q_EMIT tracksReady( list ); 0205 } 0206 0207 m_solver->deleteLater(); 0208 m_solver = nullptr; 0209 } 0210 0211 0212 Meta::TrackList 0213 Dynamic::BiasedPlaylist::getContext() 0214 { 0215 Meta::TrackList context = The::playlist()->tracks(); 0216 0217 return context; 0218 } 0219