/src/libtomahawk/playlist/TreeModel.cpp

http://github.com/tomahawk-player/tomahawk · C++ · 418 lines · 285 code · 92 blank · 41 comment · 42 complexity · fa9a9104d3b31b9f5c55bbe0cb23c667 MD5 · raw file

  1. /* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
  2. *
  3. * Copyright 2010-2015, Christian Muehlhaeuser <muesli@tomahawk-player.org>
  4. * Copyright 2010-2011, Jeff Mitchell <jeff@tomahawk-player.org>
  5. * Copyright 2012, Leo Franchi <lfranchi@kde.org>
  6. * Copyright 2013, Teo Mrnjavac <teo@kde.org>
  7. *
  8. * Tomahawk is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation, either version 3 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * Tomahawk is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
  20. */
  21. #include "TreeModel.h"
  22. #include <QMimeData>
  23. #include "Pipeline.h"
  24. #include "Source.h"
  25. #include "SourceList.h"
  26. #include "audio/AudioEngine.h"
  27. #include "database/DatabaseCommand_AllAlbums.h"
  28. #include "database/DatabaseCommand_AllTracks.h"
  29. #include "database/Database.h"
  30. #include "AlbumPlaylistInterface.h"
  31. #include "PlayableItem.h"
  32. #include "utils/TomahawkUtilsGui.h"
  33. #include "utils/Closure.h"
  34. #include "utils/Logger.h"
  35. using namespace Tomahawk;
  36. TreeModel::TreeModel( QObject* parent )
  37. : PlayableModel( parent )
  38. , m_mode( DatabaseMode )
  39. {
  40. PlayableModel::setIcon( TomahawkUtils::tinted( TomahawkUtils::defaultPixmap(
  41. TomahawkUtils::DefaultCollection,
  42. TomahawkUtils::Original,
  43. // big enough for the ViewPage header on retina
  44. QSize( 256, 256 ) ), Qt::white ) );
  45. connect( AudioEngine::instance(), SIGNAL( started( Tomahawk::result_ptr ) ), SLOT( onPlaybackStarted( Tomahawk::result_ptr ) ), Qt::DirectConnection );
  46. connect( AudioEngine::instance(), SIGNAL( stopped() ), SLOT( onPlaybackStopped() ), Qt::DirectConnection );
  47. }
  48. TreeModel::~TreeModel()
  49. {
  50. tDebug() << Q_FUNC_INFO;
  51. }
  52. void
  53. TreeModel::setMode( ModelMode mode )
  54. {
  55. clear();
  56. m_mode = mode;
  57. emit modeChanged( mode );
  58. }
  59. Tomahawk::collection_ptr
  60. TreeModel::collection() const
  61. {
  62. return m_collection;
  63. }
  64. void
  65. TreeModel::getCover( const QModelIndex& index )
  66. {
  67. PlayableItem* item = itemFromIndex( index );
  68. if ( !item->artist().isNull() && !item->artist()->coverLoaded() )
  69. item->artist()->cover( QSize( 0, 0 ) );
  70. else if ( !item->album().isNull() && !item->album()->coverLoaded() )
  71. item->album()->cover( QSize( 0, 0 ) );
  72. }
  73. bool
  74. TreeModel::canFetchMore( const QModelIndex& parent ) const
  75. {
  76. PlayableItem* parentItem = itemFromIndex( parent );
  77. if ( parentItem->fetchingMore() )
  78. return false;
  79. if ( !parentItem->artist().isNull() )
  80. {
  81. return true;
  82. }
  83. else if ( !parentItem->album().isNull() )
  84. {
  85. return true;
  86. }
  87. return false;
  88. }
  89. void
  90. TreeModel::fetchMore( const QModelIndex& parent )
  91. {
  92. PlayableItem* parentItem = itemFromIndex( parent );
  93. if ( !parentItem || parentItem->fetchingMore() )
  94. return;
  95. parentItem->setFetchingMore( true );
  96. if ( !parentItem->artist().isNull() )
  97. {
  98. tDebug() << Q_FUNC_INFO << "Loading Artist:" << parentItem->artist()->name();
  99. fetchAlbums( parentItem->artist() );
  100. }
  101. else if ( !parentItem->album().isNull() )
  102. {
  103. tDebug() << Q_FUNC_INFO << "Loading Album:" << parentItem->album()->artist()->name() << parentItem->album()->name() << parentItem->album()->id();
  104. addTracks( parentItem->album(), parent );
  105. }
  106. else
  107. Q_ASSERT( false );
  108. }
  109. void
  110. TreeModel::addArtists( const artist_ptr& artist )
  111. {
  112. if ( artist.isNull() )
  113. return;
  114. startLoading();
  115. QList<Tomahawk::artist_ptr> artists;
  116. artists << artist;
  117. onArtistsAdded( artists );
  118. }
  119. void
  120. TreeModel::fetchAlbums( const artist_ptr& artist )
  121. {
  122. startLoading();
  123. connect( artist.data(), SIGNAL( albumsAdded( QList<Tomahawk::album_ptr>, Tomahawk::ModelMode ) ),
  124. SLOT( onAlbumsFound( QList<Tomahawk::album_ptr>, Tomahawk::ModelMode ) ), Qt::UniqueConnection );
  125. const QModelIndex parent = indexFromArtist( artist );
  126. addAlbums( parent, artist->albums( m_mode, m_collection ) );
  127. }
  128. void
  129. TreeModel::onAlbumsFound( const QList<Tomahawk::album_ptr>& albums, ModelMode mode )
  130. {
  131. if ( m_mode != mode )
  132. return;
  133. Tomahawk::Artist* artist = qobject_cast< Tomahawk::Artist* >( sender() );
  134. if ( !artist )
  135. return;
  136. const artist_ptr artistp = artist->weakRef().toStrongRef();
  137. disconnect( artist, SIGNAL( albumsAdded( QList<Tomahawk::album_ptr>, Tomahawk::ModelMode ) ),
  138. this, SLOT( onAlbumsFound( QList<Tomahawk::album_ptr>, Tomahawk::ModelMode ) ) );
  139. const QModelIndex parent = indexFromArtist( artistp );
  140. addAlbums( parent, albums );
  141. }
  142. void
  143. TreeModel::addAlbums( const QModelIndex& parent, const QList<Tomahawk::album_ptr>& albums )
  144. {
  145. finishLoading();
  146. if ( albums.isEmpty() )
  147. return;
  148. PlayableItem* parentItem = itemFromIndex( parent );
  149. QPair< int, int > crows;
  150. const int c = rowCount( parent );
  151. crows.first = c;
  152. crows.second = c + albums.count() - 1;
  153. emit beginInsertRows( parent, crows.first, crows.second );
  154. foreach( const album_ptr& album, albums )
  155. {
  156. PlayableItem* albumitem = new PlayableItem( album, parentItem );
  157. albumitem->index = createIndex( parentItem->children.count() - 1, 0, albumitem );
  158. connect( albumitem, SIGNAL( dataChanged() ), SLOT( onDataChanged() ) );
  159. getCover( albumitem->index );
  160. }
  161. emit endInsertRows();
  162. }
  163. void
  164. TreeModel::addTracks( const album_ptr& album, const QModelIndex& parent )
  165. {
  166. startLoading();
  167. QList<query_ptr> tracks = album->tracks( m_mode, m_collection );
  168. onTracksAdded( tracks, parent );
  169. if ( tracks.isEmpty() )
  170. startLoading();
  171. NewClosure( album.data(), SIGNAL( tracksAdded( QList<Tomahawk::query_ptr>, Tomahawk::ModelMode, Tomahawk::collection_ptr ) ),
  172. const_cast<TreeModel*>(this), SLOT( addTracks( Tomahawk::album_ptr, QModelIndex ) ), album, parent );
  173. }
  174. void
  175. TreeModel::addCollection( const collection_ptr& collection )
  176. {
  177. startLoading();
  178. m_collection = collection;
  179. Tomahawk::ArtistsRequest* req = m_collection->requestArtists();
  180. connect( dynamic_cast< QObject* >( req ), SIGNAL( artists( QList< Tomahawk::artist_ptr > ) ),
  181. this, SLOT( onArtistsAdded( QList< Tomahawk::artist_ptr > ) ), Qt::UniqueConnection );
  182. req->enqueue();
  183. setIcon( collection->bigIcon() );
  184. setTitle( collection->prettyName() );
  185. setDescription( collection->description() );
  186. }
  187. //void
  188. //TreeModel::addFilteredCollection( const collection_ptr& collection, unsigned int amount, DatabaseCommand_AllArtists::SortOrder order )
  189. //{
  190. // qDebug() << Q_FUNC_INFO << collection->name()
  191. // << collection->source()->id()
  192. // << collection->source()->nodeId()
  193. // << amount << order;
  194. // DatabaseCommand_AllArtists* cmd = new DatabaseCommand_AllArtists( collection );
  195. // cmd->setLimit( amount );
  196. // cmd->setSortOrder( order );
  197. // cmd->setSortDescending( true );
  198. // connect( cmd, SIGNAL( artists( QList<Tomahawk::artist_ptr>, Tomahawk::collection_ptr ) ),
  199. // SLOT( onArtistsAdded( QList<Tomahawk::artist_ptr>, Tomahawk::collection_ptr ) ) );
  200. // Database::instance()->enqueue( Tomahawk::dbcmd_ptr( cmd ) );
  201. // if ( collection->source()->isLocal() )
  202. // setTitle( tr( "My Collection" ) );
  203. // else
  204. // setTitle( tr( "Collection of %1" ).arg( collection->source()->friendlyName() ) );
  205. //}
  206. void
  207. TreeModel::onArtistsAdded( const QList<Tomahawk::artist_ptr>& artists )
  208. {
  209. finishLoading();
  210. if ( artists.isEmpty() )
  211. return;
  212. int c = rowCount( QModelIndex() );
  213. QPair< int, int > crows;
  214. crows.first = c;
  215. crows.second = c + artists.count() - 1;
  216. emit beginInsertRows( QModelIndex(), crows.first, crows.second );
  217. foreach( const artist_ptr& artist, artists )
  218. {
  219. PlayableItem* artistitem = new PlayableItem( artist, rootItem() );
  220. artistitem->index = createIndex( rootItem()->children.count() - 1, 0, artistitem );
  221. connect( artistitem, SIGNAL( dataChanged() ), SLOT( onDataChanged() ) );
  222. }
  223. emit endInsertRows();
  224. }
  225. void
  226. TreeModel::onTracksAdded( const QList<Tomahawk::query_ptr>& tracks, const QModelIndex& parent )
  227. {
  228. finishLoading();
  229. if ( tracks.isEmpty() )
  230. return;
  231. PlayableItem* parentItem = itemFromIndex( parent );
  232. QPair< int, int > crows;
  233. int c = rowCount( parent );
  234. removeRows( 0, c, parent );
  235. crows.first = c;
  236. crows.second = c + tracks.count() - 1;
  237. emit beginInsertRows( parent, crows.first, crows.second );
  238. foreach( const query_ptr& query, tracks )
  239. {
  240. PlayableItem* item = new PlayableItem( query, parentItem );
  241. item->index = createIndex( parentItem->children.count() - 1, 0, item );
  242. connect( item, SIGNAL( dataChanged() ), SLOT( onDataChanged() ) );
  243. }
  244. emit endInsertRows();
  245. emit selectRequest( index( 0, 0, parent ) );
  246. }
  247. QModelIndex
  248. TreeModel::indexFromArtist( const Tomahawk::artist_ptr& artist ) const
  249. {
  250. for ( int i = 0; i < rowCount( QModelIndex() ); i++ )
  251. {
  252. QModelIndex idx = index( i, 0, QModelIndex() );
  253. PlayableItem* item = itemFromIndex( idx );
  254. if ( item && item->artist() == artist )
  255. {
  256. return idx;
  257. }
  258. }
  259. tDebug() << Q_FUNC_INFO << "Could not find item for artist:" << artist->name();
  260. return QModelIndex();
  261. }
  262. QModelIndex
  263. TreeModel::indexFromAlbum( const Tomahawk::album_ptr& album ) const
  264. {
  265. QModelIndex artistIdx = indexFromArtist( album->artist() );
  266. for ( int i = 0; i < rowCount( artistIdx ); i++ )
  267. {
  268. QModelIndex idx = index( i, 0, artistIdx );
  269. PlayableItem* item = itemFromIndex( idx );
  270. if ( item && item->album() == album )
  271. {
  272. return idx;
  273. }
  274. }
  275. tDebug() << Q_FUNC_INFO << "Could not find item for album:" << album->name() << album->artist()->name();
  276. return QModelIndex();
  277. }
  278. QModelIndex
  279. TreeModel::indexFromResult( const Tomahawk::result_ptr& result ) const
  280. {
  281. QModelIndex albumIdx = indexFromAlbum( result->track()->albumPtr() );
  282. for ( int i = 0; i < rowCount( albumIdx ); i++ )
  283. {
  284. QModelIndex idx = index( i, 0, albumIdx );
  285. PlayableItem* item = itemFromIndex( idx );
  286. // tDebug() << Q_FUNC_INFO << item->result()->toString();
  287. if ( item && item->result() == result )
  288. {
  289. return idx;
  290. }
  291. }
  292. tDebug() << Q_FUNC_INFO << "Could not find item for result:" << result->toString();
  293. return QModelIndex();
  294. }
  295. QModelIndex
  296. TreeModel::indexFromQuery( const Tomahawk::query_ptr& query ) const
  297. {
  298. QModelIndex albumIdx = indexFromAlbum( query->queryTrack()->albumPtr() );
  299. for ( int i = 0; i < rowCount( albumIdx ); i++ )
  300. {
  301. QModelIndex idx = index( i, 0, albumIdx );
  302. PlayableItem* item = itemFromIndex( idx );
  303. if ( item && item->result() && item->result()->track()->equals( query->track() ) )
  304. {
  305. return idx;
  306. }
  307. }
  308. tDebug() << Q_FUNC_INFO << "Could not find item for query:" << query->toString();
  309. return QModelIndex();
  310. }
  311. PlayableItem*
  312. TreeModel::itemFromResult( const Tomahawk::result_ptr& result ) const
  313. {
  314. QModelIndex albumIdx = indexFromAlbum( result->track()->albumPtr() );
  315. for ( int i = 0; i < rowCount( albumIdx ); i++ )
  316. {
  317. QModelIndex idx = index( i, 0, albumIdx );
  318. PlayableItem* item = itemFromIndex( idx );
  319. if ( item && item->result() == result )
  320. {
  321. return item;
  322. }
  323. }
  324. tDebug() << Q_FUNC_INFO << "Could not find item for result:" << result->toString();
  325. return 0;
  326. }