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 #define DEBUG_PREFIX "CollectionLocation"
0020 
0021 #include "CollectionLocation.h"
0022 
0023 #include "core/capabilities/TranscodeCapability.h"
0024 #include "core/collections/Collection.h"
0025 #include "core/collections/CollectionLocationDelegate.h"
0026 #include "core/collections/QueryMaker.h"
0027 #include "core/meta/Meta.h"
0028 #include "core/support/Components.h"
0029 #include "core/support/Debug.h"
0030 #include "core/transcoding/TranscodingConfiguration.h"
0031 #include "core/transcoding/TranscodingController.h"
0032 
0033 #include <KLocalizedString>
0034 #include <QDir>
0035 #include <QTimer>
0036 
0037 using namespace Collections;
0038 
0039 CollectionLocation::CollectionLocation()
0040     :QObject()
0041     , m_destination( nullptr )
0042     , m_source( nullptr )
0043     , m_sourceTracks()
0044     , m_parentCollection( nullptr )
0045     , m_removeSources( false )
0046     , m_isRemoveAction( false )
0047     , m_noRemoveConfirmation( false )
0048     , m_transcodingConfiguration( Transcoding::JUST_COPY )
0049 {
0050     //nothing to do
0051 }
0052 
0053 CollectionLocation::CollectionLocation( Collections::Collection *parentCollection)
0054     :QObject()
0055     , m_destination( nullptr )
0056     , m_source( nullptr )
0057     , m_sourceTracks()
0058     , m_parentCollection( parentCollection )
0059     , m_removeSources( false )
0060     , m_isRemoveAction( false )
0061     , m_noRemoveConfirmation( false )
0062     , m_transcodingConfiguration( Transcoding::JUST_COPY )
0063 {
0064     //nothing to do
0065 }
0066 
0067 CollectionLocation::~CollectionLocation()
0068 {
0069     //nothing to do
0070 }
0071 
0072 Collections::Collection*
0073 CollectionLocation::collection() const
0074 {
0075     return m_parentCollection;
0076 }
0077 
0078 QString
0079 CollectionLocation::prettyLocation() const
0080 {
0081     return QString();
0082 }
0083 
0084 QStringList
0085 CollectionLocation::actualLocation() const
0086 {
0087     return QStringList();
0088 }
0089 
0090 bool
0091 CollectionLocation::isWritable() const
0092 {
0093     return false;
0094 }
0095 
0096 bool
0097 CollectionLocation::isOrganizable() const
0098 {
0099     return false;
0100 }
0101 
0102 void
0103 CollectionLocation::prepareCopy( const Meta::TrackPtr &track, CollectionLocation *destination )
0104 {
0105     Q_ASSERT(destination);
0106     Meta::TrackList list;
0107     list.append( track );
0108     prepareCopy( list, destination );
0109 }
0110 
0111 void
0112 CollectionLocation::prepareCopy( const Meta::TrackList &tracks, CollectionLocation *destination )
0113 {
0114     if( !destination->isWritable() )
0115     {
0116         CollectionLocationDelegate *delegate = Amarok::Components::collectionLocationDelegate();
0117         delegate->notWriteable( this );
0118         destination->deleteLater();
0119         deleteLater();
0120         return;
0121     }
0122 
0123     m_destination = destination;
0124     m_destination->setSource( this );
0125     startWorkflow( tracks, false );
0126 }
0127 
0128 void
0129 CollectionLocation::prepareCopy( Collections::QueryMaker *qm, CollectionLocation *destination )
0130 {
0131     DEBUG_BLOCK
0132     if( !destination->isWritable() )
0133     {
0134         CollectionLocationDelegate *delegate = Amarok::Components::collectionLocationDelegate();
0135         delegate->notWriteable( this );
0136         destination->deleteLater();
0137         qm->deleteLater();
0138         deleteLater();
0139         return;
0140     }
0141     m_destination = destination;
0142     m_removeSources = false;
0143     m_isRemoveAction = false;
0144     connect( qm, &Collections::QueryMaker::newTracksReady, this, &CollectionLocation::resultReady );
0145     connect( qm, &Collections::QueryMaker::queryDone, this, &CollectionLocation::queryDone );
0146     qm->setQueryType( Collections::QueryMaker::Track );
0147     qm->run();
0148 }
0149 
0150 void
0151 CollectionLocation::prepareMove( const Meta::TrackPtr &track, CollectionLocation *destination )
0152 {
0153     Meta::TrackList list;
0154     list.append( track );
0155     prepareMove( list, destination );
0156 }
0157 
0158 void
0159 CollectionLocation::prepareMove( const Meta::TrackList &tracks, CollectionLocation *destination )
0160 {
0161     DEBUG_BLOCK
0162     if( !destination->isWritable() )
0163     {
0164         CollectionLocationDelegate *delegate = Amarok::Components::collectionLocationDelegate();
0165         delegate->notWriteable( this );
0166         destination->deleteLater();
0167         deleteLater();
0168         return;
0169     }
0170 
0171     m_destination = destination;
0172     m_destination->setSource( this );
0173     startWorkflow( tracks, true );
0174 }
0175 
0176 void
0177 CollectionLocation::prepareMove( Collections::QueryMaker *qm, CollectionLocation *destination )
0178 {
0179     DEBUG_BLOCK
0180     if( !destination->isWritable() )
0181     {
0182         Collections::CollectionLocationDelegate *delegate = Amarok::Components::collectionLocationDelegate();
0183         delegate->notWriteable( this );
0184         destination->deleteLater();
0185         qm->deleteLater();
0186         deleteLater();
0187         return;
0188     }
0189     m_destination = destination;
0190     m_isRemoveAction = false;
0191     m_removeSources = true;
0192     connect( qm, &Collections::QueryMaker::newTracksReady, this, &CollectionLocation::resultReady );
0193     connect( qm, &Collections::QueryMaker::queryDone, this, &CollectionLocation::queryDone );
0194     qm->setQueryType( Collections::QueryMaker::Track );
0195     qm->run();
0196 }
0197 
0198 void
0199 CollectionLocation::prepareRemove( const Meta::TrackList &tracks )
0200 {
0201     DEBUG_BLOCK
0202     if( !isWritable() )
0203     {
0204         Collections::CollectionLocationDelegate *delegate = Amarok::Components::collectionLocationDelegate();
0205         delegate->notWriteable( this );
0206         deleteLater();
0207         return;
0208     }
0209     startRemoveWorkflow( tracks );
0210 }
0211 
0212 void
0213 CollectionLocation::prepareRemove( Collections::QueryMaker *qm )
0214 {
0215     DEBUG_BLOCK
0216     if( !isWritable() )
0217     {
0218         Collections::CollectionLocationDelegate *delegate = Amarok::Components::collectionLocationDelegate();
0219         delegate->notWriteable( this );
0220         qm->deleteLater();
0221         deleteLater();
0222         return;
0223     }
0224 
0225     m_isRemoveAction = true;
0226     m_removeSources = false;
0227 
0228     connect( qm, &Collections::QueryMaker::newTracksReady, this, &CollectionLocation::resultReady );
0229     connect( qm, &Collections::QueryMaker::queryDone, this, &CollectionLocation::queryDone );
0230     qm->setQueryType( Collections::QueryMaker::Track );
0231     qm->run();
0232 }
0233 
0234 bool
0235 CollectionLocation::insert( const Meta::TrackPtr &track, const QString &url )
0236 {
0237     Q_UNUSED( track )
0238     Q_UNUSED( url )
0239     warning() << __PRETTY_FUNCTION__ << "Don't call this method. It exists only because"
0240               << "database importers need it. Call prepareCopy() instead.";
0241     return false;
0242 }
0243 
0244 void
0245 CollectionLocation::abort()
0246 {
0247     Q_EMIT aborted();
0248 }
0249 
0250 void
0251 CollectionLocation::getKIOCopyableUrls( const Meta::TrackList &tracks )
0252 {
0253     DEBUG_BLOCK
0254     QMap<Meta::TrackPtr, QUrl> urls;
0255     foreach( Meta::TrackPtr track, tracks )
0256     {
0257         if( track->isPlayable() )
0258         {
0259             urls.insert( track, track->playableUrl() );
0260             debug() << "adding url " << track->playableUrl();
0261         }
0262     }
0263 
0264     slotGetKIOCopyableUrlsDone( urls );
0265 }
0266 
0267 void
0268 CollectionLocation::copyUrlsToCollection( const QMap<Meta::TrackPtr, QUrl> &sources,
0269                                           const Transcoding::Configuration &configuration )
0270 {
0271     DEBUG_BLOCK
0272     //reimplement in implementations which are writable
0273     Q_UNUSED( sources )
0274     Q_UNUSED( configuration )
0275     slotCopyOperationFinished();
0276 }
0277 
0278 void
0279 CollectionLocation::removeUrlsFromCollection( const Meta::TrackList &sources )
0280 {
0281     DEBUG_BLOCK
0282     //reimplement in implementations which are writable
0283     Q_UNUSED( sources )
0284     slotRemoveOperationFinished();
0285 }
0286 
0287 void
0288 CollectionLocation::showSourceDialog( const Meta::TrackList &tracks, bool removeSources )
0289 {
0290     Q_UNUSED( tracks )
0291     Q_UNUSED( removeSources )
0292 
0293     m_transcodingConfiguration = getDestinationTranscodingConfig();
0294     if( m_transcodingConfiguration.isValid() )
0295         slotShowSourceDialogDone();
0296     else
0297         abort();
0298 }
0299 
0300 Transcoding::Configuration
0301 CollectionLocation::getDestinationTranscodingConfig()
0302 {
0303     Transcoding::Configuration configuration( Transcoding::JUST_COPY );
0304     Collection *destCollection = destination() ? destination()->collection() : nullptr;
0305     if( !destCollection )
0306         return configuration;
0307     if( !destCollection->has<Capabilities::TranscodeCapability>() )
0308         return configuration;
0309     QScopedPointer<Capabilities::TranscodeCapability> tc(
0310         destCollection->create<Capabilities::TranscodeCapability>() );
0311     if( !tc )
0312         return configuration;
0313 
0314     Transcoding::Controller* tcC = Amarok::Components::transcodingController();
0315     QSet<Transcoding::Encoder> availableEncoders;
0316     if( tcC )
0317         availableEncoders = tcC->availableEncoders();
0318 
0319     Transcoding::Configuration saved = tc->savedConfiguration();
0320     if( saved.isValid() && ( saved.isJustCopy() || availableEncoders.contains( saved.encoder() ) ) )
0321         return saved;
0322     // saved configuration was not available or was invalid, ask user
0323 
0324     CollectionLocationDelegate *delegate = Amarok::Components::collectionLocationDelegate();
0325     bool saveConfiguration = false;
0326     CollectionLocationDelegate::OperationType operation = CollectionLocationDelegate::Copy;
0327     if( isGoingToRemoveSources() )
0328         operation = CollectionLocationDelegate::Move;
0329     if( collection() && collection() == destination()->collection() )
0330         operation = CollectionLocationDelegate::Move; // organizing
0331     configuration = delegate->transcode( tc->playableFileTypes(), &saveConfiguration,
0332                                          operation, destCollection->prettyName(),
0333                                          saved );
0334     if( configuration.isValid() )
0335     {
0336         if( saveConfiguration )
0337             tc->setSavedConfiguration( configuration );
0338         else //save the trackSelection value for restore anyway
0339             tc->setSavedConfiguration( Transcoding::Configuration( Transcoding::INVALID,
0340                                         configuration.trackSelection() ) );
0341     }
0342     return configuration; // may be invalid, it means user has hit cancel
0343 }
0344 
0345 void
0346 CollectionLocation::showDestinationDialog( const Meta::TrackList &tracks,
0347                                            bool removeSources,
0348                                            const Transcoding::Configuration &configuration )
0349 {
0350     Q_UNUSED( tracks )
0351     Q_UNUSED( configuration )
0352     setGoingToRemoveSources( removeSources );
0353     slotShowDestinationDialogDone();
0354 }
0355 
0356 void
0357 CollectionLocation::showRemoveDialog( const Meta::TrackList &tracks )
0358 {
0359     DEBUG_BLOCK
0360 
0361     if( !isHidingRemoveConfirm() )
0362     {
0363         Collections::CollectionLocationDelegate *delegate = Amarok::Components::collectionLocationDelegate();
0364 
0365         const bool del = delegate->reallyDelete( this, tracks );
0366 
0367         if( !del )
0368             slotFinishRemove();
0369         else
0370             slotShowRemoveDialogDone();
0371     } else
0372         slotShowRemoveDialogDone();
0373 }
0374 
0375 QString
0376 CollectionLocation::operationText( const Transcoding::Configuration &configuration )
0377 {
0378     if( source()->collection() == collection() )
0379     {
0380         if( configuration.isJustCopy() )
0381             return i18n( "Organize tracks" );
0382         else
0383             return i18n( "Transcode and organize tracks" );
0384     }
0385     if( isGoingToRemoveSources() )
0386     {
0387         if( configuration.isJustCopy() )
0388             return i18n( "Move tracks" );
0389         else
0390             return i18n( "Transcode and move tracks" );
0391     }
0392     else
0393     {
0394         if( configuration.isJustCopy() )
0395             return i18n( "Copy tracks" );
0396         else
0397             return i18n( "Transcode and copy tracks" );
0398     }
0399 }
0400 
0401 QString
0402 CollectionLocation::operationInProgressText( const Transcoding::Configuration &configuration,
0403                                                 int trackCount, QString destinationName )
0404 {
0405     if( destinationName.isEmpty() )
0406         destinationName = prettyLocation();
0407     if( source()->collection() == collection() )
0408     {
0409         if( configuration.isJustCopy() )
0410             return i18np( "Organizing one track",
0411                           "Organizing %1 tracks", trackCount );
0412         else
0413             return i18np( "Transcoding and organizing one track",
0414                           "Transcoding and organizing %1 tracks", trackCount );
0415     }
0416     if( isGoingToRemoveSources() )
0417     {
0418         if( configuration.isJustCopy() )
0419             return i18np( "Moving one track to %2",
0420                           "Moving %1 tracks to %2", trackCount, destinationName );
0421         else
0422             return i18np( "Transcoding and moving one track to %2",
0423                           "Transcoding and moving %1 tracks to %2", trackCount, destinationName );
0424     }
0425     else
0426     {
0427         if( configuration.isJustCopy() )
0428             return i18np( "Copying one track to %2",
0429                           "Copying %1 tracks to %2", trackCount, destinationName );
0430         else
0431             return i18np( "Transcoding and copying one track to %2",
0432                           "Transcoding and copying %1 tracks to %2", trackCount, destinationName );
0433     }
0434 }
0435 
0436 void
0437 CollectionLocation::slotGetKIOCopyableUrlsDone( const QMap<Meta::TrackPtr, QUrl> &sources )
0438 {
0439     Q_EMIT startCopy( sources, m_transcodingConfiguration );
0440 }
0441 
0442 void
0443 CollectionLocation::slotCopyOperationFinished()
0444 {
0445     Q_EMIT finishCopy();
0446 }
0447 
0448 void
0449 CollectionLocation::slotRemoveOperationFinished()
0450 {
0451     Q_EMIT finishRemove();
0452 }
0453 
0454 void
0455 CollectionLocation::slotShowSourceDialogDone()
0456 {
0457     Q_EMIT prepareOperation( m_sourceTracks, m_removeSources, m_transcodingConfiguration );
0458 }
0459 
0460 void
0461 CollectionLocation::slotShowDestinationDialogDone()
0462 {
0463     Q_EMIT operationPrepared();
0464 }
0465 
0466 void
0467 CollectionLocation::slotShowRemoveDialogDone()
0468 {
0469     Q_EMIT startRemove();
0470 }
0471 
0472 void
0473 CollectionLocation::slotShowSourceDialog()
0474 {
0475     showSourceDialog( m_sourceTracks, m_removeSources );
0476 }
0477 
0478 void
0479 CollectionLocation::slotPrepareOperation( const Meta::TrackList &tracks, bool removeSources,
0480                                           const Transcoding::Configuration &configuration )
0481 {
0482     m_removeSources = removeSources;
0483     showDestinationDialog( tracks, removeSources, configuration );
0484 }
0485 
0486 void
0487 CollectionLocation::slotOperationPrepared()
0488 {
0489     getKIOCopyableUrls( m_sourceTracks );
0490 }
0491 
0492 void
0493 CollectionLocation::slotStartCopy( const QMap<Meta::TrackPtr, QUrl> &sources,
0494                                    const Transcoding::Configuration &configuration )
0495 {
0496     DEBUG_BLOCK
0497     copyUrlsToCollection( sources, configuration );
0498 }
0499 
0500 void
0501 CollectionLocation::slotFinishCopy()
0502 {
0503     DEBUG_BLOCK
0504     if( m_removeSources )
0505     {
0506         removeSourceTracks( m_tracksSuccessfullyTransferred );
0507         m_sourceTracks.clear();
0508         m_tracksSuccessfullyTransferred.clear();
0509     }
0510     else
0511     {
0512         m_sourceTracks.clear();
0513         m_tracksSuccessfullyTransferred.clear();
0514 
0515         if( m_destination )
0516             m_destination->deleteLater();
0517         m_destination = nullptr;
0518         this->deleteLater();
0519     }
0520 }
0521 
0522 void
0523 CollectionLocation::slotStartRemove()
0524 {
0525     DEBUG_BLOCK
0526     removeUrlsFromCollection( m_sourceTracks );
0527 }
0528 
0529 void
0530 CollectionLocation::slotFinishRemove()
0531 {
0532     DEBUG_BLOCK
0533 
0534     Collections::CollectionLocationDelegate *delegate = Amarok::Components::collectionLocationDelegate();
0535     if( m_tracksWithError.size() > 0 )
0536     {
0537         delegate->errorDeleting( this, m_tracksWithError.keys() );
0538         m_tracksWithError.clear();
0539     }
0540 
0541     QStringList dirsToRemove;
0542     debug() << "remove finished updating";
0543     foreach( Meta::TrackPtr track, m_tracksSuccessfullyTransferred )
0544     {
0545         if(!track)
0546             continue;
0547 
0548         if( track->playableUrl().isLocalFile() )
0549             dirsToRemove.append( track->playableUrl().adjusted( QUrl::RemoveFilename ).path() );
0550     }
0551 
0552     if( !dirsToRemove.isEmpty() && delegate->deleteEmptyDirs( this ) )
0553     {
0554         debug() << "Removing empty directories";
0555         dirsToRemove.removeDuplicates();
0556         dirsToRemove.sort();
0557         while( !dirsToRemove.isEmpty() )
0558         {
0559             QDir dir( dirsToRemove.takeLast() );
0560             if( !dir.exists() )
0561                 continue;
0562 
0563             dir.setFilter( QDir::NoDotAndDotDot );
0564             while( !dir.isRoot() && dir.isEmpty() )
0565             {
0566                 const QString name = dir.dirName();
0567                 dir.cdUp();
0568                 if( !dir.rmdir( name ) )
0569                 {
0570                     debug() << "Unable to remove " << name;
0571                     break;
0572                 }
0573             }
0574         }
0575     }
0576 
0577     m_tracksSuccessfullyTransferred.clear();
0578     m_sourceTracks.clear();
0579     this->deleteLater();
0580 }
0581 
0582 void
0583 CollectionLocation::slotAborted()
0584 {
0585     m_destination->deleteLater();
0586     deleteLater();
0587 }
0588 
0589 void
0590 CollectionLocation::resultReady( const Meta::TrackList &tracks )
0591 {
0592     m_sourceTracks << tracks;
0593 }
0594 
0595 void
0596 CollectionLocation::queryDone()
0597 {
0598     DEBUG_BLOCK
0599     QObject *obj = sender();
0600     if( obj )
0601     {
0602         obj->deleteLater();
0603     }
0604     if( m_isRemoveAction )
0605     {
0606         debug() << "we were about to remove something, lets proceed";
0607         prepareRemove( m_sourceTracks );
0608     }
0609     else if( m_removeSources )
0610     {
0611         debug() << "we were about to move something, lets proceed";
0612         prepareMove( m_sourceTracks, m_destination );
0613     }
0614     else
0615     {
0616         debug() << "we were about to copy something, lets proceed";
0617         prepareCopy( m_sourceTracks, m_destination );
0618     }
0619 }
0620 
0621 void
0622 CollectionLocation::setupConnections()
0623 {
0624     connect( this, &CollectionLocation::prepareOperation,
0625              m_destination, &Collections::CollectionLocation::slotPrepareOperation );
0626     connect( m_destination, &Collections::CollectionLocation::operationPrepared,
0627              this, &CollectionLocation::slotOperationPrepared );
0628     connect( this, &CollectionLocation::startCopy,
0629              m_destination, &Collections::CollectionLocation::slotStartCopy );
0630     connect( m_destination, &Collections::CollectionLocation::finishCopy,
0631              this, &CollectionLocation::slotFinishCopy );
0632     connect( this, &CollectionLocation::aborted, this, &CollectionLocation::slotAborted );
0633     connect( m_destination, &Collections::CollectionLocation::aborted, this, &CollectionLocation::slotAborted );
0634 }
0635 
0636 void
0637 CollectionLocation::setupRemoveConnections()
0638 {
0639     connect( this, &CollectionLocation::aborted,
0640              this, &CollectionLocation::slotAborted );
0641     connect( this, &CollectionLocation::startRemove,
0642              this, &CollectionLocation::slotStartRemove );
0643     connect( this, &CollectionLocation::finishRemove,
0644              this, &CollectionLocation::slotFinishRemove );
0645 }
0646 
0647 void
0648 CollectionLocation::startWorkflow( const Meta::TrackList &tracks, bool removeSources )
0649 {
0650     DEBUG_BLOCK
0651     m_removeSources = removeSources;
0652     m_sourceTracks = tracks;
0653     setupConnections();
0654     if( tracks.size() <= 0 )
0655         abort();
0656     else
0657         // show dialog in next mainloop iteration so that prepare[Something]() returns quickly
0658         QTimer::singleShot( 0, this, &CollectionLocation::slotShowSourceDialog );
0659 }
0660 
0661 void
0662 CollectionLocation::startRemoveWorkflow( const Meta::TrackList &tracks )
0663 {
0664     DEBUG_BLOCK
0665     m_sourceTracks = tracks;
0666     setupRemoveConnections();
0667     if( tracks.isEmpty() )
0668         abort();
0669     else
0670         showRemoveDialog( tracks );
0671 }
0672 
0673 void
0674 CollectionLocation::removeSourceTracks( const Meta::TrackList &tracks )
0675 {
0676     DEBUG_BLOCK
0677     debug() << "Transfer errors:" << m_tracksWithError.count() << "of" << tracks.count();
0678 
0679     foreach( Meta::TrackPtr track, m_tracksWithError.keys() )
0680     {
0681         debug() << "transfer error for track" << track->playableUrl();
0682     }
0683 
0684     QSet<Meta::TrackPtr> toRemove(tracks.begin(), tracks.end());
0685     QList<Meta::TrackPtr> trackswitherrorkeys=m_tracksWithError.keys();
0686     QSet<Meta::TrackPtr> errored(trackswitherrorkeys.begin(), trackswitherrorkeys.end());
0687     toRemove.subtract( errored );
0688 
0689     // start the remove workflow
0690     setHidingRemoveConfirm( true );
0691     prepareRemove( toRemove.values() );
0692 }
0693 
0694 CollectionLocation*
0695 CollectionLocation::source() const
0696 {
0697     return m_source;
0698 }
0699 
0700 CollectionLocation*
0701 CollectionLocation::destination() const
0702 {
0703     return m_destination;
0704 }
0705 
0706 void
0707 CollectionLocation::setSource( CollectionLocation *source )
0708 {
0709     m_source = source;
0710 }
0711 
0712 void
0713 CollectionLocation::transferSuccessful( const Meta::TrackPtr &track )
0714 {
0715     m_tracksSuccessfullyTransferred.append( track );
0716 }
0717 
0718 bool
0719 CollectionLocation::isGoingToRemoveSources() const
0720 {
0721     return m_removeSources;
0722 }
0723 void
0724 CollectionLocation::setGoingToRemoveSources( bool removeSources )
0725 {
0726     m_removeSources = removeSources;
0727 }
0728 
0729 bool
0730 CollectionLocation::isHidingRemoveConfirm() const
0731 {
0732     return m_noRemoveConfirmation;
0733 }
0734 
0735 void
0736 CollectionLocation::setHidingRemoveConfirm( bool hideRemoveConfirm )
0737 {
0738     m_noRemoveConfirmation = hideRemoveConfirm;
0739 }
0740 
0741 void
0742 CollectionLocation::transferError( const Meta::TrackPtr &track, const QString &error )
0743 {
0744     m_tracksWithError.insert( track, error );
0745 }
0746