/src/libtomahawk/jobview/JobStatusModel.cpp

http://github.com/tomahawk-player/tomahawk · C++ · 319 lines · 205 code · 69 blank · 45 comment · 22 complexity · 6251f8af6d01c579633a75b4f4c6d369 MD5 · raw file

  1. /* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
  2. *
  3. * Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
  4. * Copyright 2010-2011, Jeff Mitchell <jeff@tomahawk-player.org>
  5. *
  6. * Tomahawk is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Tomahawk is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include "JobStatusModel.h"
  20. #include "JobStatusItem.h"
  21. #include "utils/Logger.h"
  22. #include <QPixmap>
  23. JobStatusSortModel::JobStatusSortModel( QObject* parent )
  24. : QSortFilterProxyModel( parent )
  25. {
  26. setDynamicSortFilter( true );
  27. }
  28. JobStatusSortModel::~JobStatusSortModel()
  29. {
  30. }
  31. void
  32. JobStatusSortModel::setJobModel( JobStatusModel* model )
  33. {
  34. setSourceModel( model );
  35. m_sourceModel = model;
  36. connect( m_sourceModel, SIGNAL( customDelegateJobInserted( int, JobStatusItem* ) ), this, SLOT( customDelegateJobInsertedSlot( int, JobStatusItem* ) ) );
  37. connect( m_sourceModel, SIGNAL( customDelegateJobRemoved( int ) ), this, SLOT( customDelegateJobRemovedSlot( int ) ) );
  38. connect( m_sourceModel, SIGNAL( refreshDelegates() ), this, SLOT( refreshDelegatesSlot() ) );
  39. }
  40. void
  41. JobStatusSortModel::addJob( JobStatusItem* item )
  42. {
  43. m_sourceModel->addJob( item );
  44. }
  45. void
  46. JobStatusSortModel::customDelegateJobInsertedSlot( int row, JobStatusItem* item )
  47. {
  48. emit customDelegateJobInserted( mapFromSource( m_sourceModel->index( row ) ).row(), item );
  49. }
  50. void
  51. JobStatusSortModel::customDelegateJobRemovedSlot( int row )
  52. {
  53. emit customDelegateJobRemoved( mapFromSource( m_sourceModel->index( row ) ).row() );
  54. }
  55. void
  56. JobStatusSortModel::refreshDelegatesSlot()
  57. {
  58. sort( 0 );
  59. emit refreshDelegates();
  60. }
  61. bool
  62. JobStatusSortModel::lessThan( const QModelIndex& left, const QModelIndex& right ) const
  63. {
  64. const int leftSort = left.data( JobStatusModel::SortRole ).toInt();
  65. const int rightSort = right.data( JobStatusModel::SortRole ).toInt();
  66. if ( leftSort == rightSort )
  67. return left.data( JobStatusModel::AgeRole ).toUInt() > right.data( JobStatusModel::AgeRole ).toUInt();
  68. return leftSort < rightSort;
  69. }
  70. JobStatusModel::JobStatusModel( QObject* parent )
  71. : QAbstractListModel ( parent )
  72. {
  73. }
  74. JobStatusModel::~JobStatusModel()
  75. {
  76. qDeleteAll( m_items );
  77. m_collapseCount.clear();
  78. }
  79. void
  80. JobStatusModel::addJob( JobStatusItem* item )
  81. {
  82. // tLog() << Q_FUNC_INFO << "current jobs of item type: " << m_jobTypeCount[ item->type() ] << ", current queue size of item type: " << m_jobQueue[ item->type() ].size();
  83. if ( item->concurrentJobLimit() > 0 )
  84. {
  85. if ( m_jobTypeCount[ item->type() ] >= item->concurrentJobLimit() )
  86. {
  87. m_jobQueue[ item->type() ].enqueue( item );
  88. return;
  89. }
  90. int currentJobCount = m_jobTypeCount[ item->type() ];
  91. currentJobCount++;
  92. m_jobTypeCount[ item->type() ] = currentJobCount;
  93. }
  94. // tLog() << Q_FUNC_INFO << "new current jobs of item type: " << m_jobTypeCount[ item->type() ];
  95. connect( item, SIGNAL( statusChanged() ), SLOT( itemUpdated() ) );
  96. connect( item, SIGNAL( finished() ), SLOT( itemFinished() ) );
  97. if ( item->collapseItem() )
  98. {
  99. if ( m_collapseCount.contains( item->type() ) )
  100. {
  101. m_collapseCount[ item->type() ].append( item );
  102. // qDebug() << "Adding item:" << item << "TO COLLAPSE ONLY";
  103. return; // we're done, no new rows
  104. }
  105. else
  106. {
  107. m_collapseCount.insert( item->type(), QList< JobStatusItem* >() << item );
  108. }
  109. }
  110. // tLog() << Q_FUNC_INFO << "Adding item:" << item;
  111. int currentEndRow = m_items.count();
  112. beginInsertRows( QModelIndex(), currentEndRow, currentEndRow );
  113. m_items.append( item );
  114. endInsertRows();
  115. if ( item->hasCustomDelegate() )
  116. {
  117. // tLog() << Q_FUNC_INFO << "job has custom delegate";
  118. emit customDelegateJobInserted( currentEndRow, item );
  119. }
  120. emit refreshDelegates();
  121. }
  122. Qt::ItemFlags
  123. JobStatusModel::flags( const QModelIndex& index ) const
  124. {
  125. Q_UNUSED( index );
  126. // Don't let the items be selectable
  127. return Qt::ItemIsEnabled;
  128. }
  129. QVariant
  130. JobStatusModel::data( const QModelIndex& index, int role ) const
  131. {
  132. if ( !hasIndex( index.row(), index.column(), index.parent() ) )
  133. return QVariant();
  134. JobStatusItem* item = m_items[ index.row() ];
  135. switch ( role )
  136. {
  137. case Qt::DecorationRole:
  138. return item->icon();
  139. case Qt::ToolTipRole:
  140. case Qt::DisplayRole:
  141. {
  142. if ( m_collapseCount.contains( item->type() ) )
  143. return m_collapseCount[ item->type() ].last()->mainText();
  144. else
  145. return item->mainText();
  146. }
  147. case RightColumnRole:
  148. {
  149. if ( m_collapseCount.contains( item->type() ) )
  150. return m_collapseCount[ item->type() ].count();
  151. else
  152. return item->rightColumnText();
  153. }
  154. case AllowMultiLineRole:
  155. return item->allowMultiLine();
  156. case JobDataRole:
  157. return QVariant::fromValue< JobStatusItem* >( item );
  158. case SortRole:
  159. return item->weight();
  160. case AgeRole:
  161. return item->age();
  162. default:
  163. return QVariant();
  164. }
  165. return QVariant();
  166. }
  167. int
  168. JobStatusModel::rowCount( const QModelIndex& parent ) const
  169. {
  170. Q_UNUSED( parent );
  171. return m_items.count();
  172. }
  173. void
  174. JobStatusModel::itemFinished()
  175. {
  176. // tLog( LOGVERBOSE ) << Q_FUNC_INFO;
  177. JobStatusItem* item = qobject_cast< JobStatusItem* >( sender() );
  178. Q_ASSERT( item );
  179. // tDebug() << "Got item finished:" << item->type() << item->mainText() << item;
  180. if ( !m_items.contains( item ) && !m_collapseCount.contains( item->type() ) )
  181. return;
  182. // foreach( JobStatusItem* item, m_items )
  183. // {
  184. // qDebug() << "ITEM #:" << item;
  185. // }
  186. // foreach( const QString& str, m_collapseCount.keys() )
  187. // {
  188. // tDebug() << "\t" << str;
  189. // foreach( JobStatusItem* chain, m_collapseCount[ str ] )
  190. // qDebug() << "\t\t" << chain;
  191. // }
  192. if ( m_collapseCount.contains( item->type() ) )
  193. {
  194. const int indexOf = m_items.indexOf( m_collapseCount[ item->type() ].first() );
  195. // tDebug() << "index in main list of collapsed irst item:" << indexOf;
  196. if ( m_collapseCount[ item->type() ].first() == item &&
  197. m_items.contains( m_collapseCount[ item->type() ].first() ) && m_collapseCount[ item->type() ].size() > 1 )
  198. {
  199. // the placeholder we use that links m_items and m_collapsecount is done, so choose another one
  200. m_items.replace( m_items.indexOf( m_collapseCount[ item->type() ].first() ), m_collapseCount[ item->type() ][ 1 ] );
  201. // qDebug() << "Replaced" << m_collapseCount[ item->type() ].first() << "with:" << m_collapseCount[ item->type() ][ 1 ] << m_items;
  202. }
  203. m_collapseCount[ item->type() ].removeAll( item );
  204. // tDebug() << "New collapse count list:" << m_collapseCount[ item->type() ];
  205. if ( m_collapseCount[ item->type() ].isEmpty() )
  206. m_collapseCount.remove( item->type() );
  207. else
  208. {
  209. // One less to count, but item is still there
  210. const QModelIndex idx = index( indexOf, 0, QModelIndex() );
  211. emit dataChanged( idx, idx );
  212. emit refreshDelegates();
  213. return;
  214. }
  215. }
  216. // Remove row completely
  217. const int idx = m_items.indexOf( item );
  218. // tDebug() << "Got index of item:" << idx;
  219. Q_ASSERT( idx >= 0 );
  220. beginRemoveRows( QModelIndex(), idx, idx );
  221. m_items.removeAll( item );
  222. endRemoveRows();
  223. if ( item->customDelegate() )
  224. emit customDelegateJobRemoved( idx );
  225. emit refreshDelegates();
  226. // tLog() << Q_FUNC_INFO << "current jobs of item type: " << m_jobTypeCount[ item->type() ] << ", current queue size of item type: " << m_jobQueue[ item->type() ].size();
  227. if ( item->concurrentJobLimit() > 0 )
  228. {
  229. int currentJobs = m_jobTypeCount[ item->type() ];
  230. currentJobs--;
  231. m_jobTypeCount[ item->type() ] = currentJobs;
  232. if ( !m_jobQueue[ item->type() ].isEmpty() )
  233. {
  234. JobStatusItem* nextItem = m_jobQueue[ item->type() ].dequeue();
  235. QMetaObject::invokeMethod( this, "addJob", Qt::QueuedConnection, Q_ARG( JobStatusItem*, nextItem ) );
  236. }
  237. }
  238. item->deleteLater();
  239. }
  240. void
  241. JobStatusModel::itemUpdated()
  242. {
  243. // tLog( LOGVERBOSE ) << Q_FUNC_INFO;
  244. JobStatusItem* item = qobject_cast< JobStatusItem* >( sender() );
  245. Q_ASSERT( item );
  246. if ( m_collapseCount.contains( item->type() ) )
  247. item = m_collapseCount[ item->type() ].first();
  248. const QModelIndex idx = index( m_items.indexOf( item ), 0, QModelIndex() );
  249. emit dataChanged( idx, idx );
  250. }