add mp3 and ogg torrent url info to JamendoAlbum
[amarok.git] / src / MediaDevicePluginManager.cpp
blob19dd5cc607b4a8c55e69fe0305a5e4ac250832df
1 //
2 // C++ Implementation: mediadevicepluginmanager
3 //
4 // Description:
5 //
6 //
7 // Authors: Jeff Mitchell <kde-dev@emailgoeshere.com>, (C) 2005, 2006
8 // Martin Aumueller <aumuell@reserv.at>, (C) 2006
9 //
10 // Copyright: See COPYING file that comes with this distribution
13 #include "MediaDevicePluginManager.h"
15 #include "amarok.h"
16 #include "debug.h"
17 #include "deviceconfiguredialog.h"
18 #include "hintlineedit.h"
19 #include "mediabrowser.h"
20 #include "MediaDeviceCache.h"
21 #include "plugin/pluginconfig.h"
22 #include "pluginmanager.h"
23 #include "statusbar.h"
25 #include <k3activelabel.h>
26 #include <KApplication>
27 #include <KComboBox>
28 #include <KConfig>
29 #include <KIconLoader>
30 #include <KLineEdit>
31 #include <KLocale>
32 #include <KPushButton>
33 #include <KVBox>
34 #include <Solid/Device>
36 #include <QAbstractButton>
37 #include <q3groupbox.h>
38 #include <QLabel>
39 #include <QLayout>
40 #include <QSignalMapper>
41 #include <QToolTip>
44 using Amarok::escapeHTMLAttr;
46 typedef QMap<QString, Medium*> MediumMap;
48 namespace Amarok
50 QString escapeHTMLAttr( const QString &s )
52 return QString(s).replace( "%", "%25" ).replace( "'", "%27" ).replace( "\"", "%22" ).replace( "#", "%23" ).replace( "?", "%3F" );
55 QString unescapeHTMLAttr( const QString &s )
57 return QString(s).replace( "%3F", "?" ).replace( "%23", "#" ).replace( "%22", "\"" ).replace( "%27", "'" ).replace( "%25", "%" );
61 MediaDevicePluginManagerDialog::MediaDevicePluginManagerDialog()
62 : KPageDialog( Amarok::mainWindow() )
64 setObjectName( "mediadevicepluginmanagerdialog" );
65 setModal( false );
66 setButtons( Ok | Cancel );
67 setDefaultButton( Ok );
69 kapp->setTopWidget( this );
70 setCaption( KDialog::makeStandardCaption( i18n( "Manage Devices and Plugins" ) ) );
72 KVBox *vbox = new KVBox( this );
73 setMainWidget( vbox );
75 vbox->setSpacing( KDialog::spacingHint() );
76 vbox->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) );
78 m_location = new Q3GroupBox( 1, Qt::Vertical, i18n( "Devices" ), vbox );
79 m_location->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred ) );
80 m_devicesBox = new KVBox( m_location );
81 m_devicesBox->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) );
83 m_manager = new MediaDevicePluginManager( m_devicesBox );
85 KHBox *hbox = new KHBox( vbox );
86 KPushButton *detectDevices = new KPushButton( i18n( "Autodetect Devices" ), hbox);
87 detectDevices->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ) );
88 connect( detectDevices, SIGNAL( clicked() ), m_manager, SLOT( redetectDevices() ) );
90 KPushButton *addButton = new KPushButton( i18n( "Add Device..." ), hbox );
91 addButton->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ) );
92 connect( addButton, SIGNAL( clicked() ), m_manager, SLOT( newDevice() ) );
93 connect( this,SIGNAL(okClicked()),this,SLOT(slotOk()));
96 MediaDevicePluginManagerDialog::~MediaDevicePluginManagerDialog()
98 delete m_manager;
101 void
102 MediaDevicePluginManagerDialog::slotOk()
104 m_manager->finished();
105 slotButtonClicked( Ok );
108 MediaDevicePluginManager::MediaDevicePluginManager( QWidget *widget, const bool nographics )
109 : m_widget( widget )
111 detectDevices( false, nographics );
113 connect( this, SIGNAL( selectedPlugin( const QString &, const QString & ) ), MediaBrowser::instance(), SLOT( pluginSelected( const QString &, const QString & ) ) );
116 MediaDevicePluginManager::~MediaDevicePluginManager()
120 bool
121 MediaDevicePluginManager::detectDevices( const bool redetect, const bool nographics )
123 bool foundNew = false;
124 KConfigGroup config = Amarok::config( "PortableDevices" );
125 if( redetect )
126 MediaDeviceCache::instance()->refreshCache();
127 QStringList deviceList = MediaDeviceCache::instance()->getAll();
128 foreach( QString device, deviceList )
130 if( !config.readEntry( device, QString() ).isEmpty() &&
131 config.readEntry( device, QString() ) == "deleted" && !redetect)
133 debug() << "skipping: deleted";
134 continue;
137 bool skipflag = false;
139 foreach( MediaDeviceConfig* mediadevice, m_deviceList )
141 if( device == mediadevice->uid() )
143 skipflag = true;
144 debug() << "skipping: already listed";
148 if( m_deletedMap.contains( device ) &&
149 !MediaDeviceCache::instance()->deviceType( device ) == MediaDeviceCache::SolidType )
151 skipflag = true;
152 debug() << "skipping: deleted & not autodetect";
155 if( skipflag )
156 continue;
158 if( m_deletedMap.contains( device ) )
159 m_deletedMap.remove( device );
161 MediaDeviceConfig *dev = new MediaDeviceConfig( device, this, nographics, m_widget );
162 m_deviceList.append( dev );
163 connect( dev, SIGNAL(deleteDevice(QString &)), SLOT(deleteDevice(QString &)) );
165 foundNew = true;
168 return foundNew;
171 void
172 MediaDevicePluginManager::redetectDevices()
174 if( !detectDevices( true ) )
176 Amarok::StatusBar::instance()->longMessageThreadSafe( i18n("No new media devices were found. If you feel this is an\n"
177 "error, ensure that the DBUS and HAL daemons are running\n"
178 "and KDE was built with support for them. You can test this\n"
179 "by running\n"
180 " \"qdbus org.kde.kded /modules/mediamanager fullList\"\n"
181 "in a Konsole window.") );
185 void
186 MediaDevicePluginManager::deleteDevice( const QString &uid )
188 for( int i = 0; i < m_deviceList.size(); ++i )
190 if( m_deviceList[i]->uid() == uid )
191 m_deletedMap[uid] = true;
195 void
196 MediaDevicePluginManager::finished()
198 foreach( MediaDeviceConfig* mediadevice, m_deviceList )
200 if( mediadevice->plugin() != mediadevice->oldPlugin() )
202 mediadevice->setOldPlugin( mediadevice->plugin() );
203 emit selectedPlugin( mediadevice->uid(), mediadevice->plugin() );
205 mediadevice->configButton()->setEnabled( mediadevice->pluginCombo()->currentText() != i18n( "Do not handle" ) );
208 KConfigGroup config = Amarok::config( "MediaBrowser" );
209 for( DeletedMap::Iterator dit = m_deletedMap.begin();
210 dit != m_deletedMap.end();
211 ++dit )
213 if( MediaDeviceCache::instance()->deviceType( dit.key() ) == MediaDeviceCache::SolidType )
214 config.writeEntry( dit.key(), "deleted" );
215 else
216 config.deleteEntry( dit.key() );
217 MediaDeviceCache::instance()->refreshCache();
219 m_deletedMap.clear();
222 void
223 MediaDevicePluginManager::newDevice()
225 DEBUG_BLOCK
226 ManualDeviceAdder* mda = new ManualDeviceAdder( this );
227 if( mda->exec() == QDialog::Accepted && mda->successful() )
229 if( !Amarok::config( "PortableDevices" ).readEntry( mda->getId(), QString() ).isNull() )
231 //abort! Can't have the same device defined twice...should never
232 //happen due to name checking earlier...right?
233 Amarok::StatusBar::instance()->longMessageThreadSafe( i18n("Sorry, you cannot define two devices\n"
234 "with the same name and mountpoint!") );
236 else
238 Amarok::config( "PortableDevices" ).writeEntry( mda->getId(), mda->getPlugin() );
239 MediaDeviceCache::instance()->refreshCache();
240 detectDevices();
243 delete mda;
246 /////////////////////////////////////////////////////////////////////
248 ManualDeviceAdder::ManualDeviceAdder( MediaDevicePluginManager* mpm )
249 : KPageDialog( Amarok::mainWindow() )
251 setObjectName( "manualdeviceadder" );
252 setModal( true );
253 setButtons( Ok | Cancel );
254 setDefaultButton( Ok );
257 m_mpm = mpm;
258 m_successful = false;
259 m_newId = QString();
261 kapp->setTopWidget( this );
262 setCaption( KDialog::makeStandardCaption( i18n( "Add New Device") ) );
264 KHBox* hbox = new KHBox( this );
265 setMainWidget( hbox );
266 hbox->setSpacing( KDialog::spacingHint() );
268 KVBox* vbox1 = new KVBox( hbox );
270 new QLabel( i18n( "Select the plugin to use with this device:"), vbox1 );
271 m_mdaCombo = new KComboBox( false, vbox1 );
272 m_mdaCombo->setObjectName( "m_mdacombo" );
273 m_mdaCombo->addItem( i18n( "Do not handle" ) );
274 for( KService::List::ConstIterator it = MediaBrowser::instance()->getPlugins().begin();
275 it != MediaBrowser::instance()->getPlugins().end();
276 ++it )
277 m_mdaCombo->addItem( (*it)->name() );
279 new QLabel( "", vbox1 );
280 QLabel* nameLabel = new QLabel( vbox1 );
281 nameLabel->setText( i18n( "Enter a &name for this device (required):" ) );
282 m_mdaName = new HintLineEdit( QString(), vbox1);
283 nameLabel->setBuddy( m_mdaName );
284 m_mdaName->setHint( i18n( "Example: My_Ipod" ) );
285 m_mdaName->setToolTip( i18n( "Enter a name for the device. The name must be unique across all devices, including autodetected devices. It must not contain the pipe ( | ) character." ) );
287 new QLabel( "", vbox1 );
288 QLabel* mpLabel = new QLabel( vbox1 );
289 mpLabel->setText( i18n( "Enter the &mount point of the device, if applicable:" ) );
290 m_mdaMountPoint = new HintLineEdit( QString(), vbox1);
291 mpLabel->setBuddy( m_mdaMountPoint );
292 m_mdaMountPoint->setHint( i18n( "Example: /mnt/ipod" ) );
293 m_mdaMountPoint->setToolTip( i18n( "Enter the device's mount point. Some devices (such as MTP devices) may not have a mount point and this can be ignored. All other devices (iPods, UMS/VFAT devices) should enter the mount point here." ) );
295 connect( m_mdaCombo, SIGNAL( activated(const QString&) ), this, SLOT( comboChanged(const QString&) ) );
298 ManualDeviceAdder::~ManualDeviceAdder()
300 delete m_mdaName;
301 delete m_mdaMountPoint;
304 void
305 ManualDeviceAdder::slotButtonClicked( KDialog::ButtonCode button)
307 if( button != KDialog::Ok )
308 KDialog::slotButtonClicked( button );
309 if( !getId( true ).isEmpty() &&
310 MediaDeviceCache::instance()->deviceType( m_newId ) == MediaDeviceCache::InvalidType )
312 m_successful = true;
313 slotButtonClicked( Ok );
315 else
317 Amarok::StatusBar::instance()->longMessageThreadSafe( i18n("Sorry, every device must have a name and\n"
318 "you cannot define two devices with the\n"
319 "same name. These names must be unique\n"
320 "across autodetected devices as well.\n") );
324 void
325 ManualDeviceAdder::comboChanged( const QString &string )
327 //best thing to do here would be to find out if the plugin selected
328 //has m_hasMountPoint set to false...but any way to do this
329 //without instantiating it? This way will suffice for now...
330 if( MediaBrowser::instance()->getInternalPluginName( string ) == "ifp-mediadevice" ||
331 MediaBrowser::instance()->getInternalPluginName( string ) == "daap-mediadevice" ||
332 MediaBrowser::instance()->getInternalPluginName( string ) == "mtp-mediadevice" ||
333 MediaBrowser::instance()->getInternalPluginName( string ) == "njb-mediadevice" )
335 m_comboOldText = m_mdaMountPoint->text();
336 m_mdaMountPoint->setText( QString() );
337 m_mdaMountPoint->setEnabled(false);
339 else if( m_mdaMountPoint->isEnabled() == false )
341 m_mdaMountPoint->setText( m_comboOldText );
342 m_mdaMountPoint->setEnabled(true);
344 m_selectedPlugin = MediaBrowser::instance()->getInternalPluginName( string );
347 QString
348 ManualDeviceAdder::getId( bool recreate )
350 if( !recreate )
351 return m_newId;
353 if( !m_newId.isEmpty() && recreate )
355 m_newId = QString();
358 if( m_mdaMountPoint->isEnabled() == false &&
359 m_mdaName->text().isNull() )
360 return QString();
361 if( m_mdaMountPoint->text().isNull() &&
362 m_mdaName->text().isNull() )
363 return QString();
364 m_newId = "manual|" + m_selectedPlugin + '|' +
365 m_mdaName->text() + '|' +
366 ( m_mdaMountPoint->text().isNull() ||
367 m_mdaMountPoint->isEnabled() == false ?
368 "(null)" : m_mdaMountPoint->text() );
369 return m_newId;
372 MediaDeviceConfig::MediaDeviceConfig( QString uid, MediaDevicePluginManager *mgr, const bool nographics, QWidget *parent, const char *name )
373 : KHBox( parent )
374 , m_manager( mgr )
375 , m_uid( uid )
376 , m_configButton( 0 )
377 , m_removeButton( 0 )
378 , m_new( true )
380 setObjectName( name );
382 KConfigGroup config = Amarok::config( "PortableDevices" );
383 m_oldPlugin = config.readEntry( m_uid, QString() );
384 if( !m_oldPlugin.isEmpty() )
385 m_new = false;
387 setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ) );
388 setSpacing( 5 );
390 const QString labelTextNone = i18n( "(none)" );
391 QString row = "<tr><td>%1</td><td>%2</td></tr>";
392 QString table;
393 table += row.arg( Qt::escape( i18n( "Autodetected:" ) ),
394 Qt::escape( MediaDeviceCache::instance()->deviceType( m_uid ) == MediaDeviceCache::SolidType ? i18n("Yes") : i18n("No") ) );
395 table += row.arg( Qt::escape( i18n( "Unique ID:" ) ),
396 Qt::escape( m_uid ) );
397 if( MediaDeviceCache::instance()->deviceType( m_uid ) == MediaDeviceCache::SolidType )
399 Solid::Device device( m_uid );
400 if( device.isValid() )
402 if( !device.vendor().isEmpty() )
403 table += row.arg( Qt::escape( i18n( "Vendor:" ) ),
404 Qt::escape( device.vendor() ) );
405 if( !device.product().isEmpty() )
406 table += row.arg( Qt::escape( i18n( "Product:" ) ),
407 Qt::escape( device.product() ) );
411 QString title = Qt::escape( i18n( "Device information for %1").arg( m_uid ) );
412 QString details = QString( "<em>%1</em><br />" "<table>%2</table>" ).arg( title, table );
414 (void)new QLabel( i18n("Name: "), this );
415 (void)new QLabel( m_uid, this );
416 (void)new K3ActiveLabel( i18n( "(<a href='whatsthis:%1'>Details</a>)" )
417 .arg( Amarok::escapeHTMLAttr( details ) ), this );
419 (void)new QLabel( i18n("Plugin:"), this );
420 m_pluginCombo = new KComboBox( false, this );
421 m_pluginCombo->addItem( i18n( "Do not handle" ) );
423 for( KService::List::ConstIterator it = MediaBrowser::instance()->getPlugins().begin();
424 it != MediaBrowser::instance()->getPlugins().end();
425 ++it ){
426 m_pluginCombo->addItem( (*it)->name() );
427 if ( (*it)->property( "X-KDE-Amarok-name" ).toString() == config.readEntry( m_uid, QString() ) )
428 m_pluginCombo->setCurrentItem( (*it)->name() );
431 m_configButton = new KPushButton( KIcon(KIcon( Amarok::icon( "configure" ) )), QString(), this );
432 connect( m_configButton, SIGNAL(clicked()), SLOT(configureDevice()) );
433 m_configButton->setEnabled( !m_new && m_pluginCombo->currentText() != i18n( "Do not handle" ) );
434 m_configButton->setToolTip( i18n( "Configure device settings" ) );
436 m_removeButton = new KPushButton( i18n( "Remove" ), this );
437 connect( m_removeButton, SIGNAL(clicked()), SLOT(deleteDevice()) );
438 m_removeButton->setToolTip( i18n( "Remove entries corresponding to this device from configuration file" ) );
440 if( !nographics )
441 show();
444 MediaDeviceConfig::~MediaDeviceConfig()
448 void
449 MediaDeviceConfig::configureDevice() //slot
451 MediaDevice *device = MediaBrowser::instance()->deviceFromId( m_uid );
452 if( device )
454 DeviceConfigureDialog* dcd = new DeviceConfigureDialog( device );
455 dcd->exec();
456 delete dcd;
458 else
459 debug() << "Could not show the configuration dialog because the device could not be found.";
462 void
463 MediaDeviceConfig::deleteDevice() //slot
465 emit deleteDevice( m_uid );
466 delete this;
469 QString
470 MediaDeviceConfig::plugin()
472 return MediaBrowser::instance()->getInternalPluginName( m_pluginCombo->currentText() );
476 #include "MediaDevicePluginManager.moc"