731 lines
21 KiB
C++
731 lines
21 KiB
C++
/*
|
|
* Cantata
|
|
*
|
|
* Copyright (c) 2011-2014 Craig Drummond <craig.p.drummond@gmail.com>
|
|
* Copyright (c) 2014 Niklas Wenzel <nikwen.developer@gmail.com>
|
|
*
|
|
* ----
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; see the file COPYING. If not, write to
|
|
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include <QModelIndex>
|
|
#include <QDataStream>
|
|
#include <QMimeData>
|
|
#include <QStringList>
|
|
#include <QPainter>
|
|
#include <QFile>
|
|
#include "support/localize.h"
|
|
#include "gui/plurals.h"
|
|
#include "support/globalstatic.h"
|
|
#include "albumsmodel.h"
|
|
#include "gui/settings.h"
|
|
#include "musiclibraryitemsong.h"
|
|
#include "musiclibraryitemartist.h"
|
|
#include "musiclibraryitemroot.h"
|
|
#include "musiclibrarymodel.h"
|
|
#include "playqueuemodel.h"
|
|
#include "proxymodel.h"
|
|
#include "mpd/song.h"
|
|
#include "gui/covers.h"
|
|
#include "roles.h"
|
|
#include "mpd/mpdparseutils.h"
|
|
#include "widgets/icons.h"
|
|
#include "support/utils.h"
|
|
#include "config.h"
|
|
#if defined ENABLE_MODEL_TEST
|
|
#include "modeltest.h"
|
|
#endif
|
|
|
|
static int sortAlbums=AlbumsModel::Sort_AlbumArtist;
|
|
|
|
GLOBAL_STATIC(AlbumsModel, instance)
|
|
|
|
AlbumsModel::Sort AlbumsModel::toSort(const QString &str)
|
|
{
|
|
for (int i=0; i<=Sort_YearArtist; ++i) {
|
|
if (sortStr((Sort)i)==str) {
|
|
return (Sort)i;
|
|
}
|
|
}
|
|
return AlbumsModel::Sort_AlbumArtist;
|
|
}
|
|
|
|
QString AlbumsModel::sortStr(Sort m)
|
|
{
|
|
switch (m) {
|
|
default:
|
|
case Sort_AlbumArtist: return QLatin1String("album-artist");
|
|
case Sort_AlbumYear: return QLatin1String("album-year");
|
|
case Sort_ArtistAlbum: return QLatin1String("artist-album");
|
|
case Sort_ArtistYear: return QLatin1String("artist-year");
|
|
case Sort_YearAlbum: return QLatin1String("year-album");
|
|
case Sort_YearArtist: return QLatin1String("year-artist");
|
|
}
|
|
}
|
|
|
|
|
|
AlbumsModel::AlbumsModel(QObject *parent)
|
|
: ActionModel(parent)
|
|
, enabled(false)
|
|
// , coversRequested(false)
|
|
{
|
|
#if defined ENABLE_MODEL_TEST
|
|
new ModelTest(this, this);
|
|
#endif
|
|
}
|
|
|
|
AlbumsModel::~AlbumsModel()
|
|
{
|
|
}
|
|
|
|
QVariant AlbumsModel::headerData(int /*section*/, Qt::Orientation /*orientation*/, int /*role*/) const
|
|
{
|
|
return QVariant();
|
|
}
|
|
|
|
int AlbumsModel::rowCount(const QModelIndex &index) const
|
|
{
|
|
if (!index.isValid()) {
|
|
return items.size();
|
|
}
|
|
|
|
Item *item=static_cast<Item *>(index.internalPointer());
|
|
if (item->isAlbum()) {
|
|
AlbumItem *al=static_cast<AlbumItem *>(index.internalPointer());
|
|
return al->songs.count();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
bool AlbumsModel::hasChildren(const QModelIndex &parent) const
|
|
{
|
|
return !parent.isValid() || static_cast<Item *>(parent.internalPointer())->isAlbum();
|
|
}
|
|
|
|
QModelIndex AlbumsModel::parent(const QModelIndex &index) const
|
|
{
|
|
if (!index.isValid()) {
|
|
return QModelIndex();
|
|
}
|
|
|
|
Item *item=static_cast<Item *>(index.internalPointer());
|
|
|
|
if (item->isAlbum()) {
|
|
return QModelIndex();
|
|
} else {
|
|
SongItem *song=static_cast<SongItem *>(item);
|
|
|
|
if (song->parent) {
|
|
return createIndex(items.indexOf(song->parent), 0, song->parent);
|
|
}
|
|
}
|
|
|
|
return QModelIndex();
|
|
}
|
|
|
|
QModelIndex AlbumsModel::index(int row, int col, const QModelIndex &parent) const
|
|
{
|
|
if (!hasIndex(row, col, parent)) {
|
|
return QModelIndex();
|
|
}
|
|
|
|
if (parent.isValid()) {
|
|
Item *p=static_cast<Item *>(parent.internalPointer());
|
|
|
|
if (p->isAlbum()) {
|
|
AlbumItem *pl=static_cast<AlbumItem *>(p);
|
|
return row<pl->songs.count() ? createIndex(row, col, pl->songs.at(row)) : QModelIndex();
|
|
}
|
|
}
|
|
|
|
return row<items.count() ? createIndex(row, col, items.at(row)) : QModelIndex();
|
|
}
|
|
|
|
#ifdef ENABLE_UBUNTU
|
|
static const QString constDefaultCover=QLatin1String("qrc:/album.svg");
|
|
#endif
|
|
|
|
QVariant AlbumsModel::data(const QModelIndex &index, int role) const
|
|
{
|
|
if (!index.isValid()) {
|
|
return QVariant();
|
|
}
|
|
|
|
Item *item=static_cast<Item *>(index.internalPointer());
|
|
|
|
if (item->isAlbum()) {
|
|
AlbumItem *al=static_cast<AlbumItem *>(item);
|
|
|
|
switch (role) {
|
|
default:
|
|
return ActionModel::data(index, role);
|
|
#ifdef ENABLE_UBUNTU
|
|
case Cantata::Role_Image: {
|
|
QString cover=al->cover();
|
|
return cover.isEmpty() ? constDefaultCover : cover;
|
|
}
|
|
#endif
|
|
case Cantata::Role_ListImage:
|
|
return true;
|
|
#ifndef ENABLE_UBUNTU
|
|
case Qt::DecorationRole:
|
|
return Icons::self()->albumIcon;
|
|
#endif
|
|
case Qt::ToolTipRole:
|
|
if (!Settings::self()->infoTooltips()) {
|
|
return QVariant();
|
|
}
|
|
return 0==al->songs.count()
|
|
? QString()
|
|
: (al->artist+QLatin1Char('\n')+al->albumDisplay()+QLatin1Char('\n')+
|
|
Plurals::tracksWithDuration(al->trackCount(), Utils::formatTime(al->totalTime(), true)));
|
|
case Qt::DisplayRole:
|
|
return al->album;
|
|
case Qt::FontRole:
|
|
if (al->isNew) {
|
|
QFont f=ActionModel::data(index, role).value<QFont>();
|
|
f.setBold(true);
|
|
return f;
|
|
}
|
|
break;
|
|
case Cantata::Role_MainText:
|
|
return al->albumDisplay();
|
|
case Cantata::Role_BriefMainText:
|
|
return al->album;
|
|
case Cantata::Role_SubText:
|
|
return al->artist;
|
|
case Cantata::Role_TitleText:
|
|
return i18nc("Album by Artist", "%1 by %2", al->album, al->artist);
|
|
case Cantata::Role_CoverSong: {
|
|
QVariant v;
|
|
v.setValue<Song>(al->coverSong());
|
|
return v;
|
|
}
|
|
}
|
|
} else {
|
|
SongItem *si=static_cast<SongItem *>(item);
|
|
|
|
switch (role) {
|
|
default:
|
|
return ActionModel::data(index, role);
|
|
#ifdef ENABLE_UBUNTU
|
|
case Cantata::Role_Image:
|
|
return QString();
|
|
#endif
|
|
case Cantata::Role_ListImage:
|
|
return false;
|
|
#ifndef ENABLE_UBUNTU
|
|
case Qt::DecorationRole:
|
|
return Song::Playlist==si->type ? Icons::self()->playlistIcon : Icons::self()->audioFileIcon;
|
|
#endif
|
|
case Qt::ToolTipRole:
|
|
if (!Settings::self()->infoTooltips()) {
|
|
return QVariant();
|
|
}
|
|
return si->toolTip();
|
|
case Cantata::Role_MainText:
|
|
case Qt::DisplayRole:
|
|
if (Song::Playlist==si->type) {
|
|
return si->isCueFile() ? i18n("Cue Sheet") : i18n("Playlist");
|
|
}
|
|
if (Song::SingleTracks==si->parent->type) {
|
|
return si->artistSong();
|
|
}
|
|
return si->trackAndTitleStr();
|
|
case Cantata::Role_SubText:
|
|
return Utils::formatTime(si->time, true);
|
|
}
|
|
}
|
|
|
|
return QVariant();
|
|
}
|
|
|
|
Qt::ItemFlags AlbumsModel::flags(const QModelIndex &index) const
|
|
{
|
|
if (index.isValid()) {
|
|
return Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsEnabled;
|
|
}
|
|
return Qt::NoItemFlags;
|
|
}
|
|
|
|
QStringList AlbumsModel::filenames(const QModelIndexList &indexes, bool allowPlaylists) const
|
|
{
|
|
QList<Song> songList=songs(indexes, allowPlaylists);
|
|
QStringList fnames;
|
|
foreach (const Song &s, songList) {
|
|
fnames.append(s.file);
|
|
}
|
|
return fnames;
|
|
}
|
|
|
|
QList<Song> AlbumsModel::songs(const QModelIndexList &indexes, bool allowPlaylists) const
|
|
{
|
|
QList<Song> songs;
|
|
QSet<QString> files;
|
|
|
|
foreach(QModelIndex index, indexes) {
|
|
Item *item=static_cast<Item *>(index.internalPointer());
|
|
|
|
if (item->isAlbum()) {
|
|
QList<Song> albumSongs;
|
|
const SongItem *cue=allowPlaylists ? static_cast<AlbumItem*>(item)->getCueFile() : 0;
|
|
if (cue) {
|
|
if (!files.contains(cue->file)) {
|
|
albumSongs << *cue;
|
|
files << cue->file;
|
|
}
|
|
} else {
|
|
foreach (const SongItem *s, static_cast<AlbumItem*>(item)->songs) {
|
|
if ((/*allowPlaylists || */Song::Playlist!=s->type) && !files.contains(s->file)) {
|
|
albumSongs << *s;
|
|
files << s->file;
|
|
}
|
|
}
|
|
}
|
|
qSort(albumSongs);
|
|
songs << albumSongs;
|
|
} else if ((allowPlaylists || Song::Playlist!=static_cast<SongItem*>(item)->type) && !files.contains(static_cast<SongItem*>(item)->file)) {
|
|
songs << *static_cast<SongItem*>(item);
|
|
files << static_cast<SongItem*>(item)->file;
|
|
}
|
|
}
|
|
return songs;
|
|
}
|
|
|
|
#ifndef ENABLE_UBUNTU
|
|
QMimeData * AlbumsModel::mimeData(const QModelIndexList &indexes) const
|
|
{
|
|
QMimeData *mimeData = new QMimeData();
|
|
QStringList files=filenames(indexes, true);
|
|
PlayQueueModel::encode(*mimeData, PlayQueueModel::constFileNameMimeType, files);
|
|
// if (!MPDConnection::self()->getDetails().dir.isEmpty()) {
|
|
// QStringList paths;
|
|
// foreach (const QString &f, files) {
|
|
// paths << MPDConnection::self()->getDetails().dir+f;
|
|
// }
|
|
// PlayQueueModel::encode(*mimeData, PlayQueueModel::constUriMimeType, paths);
|
|
// }
|
|
return mimeData;
|
|
}
|
|
#endif
|
|
|
|
void AlbumsModel::update(const MusicLibraryItemRoot *root, bool incremental)
|
|
{
|
|
if (!enabled) {
|
|
return;
|
|
}
|
|
|
|
bool changesMade=false;
|
|
bool resettingModel=!incremental || items.isEmpty() || 0==root->childCount();
|
|
|
|
if (!incremental) {
|
|
clear();
|
|
}
|
|
|
|
if (resettingModel) {
|
|
beginResetModel();
|
|
}
|
|
QList<AlbumItem *>::Iterator it=items.begin();
|
|
QList<AlbumItem *>::Iterator end=items.end();
|
|
|
|
for (; it!=end; ++it) {
|
|
(*it)->updated=false;
|
|
}
|
|
|
|
for (int i = 0; i < root->childCount(); i++) {
|
|
MusicLibraryItemArtist *artistItem = static_cast<MusicLibraryItemArtist*>(root->childItem(i));
|
|
const QString &artist=artistItem->data();
|
|
for (int j = 0; j < artistItem->childCount(); j++) {
|
|
MusicLibraryItemAlbum *albumItem = static_cast<MusicLibraryItemAlbum*>(artistItem->childItem(j));
|
|
const QString &albumId=albumItem->albumId();
|
|
bool found=false;
|
|
it=items.begin();
|
|
end=items.end();
|
|
for (; it!=end; ++it) {
|
|
if ((*it)->year==albumItem->year() && (*it)->artist==artist && (*it)->albumId()==albumId) {
|
|
if (!resettingModel) {
|
|
QModelIndex albumIndex=index(items.indexOf(*it), 0, QModelIndex());
|
|
bool hadSongs=!(*it)->songs.isEmpty();
|
|
if (hadSongs) {
|
|
beginRemoveRows(albumIndex, 0, (*it)->songs.count()-1);
|
|
}
|
|
(*it)->clearSongs();
|
|
if (hadSongs) {
|
|
endRemoveRows();
|
|
}
|
|
if (albumItem->childCount()) {
|
|
beginInsertRows(albumIndex, 0, albumItem->childCount()-1);
|
|
}
|
|
}
|
|
(*it)->setSongs(albumItem);
|
|
if (!resettingModel && albumItem->childCount()) {
|
|
endInsertRows();
|
|
}
|
|
(*it)->genres=albumItem->genres();
|
|
(*it)->updated=true;
|
|
found=true;
|
|
if ((*it)->isNew!=albumItem->isNew()) {
|
|
(*it)->isNew=albumItem->isNew();
|
|
if (!resettingModel) {
|
|
QModelIndex albumIndex=index(items.indexOf(*it), 0, QModelIndex());
|
|
emit dataChanged(albumIndex, albumIndex);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!found) {
|
|
changesMade=true;
|
|
AlbumItem *a=new AlbumItem(artist, albumItem->data(), albumId,
|
|
artistItem->hasSort() ? artistItem->sortString() : QString(),
|
|
albumItem->hasSort() ? albumItem->sortString() : QString(),
|
|
albumItem->year());
|
|
a->setSongs(albumItem);
|
|
a->genres=albumItem->genres();
|
|
a->updated=true;
|
|
a->type=albumItem->songType();
|
|
a->isNew=albumItem->isNew();
|
|
if (!resettingModel) {
|
|
beginInsertRows(QModelIndex(), items.count(), items.count());
|
|
}
|
|
items.append(a);
|
|
if (!resettingModel) {
|
|
endInsertRows();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (resettingModel) {
|
|
endResetModel();
|
|
} else {
|
|
for (int i=0; i<items.count();) {
|
|
AlbumItem *ai=items.at(i);
|
|
if (!ai->updated) {
|
|
beginRemoveRows(QModelIndex(), i, i);
|
|
delete items.takeAt(i);
|
|
endRemoveRows();
|
|
} else {
|
|
++i;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (changesMade) {
|
|
emit updated();
|
|
}
|
|
}
|
|
|
|
void AlbumsModel::setCover(const Song &song, const QImage &img, const QString &file)
|
|
{
|
|
#ifdef ENABLE_UBUNTU
|
|
if (img.isNull()) {
|
|
if (!file.isEmpty()) return; //If empty, we need to execute the stuff below to set m_coverRequested to false
|
|
}
|
|
|
|
QList<AlbumItem *>::Iterator it=items.begin();
|
|
QList<AlbumItem *>::Iterator end=items.end();
|
|
QString artist=MusicLibraryItemRoot::artistName(song);
|
|
const QString &albumId=song.albumId();
|
|
|
|
for (int row=0; it!=end; ++it, ++row) {
|
|
if ((*it)->artist==artist && (*it)->albumId()==albumId) {
|
|
if ((*it)->coverRequested) {
|
|
(*it)->coverRequested=false;
|
|
if (!file.isEmpty()) {
|
|
(*it)->coverFile="file://"+file;
|
|
QModelIndex idx=index(row, 0, QModelIndex());
|
|
emit dataChanged(idx, idx);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
#else
|
|
Q_UNUSED(song)
|
|
Q_UNUSED(img)
|
|
Q_UNUSED(file)
|
|
#endif
|
|
}
|
|
|
|
void AlbumsModel::coverLoaded(const Song &song, int s)
|
|
{
|
|
Q_UNUSED(s)
|
|
#ifdef ENABLE_UBUNTU
|
|
Q_UNUSED(song)
|
|
#else
|
|
if (!song.isArtistImageRequest()) {
|
|
QList<AlbumItem *>::Iterator it=items.begin();
|
|
QList<AlbumItem *>::Iterator end=items.end();
|
|
const QString &albumArtist=song.albumArtist();
|
|
const QString &albumId=song.albumId();
|
|
|
|
for (int row=0; it!=end; ++it, ++row) {
|
|
if ((*it)->artist==albumArtist && (*it)->albumId()==albumId) {
|
|
QModelIndex idx=index(row, 0, QModelIndex());
|
|
emit dataChanged(idx, idx);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void AlbumsModel::clearNewState()
|
|
{
|
|
for (int i=0; i<items.count(); ++i) {
|
|
AlbumItem *al=items.at(i);
|
|
if (al->isNew) {
|
|
al->isNew=false;
|
|
QModelIndex idx=index(i, 0, QModelIndex());
|
|
emit dataChanged(idx, idx);
|
|
}
|
|
}
|
|
}
|
|
|
|
void AlbumsModel::clear()
|
|
{
|
|
beginResetModel();
|
|
qDeleteAll(items);
|
|
items.clear();
|
|
endResetModel();
|
|
|
|
#ifdef ENABLE_UBUNTU //For displaying a message when there is no album
|
|
emit updated();
|
|
#endif
|
|
}
|
|
|
|
void AlbumsModel::setEnabled(bool e)
|
|
{
|
|
if (e==enabled) {
|
|
return;
|
|
}
|
|
enabled=e;
|
|
|
|
if (enabled) {
|
|
#ifdef ENABLE_UBUNTU
|
|
connect(Covers::self(), SIGNAL(cover(const Song &, const QImage &, const QString &)),
|
|
this, SLOT(setCover(const Song &, const QImage &, const QString &)));
|
|
#else
|
|
connect(Covers::self(), SIGNAL(loaded(Song,int)), this, SLOT(coverLoaded(Song,int)));
|
|
#endif
|
|
update(MusicLibraryModel::self()->root(), false);
|
|
} else {
|
|
clear();
|
|
#ifdef ENABLE_UBUNTU
|
|
disconnect(Covers::self(), SIGNAL(cover(const Song &, const QImage &, const QString &)),
|
|
this, SLOT(setCover(const Song &, const QImage &, const QString &)));
|
|
#else
|
|
disconnect(Covers::self(), SIGNAL(loaded(Song,int)), this, SLOT(coverLoaded(Song,int)));
|
|
#endif
|
|
}
|
|
}
|
|
|
|
int AlbumsModel::albumSort() const
|
|
{
|
|
return sortAlbums;
|
|
}
|
|
|
|
void AlbumsModel::setAlbumSort(int s)
|
|
{
|
|
if (s!=sortAlbums) {
|
|
beginResetModel();
|
|
sortAlbums=s;
|
|
endResetModel();
|
|
}
|
|
}
|
|
|
|
AlbumsModel::AlbumItem::AlbumItem(const QString &ar, const QString &al, const QString &i, const QString &arSort, const QString &alSort, quint16 y)
|
|
: artist(ar)
|
|
, album(al)
|
|
, albumSortString(alSort)
|
|
, id(i)
|
|
, year(y)
|
|
, updated(false)
|
|
, numTracks(0)
|
|
, time(0)
|
|
, isNew(false)
|
|
#ifdef ENABLE_UBUNTU
|
|
, coverRequested(false)
|
|
#endif
|
|
{
|
|
if (!arSort.isEmpty()) {
|
|
artistSortString=arSort;
|
|
} else if (artist.startsWith(QLatin1String("The "))) {
|
|
artistSortString=artist.mid(4);
|
|
}
|
|
}
|
|
|
|
AlbumsModel::AlbumItem::~AlbumItem()
|
|
{
|
|
clearSongs();
|
|
}
|
|
|
|
bool AlbumsModel::AlbumItem::operator<(const AlbumItem &o) const
|
|
{
|
|
switch (sortAlbums) {
|
|
default:
|
|
case Sort_AlbumArtist: {
|
|
int compare=sortAlbum().localeAwareCompare(o.sortAlbum());
|
|
if (0!=compare) {
|
|
return compare<0;
|
|
}
|
|
compare=sortArtist().localeAwareCompare(o.sortArtist());
|
|
if (0!=compare) {
|
|
return compare<0;
|
|
}
|
|
return year==o.year ? id.compare(o.id)<0 : year<o.year;
|
|
}
|
|
case Sort_AlbumYear: {
|
|
int compare=sortAlbum().localeAwareCompare(o.sortAlbum());
|
|
if (0!=compare) {
|
|
return compare<0;
|
|
}
|
|
if (year!=o.year) {
|
|
return year<o.year;
|
|
}
|
|
compare=sortArtist().localeAwareCompare(o.sortArtist())<0;
|
|
return 0==compare ? id.compare(o.id)<0 : compare<0;
|
|
}
|
|
case Sort_ArtistAlbum: {
|
|
int compare=sortArtist().localeAwareCompare(o.sortArtist());
|
|
if (0!=compare) {
|
|
return compare<0;
|
|
}
|
|
compare=sortAlbum().localeAwareCompare(o.sortAlbum());
|
|
if (0!=compare) {
|
|
return compare<0;
|
|
}
|
|
return year==o.year ? id.compare(o.id)<0 : year<o.year;
|
|
}
|
|
case Sort_ArtistYear: {
|
|
int compare=sortArtist().localeAwareCompare(o.sortArtist());
|
|
if (0!=compare) {
|
|
return compare<0;
|
|
}
|
|
if (year!=o.year) {
|
|
return year<o.year;
|
|
}
|
|
compare=sortAlbum().localeAwareCompare(o.sortAlbum());
|
|
return 0==compare ? id.compare(o.id)<0 : compare<0;
|
|
}
|
|
case Sort_YearAlbum:
|
|
if (year==o.year) {
|
|
int compare=sortAlbum().localeAwareCompare(o.sortAlbum());
|
|
if (0!=compare) {
|
|
return compare<0;
|
|
}
|
|
compare=sortArtist().localeAwareCompare(o.sortArtist());
|
|
return 0==compare ? id.compare(o.id)<0 : compare<0;
|
|
}
|
|
return year<o.year;
|
|
case Sort_YearArtist:
|
|
if (year==o.year) {
|
|
int compare=sortArtist().localeAwareCompare(o.sortArtist());
|
|
if (0!=compare) {
|
|
return compare<0;
|
|
}
|
|
compare=sortAlbum().localeAwareCompare(o.sortAlbum());
|
|
return 0==compare ? id.compare(o.id)<0 : compare<0;
|
|
}
|
|
return year<o.year;
|
|
}
|
|
}
|
|
|
|
void AlbumsModel::AlbumItem::clearSongs()
|
|
{
|
|
time=0;
|
|
qDeleteAll(songs);
|
|
songs.clear();
|
|
}
|
|
|
|
void AlbumsModel::AlbumItem::setSongs(MusicLibraryItemAlbum *ai)
|
|
{
|
|
foreach (MusicLibraryItem *item, ai->childItems()) {
|
|
songs.append(new SongItem(static_cast<MusicLibraryItemSong*>(item)->song(), this));
|
|
}
|
|
}
|
|
|
|
quint32 AlbumsModel::AlbumItem::trackCount()
|
|
{
|
|
updateStats();
|
|
return numTracks;
|
|
}
|
|
|
|
quint32 AlbumsModel::AlbumItem::totalTime()
|
|
{
|
|
updateStats();
|
|
return time;
|
|
}
|
|
|
|
void AlbumsModel::AlbumItem::updateStats()
|
|
{
|
|
if (0==time) {
|
|
numTracks=0;
|
|
foreach (SongItem *s, songs) {
|
|
if (Song::Playlist!=s->type) {
|
|
time+=s->time;
|
|
numTracks++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef ENABLE_UBUNTU
|
|
QString AlbumsModel::AlbumItem::cover()
|
|
{
|
|
if (Song::SingleTracks!=type && songs.count() && coverFile.isEmpty() && !coverRequested) {
|
|
coverRequested=true;
|
|
coverFile=Covers::self()->requestImage(coverSong()).fileName;
|
|
if (!coverFile.isEmpty()) {
|
|
coverRequested=false;
|
|
coverFile="file://"+coverFile;
|
|
}
|
|
}
|
|
|
|
return coverFile;
|
|
}
|
|
#endif
|
|
|
|
const Song & AlbumsModel::AlbumItem::coverSong()
|
|
{
|
|
if (cSong.isEmpty() && songs.count()) {
|
|
SongItem *firstSong=songs.first();
|
|
cSong.artist=firstSong->artist;
|
|
cSong.albumartist=Song::useComposer() && !firstSong->composer().isEmpty()
|
|
? firstSong->albumArtist() : artist;
|
|
cSong.album=album;
|
|
cSong.year=year;
|
|
cSong.file=firstSong->file;
|
|
cSong.type=type;
|
|
cSong.setComposer(firstSong->composer());
|
|
cSong.setMbAlbumId(firstSong->mbAlbumId());
|
|
}
|
|
return cSong;
|
|
}
|
|
|
|
const AlbumsModel::SongItem *AlbumsModel::AlbumItem::getCueFile() const
|
|
{
|
|
foreach (SongItem *s, songs) {
|
|
if (s->isCueFile()) {
|
|
return s;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|