File indexing completed on 2024-05-19 04:49:27

0001 /****************************************************************************************
0002  * Copyright (c) 2007-2008 Maximilian Kossick <maximilian.kossick@googlemail.com>       *
0003  * Copyright (c) 2008 Jason A. Donenfeld <Jason@zx2c4.com>                              *
0004  * Copyright (c) 2010 Casey Link <unnamedrambler@gmail.com>                             *
0005  *                                                                                      *
0006  * This program is free software; you can redistribute it and/or modify it under        *
0007  * the terms of the GNU General Public License as published by the Free Software        *
0008  * Foundation; either version 2 of the License, or (at your option) any later           *
0009  * version.                                                                             *
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 AMAROK_COLLECTIONLOCATION_H
0020 #define AMAROK_COLLECTIONLOCATION_H
0021 
0022 #include "core/amarokcore_export.h"
0023 #include "core/meta/forward_declarations.h"
0024 #include "core/transcoding/TranscodingConfiguration.h"
0025 
0026 #include <QList>
0027 #include <QObject>
0028 
0029 #include <QUrl>
0030 
0031 namespace Collections {
0032     class Collection;
0033     class QueryMaker;
0034 
0035 /**
0036     This base class defines the methods necessary to allow the copying and moving
0037     of tracks between different collections in a generic way.
0038 
0039     This class should be used as follows in client code:
0040     - select a source and a destination CollectionLocation
0041     - call prepareCopy or prepareMove on the source CollectionLocation
0042     - forget about the rest of the workflow
0043 
0044     Implementations which are writable must reimplement the following methods
0045     - prettyLocation()
0046     - isWritable()
0047     - remove( Meta::Track )
0048     - copyUrlsToCollection( QMap<Meta::TrackPtr, QUrl> )
0049 
0050     Writable collections that are also organizable should reimplement isOrganizable().
0051     Organizable means that the user is able to decide (to varying degrees, the details
0052     depend on the actual collection) where the files are stored in the filesystem (or some
0053     kind of VFS). An example would be the local collection, where the user can select the directory
0054     structure that Amarok uses to store the files. An example for a writable collection that is not
0055     organizable are ipods, where the user has no control about the actual location of the music files
0056     (they are automatically stored in a not human-readable form).
0057 
0058     Implementations which are only readable can reimplement getKIOCopyableUrls( Meta::TrackList )
0059     if it is necessary, but can use the default implementations if possible.
0060 
0061     Implementations that have a string expressable location(s), such as a URL or path on disk
0062     should reimplement actualLocation().
0063 
0064     Implementations that need additional information provided by the user have to implement
0065     showSourceDialog() and showDestinationDialog(), depending on whether the information is required
0066     in the source, the destination, or both.
0067 
0068     The methods will be called in the following order:
0069     startWorkflow (source)
0070     showSourceDialog (source) (reimplementable)
0071     slotShowSourceDialogDone (source)
0072     slotPrepareOperation (destination)
0073     showDestinationDialog (destination) (reimplementable)
0074     slotShowDestinationDialogDone (destination)
0075     slotOperationPrepared (source)
0076     getKIOCopyableUrls (source) (reimplementable)
0077     slotGetKIOCopyableUrlsDone (source)
0078     slotStartCopy (destination)
0079     copyUrlsToCollection (destination) (reimplementable)
0080     slotCopyOperationFinished (destination)
0081     slotFinishCopy (source)
0082 
0083     To provide removal ability, it is required to reimplement removeUrlsFromCollection,
0084     and this function must call slotRemoveOperationFinished() when it is done.  Optionally,
0085     showRemoveDialog can be reimplemented to customize the warning displayed before a removal,
0086     and this function must call slotShowRemoveDialogDone when finished.
0087 
0088     The methods for remove will be called in the following order:
0089     startRemoveWorkflow
0090     showRemoveDialog (reimplementable)
0091     slotShowRemoveDialogDone
0092     slotStartRemove
0093     removeUrlsFromCollection (reimplementable)
0094     slotRemoveOperationFinished
0095     slotFinishRemove
0096 */
0097 
0098 class AMAROKCORE_EXPORT CollectionLocation : public QObject
0099 {
0100     Q_OBJECT
0101 
0102     //testing only do not use these properties in anything but tests
0103     Q_PROPERTY( bool removeSources
0104                 READ getRemoveSources
0105                 WRITE setRemoveSources
0106                 DESIGNABLE false
0107                 SCRIPTABLE false )
0108 
0109     public:
0110         CollectionLocation();
0111         explicit CollectionLocation( Collections::Collection *parentCollection );
0112          ~CollectionLocation() override;
0113 
0114         /**
0115             Returns a pointer to the collection location's corresponding collection.
0116             @return a pointer to the collection location's corresponding collection
0117          */
0118         virtual Collections::Collection *collection() const;
0119 
0120         /**
0121             a displayable string representation of the collection location. use the return
0122             value of this method to display the collection location to the user.
0123             @return a string representation of the collection location
0124         */
0125         virtual QString prettyLocation() const;
0126 
0127         /**
0128             Returns a list of machine usable strings representing the collection location.
0129             For example, a local collection would return a list of paths where tracks are
0130             stored, while an Ampache collection would return a list with one string
0131             containing the URL of an ampache server. An iPod collection and a MTP device
0132             collection are examples of collections that do not need to reimplement this method.
0133         */
0134         virtual QStringList actualLocation() const;
0135 
0136         /**
0137             Returns whether the collection location is writable or not. For example, a
0138             local collection or an ipod collection would return true, a daap collection
0139             or a service collection false. The value returned by this method indicates
0140             if it is possible to copy tracks to the collection, and if it is generally
0141             possible to remove/delete files from the collection.
0142             @return @c true if the collection location is writable
0143             @return @c false if the collection location is not writable
0144         */
0145         virtual bool isWritable() const;
0146 
0147         /**
0148            Returns whether the collection is organizable or not. Organizable collections
0149            allow move operations where the source and destination collection are the same.
0150            @return @c true if the collection location is organizable, false otherwise
0151          */
0152         virtual bool isOrganizable() const;
0153 
0154         /**
0155            Convenience method for copying a single track.
0156            @see prepareCopy( Meta::TrackList, CollectionLocation* )
0157         */
0158         void prepareCopy( const Meta::TrackPtr &track, CollectionLocation *destination );
0159         /**
0160            Schedule copying of @p tracks to collection location @p destination.
0161            This method takes ownership of the @p destination, you may not reference
0162            or delete it after this call. This method returns immediately and the actual
0163            copy is performed in the event loop and/or another thread.
0164            @param tracks tracks
0165            @param destination the collection location destination
0166         */
0167         void prepareCopy( const Meta::TrackList &tracks, CollectionLocation *destination );
0168         /**
0169            Convenience method for copying tracks based on QueryMaker results,
0170            takes ownership of the @p qm.
0171            @param qm the QueryMaker query
0172            @param destination the collection destination
0173            @see prepareCopy( Meta::TrackList, CollectionLocation* )
0174         */
0175         void prepareCopy( Collections::QueryMaker *qm, CollectionLocation *destination );
0176 
0177         /**
0178          * Convenience method for moving a single track.
0179          * @see prepareMove( Meta::TrackList, CollectionLocation* )
0180          */
0181         void prepareMove( const Meta::TrackPtr &track, CollectionLocation *destination );
0182         /**
0183            Schedule moving of @p tracks to collection location @p destination.
0184            This method takes ownership of the @p destination, you may not reference
0185            or delete it after this call. This method returns immediately and the actual
0186            move is performed in the event loop and/or another thread.
0187            @param tracks tracks
0188            @param destination the collection location destination
0189         */
0190         void prepareMove( const Meta::TrackList &tracks, CollectionLocation *destination );
0191         /**
0192            Convenience method for moving tracks based on QueryMaker results,
0193            takes ownership of the @p qm.
0194            @param qm the QueryMaker query
0195            @param destination the collection destination
0196            @see prepareMove( Meta::TrackList, CollectionLocation* )
0197         */
0198         void prepareMove( Collections::QueryMaker *qm, CollectionLocation *destination );
0199 
0200         /**
0201            Starts workflow for removing tracks.
0202          */
0203         void prepareRemove( const Meta::TrackList &tracks );
0204         /**
0205            Convenience method for removing tracks selected by QueryMaker,
0206            takes ownership of the @p qm.
0207            @param qm the QueryMaker query
0208            @see prepareRemove( Meta::TrackList )
0209          */
0210         void prepareRemove( Collections::QueryMaker *qm );
0211 
0212         /**
0213          * Adds or merges a track to the collection (not to the disk)
0214          * Inserts a set of TrackPtrs directly into the database without needing to actual move any files
0215          * @param track track
0216          * @param path path
0217          * This is a hack required by the DatabaseImporter
0218          * TODO: Remove this hack
0219          * @return true if the database entry was inserted, false otherwise
0220          */
0221         virtual bool insert( const Meta::TrackPtr &track, const QString &path );
0222 
0223         /**
0224           explicitly inform the source collection of successful transfer.
0225           The source collection will only remove files (if necessary)
0226           for which this method was called.
0227           @param track track
0228           */
0229         void transferSuccessful( const Meta::TrackPtr &track );
0230 
0231         /**
0232         * tells the source location that an error occurred during the transfer of the file
0233         * @param track track
0234         * @param error error
0235         */
0236         virtual void transferError( const Meta::TrackPtr &track, const QString &error );
0237 
0238     Q_SIGNALS:
0239         void startCopy( const QMap<Meta::TrackPtr, QUrl> &sources,
0240                         const Transcoding::Configuration & );
0241         void finishCopy();
0242         void startRemove();
0243         void finishRemove();
0244         void prepareOperation( const Meta::TrackList &tracks, bool removeSources,
0245                                const Transcoding::Configuration & );
0246         void operationPrepared();
0247         void aborted();
0248 
0249     protected:
0250         /**
0251          * aborts the workflow
0252          */
0253         void abort();
0254 
0255         /**
0256          * allows the destination location to access the source CollectionLocation.
0257          * note: subclasses do not take ownership  of the pointer
0258          */
0259         CollectionLocation* source() const;
0260 
0261         /**
0262           * allows the source location to access the destination CollectionLocation.
0263           * Pointer may be null!
0264           * note: subclasses do not take ownership of the pointer
0265           */
0266         CollectionLocation* destination() const;
0267 
0268         /**
0269             this method is called on the source location, and should return a list of urls
0270             which the destination location can copy using KIO. You must call
0271             slotGetKIOCopyableUrlsDone( QMap<Meta::TrackPtr, QUrl> ) after retrieving the
0272             urls. The order of urls passed to that method has to be the same as the order
0273             of the tracks passed to this method.
0274         */
0275         virtual void getKIOCopyableUrls( const Meta::TrackList &tracks );
0276         /**
0277             this method is called on the destination. reimplement it if your implementation
0278             is writable. You must call slotCopyOperationFinished() when you are done copying
0279             the files.
0280 
0281             Before calling slotCopyOperationFinished(), you should call
0282             source()->transferSuccessful() for every source track that was for sure
0283             successfully copied to destination collection. Only such marked tracks are
0284             then removed in case of a "move" action.
0285         */
0286         virtual void copyUrlsToCollection( const QMap<Meta::TrackPtr, QUrl> &sources,
0287                                            const Transcoding::Configuration &configuration );
0288 
0289         /**
0290            this method is called on the collection you want to remove tracks from.  it must
0291            be reimplemented if your collection is writable and you wish to implement
0292            removing tracks. You must call slotRemoveOperationFinished() when you are done
0293            removing the files.
0294 
0295            Before calling slotRemoveOperationFinished(), you should call transferSuccessful()
0296            for every track that was successfully deleted. CollectionLocation then scans
0297            directories of such tracks and allows user to remove empty ones.
0298         */
0299         virtual void removeUrlsFromCollection( const Meta::TrackList &sources );
0300 
0301         /**
0302          * this method is called on the source. It allows the source CollectionLocation to
0303          * show a dialog. Classes that reimplement this method must call
0304          * slotShowSourceDialogDone() after they have acquired all necessary information from the user.
0305          *
0306          * Default implementation calls getDestinationTranscodingConfig() which may ask
0307          * user. If you reimplement this you may (or not) call this base method instead
0308          * of calling slotShowDestinationDialogDone() to support transcoding.
0309          */
0310         virtual void showSourceDialog( const Meta::TrackList &tracks, bool removeSources );
0311 
0312         /**
0313          * Get transcoding configuration to use when transferring tracks to destination.
0314          * If destination collection doesn't support transcoding, JUST_COPY configuration
0315          * is returned, otherwise preferred configuration is read or user is asked.
0316          * Returns invalid configuration in case user has hit cancel or closed the dialog.
0317          *
0318          * This method is meant to be called by source collection.
0319          */
0320         virtual Transcoding::Configuration getDestinationTranscodingConfig();
0321 
0322         /**
0323          * This method is called on the destination. It allows the destination
0324          * CollectionLocation to show a dialog. Classes that reimplement this method
0325          * must call slotShowDestinationDialogDone() after they have acquired all necessary
0326          * information from the user.
0327          *
0328          * Default implementation calls setGoingToRemoveSources( removeSources ) so that
0329          * isGoingToRemoveSources() is available on destination, too and then calls
0330          * slotShowDestinationDialogDone()
0331          */
0332         virtual void showDestinationDialog( const Meta::TrackList &tracks,
0333                                             bool removeSources,
0334                                             const Transcoding::Configuration &configuration );
0335 
0336         /**
0337          * this methods allows the collection to show a warning dialog before tracks are removed,
0338          * rather than using the default provided.  Classes that reimplement this method must call
0339          * slotShowRemoveDialogDone() after they are finished.
0340         */
0341 
0342         virtual void showRemoveDialog( const Meta::TrackList &tracks );
0343 
0344         /**
0345          * Get nice localised string describing the current operation based on transcoding
0346          * configuration and isGoingToRemoveSources(); meant to be called by destination
0347          * collection.
0348          *
0349          * @return "Copy Tracks", "Transcode and Organize Tracks" etc.
0350          */
0351         QString operationText( const Transcoding::Configuration &configuration );
0352 
0353         /**
0354          * Get nice localised string that can be used as progress bar text for the current
0355          * operation; meant to be called by the destination collection.
0356          *
0357          * @param configuration the transcoding configuration
0358          * @param trackCount number of tracks in the transfer
0359          * @param destinationName pretty localised name of the destination collection;
0360          *        prettyLocation() is used if the string is empty or not specified
0361          *
0362          * @return "Transcoding and moving <trackCount> tracks to <destinationName>" etc.
0363          */
0364         QString operationInProgressText( const Transcoding::Configuration &configuration,
0365                                          int trackCount, QString destinationName = QString() );
0366 
0367         /**
0368         * Sets or gets whether some source files may be removed
0369         */
0370         virtual bool isGoingToRemoveSources() const;
0371         virtual void setGoingToRemoveSources( bool removeSources );
0372 
0373         /**
0374         * Sets or gets whether to stifle the removal confirmation
0375         */
0376         virtual bool isHidingRemoveConfirm() const;
0377         virtual void setHidingRemoveConfirm( bool hideRemoveConfirm );
0378 
0379     protected Q_SLOTS:
0380         /**
0381          * this slot has to be called from getKIOCopyableUrls( Meta::TrackList )
0382          * Please note: the order of urls in the argument has to be the same as in the
0383          * tracklist
0384          */
0385         void slotGetKIOCopyableUrlsDone( const QMap<Meta::TrackPtr, QUrl> &sources );
0386         void slotCopyOperationFinished();
0387         void slotRemoveOperationFinished();
0388         void slotShowSourceDialogDone();
0389         void slotShowRemoveDialogDone();
0390         void slotShowDestinationDialogDone();
0391 
0392     private Q_SLOTS:
0393         void slotShowSourceDialog();  // trick to show dialog in next mainloop iteration
0394         void slotPrepareOperation( const Meta::TrackList &tracks, bool removeSources,
0395                                    const Transcoding::Configuration &configuration );
0396         void slotOperationPrepared();
0397         void slotStartCopy( const QMap<Meta::TrackPtr, QUrl> &sources,
0398                             const Transcoding::Configuration &configuration );
0399         void slotFinishCopy();
0400         void slotStartRemove();
0401         void slotFinishRemove();
0402         void slotAborted();
0403         void resultReady( const Meta::TrackList &tracks );
0404         void queryDone();
0405 
0406     private:
0407         void setupConnections();
0408         void setupRemoveConnections();
0409         void startWorkflow( const Meta::TrackList &tracks, bool removeSources );
0410         void startRemoveWorkflow( const Meta::TrackList &tracks );
0411         void removeSourceTracks( const Meta::TrackList &tracks );
0412         void setSource( CollectionLocation *source );
0413 
0414         //only used in the source CollectionLocation
0415         CollectionLocation *m_destination;
0416         //only used in destination CollectionLocation
0417         CollectionLocation *m_source;
0418 
0419         Meta::TrackList getSourceTracks() const { return m_sourceTracks; }
0420         void setSourceTracks( const Meta::TrackList &tracks ) { m_sourceTracks = tracks; }
0421         Meta::TrackList m_sourceTracks;
0422 
0423         Collections::Collection *m_parentCollection;
0424 
0425         bool getRemoveSources() const { return m_removeSources; }
0426         void setRemoveSources( bool removeSources ) { m_removeSources = removeSources; }
0427         bool m_removeSources;
0428         bool m_isRemoveAction;
0429         bool m_noRemoveConfirmation;
0430         Transcoding::Configuration m_transcodingConfiguration;
0431         //used by the source collection to store the tracks that were successfully
0432         //copied by the destination and can be removed as part of a move
0433         Meta::TrackList m_tracksSuccessfullyTransferred;
0434         QMap<Meta::TrackPtr, QString> m_tracksWithError;
0435 };
0436 
0437 } //namespace Collections
0438 
0439 #endif