playlistmodel.cpp 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. #include <QtCore/qfileinfo.h>
  2. #include <QtCore/qurl.h>
  3. #include <QDateTime>
  4. #include <QDebug>
  5. #include <QMap>
  6. #include <QMessageBox>
  7. #include <QMultiMap>
  8. #include <qmediaplaylist.h>
  9. #include "playlistmodel.h"
  10. #include "abstractmetadataloader.h"
  11. #include "urlutils.h"
  12. #include "mainwindow.h"
  13. using namespace Abstract;
  14. PlaylistModel::PlaylistModel(QObject *parent)
  15. : QAbstractListModel(parent)
  16. , m_playlist(0)
  17. {
  18. m_isFetched = false;
  19. QHash<int, QByteArray> roles;
  20. roles[NameRole] = "name";
  21. roles[PictureRole] = "picture";
  22. roles[UrlRole] = "url";
  23. roles[ArtistRole] = "artist";
  24. roles[LastModifiedRole] = "lastModified";
  25. roles[GenreRole] = "genre";
  26. roles[AlbumRole] = "album";
  27. roles[TrackNumberRole] = "trackNr";
  28. roles[CommentRole] = "comment";
  29. roles[DurationRole] = "duration";
  30. // m_isSorted = false;
  31. setRoleNames(roles);
  32. connect (MetaDataLoader::instance(), SIGNAL(fetched(MetaDataValue)),
  33. this, SLOT(fetched(MetaDataValue)), Qt::UniqueConnection);
  34. }
  35. int PlaylistModel::rowCount(const QModelIndex &) const
  36. {
  37. return m_playlist ? m_playlist->mediaCount() : 0;
  38. }
  39. QVariant PlaylistModel::data(const QModelIndex &index, int role) const
  40. {
  41. if (!index.isValid()) return QVariant();
  42. if ((index.row() < 0) || (index.row() >= rowCount())) return QVariant();
  43. QMediaContent mc = m_playlist->media(index.row());
  44. QUrl location = mc.canonicalUrl();
  45. MetaDataValue mdv;
  46. if (m_values.contains(location) )
  47. mdv = m_values[location];
  48. else {
  49. mdv.setUrl(location);
  50. QString path = UrlUtils::toLocalFile(location);
  51. QFileInfo finfo(path);
  52. mdv.setTrackTitle(UrlUtils::baseName(finfo));
  53. }
  54. if ((role == Qt::DisplayRole) || (role == NameRole)) {
  55. if (mdv.artist().isEmpty())
  56. return mdv.trackTitle();
  57. else return QString("%2 - %1").arg(mdv.artist()).arg(mdv.trackTitle());
  58. }
  59. if (role == TrackNumberRole) {
  60. return mdv.trackNumber();
  61. }
  62. if (role == DurationRole) {
  63. return mdv.trackTime();
  64. }
  65. if (role == GenreRole) {
  66. return mdv.genre();
  67. }
  68. if (role == ArtistRole) {
  69. return mdv.artist();
  70. }
  71. if (role == CommentRole) {
  72. return mdv.comment();
  73. }
  74. if (role == AlbumRole) {
  75. return mdv.albumTitle();
  76. }
  77. if (role == LastModifiedRole) {
  78. return mdv.lastModified();
  79. }
  80. if ((role == Qt::ToolTipRole) || (role == UrlRole) || (role == Qt::StatusTipRole)) {
  81. return mdv.url();
  82. }
  83. // TODO - handle decoration role
  84. return QVariant();
  85. }
  86. QMediaPlaylist *PlaylistModel::playlist() const
  87. {
  88. return m_playlist;
  89. }
  90. void PlaylistModel::setPlaylist(QMediaPlaylist *playlist)
  91. {
  92. if (m_playlist) {
  93. disconnect(m_playlist, SIGNAL(mediaAboutToBeInserted(int,int)), this, SLOT(beginInsertItems(int,int)));
  94. disconnect(m_playlist, SIGNAL(mediaInserted(int,int)), this, SLOT(endInsertItems()));
  95. disconnect(m_playlist, SIGNAL(mediaAboutToBeRemoved(int,int)), this, SLOT(beginRemoveItems(int,int)));
  96. disconnect(m_playlist, SIGNAL(mediaRemoved(int,int)), this, SLOT(endRemoveItems()));
  97. disconnect(m_playlist, SIGNAL(mediaChanged(int,int)), this, SLOT(changeItems(int,int)));
  98. }
  99. m_playlist = playlist;
  100. if (m_playlist) {
  101. connect(m_playlist, SIGNAL(mediaAboutToBeInserted(int,int)), this, SLOT(beginInsertItems(int,int)));
  102. connect(m_playlist, SIGNAL(mediaInserted(int,int)), this, SLOT(endInsertItems()));
  103. connect(m_playlist, SIGNAL(mediaAboutToBeRemoved(int,int)), this, SLOT(beginRemoveItems(int,int)));
  104. connect(m_playlist, SIGNAL(mediaRemoved(int,int)), this, SLOT(endRemoveItems()));
  105. connect(m_playlist, SIGNAL(mediaChanged(int,int)), this, SLOT(changeItems(int,int)));
  106. }
  107. reset();
  108. }
  109. void PlaylistModel::beginInsertItems(int start, int end) {
  110. m_indexes.clear();
  111. beginInsertRows(QModelIndex(), start, end);
  112. }
  113. void PlaylistModel::endInsertItems() {
  114. endInsertRows();
  115. }
  116. void PlaylistModel::beginRemoveItems(int start, int end) {
  117. m_indexes.clear();
  118. beginRemoveRows(QModelIndex(), start, end);
  119. }
  120. void PlaylistModel::endRemoveItems() {
  121. endInsertRows();
  122. }
  123. void PlaylistModel::changeItems(int start, int end) {
  124. m_indexes.clear();
  125. emit dataChanged(index(start,0), index(end,1));
  126. }
  127. int PlaylistModel::findRow(QUrl key) {
  128. if (m_indexes.contains(key)) return m_indexes[key];
  129. int retval = -1;
  130. for (int r=0; r<rowCount(); ++r) {
  131. QUrl u = data(index(r,0), UrlRole).toString();
  132. m_indexes[u] = r;
  133. if (u == key) retval = r;
  134. }
  135. return retval;
  136. }
  137. void PlaylistModel::shuffle() {
  138. m_playlist->shuffle();
  139. reset();
  140. }
  141. void PlaylistModel::fetched(MetaDataValue mdv) {
  142. m_values[mdv.url()]=mdv;
  143. // qDebug() << "fetched: " << mdv.url();
  144. int r = findRow(mdv.url());
  145. if (r != -1) {
  146. QModelIndex tl = index(r,0, QModelIndex());
  147. emit dataChanged(tl, tl);
  148. }
  149. }
  150. void PlaylistModel::clear() {
  151. m_playlist->clear();
  152. m_isFetched=false;
  153. reset();
  154. }
  155. void PlaylistModel::sortByRole(PlayListRoles role) {
  156. if (!m_isFetched) {
  157. fetchAll();
  158. return;
  159. }
  160. m_indexes.clear();
  161. if (role == LastModifiedRole) {
  162. QMultiMap<QDateTime, QUrl> mapping;
  163. for (int i=0; i<rowCount(); ++i) {
  164. QUrl url = m_playlist->media(i).canonicalUrl();
  165. MetaDataValue mdv = m_values[url];
  166. mapping.insert(mdv.lastModified(), url);
  167. }
  168. m_playlist->clear();
  169. QMultiMap<QDateTime, QUrl>::const_iterator itr = mapping.constEnd();
  170. while (itr != mapping.constBegin()) {
  171. --itr;
  172. QUrl url = itr.value();
  173. m_playlist->addMedia(QMediaContent(url));
  174. }
  175. reset();
  176. return;
  177. }
  178. QMultiMap<QString, QUrl> mapping;
  179. QRegExp rx("(\\d+).*");
  180. for (int i=0; i<rowCount(); ++i) {
  181. QUrl url = m_playlist->media(i).canonicalUrl();
  182. MetaDataValue mdv = m_values[url];
  183. QString key = mdv.trackTitle();
  184. if (role == AlbumRole) {
  185. QString tn = mdv.trackNumber();
  186. if (rx.exactMatch(tn))
  187. tn = rx.cap();
  188. int trackNumber = tn.toInt();
  189. if (trackNumber > 0)
  190. key = QString("%1-%2").arg(mdv.albumTitle()).arg(trackNumber, 4, QChar('0'));
  191. else key = QString("%1-%2").arg(mdv.albumTitle()).arg(mdv.trackTitle());
  192. }
  193. else if (role == ArtistRole) {
  194. key = QString("%1-%2").arg(mdv.artist()).arg(mdv.trackTitle());
  195. }
  196. else if (role == NameRole) {
  197. key = mdv.trackTitle();
  198. }
  199. mapping.insert(key, url);
  200. }
  201. m_playlist->clear();
  202. QMultiMap<QString, QUrl>::const_iterator itr = mapping.constBegin();
  203. while (itr != mapping.constEnd()) {
  204. QUrl url = itr.value();
  205. m_playlist->addMedia(QMediaContent(url));
  206. itr++;
  207. }
  208. reset();
  209. }
  210. void PlaylistModel::setFetched(bool f) {
  211. m_isFetched = f;
  212. if (f == true)
  213. MetaDataLoader::instance()->disconnect(this, SLOT(setFetched()));
  214. }
  215. void PlaylistModel::deleteTrack(int i) {
  216. beginRemoveItems(i, i);
  217. QMediaContent mc = m_playlist->media(i);
  218. QString fileName = UrlUtils::toLocalFile(mc.canonicalUrl());
  219. int response = QMessageBox::question(MainWindow::instance(),
  220. tr("Delete File"), tr("delete ") + fileName, QMessageBox::No, QMessageBox::Yes);
  221. if (response == QMessageBox::Yes) {
  222. m_playlist->removeMedia(i, i);
  223. QFile f(fileName);
  224. f.remove();
  225. }
  226. endRemoveItems();
  227. reset();
  228. }
  229. void PlaylistModel::fetchAll() {
  230. MetaDataLoader *mdl = MetaDataLoader::instance();
  231. connect (mdl, SIGNAL(finished()), this, SLOT(setFetched()));
  232. int r = rowCount();
  233. int c = 0;
  234. for (int i=0; i<r; ++i) {
  235. QMediaContent mc = m_playlist->media(i);
  236. QUrl url = mc.canonicalUrl();
  237. if (m_values.contains(url)) continue;
  238. mdl->get(url);
  239. c++;
  240. }
  241. if (c == 0) m_isFetched = true;
  242. }
  243. void PlaylistModel::fetch(int i) {
  244. MetaDataLoader *mdl = MetaDataLoader::instance();
  245. QMediaContent mc = m_playlist->media(i);
  246. mdl->get(mc.canonicalUrl());
  247. }