You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
soundkonverter/src/replaygainfilelist.cpp

1263 lines
47 KiB

#include "replaygainfilelist.h"
#include "tagengine.h"
#include "logger.h"
#include "config.h"
#include "replaygain.h"
#include "replaygainpluginloader.h"
#include <tqdir.h>
#include <tqpainter.h>
#include <tqsimplerichtext.h>
#include <tqapplication.h>
#include <tqheader.h>
#include <tqlayout.h>
#include <tqtimer.h>
#include <tdelocale.h>
#include <kiconloader.h>
#include <kurldrag.h>
#include <tdepopupmenu.h>
#include <tdeaction.h>
#include <tdeactioncollection.h>
#include <tdemessagebox.h>
#include <kmountpoint.h>
#include <kprogress.h>
#include <kprocess.h>
#include <kmimetype.h>
#include <tdeapplication.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( TQListView* parent )
: TDEListViewItem( parent )
{
m_type = File;
mimeType = "application/octet-stream";
addingReplayGain = false;
queued = false;
}
// ReplayGainFileListItem::ReplayGainFileListItem( TQListView* parent, TQListViewItem* after )
// : TDEListViewItem( parent, after )
// {
// m_type = File;
// mimeType = "application/octet-stream";
// addingReplayGain = false;
// queued = false;
// }
ReplayGainFileListItem::ReplayGainFileListItem( ReplayGainFileListItem* parent )
: TDEListViewItem( parent )
{
m_type = File;
mimeType = "application/octet-stream";
addingReplayGain = false;
queued = false;
}
ReplayGainFileListItem::~ReplayGainFileListItem()
{}
void ReplayGainFileListItem::paintCell( TQPainter *p, const TQColorGroup &cg, int column, int width, int alignment )
{
// NOTE speed up this function
// NOTE calculate the red color
TQColorGroup _cg( cg );
TQColor c;
if( column == ((ReplayGainFileList*)listView())->columnByName(i18n("File")) )
{
int margin = listView()->itemMargin();
int w = width - 2*margin;
int h = height();
TQRect textRect = p->boundingRect( margin, 0, w, h, alignment, text(column) );
if( textRect.width() > w ) {
alignment = TQt::AlignRight | TQt::SingleLine;
}
}
if( isSelected() && addingReplayGain ) {
_cg.setColor( TQColorGroup::Highlight, TQColor( 215, 62, 62 ) );
TQListViewItem::paintCell( p, _cg, column, width, alignment );
return;
}
else if( addingReplayGain && column != listView()->sortColumn() ) {
_cg.setColor( TQColorGroup::Base, TQColor( 255, 234, 234 ) );
TQListViewItem::paintCell( p, _cg, column, width, alignment );
return;
}
else if( addingReplayGain && column == listView()->sortColumn() ) {
_cg.setColor( TQColorGroup::Base, TQColor( 247, 227, 227 ) );
TQListViewItem::paintCell( p, _cg, column, width, alignment );
return;
}
if( isSelected() && queued ) {
_cg.setColor( TQColorGroup::Highlight, TQColor( 230, 232, 100 ) );
TQListViewItem::paintCell( p, _cg, column, width, alignment );
return;
}
else if( queued && column != listView()->sortColumn() ) {
_cg.setColor( TQColorGroup::Base, TQColor( 255, 255, 190 ) );
TQListViewItem::paintCell( p, _cg, column, width, alignment );
return;
}
else if( queued && column == listView()->sortColumn() ) {
_cg.setColor( TQColorGroup::Base, TQColor( 255, 243, 168 ) );
TQListViewItem::paintCell( p, _cg, column, width, alignment );
return;
}
TDEListViewItem::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, TDEGlobal::iconLoader()->loadIcon("media-optical-cdrom-unmounted",TDEIcon::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")), TQString().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")), TQString().sprintf("%+.2f dB",tags->album_gain) );
}
else {
setText( ((ReplayGainFileList*)listView())->columnByName(i18n("Album")), i18n("Unknown") );
}
}
}
int ReplayGainFileListItem::compare( TQListViewItem* 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 TDEListViewItem::compare( item, column, ascending );
}
ReplayGainFileList::ReplayGainFileList( TagEngine* _tagEngine, Config* _config, Logger* _logger, TQWidget *parent, const char *name )
: TDEListView( parent, name )
{
tagEngine = _tagEngine;
config = _config;
logger = _logger;
processing = false;
queue = false;
time = 0;
processedTime = 0;
addColumn( i18n("File"), 390 );
setColumnWidthMode( 0, TQListView::Manual );
addColumn( i18n("Track"), 90 );
setColumnAlignment( 1, TQt::AlignRight );
addColumn( i18n("Album"), 90 );
setColumnAlignment( 2, TQt::AlignRight );
setSelectionMode( TQListView::Extended );
setAllColumnsShowFocus( true );
setResizeMode( TQListView::LastColumn );
setShowSortIndicator( true );
setSorting( 0 );
setRootIsDecorated( true );
setDragEnabled( true );
setAcceptDrops( true );
TQGridLayout* grid = new TQGridLayout( 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 TDEPopupMenu( this );
connect( TQT_TQOBJECT(this), TQT_SIGNAL(contextMenuRequested(TQListViewItem*,const TQPoint&,int)),
TQT_TQOBJECT(this), TQT_SLOT(showContextMenu(TQListViewItem*,const TQPoint&,int))
);
// we haven't got access to the action collection of soundKonverter, so let's create a new one
actionCollection = new TDEActionCollection( this );
calc_gain = new TDEAction( i18n("Calculate Replay Gain tags"), "apply", 0, TQT_TQOBJECT(this), TQT_SLOT(calcSelectedItemsGain()), actionCollection, "calc_album" );
remove_gain = new TDEAction( i18n("Remove Replay Gain tags"), "cancel", 0, TQT_TQOBJECT(this), TQT_SLOT(removeSelectedItemsGain()), actionCollection, "remove_gain" );
remove = new TDEAction( i18n("Remove"), "edittrash", Key_Delete, TQT_TQOBJECT(this), TQT_SLOT(removeSelectedItems()), actionCollection, "remove" );
paste = new TDEAction( i18n("Paste"), "edit-paste", 0, TQT_TQOBJECT(this), 0, actionCollection, "paste" );
newalbum = new TDEAction( i18n("New album"), "document-new", 0, TQT_TQOBJECT(this), TQT_SLOT(createNewAlbum()), actionCollection, "newalbum" );
open_albums = new TDEAction( i18n("Open all albums"), "view_tree", 0, TQT_TQOBJECT(this), TQT_SLOT(openAlbums()), actionCollection, "open_albums" );
close_albums = new TDEAction( i18n("Cloase all albums"), "view_text", 0, TQT_TQOBJECT(this), TQT_SLOT(closeAlbums()), actionCollection, "close_albums" );
replayGain = new ReplayGain( config, logger );
bubble = new TQSimpleRichText( 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>" ), TQApplication::font() );
connect( header(), TQT_SIGNAL(sizeChange( int, int, int )),
TQT_SLOT(columnResizeEvent( int, int, int ))
);
connect( TQT_TQOBJECT(this), TQT_SIGNAL( dropped(TQDropEvent*, TQListViewItem*, TQListViewItem*) ),
TQT_SLOT( slotDropped(TQDropEvent*, TQListViewItem*, TQListViewItem*) )
);
process = new TDEProcess();
connect( process, TQT_SIGNAL(receivedStdout(TDEProcess*,char*,int)),
TQT_TQOBJECT(this), TQT_SLOT(processOutput(TDEProcess*,char*,int))
);
connect( process, TQT_SIGNAL(receivedStderr(TDEProcess*,char*,int)),
TQT_TQOBJECT(this), TQT_SLOT(processOutput(TDEProcess*,char*,int))
);
connect( process, TQT_SIGNAL(processExited(TDEProcess*)),
TQT_TQOBJECT(this), TQT_SLOT(processExit(TDEProcess*))
);
tUpdateProgress = new TQTimer( this, "tUpdateProgress" );
connect( tUpdateProgress, TQT_SIGNAL(timeout()),
TQT_TQOBJECT(this), TQT_SLOT(update())
);
}
ReplayGainFileList::~ReplayGainFileList()
{
delete replayGain;
}
int ReplayGainFileList::columnByName( const TQString& name )
{
for( int i = 0; i < columns(); ++i ) {
if( columnText( i ) == name ) return i;
}
return -1;
}
void ReplayGainFileList::viewportPaintEvent( TQPaintEvent* e )
{
TDEListView::viewportPaintEvent( e );
// the bubble help
if( childCount() == 0 ) {
TQPainter 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, TQRect(), colorGroup() );
}
}
void ReplayGainFileList::viewportResizeEvent( TQResizeEvent* )
{
// 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( TQDropEvent* e ) const
{
return ( e->source() == viewport() || KURLDrag::canDecode(e) ); // TODO verify the files
}
void ReplayGainFileList::slotDropped( TQDropEvent* e, TQListViewItem*, TQListViewItem* )
{
TQString 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 = TQDir::convertSeparators( (*it).pathOrURL() );
TQFileInfo fileInfo( file );
if( fileInfo.isDir() )
{
addDir( file );
}
else
{
addFile( (*it).url() );
}
}
}
}
void ReplayGainFileList::contentsDragEnterEvent( TQDragEnterEvent *e )
{
e->accept( e->source() == viewport() || KURLDrag::canDecode(e) );
}
void ReplayGainFileList::contentsDragMoveEvent( TQDragMoveEvent *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 TDEListView
TDEListView::contentsDragMoveEvent( e );
return;
}
// translate the coordinates of the mouse pointer
TQPoint 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 TDEListView
TDEListView::contentsDragMoveEvent( e );
}
void ReplayGainFileList::contentsDropEvent( TQDropEvent *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
TQPoint 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() ) {
TQPoint 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 TQString& directory, TQStringList filter, bool recursive, bool fast, int count )
{ // NOTE speed up?
TQDir dir( directory );
dir.setFilter( TQDir::Files | TQDir::Dirs | TQDir::NoSymLinks | TQDir::Readable );
TQStringList list = dir.entryList();
for( TQStringList::Iterator it = list.begin(); it != list.end(); ++it ) {
if( *it == "." || *it == ".." ) continue;
TQFileInfo 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( TQStringList::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( TQStringList::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( TQListViewItem* item, const TQPoint& 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 TQString& file )
{
TQString filename = file;
TQString filePathName;
TQString 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 = TQDir::homeDirPath() + "/" + filePathName;
}
else if( filename.left( 14 ) == "system:/users/" || filename.left( 6 ) == "home:/" ) {
int length = ( filename.left(6) == "home:/" ) ? 6 : 14;
TQString 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 TDESharedPtr<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 ) {
TQFileInfo 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")), TQString().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")), TQString().sprintf("%+.2f dB",tags->album_gain) );
}
else {
item->setText( columnByName(i18n("Album")), i18n("Unknown") );
}
}
else {
TQString mimeType = KMimeType::findByFileContent( filePathName )->name();
TQString 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) == TQString(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")), TQString().sprintf("%+.2f dB",tags->track_gain) );
}
else {
item->setText( columnByName(i18n("Track")), i18n("Unknown") );
}
if( tags->album_gain != 210588 ) {
item->setText( columnByName(i18n("Album")), TQString().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")), TQString().sprintf("%+.2f dB",tags->track_gain) );
}
else {
item->setText( columnByName(i18n("Track")), i18n("Unknown") );
}
if( tags->album_gain != 210588 ) {
item->setText( columnByName(i18n("Album")), TQString().sprintf("%+.2f dB",tags->album_gain) );
}
else {
item->setText( columnByName(i18n("Album")), i18n("Unknown") );
}
}
}
}
void ReplayGainFileList::addDir( const TQString& directory, const TQStringList& 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") );
TQStringList fileList;
bool force = false;
if( mode & ReplayGainFileListItem::force ) force = true;
TQString 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;
TQString 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( TDEProcess* proc, char* data, int )
{
int iPercent = 0, iTime = 0, iPos = 0, iNum = 0;
TQString 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;
}
TQString 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( TDEProcess* 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) );
}