File indexing completed on 2024-05-19 04:49:17
0001 /**************************************************************************************** 0002 * Copyright (c) 2011 Bart Cerneels <bart.cerneels@kde.org> * 0003 * * 0004 * This program is free software; you can redistribute it and/or modify it under * 0005 * the terms of the GNU General Public License as published by the Free Software * 0006 * Foundation; either version 2 of the License, or (at your option) any later * 0007 * version. * 0008 * * 0009 * This program is distributed in the hope that it will be useful, but WITHOUT ANY * 0010 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * 0011 * PARTICULAR PURPOSE. See the GNU General Public License for more details. * 0012 * * 0013 * You should have received a copy of the GNU General Public License along with * 0014 * this program. If not, see <http://www.gnu.org/licenses/>. * 0015 ****************************************************************************************/ 0016 0017 #ifndef MEMORYMETA_H 0018 #define MEMORYMETA_H 0019 0020 #include "amarok_export.h" 0021 #include "MemoryCollection.h" 0022 #include "core/meta/Meta.h" 0023 0024 using namespace Collections; 0025 0026 /** These classes can be used with a MemoryCollection to populate the meta-type maps */ 0027 namespace MemoryMeta { 0028 0029 class Track; 0030 0031 /** 0032 * Base class for all MemoryMeta:: entities that store a list of associated tracks: 0033 * Artist, Album, Composer, Genre, Year. 0034 * 0035 * All methods of this class are thread-safe. 0036 */ 0037 class Base 0038 { 0039 public: 0040 explicit Base( const QString &name ) : m_name( name ) {} 0041 virtual ~Base() {} 0042 0043 // Meta::{Artist,Album,Composer,Genre,Year} methods: 0044 virtual QString name() const { return m_name; } 0045 virtual Meta::TrackList tracks(); 0046 0047 // MemoryMeta::Base methods: 0048 void addTrack( Track *track ); 0049 void removeTrack( Track *track ); 0050 0051 private: 0052 QString m_name; 0053 /* We cannot easily store AmarokSharedPointer to tracks, because it creates reference 0054 * counting cycle: MemoryMeta::Track::m_album -> MemoryMeta::Album::tracks() -> 0055 * MemoryMeta::Track. We therefore store plain pointers and rely on 0056 * MemoryMeta::Track to notify when it is destroyed. */ 0057 QList<Track *> m_tracks; 0058 QReadWriteLock m_tracksLock; 0059 }; 0060 0061 class Artist : public Meta::Artist, public Base 0062 { 0063 public: 0064 explicit Artist( const QString &name ) : MemoryMeta::Base( name ) {} 0065 0066 QString name() const override { return MemoryMeta::Base::name(); } 0067 Meta::TrackList tracks() override { return MemoryMeta::Base::tracks(); } 0068 }; 0069 0070 class Album : public Meta::Album, public Base 0071 { 0072 public: 0073 Album( const QString &name, const Meta::ArtistPtr &albumArtist ) 0074 : MemoryMeta::Base( name ) 0075 , m_albumArtist( albumArtist ) 0076 , m_isCompilation( false ) 0077 , m_canUpdateCompilation( false ) 0078 , m_canUpdateImage( false ) 0079 {} 0080 /** 0081 * Copy-like constructor for MapChanger 0082 */ 0083 explicit Album( const Meta::AlbumPtr &other ); 0084 0085 /* Meta::MetaCapability virtual methods */ 0086 bool hasCapabilityInterface( Capabilities::Capability::Type type ) const override; 0087 Capabilities::Capability* createCapabilityInterface( Capabilities::Capability::Type type ) override; 0088 0089 /* Meta::Base virtual methods */ 0090 QString name() const override { return MemoryMeta::Base::name(); } 0091 0092 /* Meta::Album virtual methods */ 0093 bool isCompilation() const override { return m_isCompilation; } 0094 bool canUpdateCompilation() const override { return m_canUpdateCompilation; } 0095 void setCompilation( bool isCompilation ) override; 0096 0097 bool hasAlbumArtist() const override { return !m_albumArtist.isNull(); } 0098 Meta::ArtistPtr albumArtist() const override { return m_albumArtist; } 0099 Meta::TrackList tracks() override { return MemoryMeta::Base::tracks(); } 0100 0101 bool hasImage( int /* size */ = 0 ) const override { return !m_image.isNull(); } 0102 QImage image( int size = 0 ) const override; 0103 bool canUpdateImage() const override { return m_canUpdateImage; } 0104 void setImage( const QImage &image ) override; 0105 void removeImage() override; 0106 0107 /* MemoryMeta::Album methods: */ 0108 /** 0109 * Re-read isCompilation, canUpdateCompilation, image, canUpdateImage from all 0110 * underlying tracks. 0111 */ 0112 void updateCachedValues(); 0113 0114 private: 0115 Meta::ArtistPtr m_albumArtist; 0116 bool m_isCompilation; 0117 bool m_canUpdateCompilation; 0118 QImage m_image; 0119 bool m_canUpdateImage; 0120 }; 0121 0122 class Composer : public Meta::Composer, public Base 0123 { 0124 public: 0125 explicit Composer( const QString &name ) : MemoryMeta::Base( name ) {} 0126 0127 QString name() const override { return MemoryMeta::Base::name(); } 0128 Meta::TrackList tracks() override { return MemoryMeta::Base::tracks(); } 0129 }; 0130 0131 class Genre : public Meta::Genre, public Base 0132 { 0133 public: 0134 explicit Genre( const QString &name ) : MemoryMeta::Base( name ) {} 0135 0136 QString name() const override { return MemoryMeta::Base::name(); } 0137 Meta::TrackList tracks() override { return MemoryMeta::Base::tracks(); } 0138 }; 0139 0140 class Year : public Meta::Year, public Base 0141 { 0142 public: 0143 explicit Year( const QString &name ) : MemoryMeta::Base( name ) {} 0144 0145 QString name() const override { return MemoryMeta::Base::name(); } 0146 Meta::TrackList tracks() override { return MemoryMeta::Base::tracks(); } 0147 }; 0148 0149 class AMAROK_EXPORT Track : public Meta::Track 0150 { 0151 public: 0152 explicit Track( const Meta::TrackPtr &originalTrack ); 0153 ~Track() override; 0154 0155 /* Meta::MetaCapability methods */ 0156 bool hasCapabilityInterface( Capabilities::Capability::Type type ) const override 0157 { return m_track->hasCapabilityInterface( type ); } 0158 Capabilities::Capability *createCapabilityInterface( Capabilities::Capability::Type type ) override 0159 { return m_track->createCapabilityInterface( type ); } 0160 0161 /* Meta::Base virtual methods */ 0162 QString name() const override { return m_track->name(); } 0163 0164 /* Meta::Track virtual methods */ 0165 QUrl playableUrl() const override { return m_track->playableUrl(); } 0166 QString prettyUrl() const override { return m_track->prettyUrl(); } 0167 QString uidUrl() const override { return m_track->uidUrl(); } 0168 QString notPlayableReason() const override { return m_track->notPlayableReason(); } 0169 0170 //these functions return the proxy track values 0171 Meta::AlbumPtr album() const override { return m_album; } 0172 Meta::ArtistPtr artist() const override { return m_artist; } 0173 Meta::ComposerPtr composer() const override { return m_composer; } 0174 Meta::GenrePtr genre() const override { return m_genre; } 0175 Meta::YearPtr year() const override { return m_year; } 0176 0177 //TODO:implement labels 0178 Meta::LabelList labels() const override { return Meta::LabelList(); } 0179 qreal bpm() const override { return m_track->bpm(); } 0180 QString comment() const override { return m_track->comment(); } 0181 qint64 length() const override { return m_track->length(); } 0182 int filesize() const override { return m_track->filesize(); } 0183 int sampleRate() const override { return m_track->sampleRate(); } 0184 int bitrate() const override { return m_track->bitrate(); } 0185 QDateTime createDate() const override { return m_track->createDate(); } 0186 QDateTime modifyDate() const override { return m_track->modifyDate(); } 0187 int trackNumber() const override { return m_track->trackNumber(); } 0188 int discNumber() const override { return m_track->discNumber(); } 0189 0190 qreal replayGain( Meta::ReplayGainTag mode ) const override 0191 { return m_track->replayGain( mode ); } 0192 QString type() const override { return m_track->type(); } 0193 0194 void prepareToPlay() override { m_track->prepareToPlay(); } 0195 void finishedPlaying( double fraction ) override { m_track->finishedPlaying( fraction ); } 0196 0197 bool inCollection() const override { return m_track->inCollection(); } 0198 Collections::Collection *collection() const override { return m_track->collection(); } 0199 0200 QString cachedLyrics() const override { return m_track->cachedLyrics(); } 0201 void setCachedLyrics( const QString &lyrics ) override { m_track->setCachedLyrics( lyrics ); } 0202 0203 //TODO: implement labels 0204 void addLabel( const QString &label ) override { Q_UNUSED( label ) } 0205 void addLabel( const Meta::LabelPtr &label ) override { Q_UNUSED( label ) } 0206 void removeLabel( const Meta::LabelPtr &label ) override { Q_UNUSED( label ) } 0207 0208 Meta::TrackEditorPtr editor() override; 0209 Meta::StatisticsPtr statistics() override; 0210 0211 // MemoryMeta::Track methods: 0212 0213 /* All of these set* methods pass the pointer to AmarokSharedPointer (thus memory-manage it), 0214 * remove this track from previous {Album,Artist,Composer,Genre,Year} entity (if any) 0215 * and add this track to newly set entity. (if non-null) 0216 * All these methods are reentrant, but not thread-safe: caller must ensure that 0217 * only one of the following methods is called at a time on a single instance. 0218 */ 0219 void setAlbum( Album *album ); 0220 void setArtist( Artist *artist ); 0221 void setComposer( Composer *composer ); 0222 void setGenre( Genre *genre ); 0223 void setYear( Year *year ); 0224 0225 /** 0226 * Return the original track this track proxies. 0227 */ 0228 Meta::TrackPtr originalTrack() const { return m_track; } 0229 0230 /** 0231 * Make notifyObservers() public so that MapChanger can call this 0232 */ 0233 using Meta::Track::notifyObservers; 0234 0235 private: 0236 Meta::TrackPtr m_track; 0237 Meta::AlbumPtr m_album; 0238 Meta::ArtistPtr m_artist; 0239 Meta::ComposerPtr m_composer; 0240 Meta::GenrePtr m_genre; 0241 Meta::YearPtr m_year; 0242 }; 0243 0244 /** 0245 * Helper class that facilitates adding, removing and changing tracks that are in 0246 * MemoryCollection. This class locks underlying MemoryCollection upon construction for 0247 * writing and releases the lock in destructor. 0248 * 0249 * Typical usage: 0250 * { 0251 * MemoryMeta::MapChanger changer( memoryCollectionPtr ); 0252 * Meta::Track newTrack = changer.addTrack( trackPtr ); 0253 * ... 0254 * changer.removeTrack( newTrack ); 0255 * } 0256 * 0257 * All methods in this class are re-entrant and it operates on MemoryCollection in 0258 * a thread-safe way: you can run MapChangers from multiple threads on a single 0259 * MemoryCollection at once. (each thread constructing MapChanger when needed and deleting 0260 * it as soon as possible) 0261 * 0262 * All methods can be called multiple times on a single instance and can be combined. 0263 */ 0264 class AMAROK_EXPORT MapChanger 0265 { 0266 public: 0267 explicit MapChanger( MemoryCollection *memoryCollection ); 0268 ~MapChanger(); 0269 0270 /** 0271 * Adds a track to MemoryCollection by proxying it using @see MemoryMeta::Track 0272 * track artist, album, genre, composer and year are replaced in MemoryMeta::Track 0273 * by relevant MemoryMeta entities, based on their value. Refuses to add a track 0274 * whose proxy is already in MemoryCollection (returns null pointer in this case) 0275 * 0276 * @return pointer to a newly created MemoryMeta::Track (may be null if not 0277 * successful) 0278 */ 0279 Meta::TrackPtr addTrack( Meta::TrackPtr track ); 0280 0281 /** 0282 * Removes a track from MemoryCollection. Pays attention to remove artists, 0283 * albums, genres, composers and years that may become dangling in 0284 * MemoryCollection. 0285 * 0286 * @param track MemoryMeta track to remove, it doesn't matter if this is the track 0287 * returned by MapChanger::addTrack or the underlying one passed to 0288 * MapChanger::addTrack - the real track is looked up using its uidUrl in 0289 * MemoryCollection. 0290 * 0291 * @return shared pointer to underlying track of the deleted track, i.e. the track 0292 * that you passed to MapChanger::addTrack() originally. May be null pointer if 0293 * @param track is not found in collection or if it wasn't added using MapChanger. 0294 */ 0295 Meta::TrackPtr removeTrack( Meta::TrackPtr track ); 0296 0297 /** 0298 * Reflects changes made to underlying track to its proxy track in 0299 * MemoryCollection and to MemoryCollection maps. 0300 * 0301 * The one who called MapChanger::addTrack() is responsible to call this method 0302 * every time it detects that some metadata of underlying track have changed 0303 * (perhaps by becoming its observer), even in minor fields such as comment. This 0304 * method instructs proxy track to call notifyObservers(). 0305 * 0306 * Please note that this method is currently unable to cope with changes 0307 * to track uidUrl(). If you really need it, change MemoryCollection's 0308 * trackMap manually _before_ calling this. 0309 * 0310 * @param track track whose metadata have changed, it doesn't matter if this is 0311 * the track returned by MapChanger::addTrack or the underlying one passed to 0312 * MapChanger::addTrack - the real track is looked up using its uidUrl in 0313 * MemoryCollection. Does nothing if @param track is not found in MemoryCollection. 0314 * 0315 * @return true if memory collection maps had to be changed, false for minor 0316 * changes where this is not required 0317 */ 0318 bool trackChanged( Meta::TrackPtr track ); 0319 0320 private: 0321 /** 0322 * Worker for addTrack. 0323 * 0324 * @param track original underlying track - source of metadata 0325 * @param memoryTrack new track to add to MemoryCollection - target of metadata 0326 */ 0327 Meta::TrackPtr addExistingTrack( Meta::TrackPtr track, Track *memoryTrack ); 0328 0329 /** 0330 * Return true if at least one of the tracks in @param needles is in 0331 * @param haystack, false otherwise. Comparison is done using track uidUrl. 0332 */ 0333 static bool hasTrackInMap( const Meta::TrackList &needles, const TrackMap &haystack ); 0334 0335 /** 0336 * Return true if artist @param artist is referenced as albumArtist of one of the 0337 * albums from @param haystack. The match is done using Meta:ArtistPtr 0338 * operator==. 0339 */ 0340 static bool referencedAsAlbumArtist( const Meta::ArtistPtr &artist, const AlbumMap &haystack ); 0341 0342 /** 0343 * Return true if @param first has different value than @param other. Specifically 0344 * returns true if one entity is null and the other non-null, but returns true if 0345 * both are null. 0346 */ 0347 static bool entitiesDiffer( const Meta::Base *first, const Meta::Base *second ); 0348 /** 0349 * Overload for albums, we compare album artist, isCollection and image too 0350 */ 0351 static bool entitiesDiffer( const Meta::Album *first, const Meta::Album *second ); 0352 0353 MemoryCollection *m_mc; 0354 }; 0355 0356 } 0357 #endif