File indexing completed on 2025-01-05 04:26:02
0001 /**************************************************************************************** 0002 * Copyright (c) 2009 Alejandro Wainzinger <aikawarazuni@gmail.com> * 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) version 3 or * 0007 * any later version accepted by the membership of KDE e.V. (or its successor approved * 0008 * by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of * 0009 * version 3 of the license. * 0010 * * 0011 * This program is distributed in the hope that it will be useful, but WITHOUT ANY * 0012 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * 0013 * PARTICULAR PURPOSE. See the GNU General Public License for more details. * 0014 * * 0015 * You should have received a copy of the GNU General Public License along with * 0016 * this program. If not, see <http://www.gnu.org/licenses/>. * 0017 ****************************************************************************************/ 0018 0019 #ifndef MEDIADEVICEHANDLER_H 0020 #define MEDIADEVICEHANDLER_H 0021 0022 #include "core/meta/Observer.h" 0023 #include "core-impl/collections/mediadevicecollection/MediaDeviceMeta.h" 0024 #include "core-impl/collections/mediadevicecollection/handler/MediaDeviceHandlerCapability.h" 0025 #include "core-impl/collections/mediadevicecollection/handler/capabilities/PlaylistCapability.h" 0026 #include "core-impl/collections/mediadevicecollection/handler/capabilities/PodcastCapability.h" 0027 #include "core-impl/collections/mediadevicecollection/handler/capabilities/ReadCapability.h" 0028 #include "core-impl/collections/mediadevicecollection/handler/capabilities/WriteCapability.h" 0029 #include "core-impl/collections/mediadevicecollection/playlist/MediaDevicePlaylist.h" 0030 #include "core-impl/collections/mediadevicecollection/playlist/MediaDeviceUserPlaylistProvider.h" 0031 #include "core-impl/collections/support/MemoryCollection.h" 0032 #include "core-impl/playlists/providers/user/UserPlaylistProvider.h" 0033 0034 #include <ThreadWeaver/Job> 0035 0036 #include <QAction> 0037 #include <QObject> 0038 #include <QMap> 0039 #include <QMultiMap> 0040 0041 class QString; 0042 class QMutex; 0043 0044 namespace Collections { 0045 class MediaDeviceCollection; 0046 } 0047 0048 namespace Meta 0049 { 0050 typedef QMultiMap<QString, Meta::TrackPtr> TitleMap; 0051 0052 class MEDIADEVICECOLLECTION_EXPORT MetaHandlerCapability 0053 { 0054 public: 0055 virtual ~MetaHandlerCapability() {} 0056 0057 virtual bool hasCapabilityInterface( Handler::Capability::Type type ) const; 0058 0059 virtual Handler::Capability* createCapabilityInterface( Handler::Capability::Type type ); 0060 0061 /** 0062 * Retrieves a specialized interface which represents a capability of this 0063 * object. 0064 * 0065 * @returns a pointer to the capability interface if it exists, 0 otherwise 0066 */ 0067 template <class CapIface> CapIface *create() 0068 { 0069 Handler::Capability::Type type = CapIface::capabilityInterfaceType(); 0070 Handler::Capability *iface = createCapabilityInterface(type); 0071 return qobject_cast<CapIface *>(iface); 0072 } 0073 0074 /** 0075 * Tests if an object provides a given capability interface. 0076 * 0077 * @returns true if the interface is available, false otherwise 0078 */ 0079 template <class CapIface> bool is() const 0080 { 0081 return hasCapabilityInterface( CapIface::capabilityInterfaceType() ); 0082 } 0083 }; 0084 0085 /** 0086 The MediaDeviceHandler is the backend where all low-level library calls are made. 0087 It exists to leave a generic API in the other classes, while allowing for low-level 0088 calls to be isolated here. 0089 */ 0090 0091 class MEDIADEVICECOLLECTION_EXPORT MediaDeviceHandler : public QObject, public Meta::MetaHandlerCapability, public Meta::Observer 0092 { 0093 Q_OBJECT 0094 0095 public: 0096 /** 0097 * Destructor 0098 */ 0099 ~MediaDeviceHandler() override; 0100 0101 // Declare thread as friend class 0102 0103 friend class ParseWorkerThread; 0104 0105 /** 0106 * Begins an attempt to connect to the device, and emits 0107 * attemptConnectionDone when it finishes. 0108 */ 0109 virtual void init() = 0; // collection 0110 0111 /** 0112 * Checks if the handler successfully connected 0113 * to the device. 0114 * @return 0115 * TRUE if the device was successfully connected to 0116 * FALSE if the device was not successfully connected to 0117 */ 0118 bool succeeded() const // collection 0119 { 0120 return m_success; 0121 } 0122 0123 /// Methods provided for CollectionLocation 0124 0125 /** 0126 * Checks if a device can be written to. 0127 * @return 0128 * TRUE if the device can be written to 0129 * FALSE if the device can not be written to 0130 */ 0131 virtual bool isWritable() const = 0; 0132 0133 /** Given a list of tracks, get URLs for device tracks 0134 * of this type of device. If the device needs to 0135 * do some work to get URLs (e.g. copy tracks to a 0136 * temporary location) the overridden method in 0137 * the handler takes care of it, but must Q_EMIT 0138 * gotCopyableUrls when finished. 0139 * @param tracks The list of tracks for which to fetch urls 0140 */ 0141 virtual void getCopyableUrls( const Meta::TrackList &tracks ); 0142 0143 /** 0144 * Fetches the human-readable name of the device. 0145 * This is often called from the Collection since 0146 * a library call is needed to get this name. 0147 * @return A QString with the name 0148 */ 0149 virtual QString prettyName() const = 0; 0150 0151 /** 0152 * Copies a list of tracks to the device. 0153 * @param tracklist The list of tracks to copy. 0154 */ 0155 void copyTrackListToDevice( const Meta::TrackList tracklist ); 0156 0157 /** 0158 * Removes a list of tracks from the device. 0159 * @param tracks The list of tracks to remove. 0160 */ 0161 void removeTrackListFromDevice( const Meta::TrackList &tracks ); 0162 0163 /** This function is called just before a track in the playlist is to be played, and gives 0164 * a chance for e.g. MTP to copy the track to a temporary location, set a playable url, 0165 * to emulate the track actually being played off the device 0166 * @param track The track that needs to prepare to be played 0167 */ 0168 virtual void prepareToPlay( Meta::MediaDeviceTrackPtr &track ) { Q_UNUSED( track ) } // called by @param track 0169 0170 virtual float usedcapacity(); 0171 virtual float totalcapacity(); 0172 0173 Playlists::UserPlaylistProvider* provider(); 0174 0175 // HACK: Used for device-specific actions, such as initialize for iPod 0176 virtual QList<QAction *> collectionActions() { return QList<QAction*> (); } 0177 0178 Q_SIGNALS: 0179 void gotCopyableUrls( const QMap<Meta::TrackPtr, QUrl> &urls ); 0180 void databaseWritten( bool succeeded ); 0181 0182 void deleteTracksDone(); 0183 void incrementProgress(); 0184 void endProgressOperation( QObject *owner ); 0185 0186 void copyTracksDone( bool success ); 0187 void removeTracksDone(); 0188 0189 /* File I/O Methods */ 0190 0191 public Q_SLOTS: 0192 0193 /** 0194 * Parses the media device's database and creates a Meta::MediaDeviceTrack 0195 * for each track in the database. NOTE: only call once per device. 0196 */ 0197 void parseTracks(); // collection 0198 0199 /** 0200 * Writes to the device's database if it has one, otherwise 0201 * simply calls slotDatabaseWritten to continue the workflow. 0202 */ 0203 0204 virtual void writeDatabase() { slotDatabaseWritten( true ); } 0205 0206 void savePlaylist( const Playlists::MediaDevicePlaylistPtr &playlist, const QString& name ); 0207 void renamePlaylist( const Playlists::MediaDevicePlaylistPtr &playlist ); 0208 void deletePlaylists( const Playlists::MediaDevicePlaylistList &playlistlist ); 0209 0210 bool privateParseTracks(); 0211 0212 void copyNextTrackToDevice(); 0213 bool privateCopyTrackToDevice( const Meta::TrackPtr& track ); 0214 0215 void removeNextTrackFromDevice(); 0216 void privateRemoveTrackFromDevice( const Meta::TrackPtr &track ); 0217 0218 void slotCopyNextTrackFailed( ThreadWeaver::JobPointer job, const Meta::TrackPtr& track ); 0219 void slotCopyNextTrackDone( ThreadWeaver::JobPointer job, const Meta::TrackPtr& track ); 0220 0221 protected: 0222 0223 /** 0224 * Constructor 0225 * @param parent the Collection whose handler this is 0226 */ 0227 MediaDeviceHandler( QObject *parent ); 0228 0229 /** 0230 * Creates a MediaDeviceTrack based on the latest track struct created as a 0231 * result of a copy to the device, and adds it into the collection to reflect 0232 * that it has been copied. 0233 * @param track The track to add to the collection 0234 */ 0235 void addMediaDeviceTrackToCollection( Meta::MediaDeviceTrackPtr &track ); 0236 0237 /** 0238 * Removes the @param track from all the collection's maps to reflect that 0239 * it has been removed from the collection 0240 * @param track The track to remove from the collection 0241 */ 0242 void removeMediaDeviceTrackFromCollection( Meta::MediaDeviceTrackPtr &track ); 0243 0244 /** 0245 * Uses wrapped libGet methods to fill a track with information from device 0246 * @param track The track from whose associated struct to get the information 0247 * @param destTrack The track that we want to fill with information 0248 */ 0249 void getBasicMediaDeviceTrackInfo( const Meta::MediaDeviceTrackPtr& track, Meta::MediaDeviceTrackPtr destTrack ); 0250 0251 /** 0252 * Uses wrapped libSet methods to fill a track struct of the particular library 0253 * with information from a Meta::Track 0254 * @param srcTrack The track that has the source information 0255 * @param destTrack The track whose associated struct we want to fill with information 0256 */ 0257 void setBasicMediaDeviceTrackInfo( const Meta::TrackPtr &srcTrack, Meta::MediaDeviceTrackPtr destTrack ); 0258 0259 Collections::MediaDeviceCollection *m_memColl; ///< Associated collection 0260 0261 bool m_success; 0262 bool m_copyingthreadsafe; ///< whether or not the handler's method of copying is threadsafe 0263 TitleMap m_titlemap; ///< Map of track titles to tracks, used to detect duplicates 0264 0265 protected Q_SLOTS: 0266 0267 void slotFinalizeTrackCopy( const Meta::TrackPtr & track ); 0268 void slotCopyTrackFailed( const Meta::TrackPtr & track ); 0269 void slotFinalizeTrackRemove( const Meta::TrackPtr & track ); 0270 0271 void slotDatabaseWritten( bool success ); 0272 0273 void enqueueNextCopyThread(); 0274 0275 void slotDeletingHandler(); 0276 0277 private: 0278 0279 /** 0280 * Pulls out meta information (e.g. artist string) 0281 * from track struct, inserts into appropriate map 0282 * (e.g. ArtistMap). Sets track's meta info 0283 * (e.g. artist string) to that extracted from 0284 * track struct's. 0285 * @param track - track being written to 0286 * @param Map - map where meta information is 0287 * associated to appropriate meta pointer 0288 * (e.g. QString artist, ArtistPtr ) 0289 */ 0290 0291 void setupArtistMap( Meta::MediaDeviceTrackPtr track, ArtistMap &artistMap ); 0292 void setupAlbumMap( Meta::MediaDeviceTrackPtr track, AlbumMap &albumMap, ArtistMap &artistMap ); 0293 void setupGenreMap( Meta::MediaDeviceTrackPtr track, GenreMap &genreMap ); 0294 void setupComposerMap( Meta::MediaDeviceTrackPtr track, ComposerMap &composerMap ); 0295 void setupYearMap( Meta::MediaDeviceTrackPtr track, YearMap &yearMap ); 0296 0297 // Misc. Helper Methods 0298 0299 /** 0300 * Tries to create read capability in m_rc 0301 * @return true if m_rc is valid read capability, false otherwise 0302 */ 0303 bool setupReadCapability(); 0304 0305 /** 0306 * Tries to create write capability in m_rc 0307 * @return true if m_wc is valid write capability, false otherwise 0308 */ 0309 bool setupWriteCapability(); 0310 0311 /** 0312 * @return free space on the device 0313 */ 0314 float freeSpace(); 0315 0316 // Observer Methods 0317 0318 /** These methods are called when the metadata of a track has changed. They invoke an MediaDevice DB update */ 0319 void metadataChanged( const Meta::TrackPtr &track ) override; 0320 void metadataChanged( const Meta::ArtistPtr &artist ) override; 0321 void metadataChanged( const Meta::AlbumPtr &album ) override; 0322 void metadataChanged( const Meta::GenrePtr &genre ) override; 0323 void metadataChanged( const Meta::ComposerPtr &composer ) override; 0324 void metadataChanged(const YearPtr &year ) override; 0325 0326 /** 0327 * Handler Variables 0328 */ 0329 0330 Playlists::MediaDeviceUserPlaylistProvider *m_provider; ///< Associated playlist provider 0331 0332 bool m_copyFailed; ///< Indicates whether a copy failed or not 0333 bool m_isCopying; 0334 bool m_isDeleting; 0335 0336 Meta::TrackList m_tracksToCopy; ///< List of tracks left to copy 0337 Meta::TrackList m_tracksCopying; ///< List of tracks currently copying 0338 Meta::TrackList m_tracksToDelete; ///< List of tracks left to delete 0339 0340 int m_numTracksToCopy; ///< The number of tracks left to copy 0341 int m_numTracksToRemove; ///< The number of tracks left to remove 0342 0343 QMap<Meta::TrackPtr, QString> m_tracksFailed; ///< tracks that failed to copy 0344 QHash<Meta::TrackPtr, Meta::MediaDeviceTrackPtr> m_trackSrcDst; ///< points source to destTracks, for completion of addition to collection 0345 0346 QMutex m_mutex; ///< A make certain operations atomic when threads are at play 0347 0348 // Capability-related variables 0349 0350 Handler::PlaylistCapability *m_pc; 0351 Handler::PodcastCapability *m_podcastCapability; 0352 Handler::ReadCapability *m_rc; 0353 Handler::WriteCapability *m_wc; 0354 }; 0355 0356 /** 0357 * The ParseWorkerThread is used to run a full parse of the device's database in 0358 * a separate thread. Once done, it informs the Collection it is done 0359 */ 0360 0361 class ParseWorkerThread : public QObject , public ThreadWeaver::Job 0362 { 0363 Q_OBJECT 0364 public: 0365 /** 0366 * The constructor. 0367 * @param handler The handler 0368 */ 0369 0370 explicit ParseWorkerThread( MediaDeviceHandler* handler); 0371 0372 /** 0373 * The destructor. 0374 */ 0375 0376 ~ParseWorkerThread() override; 0377 0378 /** 0379 * Sees the success variable, which says whether or not the copy completed 0380 successfully. 0381 * @return Whether or not the copy was successful, i.e. m_success 0382 */ 0383 0384 bool success() const override; 0385 0386 Q_SIGNALS: 0387 /** This signal is emitted when this job is being processed by a thread. */ 0388 void started(ThreadWeaver::JobPointer); 0389 /** This signal is emitted when the job has been finished (no matter if it succeeded or not). */ 0390 void done(ThreadWeaver::JobPointer); 0391 /** This job has failed. 0392 * This signal is emitted when success() returns false after the job is executed. */ 0393 void failed(ThreadWeaver::JobPointer); 0394 0395 private Q_SLOTS: 0396 /** 0397 * Is called when the job is done successfully, and simply 0398 * calls Collection's emitCollectionReady() 0399 * @param job The job that was done 0400 */ 0401 0402 void slotDoneSuccess( ThreadWeaver::JobPointer ); 0403 0404 protected: 0405 /** 0406 * Reimplemented, simply runs the parse method. 0407 */ 0408 void run(ThreadWeaver::JobPointer self = QSharedPointer<ThreadWeaver::Job>(), ThreadWeaver::Thread *thread = nullptr) override; 0409 void defaultBegin(const ThreadWeaver::JobPointer& job, ThreadWeaver::Thread *thread) override; 0410 void defaultEnd(const ThreadWeaver::JobPointer& job, ThreadWeaver::Thread *thread) override; 0411 0412 private: 0413 bool m_success; ///< Whether or not the parse was successful 0414 MediaDeviceHandler *m_handler; ///< The handler 0415 }; 0416 0417 /** 0418 * The CopyWorkerThread is used to run a copy operation on a single track in a separate thread. 0419 * Copying is generally done one thread at a time so as to not hurt performance, and because 0420 * many copying mechanisms like that of libmtp can only copy one file at a time. Copying 0421 * methods that are not threadsafe should not use CopyWorkerThread, and should set the 0422 * Handler's m_copyingthreadsafe variable to false in the Handler's constructor. 0423 */ 0424 0425 class CopyWorkerThread : public QObject, public ThreadWeaver::Job 0426 { 0427 Q_OBJECT 0428 public: 0429 /** 0430 * The constructor. 0431 * @param track The source track to copy from 0432 * @param handler The handler 0433 */ 0434 0435 CopyWorkerThread( const Meta::TrackPtr &track, MediaDeviceHandler* handler ); 0436 0437 /** 0438 * The destructor. 0439 */ 0440 0441 ~CopyWorkerThread() override; 0442 0443 /** 0444 * Sets the success variable, which says whether or not the copy completed successfully. 0445 * @return Whether or not the copy was successful, i.e. m_success 0446 */ 0447 0448 bool success() const override; 0449 0450 Q_SIGNALS: 0451 0452 /** 0453 * Is emitted when the job is done successfully 0454 * Parameters: 0455 * The job that was done 0456 * @param track The source track used for the copy 0457 */ 0458 0459 void copyTrackDone( ThreadWeaver::JobPointer, const Meta::TrackPtr& track ); 0460 0461 /** 0462 * Is emitted when the job is done and has failed 0463 * Parameters: 0464 * The job that was done 0465 * @param track The source track used for the copy 0466 */ 0467 void copyTrackFailed( ThreadWeaver::JobPointer, const Meta::TrackPtr& track ); 0468 0469 /** This signal is emitted when this job is being processed by a thread. */ 0470 void started(ThreadWeaver::JobPointer); 0471 /** This signal is emitted when the job has been finished (no matter if it succeeded or not). */ 0472 void done(ThreadWeaver::JobPointer); 0473 /** This job has failed. 0474 * This signal is emitted when success() returns false after the job is executed. */ 0475 void failed(ThreadWeaver::JobPointer); 0476 0477 private Q_SLOTS: 0478 /** 0479 * Is called when the job is done successfully, and simply 0480 * emits copyTrackDone 0481 * @param job The job that was done 0482 */ 0483 0484 void slotDoneSuccess( ThreadWeaver::JobPointer ); 0485 0486 /** 0487 * Is called when the job is done and failed, and simply 0488 * emits copyTrackFailed 0489 * @param job The job that was done 0490 */ 0491 0492 void slotDoneFailed( ThreadWeaver::JobPointer ); 0493 0494 protected: 0495 /** 0496 * Reimplemented, simply runs the copy track method. 0497 */ 0498 void run(ThreadWeaver::JobPointer self = QSharedPointer<ThreadWeaver::Job>(), ThreadWeaver::Thread *thread = nullptr) override; 0499 void defaultBegin(const ThreadWeaver::JobPointer& job, ThreadWeaver::Thread *thread) override; 0500 void defaultEnd(const ThreadWeaver::JobPointer& job, ThreadWeaver::Thread *thread) override; 0501 0502 private: 0503 bool m_success; ///< Whether or not the copy was successful 0504 Meta::TrackPtr m_track; ///< The source track to copy from 0505 MediaDeviceHandler *m_handler; ///< The handler 0506 }; 0507 0508 } 0509 #endif