|
|
|
// (c) 2004 Christian Muehlhaeuser <chris@chris.de>
|
|
|
|
// (c) 2005-2006 Martin Aumueller <aumuell@reserv.at>
|
|
|
|
// (c) 2005 Seb Ruiz <me@sebruiz.net>
|
|
|
|
// (c) 2006 T.R.Shashwath <trshash84@gmail.com>
|
|
|
|
// See COPYING file for licensing information
|
|
|
|
|
|
|
|
|
|
|
|
#define DEBUG_PREFIX "MediaBrowser"
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include "amarok.h"
|
|
|
|
#include "amarokconfig.h"
|
|
|
|
#include "app.h"
|
|
|
|
#include "browserToolBar.h"
|
|
|
|
#include "clicklineedit.h"
|
|
|
|
#include "collectiondb.h"
|
|
|
|
#include "colorgenerator.h"
|
|
|
|
#include "contextbrowser.h"
|
|
|
|
#include "debug.h"
|
|
|
|
#include "editfilterdialog.h"
|
|
|
|
#include "deviceconfiguredialog.h"
|
|
|
|
#include "mediadevicemanager.h"
|
|
|
|
#include "expression.h"
|
|
|
|
#include "hintlineedit.h"
|
|
|
|
#include "mediabrowser.h"
|
|
|
|
#include "medium.h"
|
|
|
|
#include "mediumpluginmanager.h"
|
|
|
|
#include "metabundle.h"
|
|
|
|
#include "mountpointmanager.h"
|
|
|
|
#include "playlist.h"
|
|
|
|
#include "playlistbrowser.h"
|
|
|
|
#include "playlistbrowseritem.h"
|
|
|
|
#include "playlistloader.h"
|
|
|
|
#include "pluginmanager.h"
|
|
|
|
#include "podcastbundle.h"
|
|
|
|
#include "scriptmanager.h"
|
|
|
|
#include "scrobbler.h"
|
|
|
|
#include "statusbar.h"
|
|
|
|
#include "transferdialog.h"
|
|
|
|
#include "browserToolBar.h"
|
|
|
|
|
|
|
|
#include <tqvbuttongroup.h>
|
|
|
|
#include <tqcheckbox.h>
|
|
|
|
#include <tqdatetime.h>
|
|
|
|
#include <tqdir.h>
|
|
|
|
#include <tqdom.h>
|
|
|
|
#include <tqfileinfo.h>
|
|
|
|
#include <tqgroupbox.h>
|
|
|
|
#include <tqheader.h>
|
|
|
|
#include <tqimage.h>
|
|
|
|
#include <tqlabel.h>
|
|
|
|
#include <tqobjectlist.h>
|
|
|
|
#include <tqpainter.h>
|
|
|
|
#include <tqradiobutton.h>
|
|
|
|
#include <tqsimplerichtext.h>
|
|
|
|
#include <tqtimer.h>
|
|
|
|
#include <tqtooltip.h> //TQToolTip::add()
|
|
|
|
|
|
|
|
#include <kapplication.h> //kapp
|
|
|
|
#include <kcombobox.h>
|
|
|
|
#include <kdirlister.h>
|
|
|
|
#include <kfiledialog.h>
|
|
|
|
#include <kglobal.h>
|
|
|
|
#include <kiconloader.h>
|
|
|
|
#include <kinputdialog.h>
|
|
|
|
#include <kio/job.h>
|
|
|
|
#include <klocale.h>
|
|
|
|
#include <kmessagebox.h>
|
|
|
|
#include <kmultipledrag.h>
|
|
|
|
#include <kpopupmenu.h>
|
|
|
|
#include <kprocess.h>
|
|
|
|
#include <kprogress.h>
|
|
|
|
#include <kpushbutton.h>
|
|
|
|
#include <krun.h>
|
|
|
|
#include <kstandarddirs.h> //locate file
|
|
|
|
#include <ktabbar.h>
|
|
|
|
#include <ktempfile.h>
|
|
|
|
#include <ktoolbarbutton.h> //ctor
|
|
|
|
#include <kurldrag.h> //dragObject()
|
|
|
|
#include <kactioncollection.h>
|
|
|
|
|
|
|
|
|
|
|
|
MediaBrowser *MediaBrowser::s_instance = 0;
|
|
|
|
|
|
|
|
TQPixmap *MediaItem::s_pixUnknown = 0;
|
|
|
|
TQPixmap *MediaItem::s_pixArtist = 0;
|
|
|
|
TQPixmap *MediaItem::s_pixAlbum = 0;
|
|
|
|
TQPixmap *MediaItem::s_pixFile = 0;
|
|
|
|
TQPixmap *MediaItem::s_pixTrack = 0;
|
|
|
|
TQPixmap *MediaItem::s_pixPodcast = 0;
|
|
|
|
TQPixmap *MediaItem::s_pixPlaylist = 0;
|
|
|
|
TQPixmap *MediaItem::s_pixInvisible = 0;
|
|
|
|
TQPixmap *MediaItem::s_pixStale = 0;
|
|
|
|
TQPixmap *MediaItem::s_pixOrphaned = 0;
|
|
|
|
TQPixmap *MediaItem::s_pixDirectory = 0;
|
|
|
|
TQPixmap *MediaItem::s_pixRootItem = 0;
|
|
|
|
TQPixmap *MediaItem::s_pixTransferFailed = 0;
|
|
|
|
TQPixmap *MediaItem::s_pixTransferBegin = 0;
|
|
|
|
TQPixmap *MediaItem::s_pixTransferEnd = 0;
|
|
|
|
|
|
|
|
bool MediaBrowser::isAvailable() //static
|
|
|
|
{
|
|
|
|
if( !MediaBrowser::instance() )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
//to re-enable hiding, uncomment this and get rid of the return true above:
|
|
|
|
//return MediaBrowser::instance()->m_haveDevices;
|
|
|
|
}
|
|
|
|
|
|
|
|
class SpaceLabel : public TQLabel {
|
|
|
|
public:
|
|
|
|
SpaceLabel(TQWidget *parent)
|
|
|
|
: TQLabel(parent)
|
|
|
|
{
|
|
|
|
m_total = m_used = m_scheduled = 0;
|
|
|
|
setBackgroundMode(TQt::NoBackground);
|
|
|
|
}
|
|
|
|
|
|
|
|
void paintEvent(TQPaintEvent *e)
|
|
|
|
{
|
|
|
|
TQPainter p(this);
|
|
|
|
p.fillRect(e->rect(), colorGroup().brush(TQColorGroup::Background));
|
|
|
|
|
|
|
|
if(m_total > 0)
|
|
|
|
{
|
|
|
|
int used = int(float(m_used)/float(m_total)*width());
|
|
|
|
int scheduled = int(float(m_used + m_scheduled)/float(m_total)*width());
|
|
|
|
|
|
|
|
if(m_used > 0)
|
|
|
|
{
|
|
|
|
TQColor blueish(70,120,255);
|
|
|
|
if(e->rect().left() < used)
|
|
|
|
{
|
|
|
|
int right = used;
|
|
|
|
if(e->rect().right() < right)
|
|
|
|
right = e->rect().right();
|
|
|
|
p.fillRect(e->rect().left(), e->rect().top(),
|
|
|
|
used, e->rect().bottom()+1, TQBrush(blueish, TQt::SolidPattern));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(m_scheduled > 0)
|
|
|
|
{
|
|
|
|
TQColor sched(70, 230, 120);
|
|
|
|
if(m_used + m_scheduled > m_total - m_total/200)
|
|
|
|
{
|
|
|
|
sched.setRgb( 255, 120, 120 );
|
|
|
|
}
|
|
|
|
int left = e->rect().left();
|
|
|
|
if(used > left)
|
|
|
|
left = used;
|
|
|
|
int right = e->rect().right();
|
|
|
|
if(scheduled < right)
|
|
|
|
right = scheduled;
|
|
|
|
p.fillRect(left, e->rect().top(), right, e->rect().bottom()+1, TQBrush(sched, TQt::SolidPattern));
|
|
|
|
}
|
|
|
|
|
|
|
|
if(m_used + m_scheduled < m_total)
|
|
|
|
{
|
|
|
|
TQColor grey(180, 180, 180);
|
|
|
|
int left = e->rect().left();
|
|
|
|
if(scheduled > left)
|
|
|
|
left = scheduled;
|
|
|
|
int right = e->rect().right();
|
|
|
|
p.fillRect(left, e->rect().top(), right, e->rect().bottom()+1, colorGroup().brush(TQColorGroup::Background));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
TQLabel::paintEvent(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
KIO::filesize_t m_total;
|
|
|
|
KIO::filesize_t m_used;
|
|
|
|
KIO::filesize_t m_scheduled;
|
|
|
|
};
|
|
|
|
|
|
|
|
class DummyMediaDevice : public MediaDevice
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
DummyMediaDevice() : MediaDevice()
|
|
|
|
{
|
|
|
|
m_name = i18n( "No Device Available" );
|
|
|
|
m_type = "dummy-mediadevice";
|
|
|
|
m_medium = Medium( "DummyDevice", "DummyDevice" );
|
|
|
|
}
|
|
|
|
void init( MediaBrowser *browser ) { MediaDevice::init( browser ); }
|
|
|
|
virtual ~DummyMediaDevice() {}
|
|
|
|
virtual bool isConnected() { return false; }
|
|
|
|
virtual MediaItem* trackExists(const MetaBundle&) { return 0; }
|
|
|
|
virtual bool lockDevice(bool) { return true; }
|
|
|
|
virtual void unlockDevice() {}
|
|
|
|
virtual bool openDevice( bool silent )
|
|
|
|
{
|
|
|
|
if( !silent )
|
|
|
|
{
|
|
|
|
//TQString msg = i18n( "Sorry, you do not have a supported portable music player." );
|
|
|
|
//Amarok::StatusBar::instance()->longMessage( msg, KDE::StatusBar::Sorry );
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
virtual bool closeDevice() { return false; }
|
|
|
|
virtual void synchronizeDevice() {}
|
|
|
|
virtual MediaItem* copyTrackToDevice(const MetaBundle&) { return 0; }
|
|
|
|
virtual int deleteItemFromDevice(MediaItem*, int) { return -1; }
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
MediaBrowser::MediaBrowser( const char *name )
|
|
|
|
: TQVBox( 0, name )
|
|
|
|
, m_timer( new TQTimer( this ) )
|
|
|
|
, m_currentDevice( m_devices.end() )
|
|
|
|
, m_waitForTranscode( false )
|
|
|
|
, m_quitting( false )
|
|
|
|
{
|
|
|
|
s_instance = this;
|
|
|
|
|
|
|
|
// preload pixmaps used in browser
|
|
|
|
KIconLoader iconLoader;
|
|
|
|
MediaItem::s_pixUnknown = new TQPixmap(iconLoader.loadIcon( Amarok::icon( "unknown" ), KIcon::Toolbar, KIcon::SizeSmall ));
|
|
|
|
MediaItem::s_pixTrack = new TQPixmap(iconLoader.loadIcon( Amarok::icon( "playlist" ), KIcon::Toolbar, KIcon::SizeSmall ));
|
|
|
|
MediaItem::s_pixFile = new TQPixmap(iconLoader.loadIcon( Amarok::icon( "sound" ), KIcon::Toolbar, KIcon::SizeSmall ) );
|
|
|
|
MediaItem::s_pixPodcast = new TQPixmap(iconLoader.loadIcon( Amarok::icon( "podcast" ), KIcon::Toolbar, KIcon::SizeSmall ) );
|
|
|
|
MediaItem::s_pixPlaylist = new TQPixmap(iconLoader.loadIcon( Amarok::icon( "playlist" ), KIcon::Toolbar, KIcon::SizeSmall ) );
|
|
|
|
MediaItem::s_pixRootItem = new TQPixmap(iconLoader.loadIcon( Amarok::icon( "files2" ), KIcon::Toolbar, KIcon::SizeSmall ) );
|
|
|
|
// history
|
|
|
|
// favorites
|
|
|
|
// collection
|
|
|
|
// folder
|
|
|
|
// folder_red
|
|
|
|
// player_playlist_2
|
|
|
|
// cancel
|
|
|
|
// sound
|
|
|
|
MediaItem::s_pixArtist = new TQPixmap(iconLoader.loadIcon( Amarok::icon( "personal" ), KIcon::Toolbar, KIcon::SizeSmall ) );
|
|
|
|
MediaItem::s_pixAlbum = new TQPixmap(iconLoader.loadIcon( Amarok::icon( "cdrom_unmount" ), KIcon::Toolbar, KIcon::SizeSmall ) );
|
|
|
|
MediaItem::s_pixInvisible = new TQPixmap(iconLoader.loadIcon( Amarok::icon( "cancel" ), KIcon::Toolbar, KIcon::SizeSmall ) );
|
|
|
|
MediaItem::s_pixStale = new TQPixmap(iconLoader.loadIcon( Amarok::icon( "cancel" ), KIcon::Toolbar, KIcon::SizeSmall ) );
|
|
|
|
MediaItem::s_pixOrphaned = new TQPixmap(iconLoader.loadIcon( Amarok::icon( "cancel" ), KIcon::Toolbar, KIcon::SizeSmall ) );
|
|
|
|
MediaItem::s_pixDirectory = new TQPixmap(iconLoader.loadIcon( Amarok::icon( "folder" ), KIcon::Toolbar, KIcon::SizeSmall ) );
|
|
|
|
MediaItem::s_pixTransferBegin = new TQPixmap(iconLoader.loadIcon( Amarok::icon( "play" ), KIcon::Toolbar, KIcon::SizeSmall ) );
|
|
|
|
MediaItem::s_pixTransferEnd = new TQPixmap(iconLoader.loadIcon( Amarok::icon( "stop" ), KIcon::Toolbar, KIcon::SizeSmall ) );
|
|
|
|
MediaItem::s_pixTransferFailed = new TQPixmap(iconLoader.loadIcon( Amarok::icon( "cancel" ), KIcon::Toolbar, KIcon::SizeSmall ) );
|
|
|
|
|
|
|
|
setSpacing( 4 );
|
|
|
|
|
|
|
|
m_toolbar = new Browser::ToolBar( this );
|
|
|
|
m_toolbar->setIconText( KToolBar::IconTextRight, false );
|
|
|
|
|
|
|
|
m_toolbar->insertButton( "connect_creating", CONNECT, true, i18n("Connect") );
|
|
|
|
TQToolTip::add( m_toolbar->getButton(CONNECT), i18n( "Connect media device" ) );
|
|
|
|
|
|
|
|
m_toolbar->insertButton( "player_eject", DISCONNECT, true, i18n("Disconnect") );
|
|
|
|
TQToolTip::add( m_toolbar->getButton(DISCONNECT), i18n( "Disconnect media device" ) );
|
|
|
|
|
|
|
|
m_toolbar->insertButton( "rebuild", TRANSFER, true, i18n("Transfer") );
|
|
|
|
TQToolTip::add( m_toolbar->getButton(TRANSFER), i18n( "Transfer tracks to media device" ) );
|
|
|
|
|
|
|
|
m_toolbar->insertLineSeparator();
|
|
|
|
|
|
|
|
// m_toolbar->setIconText( KToolBar::IconTextRight, true );
|
|
|
|
m_toolbar->insertButton( Amarok::icon( "add_playlist" ), CUSTOM, TQT_SIGNAL( clicked() ), TQT_TQOBJECT(this), TQT_SLOT( customClicked() ), true, "custom" );
|
|
|
|
TQToolTip::add( m_toolbar->getButton(TRANSFER), i18n( "Transfer tracks to media device" ) );
|
|
|
|
|
|
|
|
m_toolbar->setIconText( KToolBar::IconOnly, false );
|
|
|
|
|
|
|
|
m_toolbar->insertButton( Amarok::icon( "configure" ), CONFIGURE, true, i18n("Configure") );
|
|
|
|
TQToolTip::add( m_toolbar->getButton(CONFIGURE), i18n( "Configure device" ) );
|
|
|
|
|
|
|
|
|
|
|
|
m_deviceCombo = new KComboBox( this );
|
|
|
|
|
|
|
|
// searching/filtering
|
|
|
|
{ //<Search LineEdit>
|
|
|
|
KToolBar* searchToolBar = new Browser::ToolBar( this );
|
|
|
|
KToolBarButton *button = new KToolBarButton( "locationbar_erase", 0, searchToolBar );
|
|
|
|
m_searchEdit = new ClickLineEdit( i18n( "Enter search terms here" ), searchToolBar );
|
|
|
|
KPushButton *filterButton = new KPushButton("...", searchToolBar, "filter");
|
|
|
|
searchToolBar->setStretchableWidget( m_searchEdit );
|
|
|
|
m_searchEdit->setFrame( TQFrame::Sunken );
|
|
|
|
|
|
|
|
connect( button, TQT_SIGNAL( clicked() ), m_searchEdit, TQT_SLOT( clear() ) );
|
|
|
|
connect( filterButton, TQT_SIGNAL( clicked() ), TQT_SLOT( slotEditFilter() ) );
|
|
|
|
|
|
|
|
TQToolTip::add( button, i18n( "Clear filter" ) );
|
|
|
|
TQToolTip::add( m_searchEdit, i18n( "Enter space-separated terms to search" ) );
|
|
|
|
TQToolTip::add( filterButton, i18n( "Click to edit filter" ) );
|
|
|
|
} //</Search LineEdit>
|
|
|
|
|
|
|
|
connect( m_timer, TQT_SIGNAL( timeout() ), TQT_SLOT( slotSetFilter() ) );
|
|
|
|
connect( m_searchEdit, TQT_SIGNAL( textChanged( const TQString& ) ), TQT_SLOT( slotSetFilterTimeout() ) );
|
|
|
|
connect( m_searchEdit, TQT_SIGNAL( returnPressed() ), TQT_SLOT( slotSetFilter() ) );
|
|
|
|
|
|
|
|
// connect to device manager
|
|
|
|
connect( MediaDeviceManager::instance(), TQT_SIGNAL( mediumAdded(const Medium *, TQString) ),
|
|
|
|
TQT_SLOT( mediumAdded(const Medium *, TQString) ) );
|
|
|
|
connect( MediaDeviceManager::instance(), TQT_SIGNAL( mediumChanged(const Medium *, TQString) ),
|
|
|
|
TQT_SLOT( mediumChanged(const Medium *, TQString) ) );
|
|
|
|
connect( MediaDeviceManager::instance(), TQT_SIGNAL( mediumRemoved(const Medium *, TQString) ),
|
|
|
|
TQT_SLOT( mediumRemoved(const Medium *, TQString) ) );
|
|
|
|
|
|
|
|
|
|
|
|
// we always have a dummy device
|
|
|
|
m_pluginName[ i18n( "Disable" ) ] = "dummy-mediadevice";
|
|
|
|
m_pluginAmarokName["dummy-mediadevice"] = i18n( "Disable" );
|
|
|
|
m_pluginName[ i18n( "Do not handle" ) ] = "ignore";
|
|
|
|
m_pluginAmarokName["ignore"] = i18n( "Do not handle" );
|
|
|
|
// query available device plugins
|
|
|
|
m_plugins = PluginManager::query( "[X-KDE-Amarok-plugintype] == 'mediadevice'" );
|
|
|
|
for( KTrader::OfferList::ConstIterator it = m_plugins.begin(); it != m_plugins.end(); ++it ) {
|
|
|
|
// Save name properties in TQMap for lookup
|
|
|
|
m_pluginName[(*it)->name()] = (*it)->property( "X-KDE-Amarok-name" ).toString();
|
|
|
|
m_pluginAmarokName[(*it)->property( "X-KDE-Amarok-name" ).toString()] = (*it)->name();
|
|
|
|
}
|
|
|
|
|
|
|
|
m_views = new TQVBox( this );
|
|
|
|
m_queue = new MediaQueue( this );
|
|
|
|
m_progressBox = new TQHBox( this );
|
|
|
|
m_progress = new KProgress( m_progressBox );
|
|
|
|
m_cancelButton = new KPushButton( SmallIconSet( Amarok::icon( "cancel" ) ), i18n("Cancel"), m_progressBox );
|
|
|
|
|
|
|
|
|
|
|
|
m_stats = new SpaceLabel(this);
|
|
|
|
|
|
|
|
m_progressBox->hide();
|
|
|
|
|
|
|
|
MediaDevice *dev = new DummyMediaDevice();
|
|
|
|
dev->init( this );
|
|
|
|
addDevice( dev );
|
|
|
|
activateDevice( 0, false );
|
|
|
|
queue()->load( Amarok::saveLocation() + "transferlist.xml" );
|
|
|
|
queue()->computeSize();
|
|
|
|
|
|
|
|
setFocusProxy( m_queue );
|
|
|
|
|
|
|
|
updateStats();
|
|
|
|
|
|
|
|
TQMap<TQString, Medium*> mmap = MediaDeviceManager::instance()->getMediumMap();
|
|
|
|
|
|
|
|
bool newflag = false;
|
|
|
|
//This deals with <strike>auto-detectable</strike> ALL devices!
|
|
|
|
for( TQMap<TQString, Medium*>::Iterator it = mmap.begin();
|
|
|
|
it != mmap.end();
|
|
|
|
it++ )
|
|
|
|
{
|
|
|
|
TQString handler = Amarok::config( "MediaBrowser" )->readEntry( (*it)->id() );
|
|
|
|
//debug() << "[MediaBrowser] (*it)->id() = " << (*it)->id() << ", handler = " << handler << endl;
|
|
|
|
if( handler.isEmpty() )
|
|
|
|
{
|
|
|
|
//this should probably never be the case with a manually added device, unless amarokrc's been messed with
|
|
|
|
Amarok::config( "MediaBrowser" )->writeEntry( (*it)->id(), "ignore" );
|
|
|
|
newflag = true;
|
|
|
|
mediumAdded( *it, (*it)->name(), true );
|
|
|
|
}
|
|
|
|
//and this definitely shouldn't!
|
|
|
|
else if( handler != "deleted" )
|
|
|
|
mediumAdded( *it, (*it)->name(), true );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( newflag )
|
|
|
|
Amarok::StatusBar::instance()->longMessageThreadSafe(
|
|
|
|
i18n("Amarok has detected new portable media devices.\n"
|
|
|
|
"Go to the \"Media Devices\" pane of the configuration\n"
|
|
|
|
"dialog to choose a plugin for these devices.") );
|
|
|
|
|
|
|
|
connect( m_toolbar->getButton(CONNECT), TQT_SIGNAL( clicked() ), TQT_SLOT( connectClicked() ) );
|
|
|
|
connect( m_toolbar->getButton(DISCONNECT), TQT_SIGNAL( clicked() ), TQT_SLOT( disconnectClicked() ) );
|
|
|
|
connect( m_toolbar->getButton(TRANSFER), TQT_SIGNAL( clicked() ), TQT_SLOT( transferClicked() ) );
|
|
|
|
connect( m_toolbar->getButton(CONFIGURE), TQT_SIGNAL( clicked() ), TQT_SLOT( config() ) );
|
|
|
|
|
|
|
|
connect( m_deviceCombo, TQT_SIGNAL( activated( int ) ), TQT_SLOT( activateDevice( int ) ) );
|
|
|
|
|
|
|
|
connect( m_cancelButton, TQT_SIGNAL( clicked() ), TQT_SLOT( cancelClicked() ) );
|
|
|
|
connect( pApp, TQT_SIGNAL( prepareToQuit() ), TQT_SLOT( prepareToQuit() ) );
|
|
|
|
connect( CollectionDB::instance(), TQT_SIGNAL( tagsChanged( const MetaBundle& ) ),
|
|
|
|
TQT_SLOT( tagsChanged( const MetaBundle& ) ) );
|
|
|
|
|
|
|
|
m_haveDevices = false;
|
|
|
|
TQMap<TQString,TQString> savedDevices = Amarok::config( "MediaBrowser" )->entryMap( "MediaBrowser" );
|
|
|
|
for( TQMap<TQString,TQString>::Iterator it = savedDevices.begin();
|
|
|
|
it != savedDevices.end();
|
|
|
|
++it )
|
|
|
|
{
|
|
|
|
if( it.data() != "deleted" && it.data() != "ignore" )
|
|
|
|
{
|
|
|
|
m_haveDevices = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
emit availabilityChanged( m_haveDevices );
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
MediaBrowser::blockQuit() const
|
|
|
|
{
|
|
|
|
for( TQValueList<MediaDevice *>::const_iterator it = m_devices.begin();
|
|
|
|
it != m_devices.end();
|
|
|
|
++it )
|
|
|
|
{
|
|
|
|
if( *it && (*it)->isConnected() )
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaBrowser::tagsChanged( const MetaBundle &bundle )
|
|
|
|
{
|
|
|
|
m_itemMapMutex.lock();
|
|
|
|
debug() << "tags changed for " << bundle.url().url() << endl;
|
|
|
|
ItemMap::iterator it = m_itemMap.find( bundle.url().url() );
|
|
|
|
if( it != m_itemMap.end() )
|
|
|
|
{
|
|
|
|
MediaItem *item = *it;
|
|
|
|
m_itemMapMutex.unlock();
|
|
|
|
if( item->device() )
|
|
|
|
{
|
|
|
|
item->device()->tagsChanged( item, bundle );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// it's an item on the transfer queue
|
|
|
|
item->setBundle( new MetaBundle( bundle ) );
|
|
|
|
|
|
|
|
TQString text = item->bundle()->prettyTitle();
|
|
|
|
if( text.isEmpty() || (!item->bundle()->isValidMedia() && !item->bundle()->podcastBundle()) )
|
|
|
|
text = item->bundle()->url().prettyURL();
|
|
|
|
if( !item->m_playlistName.isNull() )
|
|
|
|
{
|
|
|
|
text += " (" + item->m_playlistName + ')';
|
|
|
|
}
|
|
|
|
item->setText( 0, text);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_itemMapMutex.unlock();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
MediaBrowser::getBundle( const KURL &url, MetaBundle *bundle ) const
|
|
|
|
{
|
|
|
|
TQMutexLocker locker( &m_itemMapMutex );
|
|
|
|
ItemMap::const_iterator it = m_itemMap.find( url.url() );
|
|
|
|
if( it == m_itemMap.end() )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if( bundle )
|
|
|
|
*bundle = TQDeepCopy<MetaBundle>( *(*it)->bundle() );
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
KURL
|
|
|
|
MediaBrowser::getProxyUrl( const KURL& daapUrl ) const
|
|
|
|
{
|
|
|
|
DEBUG_BLOCK
|
|
|
|
KURL url;
|
|
|
|
MediaDevice* dc = dynamic_cast<MediaDevice*>( queryList( "DaapClient" )->getFirst() );
|
|
|
|
if( dc )
|
|
|
|
url = dc->getProxyUrl( daapUrl );
|
|
|
|
return url;
|
|
|
|
}
|
|
|
|
|
|
|
|
MediaDevice *
|
|
|
|
MediaBrowser::currentDevice() const
|
|
|
|
{
|
|
|
|
TQValueList<MediaDevice *>::const_iterator current = m_currentDevice;
|
|
|
|
if( current != m_devices.constEnd() )
|
|
|
|
{
|
|
|
|
return *m_currentDevice;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
MediaDevice *
|
|
|
|
MediaBrowser::deviceFromId( const TQString &id ) const
|
|
|
|
{
|
|
|
|
for( TQValueList<MediaDevice *>::const_iterator it = m_devices.constBegin();
|
|
|
|
it != m_devices.end();
|
|
|
|
it++ )
|
|
|
|
{
|
|
|
|
if( (*it)->uniqueId() == id )
|
|
|
|
return (*it);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaBrowser::activateDevice( const MediaDevice *dev )
|
|
|
|
{
|
|
|
|
int index = 0;
|
|
|
|
for( TQValueList<MediaDevice *>::iterator it = m_devices.begin();
|
|
|
|
it != m_devices.end();
|
|
|
|
it++ )
|
|
|
|
{
|
|
|
|
if( *it == dev )
|
|
|
|
{
|
|
|
|
activateDevice( index );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
index++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaBrowser::activateDevice( int index, bool skipDummy )
|
|
|
|
{
|
|
|
|
if( currentDevice() && currentDevice()->customAction() )
|
|
|
|
{
|
|
|
|
currentDevice()->customAction()->unplug( m_toolbar );
|
|
|
|
m_toolbar->hide();
|
|
|
|
m_toolbar->show();
|
|
|
|
}
|
|
|
|
|
|
|
|
for( TQValueList<MediaDevice *>::iterator it = m_devices.begin();
|
|
|
|
it != m_devices.end();
|
|
|
|
it++ )
|
|
|
|
{
|
|
|
|
(*it)->view()->hide();
|
|
|
|
}
|
|
|
|
|
|
|
|
if( index < 0 )
|
|
|
|
{
|
|
|
|
m_currentDevice = m_devices.end();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( skipDummy )
|
|
|
|
index++;
|
|
|
|
|
|
|
|
if( (uint)index >= m_devices.count() )
|
|
|
|
{
|
|
|
|
m_currentDevice = m_devices.end();
|
|
|
|
updateButtons();
|
|
|
|
queue()->computeSize();
|
|
|
|
updateStats();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_currentDevice = m_devices.at( index );
|
|
|
|
if( currentDevice() )
|
|
|
|
{
|
|
|
|
currentDevice()->view()->show();
|
|
|
|
if( currentDevice()->customAction() )
|
|
|
|
{
|
|
|
|
m_toolbar->setIconText( KToolBar::IconTextRight, false );
|
|
|
|
currentDevice()->customAction()->plug( m_toolbar );
|
|
|
|
m_toolbar->hide();
|
|
|
|
m_toolbar->show();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
m_deviceCombo->setCurrentItem( index-1 );
|
|
|
|
|
|
|
|
updateButtons();
|
|
|
|
queue()->computeSize();
|
|
|
|
updateStats();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaBrowser::addDevice( MediaDevice *device )
|
|
|
|
{
|
|
|
|
m_devices.append( device );
|
|
|
|
|
|
|
|
device->loadConfig();
|
|
|
|
|
|
|
|
if( device->autoConnect() )
|
|
|
|
{
|
|
|
|
device->connectDevice( true );
|
|
|
|
updateButtons();
|
|
|
|
}
|
|
|
|
|
|
|
|
updateDevices();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaBrowser::removeDevice( MediaDevice *device )
|
|
|
|
{
|
|
|
|
DEBUG_BLOCK
|
|
|
|
|
|
|
|
debug() << "remove device: type=" << device->deviceType() << endl;
|
|
|
|
|
|
|
|
for( TQValueList<MediaDevice *>::iterator it = m_devices.begin();
|
|
|
|
it != m_devices.end();
|
|
|
|
it++ )
|
|
|
|
{
|
|
|
|
if( *it == device )
|
|
|
|
{
|
|
|
|
bool current = (it == m_currentDevice);
|
|
|
|
m_devices.remove( device );
|
|
|
|
if( current )
|
|
|
|
activateDevice( 0, false );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if( device->isConnected() )
|
|
|
|
{
|
|
|
|
if( device->disconnectDevice( false /* don't run post-disconnect command */ ) )
|
|
|
|
unloadDevicePlugin( device );
|
|
|
|
else
|
|
|
|
{
|
|
|
|
debug() << "Cannot remove device because disconnect failed" << endl;
|
|
|
|
Amarok::StatusBar::instance()->longMessage(
|
|
|
|
i18n( "Cannot remove device because disconnect failed" ),
|
|
|
|
KDE::StatusBar::Warning );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
unloadDevicePlugin( device );
|
|
|
|
|
|
|
|
updateDevices();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaBrowser::updateDevices()
|
|
|
|
{
|
|
|
|
m_deviceCombo->clear();
|
|
|
|
uint i = 0;
|
|
|
|
for( TQValueList<MediaDevice *>::iterator it = m_devices.begin();
|
|
|
|
it != m_devices.end();
|
|
|
|
it++ )
|
|
|
|
{
|
|
|
|
if( m_devices.count() > 1 && dynamic_cast<DummyMediaDevice *>(*it) )
|
|
|
|
continue;
|
|
|
|
TQString name = (*it)->name();
|
|
|
|
if( !(*it)->deviceNode().isEmpty() )
|
|
|
|
{
|
|
|
|
name = i18n( "%1 at %2" ).arg( name, (*it)->deviceNode() );
|
|
|
|
}
|
|
|
|
if( (*it)->hasMountPoint() && !(*it)->mountPoint().isEmpty() )
|
|
|
|
{
|
|
|
|
name += i18n( " (mounted at %1)" ).arg( (*it)->mountPoint() );
|
|
|
|
}
|
|
|
|
m_deviceCombo->insertItem( name, i );
|
|
|
|
if( it == m_currentDevice )
|
|
|
|
{
|
|
|
|
m_deviceCombo->setCurrentItem( i );
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
m_deviceCombo->setEnabled( m_devices.count() > 1 );
|
|
|
|
m_haveDevices = m_devices.count() > 1;
|
|
|
|
emit availabilityChanged( m_haveDevices );
|
|
|
|
}
|
|
|
|
|
|
|
|
TQStringList
|
|
|
|
MediaBrowser::deviceNames() const
|
|
|
|
{
|
|
|
|
TQStringList list;
|
|
|
|
|
|
|
|
for( TQValueList<MediaDevice *>::const_iterator it = m_devices.constBegin();
|
|
|
|
it != m_devices.constEnd();
|
|
|
|
it++ )
|
|
|
|
{
|
|
|
|
TQString name = (*it)->name();
|
|
|
|
list << name;
|
|
|
|
}
|
|
|
|
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
MediaBrowser::deviceSwitch( const TQString &name )
|
|
|
|
{
|
|
|
|
int index = 0;
|
|
|
|
for( TQValueList<MediaDevice *>::iterator it = m_devices.begin();
|
|
|
|
it != m_devices.end();
|
|
|
|
it++ )
|
|
|
|
{
|
|
|
|
if( (*it)->name() == name )
|
|
|
|
{
|
|
|
|
activateDevice( index, false );
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
index++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaBrowser::transcodingFinished( const TQString &src, const TQString &dst )
|
|
|
|
{
|
|
|
|
KURL srcJob = KURL::fromPathOrURL( m_transcodeSrc );
|
|
|
|
KURL srcResult = KURL::fromPathOrURL( src );
|
|
|
|
|
|
|
|
if( srcJob.path() == srcResult.path() )
|
|
|
|
{
|
|
|
|
m_transcodedUrl = KURL::fromPathOrURL( dst );
|
|
|
|
m_waitForTranscode = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
debug() << "transcoding for " << src << " finished, "
|
|
|
|
<< "but we are waiting for " << m_transcodeSrc << " -- aborting" << endl;
|
|
|
|
m_waitForTranscode = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
KURL
|
|
|
|
MediaBrowser::transcode( const KURL &src, const TQString &filetype )
|
|
|
|
{
|
|
|
|
const ScriptManager* const sm = ScriptManager::instance();
|
|
|
|
|
|
|
|
if( sm->transcodeScriptRunning().isEmpty() )
|
|
|
|
{
|
|
|
|
debug() << "cannot transcode with no transcoder registered" << endl;
|
|
|
|
return KURL();
|
|
|
|
}
|
|
|
|
|
|
|
|
m_waitForTranscode = true;
|
|
|
|
m_transcodeSrc = src.url();
|
|
|
|
m_transcodedUrl = KURL();
|
|
|
|
ScriptManager::instance()->notifyTranscode( src.url(), filetype );
|
|
|
|
|
|
|
|
while( m_waitForTranscode && sm->transcodeScriptRunning() != TQString() )
|
|
|
|
{
|
|
|
|
usleep( 10000 );
|
|
|
|
kapp->processEvents( 100 );
|
|
|
|
}
|
|
|
|
|
|
|
|
return m_transcodedUrl;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaBrowser::slotSetFilterTimeout() //SLOT
|
|
|
|
{
|
|
|
|
m_timer->start( 280, true ); //stops the timer for us first
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaBrowser::slotSetFilter() //SLOT
|
|
|
|
{
|
|
|
|
m_timer->stop();
|
|
|
|
|
|
|
|
if( currentDevice() )
|
|
|
|
currentDevice()->view()->setFilter( m_searchEdit->text() );
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaBrowser::slotSetFilter( const TQString &text )
|
|
|
|
{
|
|
|
|
m_searchEdit->setText( text );
|
|
|
|
slotSetFilter();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaBrowser::slotEditFilter()
|
|
|
|
{
|
|
|
|
EditFilterDialog *fd = new EditFilterDialog( this, true, m_searchEdit->text() );
|
|
|
|
connect( fd, TQT_SIGNAL(filterChanged(const TQString &)), TQT_SLOT(slotSetFilter(const TQString &)) );
|
|
|
|
if( fd->exec() )
|
|
|
|
m_searchEdit->setText( fd->filter() );
|
|
|
|
delete fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaBrowser::prepareToQuit()
|
|
|
|
{
|
|
|
|
m_waitForTranscode = false;
|
|
|
|
m_quitting = true;
|
|
|
|
for( TQValueList<MediaDevice *>::iterator it = m_devices.begin();
|
|
|
|
it != m_devices.end();
|
|
|
|
++it )
|
|
|
|
{
|
|
|
|
if( (*it)->isConnected() )
|
|
|
|
(*it)->disconnectDevice( false /* don't unmount */ );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
MediaBrowser::~MediaBrowser()
|
|
|
|
{
|
|
|
|
debug() << "having to remove " << m_devices.count() << " devices" << endl;
|
|
|
|
while( !m_devices.isEmpty() )
|
|
|
|
{
|
|
|
|
removeDevice( m_devices.last() );
|
|
|
|
}
|
|
|
|
|
|
|
|
queue()->save( Amarok::saveLocation() + "transferlist.xml" );
|
|
|
|
|
|
|
|
delete m_deviceCombo;
|
|
|
|
delete m_queue;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
MediaItem::MediaItem( TQListView* parent )
|
|
|
|
: KListViewItem( parent )
|
|
|
|
{
|
|
|
|
init();
|
|
|
|
}
|
|
|
|
|
|
|
|
MediaItem::MediaItem( TQListViewItem* parent )
|
|
|
|
: KListViewItem( parent )
|
|
|
|
{
|
|
|
|
init();
|
|
|
|
}
|
|
|
|
|
|
|
|
MediaItem::MediaItem( TQListView* parent, TQListViewItem* after )
|
|
|
|
: KListViewItem( parent, after )
|
|
|
|
{
|
|
|
|
init();
|
|
|
|
}
|
|
|
|
|
|
|
|
MediaItem::MediaItem( TQListViewItem* parent, TQListViewItem* after )
|
|
|
|
: KListViewItem( parent, after )
|
|
|
|
{
|
|
|
|
init();
|
|
|
|
}
|
|
|
|
|
|
|
|
MediaItem::~MediaItem()
|
|
|
|
{
|
|
|
|
setBundle( 0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaItem::init()
|
|
|
|
{
|
|
|
|
m_bundle=0;
|
|
|
|
m_order=0;
|
|
|
|
m_type=UNKNOWN;
|
|
|
|
m_playlistName = TQString();
|
|
|
|
m_device=0;
|
|
|
|
m_flags=0;
|
|
|
|
setExpandable( false );
|
|
|
|
setDragEnabled( true );
|
|
|
|
setDropEnabled( true );
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaItem::setBundle( MetaBundle *bundle )
|
|
|
|
{
|
|
|
|
MediaBrowser::instance()->m_itemMapMutex.lock();
|
|
|
|
if( m_bundle )
|
|
|
|
{
|
|
|
|
TQString itemUrl = url().url();
|
|
|
|
MediaBrowser::ItemMap::iterator it = MediaBrowser::instance()->m_itemMap.find( itemUrl );
|
|
|
|
if( it != MediaBrowser::instance()->m_itemMap.end() && *it == this )
|
|
|
|
MediaBrowser::instance()->m_itemMap.remove( itemUrl );
|
|
|
|
}
|
|
|
|
delete m_bundle;
|
|
|
|
m_bundle = bundle;
|
|
|
|
|
|
|
|
if( m_bundle )
|
|
|
|
{
|
|
|
|
TQString itemUrl = url().url();
|
|
|
|
MediaBrowser::ItemMap::iterator it = MediaBrowser::instance()->m_itemMap.find( itemUrl );
|
|
|
|
if( it == MediaBrowser::instance()->m_itemMap.end() )
|
|
|
|
MediaBrowser::instance()->m_itemMap[itemUrl] = this;
|
|
|
|
}
|
|
|
|
MediaBrowser::instance()->m_itemMapMutex.unlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MediaItem::paintCell( TQPainter *p, const TQColorGroup &cg, int column, int width, int align )
|
|
|
|
{
|
|
|
|
switch( type() )
|
|
|
|
{
|
|
|
|
case INVISIBLE:
|
|
|
|
case PODCASTSROOT:
|
|
|
|
case PLAYLISTSROOT:
|
|
|
|
case ORPHANEDROOT:
|
|
|
|
case STALEROOT:
|
|
|
|
{
|
|
|
|
TQFont font( p->font() );
|
|
|
|
font.setBold( true );
|
|
|
|
p->setFont( font );
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
KListViewItem::paintCell( p, cg, column, width, align );
|
|
|
|
}
|
|
|
|
|
|
|
|
const MetaBundle *
|
|
|
|
MediaItem::bundle() const
|
|
|
|
{
|
|
|
|
return m_bundle;
|
|
|
|
}
|
|
|
|
|
|
|
|
KURL
|
|
|
|
MediaItem::url() const
|
|
|
|
{
|
|
|
|
if( bundle() )
|
|
|
|
return bundle()->url();
|
|
|
|
else
|
|
|
|
return KURL();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
MediaItem::isFileBacked() const
|
|
|
|
{
|
|
|
|
switch( type() )
|
|
|
|
{
|
|
|
|
case ARTIST:
|
|
|
|
case ALBUM:
|
|
|
|
case PODCASTSROOT:
|
|
|
|
case PODCASTCHANNEL:
|
|
|
|
case PLAYLISTSROOT:
|
|
|
|
case PLAYLIST:
|
|
|
|
case PLAYLISTITEM:
|
|
|
|
case INVISIBLEROOT:
|
|
|
|
case STALEROOT:
|
|
|
|
case STALE:
|
|
|
|
case ORPHANEDROOT:
|
|
|
|
return false;
|
|
|
|
|
|
|
|
case UNKNOWN:
|
|
|
|
case TRACK:
|
|
|
|
case ORPHANED:
|
|
|
|
case INVISIBLE:
|
|
|
|
case PODCASTITEM:
|
|
|
|
case DIRECTORY:
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
long
|
|
|
|
MediaItem::size() const
|
|
|
|
{
|
|
|
|
if( !isFileBacked() )
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if( bundle() )
|
|
|
|
return bundle()->filesize();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaItem::setType( Type type )
|
|