/* * Cantata * * Copyright (c) 2011-2014 Craig Drummond * */ /* * Copyright (c) 2008 Sander Knopper (sander AT knopper DOT tk) and * Roeland Douma (roeland AT rullzer DOT com) * * This file is part of QtMPC. * * QtMPC 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. * * QtMPC 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 QtMPC. If not, see . */ #include "musiclibraryitemalbum.h" #include "musiclibraryitemartist.h" #include "musiclibraryitemsong.h" #include "musiclibraryitemroot.h" #include "musiclibrarymodel.h" #include "roles.h" #include "support/utils.h" #include "widgets/icons.h" #include "gui/settings.h" #include #include #include #include #include #include #include MusicLibraryModel::MusicLibraryModel(QObject *parent) : ActionModel(parent) , rootItem(new MusicLibraryItemRoot) { rootItem->setModel(this); } MusicLibraryModel::~MusicLibraryModel() { delete rootItem; } QModelIndex MusicLibraryModel::index(int row, int column, const QModelIndex &parent) const { if (!hasIndex(row, column, parent)) { return QModelIndex(); } const MusicLibraryItem * parentItem; if (!parent.isValid()) { parentItem = rootItem; } else { parentItem = static_cast(parent.internalPointer()); } MusicLibraryItem * const childItem = parentItem->childItem(row); if (childItem) { return createIndex(row, column, childItem); } return QModelIndex(); } QModelIndex MusicLibraryModel::parent(const QModelIndex &index) const { if (!index.isValid()) { return QModelIndex(); } const MusicLibraryItem * const childItem = static_cast(index.internalPointer()); MusicLibraryItem * const parentItem = childItem->parentItem(); if (parentItem == rootItem) { return QModelIndex(); } return createIndex(parentItem->row(), 0, parentItem); } int MusicLibraryModel::rowCount(const QModelIndex &parent) const { if (parent.column() > 0) { return 0; } const MusicLibraryItem *parentItem; if (!parent.isValid()) { parentItem = rootItem; } else { parentItem = static_cast(parent.internalPointer()); } return parentItem->childCount(); } const MusicLibraryItemRoot * MusicLibraryModel::root(const MusicLibraryItem *item) const { if (MusicLibraryItem::Type_Root==item->itemType()) { return static_cast(item); } if (MusicLibraryItem::Type_Artist==item->itemType()) { return static_cast(item->parentItem()); } if (MusicLibraryItem::Type_Album==item->itemType()) { return static_cast(item->parentItem()->parentItem()); } if (MusicLibraryItem::Type_Song==item->itemType()) { return root(item->parentItem()); } return nullptr; } static QString parentData(const MusicLibraryItem *i) { QString data; const MusicLibraryItem *itm=i; while (itm->parentItem()) { if (!itm->parentItem()->data().isEmpty()) { if (MusicLibraryItem::Type_Root==itm->parentItem()->itemType()) { data=""+itm->parentItem()->data()+"
"+data; } else { data=itm->parentItem()->data()+"
"+data; } } itm=itm->parentItem(); } return data; } QVariant MusicLibraryModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return QVariant(); } if (Qt::CheckStateRole==role) { return static_cast(index.internalPointer())->checkState(); } MusicLibraryItem *item = static_cast(index.internalPointer()); switch (role) { case Qt::DecorationRole: switch (item->itemType()) { case MusicLibraryItem::Type_Root: return static_cast(item)->icon(); case MusicLibraryItem::Type_Artist: return Icons::self()->artistIcon; case MusicLibraryItem::Type_Album: return Icons::self()->albumIcon(32, true); case MusicLibraryItem::Type_Song: return Song::Playlist==static_cast(item)->song().type ? Icons::self()->playlistListIcon : Icons::self()->audioListIcon; default: return QVariant(); } case Cantata::Role_BriefMainText: if (MusicLibraryItem::Type_Album==item->itemType()) { return item->data(); } case Cantata::Role_MainText: case Qt::DisplayRole: if (MusicLibraryItem::Type_Song==item->itemType()) { MusicLibraryItemSong *song = static_cast(item); if (Song::Playlist==song->song().type) { return song->song().isCueFile() ? tr("Cue Sheet") : tr("Playlist"); } if (MusicLibraryItem::Type_Root==song->parentItem()->itemType()) { return song->song().trackAndTitleStr(); } return song->song().trackAndTitleStr(); } return item->displayData(); case Qt::ToolTipRole: if (!Settings::self()->infoTooltips()) { return QVariant(); } if (MusicLibraryItem::Type_Song==item->itemType()) { return static_cast(item)->song().toolTip(); } return parentData(item)+ (0==item->childCount() ? item->displayData(true) : (item->displayData(true)+"
"+data(index, Cantata::Role_SubText).toString())); case Cantata::Role_SubText: switch (item->itemType()) { case MusicLibraryItem::Type_Root: { MusicLibraryItemRoot *collection=static_cast(item); if (collection->flat()) { return tr("%n Track(s)", "", item->childCount()); } return tr("%n Artist(s)", "", item->childCount()); } case MusicLibraryItem::Type_Artist: return tr("%n Album(s)", "", item->childCount()); case MusicLibraryItem::Type_Song: return Utils::formatTime(static_cast(item)->time(), true); case MusicLibraryItem::Type_Album: return tr("%n Tracks (%1)", "", static_cast(item)->trackCount()) .arg(Utils::formatTime(static_cast(item)->totalTime())); default: return QVariant(); } case Cantata::Role_ListImage: switch (item->itemType()) { case MusicLibraryItem::Type_Album: return true; default: return false; } case Cantata::Role_CoverSong: { QVariant v; switch (item->itemType()) { case MusicLibraryItem::Type_Album: v.setValue(static_cast(item)->coverSong()); break; case MusicLibraryItem::Type_Artist: v.setValue(static_cast(item)->coverSong()); break; default: break; } return v; } case Cantata::Role_TitleText: if (MusicLibraryItem::Type_Album==item->itemType()) { return tr("%1 by %2", "Album by Artist").arg(item->data()).arg(item->parentItem()->data()); } return item->data(); default: break; } return ActionModel::data(index, role); } bool MusicLibraryModel::setData(const QModelIndex &idx, const QVariant &value, int role) { if (Qt::CheckStateRole==role) { if (!idx.isValid()) { return false; } MusicLibraryItem *item = static_cast(idx.internalPointer()); Qt::CheckState check=value.toBool() ? Qt::Checked : Qt::Unchecked; if (item->checkState()==check) { return false; } switch (item->itemType()) { case MusicLibraryItem::Type_Artist: { MusicLibraryItemArtist *artistItem=static_cast(item); QModelIndex artistIndex=index(artistItem->row(), 0, QModelIndex()); item->setCheckState(check); for (MusicLibraryItem *album: artistItem->childItems()) { if (check!=album->checkState()) { MusicLibraryItemAlbum *albumItem=static_cast(album); QModelIndex albumIndex=index(albumItem->row(), 0, artistIndex); album->setCheckState(check); for (MusicLibraryItem *song: albumItem->childItems()) { song->setCheckState(check); } emit dataChanged(index(0, 0, albumIndex), index(0, albumItem->childCount(), albumIndex)); } emit dataChanged(index(0, 0, artistIndex), index(0, artistItem->childCount(), artistIndex)); } emit dataChanged(idx, idx); break; } case MusicLibraryItem::Type_Album: { MusicLibraryItemArtist *artistItem=static_cast(item->parentItem()); MusicLibraryItemAlbum *albumItem=static_cast(item); QModelIndex artistIndex=index(artistItem->row(), 0, QModelIndex()); item->setCheckState(check); for (MusicLibraryItem *song: albumItem->childItems()) { song->setCheckState(check); } setParentState(artistIndex); emit dataChanged(idx, idx); break; } case MusicLibraryItem::Type_Song: { item->setCheckState(check); MusicLibraryItemAlbum *albumItem=static_cast(item->parentItem()); MusicLibraryItemArtist *artistItem=static_cast(albumItem->parentItem()); QModelIndex artistIndex=index(artistItem->row(), 0, QModelIndex()); QModelIndex albumIndex=index(albumItem->row(), 0, artistIndex); setParentState(albumIndex); setParentState(artistIndex); emit dataChanged(idx, idx); break; } case MusicLibraryItem::Type_Root: return false; } return true; } return ActionModel::setData(idx, value, role); } void MusicLibraryModel::setParentState(const QModelIndex &parent) { MusicLibraryItemContainer *parentItem=static_cast(parent.internalPointer()); Qt::CheckState parentCheck=parentItem->checkState(); bool haveCheckedChildren=false; bool haveUncheckedChildren=false; bool stop=false; for (MusicLibraryItem *child: parentItem->childItems()) { switch (child->checkState()) { case Qt::PartiallyChecked: parentCheck=Qt::PartiallyChecked; stop=true; break; case Qt::Unchecked: haveUncheckedChildren=true; parentCheck=haveCheckedChildren ? Qt::PartiallyChecked : Qt::Unchecked; stop=haveCheckedChildren && haveUncheckedChildren; break; case Qt::Checked: haveCheckedChildren=true; parentCheck=haveUncheckedChildren ? Qt::PartiallyChecked : Qt::Checked; stop=haveCheckedChildren && haveUncheckedChildren; break; } if (stop) { break; } } if (parentItem->checkState()!=parentCheck) { parentItem->setCheckState(parentCheck); emit dataChanged(parent, parent); } } void MusicLibraryModel::clear() { beginResetModel(); rootItem->clear(); endResetModel(); } void MusicLibraryModel::setSongs(const QSet &songs) { rootItem->update(songs); // for (MusicLibraryItem *artist: rootItem->childItems()) { // MusicLibraryItemArtist *artistItem=static_cast(artist); // artistItem->setCheckState(Qt::Checked); // for (MusicLibraryItem *album: artistItem->childItems()) { // MusicLibraryItemAlbum *albumItem=static_cast(album); // albumItem->setCheckState(Qt::Checked); // for (MusicLibraryItem *song: albumItem->childItems()) { // song->setCheckState(Qt::Checked); // } // } // } } Qt::ItemFlags MusicLibraryModel::flags(const QModelIndex &index) const { if (index.isValid()) { return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable; } return Qt::ItemIsDropEnabled; } #include "moc_musiclibrarymodel.cpp"