2 // C++ Implementation: mediadevicepluginmanager
7 // Authors: Jeff Mitchell <kde-dev@emailgoeshere.com>, (C) 2005, 2006
8 // Martin Aumueller <aumuell@reserv.at>, (C) 2006
10 // Copyright: See COPYING file that comes with this distribution
13 #include "MediaDevicePluginManager.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>
29 #include <KIconLoader>
32 #include <KPushButton>
34 #include <Solid/Device>
36 #include <QAbstractButton>
37 #include <q3groupbox.h>
40 #include <QSignalMapper>
44 using Amarok::escapeHTMLAttr
;
46 typedef QMap
<QString
, Medium
*> MediumMap
;
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" );
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()
102 MediaDevicePluginManagerDialog::slotOk()
104 m_manager
->finished();
105 slotButtonClicked( Ok
);
108 MediaDevicePluginManager::MediaDevicePluginManager( QWidget
*widget
, const bool nographics
)
111 detectDevices( false, nographics
);
113 connect( this, SIGNAL( selectedPlugin( const QString
&, const QString
& ) ), MediaBrowser::instance(), SLOT( pluginSelected( const QString
&, const QString
& ) ) );
116 MediaDevicePluginManager::~MediaDevicePluginManager()
121 MediaDevicePluginManager::detectDevices( const bool redetect
, const bool nographics
)
123 bool foundNew
= false;
124 KConfigGroup config
= Amarok::config( "PortableDevices" );
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";
137 bool skipflag
= false;
139 foreach( MediaDeviceConfig
* mediadevice
, m_deviceList
)
141 if( device
== mediadevice
->uid() )
144 debug() << "skipping: already listed";
148 if( m_deletedMap
.contains( device
) &&
149 !MediaDeviceCache::instance()->deviceType( device
) == MediaDeviceCache::SolidType
)
152 debug() << "skipping: deleted & not autodetect";
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
&)) );
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"
180 " \"qdbus org.kde.kded /modules/mediamanager fullList\"\n"
181 "in a Konsole window.") );
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;
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();
213 if( MediaDeviceCache::instance()->deviceType( dit
.key() ) == MediaDeviceCache::SolidType
)
214 config
.writeEntry( dit
.key(), "deleted" );
216 config
.deleteEntry( dit
.key() );
217 MediaDeviceCache::instance()->refreshCache();
219 m_deletedMap
.clear();
223 MediaDevicePluginManager::newDevice()
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!") );
238 Amarok::config( "PortableDevices" ).writeEntry( mda
->getId(), mda
->getPlugin() );
239 MediaDeviceCache::instance()->refreshCache();
246 /////////////////////////////////////////////////////////////////////
248 ManualDeviceAdder::ManualDeviceAdder( MediaDevicePluginManager
* mpm
)
249 : KPageDialog( Amarok::mainWindow() )
251 setObjectName( "manualdeviceadder" );
253 setButtons( Ok
| Cancel
);
254 setDefaultButton( Ok
);
258 m_successful
= false;
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();
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()
301 delete m_mdaMountPoint
;
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
)
313 slotButtonClicked( Ok
);
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") );
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
);
348 ManualDeviceAdder::getId( bool recreate
)
353 if( !m_newId
.isEmpty() && recreate
)
358 if( m_mdaMountPoint
->isEnabled() == false &&
359 m_mdaName
->text().isNull() )
361 if( m_mdaMountPoint
->text().isNull() &&
362 m_mdaName
->text().isNull() )
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() );
372 MediaDeviceConfig::MediaDeviceConfig( QString uid
, MediaDevicePluginManager
*mgr
, const bool nographics
, QWidget
*parent
, const char *name
)
376 , m_configButton( 0 )
377 , m_removeButton( 0 )
380 setObjectName( name
);
382 KConfigGroup config
= Amarok::config( "PortableDevices" );
383 m_oldPlugin
= config
.readEntry( m_uid
, QString() );
384 if( !m_oldPlugin
.isEmpty() )
387 setSizePolicy( QSizePolicy( QSizePolicy::Expanding
, QSizePolicy::Fixed
) );
390 const QString labelTextNone
= i18n( "(none)" );
391 QString row
= "<tr><td>%1</td><td>%2</td></tr>";
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();
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" ) );
444 MediaDeviceConfig::~MediaDeviceConfig()
449 MediaDeviceConfig::configureDevice() //slot
451 MediaDevice
*device
= MediaBrowser::instance()->deviceFromId( m_uid
);
454 DeviceConfigureDialog
* dcd
= new DeviceConfigureDialog( device
);
459 debug() << "Could not show the configuration dialog because the device could not be found.";
463 MediaDeviceConfig::deleteDevice() //slot
465 emit
deleteDevice( m_uid
);
470 MediaDeviceConfig::plugin()
472 return MediaBrowser::instance()->getInternalPluginName( m_pluginCombo
->currentText() );
476 #include "MediaDevicePluginManager.moc"