Between the business of school &c. I've been at work
making Media Device code smaller and easier to write, as promised. Here is a preview of the difference in the amount of code required before, and in my git branch after. Let's just look at the MediaDeviceCollectionFactory subclass for Ipods, which keeps track of Ipods connected and talks to Solid.
Before:AMAROK_EXPORT_PLUGIN( IpodCollectionFactory )
IpodCollectionFactory::IpodCollectionFactory()
: Amarok::CollectionFactory()
{
//nothing to do
}
IpodCollectionFactory::~IpodCollectionFactory()
{
DEBUG_BLOCK
}
void
IpodCollectionFactory::init()
{
DEBUG_BLOCK
// connect to the monitor
// connect( this, SIGNAL( ipodDetected( const MediaDeviceInfo & ) ),
// MediaDeviceMonitor::instance(), SIGNAL( deviceDetected( const MediaDeviceInfo & ) ) );
connect( MediaDeviceMonitor::instance(), SIGNAL( ipodReadyToConnect( const QString &, const QString & ) ),
SLOT( ipodDetected( const QString &, const QString & ) ) );
// HACK: emitting old signal to avoid refactoring applet yet
connect( this, SIGNAL( tellIpodDetected( const QString &, const QString & ) ),
MediaDeviceMonitor::instance(), SIGNAL( ipodDetected( const QString &, const QString & ) ) );
connect( MediaDeviceMonitor::instance(), SIGNAL( ipodReadyToDisconnect( const QString & ) ),
SLOT( deviceRemoved( const QString & ) ) );
connect( MediaDeviceMonitor::instance(), SIGNAL( deviceRemoved( const QString & ) ), SLOT( deviceRemoved( const QString & ) ) );
// HACK: Usability: Force auto-connection of device upon detection
checkDevicesForIpod();
}
void
IpodCollectionFactory::ipodDetected( const QString &mountPoint, const QString &udi )
{
DEBUG_BLOCK
IpodCollection* coll = 0;
if( !m_collectionMap.contains( udi ) )
{
debug() << "New Ipod not seen before";
coll = new IpodCollection( mountPoint, udi );
if( coll )
{
// TODO: connect to MediaDeviceMonitor signals
connect( coll, SIGNAL( collectionDisconnected( const QString &) ),
this, SLOT( slotCollectionDisconnected( const QString & ) ) );
m_collectionMap.insert( udi, coll );
emit newCollection( coll );
debug() << "emitting new ipod collection";
}
}
}
void
IpodCollectionFactory::deviceRemoved( const QString &udi )
{
DEBUG_BLOCK
if( m_collectionMap.contains( udi ) )
{
IpodCollection* coll = m_collectionMap[ udi ];
if( coll )
{
m_collectionMap.remove( udi ); // remove from map
coll->deviceRemoved(); //collection will be deleted by collectionmanager
}
else
warning() << "collection already null";
}
else
warning() << "removing non-existent device";
return;
}
void
IpodCollectionFactory::slotCollectionDisconnected( const QString & udi)
{
m_collectionMap.remove( udi ); // remove from map
}
void
IpodCollectionFactory::slotCollectionReady()
{
DEBUG_BLOCK
IpodCollection
collection = dynamic_cast( sender() );
if( collection )
{
debug() << "emitting ipod collection newcollection";
emit newCollection( collection );
}
}
void
IpodCollectionFactory::checkDevicesForIpod()
{
QStringList udiList = MediaDeviceMonitor::instance()->getDevices();
/ poll udi list for supported devices
/
foreach( const QString &udi, udiList )
{
/ if ipod device found, emit signal */
if( isIpod( udi ) )
{
// HACK: Usability: Force auto-connection of device upon detection
QString mountpoint = MediaDeviceCache::instance()->volumeMountPoint(udi);
ipodDetected( mountpoint, udi );
//MediaDeviceInfo
deviceinfo =
new IpodDeviceInfo( mountpoint, udi );
//emit ipodDetected( deviceinfo );
// HACK: emit old signal to avoid refactor of applet yet
emit tellIpodDetected( mountpoint, udi );
}
}
}
bool
IpodCollectionFactory::isIpod( const QString &udi ) const
{
DEBUG_BLOCK
Solid::Device device;
device = Solid::Device(udi);
/ going until we reach a vendor, e.g. Apple
/
while ( device.isValid() && device.vendor().isEmpty() )
{
device = Solid::Device( device.parentUdi() );
}
debug() << "Device udi: " << udi;
debug() << "Device name: " <<>deviceName(udi);
debug() << "Mount point: " <<>volumeMountPoint(udi);
if ( device.isValid() )
{
debug() << "vendor: " << device.vendor() << ", product: " << device.product();
}
/ if iPod found, return true */
return device.product() == "iPod";
}
After:AMAROK_EXPORT_PLUGIN( IpodCollectionFactory )
IpodCollectionFactory::IpodCollectionFactory()
: MediaDeviceCollectionFactory
( new IpodConnectionAssistant() )
{
//nothing to do
}
IpodCollectionFactory::~IpodCollectionFactory()
{
DEBUG_BLOCK
}
----------------------------------------------------------------------------------------------
As you can see (excuse the bad formatting, blogger doesn't take kindly to source code), the amount of code required has been greatly reduced, and the other required classes are soon to follow. Also, things are going to be implemented more in the predictably correct classes now, and after refactoring is done and I've ported both Ipods and MTPs to it, I will write a small tutorial on how to go about implementing your own device. No, UMS will be done by me, heh, but it should be a piece of cake afterward to implement support for some of the other devices some of you miss from Amarok 1.4, so yay!
Unfortunately I'm fairly busy with school too so this proceeds in big bumps every 4-7 days, might take a bit, but getting there. I'm going to Boston next weekend for the KDE GSoC meetup, which should be fun. If you're around, do say hello!