/* * Cantata * * Copyright (c) 2011-2012 Craig Drummond * * ---- * * 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 "config.h" #include "device.h" #include "devicesmodel.h" #include "umsdevice.h" #ifdef MTP_FOUND #include "mtpdevice.h" #endif #include "tags.h" #include "song.h" #include "mpdparseutils.h" #include "musiclibraryitemartist.h" #include "musiclibraryitemalbum.h" #include "musiclibraryitemsong.h" #include "localize.h" #include #include #include #include #include const QLatin1String Device::constNoCover("-"); Device * Device::create(DevicesModel *m, const QString &udi) { Solid::Device device=Solid::Device(udi); if (device.is()) { #ifdef MTP_FOUND Solid::PortableMediaPlayer *pmp = device.as(); if (pmp->supportedProtocols().contains(QLatin1String("mtp"))) { return new MtpDevice(m, device); } #endif } else if (device.is()) { //HACK: ignore apple stuff until we have common MediaDeviceFactory. if (!device.vendor().contains("apple", Qt::CaseInsensitive)) { // Solid::StorageAccess *sa = device.as(); // if (QLatin1String("usb")==sa->bus) { return new UmsDevice(m, device); // } } } return 0; } bool Device::fixVariousArtists(const QString &file, Song &song, bool applyFix) { Song orig=song; if (!file.isEmpty() && song.albumartist.isEmpty()) { song=Tags::read(file); } if (song.artist.isEmpty() || song.albumartist.isEmpty() || !Song::isVariousArtists(song.albumartist)) { song=orig; return false; } bool needsUpdating=false; if (!applyFix) { // Then real artist is embedded in track title... needsUpdating=song.revertVariousArtists(); } else if (applyFix) { // We must be copying to device, and need to place song artist into title... needsUpdating=song.fixVariousArtists(); } if (needsUpdating && (file.isEmpty() || Tags::Update_Modified==Tags::updateArtistAndTitle(file, song))) { return true; } song=orig; return false; } void Device::applyUpdate() { if (!update) { return; } /*if (m_childItems.count() && update && update->childCount()) { QSet currentSongs=allSongs(); QSet updateSongs=update->allSongs(); QSet removed=currentSongs-updateSongs; QSet added=updateSongs-currentSongs; foreach (const Song &s, added) { addSongToList(s); } foreach (const Song &s, removed) { removeSongFromList(s); } delete update; } else*/ { int oldCount=childCount(); if (oldCount>0) { model->beginRemoveRows(model->createIndex(model->devices.indexOf(this), 0, this), 0, oldCount-1); m_childItems.clear(); qDeleteAll(m_childItems); model->endRemoveRows(); } int newCount=newRows(); if (newCount>0) { model->beginInsertRows(model->createIndex(model->devices.indexOf(this), 0, this), 0, newCount-1); foreach (MusicLibraryItem *item, update->childItems()) { item->setParent(this); } delete update; refreshIndexes(); model->endInsertRows(); } } update=0; } const MusicLibraryItem * Device::findSong(const Song &s) const { MusicLibraryItemArtist *artistItem = ((MusicLibraryItemRoot *)this)->artist(s, false); if (artistItem) { MusicLibraryItemAlbum *albumItem = artistItem->album(s, false); if (albumItem) { foreach (const MusicLibraryItem *songItem, albumItem->childItems()) { if (songItem->data()==s.title) { return songItem; } } } } return 0; } bool Device::songExists(const Song &s) const { const MusicLibraryItem *song=findSong(s); if (song) { return true; } if (!s.isVariousArtists()) { Song mod(s); #ifdef ENABLE_KDE_SUPPORT mod.albumartist=i18n("Various Artists"); #else mod.albumartist=tr("Various Artists"); #endif if (MPDParseUtils::groupMultiple()) { song=findSong(mod); if (song) { Song sng=static_cast(song)->song(); if (sng.albumArtist()==s.albumArtist()) { return true; } } } if (MPDParseUtils::groupSingle()) { #ifdef ENABLE_KDE_SUPPORT mod.album=i18n("Single Tracks"); #else mod.album=QObject::tr("Single Tracks"); #endif song=findSong(mod); if (song) { Song sng=static_cast(song)->song(); if (sng.albumArtist()==s.albumArtist() && sng.album==s.album) { return true; } } } } return false; } void Device::addSongToList(const Song &s) { MusicLibraryItemArtist *artistItem = artist(s, false); if (!artistItem) { model->beginInsertRows(model->createIndex(model->devices.indexOf(this), 0, this), childCount(), childCount()); artistItem = createArtist(s); model->endInsertRows(); } MusicLibraryItemAlbum *albumItem = artistItem->album(s, false); if (!albumItem) { model->beginInsertRows(model->createIndex(childItems().indexOf(artistItem), 0, artistItem), artistItem->childCount(), artistItem->childCount()); albumItem = artistItem->createAlbum(s); model->endInsertRows(); } foreach (const MusicLibraryItem *songItem, albumItem->childItems()) { if (songItem->data()==s.title) { return; } } model->beginInsertRows(model->createIndex(artistItem->childItems().indexOf(albumItem), 0, albumItem), albumItem->childCount(), albumItem->childCount()); MusicLibraryItemSong *songItem = new MusicLibraryItemSong(s, albumItem); albumItem->append(songItem); model->endInsertRows(); } void Device::removeSongFromList(const Song &s) { MusicLibraryItemArtist *artistItem = artist(s, false); if (!artistItem) { return; } MusicLibraryItemAlbum *albumItem = artistItem->album(s, false); if (!albumItem) { return; } MusicLibraryItem *songItem=0; int songRow=0; foreach (MusicLibraryItem *song, albumItem->childItems()) { if (static_cast(song)->song().title==s.title) { songItem=song; break; } songRow++; } if (!songItem) { return; } if (1==artistItem->childCount() && 1==albumItem->childCount()) { // 1 album with 1 song - so remove whole artist int row=m_childItems.indexOf(artistItem); model->beginRemoveRows(model->createIndex(model->devices.indexOf(this), 0, this), row, row); remove(artistItem); model->endRemoveRows(); return; } if (1==albumItem->childCount()) { // multiple albums, but this album only has 1 song - remove album int row=artistItem->childItems().indexOf(albumItem); model->beginRemoveRows(model->createIndex(childItems().indexOf(artistItem), 0, artistItem), row, row); artistItem->remove(albumItem); model->endRemoveRows(); return; } // Just remove particular song model->beginRemoveRows(model->createIndex(artistItem->childItems().indexOf(albumItem), 0, albumItem), songRow, songRow); albumItem->remove(songRow); model->endRemoveRows(); } void Device::setStatusMessage(const QString &msg) { statusMsg=msg; QModelIndex modelIndex=model->createIndex(model->devices.indexOf(this), 0, this); emit model->dataChanged(modelIndex, modelIndex); } void Device::songCount(int c) { setStatusMessage(i18n("Updating (%1)...", c)); }