summaryrefslogtreecommitdiffstats
path: root/src/replaygainfilelist.cpp
diff options
context:
space:
mode:
authortpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-03-01 19:09:31 +0000
committertpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-03-01 19:09:31 +0000
commitf2cfda2a54780868dfe0af7bd652fcd4906547da (patch)
treec6ac23545528f5701818424f2af5f79ce3665e6c /src/replaygainfilelist.cpp
downloadsoundkonverter-f2cfda2a54780868dfe0af7bd652fcd4906547da.tar.gz
soundkonverter-f2cfda2a54780868dfe0af7bd652fcd4906547da.zip
Added KDE3 version of SoundKonverter
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/soundkonverter@1097614 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'src/replaygainfilelist.cpp')
-rwxr-xr-xsrc/replaygainfilelist.cpp1262
1 files changed, 1262 insertions, 0 deletions
diff --git a/src/replaygainfilelist.cpp b/src/replaygainfilelist.cpp
new file mode 100755
index 0000000..2d71806
--- /dev/null
+++ b/src/replaygainfilelist.cpp
@@ -0,0 +1,1262 @@
+
+#include "replaygainfilelist.h"
+#include "tagengine.h"
+#include "logger.h"
+#include "config.h"
+#include "replaygain.h"
+#include "replaygainpluginloader.h"
+
+#include <qdir.h>
+#include <qpainter.h>
+#include <qsimplerichtext.h>
+#include <qapplication.h>
+#include <qheader.h>
+#include <qlayout.h>
+#include <qtimer.h>
+
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kurldrag.h>
+#include <kpopupmenu.h>
+#include <kaction.h>
+#include <kactioncollection.h>
+#include <kmessagebox.h>
+#include <kmountpoint.h>
+#include <kprogress.h>
+#include <kprocess.h>
+#include <kmimetype.h>
+#include <kapplication.h>
+#include <kuser.h>
+
+// TODO move listDir, addFiles, addDir, etc -- done?
+
+// ### soundkonverter 0.4: give the 'track' and 'album' column a minimum width and fill the rest of the space with the 'file' column - make some margins, too
+
+
+ReplayGainFileListItem::ReplayGainFileListItem( QListView* parent )
+ : KListViewItem( parent )
+{
+ m_type = File;
+ mimeType = "application/octet-stream";
+ addingReplayGain = false;
+ queued = false;
+}
+
+// ReplayGainFileListItem::ReplayGainFileListItem( QListView* parent, QListViewItem* after )
+// : KListViewItem( parent, after )
+// {
+// m_type = File;
+// mimeType = "application/octet-stream";
+// addingReplayGain = false;
+// queued = false;
+// }
+
+ReplayGainFileListItem::ReplayGainFileListItem( ReplayGainFileListItem* parent )
+ : KListViewItem( parent )
+{
+ m_type = File;
+ mimeType = "application/octet-stream";
+ addingReplayGain = false;
+ queued = false;
+}
+
+ReplayGainFileListItem::~ReplayGainFileListItem()
+{}
+
+void ReplayGainFileListItem::paintCell( QPainter *p, const QColorGroup &cg, int column, int width, int alignment )
+{
+ // NOTE speed up this function
+ // NOTE calculate the red color
+
+ QColorGroup _cg( cg );
+ QColor c;
+
+ if( column == ((ReplayGainFileList*)listView())->columnByName(i18n("File")) )
+ {
+ int margin = listView()->itemMargin();
+ int w = width - 2*margin;
+ int h = height();
+ QRect textRect = p->boundingRect( margin, 0, w, h, alignment, text(column) );
+
+ if( textRect.width() > w ) {
+ alignment = Qt::AlignRight | Qt::SingleLine;
+ }
+ }
+
+ if( isSelected() && addingReplayGain ) {
+ _cg.setColor( QColorGroup::Highlight, QColor( 215, 62, 62 ) );
+ QListViewItem::paintCell( p, _cg, column, width, alignment );
+ return;
+ }
+ else if( addingReplayGain && column != listView()->sortColumn() ) {
+ _cg.setColor( QColorGroup::Base, QColor( 255, 234, 234 ) );
+ QListViewItem::paintCell( p, _cg, column, width, alignment );
+ return;
+ }
+ else if( addingReplayGain && column == listView()->sortColumn() ) {
+ _cg.setColor( QColorGroup::Base, QColor( 247, 227, 227 ) );
+ QListViewItem::paintCell( p, _cg, column, width, alignment );
+ return;
+ }
+
+ if( isSelected() && queued ) {
+ _cg.setColor( QColorGroup::Highlight, QColor( 230, 232, 100 ) );
+ QListViewItem::paintCell( p, _cg, column, width, alignment );
+ return;
+ }
+ else if( queued && column != listView()->sortColumn() ) {
+ _cg.setColor( QColorGroup::Base, QColor( 255, 255, 190 ) );
+ QListViewItem::paintCell( p, _cg, column, width, alignment );
+ return;
+ }
+ else if( queued && column == listView()->sortColumn() ) {
+ _cg.setColor( QColorGroup::Base, QColor( 255, 243, 168 ) );
+ QListViewItem::paintCell( p, _cg, column, width, alignment );
+ return;
+ }
+
+ KListViewItem::paintCell( p, _cg, column, width, alignment );
+}
+
+void ReplayGainFileListItem::setType( Type type )
+{
+ if( type == m_type ) return;
+
+ m_type = type;
+
+ if( type == Album ) {
+ setOpen( true );
+ setPixmap( 0, KGlobal::iconLoader()->loadIcon("cdrom_unmount",KIcon::Small) );
+ }
+}
+
+void ReplayGainFileListItem::updateReplayGainCells( TagData* tags )
+{
+ if( !tags ) {
+ setText( ((ReplayGainFileList*)listView())->columnByName(i18n("Track")), i18n("Unknown") );
+ setText( ((ReplayGainFileList*)listView())->columnByName(i18n("Album")), i18n("Unknown") );
+ }
+ else {
+ if( tags->track_gain != 210588 ) {
+ setText( ((ReplayGainFileList*)listView())->columnByName(i18n("Track")), QString().sprintf("%+.2f dB",tags->track_gain) );
+ }
+ else {
+ setText( ((ReplayGainFileList*)listView())->columnByName(i18n("Track")), i18n("Unknown") );
+ }
+ if( tags->album_gain != 210588 ) {
+ setText( ((ReplayGainFileList*)listView())->columnByName(i18n("Album")), QString().sprintf("%+.2f dB",tags->album_gain) );
+ }
+ else {
+ setText( ((ReplayGainFileList*)listView())->columnByName(i18n("Album")), i18n("Unknown") );
+ }
+ }
+}
+
+int ReplayGainFileListItem::compare( QListViewItem* item, int column, bool ascending ) const
+{
+ // NOTE looking at the types, not the strings would be better
+ if( text(1) == "" && item->text(1) != "" ) return -1;
+ else if( text(1) != "" && item->text(1) == "" ) return 1;
+ else return KListViewItem::compare( item, column, ascending );
+}
+
+ReplayGainFileList::ReplayGainFileList( TagEngine* _tagEngine, Config* _config, Logger* _logger, QWidget *parent, const char *name )
+ : KListView( parent, name )
+{
+ tagEngine = _tagEngine;
+ config = _config;
+ logger = _logger;
+
+ processing = false;
+ queue = false;
+
+ time = 0;
+ processedTime = 0;
+
+ addColumn( i18n("File"), 390 );
+ setColumnWidthMode( 0, QListView::Manual );
+ addColumn( i18n("Track"), 90 );
+ setColumnAlignment( 1, Qt::AlignRight );
+ addColumn( i18n("Album"), 90 );
+ setColumnAlignment( 2, Qt::AlignRight );
+
+ setSelectionMode( QListView::Extended );
+ setAllColumnsShowFocus( true );
+ setResizeMode( QListView::LastColumn );
+ setShowSortIndicator( true );
+ setSorting( 0 );
+ setRootIsDecorated( true );
+
+ setDragEnabled( true );
+ setAcceptDrops( true );
+
+ QGridLayout* grid = new QGridLayout( this, 2, 1, 11, 6 );
+ grid->setRowStretch( 0, 1 );
+ grid->setRowStretch( 2, 1 );
+ grid->setColStretch( 0, 1 );
+ grid->setColStretch( 2, 1 );
+ pScanStatus = new KProgress( this, "pScanStatus" );
+ pScanStatus->setMinimumHeight( pScanStatus->height() );
+ pScanStatus->setFormat( "%v / %m" );
+ pScanStatus->hide();
+ grid->addWidget( pScanStatus, 1, 1 );
+ grid->setColStretch( 1, 2 );
+
+ contextMenu = new KPopupMenu( this );
+ connect( this, SIGNAL(contextMenuRequested(QListViewItem*,const QPoint&,int)),
+ this, SLOT(showContextMenu(QListViewItem*,const QPoint&,int))
+ );
+
+ // we haven't got access to the action collection of soundKonverter, so let's create a new one
+ actionCollection = new KActionCollection( this );
+
+ calc_gain = new KAction( i18n("Calculate Replay Gain tags"), "apply", 0, this, SLOT(calcSelectedItemsGain()), actionCollection, "calc_album" );
+ remove_gain = new KAction( i18n("Remove Replay Gain tags"), "cancel", 0, this, SLOT(removeSelectedItemsGain()), actionCollection, "remove_gain" );
+ remove = new KAction( i18n("Remove"), "edittrash", Key_Delete, this, SLOT(removeSelectedItems()), actionCollection, "remove" );
+ paste = new KAction( i18n("Paste"), "editpaste", 0, this, 0, actionCollection, "paste" );
+ newalbum = new KAction( i18n("New album"), "filenew", 0, this, SLOT(createNewAlbum()), actionCollection, "newalbum" );
+ open_albums = new KAction( i18n("Open all albums"), "view_tree", 0, this, SLOT(openAlbums()), actionCollection, "open_albums" );
+ close_albums = new KAction( i18n("Cloase all albums"), "view_text", 0, this, SLOT(closeAlbums()), actionCollection, "close_albums" );
+
+ replayGain = new ReplayGain( config, logger );
+
+ bubble = new QSimpleRichText( i18n( "<div align=center>"
+ "<h3>Replay Gain Tool</h3>"
+ "With this tool you can add Replay Gain tags to your audio files and remove them."
+ //"<br>Replay Gain adds a volume correction information to the files for playing them at the same volume."
+ //"Replay Gain allows you to play all audio files at the same volume level without modifying the audio data."
+ "<br>Replay Gain adds a volume correction information to the files so that they can be played at an equal volume level."
+// "<br><a href=\"documenation:replaygaintool\">Learn more about Replay Gain ...</a><br/>"
+ "</div>" ), QApplication::font() );
+
+ connect( header(), SIGNAL(sizeChange( int, int, int )),
+ SLOT(columnResizeEvent( int, int, int ))
+ );
+ connect( this, SIGNAL( dropped(QDropEvent*, QListViewItem*, QListViewItem*) ),
+ SLOT( slotDropped(QDropEvent*, QListViewItem*, QListViewItem*) )
+ );
+
+ process = new KProcess();
+ connect( process, SIGNAL(receivedStdout(KProcess*,char*,int)),
+ this, SLOT(processOutput(KProcess*,char*,int))
+ );
+ connect( process, SIGNAL(receivedStderr(KProcess*,char*,int)),
+ this, SLOT(processOutput(KProcess*,char*,int))
+ );
+ connect( process, SIGNAL(processExited(KProcess*)),
+ this, SLOT(processExit(KProcess*))
+ );
+
+ tUpdateProgress = new QTimer( this, "tUpdateProgress" );
+ connect( tUpdateProgress, SIGNAL(timeout()),
+ this, SLOT(update())
+ );
+}
+
+ReplayGainFileList::~ReplayGainFileList()
+{
+ delete replayGain;
+}
+
+int ReplayGainFileList::columnByName( const QString& name )
+{
+ for( int i = 0; i < columns(); ++i ) {
+ if( columnText( i ) == name ) return i;
+ }
+ return -1;
+}
+
+void ReplayGainFileList::viewportPaintEvent( QPaintEvent* e )
+{
+ KListView::viewportPaintEvent( e );
+
+ // the bubble help
+ if( childCount() == 0 ) {
+ QPainter p( viewport() );
+
+ bubble->setWidth( width() - 50 );
+
+ const uint w = bubble->width() + 20;
+ const uint h = bubble->height() + 20;
+
+ p.setBrush( colorGroup().background() );
+ p.drawRoundRect( 15, 15, w, h, (8*200)/w, (8*200)/h );
+ bubble->draw( &p, 20, 20, QRect(), colorGroup() );
+ }
+}
+
+void ReplayGainFileList::viewportResizeEvent( QResizeEvent* )
+{
+ // needed for correct redraw of bubble help
+ triggerUpdate();
+}
+
+void ReplayGainFileList::columnResizeEvent( int, int, int )
+{
+ // needed for correct redraw of bubble help
+ triggerUpdate();
+}
+
+bool ReplayGainFileList::acceptDrag( QDropEvent* e ) const
+{
+ return ( e->source() == viewport() || KURLDrag::canDecode(e) ); // TODO verify the files
+}
+
+void ReplayGainFileList::slotDropped( QDropEvent* e, QListViewItem*, QListViewItem* )
+{
+ QString file;
+ KURL::List list;
+ if( KURLDrag::decode( e, list ) )
+ {
+ for( KURL::List::Iterator it = list.begin(); it != list.end(); ++it )
+ {
+ // TODO verify the files (necessary when multiple files are being dropped)
+ file = QDir::convertSeparators( (*it).pathOrURL() );
+ QFileInfo fileInfo( file );
+ if( fileInfo.isDir() )
+ {
+ addDir( file );
+ }
+ else
+ {
+ addFile( (*it).url() );
+ }
+ }
+ }
+}
+
+void ReplayGainFileList::contentsDragEnterEvent( QDragEnterEvent *e )
+{
+ e->accept( e->source() == viewport() || KURLDrag::canDecode(e) );
+}
+
+void ReplayGainFileList::contentsDragMoveEvent( QDragMoveEvent *e )
+{ // the mouse has moved while dragging some stuff
+
+ // if the file is added from an external app, don't let the user select the position to drop
+ if( e->source() != viewport() ) {
+ setDropHighlighter( false );
+ setDropVisualizer( false );
+ cleanItemHighlighter();
+ cleanDropVisualizer();
+
+ // the rest is handled by KListView
+ KListView::contentsDragMoveEvent( e );
+
+ return;
+ }
+
+ // translate the coordinates of the mouse pointer
+ QPoint vp = contentsToViewport( e->pos() );
+ // and get the list view item below the pointer
+ ReplayGainFileListItem* item = itemAt( vp );
+
+ if( item && item->type() == ReplayGainFileListItem::Album ) { // the pointer is above an 'album' element
+ // draw a nice rect around the item
+ setDropHighlighter( true );
+ setDropVisualizer( false );
+ cleanDropVisualizer();
+ }
+ else if( item ) { // the pointer is above an 'file' element
+ // draw a line above or below the item
+ setDropVisualizer( true );
+ setDropHighlighter( false );
+ cleanItemHighlighter();
+ }
+
+ // the rest is handled by KListView
+ KListView::contentsDragMoveEvent( e );
+}
+
+void ReplayGainFileList::contentsDropEvent( QDropEvent *e )
+{ // the stuff has been dropped
+
+ emit dropped( e, 0, 0 ); // NOTE it works this way
+
+ bool formatError = false;
+
+ cleanDropVisualizer();
+ cleanItemHighlighter();
+
+ // get the item below the mouse pointer, where the stuff has been dropped
+ QPoint vp = contentsToViewport( e->pos() );
+ ReplayGainFileListItem* newParent = itemAt( vp );
+
+ // if the item is a 'file', use the parent item
+ if( newParent && newParent->type() != ReplayGainFileListItem::Album ) {
+ newParent = newParent->parent();
+ }
+
+ // TODO if the mouse is on the left side under the parent but not under the sibling item, use the parent
+/* if( newParent == 0 && vp.x() >= 2*treeStepSize() ) {
+ QPoint p = vp;
+ int height = 0;
+ if( firstChild() ) {
+ height = firstChild()->height();
+ }
+ p.setY( p.y() - height );
+ ReplayGainFileListItem* it = itemAt( p );
+ if( it && it->type() != ReplayGainFileListItem::Album ) {
+ newParent = it->parent();
+ }
+ else if( it ) {
+ newParent = it;
+ }
+ }*/
+
+ ReplayGainFileListItem* i;
+
+ // iterate through all items and move all selected ones
+ for( ReplayGainFileListItem* item = firstChild(); item != 0; ) {
+ if( item->type() == ReplayGainFileListItem::File ) {
+ if( newParent == 0 ) {
+ item = item->nextSibling();
+ continue;
+ }
+ if( item->isSelected() ) {
+ if( newParent == 0 || newParent->mimeType == item->mimeType || newParent->mimeType == "application/octet-stream" ) {
+ if( newParent->mimeType == "application/octet-stream" ) newParent->mimeType = item->mimeType;
+ i = item;
+ item = item->nextSibling();
+ takeItem( i );
+ if( newParent ) newParent->insertItem( i );
+ else insertItem( i );
+ }
+ else {
+ item = item->nextSibling();
+ formatError = true;
+ }
+ }
+ else {
+ item = item->nextSibling();
+ }
+ }
+ else {
+ if( item == newParent ) {
+ item = item->nextSibling();
+ continue;
+ }
+ if( item->isSelected() ) {
+ if( newParent == 0 || newParent->mimeType == item->mimeType || newParent->mimeType == "application/octet-stream" ) {
+ if( newParent->mimeType == "application/octet-stream" ) newParent->mimeType = item->mimeType;
+ for( ReplayGainFileListItem* sub_item = item->firstChild(); sub_item != 0; ) {
+ i = sub_item;
+ sub_item = sub_item->nextSibling();
+ item->takeItem( i );
+ if( newParent ) newParent->insertItem( i );
+ else insertItem( i );
+ }
+ i = item;
+ item = item->nextSibling();
+ delete i;
+ }
+ else {
+ item = item->nextSibling();
+ formatError = true;
+ }
+ }
+ else {
+ for( ReplayGainFileListItem* sub_item = item->firstChild(); sub_item != 0; ) {
+ if( sub_item->isSelected() ) {
+ if( newParent == 0 || newParent->mimeType == item->mimeType || newParent->mimeType == "application/octet-stream" ) {
+ if( newParent && newParent->mimeType == "application/octet-stream" ) newParent->mimeType = item->mimeType;
+ i = sub_item;
+ sub_item = sub_item->nextSibling();
+ item->takeItem( i );
+ if( newParent ) newParent->insertItem( i );
+ else insertItem( i );
+ }
+ else {
+ sub_item = sub_item->nextSibling();
+ formatError = true;
+ }
+ }
+ else {
+ sub_item = sub_item->nextSibling();
+ }
+ }
+ if( item->childCount() == 0 ) {
+ i = item;
+ item = item->nextSibling();
+ delete i;
+ }
+ else {
+ item = item->nextSibling();
+ }
+ }
+ }
+ }
+
+ // FIXME make the mouse pointer look normal
+
+ if( formatError ) {
+ KMessageBox::information( this,
+ i18n("You can't place files of different formats in the same \'album\'."), i18n("Different file formats") );
+ }
+}
+
+int ReplayGainFileList::listDir( const QString& directory, QStringList filter, bool recursive, bool fast, int count )
+{ // NOTE speed up?
+ QDir dir( directory );
+ dir.setFilter( QDir::Files | QDir::Dirs | QDir::NoSymLinks | QDir::Readable );
+
+ QStringList list = dir.entryList();
+
+ for( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) {
+ if( *it == "." || *it == ".." ) continue;
+ QFileInfo fileInfo( directory + "/" + *it );
+ if( fast ) {
+ if( fileInfo.isDir() && recursive ) {
+ count = listDir( directory + "/" + *it, filter, recursive, fast, count );
+ }
+ else if( !fileInfo.isDir() || !recursive ) { // NOTE checking for isFile may not work with all file names
+ // NOTE filter feature
+ for( QStringList::Iterator jt = filter.begin(); jt != filter.end(); ++jt ) {
+ if( (*it).endsWith("."+(*jt),false) ) {
+ count++;
+ pScanStatus->setTotalSteps( count );
+ break;
+ }
+ }
+ if( filter.first() == "" ) {
+ count++;
+ pScanStatus->setTotalSteps( count );
+ }
+ }
+ }
+ else {
+ if( fileInfo.isDir() && recursive ) {
+ count = listDir( directory + "/" + *it, filter, recursive, fast, count );
+ }
+ else if( !fileInfo.isDir() || !recursive ) { // NOTE checking for isFile may not work with all file names
+ // NOTE filter feature
+ for( QStringList::Iterator jt = filter.begin(); jt != filter.end(); ++jt ) {
+ if( (*it).endsWith("."+(*jt),false) ) {
+ addFile( KURL::encode_string(directory + "/" + *it) );
+ count++;
+ pScanStatus->setProgress( count );
+ break;
+ }
+ }
+ if( filter.first() == "" ) {
+ addFile( KURL::encode_string(directory + "/" + *it) );
+ count++;
+ pScanStatus->setProgress( count );
+ }
+ }
+ }
+ }
+
+ return count;
+}
+
+void ReplayGainFileList::showContextMenu( QListViewItem* item, const QPoint& point, int )
+{
+ // remove all items from the context menu
+ contextMenu->clear();
+
+ // add a tilte to our context manu
+ //contextMenu->insertTitle( static_cast<FileListItem*>(item)->fileName );
+
+ // if item is null, we can abort here
+ if( item ) {
+ if( !processing ) {
+ calc_gain->plug( contextMenu );
+ if( item->text(columnByName(i18n("Track"))) != i18n("Unknown") || item->text(columnByName(i18n("Album"))) != i18n("Unknown") ) {
+ remove_gain->plug( contextMenu );
+ }
+ }
+ newalbum->plug( contextMenu );
+ remove->plug( contextMenu );
+ }
+ else {
+ newalbum->plug( contextMenu );
+ }
+ paste->plug( contextMenu );
+ contextMenu->insertSeparator();
+ open_albums->plug( contextMenu );
+ close_albums->plug( contextMenu );
+
+ // show the popup menu
+ contextMenu->popup( point );
+}
+
+void ReplayGainFileList::addFile( const QString& file )
+{
+ QString filename = file;
+ QString filePathName;
+ QString device;
+
+ if( filename.left( 1 ) == "/" ) {
+ filePathName = filename;
+ }
+ else if( filename.left( 7 ) == "file://" ) {
+ filePathName = filename;
+ filePathName.remove( 0, 7 );
+ }
+ else if( filename.left( 13 ) == "system:/home/" ) {
+ filePathName = filename;
+ filePathName.remove( 0, 13 );
+ filePathName = QDir::homeDirPath() + "/" + filePathName;
+ }
+ else if( filename.left( 14 ) == "system:/users/" || filename.left( 6 ) == "home:/" ) {
+ int length = ( filename.left(6) == "home:/" ) ? 6 : 14;
+ QString username = filename;
+ username.remove( 0, length );
+ username = username.left( username.find("/") );
+ filePathName = filename;
+ filePathName.remove( 0, length + username.length() );
+ KUser user( username );
+ filePathName = user.homeDir() + filePathName;
+ }
+ else if( filename.left( 14 ) == "system:/media/" || filename.left( 7 ) == "media:/" ) {
+ int length = ( filename.left(7) == "media:/" ) ? 7 : 14;
+ device = filename;
+ device.remove( 0, length );
+ device = "/dev/" + device.left( device.find( "/" ) );
+
+ KMountPoint::List mountPoints = KMountPoint::possibleMountPoints();
+
+ for( KMountPoint::List::ConstIterator jt = mountPoints.begin(); jt != mountPoints.end(); ++jt )
+ {
+ const KSharedPtr<KMountPoint> mp = *jt;
+ if( mp->mountedFrom() == device )
+ {
+ filePathName = ( mp->mountPoint() == "/" ) ? mp->mountPoint() : mp->mountPoint() + "/";
+ filePathName += filename.right( filename.length() - device.length() - length + 4 );
+ }
+ }
+ }
+ else {
+ return;
+ }
+
+ TagData* tags = tagEngine->readTags( KURL::decode_string(filePathName) );
+ if( !tags || tags->album.isEmpty() ) {
+ ReplayGainFileListItem* item = new ReplayGainFileListItem( this );
+ item->originalFileFormat = filePathName.right( filePathName.length() - filePathName.findRev(".") - 1 );
+ item->mimeType = KMimeType::findByFileContent( filePathName )->name();
+ item->fileFormat = KMimeType::findByFileContent( filePathName )->patterns().first();
+ if( item->mimeType.isEmpty() || item->mimeType == "application/octet-stream" || item->mimeType == "text/plain" ) {
+ item->mimeType = KMimeType::findByURL( filePathName.lower() )->name();
+ item->fileFormat = KMimeType::findByURL( filePathName.lower() )->patterns().first();
+ }
+ // check whether the mime type has a decoder registered
+ if( !config->acceptReplayGainFile( item->mimeType ) ) {
+ delete item;
+ return;
+ }
+ item->filePathName = filePathName;
+ if( tags ) item->time = tags->length;
+ else {
+ FormatItem* formatItem = config->getFormatItem( item->mimeType );
+ if( formatItem && formatItem->size > 0 ) {
+ QFileInfo fileInfo( filePathName );
+ item->time = fileInfo.size() / formatItem->size;
+ }
+ else {
+ item->time = 210;
+ }
+ }
+ item->setText( columnByName(i18n("File")), KURL::decode_string(filePathName).replace("%2f","/").replace("%%","%") );
+ if( tags && tags->track_gain != 210588 ) {
+ item->setText( columnByName(i18n("Track")), QString().sprintf("%+.2f dB",tags->track_gain) );
+ }
+ else {
+ item->setText( columnByName(i18n("Track")), i18n("Unknown") );
+ }
+ if( tags && tags->album_gain != 210588 ) {
+ item->setText( columnByName(i18n("Album")), QString().sprintf("%+.2f dB",tags->album_gain) );
+ }
+ else {
+ item->setText( columnByName(i18n("Album")), i18n("Unknown") );
+ }
+ }
+ else {
+ QString mimeType = KMimeType::findByFileContent( filePathName )->name();
+ QString fileFormat = KMimeType::findByFileContent( filePathName )->patterns().first();
+ if( mimeType.isEmpty() || mimeType == "application/octet-stream" || mimeType == "text/plain" ) {
+ mimeType = KMimeType::findByURL( filePathName.lower() )->name();
+ fileFormat = KMimeType::findByURL( filePathName.lower() )->patterns().first();
+ }
+ // check whether the mime type has a decoder registered
+ if( !config->acceptReplayGainFile( mimeType ) ) {
+ return;
+ }
+
+ for( ReplayGainFileListItem* it = firstChild(); it != 0; it = it->nextSibling() ) {
+ //if( it->text(0) == QString(tags->artist+" - "+tags->album) ) {
+ if( it->text(columnByName(i18n("File"))) == tags->album && it->type() == ReplayGainFileListItem::Album && it->mimeType == mimeType ) {
+ ReplayGainFileListItem* item = new ReplayGainFileListItem( it );
+ item->originalFileFormat = filePathName.right( filePathName.length() - filePathName.findRev(".") - 1 );
+ item->filePathName = filePathName;
+ item->mimeType = mimeType;
+ item->fileFormat = fileFormat;
+ item->time = tags->length;
+ item->setText( columnByName(i18n("File")), KURL::decode_string(filePathName).replace("%2f","/").replace("%%","%") );
+ if( tags->track_gain != 210588 ) {
+ item->setText( columnByName(i18n("Track")), QString().sprintf("%+.2f dB",tags->track_gain) );
+ }
+ else {
+ item->setText( columnByName(i18n("Track")), i18n("Unknown") );
+ }
+ if( tags->album_gain != 210588 ) {
+ item->setText( columnByName(i18n("Album")), QString().sprintf("%+.2f dB",tags->album_gain) );
+ }
+ else {
+ item->setText( columnByName(i18n("Album")), i18n("Unknown") );
+ }
+ tags = 0; // <--,
+ break; // |
+ } // |
+ } // |
+ if( tags ) { // <--'
+ ReplayGainFileListItem* parent = new ReplayGainFileListItem( this );
+ //parent->setText( 0, tags->artist+" - "+tags->album );
+ parent->setText( columnByName(i18n("File")), tags->album );
+ parent->setType( ReplayGainFileListItem::Album );
+ parent->mimeType = mimeType;
+ parent->fileFormat = fileFormat;
+ ReplayGainFileListItem* item = new ReplayGainFileListItem( parent );
+ item->originalFileFormat = filePathName.right( filePathName.length() - filePathName.findRev(".") - 1 );
+ item->filePathName = filePathName;
+ item->mimeType = mimeType;
+ item->fileFormat = fileFormat;
+ item->time = tags->length;
+ item->setText( columnByName(i18n("File")), KURL::decode_string(filePathName).replace("%2f","/").replace("%%","%") );
+ if( tags->track_gain != 210588 ) {
+ item->setText( columnByName(i18n("Track")), QString().sprintf("%+.2f dB",tags->track_gain) );
+ }
+ else {
+ item->setText( columnByName(i18n("Track")), i18n("Unknown") );
+ }
+ if( tags->album_gain != 210588 ) {
+ item->setText( columnByName(i18n("Album")), QString().sprintf("%+.2f dB",tags->album_gain) );
+ }
+ else {
+ item->setText( columnByName(i18n("Album")), i18n("Unknown") );
+ }
+ }
+ }
+}
+
+void ReplayGainFileList::addDir( const QString& directory, const QStringList& filter, bool recursive )
+{
+ pScanStatus->setProgress( 0 );
+ pScanStatus->setTotalSteps( 0 );
+ pScanStatus->show(); // show the status while scanning the directories
+ kapp->processEvents();
+
+ int count = listDir( directory, filter, recursive, true );
+ listDir( directory, filter, recursive );
+
+ pScanStatus->hide(); // hide the status bar, when the scan is done
+}
+
+void ReplayGainFileList::openAlbums()
+{
+ // iterate through all items and open all albums
+ for( ReplayGainFileListItem* item = firstChild(); item != 0; item = item->nextSibling() ) {
+ if( item->type() == ReplayGainFileListItem::Album ) {
+ item->setOpen( true );
+ }
+ }
+}
+
+void ReplayGainFileList::closeAlbums()
+{
+ // iterate through all items and close all albums
+ for( ReplayGainFileListItem* item = firstChild(); item != 0; item = item->nextSibling() ) {
+ if( item->type() == ReplayGainFileListItem::Album ) {
+ item->setOpen( false );
+ }
+ }
+}
+
+void ReplayGainFileList::removeSelectedItems()
+{
+ ReplayGainFileListItem* i;
+
+ // iterate through all items and remove all selected ones
+ for( ReplayGainFileListItem* item = firstChild(); item != 0; ) {
+ if( item->type() == ReplayGainFileListItem::File ) {
+ if( item->isSelected() ) {
+ i = item;
+ item = item->nextSibling();
+ delete i;
+ }
+ else {
+ item = item->nextSibling();
+ }
+ }
+ else {
+ if( item->isSelected() ) {
+ i = item;
+ item = item->nextSibling();
+ delete i;
+ }
+ else {
+ for( ReplayGainFileListItem* sub_item = item->firstChild(); sub_item != 0; ) {
+ if( sub_item->isSelected() ) {
+ i = sub_item;
+ sub_item = sub_item->nextSibling();
+ delete i;
+ }
+ else {
+ sub_item = sub_item->nextSibling();
+ }
+ }
+ if( item->childCount() == 0 ) {
+ i = item;
+ item = item->nextSibling();
+ delete i;
+ }
+ else {
+ item = item->nextSibling();
+ }
+ }
+ }
+ }
+}
+
+void ReplayGainFileList::createNewAlbum()
+{
+ ReplayGainFileListItem* item = new ReplayGainFileListItem( this );
+ item->setText( columnByName(i18n("File")), i18n("New album") );
+ item->setType( ReplayGainFileListItem::Album );
+ item->mimeType = "application/octet-stream";
+}
+
+void ReplayGainFileList::calcSelectedItemsGain()
+{
+ if( processing ) return;
+
+ // iterate through all items and remove the replay gain from all selected ones
+ for( ReplayGainFileListItem* item = firstChild(); item != 0; item = item->nextSibling() ) {
+ if( item->type() == ReplayGainFileListItem::File ) {
+ if( item->isSelected() ) {
+ item->queued = true;
+ item->repaint();
+ item->mode = ReplayGainFileListItem::force;
+ }
+ }
+ else {
+ if( item->isSelected() ) {
+ item->queued = true;
+ item->repaint();
+ item->mode = ReplayGainFileListItem::force;
+ for( ReplayGainFileListItem* sub_item = item->firstChild(); sub_item != 0; sub_item = sub_item->nextSibling() ) {
+ sub_item->queued = true;
+ sub_item->repaint();
+ sub_item->mode = ReplayGainFileListItem::force;
+ }
+ }
+ else {
+ for( ReplayGainFileListItem* sub_item = item->firstChild(); sub_item != 0; sub_item = sub_item->nextSibling() ) {
+ if( sub_item->isSelected() ) {
+ item->queued = true;
+ item->repaint();
+ item->mode = ReplayGainFileListItem::force;
+ for( ReplayGainFileListItem* sub_item2 = item->firstChild(); sub_item2 != 0; sub_item2 = sub_item2->nextSibling() ) {
+ sub_item2->queued = true;
+ sub_item2->repaint();
+ sub_item2->mode = ReplayGainFileListItem::force;
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ startProcess();
+}
+
+void ReplayGainFileList::removeSelectedItemsGain()
+{
+ // iterate through all items and remove the replay gain from all selected ones
+ for( ReplayGainFileListItem* item = firstChild(); item != 0; item = item->nextSibling() ) {
+ if( item->type() == ReplayGainFileListItem::File ) {
+ if( item->isSelected() && !item->addingReplayGain ) {
+ item->queued = true;
+ item->repaint();
+ item->mode = ReplayGainFileListItem::remove;
+ }
+ }
+ else {
+ if( item->isSelected() && !item->addingReplayGain ) {
+ item->queued = true;
+ item->repaint();
+ item->mode = ReplayGainFileListItem::remove;
+ for( ReplayGainFileListItem* sub_item = item->firstChild(); sub_item != 0; sub_item = sub_item->nextSibling() ) {
+ sub_item->queued = true;
+ sub_item->repaint();
+ sub_item->mode = ReplayGainFileListItem::remove;
+ }
+ }
+ else {
+ for( ReplayGainFileListItem* sub_item = item->firstChild(); sub_item != 0; sub_item = sub_item->nextSibling() ) {
+ if( sub_item->isSelected() && !sub_item->addingReplayGain ) {
+ sub_item->queued = true;
+ sub_item->repaint();
+ sub_item->mode = ReplayGainFileListItem::remove;
+ }
+ }
+ }
+ }
+ }
+ startProcess();
+}
+
+void ReplayGainFileList::calcReplayGain( ReplayGainFileListItem* item )
+{
+ logID = logger->registerProcess( KURL::encode_string(item->text(columnByName(i18n("File")))) );
+ logger->log( logID, "Mime Type: " + item->mimeType );
+ logger->log( logID, i18n("Applying Replay Gain") );
+
+ QStringList fileList;
+ bool force = false;
+ if( mode & ReplayGainFileListItem::force ) force = true;
+ QString album_gain = "";
+ bool skip = true;
+
+ timeCount = 0;
+ file = 0;
+ files = 0;
+
+ if( item->type() == ReplayGainFileListItem::Album ) {
+ item->queued = false;
+ item->addingReplayGain = true;
+ item->repaint();
+ for( ReplayGainFileListItem* sub_item = item->firstChild(); sub_item != 0; sub_item = sub_item->nextSibling() ) {
+ if( sub_item->queued && sub_item->mode & ReplayGainFileListItem::force ) force = true; // NOTE can this be replaced by checking item?
+ sub_item->queued = false;
+ sub_item->addingReplayGain = true;
+ sub_item->repaint();
+
+ fileList += sub_item->filePathName;
+ files++;
+ timeCount += sub_item->time;
+
+ QString current_gain = sub_item->text( columnByName(i18n("Album")) );
+ if( album_gain == "" ) album_gain = current_gain;
+ else if( album_gain != current_gain ) skip = false;
+ }
+
+ if( !skip || album_gain == i18n("Unknown") || force ) {
+ if( force ) {
+ replayGain->apply( fileList, item->mimeType, process, logID, ReplayGain::Mode(ReplayGain::calc_album|ReplayGain::force) );
+ }
+ else {
+ replayGain->apply( fileList, item->mimeType, process, logID );
+ }
+ }
+ else {
+ logger->processCompleted( logID, 0 );
+ item->addingReplayGain = false;
+ item->repaint();
+ for( ReplayGainFileListItem* sub_item = item->firstChild(); sub_item != 0; sub_item = sub_item->nextSibling() ) {
+ sub_item->addingReplayGain = false;
+ sub_item->repaint();
+ }
+ processNextFile();
+ }
+ }
+ else {
+ if( item->queued && item->mode & ReplayGainFileListItem::force ) force = true;
+
+ item->queued = false;
+ item->addingReplayGain = true;
+ item->repaint();
+
+ files = 1;
+ timeCount = item->time;
+
+ if( force ) {
+ replayGain->apply( item->filePathName, item->mimeType, process, logID, ReplayGain::Mode(ReplayGain::calc_album|ReplayGain::force) );
+ }
+ else {
+ replayGain->apply( item->filePathName, item->mimeType, process, logID );
+ }
+ }
+}
+
+void ReplayGainFileList::removeReplayGain( ReplayGainFileListItem* item )
+{
+ logID = logger->registerProcess( KURL::encode_string(item->text(columnByName(i18n("File")))) );
+ logger->log( logID, "Mime Type: " + item->mimeType );
+ logger->log( logID, i18n("Removing Replay Gain") );
+
+ if( item->type() == ReplayGainFileListItem::File ) {
+ item->queued = false;
+ item->addingReplayGain = true;
+ item->repaint();
+ timeCount = item->time;
+ replayGain->apply( item->filePathName, item->mimeType, process, logID, ReplayGain::remove );
+ }
+ else {
+ item->queued = false;
+ item->repaint();
+ processNextFile();
+ }
+}
+
+void ReplayGainFileList::calcAllReplayGain( bool force )
+{
+ queue = true;
+ if( force ) mode = ReplayGainFileListItem::force;
+ else mode = ReplayGainFileListItem::Mode(0x0000);
+ startProcess();
+}
+
+void ReplayGainFileList::removeAllReplayGain()
+{
+ queue = true;
+ mode = ReplayGainFileListItem::remove;
+ startProcess();
+}
+
+void ReplayGainFileList::cancelProcess()
+{
+ queue = false;
+ if( process->isRunning() )
+ {
+ bool ret = process->kill( SIGKILL );
+ if( ret ) {
+ logger->log( logID, i18n("Killing process ...") );
+ }
+ else {
+ logger->log( logID, i18n("Killing process failed. Stopping after files are completed ...") );
+ }
+ }
+}
+
+void ReplayGainFileList::startProcess()
+{
+ emit processStarted();
+ processing = true;
+ time = 0;
+
+ for( ReplayGainFileListItem* item = firstChild(); item != 0; item = item->nextSibling() ) {
+ if( item->type() == ReplayGainFileListItem::File ) {
+ if( queue ) {
+ time += item->time;
+ }
+ else if( item->queued ) {
+ time += item->time;
+ }
+ }
+ else {
+ for( ReplayGainFileListItem* sub_item = item->firstChild(); sub_item != 0; sub_item = sub_item->nextSibling() ) {
+ if( queue ) {
+ time += sub_item->time;
+ }
+ else if( sub_item->queued ) {
+ time += sub_item->time;
+ }
+ }
+ }
+ }
+
+ emit updateProgress( 0, 100 );
+ if( !tUpdateProgress->isActive() ) {
+ tUpdateProgress->start( 200 ); // TODO use config value
+ }
+
+ currentItem = 0;
+ processNextFile();
+}
+
+void ReplayGainFileList::processNextFile()
+{
+ percent = 0;
+ lastPercent = 0;
+
+ ReplayGainFileListItem* currentSubItem = 0;
+
+ if( !currentItem ) { currentItem = firstChild(); }
+ else if( currentItem->type() == ReplayGainFileListItem::File && currentItem->parent() == 0 ) { currentItem = currentItem->nextSibling(); }
+ else if( currentItem->type() == ReplayGainFileListItem::Album ) { currentItem = currentItem->nextSibling(); }
+ else { currentSubItem = currentItem->nextSibling(); currentItem = currentItem->parent(); if( !currentSubItem ) { currentItem = currentItem->nextSibling(); } }
+
+ for( ReplayGainFileListItem* item = currentItem; item != 0; item = item->nextSibling() ) {
+ if( item->type() == ReplayGainFileListItem::File ) {
+ if( queue ) {
+ currentItem = item;
+ if( mode & ReplayGainFileListItem::remove ) removeReplayGain( item );
+ else calcReplayGain( item );
+ return;
+ }
+ else if( item->queued ) {
+ currentItem = item;
+ if( item->mode & ReplayGainFileListItem::remove ) removeReplayGain( item );
+ else calcReplayGain( item );
+ return;
+ }
+ }
+ else {
+ if( queue ) {
+ currentItem = item;
+ if( mode & ReplayGainFileListItem::remove ) {}
+ else { calcReplayGain( item ); return; }
+ }
+ else if( item->queued ) {
+ currentItem = item;
+ if( item->mode & ReplayGainFileListItem::remove ) { item->queued = false; }
+ else { calcReplayGain( item ); return; }
+ }
+
+ if( !currentSubItem ) currentSubItem = item->firstChild();
+ for( ReplayGainFileListItem* sub_item = currentSubItem; sub_item != 0; sub_item = sub_item->nextSibling() ) {
+ if( queue ) {
+ currentItem = sub_item;
+ if( mode & ReplayGainFileListItem::remove ) removeReplayGain( sub_item );
+ return;
+ }
+ else if( sub_item->queued ) {
+ currentItem = sub_item;
+ if( sub_item->mode & ReplayGainFileListItem::remove ) removeReplayGain( sub_item );
+ return;
+ }
+ }
+
+ currentSubItem = 0;
+ }
+ }
+ queue = false;
+ tUpdateProgress->stop();
+ processedTime = 0;
+ processing = false;
+ emit processStopped();
+}
+
+void ReplayGainFileList::processOutput( KProcess* proc, char* data, int )
+{
+ int iPercent = 0, iTime = 0, iPos = 0, iNum = 0;
+
+ QString log_data = data;
+ log_data.replace("\n","\\n");
+ log_data.replace("\t","\\t");
+ log_data.replace("\r","\\r");
+ log_data.replace("\b","\\b");
+ logger->log( logID, " " + i18n("Output") + ": " + log_data );
+
+ ReplayGainPlugin* plugin = config->replaygainForFormat( currentItem->mimeType );
+ if( plugin == 0 ) { // shouldn't happen
+ logger->log( logID, " NULL POINTER: ReplayGainScanner::processOutput( ... ) / plugin" );
+ return;
+ }
+ if( plugin->info.name == i18n("built-in") ) { // shouldn't happen // TODO implement a check for this
+ logger->log( logID, " Backend is an encoder" );
+ return;
+ }
+
+ QString outputPattern = ( files > 1 ) ? plugin->replaygain.output_multiple : plugin->replaygain.output_single;
+ //outputPattern.replace( "%i", "%p" ); // for compatibility with old plugins
+
+ if( outputPattern.find("%p") != -1 || outputPattern.find("%a") != -1 ) {
+ outputPattern.replace( "%p", "%i" );
+ //outputPattern.replace( "%a", "%i" ); // for compatibility with old plugins
+ sscanf( data, outputPattern, &iPercent );
+ }
+ /*else if( outputPattern.find("%t") != -1 ) { // NOTE a little bit complicated and not necessary
+ outputPattern.replace( "%t", "%i" );
+ sscanf( data, outputPattern, &iTime );
+ iPercent = iTime * 100 / currentItem->time;
+ }*/
+ else if( outputPattern.find("%0") != -1 && outputPattern.find("%1") != -1 ) {
+ if( outputPattern.find("%0") < outputPattern.find("%1") ) {
+ outputPattern.replace( "%0", "%i" );
+ outputPattern.replace( "%1", "%i" );
+ sscanf( data, outputPattern, &iPos, &iNum );
+ }
+ else {
+ outputPattern.replace( "%0", "%i" );
+ outputPattern.replace( "%1", "%i" );
+ sscanf( data, outputPattern, &iNum, &iPos );
+ }
+ if( iPos != 0 && iNum != 0 ) iPercent = iPos * 100 / iNum;
+ }
+
+ if( iPercent > 0 && iPercent <= 100 )
+ {
+ // TODO guess progress, when no signal is received
+ //lastOutputTimer.start();
+ if( files > 1 ) {
+ if( iPercent < lastPercent ) file++;
+ lastPercent = iPercent;
+ percent = file * 100 / files + iPercent / files;
+ }
+ else {
+ percent = iPercent;
+ }
+ }
+}
+
+void ReplayGainFileList::processExit( KProcess* proc )
+{
+ logger->processCompleted( logID, ( proc->signalled() ) ? -1 : 0 );
+
+ for( ReplayGainFileListItem* item = firstChild(); item != 0; item = item->nextSibling() ) {
+ if( item->type() == ReplayGainFileListItem::File ) {
+ if( item->addingReplayGain ) {
+ processedTime += item->time;
+ item->addingReplayGain = false;
+ item->repaint();
+ item->updateReplayGainCells( tagEngine->readTags(KURL::decode_string(item->filePathName)) );
+ }
+ if( item->queued && proc->signalled() ) {
+ item->queued = false;
+ item->repaint();
+ }
+ }
+ else {
+ if( item->addingReplayGain ) {
+ item->addingReplayGain = false;
+ item->repaint();
+ for( ReplayGainFileListItem* sub_item = item->firstChild(); sub_item != 0; sub_item = sub_item->nextSibling() ) {
+ processedTime += sub_item->time;
+ sub_item->addingReplayGain = false;
+ sub_item->repaint();
+ sub_item->updateReplayGainCells( tagEngine->readTags(KURL::decode_string(sub_item->filePathName)) );
+ }
+ }
+ if( item->queued && proc->signalled() ) {
+ item->queued = false;
+ item->repaint();
+ for( ReplayGainFileListItem* sub_item = item->firstChild(); sub_item != 0; sub_item = sub_item->nextSibling() ) {
+ sub_item->queued = false;
+ sub_item->repaint();
+ }
+ }
+ for( ReplayGainFileListItem* sub_item = item->firstChild(); sub_item != 0; sub_item = sub_item->nextSibling() ) {
+ if( sub_item->addingReplayGain ) {
+ processedTime += sub_item->time;
+ sub_item->addingReplayGain = false;
+ sub_item->repaint();
+ sub_item->updateReplayGainCells( tagEngine->readTags(KURL::decode_string(sub_item->filePathName)) );
+ }
+ if( sub_item->queued && proc->signalled() ) {
+ sub_item->queued = false;
+ sub_item->repaint();
+ }
+ }
+ }
+ }
+ if( proc->signalled() ) {
+ queue = false;
+ tUpdateProgress->stop();
+ processedTime = 0;
+ processing = false;
+ emit processStopped();
+ return;
+ }
+ else {
+ processNextFile();
+ }
+}
+
+void ReplayGainFileList::update()
+{
+ emit updateProgress( int(processedTime) + percent * int(timeCount) / 100, int(time) );
+}
+