You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
amarok/amarok/src/mediadevice/generic/genericmediadevice.cpp

1094 lines
34 KiB

/****************************************************************************
* copyright :(C) 2006 Roel Meeuws <r.j.meeuws+amarok@gmail.com *
* (C) 2005 Jeff Mitchell <kde-dev@emailgoeshere.com> *
* (C) 2005 Seb Ruiz <me@sebruiz.net> *
* *
* With some code helpers from KIO_VFAT *
* (c) 2004 Thomas Loeber <vfat@loeber1.de> *
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#define DEBUG_PREFIX "GenericMediaDevice"
#include "genericmediadevice.h"
AMAROK_EXPORT_PLUGIN( GenericMediaDevice )
#include "amarok.h"
#include "debug.h"
#include "medium.h"
#include "metabundle.h"
#include "collectiondb.h"
#include "collectionbrowser.h"
#include "k3bexporter.h"
#include "playlist.h"
#include "podcastbundle.h"
#include "statusbar/statusbar.h"
#include "transferdialog.h"
#include "genericmediadeviceconfigdialog.h"
#include <kapplication.h>
#include <kconfig.h> //download saveLocation
#include <kdiskfreesp.h>
#include <kiconloader.h> //smallIcon
#include <kio/job.h>
#include <kio/jobclasses.h>
#include <kio/netaccess.h>
#include <kmessagebox.h>
#include <kmountpoint.h>
#include <kpopupmenu.h>
#include <kurlrequester.h> //downloadSelectedItems()
#include <kurlrequesterdlg.h> //downloadSelectedItems()
#include <taglib/audioproperties.h>
#include <unistd.h> //usleep()
#include <tqcstring.h>
#include <tqfile.h>
#include <qstringx.h>
#include <tqstringlist.h>
#include <tqcombobox.h>
#include <tqlistbox.h>
#include <tqlineedit.h>
typedef TQPtrList<GenericMediaFile> MediaFileList;
typedef TQPtrListIterator<GenericMediaFile> MediaFileListIterator;
/**
* GenericMediaItem Class
*/
class GenericMediaItem : public MediaItem
{
public:
GenericMediaItem( TQListView *parent, TQListViewItem *after = 0 )
: MediaItem( parent, after )
{ }
GenericMediaItem( TQListViewItem *parent, TQListViewItem *after = 0 )
: MediaItem( parent, after )
{ }
// List directories first, always
int
compare( TQListViewItem *i, int col, bool ascending ) const
{
#define i static_cast<GenericMediaItem *>(i)
switch( type() )
{
case MediaItem::DIRECTORY:
if( i->type() == MediaItem::DIRECTORY )
break;
return -1;
default:
if( i->type() == MediaItem::DIRECTORY )
return 1;
}
#undef i
return MediaItem::compare(i, col, ascending);
}
private:
bool m_dir;
};
class GenericMediaFile
{
public:
GenericMediaFile( GenericMediaFile *parent, TQString basename, GenericMediaDevice *device )
: m_parent( parent )
, m_device( device )
{
m_listed = false;
m_tqchildren = new MediaFileList();
if( m_parent )
{
if( m_parent == m_device->getInitialFile() )
m_viewItem = new GenericMediaItem( m_device->view() );
else
m_viewItem = new GenericMediaItem( m_parent->getViewItem() );
setNamesFromBase( basename );
m_viewItem->setText( 0, m_baseName );
m_parent->getChildren()->append( this );
}
else
{
m_viewItem = 0;
setNamesFromBase( basename );
}
m_device->getItemMap()[m_viewItem] = this;
if( m_device->getFileMap()[m_fullName] )
{
debug() << "Trying to create two GenericMediaFile items with same fullName!" << endl;
debug() << "name already existing: " << m_device->getFileMap()[m_fullName]->getFullName() << endl;
delete this;
}
else
{
m_device->getFileMap()[m_fullName] = this;
}
}
~GenericMediaFile()
{
if( m_parent )
m_parent->removeChild( this );
m_device->getItemMap().erase( m_viewItem );
m_device->getFileMap().erase( m_fullName );
if ( m_tqchildren )
delete m_tqchildren;
if ( m_viewItem )
delete m_viewItem;
}
GenericMediaFile*
getParent() { return m_parent; }
void
setParent( GenericMediaFile* parent )
{
m_device->getFileMap().erase( m_fullName );
m_parent->getChildren()->remove( this );
m_parent = parent;
if( m_parent )
m_parent->getChildren()->append( this );
setNamesFromBase( m_baseName );
m_device->getFileMap()[m_fullName] = this;
}
void
removeChild( GenericMediaFile* childToDelete ) { m_tqchildren->remove( childToDelete ); }
GenericMediaItem*
getViewItem() { return m_viewItem; }
bool
getListed() { return m_listed; }
void
setListed( bool listed ) { m_listed = listed; }
TQString
getFullName() { return m_fullName; }
TQString
getBaseName() { return m_baseName; }
//always follow this function with setNamesFromBase()
void
setBaseName( TQString &name ) { m_baseName = name; }
void
setNamesFromBase( const TQString &name = TQString() )
{
if( name != TQString() )
m_baseName = name;
if( m_parent )
m_fullName = m_parent->getFullName() + '/' + m_baseName;
else
m_fullName = m_baseName;
if( m_viewItem )
m_viewItem->setBundle( new MetaBundle( KURL::fromPathOrURL( m_fullName ), true, TagLib::AudioProperties::Fast ) );
}
MediaFileList*
getChildren() { return m_tqchildren; }
void
deleteAll( bool onlyChildren )
{
GenericMediaFile *vmf;
if( m_tqchildren && !m_tqchildren->isEmpty() )
{
MediaFileListIterator it( *m_tqchildren );
while( ( vmf = it.current() ) != 0 )
{
++it;
vmf->deleteAll( true );
}
}
if( onlyChildren )
delete this;
}
void
renameAllChildren()
{
GenericMediaFile *vmf;
if( m_tqchildren && !m_tqchildren->isEmpty() )
{
for( vmf = m_tqchildren->first(); vmf; vmf = m_tqchildren->next() )
vmf->renameAllChildren();
}
setNamesFromBase();
}
private:
TQString m_fullName;
TQString m_baseName;
GenericMediaFile *m_parent;
MediaFileList *m_tqchildren;
GenericMediaItem *m_viewItem;
GenericMediaDevice* m_device;
bool m_listed;
};
TQString
GenericMediaDevice::fileName( const MetaBundle &bundle )
{
TQString result = cleanPath( bundle.artist() );
if( !result.isEmpty() )
{
if( m_spacesToUnderscores )
result += "_-_";
else
result += " - ";
}
if( bundle.track() )
{
result.sprintf( "%02d", bundle.track() );
if( m_spacesToUnderscores )
result += '_';
else
result += ' ';
}
result += cleanPath( bundle.title() + '.' + bundle.type() );
return result;
}
/**
* GenericMediaDevice Class
*/
GenericMediaDevice::GenericMediaDevice()
: MediaDevice()
, m_kBSize( 0 )
, m_kBAvail( 0 )
, m_connected( false )
{
DEBUG_BLOCK
m_name = i18n("Generic Audio Player");
m_dirLister = new KDirLister();
m_dirLister->setNameFilter( "*.mp3 *.wav *.asf *.flac *.wma *.ogg *.aac *.m4a *.mp4 *.mp2 *.ac3" );
m_dirLister->setAutoUpdate( false );
m_spacesToUnderscores = false;
m_ignoreThePrefix = false;
m_asciiTextOnly = false;
m_songLocation = TQString();
m_podcastLocation = TQString();
m_supportedFileTypes.clear();
m_configDialog = 0;
connect( m_dirLister, TQT_SIGNAL( newItems(const KFileItemList &) ), this, TQT_SLOT( newItems(const KFileItemList &) ) );
connect( m_dirLister, TQT_SIGNAL( completed() ), this, TQT_SLOT( dirListerCompleted() ) );
connect( m_dirLister, TQT_SIGNAL( clear() ), this, TQT_SLOT( dirListerClear() ) );
connect( m_dirLister, TQT_SIGNAL( clear(const KURL &) ), this, TQT_SLOT( dirListerClear(const KURL &) ) );
connect( m_dirLister, TQT_SIGNAL( deleteItem(KFileItem *) ), this, TQT_SLOT( dirListerDeleteItem(KFileItem *) ) );
}
void
GenericMediaDevice::init( MediaBrowser* parent )
{
MediaDevice::init( parent );
}
GenericMediaDevice::~GenericMediaDevice()
{
closeDevice();
}
void
GenericMediaDevice::applyConfig()
{
if( m_configDialog != 0)
{
m_supportedFileTypes.clear();
for( uint i = 0; i < m_configDialog->m_supportedListBox->count(); i++ )
{
TQString currentText = m_configDialog->m_supportedListBox->item( i )->text();
if( currentText == m_configDialog->m_convertComboBox->currentText() )
m_supportedFileTypes.prepend( currentText );
else
m_supportedFileTypes.append( currentText );
}
m_spacesToUnderscores = m_configDialog->m_spaceCheck->isChecked();
m_asciiTextOnly = m_configDialog->m_asciiCheck->isChecked();
m_vfatTextOnly = m_configDialog->m_vfatCheck->isChecked();
m_ignoreThePrefix = m_configDialog->m_ignoreTheCheck->isChecked();
m_songLocation = m_configDialog->m_songLocationBox->text();
m_podcastLocation = m_configDialog->m_podcastLocationBox->text();
}
setConfigString( "songLocation" , m_songLocation );
setConfigString( "podcastLocation" , m_podcastLocation );
setConfigBool( "spacesToUnderscores", m_spacesToUnderscores );
setConfigBool( "ignoreThePrefix" , m_ignoreThePrefix );
setConfigBool( "asciiTextOnly" , m_asciiTextOnly );
setConfigBool( "vfatTextOnly" , m_vfatTextOnly );
setConfigString( "supportedFiletypes" , m_supportedFileTypes.join( ", " ) );
}
void
GenericMediaDevice::loadConfig()
{
MediaDevice::loadConfig();
m_spacesToUnderscores = configBool( "spacesToUnderscores", false );
m_ignoreThePrefix = configBool( "ignoreThePrefix", false);
m_asciiTextOnly = configBool( "asciiTextOnly", false );
m_vfatTextOnly = configBool( "vfatTextOnly", false );
m_songLocation = configString( "songLocation", "/%artist/%album/%title.%filetype" );
m_podcastLocation = configString( "podcastLocation", "/podcasts/" );
m_supportedFileTypes = TQStringList::split( ", ", configString( "supportedFiletypes", "mp3"), true);
}
bool
GenericMediaDevice::openDevice( bool /*silent*/ )
{
DEBUG_BLOCK
if( !m_medium.mountPoint() )
{
Amarok::StatusBar::instance()->longMessage( i18n( "Devices handled by this plugin must be mounted first.\n"
"Please mount the device and click \"Connect\" again." ),
KDE::StatusBar::Sorry );
return false;
}
KMountPoint::List currentmountpoints = KMountPoint::currentMountPoints();
KMountPoint::List::Iterator mountiter = currentmountpoints.begin();
for(; mountiter != currentmountpoints.end(); ++mountiter)
{
if( m_medium.mountPoint() == (*mountiter)->mountPoint() )
m_medium.setFsType( (*mountiter)->mountType() );
}
m_actuallyVfat = (m_medium.fsType() == "vfat" || m_medium.fsType() == "msdosfs") ?
true : false;
m_connected = true;
KURL tempurl = KURL::fromPathOrURL( m_medium.mountPoint() );
TQString newMountPoint = tempurl.isLocalFile() ? tempurl.path( -1 ) : tempurl.prettyURL( -1 ); //no trailing slash
m_transferDir = newMountPoint;
m_initialFile = new GenericMediaFile( 0, newMountPoint, this );
listDir( newMountPoint );
connect( this, TQT_SIGNAL( startTransfer() ), MediaBrowser::instance(), TQT_SLOT( transferClicked() ) );
return true;
}
bool
GenericMediaDevice::closeDevice() //SLOT
{
if( m_connected )
{
m_initialFile->deleteAll( true );
m_view->clear();
m_connected = false;
}
//delete these?
m_mfm.clear();
m_mim.clear();
return true;
}
/// Renaming
void
GenericMediaDevice::renameItem( TQListViewItem *item ) // SLOT
{
if( !item )
return;
#define item static_cast<GenericMediaItem*>(item)
TQString src = m_mim[item]->getFullName();
TQString dst = m_mim[item]->getParent()->getFullName() + '/' + item->text(0);
debug() << "Renaming: " << src << " to: " << dst << endl;
//do we want a progress dialog? If so, set last false to true
if( KIO::NetAccess::file_move( KURL::fromPathOrURL(src), KURL::fromPathOrURL(dst), -1, false, false, false ) )
{
m_mfm.erase( m_mim[item]->getFullName() );
m_mim[item]->setNamesFromBase( item->text(0) );
m_mfm[m_mim[item]->getFullName()] = m_mim[item];
}
else
{
debug() << "Renaming FAILED!" << endl;
//failed, so set the item's text back to how it should be
item->setText( 0, m_mim[item]->getBaseName() );
}
refreshDir( m_mim[item]->getParent()->getFullName() );
m_mim[item]->renameAllChildren();
#undef item
}
/// Creating a directory
MediaItem *
GenericMediaDevice::newDirectory( const TQString &name, MediaItem *parent )
{
if( !m_connected || name.isEmpty() ) return 0;
#define parent static_cast<GenericMediaItem*>(parent)
TQString fullName = m_mim[parent]->getFullName();
TQString cleanedName = cleanPath( name );
TQString fullPath = fullName + '/' + cleanedName;
debug() << "Creating directory: " << fullPath << endl;
const KURL url( fullPath );
if( !KIO::NetAccess::mkdir( url, m_parent ) ) //failed
{
debug() << "Failed to create directory " << fullPath << endl;
return 0;
}
refreshDir( m_mim[parent]->getFullName() );
#undef parent
return 0;
}
void
GenericMediaDevice::addToDirectory( MediaItem *directory, TQPtrList<MediaItem> items )
{
if( items.isEmpty() ) return;
GenericMediaFile *dropDir;
if( !directory )
dropDir = m_initialFile;
else
{
if( directory->type() == MediaItem::TRACK )
#define directory static_cast<GenericMediaItem *>(directory)
dropDir = m_mim[directory]->getParent();
else
dropDir = m_mim[directory];
}
for( TQPtrListIterator<MediaItem> it(items); *it; ++it )
{
GenericMediaItem *currItem = static_cast<GenericMediaItem *>(*it);
TQString src = m_mim[currItem]->getFullName();
TQString dst = dropDir->getFullName() + '/' + currItem->text(0);
debug() << "Moving: " << src << " to: " << dst << endl;
const KURL srcurl(src);
const KURL dsturl(dst);
if ( !KIO::NetAccess::file_move( srcurl, dsturl, -1, false, false, m_parent ) )
debug() << "Failed moving " << src << " to " << dst << endl;
else
{
refreshDir( m_mim[currItem]->getParent()->getFullName() );
refreshDir( dropDir->getFullName() );
//smb: urls don't seem to refresh correctly, but this seems to be a samba issue?
}
}
#undef directory
}
/// Uploading
TQString
GenericMediaDevice::buildDestination( const TQString &format, const MetaBundle &mb )
{
bool isCompilation = mb.compilation() == MetaBundle::CompilationYes;
TQMap<TQString, TQString> args;
TQString artist = mb.artist();
TQString albumartist = artist;
if( isCompilation )
albumartist = i18n( "Various Artists" );
args["theartist"] = cleanPath( artist );
args["thealbumartist"] = cleanPath( albumartist );
if( m_ignoreThePrefix && artist.startsWith( "The " ) )
CollectionView::instance()->manipulateThe( artist, true );
artist = cleanPath( artist );
if( m_ignoreThePrefix && albumartist.startsWith( "The " ) )
CollectionView::instance()->manipulateThe( albumartist, true );
albumartist = cleanPath( albumartist );
for( int i = 0; i < MetaBundle::NUM_COLUMNS; i++ )
{
if( i == MetaBundle::Score || i == MetaBundle::PlayCount || i == MetaBundle::LastPlayed )
continue;
args[mb.exactColumnName( i ).lower()] = cleanPath( mb.prettyText( i ) );
}
args["artist"] = artist;
args["albumartist"] = albumartist;
args["initial"] = albumartist.mid( 0, 1 ).upper();
args["filetype"] = TQString(mb.url().pathOrURL().section( ".", -1 )).lower();
TQString track;
if ( mb.track() )
track.sprintf( "%02d", mb.track() );
args["track"] = track;
Amarok::QStringx formatx( format );
TQString result = formatx.namedOptArgs( args );
if( !result.startsWith( "/" ) )
result.prepend( "/" );
return result.replace( TQRegExp( "/\\.*" ), "/" );
}
void
GenericMediaDevice::checkAndBuildLocation( const TQString& location )
{
// check for every directory from the mount point to the location
// whether they exist or not.
int mountPointDepth = m_medium.mountPoint().contains( '/', false );
int locationDepth = location.contains( '/', false );
if( m_medium.mountPoint().endsWith( "/" ) )
mountPointDepth--;
if( location.endsWith( "/") )
locationDepth--;
// the locationDepth indicates the filename, in the following loop
// however, we only look at the direcories. hence i < locationDepth
// instead of '<='
for( int i = mountPointDepth;
i < locationDepth;
i++ )
{
TQString firstpart = location.section( '/', 0, i-1 );
TQString secondpart = cleanPath( location.section( '/', i, i ) );
KURL url = KURL::fromPathOrURL( firstpart + '/' + secondpart );
if( !KIO::NetAccess::exists( url, false, m_parent ) )
{
debug() << "directory does not exist, creating..." << url << endl;
if( !KIO::NetAccess::mkdir(url, m_view ) ) //failed
{
debug() << "Failed to create directory " << url << endl;
return;
}
}
}
}
TQString
GenericMediaDevice::buildPodcastDestination( const PodcastEpisodeBundle *bundle )
{
TQString location = m_podcastLocation.endsWith("/") ? m_podcastLocation : m_podcastLocation + '/';
// get info about the PodcastChannel
TQString parentUrl = bundle->parent().url();
TQString sql = "SELECT title,parent FROM podcastchannels WHERE url='" + CollectionDB::instance()->escapeString( parentUrl ) + "';";
TQStringList values = CollectionDB::instance()->query( sql );
TQString channelTitle;
int parent = 0;
channelTitle = values.first();
parent = values.last().toInt();
// Put the file in a directory tree like in the playlistbrowser
sql = "SELECT name,parent FROM podcastfolders WHERE id=%1;";
TQString name;
while ( parent > 0 )
{
values = CollectionDB::instance()->query( sql.tqarg( parent ) );
name = values.first();
parent = values.last().toInt();
location += cleanPath( name ) + '/';
}
location += cleanPath( channelTitle ) + '/' + cleanPath( bundle->localUrl().filename() );
return location;
}
MediaItem *
GenericMediaDevice::copyTrackToDevice( const MetaBundle& bundle )
{
if( !m_connected ) return 0;
// use different naming schemes for differen kinds of tracks
TQString path = m_transferDir;
debug() << "bundle exists: " << bundle.podcastBundle() << endl;
if( bundle.podcastBundle() )
path += buildPodcastDestination( bundle.podcastBundle() );
else
path += buildDestination( m_songLocation, bundle );
checkAndBuildLocation( path );
const KURL desturl = KURL::fromPathOrURL( path );
//kapp->processEvents( 100 );
if( !kioCopyTrack( bundle.url(), desturl ) )
{
debug() << "Failed to copy track: " << bundle.url().pathOrURL() << " to " << desturl.pathOrURL() << endl;
return 0;
}
refreshDir( m_transferDir );
//the return value just can't be null, as nothing is done with it
//other than to see if it is NULL or not
//if we're here the transfer shouldn't have failed, so we shouldn't get into a loop by waiting...
while( !m_view->firstChild() )
kapp->processEvents( 100 );
return static_cast<MediaItem*>(m_view->firstChild());
}
//Somewhat related...
MediaItem *
GenericMediaDevice::trackExists( const MetaBundle& bundle )
{
TQString key;
TQString path = buildDestination( m_songLocation, bundle);
KURL url( path );
TQStringList directories = TQStringList::split( "/", url.directory(1,1), false );
TQListViewItem *it = view()->firstChild();
for( TQStringList::Iterator directory = directories.begin();
directory != directories.end();
directory++ )
{
key = *directory;
while( it && it->text( 0 ) != key )
it = it->nextSibling();
if( !it )
return 0;
if( !it->childCount() )
expandItem( it );
it = it->firstChild();
}
key = url.fileName( true );
key = key.isEmpty() ? fileName( bundle ) : key;
while( it && it->text( 0 ) != key )
it = it->nextSibling();
return dynamic_cast<MediaItem *>( it );
}
/// File transfer methods
void
GenericMediaDevice::downloadSelectedItems()
{
KURL::List urls = getSelectedItems();
CollectionView::instance()->organizeFiles( urls, i18n("Copy Files to Collection"), true );
hideProgress();
}
KURL::List
GenericMediaDevice::getSelectedItems()
{
return m_view->nodeBuildDragList( static_cast<MediaItem*>(m_view->firstChild()), true );
}
/// Deleting
int
GenericMediaDevice::deleteItemFromDevice( MediaItem *item, int /*flags*/ )
{
if( !item || !m_connected ) return -1;
#define item static_cast<GenericMediaItem*>(item)
TQString path = m_mim[item]->getFullName();
debug() << "Deleting path: " << path << endl;
if ( !KIO::NetAccess::del( KURL::fromPathOrURL(path), m_view ))
{
debug() << "Could not delete!" << endl;
return -1;
}
if( m_mim[item] == m_initialFile )
{
m_mim[item]->deleteAll( false );
debug() << "Not deleting root directory of mount!" << endl;
path = m_initialFile->getFullName();
}
else
{
path = m_mim[item]->getParent()->getFullName();
m_mim[item]->deleteAll( true );
}
refreshDir( path );
setProgress( progress() + 1 );
#undef item
return 1;
}
/// Directory Reading
void
GenericMediaDevice::expandItem( TQListViewItem *item ) // SLOT
{
if( !item || !item->isExpandable() ) return;
#define item static_cast<GenericMediaItem *>(item)
m_dirListerComplete = false;
listDir( m_mim[item]->getFullName() );
#undef item
while( !m_dirListerComplete )
{
kapp->processEvents( 100 );
usleep(10000);
}
}
void
GenericMediaDevice::listDir( const TQString &dir )
{
m_dirListerComplete = false;
if( m_mfm[dir]->getListed() )
m_dirLister->updateDirectory( KURL::fromPathOrURL(dir) );
else
{
m_dirLister->openURL( KURL::fromPathOrURL(dir), true, true );
m_mfm[dir]->setListed( true );
}
}
void
GenericMediaDevice::refreshDir( const TQString &dir )
{
m_dirListerComplete = false;
m_dirLister->updateDirectory( KURL::fromPathOrURL(dir) );
}
void
GenericMediaDevice::newItems( const KFileItemList &items )
{
TQPtrListIterator<KFileItem> it( items );
KFileItem *kfi;
while ( (kfi = it.current()) != 0 ) {
++it;
addTrackToList( kfi->isFile() ? MediaItem::TRACK : MediaItem::DIRECTORY, kfi->url(), 0 );
}
}
void
GenericMediaDevice::dirListerCompleted()
{
m_dirListerComplete = true;
}
void
GenericMediaDevice::dirListerClear()
{
m_initialFile->deleteAll( true );
m_view->clear();
m_mfm.clear();
m_mim.clear();
KURL tempurl = KURL::fromPathOrURL( m_medium.mountPoint() );
TQString newMountPoint = tempurl.isLocalFile() ? tempurl.path( -1 ) : tempurl.prettyURL( -1 ); //no trailing slash
m_initialFile = new GenericMediaFile( 0, newMountPoint, this );
}
void
GenericMediaDevice::dirListerClear( const KURL &url )
{
TQString directory = url.pathOrURL();
GenericMediaFile *vmf = m_mfm[directory];
if( vmf )
vmf->deleteAll( false );
}
void
GenericMediaDevice::dirListerDeleteItem( KFileItem *fileitem )
{
TQString filename = fileitem->url().pathOrURL();
GenericMediaFile *vmf = m_mfm[filename];
if( vmf )
vmf->deleteAll( true );
}
int
GenericMediaDevice::addTrackToList( int type, KURL url, int /*size*/ )
{
TQString path = url.isLocalFile() ? url.path( -1 ) : url.prettyURL( -1 ); //no trailing slash
int index = path.findRev( '/', -1 );
TQString baseName = path.right( path.length() - index - 1 );
TQString parentName = path.left( index );
GenericMediaFile* parent = m_mfm[parentName];
GenericMediaFile* newItem = new GenericMediaFile( parent, baseName, this );
if( type == MediaItem::DIRECTORY ) //directory
newItem->getViewItem()->setType( MediaItem::DIRECTORY );
//TODO: this logic could maybe be taken out later...or the dirlister shouldn't
//filter, one or the other...depends if we want to allow viewing any files
//or just update the list in the plugin as appropriate
else if( type == MediaItem::TRACK ) //file
{
if( baseName.endsWith( "mp3", false ) || baseName.endsWith( "wma", false ) ||
baseName.endsWith( "wav", false ) || baseName.endsWith( "ogg", false ) ||
baseName.endsWith( "asf", false ) || baseName.endsWith( "flac", false ) ||
baseName.endsWith( "aac", false ) || baseName.endsWith( "m4a", false ) )
newItem->getViewItem()->setType( MediaItem::TRACK );
else
newItem->getViewItem()->setType( MediaItem::UNKNOWN );
}
refreshDir( parent->getFullName() );
return 0;
}
/// Capacity, in kB
bool
GenericMediaDevice::getCapacity( KIO::filesize_t *total, KIO::filesize_t *available )
{
if( !m_connected || !KURL::fromPathOrURL( m_medium.mountPoint() ).isLocalFile() ) return false;
KDiskFreeSp* kdf = new KDiskFreeSp( TQT_TQOBJECT(m_parent), "generic_kdf" );
kdf->readDF( m_medium.mountPoint() );
connect(kdf, TQT_SIGNAL(foundMountPoint( const TQString &, unsigned long, unsigned long, unsigned long )),
TQT_SLOT(foundMountPoint( const TQString &, unsigned long, unsigned long, unsigned long )));
int count = 0;
while( m_kBSize == 0 && m_kBAvail == 0){
usleep( 10000 );
kapp->processEvents( 100 );
count++;
if (count > 120){
debug() << "KDiskFreeSp taking too long. Returning false from getCapacity()" << endl;
return false;
}
}
*total = m_kBSize*1024;
*available = m_kBAvail*1024;
unsigned long localsize = m_kBSize;
m_kBSize = 0;
m_kBAvail = 0;
return localsize > 0;
}
void
GenericMediaDevice::foundMountPoint( const TQString & mountPoint, unsigned long kBSize, unsigned long /*kBUsed*/, unsigned long kBAvail )
{
if ( mountPoint == m_medium.mountPoint() ){
m_kBSize = kBSize;
m_kBAvail = kBAvail;
}
}
/// Helper functions
void
GenericMediaDevice::rmbPressed( TQListViewItem* qitem, const TQPoint& point, int )
{
enum Actions { APPEND, LOAD, TQUEUE,
DOWNLOAD,
BURN_DATACD, BURN_AUDIOCD,
DIRECTORY, RENAME,
DELETE, TRANSFER_HERE };
MediaItem *item = static_cast<MediaItem *>(qitem);
if ( item )
{
KPopupMenu menu( m_view );
menu.insertItem( SmallIconSet( Amarok::icon( "playlist" ) ), i18n( "&Load" ), LOAD );
menu.insertItem( SmallIconSet( Amarok::icon( "1downarrow" ) ), i18n( "&Append to Playlist" ), APPEND );
menu.insertItem( SmallIconSet( Amarok::icon( "fastforward" ) ), i18n( "&Queue Tracks" ), TQUEUE );
menu.insertSeparator();
menu.insertItem( SmallIconSet( Amarok::icon( "collection" ) ), i18n( "&Copy Files to Collection..." ), DOWNLOAD );
menu.insertItem( SmallIconSet( Amarok::icon( "cdrom_unmount" ) ), i18n( "Burn to CD as Data" ), BURN_DATACD );
menu.setItemEnabled( BURN_DATACD, K3bExporter::isAvailable() );
menu.insertItem( SmallIconSet( Amarok::icon( "cdaudio_unmount" ) ), i18n( "Burn to CD as Audio" ), BURN_AUDIOCD );
menu.setItemEnabled( BURN_AUDIOCD, K3bExporter::isAvailable() );
menu.insertSeparator();
menu.insertItem( SmallIconSet( Amarok::icon( "folder" ) ), i18n( "Add Directory" ), DIRECTORY );
menu.insertItem( SmallIconSet( Amarok::icon( "edit" ) ), i18n( "Rename" ), RENAME );
menu.insertItem( SmallIconSet( Amarok::icon( "remove" ) ), i18n( "Delete" ), DELETE );
menu.insertSeparator();
// NOTE: need better icon
menu.insertItem( SmallIconSet( Amarok::icon( "add_playlist" ) ), i18n( "Transfer Queue to Here..." ), TRANSFER_HERE );
menu.setItemEnabled( TRANSFER_HERE, MediaBrowser::queue()->childCount() );
int id = menu.exec( point );
switch( id )
{
case LOAD:
Playlist::instance()->insertMedia( getSelectedItems(), Playlist::Replace );
break;
case APPEND:
Playlist::instance()->insertMedia( getSelectedItems(), Playlist::Append );
break;
case TQUEUE:
Playlist::instance()->insertMedia( getSelectedItems(), Playlist::Queue );
break;
case DOWNLOAD:
downloadSelectedItems();
break;
case BURN_DATACD:
K3bExporter::instance()->exportTracks( getSelectedItems(), K3bExporter::DataCD );
break;
case BURN_AUDIOCD:
K3bExporter::instance()->exportTracks( getSelectedItems(), K3bExporter::AudioCD );
break;
case DIRECTORY:
if( item->type() == MediaItem::DIRECTORY )
m_view->newDirectory( static_cast<MediaItem*>(item) );
else
m_view->newDirectory( static_cast<MediaItem*>(item->parent()) );
break;
case RENAME:
m_view->rename( item, 0 );
break;
case DELETE:
deleteFromDevice();
break;
case TRANSFER_HERE:
#define item static_cast<GenericMediaItem*>(item)
if( item->type() == MediaItem::DIRECTORY )
m_transferDir = m_mim[item]->getFullName();
else
m_transferDir = m_mim[item]->getParent()->getFullName();
#undef item
emit startTransfer();
break;
}
return;
}
if( isConnected() )
{
KPopupMenu menu( m_view );
menu.insertItem( SmallIconSet( Amarok::icon( "folder" ) ), i18n("Add Directory" ), DIRECTORY );
if ( MediaBrowser::queue()->childCount())
{
menu.insertSeparator();
menu.insertItem( SmallIconSet( Amarok::icon( "add_playlist" ) ), i18n(" Transfer queue to here..." ), TRANSFER_HERE );
}
int id = menu.exec( point );
switch( id )
{
case DIRECTORY:
m_view->newDirectory( 0 );
break;
case TRANSFER_HERE:
m_transferDir = m_medium.mountPoint();
emit startTransfer();
break;
}
}
}
TQString GenericMediaDevice::cleanPath( const TQString &component )
{
TQString result = Amarok::cleanPath( component );
if( m_asciiTextOnly )
result = Amarok::asciiPath( result );
result.simplifyWhiteSpace();
if( m_spacesToUnderscores )
result.replace( TQRegExp( "\\s" ), "_" );
if( m_actuallyVfat || m_vfatTextOnly )
result = Amarok::vfatPath( result );
result.replace( "/", "-" );
return result;
}
/// File Information functions
bool GenericMediaDevice::isPlayable( const MetaBundle& bundle )
{
for( TQStringList::Iterator it = m_supportedFileTypes.begin(); it != m_supportedFileTypes.end() ; it++ )
{
if( bundle.type().lower() == (*it).lower() )
return true;
}
return false;
}
bool GenericMediaDevice::isPreferredFormat( const MetaBundle &bundle )
{
return m_supportedFileTypes.first().lower() == bundle.type().lower();
}
/// Configuration Dialog Extension
void GenericMediaDevice::addConfigElements( TQWidget * parent )
{
m_configDialog = new GenericMediaDeviceConfigDialog( parent );
m_configDialog->setDevice( this );
}
void GenericMediaDevice::removeConfigElements( TQWidget * /* parent */ )
{
if( m_configDialog != 0 )
delete m_configDialog;
m_configDialog = 0;
}
#include "genericmediadevice.moc"