/src/libtomahawk/playlist/TreeProxyModel.cpp

http://github.com/tomahawk-player/tomahawk · C++ · 406 lines · 297 code · 73 blank · 36 comment · 67 complexity · eb062b22d1611943d54af03a1d2f006b MD5 · raw file

  1. /* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
  2. *
  3. * Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
  4. * Copyright 2010-2012, Jeff Mitchell <jeff@tomahawk-player.org>
  5. * Copyright 2013, Teo Mrnjavac <teo@kde.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 "TreeProxyModel.h"
  21. #include "TreeProxyModelPlaylistInterface.h"
  22. #include "Source.h"
  23. #include "Query.h"
  24. #include "database/Database.h"
  25. #include "database/DatabaseImpl.h"
  26. #include "collection/AlbumsRequest.h"
  27. #include "collection/ArtistsRequest.h"
  28. #include "database/DatabaseCommand_AllAlbums.h"
  29. #include "PlayableItem.h"
  30. #include "utils/Logger.h"
  31. #include <QListView>
  32. TreeProxyModel::TreeProxyModel( QObject* parent )
  33. : PlayableProxyModel( parent )
  34. , m_artistsFilterCmd( 0 )
  35. , m_model( 0 )
  36. {
  37. setPlaylistInterface( Tomahawk::playlistinterface_ptr( new Tomahawk::TreeProxyModelPlaylistInterface( this ) ) );
  38. }
  39. void
  40. TreeProxyModel::setSourcePlayableModel( TreeModel* model )
  41. {
  42. if ( m_model )
  43. {
  44. disconnect( m_model, SIGNAL( rowsInserted( QModelIndex, int, int ) ), this, SLOT( onRowsInserted( QModelIndex, int, int ) ) );
  45. disconnect( m_model, SIGNAL( modelReset() ), this, SLOT( onModelReset() ) );
  46. }
  47. PlayableProxyModel::setSourcePlayableModel( model );
  48. m_model = model;
  49. if ( m_model )
  50. {
  51. connect( m_model, SIGNAL( rowsInserted( QModelIndex, int, int ) ), SLOT( onRowsInserted( QModelIndex, int, int ) ) );
  52. connect( m_model, SIGNAL( modelReset() ), SLOT( onModelReset() ) );
  53. }
  54. }
  55. void
  56. TreeProxyModel::onRowsInserted( const QModelIndex& parent, int /* start */, int /* end */ )
  57. {
  58. if ( m_filter.isEmpty() )
  59. return;
  60. if ( sender() != m_model )
  61. return;
  62. PlayableItem* pi = m_model->itemFromIndex( m_model->index( parent.row(), 0, parent.parent() ) );
  63. if ( pi->artist().isNull() )
  64. return;
  65. Tomahawk::AlbumsRequest* cmd = 0;
  66. if ( !m_model->collection().isNull() )
  67. cmd = m_model->collection()->requestAlbums( pi->artist() );
  68. else
  69. cmd = new Tomahawk::DatabaseCommand_AllAlbums( Tomahawk::collection_ptr(), pi->artist() );
  70. cmd->setFilter( m_filter );
  71. connect( dynamic_cast< QObject* >( cmd ), SIGNAL( albums( QList<Tomahawk::album_ptr> ) ),
  72. SLOT( onFilterAlbums( QList<Tomahawk::album_ptr> ) ) );
  73. cmd->enqueue();
  74. }
  75. void
  76. TreeProxyModel::onModelReset()
  77. {
  78. m_cache.clear();
  79. m_artistsFilter.clear();
  80. m_albumsFilter.clear();
  81. }
  82. void
  83. TreeProxyModel::setFilter( const QString& pattern )
  84. {
  85. emit filteringStarted();
  86. m_filter = pattern;
  87. beginResetModel();
  88. m_albumsFilter.clear();
  89. endResetModel();
  90. if ( m_artistsFilterCmd )
  91. {
  92. disconnect( dynamic_cast< QObject* >( m_artistsFilterCmd ), SIGNAL( artists( QList<Tomahawk::artist_ptr> ) ),
  93. this, SLOT( onFilterArtists( QList<Tomahawk::artist_ptr> ) ) );
  94. delete m_artistsFilterCmd;
  95. m_artistsFilterCmd = 0;
  96. }
  97. if ( m_filter.isEmpty() )
  98. {
  99. filterFinished();
  100. }
  101. else
  102. {
  103. Tomahawk::ArtistsRequest* cmd = 0;
  104. if ( !m_model->collection().isNull() )
  105. cmd = m_model->collection()->requestArtists();
  106. else
  107. cmd = new Tomahawk::DatabaseCommand_AllArtists(); //for SuperCollection, TODO: replace with a proper proxy-ArtistsRequest
  108. cmd->setFilter( pattern );
  109. m_artistsFilterCmd = cmd;
  110. connect( dynamic_cast< QObject* >( cmd ), SIGNAL( artists( QList<Tomahawk::artist_ptr> ) ),
  111. SLOT( onFilterArtists( QList<Tomahawk::artist_ptr> ) ) );
  112. cmd->enqueue();
  113. }
  114. }
  115. QString
  116. TreeProxyModel::filter() const
  117. {
  118. return m_filter;
  119. }
  120. void
  121. TreeProxyModel::onFilterArtists( const QList<Tomahawk::artist_ptr>& artists )
  122. {
  123. bool finished = true;
  124. m_artistsFilter = artists;
  125. m_artistsFilterCmd = 0;
  126. foreach ( const Tomahawk::artist_ptr& artist, artists )
  127. {
  128. const QModelIndex idx = m_model->indexFromArtist( artist );
  129. if ( m_model->rowCount( idx ) )
  130. {
  131. finished = false;
  132. Tomahawk::AlbumsRequest* cmd = m_model->collection()->requestAlbums( artist );
  133. cmd->setFilter( m_filter );
  134. connect( dynamic_cast< QObject* >( cmd ), SIGNAL( albums( QList<Tomahawk::album_ptr> ) ),
  135. SLOT( onFilterAlbums( QList<Tomahawk::album_ptr> ) ) );
  136. cmd->enqueue();
  137. }
  138. }
  139. if ( finished )
  140. filterFinished();
  141. }
  142. void
  143. TreeProxyModel::onFilterAlbums( const QList<Tomahawk::album_ptr>& albums )
  144. {
  145. foreach ( const Tomahawk::album_ptr& album, albums )
  146. {
  147. m_albumsFilter << album;
  148. }
  149. filterFinished();
  150. }
  151. void
  152. TreeProxyModel::filterFinished()
  153. {
  154. if ( m_artistsFilterCmd )
  155. {
  156. disconnect( dynamic_cast< QObject* >( m_artistsFilterCmd ), SIGNAL( artists( QList<Tomahawk::artist_ptr> ) ),
  157. this, SLOT( onFilterArtists( QList<Tomahawk::artist_ptr> ) ) );
  158. delete m_artistsFilterCmd;
  159. m_artistsFilterCmd = 0;
  160. }
  161. setFilterRegExp( m_filter );
  162. emit filterChanged( m_filter );
  163. emit filteringFinished();
  164. }
  165. bool
  166. TreeProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex& sourceParent ) const
  167. {
  168. PlayableItem* item = sourceModel()->itemFromIndex( sourceModel()->index( sourceRow, 0, sourceParent ) );
  169. Q_ASSERT( item );
  170. //FIXME: m_cache lookup is broken
  171. if ( /*m_model->mode() == Tomahawk::DatabaseMode &&*/ !item->query().isNull() )
  172. {
  173. /* QList< Tomahawk::query_ptr > rl = m_cache.values( sourceParent );
  174. foreach ( const Tomahawk::query_ptr& cachedQuery, rl )
  175. {
  176. if ( cachedQuery.isNull() )
  177. continue;
  178. if ( cachedQuery->track()->track() == item->query()->track()->track() &&
  179. ( cachedQuery->track()->albumpos() == item->query()->track()->albumpos() || cachedQuery->track()->albumpos() == 0 ) )
  180. {
  181. return ( cachedQuery.data() == item->query().data() );
  182. }
  183. }*/
  184. for ( int i = 0; i < sourceModel()->rowCount( sourceParent ); i++ )
  185. {
  186. if ( i == sourceRow )
  187. continue;
  188. PlayableItem* ti = sourceModel()->itemFromIndex( sourceModel()->index( i, 0, sourceParent ) );
  189. if ( ti && ti->name() == item->name() && !ti->query().isNull() )
  190. {
  191. if ( ti->query()->track()->albumpos() == item->query()->track()->albumpos() || ti->query()->track()->albumpos() == 0 || item->query()->track()->albumpos() == 0 )
  192. {
  193. if ( item->result().isNull() )
  194. return false;
  195. if ( !ti->result().isNull() )
  196. {
  197. if ( !item->result()->isOnline() && ti->result()->isOnline() )
  198. return false;
  199. if ( ( !item->result()->isLocal() ) &&
  200. !ti->result()->isLocal() )
  201. {
  202. return false;
  203. }
  204. }
  205. }
  206. }
  207. }
  208. }
  209. bool accepted = false;
  210. if ( m_filter.isEmpty() )
  211. accepted = true;
  212. else if ( !item->artist().isNull() )
  213. accepted = m_artistsFilter.contains( item->artist() );
  214. else if ( !item->album().isNull() )
  215. accepted = m_albumsFilter.contains( item->album() );
  216. if ( !accepted )
  217. {
  218. QStringList sl = m_filter.split( " ", QString::SkipEmptyParts );
  219. foreach( const QString& s, sl )
  220. {
  221. if ( !item->name().contains( s, Qt::CaseInsensitive ) &&
  222. !item->albumName().contains( s, Qt::CaseInsensitive ) &&
  223. !item->artistName().contains( s, Qt::CaseInsensitive ) )
  224. {
  225. return false;
  226. }
  227. }
  228. }
  229. m_cache.insertMulti( sourceParent, item->query() );
  230. return true;
  231. }
  232. bool
  233. TreeProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right ) const
  234. {
  235. PlayableItem* p1 = sourceModel()->itemFromIndex( left );
  236. PlayableItem* p2 = sourceModel()->itemFromIndex( right );
  237. if ( !p1 )
  238. return true;
  239. if ( !p2 )
  240. return false;
  241. /* if ( !p1->result().isNull() && p2->result().isNull() )
  242. return true;
  243. if ( p1->result().isNull() && !p2->result().isNull() )
  244. return false;*/
  245. unsigned int albumpos1 = 0;
  246. unsigned int albumpos2 = 0;
  247. unsigned int discnumber1 = 0;
  248. unsigned int discnumber2 = 0;
  249. if ( !p1->query().isNull() )
  250. {
  251. albumpos1 = p1->query()->track()->albumpos();
  252. discnumber1 = p1->query()->track()->discnumber();
  253. }
  254. if ( !p2->query().isNull() )
  255. {
  256. albumpos2 = p2->query()->track()->albumpos();
  257. discnumber2 = p2->query()->track()->discnumber();
  258. }
  259. if ( !p1->result().isNull() )
  260. {
  261. if ( albumpos1 == 0 )
  262. albumpos1 = p1->result()->track()->albumpos();
  263. if ( discnumber1 == 0 )
  264. discnumber1 = p1->result()->track()->discnumber();
  265. }
  266. if ( !p2->result().isNull() )
  267. {
  268. if ( albumpos2 == 0 )
  269. albumpos2 = p2->result()->track()->albumpos();
  270. if ( discnumber2 == 0 )
  271. discnumber2 = p2->result()->track()->discnumber();
  272. }
  273. discnumber1 = qMax( 1, (int)discnumber1 );
  274. discnumber2 = qMax( 1, (int)discnumber2 );
  275. if ( discnumber1 != discnumber2 )
  276. {
  277. return discnumber1 < discnumber2;
  278. }
  279. else
  280. {
  281. if ( albumpos1 != albumpos2 )
  282. return albumpos1 < albumpos2;
  283. }
  284. const QString& lefts = textForItem( p1 );
  285. const QString& rights = textForItem( p2 );
  286. if ( lefts == rights )
  287. return (qint64)&p1 < (qint64)&p2;
  288. return QString::localeAwareCompare( lefts, rights ) < 0;
  289. }
  290. QString
  291. TreeProxyModel::textForItem( PlayableItem* item ) const
  292. {
  293. if ( !item )
  294. return QString();
  295. if ( !item->artist().isNull() )
  296. {
  297. return item->artist()->sortname();
  298. }
  299. else if ( !item->album().isNull() )
  300. {
  301. return Tomahawk::DatabaseImpl::sortname( item->album()->name() );
  302. }
  303. else if ( !item->result().isNull() )
  304. {
  305. return item->result()->track()->trackSortname();
  306. }
  307. else if ( !item->query().isNull() )
  308. {
  309. return item->query()->track()->track();
  310. }
  311. return QString();
  312. }
  313. QModelIndex
  314. TreeProxyModel::indexFromArtist( const Tomahawk::artist_ptr& artist ) const
  315. {
  316. return mapFromSource( m_model->indexFromArtist( artist ) );
  317. }
  318. QModelIndex
  319. TreeProxyModel::indexFromAlbum( const Tomahawk::album_ptr& album ) const
  320. {
  321. return mapFromSource( m_model->indexFromAlbum( album ) );
  322. }
  323. QModelIndex
  324. TreeProxyModel::indexFromResult( const Tomahawk::result_ptr& result ) const
  325. {
  326. return mapFromSource( m_model->indexFromResult( result ) );
  327. }
  328. QModelIndex
  329. TreeProxyModel::indexFromQuery( const Tomahawk::query_ptr& query ) const
  330. {
  331. return mapFromSource( m_model->indexFromQuery( query ) );
  332. }