Git commit dc4e28253ae573e6860999b40fa4fd523971eb41 by Bart Cerneels. Committed on 13/10/2011 at 09:29. Pushed by shanachie into branch 'master'.
Reimplement UmsCollection without cruft. removed UmsHandler etc. This new UMS plugin uses the Amarok collectionscanner. It is possible to store the batchfile so scanning is not required unless something changed. Other changes: * Add MemoryMeta convinience class. * Don't put UMS stuff in Collections namespace. * Add filename scheme to the UMS config dialog and user TrackOrganizer class. TODO: * View errors in the collection browser. Needs looking at by experienced CV/QM person. CCMAIL: amarok-dev at kde.org GUI:UMS configuration changes DIGEST:Completely reimplemented USB Mass Storage media device plugin M +3 -16 src/core-impl/collections/umscollection/CMakeLists.txt M +552 -23 src/core-impl/collections/umscollection/UmsCollection.cpp M +116 -15 src/core-impl/collections/umscollection/UmsCollection.h A +222 -0 src/core-impl/collections/umscollection/UmsCollectionLocation.cpp [License: GPL (v2+)] A +89 -0 src/core-impl/collections/umscollection/UmsCollectionLocation.h [License: GPL (v2+)] M +263 -26 src/core-impl/collections/umscollection/UmsConfiguration.ui M +3 -0 src/core-impl/collections/umscollection/podcasts/UmsPodcastMeta.cpp M +14 -11 src/core-impl/collections/umscollection/podcasts/UmsPodcastProvider.cpp M +1 -4 src/core-impl/collections/umscollection/podcasts/UmsPodcastProvider.h M +1 -1 src/dialogs/TrackOrganizer.h http://commits.kde.org/amarok/dc4e28253ae573e6860999b40fa4fd523971eb41 diff --git a/src/core-impl/collections/umscollection/CMakeLists.txt b/src/core-impl/collections/umscollection/CMakeLists.txt index 37944d3..d39a546 100644 --- a/src/core-impl/collections/umscollection/CMakeLists.txt +++ b/src/core-impl/collections/umscollection/CMakeLists.txt @@ -1,13 +1,7 @@ include_directories( ../.. ../../collections - ../mediadevicecollection - ../mediadevicecollection/support - ../mediadevicecollection/handler - ../mediadevicecollection/handler/capabilities - handler - handler/capabilities + ../../metadata/audible podcasts - support ${CMAKE_BINARY_DIR}/src ${AMAROK_COLLECTION_SUPPORT_DIR} ${KDE4_INCLUDE_DIR} @@ -18,16 +12,9 @@ include_directories( ../.. set(amarok_collection-umscollection_PART_SRCS UmsCollection.cpp - handler/UmsHandler.cpp -# handler/capabilities/UmsArtworkCapability.cpp -# handler/capabilities/UmsPlaylistCapability.cpp - handler/capabilities/UmsPodcastCapability.cpp - handler/capabilities/UmsReadCapability.cpp - handler/capabilities/UmsWriteCapability.cpp + UmsCollectionLocation.cpp podcasts/UmsPodcastProvider.cpp - podcasts/UmsPodcastMeta.cpp - support/UmsDeviceInfo.cpp - support/UmsConnectionAssistant.cpp) + podcasts/UmsPodcastMeta.cpp) kde4_add_ui_files(amarok_collection-umscollection_PART_SRCS UmsConfiguration.ui diff --git a/src/core-impl/collections/umscollection/UmsCollection.cpp b/src/core-impl/collections/umscollection/UmsCollection.cpp index 2085da4..403fba9 100644 --- a/src/core-impl/collections/umscollection/UmsCollection.cpp +++ b/src/core-impl/collections/umscollection/UmsCollection.cpp @@ -1,5 +1,5 @@ /**************************************************************************************** - * Copyright (c) 2009 Alejandro Wainzinger <aikawarazuni at gmail.com> * + * Copyright (c) 2011 Bart Cerneels <bart.cerneels at kde.org> * * * * 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 * @@ -17,21 +17,42 @@ #define DEBUG_PREFIX "UmsCollection" #include "UmsCollection.h" -#include "UmsConnectionAssistant.h" -#include "UmsDeviceInfo.h" -#include "MediaDeviceInfo.h" +#include "UmsCollectionLocation.h" #include "amarokconfig.h" +#include "core/capabilities/ActionsCapability.h" #include "core/support/Debug.h" +#include "core/meta/Meta.h" -#include <KUrl> +#include "core-impl/collections/support/MemoryQueryMaker.h" +#include "core-impl/collections/support/MemoryMeta.h" +#include "core-impl/meta/file/File.h" + +#include "dialogs/FilenameLayoutDialog.h" +#include "dialogs/TrackOrganizer.h" //TODO: move to core/utils + +#include "scanner/GenericScanManager.h" + +#include "ui_UmsConfiguration.h" -using namespace Collections; +#include <solid/deviceinterface.h> +#include <solid/devicenotifier.h> +#include <solid/genericinterface.h> +#include <solid/opticaldisc.h> +#include <solid/portablemediaplayer.h> +#include <solid/storageaccess.h> +#include <solid/storagedrive.h> +#include <solid/storagevolume.h> + +#include <KDiskFreeSpaceInfo> +#include <kmimetype.h> +#include <KUrl> AMAROK_EXPORT_COLLECTION( UmsCollectionFactory, umscollection ) UmsCollectionFactory::UmsCollectionFactory( QObject *parent, const QVariantList &args ) - : MediaDeviceCollectionFactory<UmsCollection>( parent, args, new UmsConnectionAssistant() ) + : CollectionFactory( parent, args ) + , m_initialized( false ) { m_info = KPluginInfo( "amarok_collection-umscollection.desktop", "services" ); } @@ -40,22 +61,216 @@ UmsCollectionFactory::~UmsCollectionFactory() { } +void +UmsCollectionFactory::init() +{ + connect( Solid::DeviceNotifier::instance(), SIGNAL( deviceAdded( const QString & ) ), + SLOT( slotAddSolidDevice( const QString & ) ) ); + connect( Solid::DeviceNotifier::instance(), SIGNAL( deviceRemoved( const QString & ) ), + SLOT( slotRemoveSolidDevice( const QString & ) ) ); + + m_initialized = true; + + QList<Solid::Device> usbDrives = + Solid::Device::listFromQuery( "[IS StorageDrive AND StorageDrive.bus=='Usb']" ); + foreach( Solid::Device drive, usbDrives ) + { + debug() << "USB StorageDrive detected on startup: " << drive.udi(); + //search for volumes on this USB drive + QList<Solid::Device> usbStorages = + Solid::Device::listFromType( Solid::DeviceInterface::StorageAccess, drive.udi() ); + foreach( Solid::Device storage, usbStorages ) + { + debug() << "partition on a USB drive discovered: " << storage.udi(); + //HACK: seems to be a bug in Solid + if( !storage.is<Solid::StorageAccess>() ) + continue; + //TODO: blacklisted devices + slotAddSolidDevice( storage.udi() ); + } + } +} + +void +UmsCollectionFactory::slotAddSolidDevice( const QString &udi ) +{ + if( m_umsCollectionMap.keys().contains( udi ) ) + return; + + Solid::Device device( udi ); + if( !device.is<Solid::StorageAccess>() ) + return; + + //HACK: ignore apple stuff until we have common MediaDeviceFactory. + if( device.vendor().contains("apple", Qt::CaseInsensitive) ) + return; + + debug() << "Found new USB Mass Storage device with udi = " << device.udi(); + debug() << "Device name is " << device.product() << " and was made by " << device.vendor(); + debug() << "Device product is " << device.product(); + debug() << "Device description: " << device.description(); + + UmsCollection *umsCollection = new UmsCollection( device ); + m_umsCollectionMap.insert( udi, umsCollection ); + emit newCollection( umsCollection ); +} + +void +UmsCollectionFactory::slotRemoveSolidDevice( const QString &udi ) +{ + if( !m_umsCollectionMap.keys().contains( udi ) ) + return; + + UmsCollection *removedCollection = m_umsCollectionMap.take( udi ); + removedCollection->slotDeviceRemoved(); +} + //UmsCollection -UmsCollection::UmsCollection(MediaDeviceInfo* info) - : MediaDeviceCollection() +QString UmsCollection::s_settingsFileName( ".is_audio_player" ); +QString UmsCollection::s_musicFolderKey( "audio_folder" ); +QString UmsCollection::s_musicFilenameSchemeKey( "music_filenamescheme" ); +QString UmsCollection::s_vfatSafeKey( "vfat_safe" ); +QString UmsCollection::s_asciiOnlyKey( "ascii_only" ); +QString UmsCollection::s_ignoreTheKey( "ignore_the" ); +QString UmsCollection::s_replaceSpacesKey( "replace_spaces" ); +QString UmsCollection::s_regexTextKey( "regex_text" ); +QString UmsCollection::s_replaceTextKey( "replace_text" ); +QString UmsCollection::s_podcastFolderKey( "podcast_folder" ); +QString UmsCollection::s_autoConnectKey( "use_automatically" ); + +UmsCollection::UmsCollection( Solid::Device device ) + : Collection() + , m_device( device ) + , m_mc( new MemoryCollection() ) + , m_vfatSafe( true ) + , m_asciiOnly( false ) + , m_ignoreThe( false ) + , m_replaceSpaces( false ) + , m_regexText( QString() ) + , m_replaceText( QString() ) + , m_scanManager( 0 ) { - DEBUG_BLOCK - /** Fetch Info needed to construct UmsCollection */ - UmsDeviceInfo *umsinfo = qobject_cast<UmsDeviceInfo *>( info ); + debug() << "creating device with udi: " << m_device.udi(); + Solid::StorageAccess *storageAccess = m_device.as<Solid::StorageAccess>(); + connect( storageAccess, SIGNAL(accessibilityChanged( bool, QString )), + SLOT(slotAccessibilityChanged( bool, QString )) ); - m_mountPoint = umsinfo->mountpoint(); + if( storageAccess->isAccessible() ) + init(); +} + +void +UmsCollection::init() +{ + Solid::StorageAccess *storageAccess = m_device.as<Solid::StorageAccess>(); + m_mountPoint = storageAccess->filePath(); debug() << "Mounted at: " << m_mountPoint; - m_udi = umsinfo->udi(); - m_handler = new Meta::UmsHandler( this, m_mountPoint ); + m_configureAction = new QAction( KIcon( "configure" ), i18n( "&Configure %1", prettyName() ), + this ); + m_configureAction->setProperty( "popupdropper_svg_id", "configure" ); + connect( m_configureAction, SIGNAL( triggered() ), SLOT( slotConfigure() ) ); + + m_parseAction = new QAction( KIcon( "checkbox" ), i18n( "&Use as Collection" ), this ); + m_parseAction->setProperty( "popupdropper_svg_id", "edit" ); + connect( m_parseAction, SIGNAL( triggered() ), this, SLOT( parseTracks() ) ); + + m_ejectAction = new QAction( KIcon( "media-eject" ), i18n( "&Disconnect Device" ), + const_cast<UmsCollection*>( this ) ); + m_ejectAction->setProperty( "popupdropper_svg_id", "eject" ); + connect( m_ejectAction, SIGNAL( triggered() ), SLOT( slotEject() ) ); + + KUrl playerFilePath( m_mountPoint ); + playerFilePath.addPath( s_settingsFileName ); + QFile playerFile( playerFilePath.toLocalFile() ); + //prevent BR 259849: no audio_folder key in .is_audio_player file. + m_musicPath = m_mountPoint; + + if( playerFile.open( QIODevice::ReadOnly | QIODevice::Text ) ) + { + debug() << QString( "Found %1 file").arg( s_settingsFileName ); + QTextStream in(&playerFile); + while( !in.atEnd() ) + { + QString line = in.readLine(); + if( line.startsWith( s_musicFolderKey + "=" ) ) + { + debug() << QString( "Found %1" ).arg( s_musicFolderKey ); + debug() << line; + m_musicPath = KUrl( m_mountPoint ); + m_musicPath.addPath( line.section( '=', 1, 1 ) ); + m_musicPath.cleanPath(); + debug() << "Scan for music in " << m_musicPath.toLocalFile(); + if( !QDir( m_musicPath.toLocalFile() ).exists() ) + { + debug() << "Music path doesn't exist! Using the mountpoint instead"; + //TODO: add user-visible warning after string freeze. + m_musicPath = m_mountPoint; + } + } + else if( line.startsWith( s_musicFilenameSchemeKey + "=" ) ) + { + m_musicFilenameScheme = line.section( '=', 1, 1 ); + debug() << QString( "filename scheme: %1" ).arg( m_musicFilenameScheme ); + } + else if( line.startsWith( s_vfatSafeKey + "=" ) ) + { + m_vfatSafe = ( line.section( '=', 1, 1 ) == "true" ); + debug() << "vfat compatible: " << m_vfatSafe; + } + else if( line.startsWith( s_asciiOnlyKey + "=" ) ) + { + m_asciiOnly = ( line.section( '=', 1, 1 ) == "true" ); + debug() << "ASCII only: " << m_asciiOnly; + } + else if( line.startsWith( s_ignoreTheKey + "=" ) ) + { + m_ignoreThe = ( line.section( '=', 1, 1 ) == "true" ); + debug() << "ignore The in artist names: " << m_ignoreThe; + } + else if( line.startsWith( s_replaceSpacesKey + "=" ) ) + { + m_replaceSpaces = ( line.section( '=', 1, 1 ) == "true" ); + debug() << "replace spaces with underscores: " << m_replaceSpaces; + } + else if( line.startsWith( s_regexTextKey + "=" ) ) + { + m_regexText = line.section( '=', 1, 1 ); + debug() << "Regex match string: " << m_regexText; + } + else if( line.startsWith( s_replaceTextKey + "=" ) ) + { + m_replaceText = line.section( '=', 1, 1 ); + debug() << "Replace string: " << m_replaceText; + } + else if( line.startsWith( s_podcastFolderKey + "=" ) ) + { + debug() << QString( "Found %1, initializing UMS podcast provider" ) + .arg( s_podcastFolderKey ); + debug() << line; + m_podcastPath = KUrl( m_mountPoint ); + m_podcastPath.addPath( line.section( '=', 1, 1 ) ); + m_podcastPath.cleanPath(); + debug() << "scan for podcasts in " << + m_podcastPath.toLocalFile( KUrl::AddTrailingSlash ); + } + else if( line.startsWith( s_autoConnectKey + "=" ) ) + { + debug() << "Use automatically: " << line.section( '=', 1, 1 ); + m_autoConnect = ( line.section( '=', 1, 1 ) == "true" ); + } + } + } + + if( m_autoConnect ) + slotParseTracks(); } +UmsCollection::~UmsCollection() +{ + DEBUG_BLOCK +} bool UmsCollection::possiblyContainsTrack( const KUrl &url ) const @@ -70,26 +285,340 @@ UmsCollection::trackForUrl( const KUrl &url ) QString uid = QUrl::fromPercentEncoding( url.url().toUtf8() ); if( uid.startsWith("file://") ) uid = uid.remove( 0, 7 ); - Meta::TrackPtr umsTrack = memoryCollection()->trackMap().value( uid ); - return umsTrack ? umsTrack : Collection::trackForUrl(url); + return m_mc->trackMap().value( uid, Meta::TrackPtr() ); } -UmsCollection::~UmsCollection() +QueryMaker * +UmsCollection::queryMaker() { - DEBUG_BLOCK + return new MemoryQueryMaker( m_mc.toWeakRef(), collectionId() ); +} + +bool +UmsCollection::isDirInCollection( const QString &path ) +{ + return path.startsWith( m_musicPath.path() ); } QString -UmsCollection::collectionId() const +UmsCollection::uidUrlProtocol() const { - return m_mountPoint; + return QString( "file://" ); } QString UmsCollection::prettyName() const { - return m_handler->prettyName(); + if( !m_device.description().isEmpty() ) + return m_device.description(); + + QString name = m_device.vendor().simplified(); + if( !name.isEmpty() ) + name += " "; + name += m_device.product().simplified(); + + return name; +} + +KIcon +UmsCollection::icon() const +{ + if( m_device.icon().isEmpty() ) + return KIcon( "drive-removable-media-usb-pendrive" ); + else + return KIcon( m_device.icon() ); } -#include "UmsCollection.moc" +bool +UmsCollection::hasCapacity() const +{ + if( m_device.isValid() && m_device.is<Solid::StorageAccess>() ) + return m_device.as<Solid::StorageAccess>()->isAccessible(); + return false; +} + +float +UmsCollection::usedCapacity() const +{ + return KDiskFreeSpaceInfo::freeSpaceInfo( m_mountPoint ).used(); +} + +float +UmsCollection::totalCapacity() const +{ + return KDiskFreeSpaceInfo::freeSpaceInfo( m_mountPoint ).size(); +} + +CollectionLocation * +UmsCollection::location() const +{ + return new UmsCollectionLocation( this ); +} + +bool +UmsCollection::isWritable() const +{ + //TODO: check writability of music folder + return true; +} +bool +UmsCollection::isOrganizable() const +{ + return isWritable(); +} + +bool +UmsCollection::hasCapabilityInterface( Capabilities::Capability::Type type ) const +{ + switch( type ) + { + case Capabilities::Capability::Actions: + return true; + + default: + return false; + } +} + +Capabilities::Capability* +UmsCollection::createCapabilityInterface( Capabilities::Capability::Type type ) +{ + switch( type ) + { + case Capabilities::Capability::Actions: + { + QList< QAction* > actions; + actions << m_parseAction; + actions << m_configureAction; + actions << m_ejectAction; + return new Capabilities::ActionsCapability( actions ); + } + default: + return 0; + } +} + +KUrl +UmsCollection::organizedUrl( Meta::TrackPtr track ) const +{ + TrackOrganizer trackOrganizer( Meta::TrackList() << track ); + //%folder% prefix required to get absolute url. + trackOrganizer.setFormatString( "%folder%/" + m_musicFilenameScheme + ".%filetype%" ); + trackOrganizer.setVfatSafe( m_vfatSafe ); + trackOrganizer.setAsciiOnly( m_asciiOnly ); + trackOrganizer.setFolderPrefix( m_musicPath.path() ); + trackOrganizer.setIgnoreThe( m_ignoreThe ); + trackOrganizer.setReplaceSpaces( m_replaceSpaces ); + trackOrganizer.setReplace( m_regexText, m_replaceText ); + + return KUrl( trackOrganizer.getDestinations().value( track ) ); +} + +void +UmsCollection::slotDeviceRemoved() +{ + //TODO: stop scanner if running + //unregister PlaylistProvider + //CollectionManager will call destructor. + emit remove(); +} + +void +UmsCollection::slotTrackAdded( KUrl location ) +{ + Q_ASSERT( m_musicPath.isParentOf( location ) ); + MetaFile::TrackPtr track = MetaFile::TrackPtr( new MetaFile::Track( location ) ); + MemoryMeta::MapAdder( m_mc.data() ).addTrack( Meta::TrackPtr::dynamicCast( track ) ); +} + +void +UmsCollection::slotConnectionUpdated() +{ + emit collectionUpdated(); +} + +void +UmsCollection::slotAccessibilityChanged( bool accessible, const QString &udi ) +{ + if( accessible ) + init(); + else + //TODO: de-init so the entry remains valid + emit remove(); +} + +void +UmsCollection::slotParseTracks() +{ + if( !m_scanManager ) + m_scanManager = new GenericScanManager( this ); + + connect( m_scanManager, SIGNAL(directoryScanned( CollectionScanner::Directory * )), + SLOT(slotDirectoryScanned(CollectionScanner::Directory*)) ); + m_scanManager->requestFullScan( QList<KUrl>() << m_musicPath ); +} + +void +UmsCollection::slotConfigure() +{ + KDialog umsSettingsDialog; + QWidget *settingsWidget = new QWidget( &umsSettingsDialog ); + + Ui::UmsConfiguration *settings = new Ui::UmsConfiguration(); + settings->setupUi( settingsWidget ); + + settings->m_autoConnect->setChecked( m_autoConnect ); + + settings->m_musicFolder->setMode( KFile::Directory ); + settings->m_musicCheckBox->setChecked( !m_musicPath.isEmpty() ); + settings->m_musicWidget->setEnabled( settings->m_musicCheckBox->isChecked() ); + settings->m_musicFolder->setUrl( m_musicPath.isEmpty() ? KUrl( m_mountPoint ) : m_musicPath ); + + settings->m_podcastFolder->setMode( KFile::Directory ); + settings->m_podcastCheckBox->setChecked( !m_podcastPath.isEmpty() ); + settings->m_podcastWidget->setEnabled( settings->m_podcastCheckBox->isChecked() ); + settings->m_podcastFolder->setUrl( m_podcastPath.isEmpty() ? KUrl( m_mountPoint ) + : m_podcastPath ); + + FilenameLayoutDialog filenameLayoutDialog( &umsSettingsDialog, 1 ); + //TODO: save the setting that are normally written in onAccept() +// connect( this, SIGNAL(accepted()), &filenameLayoutDialog, SLOT(onAccept()) ); + QVBoxLayout layout( &umsSettingsDialog ); + layout.addWidget( &filenameLayoutDialog ); + settings->m_filenameSchemeBox->setLayout( &layout ); + + filenameLayoutDialog.setScheme( m_musicFilenameScheme ); + filenameLayoutDialog.setVfatCompatible( m_vfatSafe ); + filenameLayoutDialog.setAsciiOnly( m_asciiOnly ); + filenameLayoutDialog.setIgnoreThe( m_ignoreThe ); + filenameLayoutDialog.setReplaceSpaces( m_replaceSpaces ); + filenameLayoutDialog.setRegexpText( m_regexText ); + filenameLayoutDialog.setReplaceText( m_replaceText ); + + umsSettingsDialog.setButtons( KDialog::Ok | KDialog::Cancel ); + umsSettingsDialog.setMainWidget( settingsWidget ); + + umsSettingsDialog.setWindowTitle( i18n( "Configure USB Mass Storage Device" ) ); + + if( umsSettingsDialog.exec() == QDialog::Accepted ) + { + debug() << "accepted"; + + if( settings->m_musicCheckBox->isChecked() ) + { + if( settings->m_musicFolder->url() != m_musicPath ) + { + debug() << "music location changed from " << m_musicPath.toLocalFile() << " to "; + debug() << settings->m_musicFolder->url().toLocalFile(); + m_musicPath = settings->m_musicFolder->url(); + //TODO: reparse music + } + m_musicFilenameScheme = filenameLayoutDialog.getParsableScheme().simplified(); + } + else + { + debug() << "music support is disabled"; + m_musicPath = KUrl(); + //TODO: remove all tracks from the MemoryCollection. + } + + m_vfatSafe = filenameLayoutDialog.vfatCompatible(); + m_asciiOnly = filenameLayoutDialog.asciiOnly(); + m_ignoreThe = filenameLayoutDialog.ignoreThe(); + m_replaceSpaces = filenameLayoutDialog.replaceSpaces(); + m_regexText = filenameLayoutDialog.regexpText(); + m_replaceText = filenameLayoutDialog.replaceText(); + + if( settings->m_podcastCheckBox->isChecked() ) + { + if( settings->m_podcastFolder->url() != m_podcastPath ) + { + debug() << "podcast location changed from " << m_podcastPath << " to "; + debug() << settings->m_podcastFolder->url().url(); + m_podcastPath = settings->m_podcastFolder->url().toLocalFile(); + //TODO: reparse podcasts + } + } + else + { + debug() << "podcast support is disabled"; + m_podcastPath = KUrl(); + //TODO: remove the PodcastProvider + } + + m_autoConnect = settings->m_autoConnect->isChecked(); + if( !m_musicPath.isEmpty() && m_autoConnect ) + slotParseTracks(); + + //write the date to the on-disk file + KUrl localFile = KUrl( m_mountPoint ); + localFile.addPath( s_settingsFileName ); + QFile settingsFile( localFile.toLocalFile() ); + if( settingsFile.open( QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text ) ) + { + QTextStream s( &settingsFile ); + QString keyValuePair( "%1=%2\n" ); + if( !m_musicPath.isEmpty() ) + { + s << keyValuePair.arg( s_musicFolderKey, KUrl::relativePath( m_mountPoint, + m_musicPath.toLocalFile() ) ); + } + + if( !m_musicFilenameScheme.isEmpty() ) + { + s << keyValuePair.arg( s_musicFilenameSchemeKey, m_musicFilenameScheme ); + } + +#define TRUE_FALSE(x) x ? "true" : "false" + s << keyValuePair.arg( s_vfatSafeKey, TRUE_FALSE(m_vfatSafe) ); + s << keyValuePair.arg( s_asciiOnlyKey, TRUE_FALSE(m_asciiOnly) ); + s << keyValuePair.arg( s_ignoreTheKey, TRUE_FALSE(m_ignoreThe) ); + s << keyValuePair.arg( s_replaceSpacesKey, TRUE_FALSE(m_replaceSpaces) ); + s << keyValuePair.arg( s_regexTextKey, m_regexText ); + s << keyValuePair.arg( s_replaceTextKey, m_replaceText ); + + if( !m_podcastPath.isEmpty() ) + { + s << keyValuePair.arg( s_podcastFolderKey, KUrl::relativePath( m_mountPoint, + m_podcastPath.toLocalFile() ) ); + } + + if( m_autoConnect ) + s << keyValuePair.arg( s_autoConnectKey, "true" ); + + settingsFile.close(); + } + else + error() << "Could not open settingsfile " << localFile.toLocalFile(); + } + + delete settings; +} + +void +UmsCollection::slotEject() +{ + Solid::StorageAccess *storageAccess = m_device.as<Solid::StorageAccess>(); + storageAccess->teardown(); +} + +void +UmsCollection::slotDirectoryScanned( CollectionScanner::Directory *dir ) +{ + debug() << "directory scanned: " << dir->path(); + if( dir->tracks().isEmpty() ) + { + debug() << "does not have tracks"; + return; + } + + foreach( const CollectionScanner::Track *scannerTrack, dir->tracks() ) + { + //TODO: use proxy tracks so no real file read is required + slotTrackAdded( scannerTrack->path() ); + } + + collectionUpdated(); + //TODO: read playlists +} diff --git a/src/core-impl/collections/umscollection/UmsCollection.h b/src/core-impl/collections/umscollection/UmsCollection.h index 3f5818b..fbc9648 100644 --- a/src/core-impl/collections/umscollection/UmsCollection.h +++ b/src/core-impl/collections/umscollection/UmsCollection.h @@ -17,54 +17,155 @@ #ifndef UMSCOLLECTION_H #define UMSCOLLECTION_H -#include "UmsHandler.h" - -#include "MediaDeviceCollection.h" -#include "core/support/Debug.h" +#include <core/collections/Collection.h> +#include <core-impl/collections/support/MemoryCollection.h> +#include <utilities/collectionscanner/Directory.h> +#include <KDirWatch> #include <KIcon> +#include <solid/device.h> + #include <QtGlobal> -class MediaDeviceInfo; +using namespace Collections; + +class GenericScanManager; -namespace Collections { +class UmsPodcastProvider; class UmsCollection; -class UmsCollectionFactory : public MediaDeviceCollectionFactory<UmsCollection> +class UmsCollectionLocation; + +class UmsCollectionFactory : public CollectionFactory { Q_OBJECT public: UmsCollectionFactory( QObject *parent, const QVariantList &args ); virtual ~UmsCollectionFactory(); + + virtual void init(); + + signals: + void newCollection( Collections::Collection *newCollection ); + + private slots: + void slotAddSolidDevice( const QString & ); + void slotRemoveSolidDevice( const QString & ); + + private: + bool m_initialized; + + //maps device udi to active UMS collections + QMap<QString, UmsCollection *> m_umsCollectionMap; }; -class UmsCollection : public MediaDeviceCollection +class UmsCollection : public Collection { Q_OBJECT public: // inherited methods - UmsCollection( MediaDeviceInfo* info ); + UmsCollection( Solid::Device device ); virtual ~UmsCollection(); + /* TrackProvider methods */ virtual bool possiblyContainsTrack( const KUrl &url ) const; virtual Meta::TrackPtr trackForUrl( const KUrl &url ); - virtual QString collectionId() const; + /* Collection methods */ + virtual QueryMaker *queryMaker(); + virtual bool isDirInCollection( const QString &path ); + virtual QString uidUrlProtocol() const; + + virtual QString collectionId() const { return m_device.udi(); } virtual QString prettyName() const; - virtual KIcon icon() const { return KIcon("drive-removable-media-usb-pendrive"); }; + virtual KIcon icon() const; + + virtual bool hasCapacity() const; + virtual float usedCapacity() const; + virtual float totalCapacity() const; - // HACK: this function will be deleted later - //void writeDatabase() { m_handler->writeDatabase(); } + virtual CollectionLocation *location() const; + + virtual bool isWritable() const; + virtual bool isOrganizable() const; + + /* Capability-related methods */ + virtual bool hasCapabilityInterface( Capabilities::Capability::Type type ) const; + virtual Capabilities::Capability *createCapabilityInterface( + Capabilities::Capability::Type type ); + + /* own methods */ + const KUrl &musicPath() const { return m_musicPath; } + const KUrl &podcastPath() const { return m_podcastPath; } + + KUrl organizedUrl( Meta::TrackPtr track ) const; + + QSharedPointer<MemoryCollection> memoryCollection() const { return m_mc; } + + signals: + void remove(); + void updated(); + + public slots: + void slotDeviceRemoved(); + void slotTrackAdded( KUrl trackLocation ); + void slotConnectionUpdated(); + + private slots: + void slotAccessibilityChanged( bool accessible, const QString &udi ); + + void slotParseTracks(); + void slotConfigure(); + void slotEject(); + + void slotDirectoryScanned( CollectionScanner::Directory *dir ); private: + void init(); + + //static variables relating to the on-disk configuration file + static QString s_settingsFileName; + static QString s_musicFolderKey; + static QString s_musicFilenameSchemeKey; + static QString s_vfatSafeKey; + static QString s_asciiOnlyKey; + static QString s_ignoreTheKey; + static QString s_replaceSpacesKey; + static QString s_regexTextKey; + static QString s_replaceTextKey; + static QString s_podcastFolderKey; + static QString s_autoConnectKey; + + Solid::Device m_device; + QSharedPointer<MemoryCollection> m_mc; + + bool m_autoConnect; QString m_mountPoint; + KUrl m_musicPath; + KUrl m_podcastPath; + QString m_musicFilenameScheme; + bool m_vfatSafe; + bool m_asciiOnly; + bool m_ignoreThe; + bool m_replaceSpaces; + QString m_regexText; + QString m_replaceText; + + GenericScanManager *m_scanManager; + KDirWatch m_watcher; + + QStringList m_supportedMimeTypes; + + UmsPodcastProvider *m_podcastProvider; + + QAction *m_parseAction; + QAction *m_configureAction; + QAction *m_ejectAction; }; -} //namespace Collections - #endif diff --git a/src/core-impl/collections/umscollection/UmsCollectionLocation.cpp b/src/core-impl/collections/umscollection/UmsCollectionLocation.cpp new file mode 100644 index 0000000..af76da9 --- /dev/null +++ b/src/core-impl/collections/umscollection/UmsCollectionLocation.cpp @@ -0,0 +1,222 @@ +/**************************************************************************************** + * Copyright (c) 2011 Bart Cerneels <bart.cerneels at kde.org> * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY * + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * + * PARTICULAR PURPOSE. See the GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License along with * + * this program. If not, see <http://www.gnu.org/licenses/>. * + ****************************************************************************************/ + +#include "UmsCollectionLocation.h" + +#include "core/support/Components.h" +#include "core/support/Debug.h" +#include "core/interfaces/Logger.h" +#include "core-impl/meta/file/File.h" + +#include <KIO/CopyJob> +#include <KIO/DeleteJob> +#include <kio/job.h> +#include <KUrl> +#include <kio/jobclasses.h> + +UmsCollectionLocation::UmsCollectionLocation( const UmsCollection *umsCollection ) + : CollectionLocation( static_cast<const Collection *>( umsCollection ) ) + , m_umsCollection( umsCollection ) +{ +} + +UmsCollectionLocation::~UmsCollectionLocation() +{ +} + +QString +UmsCollectionLocation::prettyLocation() const +{ + return m_umsCollection->musicPath().toLocalFile( KUrl::RemoveTrailingSlash ); +} + +QStringList +UmsCollectionLocation::actualLocation() const +{ + return QStringList() << prettyLocation(); +} + +bool +UmsCollectionLocation::isWritable() const +{ + return m_umsCollection->isWritable(); +} + +bool +UmsCollectionLocation::isOrganizable() const +{ + return isWritable(); +} + +bool +UmsCollectionLocation::remove( const Meta::TrackPtr &track ) +{ + Q_UNUSED( track ) + /* TODO: implement using MemoryCollection access. + debug() << track->playableUrl().url(); + MetaFile::TrackPtr fileTrack = MetaFile::TrackPtr::dynamicCast( track ); + if( fileTrack.isNull() ) + { + error() << "TrackPtr passed was not a MetaFile::TrackPtr"; + return false; + } + + KUrl filePath = fileTrack->playableUrl(); + if( !m_umsCollection->musicPath().isParentOf( filePath ) ) + { + error() << "This track is not in the music path of this UMS collection"; + return false; + } + */ + + return false; +} + +bool +UmsCollectionLocation::insert( const Meta::TrackPtr &track, const QString &url ) +{ + Q_UNUSED( track ) + Q_UNUSED( url ) + //TODO: implement if really required. UMS does not have a database. + return false; +} + +void +UmsCollectionLocation::copyUrlsToCollection( const QMap<Meta::TrackPtr, KUrl> &sources, + const Transcoding::Configuration &configuration ) +{ + //TODO: transcoding options later + Q_UNUSED( configuration ) + + //TODO: disable scanning until we are done with copying + + QString loggerText = i18n( "Copying %1 tracks to %2" ).arg( sources.count() ) + .arg( m_umsCollection->prettyName() ); + UmsTransferJob *transferJob = new UmsTransferJob( this ); + QMapIterator<Meta::TrackPtr, KUrl> i( sources ); + while( i.hasNext() ) + { + i.next(); + KUrl destination = m_umsCollection->organizedUrl( i.key() ); + debug() << "destination is " << destination.toLocalFile(); + QDir dir( destination.directory() ); + if( !dir.exists() && !dir.mkpath( "." ) ) + { + error() << "could not create directory to copy into."; + return; + } + transferJob->addCopy( i.value(), destination ); + } + connect( transferJob, SIGNAL(fileTransferDone( KUrl )), m_umsCollection, + SLOT(slotTrackAdded( KUrl )) ); + //TODO: make cancelable. + Amarok::Components::logger()->newProgressOperation( transferJob, loggerText, transferJob, + SLOT(slotCancel()) ); + + connect( transferJob, SIGNAL(finished( KJob * )), SLOT(slotCopyOperationFinished()) ); + connect( transferJob, SIGNAL(finished( KJob * )), m_umsCollection, + SLOT(slotConnectionUpdated()) ); + + transferJob->start(); +} + +void +UmsCollectionLocation::removeUrlsFromCollection( const Meta::TrackList &sources ) +{ + KUrl::List sourceUrls; + foreach( const Meta::TrackPtr track, sources ) + sourceUrls << track->playableUrl(); + + QString loggerText = i18n( "Removing %1 tracks from %2" ).arg( sourceUrls.count() ) + .arg( m_umsCollection->prettyName() ); + KIO::DeleteJob *delJob = KIO::del( sourceUrls, KIO::HideProgressInfo ); + //TODO: make cancelable. + Amarok::Components::logger()->newProgressOperation( delJob, loggerText ); + + connect( delJob, SIGNAL(finished( KJob * )), SLOT(slotRemoveOperationFinished()) ); +} + +UmsTransferJob::UmsTransferJob( UmsCollectionLocation *location ) + : KCompositeJob( location ) + , m_location( location ) + , m_cancled( false ) +{ + setCapabilities( KJob::Killable ); +} + +void +UmsTransferJob::addCopy( const KUrl &from, const KUrl &to ) +{ + m_transferList << KUrlPair( from, to ); +} + +void +UmsTransferJob::start() +{ + DEBUG_BLOCK; + if( m_transferList.isEmpty() ) + return; + + startNextJob(); +} + +void +UmsTransferJob::slotCancel() +{ + DEBUG_BLOCK +} + +void +UmsTransferJob::startNextJob() +{ + if( m_transferList.isEmpty() ) + { + emitResult(); + return; + } + + KUrlPair urlPair = m_transferList.takeFirst(); + //TODO: add move as well. + KIO::FileCopyJob *job = KIO::file_copy( urlPair.first, urlPair.second, -1, + KIO::HideProgressInfo ); + connect( job, SIGNAL(percent( KJob *, unsigned long )), + SLOT(slotChildJobPercent( KJob *, unsigned long )) ); + QString loggerText = i18n( "Copying %1 tracks to %2" ).arg( m_transferList.count() ) + .arg( m_location->umsCollection()->prettyName() ); + emit infoMessage( this, loggerText, loggerText ); + addSubjob( job ); +} + +void +UmsTransferJob::slotChildJobPercent( KJob *job, unsigned long percentage ) +{ + Q_UNUSED(job) + emit percent( this, percentage ); +} + +void +UmsTransferJob::slotResult( KJob *job ) +{ + removeSubjob( job ); + + if( job->error() == KJob::NoError ) + { + KIO::FileCopyJob *copyJob = dynamic_cast<KIO::FileCopyJob *>( job ); + if( copyJob ) + emit fileTransferDone( copyJob->destUrl() ); + } + startNextJob(); +} diff --git a/src/core-impl/collections/umscollection/UmsCollectionLocation.h b/src/core-impl/collections/umscollection/UmsCollectionLocation.h new file mode 100644 index 0000000..f77cd7b --- /dev/null +++ b/src/core-impl/collections/umscollection/UmsCollectionLocation.h @@ -0,0 +1,89 @@ +/**************************************************************************************** + * Copyright (c) 2011 Bart Cerneels <bart.cerneels at kde.org> * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY * + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * + * PARTICULAR PURPOSE. See the GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License along with * + * this program. If not, see <http://www.gnu.org/licenses/>. * + ****************************************************************************************/ + +#ifndef UMSCOLLECTIONLOCATION_H +#define UMSCOLLECTIONLOCATION_H + +#include "core/collections/CollectionLocation.h" +#include "UmsCollection.h" + +#include <KJob> +#include <KCompositeJob> + +#include <QList> +#include <QPair> + +class UmsTransferJob; + +class UmsCollectionLocation : public Collections::CollectionLocation +{ + Q_OBJECT + public: + UmsCollectionLocation( const UmsCollection *umsCollection ); + ~UmsCollectionLocation(); + + const UmsCollection *umsCollection() const { return m_umsCollection; } + + /* CollectionLocation methods */ + virtual QString prettyLocation() const; + virtual QStringList actualLocation() const; + virtual bool isWritable() const; + virtual bool isOrganizable() const; + + virtual bool remove( const Meta::TrackPtr &track ); + virtual bool insert( const Meta::TrackPtr &track, const QString &url ); + + virtual void copyUrlsToCollection( const QMap<Meta::TrackPtr, KUrl> &sources, + const Transcoding::Configuration &configuration = Transcoding::Configuration() ); + virtual void removeUrlsFromCollection( const Meta::TrackList &sources ); + + private: + const UmsCollection *m_umsCollection; +}; + +class UmsTransferJob : public KCompositeJob +{ + Q_OBJECT + public: + UmsTransferJob( UmsCollectionLocation *location ); + + virtual void addCopy( const KUrl &from, const KUrl &to ); + virtual void start(); + + signals: + void fileTransferDone( KUrl destination ); + void percent( KJob *job, unsigned long percent ); + void infoMessage( KJob *job, QString plain, QString rich ); + + public slots: + void slotCancel(); + + private slots: + void startNextJob(); + void slotChildJobPercent( KJob *job, unsigned long percentage ); + + //reimplemented from KCompositeJob + virtual void slotResult( KJob *job ); + + private: + UmsCollectionLocation *m_location; + bool m_cancled; + + typedef QPair<KUrl,KUrl> KUrlPair; + QList<KUrlPair> m_transferList; +}; + +#endif // UMSCOLLECTIONLOCATION_H diff --git a/src/core-impl/collections/umscollection/UmsConfiguration.ui b/src/core-impl/collections/umscollection/UmsConfiguration.ui index a6ae315..d9a6365 100644 --- a/src/core-impl/collections/umscollection/UmsConfiguration.ui +++ b/src/core-impl/collections/umscollection/UmsConfiguration.ui @@ -7,7 +7,7 @@ <x>0</x> <y>0</y> <width>706</width> - <height>364</height> + <height>254</height> </rect> </property> <property name="minimumSize"> @@ -19,41 +19,244 @@ <property name="windowTitle"> <string>USB Mass Storage device configuration</string> </property> - <layout class="QFormLayout" name="formLayout"> - <item row="3" column="0"> - <widget class="QLabel" name="label_2"> - <property name="text"> - <string>Music folder:</string> - </property> - </widget> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_3"> + <item> + <widget class="QCheckBox" name="m_autoConnect"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>250</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>100</width> + <height>20</height> + </size> + </property> + <property name="autoFillBackground"> + <bool>false</bool> + </property> + <property name="text"> + <string>Use automatically when connected</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> </item> - <item row="3" column="1"> - <widget class="KUrlRequester" name="m_musicFolder"/> - </item> - <item row="4" column="0"> - <widget class="QLabel" name="label_3"> + <item> + <widget class="QCheckBox" name="m_musicCheckBox"> + <property name="font"> + <font> + <weight>50</weight> + <bold>false</bold> + <underline>false</underline> + </font> + </property> + <property name="toolTip"> + <string extracomment="Enabled music storage on this device"/> + </property> <property name="text"> - <string>Podcast folder:</string> + <string>Music</string> </property> </widget> </item> - <item row="4" column="1"> - <widget class="KUrlRequester" name="m_podcastFolder"/> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>12</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QWidget" name="m_musicWidget" native="true"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="MinimumExpanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_4"> + <item> + <widget class="QLabel" name="label_4"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>200</width> + <height>10</height> + </size> + </property> + <property name="text"> + <string>Music folder:</string> + </property> + </widget> + </item> + <item> + <widget class="KUrlRequester" name="m_musicFolder"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>100</width> + <height>0</height> + </size> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QGroupBox" name="m_filenameSchemeBox"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="MinimumExpanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="title"> + <string>Filename scheme of tracks that are added to the device</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> </item> - <item row="2" column="1"> - <widget class="QCheckBox" name="m_autoConnect"> - <property name="text"> - <string>Enabled</string> + <item> + <widget class="QCheckBox" name="m_podcastCheckBox"> + <property name="font"> + <font> + <weight>50</weight> + <bold>false</bold> + <underline>false</underline> + </font> + </property> + <property name="toolTip"> + <string extracomment="Enabled podcast storage on this device"/> </property> - </widget> - </item> - <item row="2" column="0"> - <widget class="QLabel" name="label"> <property name="text"> - <string>Use automatically when connected</string> + <string>Podcasts</string> </property> </widget> </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_5"> + <item> + <spacer name="horizontalSpacer_3"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>12</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QWidget" name="m_podcastWidget" native="true"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QLabel" name="label_3"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>200</width> + <height>10</height> + </size> + </property> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="text"> + <string>Podcast folder:</string> + </property> + </widget> + </item> + <item> + <widget class="KUrlRequester" name="m_podcastFolder"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>100</width> + <height>0</height> + </size> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + </layout> + </item> </layout> </widget> <customwidgets> @@ -61,8 +264,42 @@ <class>KUrlRequester</class> <extends>QFrame</extends> <header>kurlrequester.h</header> + <container>1</container> </customwidget> </customwidgets> <resources/> - <connections/> + <connections> + <connection> + <sender>m_musicCheckBox</sender> + <signal>toggled(bool)</signal> + <receiver>m_musicWidget</receiver> + <slot>setEnabled(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>12</x> + <y>41</y> + </hint> + <hint type="destinationlabel"> + <x>49</x> + <y>86</y> + </hint> + </hints> + </connection> + <connection> + <sender>m_podcastCheckBox</sender> + <signal>toggled(bool)</signal> + <receiver>m_podcastWidget</receiver> + <slot>setEnabled(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>14</x> + <y>205</y> + </hint> + <hint type="destinationlabel"> + <x>25</x> + <y>236</y> + </hint> + </hints> + </connection> + </connections> </ui> diff --git a/src/core-impl/collections/umscollection/podcasts/UmsPodcastMeta.cpp b/src/core-impl/collections/umscollection/podcasts/UmsPodcastMeta.cpp index ef47829..bba339b 100644 --- a/src/core-impl/collections/umscollection/podcasts/UmsPodcastMeta.cpp +++ b/src/core-impl/collections/umscollection/podcasts/UmsPodcastMeta.cpp @@ -16,7 +16,10 @@ #include "UmsPodcastMeta.h" +#include "core/support/Debug.h" + #include "core-impl/playlists/types/file/PlaylistFileSupport.h" + #include "UmsPodcastProvider.h" using namespace Podcasts; diff --git a/src/core-impl/collections/umscollection/podcasts/UmsPodcastProvider.cpp b/src/core-impl/collections/umscollection/podcasts/UmsPodcastProvider.cpp index 6dbb2f8..1a4a934 100644 --- a/src/core-impl/collections/umscollection/podcasts/UmsPodcastProvider.cpp +++ b/src/core-impl/collections/umscollection/podcasts/UmsPodcastProvider.cpp @@ -19,17 +19,20 @@ #include <KDialog> #include <KIO/DeleteJob> #include <KIO/FileCopyJob> +#include <KIO/Job> #include <KMimeType> +#include <QAction> #include <QDirIterator> +#include <QLabel> #include <QListWidget> #include <QObject> +#include <QVBoxLayout> using namespace Podcasts; -UmsPodcastProvider::UmsPodcastProvider( Meta::UmsHandler *handler, KUrl scanDirectory ) - : m_handler( handler ) - , m_scanDirectory( scanDirectory ) +UmsPodcastProvider::UmsPodcastProvider( KUrl scanDirectory ) + : m_scanDirectory( scanDirectory ) , m_deleteEpisodeAction( 0 ) , m_deleteChannelAction( 0 ) { @@ -152,7 +155,7 @@ UmsPodcastProvider::configureChannel( PodcastChannelPtr channel ) QString UmsPodcastProvider::prettyName() const { - return i18nc( "Podcasts on a media device", "Podcasts on %1", m_handler->prettyName() ); + return i18nc( "Podcasts on a media device", "Podcasts on %1", QString("TODO: replace me") ); } KIcon @@ -267,7 +270,7 @@ UmsPodcastProvider::deleteEpisodes( UmsPodcastEpisodeList umsEpisodes ) layout->addWidget( &label ); layout->addWidget( &listWidget ); dialog.setButtonText( KDialog::Ok, i18n( "Yes, delete from %1.", - m_handler->prettyName() ) ); + QString("TODO: replace me") ) ); dialog.setMainWidget( widget ); if( dialog.exec() != QDialog::Accepted ) @@ -467,15 +470,15 @@ UmsPodcastProvider::addPath( const QString &path ) } else if( info.isFile() ) { - foreach( const QString &mimetype, m_handler->mimetypes() ) - { - if( mime->is( mimetype ) ) - { +// foreach( const QString &mimetype, m_handler->mimetypes() ) +// { +// if( mime->is( mimetype ) ) +// { addFile( MetaFile::TrackPtr( new MetaFile::Track( KUrl( info.canonicalFilePath() ) ) ) ); return 2; - } - } +// } +// } } return 0; diff --git a/src/core-impl/collections/umscollection/podcasts/UmsPodcastProvider.h b/src/core-impl/collections/umscollection/podcasts/UmsPodcastProvider.h index 8d764d3..d46f63d 100644 --- a/src/core-impl/collections/umscollection/podcasts/UmsPodcastProvider.h +++ b/src/core-impl/collections/umscollection/podcasts/UmsPodcastProvider.h @@ -18,7 +18,6 @@ #define UMSPODCASTPROVIDER_H #include "core/podcasts/PodcastProvider.h" -#include "UmsHandler.h" #include "UmsPodcastMeta.h" class KJob; @@ -29,7 +28,7 @@ class UmsPodcastProvider : public PodcastProvider { Q_OBJECT public: - UmsPodcastProvider( Meta::UmsHandler *handler, KUrl scanDirectory ); + UmsPodcastProvider( KUrl scanDirectory ); ~UmsPodcastProvider(); UmsPodcastEpisodePtr addFile( MetaFile::TrackPtr metafileTrack ); @@ -85,10 +84,8 @@ class UmsPodcastProvider : public PodcastProvider void slotCopyComplete( KJob *job ); private: - void deleteEpisodes( UmsPodcastEpisodeList umsEpisodes ); - Meta::UmsHandler *m_handler; KUrl m_scanDirectory; QStringList m_dirList; diff --git a/src/dialogs/TrackOrganizer.h b/src/dialogs/TrackOrganizer.h index f725e33..43d104c 100644 --- a/src/dialogs/TrackOrganizer.h +++ b/src/dialogs/TrackOrganizer.h @@ -29,7 +29,7 @@ * format string. * @author Casey Link */ -class TrackOrganizer : public QObject +class AMAROK_EXPORT TrackOrganizer : public QObject { Q_OBJECT public: