summaryrefslogtreecommitdiffstats
path: root/src/k3baudioplayer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/k3baudioplayer.cpp')
-rw-r--r--src/k3baudioplayer.cpp663
1 files changed, 663 insertions, 0 deletions
diff --git a/src/k3baudioplayer.cpp b/src/k3baudioplayer.cpp
new file mode 100644
index 0000000..645b3cf
--- /dev/null
+++ b/src/k3baudioplayer.cpp
@@ -0,0 +1,663 @@
+/*
+ *
+ * $Id: k3baudioplayer.cpp 619556 2007-01-03 17:38:12Z trueg $
+ * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This file is part of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * See the file "COPYING" for the exact licensing terms.
+ */
+
+
+#include "k3baudioplayer.h"
+#include <k3bmsf.h>
+#include "kcutlabel.h"
+
+#include <qlabel.h>
+#include <qtoolbutton.h>
+#include <qlayout.h>
+#include <qtimer.h>
+#include <qdatetime.h>
+#include <qfont.h>
+#include <qslider.h>
+#include <qlistview.h>
+#include <qfile.h>
+#include <qpalette.h>
+#include <qheader.h>
+#include <qevent.h>
+#include <qdragobject.h>
+#include <qptrlist.h>
+#include <kurldrag.h>
+
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kurl.h>
+#include <kaction.h>
+
+#include <string.h>
+
+#ifdef WITH_ARTS
+#include <arts/artsflow.h>
+#endif
+
+#include <kdebug.h>
+
+using namespace std;
+
+K3bPlayListViewItem::K3bPlayListViewItem( const QString& filename, QListView* parent )
+ : KListViewItem( parent ), m_filename( filename )
+{
+ m_length = 0;
+ m_bActive = false;
+}
+
+
+K3bPlayListViewItem::K3bPlayListViewItem( const QString& filename, QListView* parent, QListViewItem* after )
+ : KListViewItem( parent, after ), m_filename( filename )
+{
+ m_length = 0;
+ m_bActive = false;
+}
+
+
+K3bPlayListViewItem::~K3bPlayListViewItem()
+{
+}
+
+
+QString K3bPlayListViewItem::text( int c ) const
+{
+ switch( c ) {
+ case 0:
+ {
+ int pos = m_filename.findRev("/");
+ if( pos >= 0 )
+ return m_filename.mid(pos+1);
+ return m_filename;
+ }
+
+ case 1:
+ if( m_length > 0 )
+ return K3b::Msf(m_length).toString(false);
+
+ default:
+ return "";
+ }
+}
+
+
+void K3bPlayListViewItem::paintCell( QPainter* p, const QColorGroup& cg, int c, int w, int a )
+{
+ if( m_bActive ) {
+ // change the color of the text:
+ // change roles: Text, HighlightedText, HighLight
+ QColorGroup newCg( cg );
+
+ // we assume the user has not configured a very dark color as base color
+ newCg.setColor( QColorGroup::Text, red );
+ newCg.setColor( QColorGroup::Highlight, red );
+ newCg.setColor( QColorGroup::HighlightedText, white );
+
+ KListViewItem::paintCell( p, newCg, c, w, a );
+ }
+ else
+ KListViewItem::paintCell( p, cg, c, w, a );
+}
+
+
+K3bPlayListView::K3bPlayListView( QWidget* parent, const char* name )
+ : KListView( parent, name )
+{
+ addColumn( i18n("Filename") );
+ addColumn( i18n("Length") );
+ setAllColumnsShowFocus( true );
+ setAcceptDrops( true );
+ setDropVisualizer( true );
+ setDragEnabled(true);
+ setItemsMovable( true );
+ header()->setClickEnabled( false );
+ setSorting( -1 );
+}
+
+
+K3bPlayListView::~K3bPlayListView()
+{
+}
+
+
+bool K3bPlayListView::acceptDrag( QDropEvent* e ) const
+{
+ // we accept textdrag (urls) and moved items (supported by KListView)
+ return KURLDrag::canDecode(e) || KListView::acceptDrag(e);
+}
+
+
+QDragObject* K3bPlayListView::dragObject()
+{
+ QPtrList<QListViewItem> list = selectedItems();
+
+ if( list.isEmpty() )
+ return 0;
+
+ QPtrListIterator<QListViewItem> it(list);
+ KURL::List urls;
+
+ for( ; it.current(); ++it )
+ urls.append( KURL( ((K3bPlayListViewItem*)it.current())->filename() ) );
+
+ return KURLDrag::newDrag( urls, viewport() );
+}
+
+
+K3bAudioPlayer::K3bAudioPlayer( QWidget* parent, const char* name )
+ : QWidget( parent, name )
+#ifdef WITH_ARTS
+, m_playObject( Arts::PlayObject::null() )
+#endif
+{
+ m_currentItem = 0L;
+ // initialize
+ // ------------------------------------------------------------------------
+ m_labelFilename = new KCutLabel( i18n("no file"), this );
+ m_labelOverallTime = new QLabel( "00:00", this );
+ m_labelCurrentTime = new QLabel( "00:00", this );
+
+ m_viewPlayList = new K3bPlayListView( this );
+
+ m_labelOverallTime->setAlignment( AlignHCenter | AlignVCenter );
+ m_labelCurrentTime->setAlignment( AlignHCenter | AlignVCenter );
+ m_labelOverallTime->setFrameStyle( QFrame::StyledPanel | QFrame::Plain );
+ m_labelCurrentTime->setFrameStyle( QFrame::StyledPanel | QFrame::Plain );
+ m_labelFilename->setFrameStyle( QFrame::StyledPanel | QFrame::Plain );
+ m_labelOverallTime->setPalette( QPalette( QColor(238, 238, 205) ) );
+ m_labelCurrentTime->setPalette( QPalette( QColor(238, 238, 205) ) );
+ m_labelFilename->setPalette( QPalette( QColor(238, 238, 205) ) );
+
+ m_buttonPlay = new QToolButton( this );
+ m_buttonPause = new QToolButton( this );
+ m_buttonStop = new QToolButton( this );
+ m_buttonPlay->setIconSet( SmallIconSet("player_play") );
+ m_buttonPause->setIconSet( SmallIconSet("player_pause") );
+ m_buttonStop->setIconSet( SmallIconSet("player_stop") );
+ m_buttonForward = new QToolButton( this );
+ m_buttonBack = new QToolButton( this );
+ m_buttonForward->setIconSet( SmallIconSet("player_end") );
+ m_buttonBack->setIconSet( SmallIconSet("player_start") );
+
+ m_seekSlider = new QSlider( QSlider::Horizontal, this );
+
+ m_updateTimer = new QTimer( this );
+ // ------------------------------------------------------------------------
+
+ // layout
+ // ------------------------------------------------------------------------
+ QGridLayout* grid = new QGridLayout( this );
+ grid->setSpacing( 2 );
+ grid->setMargin( 0 );
+
+ grid->addWidget( m_buttonPlay, 1, 0 );
+ grid->addWidget( m_buttonPause, 1, 1 );
+ grid->addWidget( m_buttonStop, 1, 2 );
+ grid->addColSpacing( 3, 5 );
+ grid->addWidget( m_buttonBack, 1, 4 );
+ grid->addWidget( m_buttonForward, 1, 5 );
+
+ grid->addMultiCellWidget( m_labelFilename, 0, 0, 0, 6 );
+
+ grid->addMultiCellWidget( m_seekSlider, 1, 1, 6, 8 );
+
+ grid->addWidget( m_labelCurrentTime, 0, 7 );
+ grid->addWidget( m_labelOverallTime, 0, 8 );
+
+ grid->addMultiCellWidget( m_viewPlayList, 2, 2, 0, 8 );
+ grid->setRowStretch( 2, 1 );
+ grid->setColStretch( 6, 1 );
+ // ------------------------------------------------------------------------
+
+
+ // actions
+ // ------------------------------------------------------------------------
+ m_actionRemove = new KAction( i18n( "Remove" ), "editdelete",
+ Key_Delete, this, SLOT(slotRemoveSelected()),
+ this, "audioplayer_remove" );
+ m_actionClear = new KAction( i18n( "Clear List" ), "editclear",
+ 0, this, SLOT(clear()),
+ this, "audioplayer_clear" );
+
+ m_contextMenu = new KActionMenu( this, "audio_player_menu" );
+ m_contextMenu->insert(m_actionRemove);
+ m_contextMenu->insert(m_actionClear);
+ // ------------------------------------------------------------------------
+
+
+ // connections
+ // ------------------------------------------------------------------------
+ connect( m_viewPlayList, SIGNAL(contextMenu(KListView*, QListViewItem*, const QPoint&)),
+ this, SLOT(slotShowContextMenu(KListView*, QListViewItem*, const QPoint&)) );
+
+ connect( m_buttonPlay, SIGNAL(clicked()), this, SLOT(play()) );
+ connect( m_buttonStop, SIGNAL(clicked()), this, SLOT(stop()) );
+ connect( m_buttonPause, SIGNAL(clicked()), this, SLOT(pause()) );
+
+ connect( m_buttonForward, SIGNAL(clicked()), this, SLOT(forward()) );
+ connect( m_buttonBack, SIGNAL(clicked()), this, SLOT(back()) );
+
+ connect( m_seekSlider, SIGNAL(sliderMoved(int)), this, SLOT(seek(int)) );
+ connect( m_seekSlider, SIGNAL(valueChanged(int)), this, SLOT(slotUpdateCurrentTime(int)) );
+
+ connect( m_updateTimer, SIGNAL(timeout()), this, SLOT(slotUpdateDisplay()) );
+ connect( m_updateTimer, SIGNAL(timeout()), this, SLOT(slotCheckEnd()) );
+
+ connect( m_viewPlayList, SIGNAL(doubleClicked(QListViewItem*)),
+ this, SLOT(slotPlayItem(QListViewItem*)) );
+ connect( m_viewPlayList, SIGNAL(dropped(QDropEvent*,QListViewItem*)),
+ this, SLOT(slotDropped(QDropEvent*,QListViewItem*)) );
+ // ------------------------------------------------------------------------
+
+
+ m_bLengthReady = false;
+}
+
+
+K3bAudioPlayer::~K3bAudioPlayer()
+{
+ // we remove the reference to the play object
+ // if we don't do this it won't be removed and K3b will crash (not sure why)
+#ifdef WITH_ARTS
+ m_playObject = Arts::PlayObject::null();
+#endif
+}
+
+
+int K3bAudioPlayer::state()
+{
+#ifdef WITH_ARTS
+ if( !m_playObject.isNull() ) {
+ switch( m_playObject.state() ) {
+ case Arts::posIdle:
+ return STOPPED;
+ case Arts::posPlaying:
+ return PLAYING;
+ case Arts::posPaused:
+ return PAUSED;
+ }
+ }
+ else if( m_currentItem )
+ return STOPPED;
+#endif
+
+ return EMPTY;
+}
+
+
+void K3bAudioPlayer::playFile( const QString& filename )
+{
+ clear();
+ if( QFile::exists( filename ) ) {
+ K3bPlayListViewItem* item = new K3bPlayListViewItem( filename, m_viewPlayList );
+ setCurrentItem( item );
+ play();
+ emit started( filename );
+ }
+}
+
+
+void K3bAudioPlayer::playFiles( const QStringList& files )
+{
+ clear();
+ QStringList::ConstIterator it = files.begin();
+ playFile( *it );
+ ++it;
+
+ for( ; it != files.end(); ++it )
+ enqueueFile( *it );
+}
+
+
+void K3bAudioPlayer::enqueueFile( const QString& filename )
+{
+ if( QFile::exists( filename ) )
+ (void)new K3bPlayListViewItem( filename, m_viewPlayList, m_viewPlayList->lastChild() );
+}
+
+
+void K3bAudioPlayer::enqueueFiles( const QStringList& files )
+{
+ for( QStringList::ConstIterator it = files.begin(); it != files.end(); ++it )
+ enqueueFile( *it );
+}
+
+
+void K3bAudioPlayer::play()
+{
+#ifdef WITH_ARTS
+ if( !m_currentItem ) {
+ setCurrentItem( m_viewPlayList->firstChild() );
+ }
+
+ if( m_currentItem ) {
+ if( m_playObject.isNull() ) {
+ Arts::PlayObjectFactory factory = Arts::Reference("global:Arts_PlayObjectFactory");
+ if( factory.isNull() ) {
+ kdDebug() << "(K3bAudioPlayer) could not create PlayObjectFactory. Possibly no artsd running." << endl;
+ m_labelFilename->setText( i18n("No running aRtsd found") );
+ return;
+ }
+
+ m_playObject = factory.createPlayObject( string(QFile::encodeName(m_currentItem->filename()) ) );
+ if( m_playObject.isNull() ) {
+ kdDebug() << "(K3bAudioPlayer) no aRts module available for: " << m_currentItem->filename() << endl;
+ m_labelFilename->setText( i18n("Unknown file format") );
+
+ // play the next if there is any
+ if( m_currentItem->itemBelow() ) {
+ setCurrentItem( m_currentItem->itemBelow() );
+ play();
+ }
+ return;
+ }
+ }
+ if( m_playObject.state() != Arts::posPlaying ) {
+ m_playObject.play();
+ emit started();
+ m_updateTimer->start( 1000 );
+ }
+
+ slotUpdateFilename();
+ }
+#endif
+}
+
+
+void K3bAudioPlayer::slotPlayItem( QListViewItem* item )
+{
+ setCurrentItem( item );
+ play();
+}
+
+
+void K3bAudioPlayer::stop()
+{
+#ifdef WITH_ARTS
+ if( !m_playObject.isNull() ) {
+ m_updateTimer->stop();
+ m_playObject.halt();
+ m_playObject = Arts::PlayObject::null();
+ m_bLengthReady = false;
+
+ emit stopped();
+ }
+#endif
+
+ m_seekSlider->setValue(0);
+ slotUpdateFilename();
+ slotUpdateCurrentTime(0);
+}
+
+
+void K3bAudioPlayer::pause()
+{
+#ifdef WITH_ARTS
+ if( !m_playObject.isNull() ) {
+ if( m_playObject.state() == Arts::posPlaying ) {
+ m_updateTimer->stop();
+ m_playObject.pause();
+ emit paused();
+ }
+
+ slotUpdateFilename();
+ }
+#endif
+}
+
+
+void K3bAudioPlayer::seek( long pos )
+{
+#ifdef WITH_ARTS
+ if( !m_playObject.isNull() ) {
+ if( m_playObject.state() != Arts::posIdle ) {
+ if( pos < 0 ) {
+ m_playObject.seek( Arts::poTime() );
+ }
+ else if( m_playObject.overallTime().seconds < pos ) {
+ m_playObject.seek( m_playObject.overallTime() );
+ }
+ else if( pos != m_playObject.currentTime().seconds ) {
+ m_playObject.seek( Arts::poTime( pos, 0, -1, "" ) );
+ }
+ }
+ }
+ else {
+ m_seekSlider->setValue(0);
+ slotUpdateCurrentTime(0);
+ }
+#endif
+}
+
+
+
+void K3bAudioPlayer::seek( int pos )
+{
+ seek( (long)pos );
+}
+
+
+void K3bAudioPlayer::forward()
+{
+ if( m_currentItem ) {
+ if( m_currentItem->itemBelow() ) {
+ bool bPlay = false;
+ if( state() == PLAYING )
+ bPlay = true;
+
+ setCurrentItem( m_currentItem->itemBelow() );
+
+ if( bPlay )
+ play();
+ }
+ }
+}
+
+
+void K3bAudioPlayer::back()
+{
+ if( m_currentItem ) {
+ if( m_currentItem->itemAbove() ) {
+ bool bPlay = false;
+ if( state() == PLAYING )
+ bPlay = true;
+
+ setCurrentItem( m_currentItem->itemAbove() );
+
+ if( bPlay )
+ play();
+ }
+ }
+}
+
+
+void K3bAudioPlayer::clear()
+{
+ setCurrentItem( 0 );
+ m_viewPlayList->clear();
+}
+
+
+long K3bAudioPlayer::length()
+{
+#ifdef WITH_ARTS
+ if( !m_playObject.isNull() ) {
+ return m_playObject.overallTime().seconds;
+ }
+#endif
+ return 0;
+}
+
+
+long K3bAudioPlayer::position()
+{
+#ifdef WITH_ARTS
+ if( !m_playObject.isNull() ) {
+ return m_playObject.currentTime().seconds;
+ }
+#endif
+ return 0;
+}
+
+
+// FIXME: let my do some useful stuff!
+bool K3bAudioPlayer::supportsMimetype( const QString& mimetype )
+{
+ if( mimetype.contains("audio") || mimetype.contains("ogg") )
+ return true;
+ else
+ return false;
+}
+
+
+void K3bAudioPlayer::slotCheckEnd()
+{
+#ifdef WITH_ARTS
+ if( !m_playObject.isNull() ) {
+ if( m_playObject.state() == Arts::posIdle ) {
+ if( m_currentItem->nextSibling() ) {
+ setCurrentItem( m_currentItem->nextSibling() );
+ play();
+ }
+ else {
+ stop();
+ }
+ emit ended();
+ }
+ }
+#endif
+}
+
+
+void K3bAudioPlayer::setCurrentItem( QListViewItem* item )
+{
+ if( item == 0 ) {
+ stop();
+ m_labelOverallTime->setText("00:00");
+ m_labelFilename->setText( i18n("no file") );
+ m_currentItem = 0;
+ }
+ else if( K3bPlayListViewItem* playItem = dynamic_cast<K3bPlayListViewItem*>(item) ) {
+ if( m_currentItem ) {
+ // reset m_currentItem
+ m_currentItem->setActive( false );
+ stop();
+ }
+ m_currentItem = playItem;
+ m_currentItem->setActive( true );
+
+ // paint the activity changes
+ m_viewPlayList->viewport()->update();
+
+ slotUpdateFilename();
+ }
+}
+
+
+void K3bAudioPlayer::slotUpdateCurrentTime( int time )
+{
+ m_labelCurrentTime->setText( K3b::Msf( time*75 ).toString(false) );
+}
+
+
+void K3bAudioPlayer::slotUpdateLength( long time )
+{
+ m_labelOverallTime->setText( K3b::Msf( time*75 ).toString(false) );
+}
+
+
+void K3bAudioPlayer::slotUpdateFilename()
+{
+ if( m_currentItem ) {
+ QString display = m_currentItem->filename();
+ int pos = display.findRev("/");
+ if( pos >= 0 )
+ display = display.mid(pos+1);
+
+ switch( state() ) {
+ case PLAYING:
+ display.prepend( QString("(%1) ").arg(i18n("playing")) );
+ break;
+ case PAUSED:
+ display.prepend( QString("(%1) ").arg(i18n("paused")) );
+ break;
+ case STOPPED:
+ display.prepend( QString("(%1) ").arg(i18n("stopped")) );
+ break;
+ default:
+ break;
+ }
+
+ m_labelFilename->setText( display );
+ }
+}
+
+
+void K3bAudioPlayer::slotUpdateDisplay()
+{
+ if( m_currentItem ) {
+ // we need to set the length here because sometimes it is not ready in the beginning (?)
+ if( !m_bLengthReady && length() > 0 ) {
+ slotUpdateLength( length() );
+ m_seekSlider->setMaxValue( length() );
+ m_currentItem->setLength( 75 * length() );
+ m_bLengthReady = true;
+
+ m_viewPlayList->viewport()->update();
+ }
+
+ m_seekSlider->setValue( position() );
+ }
+}
+
+
+void K3bAudioPlayer::slotDropped( QDropEvent* e, QListViewItem* after )
+{
+ if( !after )
+ after = m_viewPlayList->lastChild();
+
+ KURL::List urls;
+ KURLDrag::decode( e, urls );
+
+ for( KURL::List::ConstIterator it = urls.begin(); it != urls.end(); ++it ) {
+ if( QFile::exists( (*it).path() ) ) {
+ QListViewItem* newItem = new K3bPlayListViewItem( (*it).path(), m_viewPlayList, after );
+ after = newItem;
+ }
+ }
+}
+
+
+void K3bAudioPlayer::slotRemoveSelected()
+{
+ QPtrList<QListViewItem> selected = m_viewPlayList->selectedItems();
+ for( QListViewItem* item = selected.first(); item; item = selected.next() ) {
+ if( item == m_currentItem )
+ setCurrentItem(0);
+ delete item;
+ }
+}
+
+
+void K3bAudioPlayer::slotShowContextMenu( KListView*, QListViewItem* item, const QPoint& p )
+{
+ if( item )
+ m_actionRemove->setEnabled( true );
+ else
+ m_actionRemove->setEnabled( false );
+
+ m_contextMenu->popup(p);
+}
+
+
+#include "k3baudioplayer.moc"