Warning, file /multimedia/amarok/src/dynamic/Bias.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 Jones <danielcjones@gmail.com> * 0003 * Copyright (c) 2009 Leo Franchi <lfranchi@kde.org> * 0004 * Copyright (c) 2010,2011 Ralf Engels <ralf-engels@gmx.de> * 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) version 3 or * 0009 * any later version accepted by the membership of KDE e.V. (or its successor approved * 0010 * by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of * 0011 * version 3 of the license. * 0012 * * 0013 * This program is distributed in the hope that it will be useful, but WITHOUT ANY * 0014 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * 0015 * PARTICULAR PURPOSE. See the GNU General Public License for more details. * 0016 * * 0017 * You should have received a copy of the GNU General Public License along with * 0018 * this program. If not, see <http://www.gnu.org/licenses/>. * 0019 ****************************************************************************************/ 0020 0021 #define DEBUG_PREFIX "Bias" 0022 0023 #include "Bias.h" 0024 0025 #include "core/support/Debug.h" 0026 #include "dynamic/BiasFactory.h" 0027 #include "dynamic/DynamicModel.h" 0028 #include "dynamic/biases/SearchQueryBias.h" 0029 0030 #include <KLocalizedString> 0031 0032 #include <QPainter> 0033 #include <QBuffer> 0034 #include <QXmlStreamReader> 0035 #include <QXmlStreamWriter> 0036 0037 // -------- AbstractBias ------------- 0038 0039 Dynamic::AbstractBias::AbstractBias() 0040 { } 0041 0042 Dynamic::AbstractBias::~AbstractBias() 0043 { 0044 // debug() << "destroying bias" << this; 0045 } 0046 0047 void 0048 Dynamic::AbstractBias::fromXml( QXmlStreamReader *reader ) 0049 { 0050 reader->skipCurrentElement(); 0051 } 0052 0053 0054 void 0055 Dynamic::AbstractBias::toXml( QXmlStreamWriter *writer ) const 0056 { 0057 Q_UNUSED( writer ); 0058 } 0059 0060 Dynamic::BiasPtr 0061 Dynamic::AbstractBias::clone() const 0062 { 0063 QByteArray bytes; 0064 QBuffer buffer( &bytes, nullptr ); 0065 buffer.open( QIODevice::ReadWrite ); 0066 0067 // write the bias 0068 QXmlStreamWriter xmlWriter( &buffer ); 0069 xmlWriter.writeStartElement( name() ); 0070 toXml( &xmlWriter ); 0071 xmlWriter.writeEndElement(); 0072 0073 // and read a new list 0074 buffer.seek( 0 ); 0075 QXmlStreamReader xmlReader( &buffer ); 0076 while( !xmlReader.isStartElement() ) 0077 xmlReader.readNext(); 0078 return Dynamic::BiasFactory::fromXml( &xmlReader ); 0079 } 0080 0081 QString 0082 Dynamic::AbstractBias::sName() 0083 { 0084 return QStringLiteral( "abstractBias" ); 0085 } 0086 0087 QString 0088 Dynamic::AbstractBias::name() const 0089 { 0090 return Dynamic::AbstractBias::sName(); 0091 } 0092 0093 QWidget* 0094 Dynamic::AbstractBias::widget( QWidget* parent ) 0095 { 0096 Q_UNUSED( parent ); 0097 return nullptr; 0098 } 0099 0100 void 0101 Dynamic::AbstractBias::paintOperator( QPainter* painter, const QRect& rect, Dynamic::AbstractBias* bias ) 0102 { 0103 Q_UNUSED( painter ); 0104 Q_UNUSED( rect ); 0105 Q_UNUSED( bias ); 0106 } 0107 0108 void 0109 Dynamic::AbstractBias::invalidate() 0110 { } 0111 0112 void 0113 Dynamic::AbstractBias::replace( const Dynamic::BiasPtr &newBias ) 0114 { 0115 Q_EMIT replaced( BiasPtr(const_cast<Dynamic::AbstractBias*>(this)), newBias ); 0116 } 0117 0118 // -------- RandomBias ------ 0119 0120 Dynamic::RandomBias::RandomBias() 0121 { } 0122 0123 Dynamic::RandomBias::~RandomBias() 0124 { } 0125 0126 QString 0127 Dynamic::RandomBias::sName() 0128 { 0129 return QStringLiteral( "randomBias" ); 0130 } 0131 0132 QString 0133 Dynamic::RandomBias::name() const 0134 { 0135 return Dynamic::RandomBias::sName(); 0136 } 0137 0138 QString 0139 Dynamic::RandomBias::toString() const 0140 { 0141 return i18nc("Random bias representation", "Random tracks"); 0142 } 0143 0144 QWidget* 0145 Dynamic::RandomBias::widget( QWidget* parent ) 0146 { 0147 Q_UNUSED( parent ); 0148 return nullptr; 0149 } 0150 0151 Dynamic::TrackSet 0152 Dynamic::RandomBias::matchingTracks( const Meta::TrackList& playlist, 0153 int contextCount, int finalCount, 0154 const Dynamic::TrackCollectionPtr &universe ) const 0155 { 0156 Q_UNUSED( playlist ); 0157 Q_UNUSED( contextCount ); 0158 Q_UNUSED( finalCount ); 0159 return Dynamic::TrackSet( universe, true ); 0160 } 0161 0162 bool 0163 Dynamic::RandomBias::trackMatches( int position, 0164 const Meta::TrackList& playlist, 0165 int contextCount ) const 0166 { 0167 Q_UNUSED( position ); 0168 Q_UNUSED( playlist ); 0169 Q_UNUSED( contextCount ); 0170 return true; 0171 } 0172 0173 // -------- AndBias ------ 0174 0175 Dynamic::AndBias::AndBias() 0176 { } 0177 0178 Dynamic::AndBias::~AndBias() 0179 { } 0180 0181 void 0182 Dynamic::AndBias::fromXml( QXmlStreamReader *reader ) 0183 { 0184 while (!reader->atEnd()) { 0185 reader->readNext(); 0186 0187 if( reader->isStartElement() ) 0188 { 0189 Dynamic::BiasPtr bias( Dynamic::BiasFactory::fromXml( reader ) ); 0190 if( bias ) 0191 { 0192 appendBias( bias ); 0193 } 0194 else 0195 { 0196 warning()<<"Unexpected xml start element"<<reader->name()<<"in input"; 0197 reader->skipCurrentElement(); 0198 } 0199 } 0200 else if( reader->isEndElement() ) 0201 { 0202 break; 0203 } 0204 } 0205 } 0206 0207 void 0208 Dynamic::AndBias::toXml( QXmlStreamWriter *writer ) const 0209 { 0210 foreach( Dynamic::BiasPtr bias, m_biases ) 0211 { 0212 writer->writeStartElement( bias->name() ); 0213 bias->toXml( writer ); 0214 writer->writeEndElement(); 0215 } 0216 } 0217 0218 QString 0219 Dynamic::AndBias::sName() 0220 { 0221 return QStringLiteral( "andBias" ); 0222 } 0223 0224 QString 0225 Dynamic::AndBias::name() const 0226 { 0227 return Dynamic::AndBias::sName(); 0228 } 0229 0230 QString 0231 Dynamic::AndBias::toString() const 0232 { 0233 return i18nc("And bias representation", "Match all"); 0234 } 0235 0236 0237 QWidget* 0238 Dynamic::AndBias::widget( QWidget* parent ) 0239 { 0240 Q_UNUSED( parent ); 0241 return nullptr; 0242 } 0243 0244 void 0245 Dynamic::AndBias::paintOperator( QPainter* painter, const QRect& rect, Dynamic::AbstractBias* bias ) 0246 { 0247 if( m_biases.indexOf( Dynamic::BiasPtr(bias) ) > 0 ) 0248 { 0249 painter->drawText( rect.adjusted(2, 0, -2, 0), 0250 Qt::AlignRight, 0251 i18nc("Prefix for AndBias. Shown in front of a bias in the dynamic playlist view", "and" ) ); 0252 } 0253 } 0254 0255 Dynamic::TrackSet 0256 Dynamic::AndBias::matchingTracks( const Meta::TrackList& playlist, 0257 int contextCount, int finalCount, 0258 const Dynamic::TrackCollectionPtr &universe ) const 0259 { 0260 DEBUG_BLOCK; 0261 debug() << "universe:" << universe.data(); 0262 0263 m_tracks = Dynamic::TrackSet( universe, true ); 0264 m_outstandingMatches = 0; 0265 0266 foreach( Dynamic::BiasPtr bias, m_biases ) 0267 { 0268 Dynamic::TrackSet tracks = bias->matchingTracks( playlist, contextCount, finalCount, universe ); 0269 if( tracks.isOutstanding() ) 0270 m_outstandingMatches++; 0271 else 0272 m_tracks.intersect( tracks ); 0273 0274 // debug() << "AndBias::matchingTracks" << bias->name() << "tracks:"<<tracks.trackCount() << "outstanding?" << tracks.isOutstanding() << "numOUt:" << m_outstandingMatches; 0275 0276 if( m_tracks.isEmpty() ) 0277 break; 0278 } 0279 0280 // debug() << "AndBias::matchingTracks end: tracks:"<<m_tracks.trackCount() << "outstanding?" << m_tracks.isOutstanding() << "numOUt:" << m_outstandingMatches; 0281 0282 if( m_outstandingMatches > 0 ) 0283 return Dynamic::TrackSet(); 0284 else 0285 return m_tracks; 0286 } 0287 0288 bool 0289 Dynamic::AndBias::trackMatches( int position, 0290 const Meta::TrackList& playlist, 0291 int contextCount ) const 0292 { 0293 foreach( Dynamic::BiasPtr bias, m_biases ) 0294 { 0295 if( !bias->trackMatches( position, playlist, contextCount ) ) 0296 return false; 0297 } 0298 return true; 0299 } 0300 0301 void 0302 Dynamic::AndBias::invalidate() 0303 { 0304 foreach( Dynamic::BiasPtr bias, m_biases ) 0305 { 0306 bias->invalidate(); 0307 } 0308 m_tracks = TrackSet(); 0309 } 0310 0311 void 0312 Dynamic::AndBias::appendBias(const BiasPtr &bias ) 0313 { 0314 bool newInModel = DynamicModel::instance()->index( bias ).isValid(); 0315 if (newInModel) { 0316 warning() << "Argh, the old bias "<<bias->toString()<<"is still in a model"; 0317 return; 0318 } 0319 0320 BiasPtr thisPtr( this ); 0321 bool inModel = DynamicModel::instance()->index( thisPtr ).isValid(); 0322 if( inModel ) 0323 DynamicModel::instance()->beginInsertBias( thisPtr, m_biases.count() ); 0324 m_biases.append( bias ); 0325 if( inModel ) 0326 DynamicModel::instance()->endInsertBias(); 0327 0328 connect( bias.data(), &Dynamic::AbstractBias::resultReady, 0329 this, &AndBias::resultReceived ); 0330 connect( bias.data(), &Dynamic::AbstractBias::replaced, 0331 this, &AndBias::biasReplaced ); 0332 connect( bias.data(), &Dynamic::AbstractBias::changed, 0333 this, &AndBias::biasChanged ); 0334 Q_EMIT biasAppended( bias ); 0335 0336 // creating a shared pointer and destructing it just afterwards would 0337 // also destruct this object. 0338 // so we give the object creating this bias a chance to increment the refcount 0339 Q_EMIT changed( thisPtr ); 0340 } 0341 0342 void 0343 Dynamic::AndBias::moveBias( int from, int to ) 0344 { 0345 if( from == to ) 0346 return; 0347 if( from < 0 || from >= m_biases.count() ) 0348 return; 0349 if( to < 0 || to >= m_biases.count() ) 0350 return; 0351 0352 BiasPtr thisPtr( this ); 0353 bool inModel = DynamicModel::instance()->index( thisPtr ).isValid(); 0354 if( inModel ) 0355 DynamicModel::instance()->beginMoveBias( thisPtr, from, to ); 0356 m_biases.insert( to, m_biases.takeAt( from ) ); 0357 if( inModel ) 0358 DynamicModel::instance()->endMoveBias(); 0359 0360 Q_EMIT biasMoved( from, to ); 0361 Q_EMIT changed( BiasPtr( this ) ); 0362 } 0363 0364 0365 void 0366 Dynamic::AndBias::resultReceived( const Dynamic::TrackSet &tracks ) 0367 { 0368 m_tracks.intersect( tracks ); 0369 --m_outstandingMatches; 0370 0371 if( m_outstandingMatches < 0 ) 0372 warning() << "Received more results than expected."; 0373 else if( m_outstandingMatches == 0 ) 0374 Q_EMIT resultReady( m_tracks ); 0375 } 0376 0377 void 0378 Dynamic::AndBias::biasReplaced( const Dynamic::BiasPtr &oldBias, const Dynamic::BiasPtr &newBias ) 0379 { 0380 DEBUG_BLOCK; 0381 BiasPtr thisPtr( this ); 0382 int index = m_biases.indexOf( oldBias ); 0383 Q_ASSERT( index >= 0 ); 0384 0385 disconnect( oldBias.data(), nullptr, this, nullptr ); 0386 bool inModel = DynamicModel::instance()->index( thisPtr ).isValid(); 0387 if( inModel ) 0388 DynamicModel::instance()->beginRemoveBias( thisPtr, index ); 0389 m_biases.removeAt( index ); 0390 if( inModel ) 0391 DynamicModel::instance()->endRemoveBias(); 0392 Q_EMIT biasRemoved( index ); 0393 0394 if( newBias ) 0395 { 0396 connect( newBias.data(), &Dynamic::AbstractBias::resultReady, 0397 this, &AndBias::resultReceived ); 0398 connect( newBias.data(), &Dynamic::AbstractBias::replaced, 0399 this, &AndBias::biasReplaced ); 0400 connect( newBias.data(), &Dynamic::AbstractBias::changed, 0401 this, &AndBias::changed ); 0402 0403 if( inModel ) 0404 DynamicModel::instance()->beginInsertBias( thisPtr, index ); 0405 m_biases.insert( index, newBias ); 0406 if( inModel ) 0407 DynamicModel::instance()->endInsertBias(); 0408 0409 // we don't have an bias inserted signal 0410 Q_EMIT biasAppended( newBias ); 0411 Q_EMIT biasMoved( m_biases.count()-1, index ); 0412 } 0413 0414 Q_EMIT changed( thisPtr ); 0415 } 0416 0417 void 0418 Dynamic::AndBias::biasChanged( const Dynamic::BiasPtr &bias ) 0419 { 0420 BiasPtr thisPtr( this ); 0421 Q_EMIT changed( thisPtr ); 0422 bool inModel = DynamicModel::instance()->index( thisPtr ).isValid(); 0423 if( inModel ) 0424 DynamicModel::instance()->biasChanged( bias ); 0425 } 0426 0427 // -------- OrBias ------ 0428 0429 Dynamic::OrBias::OrBias() 0430 : AndBias() 0431 { } 0432 0433 QString 0434 Dynamic::OrBias::sName() 0435 { 0436 return QStringLiteral( "orBias" ); 0437 } 0438 0439 QString 0440 Dynamic::OrBias::name() const 0441 { 0442 return Dynamic::OrBias::sName(); 0443 } 0444 0445 void 0446 Dynamic::OrBias::paintOperator( QPainter* painter, const QRect& rect, Dynamic::AbstractBias* bias ) 0447 { 0448 if( m_biases.indexOf( Dynamic::BiasPtr(bias) ) > 0 ) 0449 { 0450 painter->drawText( rect.adjusted(2, 0, -2, 0), 0451 Qt::AlignRight, 0452 i18nc("Prefix for OrBias. Shown in front of a bias in the dynamic playlist view", "or" ) ); 0453 } 0454 } 0455 0456 0457 QString 0458 Dynamic::OrBias::toString() const 0459 { 0460 return i18nc("Or bias representation", "Match any"); 0461 } 0462 0463 Dynamic::TrackSet 0464 Dynamic::OrBias::matchingTracks( const Meta::TrackList& playlist, 0465 int contextCount, int finalCount, 0466 const Dynamic::TrackCollectionPtr &universe ) const 0467 { 0468 m_tracks = Dynamic::TrackSet( universe, false ); 0469 m_outstandingMatches = 0; 0470 0471 foreach( Dynamic::BiasPtr bias, m_biases ) 0472 { 0473 Dynamic::TrackSet tracks = bias->matchingTracks( playlist, contextCount, finalCount, universe ); 0474 if( tracks.isOutstanding() ) 0475 m_outstandingMatches++; 0476 else 0477 m_tracks.unite( tracks ); 0478 0479 if( m_tracks.isFull() ) 0480 break; 0481 } 0482 0483 if( m_outstandingMatches > 0 ) 0484 return Dynamic::TrackSet(); 0485 else 0486 return m_tracks; 0487 } 0488 0489 bool 0490 Dynamic::OrBias::trackMatches( int position, 0491 const Meta::TrackList& playlist, 0492 int contextCount ) const 0493 { 0494 foreach( Dynamic::BiasPtr bias, m_biases ) 0495 { 0496 if( bias->trackMatches( position, playlist, contextCount ) ) 0497 return true; 0498 } 0499 return false; 0500 } 0501 0502 void 0503 Dynamic::OrBias::resultReceived( const Dynamic::TrackSet &tracks ) 0504 { 0505 m_tracks.unite( tracks ); 0506 --m_outstandingMatches; 0507 0508 if( m_outstandingMatches < 0 ) 0509 warning() << "Received more results than expected."; 0510 else if( m_outstandingMatches == 0 ) 0511 Q_EMIT resultReady( m_tracks ); 0512 } 0513 0514