2 // C++ Implementation: mediumpluginmanager
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 "mediumpluginmanager.h"
17 #include "deviceconfiguredialog.h"
18 #include "mediadevicemanager.h"
19 #include "devicemanager.h"
20 #include "hintlineedit.h"
21 #include "mediabrowser.h"
23 #include "plugin/pluginconfig.h"
24 #include "pluginmanager.h"
25 #include "statusbar.h"
27 #include <k3activelabel.h>
28 #include <KApplication>
31 #include <KIconLoader>
34 #include <KPushButton>
37 #include <QAbstractButton>
38 #include <q3groupbox.h>
41 #include <QSignalMapper>
45 using Amarok::escapeHTMLAttr
;
47 typedef QMap
<QString
, Medium
*> MediumMap
;
51 QString
escapeHTMLAttr( const QString
&s
)
53 return QString(s
).replace( "%", "%25" ).replace( "'", "%27" ).replace( "\"", "%22" ).replace( "#", "%23" ).replace( "?", "%3F" );
56 QString
unescapeHTMLAttr( const QString
&s
)
58 return QString(s
).replace( "%3F", "?" ).replace( "%23", "#" ).replace( "%22", "\"" ).replace( "%27", "'" ).replace( "%25", "%" );
62 MediumPluginManagerDialog::MediumPluginManagerDialog()
63 : KPageDialog( Amarok::mainWindow() )
65 setObjectName( "mediumpluginmanagerdialog" );
67 setButtons( Ok
| Cancel
);
68 setDefaultButton( Ok
);
70 kapp
->setTopWidget( this );
71 setCaption( KDialog::makeStandardCaption( i18n( "Manage Devices and Plugins" ) ) );
73 KVBox
*vbox
= new KVBox( this );
74 setMainWidget( vbox
);
76 vbox
->setSpacing( KDialog::spacingHint() );
77 vbox
->setSizePolicy( QSizePolicy( QSizePolicy::Expanding
, QSizePolicy::Expanding
) );
79 m_location
= new Q3GroupBox( 1, Qt::Vertical
, i18n( "Devices" ), vbox
);
80 m_location
->setSizePolicy( QSizePolicy( QSizePolicy::Expanding
, QSizePolicy::Preferred
) );
81 m_devicesBox
= new KVBox( m_location
);
82 m_devicesBox
->setSizePolicy( QSizePolicy( QSizePolicy::Expanding
, QSizePolicy::Expanding
) );
84 m_manager
= new MediumPluginManager( m_devicesBox
);
86 KHBox
*hbox
= new KHBox( vbox
);
87 KPushButton
*detectDevices
= new KPushButton( i18n( "Autodetect Devices" ), hbox
);
88 detectDevices
->setSizePolicy( QSizePolicy( QSizePolicy::Expanding
, QSizePolicy::Fixed
) );
89 connect( detectDevices
, SIGNAL( clicked() ), m_manager
, SLOT( redetectDevices() ) );
91 KPushButton
*addButton
= new KPushButton( i18n( "Add Device..." ), hbox
);
92 addButton
->setSizePolicy( QSizePolicy( QSizePolicy::Expanding
, QSizePolicy::Fixed
) );
93 connect( addButton
, SIGNAL( clicked() ), m_manager
, SLOT( newDevice() ) );
94 connect( this,SIGNAL(okClicked()),this,SLOT(slotOk()));
97 MediumPluginManagerDialog::~MediumPluginManagerDialog()
103 MediumPluginManagerDialog::slotOk()
105 m_manager
->finished();
106 //KPageDialog::slotOk();
107 slotButtonClicked( Ok
);
110 MediumPluginManager::MediumPluginManager( QWidget
*widget
, const bool nographics
)
113 detectDevices( false, nographics
);
115 connect( this, SIGNAL( selectedPlugin( const Medium
*, const QString
) ), MediaBrowser::instance(), SLOT( pluginSelected( const Medium
*, const QString
) ) );
118 MediumPluginManager::~MediumPluginManager()
123 MediumPluginManager::hasChanged()
125 bool temp
= m_hasChanged
;
126 m_hasChanged
= false;
131 MediumPluginManager::slotChanged()//slot
138 MediumPluginManager::detectDevices( const bool redetect
, const bool nographics
)
140 bool foundNew
= false;
141 KConfigGroup config
= Amarok::config( "MediaBrowser" );
143 DeviceManager::instance()->reconcileMediumMap();
144 MediumMap mmap
= MediaDeviceManager::instance()->getMediumMap();
145 for( MediumMap::Iterator it
= mmap
.begin(); it
!= mmap
.end(); it
++ )
147 if( !config
.readEntry( (*it
)->id(), QString() ).isEmpty() &&
148 config
.readEntry( (*it
)->id(), QString() ) == "deleted" && !redetect
)
150 debug() << "skipping: deleted";
154 bool skipflag
= false;
156 for( DeviceList::Iterator dit
= m_deviceList
.begin();
157 dit
!= m_deviceList
.end();
160 if( (*it
)->id() == (*dit
)->medium()->id() )
163 debug() << "skipping: already listed";
167 if( m_deletedMap
.contains( (*it
)->id() ) && !(*it
)->isAutodetected() )
170 debug() << "skipping: deleted & not autodetect";
176 if( m_deletedMap
.contains( (*it
)->id() ) )
177 m_deletedMap
.remove( (*it
)->id() );
179 MediaDeviceConfig
*dev
= new MediaDeviceConfig( *it
, this, nographics
, m_widget
);
180 m_deviceList
.append( dev
);
181 connect( dev
, SIGNAL(deleteMedium(Medium
*)), SLOT(deleteMedium(Medium
*)) );
190 MediumPluginManager::redetectDevices()
192 if( !detectDevices( true ) )
194 Amarok::StatusBar::instance()->longMessageThreadSafe( i18n("No new media devices were found. If you feel this is an\n"
195 "error, ensure that the DBUS and HAL daemons are running\n"
196 "and KDE was built with support for them. You can test this\n"
198 " \"qdbus org.kde.kded /modules/mediamanager fullList\"\n"
199 "in a Konsole window.") );
206 MediumPluginManager::deleteMedium( Medium
*medium
)
208 for( DeviceList::Iterator it
= m_deviceList
.begin();
209 it
!= m_deviceList
.end();
212 if( (*it
)->medium() == medium
)
214 m_deletedMap
[medium
->id()] = medium
;
215 m_deviceList
.remove( *it
);
223 MediumPluginManager::finished()
225 for( DeviceList::Iterator it
= m_deviceList
.begin();
226 it
!= m_deviceList
.end();
229 if( (*it
)->plugin() != (*it
)->oldPlugin() )
231 (*it
)->setOldPlugin( (*it
)->plugin() );
232 emit
selectedPlugin( (*it
)->medium(), (*it
)->plugin() );
234 (*it
)->configButton()->setEnabled( (*it
)->pluginCombo()->currentText() != i18n( "Do not handle" ) );
237 KConfigGroup config
= Amarok::config( "MediaBrowser" );
238 for( DeletedMap::Iterator dit
= m_deletedMap
.begin();
239 dit
!= m_deletedMap
.end();
242 if( dit
.data()->isAutodetected() )
243 config
.writeEntry( dit
.data()->id(), "deleted" );
245 config
.deleteEntry( dit
.data()->id() );
246 MediaDeviceManager::instance()->removeManualDevice( dit
.data() );
248 m_deletedMap
.clear();
252 MediumPluginManager::newDevice()
255 ManualDeviceAdder
* mda
= new ManualDeviceAdder( this );
256 if( mda
->exec() == QDialog::Accepted
&& mda
->successful() )
258 if( !Amarok::config( "MediaBrowser" ).readEntry( mda
->getMedium()->id(), QString() ).isNull() )
260 //abort! Can't have the same device defined twice...should never
261 //happen due to name checking earlier...right?
262 Amarok::StatusBar::instance()->longMessageThreadSafe( i18n("Sorry, you cannot define two devices\n"
263 "with the same name and mountpoint!") );
267 Medium
*newdev
= new Medium( mda
->getMedium() );
268 Amarok::config( "MediaBrowser" ).writeEntry( newdev
->id(), mda
->getPlugin() );
269 MediaDeviceManager::instance()->addManualDevice( newdev
);
277 /////////////////////////////////////////////////////////////////////
279 ManualDeviceAdder::ManualDeviceAdder( MediumPluginManager
* mpm
)
280 : KPageDialog( Amarok::mainWindow() )
282 setObjectName( "manualdeviceadder" );
284 setButtons( Ok
| Cancel
);
285 setDefaultButton( Ok
);
289 m_successful
= false;
292 kapp
->setTopWidget( this );
293 setCaption( KDialog::makeStandardCaption( i18n( "Add New Device") ) );
295 KHBox
* hbox
= new KHBox( this );
296 setMainWidget( hbox
);
297 hbox
->setSpacing( KDialog::spacingHint() );
299 KVBox
* vbox1
= new KVBox( hbox
);
301 new QLabel( i18n( "Select the plugin to use with this device:"), vbox1
);
302 m_mdaCombo
= new KComboBox( false, vbox1
);
303 m_mdaCombo
->setObjectName( "m_mdacombo" );
304 m_mdaCombo
->addItem( i18n( "Do not handle" ) );
305 for( KService::List::ConstIterator it
= MediaBrowser::instance()->getPlugins().begin();
306 it
!= MediaBrowser::instance()->getPlugins().end();
308 m_mdaCombo
->addItem( (*it
)->name() );
310 new QLabel( "", vbox1
);
311 QLabel
* nameLabel
= new QLabel( vbox1
);
312 nameLabel
->setText( i18n( "Enter a &name for this device (required):" ) );
313 m_mdaName
= new HintLineEdit( QString(), vbox1
);
314 nameLabel
->setBuddy( m_mdaName
);
315 m_mdaName
->setHint( i18n( "Example: My_Ipod" ) );
316 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." ) );
318 new QLabel( "", vbox1
);
319 QLabel
* mpLabel
= new QLabel( vbox1
);
320 mpLabel
->setText( i18n( "Enter the &mount point of the device, if applicable:" ) );
321 m_mdaMountPoint
= new HintLineEdit( QString(), vbox1
);
322 mpLabel
->setBuddy( m_mdaMountPoint
);
323 m_mdaMountPoint
->setHint( i18n( "Example: /mnt/ipod" ) );
324 m_mdaMountPoint
->setToolTip( i18n( "Enter the device's mount point. Some devices (such as iRiver iFP 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." ) );
326 connect( m_mdaCombo
, SIGNAL( activated(const QString
&) ), this, SLOT( comboChanged(const QString
&) ) );
329 ManualDeviceAdder::~ManualDeviceAdder()
333 delete m_mdaMountPoint
;
337 ManualDeviceAdder::slotButtonClicked( KDialog::ButtonCode button
)
339 if( button
!= KDialog::Ok
)
340 KDialog::slotButtonClicked( button
);
341 if( getMedium( true ) && !getMedium()->name().isEmpty() &&
342 MediaDeviceManager::instance()->getDevice( getMedium()->name() ) == NULL
)
345 slotButtonClicked( Ok
);
349 Amarok::StatusBar::instance()->longMessageThreadSafe( i18n("Sorry, every device must have a name and\n"
350 "you cannot define two devices with the\n"
351 "same name. These names must be unique\n"
352 "across autodetected devices as well.\n") );
357 ManualDeviceAdder::comboChanged( const QString
&string
)
359 //best thing to do here would be to find out if the plugin selected
360 //has m_hasMountPoint set to false...but any way to do this
361 //without instantiating it? This way will suffice for now...
362 if( MediaBrowser::instance()->getInternalPluginName( string
) == "ifp-mediadevice" ||
363 MediaBrowser::instance()->getInternalPluginName( string
) == "daap-mediadevice" ||
364 MediaBrowser::instance()->getInternalPluginName( string
) == "mtp-mediadevice" ||
365 MediaBrowser::instance()->getInternalPluginName( string
) == "njb-mediadevice" )
367 m_comboOldText
= m_mdaMountPoint
->text();
368 m_mdaMountPoint
->setText( QString() );
369 m_mdaMountPoint
->setEnabled(false);
371 else if( m_mdaMountPoint
->isEnabled() == false )
373 m_mdaMountPoint
->setText( m_comboOldText
);
374 m_mdaMountPoint
->setEnabled(true);
376 m_selectedPlugin
= MediaBrowser::instance()->getInternalPluginName( string
);
380 ManualDeviceAdder::getMedium( bool recreate
)
385 if( m_newMed
&& recreate
)
391 if( m_mdaMountPoint
->isEnabled() == false &&
392 m_mdaName
->text().isNull() )
394 if( m_mdaMountPoint
->text().isNull() &&
395 m_mdaName
->text().isNull() )
397 QString id
= "manual|" + m_mdaName
->text() + '|' +
398 ( m_mdaMountPoint
->text().isNull() ||
399 m_mdaMountPoint
->isEnabled() == false ?
400 "(null)" : m_mdaMountPoint
->text() );
401 m_newMed
= new Medium( id
, m_mdaName
->text() );
402 m_newMed
->setAutodetected( false );
403 m_newMed
->setMountPoint( m_mdaMountPoint
->text() );
407 MediaDeviceConfig::MediaDeviceConfig( Medium
*medium
, MediumPluginManager
*mgr
, const bool nographics
, QWidget
*parent
, const char *name
)
411 , m_configButton( 0 )
412 , m_removeButton( 0 )
418 setObjectName( name
);
420 KConfigGroup config
= Amarok::config( "MediaBrowser" );
421 m_oldPlugin
= config
.readEntry( m_medium
->id(), QString() );
422 if( !m_oldPlugin
.isEmpty() )
425 setSizePolicy( QSizePolicy( QSizePolicy::Expanding
, QSizePolicy::Fixed
) );
428 const QString labelTextNone
= i18n( "(none)" );
429 QString row
= "<tr><td>%1</td><td>%2</td></tr>";
431 table
+= row
.arg( Qt::escape( i18n( "Autodetected:" ) ),
432 Qt::escape( medium
->isAutodetected() ? i18n("Yes") : i18n("No") ) );
433 table
+= row
.arg( Qt::escape( i18n( "ID:" ) ),
434 Qt::escape( medium
->id() ) );
435 table
+= row
.arg( Qt::escape( i18n( "Name:" ) ),
436 Qt::escape( medium
->name() ) );
437 table
+= row
.arg( Qt::escape( i18n( "Label:" ) ),
438 Qt::escape( medium
->label().isEmpty() ? labelTextNone
: medium
->label() ) );
439 table
+= row
.arg( Qt::escape( i18n( "User Label:" ) ),
440 Qt::escape( medium
->userLabel().isEmpty() ? labelTextNone
: medium
->userLabel() ) );
441 table
+= row
.arg( Qt::escape( i18n( "Device Node:" ) ),
442 Qt::escape( medium
->deviceNode().isEmpty() ? labelTextNone
: medium
->deviceNode() ) );
443 table
+= row
.arg( Qt::escape( i18n( "Mount Point:" ) ),
444 Qt::escape( medium
->mountPoint().isEmpty() ? labelTextNone
: medium
->mountPoint() ) );
445 table
+= row
.arg( Qt::escape( i18n( "Mime Type:" ) ),
446 Qt::escape( medium
->mimeType().isEmpty() ? labelTextNone
: medium
->mimeType() ) );
448 QString title
= Qt::escape( i18n( "Device information for %1").arg(medium
->name() ) );
449 QString details
= QString( "<em>%1</em><br />" "<table>%2</table>" ).arg( title
, table
);
451 (void)new QLabel( i18n("Name: "), this );
452 (void)new QLabel( medium
->name(), this );
453 (void)new K3ActiveLabel( i18n( "(<a href='whatsthis:%1'>Details</a>)" )
454 .arg( Amarok::escapeHTMLAttr( details
) ), this );
456 (void)new QLabel( i18n("Plugin:"), this );
457 m_pluginCombo
= new KComboBox( false, this );
458 m_pluginCombo
->addItem( i18n( "Do not handle" ) );
460 for( KService::List::ConstIterator it
= MediaBrowser::instance()->getPlugins().begin();
461 it
!= MediaBrowser::instance()->getPlugins().end();
463 m_pluginCombo
->addItem( (*it
)->name() );
464 if ( (*it
)->property( "X-KDE-Amarok-name" ).toString() == config
.readEntry( medium
->id(), QString() ) )
465 m_pluginCombo
->setCurrentItem( (*it
)->name() );
468 m_configButton
= new KPushButton( KIcon(KIcon( Amarok::icon( "configure" ) )), QString(), this );
469 connect( m_configButton
, SIGNAL(clicked()), SLOT(configureDevice()) );
470 m_configButton
->setEnabled( !m_new
&& m_pluginCombo
->currentText() != i18n( "Do not handle" ) );
471 m_configButton
->setToolTip( i18n( "Configure device settings" ) );
473 m_removeButton
= new KPushButton( i18n( "Remove" ), this );
474 connect( m_removeButton
, SIGNAL(clicked()), SLOT(deleteDevice()) );
475 m_removeButton
->setToolTip( i18n( "Remove entries corresponding to this device from configuration file" ) );
477 connect( m_pluginCombo
, SIGNAL(activated(const QString
&)), m_manager
, SLOT(slotChanged()) );
478 connect( this, SIGNAL(changed()), m_manager
, SLOT(slotChanged()) );
484 MediaDeviceConfig::~MediaDeviceConfig()
489 MediaDeviceConfig::isNew()
495 MediaDeviceConfig::medium()
501 MediaDeviceConfig::plugin()
503 return MediaBrowser::instance()->getInternalPluginName( m_pluginCombo
->currentText() );
507 MediaDeviceConfig::oldPlugin()
513 MediaDeviceConfig::setOldPlugin( const QString
&oldPlugin
)
515 m_oldPlugin
= oldPlugin
;
519 MediaDeviceConfig::configButton()
521 return m_configButton
;
525 MediaDeviceConfig::removeButton()
527 return m_removeButton
;
531 MediaDeviceConfig::pluginCombo()
533 return m_pluginCombo
;
537 MediaDeviceConfig::configureDevice() //slot
539 DeviceConfigureDialog
* dcd
= new DeviceConfigureDialog( m_medium
);
545 MediaDeviceConfig::deleteDevice() //slot
547 //TODO:save something in amarokrc such that it's not shown again until hit autoscan
548 //m_deletedMap[medium->id()] = medium;
549 emit
deleteMedium( medium() );
553 #include "mediumpluginmanager.moc"