/src/libtomahawk/PlaylistInterface.cpp

http://github.com/tomahawk-player/tomahawk · C++ · 310 lines · 218 code · 66 blank · 26 comment · 34 complexity · ba73ce64f254cbe56091ec36cfcfd2e2 MD5 · raw file

  1. /* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
  2. *
  3. * Copyright 2010-2012, Christian Muehlhaeuser <muesli@tomahawk-player.org>
  4. * Copyright 2011, Leo Franchi <lfranchi@kde.org>
  5. * Copyright 2010-2012, Jeff Mitchell <jeff@tomahawk-player.org>
  6. *
  7. * Tomahawk is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation, either version 3 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * Tomahawk is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. #include "PlaylistInterface.h"
  21. #include "Result.h"
  22. #include "Pipeline.h"
  23. #include "Source.h"
  24. #include "utils/Logger.h"
  25. using namespace Tomahawk;
  26. PlaylistInterface::PlaylistInterface()
  27. : QObject()
  28. , m_latchMode( PlaylistModes::StayOnSong )
  29. , m_prevAvail( false )
  30. , m_nextAvail( false )
  31. , m_currentIndex( -1 )
  32. , m_finished( false )
  33. , m_foundFirstTrack( false )
  34. {
  35. m_id = uuid();
  36. }
  37. PlaylistInterface::~PlaylistInterface()
  38. {
  39. }
  40. result_ptr
  41. PlaylistInterface::previousResult() const
  42. {
  43. return siblingResult( -1 );
  44. }
  45. result_ptr
  46. PlaylistInterface::nextResult() const
  47. {
  48. return siblingResult( 1 );
  49. }
  50. qint64
  51. PlaylistInterface::siblingResultIndex( int itemsAway, qint64 rootIndex ) const
  52. {
  53. qint64 idx = siblingIndex( itemsAway, rootIndex );
  54. QList< qint64 > safetyCheck;
  55. // If safetyCheck contains idx, this means the interface keeps returning the same items and we won't discover anything new - abort
  56. // This can happen in repeat / random mode e.g.
  57. while ( idx >= 0 && !safetyCheck.contains( idx ) )
  58. {
  59. safetyCheck << idx;
  60. Tomahawk::query_ptr query = queryAt( idx );
  61. if ( query && query->playable() )
  62. {
  63. return idx;
  64. }
  65. idx = siblingIndex( itemsAway < 0 ? -1 : 1, idx );
  66. }
  67. return -1;
  68. }
  69. Tomahawk::result_ptr
  70. PlaylistInterface::siblingResult( int itemsAway, qint64 rootIndex ) const
  71. {
  72. qint64 idx = siblingResultIndex( itemsAway, rootIndex );
  73. if ( idx >= 0 )
  74. {
  75. Tomahawk::query_ptr query = queryAt( idx );
  76. if ( query && query->playable() )
  77. {
  78. return query->results().first();
  79. }
  80. }
  81. return Tomahawk::result_ptr();
  82. }
  83. Tomahawk::result_ptr
  84. PlaylistInterface::setSiblingResult( int itemsAway, qint64 rootIndex )
  85. {
  86. qint64 idx = siblingResultIndex( itemsAway, rootIndex );
  87. if ( idx >= 0 )
  88. {
  89. Tomahawk::query_ptr query = queryAt( idx );
  90. if ( query && query->playable() )
  91. {
  92. setCurrentIndex( idx );
  93. return query->results().first();
  94. }
  95. }
  96. return Tomahawk::result_ptr();
  97. }
  98. int
  99. PlaylistInterface::posOfResult( const Tomahawk::result_ptr& result ) const
  100. {
  101. const QList< Tomahawk::query_ptr > queries = tracks();
  102. int res = 0;
  103. foreach ( const Tomahawk::query_ptr& query, queries )
  104. {
  105. if ( query && query->numResults() && query->results().contains( result ) )
  106. return res;
  107. res++;
  108. }
  109. return -1;
  110. }
  111. int
  112. PlaylistInterface::posOfQuery( const Tomahawk::query_ptr& query ) const
  113. {
  114. const QList< Tomahawk::query_ptr > queries = tracks();
  115. int res = 0;
  116. foreach ( const Tomahawk::query_ptr& q, queries )
  117. {
  118. if ( query == q )
  119. return res;
  120. res++;
  121. }
  122. return -1;
  123. }
  124. QList<Tomahawk::query_ptr>
  125. PlaylistInterface::filterTracks( const QList<Tomahawk::query_ptr>& queries )
  126. {
  127. QList<Tomahawk::query_ptr> result;
  128. for ( int i = 0; i < queries.count(); i++ )
  129. {
  130. bool picked = true;
  131. const query_ptr q1 = queries.at( i );
  132. for ( int j = 0; j < result.count(); j++ )
  133. {
  134. if ( !picked )
  135. break;
  136. const query_ptr& q2 = result.at( j );
  137. if ( q1->track() == q2->track() )
  138. {
  139. picked = false;
  140. }
  141. }
  142. if ( picked )
  143. {
  144. result << q1;
  145. }
  146. }
  147. Pipeline::instance()->resolve( result );
  148. return result;
  149. }
  150. bool
  151. PlaylistInterface::hasNextResult() const
  152. {
  153. Tomahawk::result_ptr r = siblingResult( 1 );
  154. return ( r && r->isOnline() );
  155. }
  156. bool
  157. PlaylistInterface::hasPreviousResult() const
  158. {
  159. Tomahawk::result_ptr r = siblingResult( -1 );
  160. return ( r && r->isOnline() );
  161. }
  162. void
  163. PlaylistInterface::onItemsChanged()
  164. {
  165. if ( QThread::currentThread() != thread() )
  166. {
  167. QMetaObject::invokeMethod( this, "onItemsChanged", Qt::QueuedConnection );
  168. return;
  169. }
  170. Tomahawk::result_ptr prevResult = siblingResult( -1, m_currentIndex );
  171. Tomahawk::result_ptr nextResult = siblingResult( 1, m_currentIndex );
  172. {
  173. bool avail = prevResult && prevResult->playable();
  174. if ( avail != m_prevAvail )
  175. {
  176. m_prevAvail = avail;
  177. emit previousTrackAvailable( avail );
  178. }
  179. }
  180. {
  181. bool avail = nextResult && nextResult->playable();
  182. if ( avail != m_nextAvail )
  183. {
  184. m_nextAvail = avail;
  185. emit nextTrackAvailable( avail );
  186. }
  187. }
  188. }
  189. void
  190. PlaylistInterface::setCurrentIndex( qint64 index )
  191. {
  192. m_currentIndex = index;
  193. emit currentIndexChanged();
  194. onItemsChanged();
  195. }
  196. void
  197. PlaylistInterface::startLoading()
  198. {
  199. foreach ( const Tomahawk::query_ptr& query, tracks() )
  200. {
  201. disconnect( query.data(), SIGNAL( playableStateChanged( bool ) ), this, SLOT( onItemsChanged() ) );
  202. disconnect( query.data(), SIGNAL( resolvingFinished( bool ) ), this, SLOT( onQueryResolved() ) );
  203. }
  204. m_finished = false;
  205. }
  206. void
  207. PlaylistInterface::finishLoading()
  208. {
  209. foreach ( const Tomahawk::query_ptr& query, tracks() )
  210. {
  211. connect( query.data(), SIGNAL( playableStateChanged( bool ) ), SLOT( onItemsChanged() ), Qt::UniqueConnection );
  212. connect( query.data(), SIGNAL( resolvingFinished( bool ) ), SLOT( onQueryResolved() ), Qt::UniqueConnection );
  213. }
  214. m_finished = true;
  215. emit finishedLoading();
  216. }
  217. void
  218. PlaylistInterface::onQueryResolved()
  219. {
  220. if ( m_foundFirstTrack )
  221. return;
  222. // We're looking for the first playable track, but want to make sure the
  223. // second track doesn't start playing before the first really finished resolving
  224. foreach ( const Tomahawk::query_ptr& query, tracks() )
  225. {
  226. if ( !query->resolvingFinished() )
  227. {
  228. // Wait for this track to be resolved
  229. return;
  230. }
  231. if ( query->playable() )
  232. {
  233. // We have a playable track, all previous tracks are resolved but not playable
  234. break;
  235. }
  236. }
  237. // We have either found the first playable track or none of the tracks are playable
  238. m_foundFirstTrack = true;
  239. emit foundFirstPlayableTrack();
  240. foreach ( const Tomahawk::query_ptr& query, tracks() )
  241. {
  242. disconnect( query.data(), SIGNAL( resolvingFinished( bool ) ), this, SLOT( onQueryResolved() ) );
  243. }
  244. }