1 // (c) 2004 Christian Muehlhaeuser <chris@chris.de>
2 // (c) 2005-2006 Martin Aumueller <aumuell@reserv.at>
3 // (c) 2005 Seb Ruiz <ruiz@kde.org>
4 // (c) 2006 T.R.Shashwath <trshash84@gmail.com>
5 // (c) 2007 Jeff Mitchell <kde-dev@emailgoeshere.com>
6 // See COPYING file for licensing information
9 #define DEBUG_PREFIX "MediaDevice"
11 #include "MediaDevice.h"
14 #include "amarokconfig.h"
16 #include "collectiondb.h"
18 #include "mediabrowser.h"
19 #include "MediaItem.h"
20 #include "metabundle.h"
21 #include "mountpointmanager.h"
22 #include "pluginmanager.h"
23 #include "podcastbundle.h"
24 #include "scriptmanager.h"
25 #include "statusbar.h"
28 #include <KMessageBox>
30 MediaDevice::MediaDevice()
33 , m_hasMountPoint( true )
34 , m_autoDeletePodcasts( false )
35 , m_syncStats( false )
36 , m_transcode( false )
37 , m_transcodeAlways( false )
38 , m_transcodeRemove( false )
43 , m_deviceNode( QString() )
44 , m_mountPoint( QString() )
45 , m_fsType( QString() )
47 , m_requireMount( false )
49 , m_transferring( false )
51 , m_deferredDisconnect( false )
52 , m_scheduledDisconnect( false )
55 , m_customButton( false )
58 , m_invisibleItem( 0 )
62 sysProc
= new K3ShellProcess(); Q_CHECK_PTR(sysProc
);
65 void MediaDevice::init( MediaBrowser
* parent
)
69 m_view
= new MediaView( m_parent
->m_views
, this );
73 MediaDevice::~MediaDevice()
80 MediaDevice::isSpecialItem( MediaItem
*item
)
82 return (item
== m_playlistItem
) ||
83 (item
== m_podcastItem
) ||
84 (item
== m_invisibleItem
) ||
85 (item
== m_staleItem
) ||
86 (item
== m_orphanedItem
);
90 MediaDevice::loadConfig()
92 m_transcode
= configBool( "Transcode" );
93 m_transcodeAlways
= configBool( "TranscodeAlways" );
94 m_transcodeRemove
= configBool( "TranscodeRemove" );
95 m_preconnectcmd
= configString( "PreConnectCommand" );
96 if( m_preconnectcmd
.isEmpty() )
97 m_preconnectcmd
= configString( "MountCommand" );
98 m_postdisconnectcmd
= configString( "PostDisconnectCommand" );
99 if( m_postdisconnectcmd
.isEmpty() )
100 m_postdisconnectcmd
= configString( "UmountCommand" );
101 if( m_requireMount
&& m_postdisconnectcmd
.isEmpty() )
102 m_postdisconnectcmd
= "kdeeject -q %d";
106 MediaDevice::configString( const QString
&name
, const QString
&defValue
)
108 QString configName
= "MediaDevice";
109 if( !uid().isEmpty() )
110 configName
+= '_' + uid();
111 KConfigGroup config
= Amarok::config( configName
);
112 return config
.readEntry( name
, defValue
);
116 MediaDevice::setConfigString( const QString
&name
, const QString
&value
)
118 QString configName
= "MediaDevice";
119 if( !uid().isEmpty() )
120 configName
+= '_' + uid();
121 KConfigGroup config
= Amarok::config( configName
);
122 config
.writeEntry( name
, value
);
126 MediaDevice::configBool( const QString
&name
, bool defValue
)
128 QString configName
= "MediaDevice";
129 if( !uid().isEmpty() )
130 configName
+= '_' + uid();
131 KConfigGroup config
= Amarok::config( configName
);
132 return config
.readEntry( name
, defValue
);
136 MediaDevice::setConfigBool( const QString
&name
, bool value
)
138 QString configName
= "MediaDevice";
139 if( !uid().isEmpty() )
140 configName
+= '_' + uid();
141 KConfigGroup config
= Amarok::config( configName
);
142 config
.writeEntry( name
, value
);
152 MediaDevice::hideProgress()
154 m_parent
->m_progressBox
->hide();
158 MediaDevice::updateRootItems()
161 m_podcastItem
->setVisible(m_podcastItem
->childCount() > 0);
163 m_invisibleItem
->setVisible(m_invisibleItem
->childCount() > 0);
165 m_staleItem
->setVisible(m_staleItem
->childCount() > 0);
167 m_orphanedItem
->setVisible(m_orphanedItem
->childCount() > 0);
171 MediaDevice::bundlesToSync( const QString
&name
, const KUrl
&url
)
174 // BundleList bundles;
175 // if( !PlaylistFile::isPlaylistFile( url ) )
177 // Amarok::StatusBar::instance()->longMessage( i18n( "Not a playlist file: %1", url.path() ),
178 // KDE::StatusBar::Sorry );
182 // PlaylistFile playlist( url.path() );
183 // if( playlist.isError() )
185 // Amarok::StatusBar::instance()->longMessage( i18n( "Failed to load playlist: %1", url.path() ),
186 // KDE::StatusBar::Sorry );
190 // for( BundleList::iterator it = playlist.bundles().begin();
191 // it != playlist.bundles().end();
194 // bundles += MetaBundle( (*it).url() );
196 // preparePlaylistForSync( name, bundles );
201 MediaDevice::bundlesToSync( const QString
&name
, const QString
&query
)
203 // const QStringList values = CollectionDB::instance()->query( query );
205 // BundleList bundles;
206 // for( QStringList::const_iterator it = values.begin(); it != values.end(); ++it )
207 // bundles += CollectionDB::instance()->bundleFromQuery( &it );
208 // preparePlaylistForSync( name, bundles );
213 MediaDevice::preparePlaylistForSync( const QString
&name
, const BundleList
&bundles
)
215 if( ! m_playlistItem
) // might be syncing a new playlist from the playlist browser
217 MediaItem
*pl
= m_playlistItem
->findItem( name
);
221 for( MediaItem
*it
= static_cast<MediaItem
*>(pl
->firstChild());
225 next
= static_cast<MediaItem
*>(it
->nextSibling());
226 const MetaBundle
*bundle
= (*it
).bundle();
229 if( isOnOtherPlaylist( name
, *bundle
) )
231 if( isInBundleList( bundles
, *bundle
) )
233 deleteItemFromDevice( it
);
235 deleteItemFromDevice( pl
, None
);
241 MediaDevice::bundleMatch( const MetaBundle
&b1
, const MetaBundle
&b2
)
243 if( b1
.track() != b2
.track() )
245 if( b1
.title() != b2
.title() )
247 if( b1
.album() != b2
.album() )
249 if( b1
.artist() != b2
.artist() )
252 if( b1
.discNumber() != b2
.discNumber() )
254 if( b1
.composer() != b2
.composer() )
262 MediaDevice::isInBundleList( const BundleList
&bundles
, const MetaBundle
&b
)
264 for( BundleList::const_iterator it
= bundles
.begin();
268 if( bundleMatch( b
, *it
) )
276 MediaDevice::isOnOtherPlaylist( const QString
&playlistToAvoid
, const MetaBundle
&bundle
)
278 for( MediaItem
*it
= static_cast<MediaItem
*>(m_playlistItem
->firstChild());
280 it
= static_cast<MediaItem
*>(it
->nextSibling()) )
282 if( it
->text( 0 ) == playlistToAvoid
)
284 if( isOnPlaylist( *it
, bundle
) )
292 MediaDevice::isOnPlaylist( const MediaItem
&playlist
, const MetaBundle
&bundle
)
294 for( MediaItem
*it
= static_cast<MediaItem
*>(playlist
.firstChild());
296 it
= static_cast<MediaItem
*>(it
->nextSibling()) )
298 const MetaBundle
*b
= (*it
).bundle();
301 if( bundleMatch( *b
, bundle
) )
309 MediaDevice::copyTrackFromDevice( MediaItem
*item
)
311 debug() << "copyTrackFromDevice: not copying " << item
->url() << ": not implemented";
315 MediaDevice::replaceVariables( const QString
&cmd
)
317 QString result
= cmd
;
318 result
.replace( "%d", deviceNode() );
319 result
.replace( "%m", mountPoint() );
323 int MediaDevice::runPreConnectCommand()
325 if( m_preconnectcmd
.isEmpty() )
328 QString cmd
= replaceVariables( m_preconnectcmd
);
330 debug() << "running pre-connect command: [" << cmd
<< "]";
332 debug() << "pre-connect: e=" << e
;
336 int MediaDevice::runPostDisconnectCommand()
338 if( m_postdisconnectcmd
.isEmpty() )
341 QString cmd
= replaceVariables( m_postdisconnectcmd
);
342 debug() << "running post-disconnect command: [" << cmd
<< "]";
344 debug() << "post-disconnect: e=" << e
;
349 int MediaDevice::sysCall( const QString
&command
)
351 if ( sysProc
->isRunning() ) return -1;
353 sysProc
->clearArguments();
354 (*sysProc
) << command
;
355 if (!sysProc
->start( K3Process::Block
, K3Process::AllOutput
))
356 kFatal() << i18n("could not execute %1", command
.toLocal8Bit().data());
358 return (sysProc
->exitStatus());
362 MediaDevice::abortTransfer()
369 MediaDevice::kioCopyTrack( const KUrl
&src
, const KUrl
&dst
)
373 KIO::FileCopyJob
*job
= KIO::file_copy( src
, dst
,
374 -1 /* permissions */,
375 KIO::HideProgressInfo
);
376 connect( job
, SIGNAL( result( KIO::Job
* ) ),
377 this, SLOT( fileTransferred( KIO::Job
* ) ) );
379 bool tryToRemove
= false;
384 job
->kill( KJob::EmitResult
);
391 kapp
->processEvents( QEventLoop::ExcludeUserInputEvents
);
400 Amarok::StatusBar::instance()->longMessage(
401 i18n( "Media Device: Copying %1 to %2 failed" )
402 .arg( src
.prettyUrl(), dst
.prettyUrl() ),
403 KDE::StatusBar::Error
);
407 MetaBundle
bundle2(dst
);
408 if(!bundle2
.isValidMedia() && bundle2
.filesize()==MetaBundle::Undetermined
)
411 // probably s.th. went wrong
412 Amarok::StatusBar::instance()->longMessage(
413 i18n( "Media Device: Reading tags from %1 failed", dst
.prettyUrl() ),
414 KDE::StatusBar::Error
);
421 QFile::remove( dst
.path() );
429 MediaDevice::fileTransferred( KIO::Job
*job
) //SLOT
434 debug() << "file transfer failed: " << job
->errorText();
438 m_copyFailed
= false;
445 MediaDevice::connectDevice( bool silent
)
447 if( !lockDevice( true ) )
450 runPreConnectCommand();
451 openDevice( silent
);
454 && MediaBrowser::instance()->currentDevice() != this
455 && MediaBrowser::instance()->currentDevice()
456 && !MediaBrowser::instance()->currentDevice()->isConnected() )
458 MediaBrowser::instance()->activateDevice( this );
460 m_parent
->updateStats();
461 m_parent
->updateButtons();
471 syncStatsFromDevice( 0 );
472 Scrobbler::instance()->m_submitter
->syncComplete();
475 // delete podcasts already played
476 if( m_autoDeletePodcasts
&& m_podcastItem
)
478 QList
<MediaItem
*> list
;
479 //NOTE we assume that currentItem is the main target
480 int numFiles
= m_view
->getSelectedLeaves( m_podcastItem
, &list
, MediaView::OnlyPlayed
);
484 m_parent
->m_stats
->setText( i18np( "1 track to be deleted", "%1 tracks to be deleted", numFiles
) );
486 setProgress( 0, numFiles
);
488 int numDeleted
= deleteItemFromDevice( m_podcastItem
, true );
492 Amarok::StatusBar::instance()->longMessage(
493 i18n( "Failed to purge podcasts already played" ),
494 KDE::StatusBar::Sorry
);
496 else if( numDeleted
> 0 )
498 Amarok::StatusBar::instance()->shortMessage(
499 i18np( "Purged 1 podcasts already played",
500 "Purged %1 podcasts already played",
506 QTimer::singleShot( 1500, m_parent
->m_progressBox
, SLOT(hide()) );
507 m_parent
->queue()->computeSize();
508 m_parent
->updateStats();
515 if( m_deferredDisconnect
)
517 m_deferredDisconnect
= false;
518 disconnectDevice( m_runDisconnectHook
);
521 Amarok::StatusBar::instance()->shortMessage( i18n( "Device successfully connected" ) );
523 m_parent
->updateDevices();
529 MediaDevice::disconnectDevice( bool postDisconnectHook
)
535 debug() << "disconnecting: hook=" << postDisconnectHook
;
537 if( !lockDevice( true ) )
539 m_runDisconnectHook
= postDisconnectHook
;
540 m_deferredDisconnect
= true;
541 debug() << "disconnecting: locked";
544 debug() << "disconnecting: ok";
554 m_parent
->updateStats();
557 if( postDisconnectHook
&& runPostDisconnectCommand() != 0 )
559 Amarok::StatusBar::instance()->longMessage(
560 i18n( "Post-disconnect command failed, before removing device, please make sure that it is safe to do so." ),
561 KDE::StatusBar::Information
);
565 Amarok::StatusBar::instance()->shortMessage( i18n( "Device successfully disconnected" ) );
567 m_parent
->updateDevices();
573 MediaDevice::syncStatsFromDevice( MediaItem
*root
)
575 MediaItem
*it
= static_cast<MediaItem
*>( m_view
->firstChild() );
578 it
= static_cast<MediaItem
*>( root
->firstChild() );
581 kapp
->processEvents( QEventLoop::ExcludeUserInputEvents
);
583 for( ; it
; it
= static_cast<MediaItem
*>( it
->nextSibling() ) )
587 case MediaItem::TRACK
:
588 if( !it
->parent() || static_cast<MediaItem
*>( it
->parent() )->type() != MediaItem::PLAYLIST
)
590 const MetaBundle
*bundle
= it
->bundle();
591 for( int i
=0; i
<it
->recentlyPlayed(); i
++ )
594 if( bundle
->length() > 30
595 && !bundle
->artist().isEmpty() && bundle
->artist() != i18n( "Unknown" )
596 && !bundle
->title().isEmpty() && bundle
->title() != i18n( "Unknown" ) )
598 // don't submit tracks shorter than 30 sec or w/o artist/title
599 debug() << "scrobbling " << bundle
->artist() << " - " << bundle
->title();
600 SubmitItem
*sit
= new SubmitItem( bundle
->artist(), bundle
->album(), bundle
->title(), bundle
->length(), false /* fake time */ );
601 Scrobbler::instance()->m_submitter
->submitItem( sit
);
604 // increase Amarok playcount
605 QString url
= CollectionDB::instance()->getURL( *bundle
);
608 QDateTime t
= it
->playTime();
609 CollectionDB::instance()->addSongPercentage( url
, 100, "mediadevice", t
.isValid() ? &t
: 0 );
610 debug() << "played " << url
;
614 if( it
->ratingChanged() )
616 // copy rating from media device to Amarok
617 QString url
= CollectionDB::instance()->getURL( *bundle
);
618 debug() << "rating changed " << url
<< ": " << it
->rating()/10;
621 CollectionDB::instance()->setSongRating( url
, it
->rating()/10 );
622 it
->setRating( it
->rating() ); // prevent setting it again next time
627 case MediaItem::PODCASTITEM
:
628 if( !it
->parent() || static_cast<MediaItem
*>( it
->parent() )->type() != MediaItem::PLAYLIST
)
630 const MetaBundle
*bundle
= it
->bundle();
631 if( it
->played() || it
->recentlyPlayed() )
633 if( PodcastEpisodeBundle
*peb
= bundle
->podcastBundle() )
635 debug() << "marking podcast episode as played: " << peb
->url();
637 // if( PlaylistBrowser::instance() )
639 // PodcastEpisode *p = PlaylistBrowser::instance()->findPodcastEpisode( peb->url(), peb->parent() );
643 // debug() << "did not find podcast episode: " << peb->url() << " from " << peb->parent();
651 syncStatsFromDevice( it
);
658 MediaDevice::syncStatsToDevice( MediaItem
*root
)
660 MediaItem
*it
= static_cast<MediaItem
*>( m_view
->firstChild() );
663 it
= static_cast<MediaItem
*>( root
->firstChild() );
666 kapp
->processEvents( QEventLoop::ExcludeUserInputEvents
);
668 for( ; it
; it
= static_cast<MediaItem
*>( it
->nextSibling() ) )
672 case MediaItem::TRACK
:
673 if( !it
->parent() || static_cast<MediaItem
*>( it
->parent() )->type() != MediaItem::PLAYLIST
)
675 const MetaBundle
*bundle
= it
->bundle();
676 QString url
= CollectionDB::instance()->getURL( *bundle
);
677 it
->syncStatsFromPath( url
);
681 case MediaItem::PODCASTITEM
:
682 if( !it
->parent() || static_cast<MediaItem
*>( it
->parent() )->type() != MediaItem::PLAYLIST
)
684 const MetaBundle
*bundle
= it
->bundle();
685 if( PodcastEpisodeBundle
*peb
= bundle
->podcastBundle() )
688 // if( PlaylistBrowser::instance() )
690 // PodcastEpisode *p = PlaylistBrowser::instance()->findPodcastEpisode( peb->url(), peb->parent() );
692 // it->setListened( !p->isNew() );
699 syncStatsToDevice( it
);
706 MediaDevice::transferFiles()
708 if( !lockDevice( true ) )
713 setCanceled( false );
715 m_transferring
= true;
716 m_parent
->transferAction()->setEnabled( false );
718 setProgress( 0, m_parent
->m_queue
->childCount() );
720 // ok, let's copy the stuff to the device
722 KUrl::List existing
, unplayable
;
723 unsigned transcodeFail
= 0;
724 // iterate through items
725 MediaItem
*next
= static_cast<MediaItem
*>(m_parent
->m_queue
->firstChild());
728 MediaItem
*transferredItem
= next
;
729 transferredItem
->setFailed( false );
730 transferredItem
->m_flags
|= MediaItem::Transferring
;
731 next
= static_cast<MediaItem
*>( transferredItem
->nextSibling() );
733 if( transferredItem
->device() )
735 transferredItem
->device()->copyTrackFromDevice( transferredItem
);
736 m_parent
->m_queue
->subtractItemFromSize( transferredItem
, true );
737 delete transferredItem
;
738 setProgress( progress() + 1 );
739 m_parent
->m_queue
->itemCountChanged();
740 kapp
->processEvents( QEventLoop::ExcludeUserInputEvents
);
745 if( transferredItem
->type() == MediaItem::PLAYLIST
)
747 if( transferredItem
->flags() & MediaItem::SmartPlaylist
)
748 bundles
= bundlesToSync( transferredItem
->text( 0 ), transferredItem
->data() );
750 bundles
= bundlesToSync( transferredItem
->text( 0 ), KUrl( transferredItem
->data() ) );
752 else if( transferredItem
->bundle() )
753 bundles
+= *transferredItem
->bundle();
756 // this should not happen
757 debug() << "invalid item in transfer queue";
758 m_parent
->m_queue
->subtractItemFromSize( transferredItem
, true );
759 delete transferredItem
;
760 m_parent
->m_queue
->itemCountChanged();
764 if( bundles
.count() > 1 )
765 setProgress( progress(), MediaBrowser::instance()->m_progress
->maximum() + bundles
.count() - 1 );
767 QString playlist
= transferredItem
->m_playlistName
;
768 for( BundleList::const_iterator it
= bundles
.begin();
775 const MetaBundle
*bundle
= &(*it
);
777 bool transcoding
= false;
778 MediaItem
*item
= trackExists( *bundle
);
779 if( item
&& playlist
.isEmpty() )
781 Amarok::StatusBar::instance()->shortMessage( i18n( "Track already on media device: %1" ).
782 arg( (*it
).url().prettyUrl() ),
783 KDE::StatusBar::Sorry
);
784 existing
+= (*it
).url();
785 setProgress( progress() + 1 );
788 else if( !item
) // the item does not yet exist on the media device
790 if( m_transcode
&& ( !isPlayable( *bundle
) || m_transcodeAlways
) )
792 QString preferred
= supportedFiletypes().isEmpty() ? "mp3" : supportedFiletypes().first();
793 debug() << "transcoding " << bundle
->url() << " to " << preferred
;
794 KUrl transcoded
= MediaBrowser::instance()->transcode( bundle
->url(), preferred
);
797 if( transcoded
.isEmpty() )
799 debug() << "transcoding failed";
805 MetaBundle
*transcodedBundle
= new MetaBundle( transcoded
);
806 transcodedBundle
->setArtist( bundle
->artist() );
807 transcodedBundle
->setTitle( bundle
->title() );
808 transcodedBundle
->setComposer( bundle
->composer() );
809 transcodedBundle
->setAlbum( bundle
->album() );
810 transcodedBundle
->setGenre( bundle
->genre() );
811 transcodedBundle
->setComment( bundle
->comment() );
812 transcodedBundle
->setYear( bundle
->year() );
813 transcodedBundle
->setDiscNumber( bundle
->discNumber() );
814 transcodedBundle
->setTrack( bundle
->track() );
815 if( bundle
->podcastBundle() )
817 transcodedBundle
->setPodcastBundle( *bundle
->podcastBundle() );
818 transcodedBundle
->copyFrom( *bundle
->podcastBundle() );
820 bundle
= transcodedBundle
;
824 if( !isPlayable( *bundle
) )
826 Amarok::StatusBar::instance()->shortMessage( i18n( "Track not playable on media device: %1", bundle
->url().path() ),
827 KDE::StatusBar::Sorry
);
828 unplayable
+= (*it
).url();
829 transferredItem
->setFailed();
835 setProgress( progress() + 1 );
838 item
= copyTrackToDevice( *bundle
);
841 if( !item
) // copyTrackToDevice() failed
845 Amarok::StatusBar::instance()->longMessage(
846 i18n( "Failed to copy track to media device: %1", bundle
->url().path() ),
847 KDE::StatusBar::Sorry
);
848 transferredItem
->setFailed();
854 if( m_transcodeRemove
)
855 QFile( bundle
->url().path() ).remove();
866 setProgress( progress() + 1 );
870 item
->syncStatsFromPath( (*it
).url().path() );
872 if( m_playlistItem
&& !playlist
.isEmpty() )
874 MediaItem
*pl
= m_playlistItem
->findItem( playlist
);
877 QList
<MediaItem
*> items
;
878 pl
= newPlaylist( playlist
, m_playlistItem
, items
);
882 QList
<MediaItem
*> items
;
883 items
.append( item
);
884 addToPlaylist( pl
, pl
->lastChild(), items
);
888 setProgress( progress() + 1 );
891 transferredItem
->m_flags
&= ~MediaItem::Transferring
;
895 m_parent
->updateStats();
899 if( !(transferredItem
->flags() & MediaItem::Failed
) )
901 m_parent
->m_queue
->subtractItemFromSize( transferredItem
, true );
902 delete transferredItem
;
903 m_parent
->m_queue
->itemCountChanged();
905 m_parent
->updateStats();
907 kapp
->processEvents( QEventLoop::ExcludeUserInputEvents
);
911 fileTransferFinished();
914 if( unplayable
.count() > 0 )
916 msg
= i18np( "One track not playable on media device",
917 "%1 tracks not playable on media device", unplayable
.count() );
919 if( existing
.count() > 0 )
922 msg
= i18np( "One track already on media device",
923 "%1 tracks already on media device", existing
.count() );
925 msg
+= i18np( ", one track already on media device",
926 ", %1 tracks already on media device", existing
.count() );
928 if( transcodeFail
> 0 )
931 msg
= i18np( "One track was not transcoded",
932 "%1 tracks were not transcoded", transcodeFail
);
934 msg
+= i18np( ", one track was not transcoded",
935 ", %1 tracks were not transcoded", transcodeFail
);
937 const ScriptManager
* const sm
= ScriptManager::instance();
938 if( !sm
->transcodeScriptRunning().isEmpty() )
939 msg
+= i18n( " (no transcode script running)" );
942 if( unplayable
.count() + existing
.count() > 0 )
944 QString longMsg
= i18n( "The following tracks were not transferred: ");
945 for( KUrl::List::Iterator it
= existing
.begin();
946 it
!= existing
.end();
949 longMsg
+= "<br>" + (*it
).prettyUrl();
951 for( KUrl::List::Iterator it
= unplayable
.begin();
952 it
!= unplayable
.end();
955 longMsg
+= "<br>" + (*it
).prettyUrl();
957 Amarok::StatusBar::instance()->shortLongMessage( msg
, longMsg
, KDE::StatusBar::Sorry
);
959 else if( !msg
.isEmpty() )
961 Amarok::StatusBar::instance()->shortMessage( msg
, KDE::StatusBar::Sorry
);
964 m_parent
->updateButtons();
965 m_parent
->queue()->save( Amarok::saveLocation() + "transferlist.xml" );
966 m_transferring
= false;
968 if( m_deferredDisconnect
)
970 m_deferredDisconnect
= false;
971 disconnectDevice( m_runDisconnectHook
);
973 else if( m_scheduledDisconnect
)
975 disconnectDevice( true );
977 m_scheduledDisconnect
= false;
981 MediaDevice::progress() const
983 return m_parent
->m_progress
->value();
987 MediaDevice::setProgress( const int progress
, const int total
)
990 m_parent
->m_progress
->setRange( 0, total
);
991 m_parent
->m_progress
->setValue( progress
);
992 m_parent
->m_progressBox
->show();
996 MediaDevice::fileTransferFinished() //SLOT
998 m_parent
->updateStats();
999 m_parent
->m_progressBox
->hide();
1000 m_parent
->transferAction()->setEnabled( isConnected() && m_parent
->queue()->childCount() > 0 );
1006 MediaDevice::deleteFromDevice(MediaItem
*item
, int flags
)
1008 MediaItem
* fi
= item
;
1011 if ( !(flags
& Recursing
) )
1013 if( !lockDevice( true ) )
1016 setCanceled( false );
1020 QList
<MediaItem
*> list
;
1021 //NOTE we assume that currentItem is the main target
1022 int numFiles
= m_view
->getSelectedLeaves(item
, &list
, MediaView::OnlySelected
| ((flags
& OnlyPlayed
) ? MediaView::OnlyPlayed
: MediaView::None
) );
1024 m_parent
->m_stats
->setText( i18np( "1 track to be deleted", "%1 tracks to be deleted", numFiles
) );
1025 if( numFiles
> 0 && (flags
& DeleteTrack
) )
1027 int button
= KMessageBox::warningContinueCancel( m_parent
,
1028 i18np( "<p>You have selected 1 track to be <b>irreversibly</b> deleted.",
1029 "<p>You have selected %1 tracks to be <b>irreversibly</b> deleted.",
1033 KGuiItem(i18n("&Delete"),"edit-delete") );
1035 if ( button
!= KMessageBox::Continue
)
1037 m_parent
->queue()->computeSize();
1038 m_parent
->updateStats();
1044 if(!isTransferring())
1046 setProgress( 0, numFiles
);
1050 // don't return if numFiles==0: playlist items might be to delete
1053 fi
= static_cast<MediaItem
*>(m_view
->firstChild());
1058 MediaItem
*next
= static_cast<MediaItem
*>(fi
->nextSibling());
1065 if( !fi
->isVisible() )
1071 if( fi
->isSelected() )
1073 int ret
= deleteItemFromDevice(fi
, flags
);
1074 if( ret
>= 0 && count
>= 0 )
1081 if( fi
->childCount() )
1083 int ret
= deleteFromDevice( static_cast<MediaItem
*>(fi
->firstChild()), flags
| Recursing
);
1084 if( ret
>= 0 && count
>= 0 )
1090 m_parent
->updateStats();
1095 if(!(flags
& Recursing
))
1098 synchronizeDevice();
1102 if(!isTransferring())
1104 QTimer::singleShot( 1500, m_parent
->m_progressBox
, SLOT(hide()) );
1107 if( m_deferredDisconnect
)
1109 m_deferredDisconnect
= false;
1110 disconnectDevice( m_runDisconnectHook
);
1113 m_parent
->queue()->computeSize();
1114 m_parent
->updateStats();
1120 MediaDevice::purgeEmptyItems( MediaItem
*root
)
1125 it
= static_cast<MediaItem
*>(root
->firstChild());
1129 it
= static_cast<MediaItem
*>(m_view
->firstChild());
1132 MediaItem
*next
= 0;
1133 for( ; it
; it
=next
)
1135 next
= static_cast<MediaItem
*>(it
->nextSibling());
1136 purgeEmptyItems( it
);
1137 if( it
->childCount() == 0 &&
1138 (it
->type() == MediaItem::ARTIST
||
1139 it
->type() == MediaItem::ALBUM
||
1140 it
->type() == MediaItem::PODCASTCHANNEL
) )
1146 MediaDevice::isPlayable( const MetaBundle
&bundle
)
1148 if( supportedFiletypes().isEmpty() )
1151 QString type
= bundle
.url().path().section( ".", -1 ).toLower();
1152 return supportedFiletypes().contains( type
);
1156 MediaDevice::isPreferredFormat( const MetaBundle
&bundle
)
1158 if( supportedFiletypes().isEmpty() )
1161 QString type
= bundle
.url().path().section( ".", -1 ).toLower();
1162 return ( type
== supportedFiletypes().first() );
1165 #include "MediaDevice.moc"