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.
1446 lines
60 KiB
1446 lines
60 KiB
|
|
#include "filelist.h"
|
|
#include "cdmanager.h"
|
|
#include "tagengine.h"
|
|
#include "options.h"
|
|
#include "convert.h"
|
|
#include "optionseditor.h"
|
|
#include "outputdirectory.h"
|
|
#include "config.h"
|
|
#include "logger.h"
|
|
#include "convertpluginloader.h" // NOTE DEBUG
|
|
|
|
#include <tdelocale.h>
|
|
#include <tdepopupmenu.h>
|
|
#include <tdeaction.h>
|
|
#include <tdeactioncollection.h>
|
|
#include <kmimetype.h>
|
|
#include <kurl.h>
|
|
#include <kmountpoint.h>
|
|
#include <kstandarddirs.h>
|
|
#include <kurldrag.h>
|
|
#include <tdeapplication.h>
|
|
|
|
#include <tqlayout.h>
|
|
#include <tqfileinfo.h>
|
|
#include <tqsimplerichtext.h>
|
|
#include <tqpainter.h>
|
|
#include <tqapplication.h>
|
|
#include <tqdragobject.h>
|
|
#include <tqheader.h>
|
|
#include <tqdir.h>
|
|
#include <kprogress.h>
|
|
#include <kuser.h>
|
|
|
|
// TODO when stopping items by using the context menu, the queue mode restarts that item
|
|
|
|
// TODO when dropping items, don't let the user select the position
|
|
|
|
// ### soundkonverter 0.4: draw tooltip like bubble info box
|
|
|
|
FileListItem::FileListItem( TDEListView* parent, FileListItem* after )
|
|
: TDEListViewItem( parent, after )
|
|
{
|
|
tags = 0;
|
|
converting = false;
|
|
time = 0;
|
|
ripping = false;
|
|
}
|
|
|
|
FileListItem::FileListItem( TDEListView* parent )
|
|
: TDEListViewItem( parent )
|
|
{
|
|
tags = 0;
|
|
converting = false;
|
|
time = 0;
|
|
ripping = false;
|
|
}
|
|
|
|
FileListItem::~FileListItem()
|
|
{}
|
|
|
|
void FileListItem::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 == ((FileList*)listView())->columnByName(i18n("Input")) || column == ((FileList*)listView())->columnByName(i18n("Output")) )
|
|
{
|
|
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 ( textRect.width() <= w ) {
|
|
p->drawText( margin, 0, w, h, alignment | TQt::SingleLine | TQt::ExpandTabs, text(column), -1 );
|
|
}
|
|
else {
|
|
textRect = p->boundingRect( margin, 0, w, h, TQt::AlignLeft, "... " );
|
|
p->drawText( margin, 0, textRect.width(), h, TQt::AlignLeft | TQt::SingleLine | TQt::ExpandTabs, "...", -1 );
|
|
p->drawText( margin+textRect.width(), 0, w-textRect.width(), h, TQt::AlignRight | TQt::SingleLine | TQt::ExpandTabs, text(column), -1 );
|
|
}*/
|
|
}
|
|
|
|
if( isSelected() && converting ) {
|
|
_cg.setColor( TQColorGroup::Highlight, TQColor( 215, 62, 62 ) );
|
|
TQListViewItem::paintCell( p, _cg, column, width, alignment );
|
|
return;
|
|
}
|
|
else if( converting && column != listView()->sortColumn() ) {
|
|
_cg.setColor( TQColorGroup::Base, TQColor( 255, 234, 234 ) );
|
|
TQListViewItem::paintCell( p, _cg, column, width, alignment );
|
|
return;
|
|
}
|
|
else if( converting && column == listView()->sortColumn() ) {
|
|
_cg.setColor( TQColorGroup::Base, TQColor( 247, 227, 227 ) );
|
|
TQListViewItem::paintCell( p, _cg, column, width, alignment );
|
|
return;
|
|
}
|
|
|
|
TDEListViewItem::paintCell( p, _cg, column, width, alignment );
|
|
}
|
|
|
|
/*void FileListItem::updateOutputCell()
|
|
{
|
|
setText( ((FileList*)listView())->columnByName(i18n("Output")), OutputDirectory::calcPath(this) ); // FIXME no config !!!
|
|
}
|
|
|
|
void FileListItem::updateOptionsCell()
|
|
{
|
|
setText( ((FileList*)listView())->columnByName(i18n("Quality")), ((FileList*)listView())->config->getProfileName(options) );
|
|
}*/
|
|
|
|
FileList::FileList( CDManager* _cdManager, TagEngine* _tagEngine, Config* _config, Options* _options, Logger* _logger, TQWidget* parent, const char* name )
|
|
: TDEListView( parent, name )
|
|
{
|
|
cdManager = _cdManager;
|
|
tagEngine = _tagEngine;
|
|
config = _config;
|
|
options = _options;
|
|
logger = _logger;
|
|
optionsEditor = 0;
|
|
|
|
queue = false;
|
|
notify = "";
|
|
|
|
setAcceptDrops( true );
|
|
setDragEnabled( true );
|
|
|
|
addColumn( i18n("State"), 120 );
|
|
addColumn( i18n("Input"), 180 );
|
|
addColumn( i18n("Output"), 180 );
|
|
addColumn( i18n("Quality") );
|
|
|
|
header()->setClickEnabled( false );
|
|
|
|
setSelectionMode( TQListView::Extended );
|
|
setAllColumnsShowFocus( true );
|
|
setResizeMode( LastColumn );
|
|
setSorting( -1 ); // NOTE if commented out, items aren't moveable anymore
|
|
|
|
setMinimumHeight( 200 );
|
|
|
|
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 );
|
|
|
|
edit = new TDEAction( i18n("Edit options ..."), "view_text", 0, TQT_TQOBJECT(this), TQT_SLOT(showOptionsEditorDialog()), actionCollection, "edit_options" );
|
|
start = new TDEAction( i18n("Start conversion"), "system-run", 0, TQT_TQOBJECT(this), TQT_SLOT(convertSelectedItems()), actionCollection, "start_conversion" );
|
|
stop = new TDEAction( i18n("Stop conversion"), "process-stop", 0, TQT_TQOBJECT(this), TQT_SLOT(stopSelectedItems()), actionCollection, "stop_conversion" );
|
|
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" ); // TODO paste
|
|
|
|
connect( TQT_TQOBJECT(this), TQT_SIGNAL(selectionChanged()),
|
|
TQT_TQOBJECT(this), TQT_SLOT(itemsSelected())
|
|
);
|
|
|
|
// connect( TQT_TQOBJECT(this), TQT_SIGNAL(clicked(TQListViewItem*,const TQPoint&,int)),
|
|
// TQT_TQOBJECT(this), TQT_SLOT(clickedSomewhere(TQListViewItem*,const TQPoint&,int))
|
|
// );
|
|
|
|
bubble = new TQSimpleRichText( i18n( "<div align=center>"
|
|
"<h3>File List</h3>"
|
|
"Select your desired output options in the form above and add some files.<br/>"
|
|
"You can add files by clicking on \"Add files ...\" or dropping them here."
|
|
// "<br/><a href=\"documenation:about_compression\">Learn more about audio compression ...</a>"
|
|
"</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*) )
|
|
);
|
|
|
|
// if( TQFile::exists(locateLocal("data","soundkonverter/filelist.autosave.xml")) ) load( true );
|
|
|
|
// debug(); // NOTE DEBUG
|
|
}
|
|
|
|
FileList::~FileList()
|
|
{
|
|
delete optionsEditor;
|
|
}
|
|
|
|
int FileList::columnByName( const TQString& name )
|
|
{
|
|
for( int i = 0; i < columns(); ++i ) {
|
|
if( columnText( i ) == name ) return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
void FileList::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 FileList::viewportResizeEvent( TQResizeEvent* )
|
|
{
|
|
// needed for correct redraw of bubble help
|
|
triggerUpdate();
|
|
}
|
|
|
|
void FileList::columnResizeEvent( int, int, int )
|
|
{
|
|
// needed for correct redraw of bubble help
|
|
triggerUpdate();
|
|
}
|
|
|
|
// void FileList::clickedSomewhere( TQListViewItem*, const TQPoint& pos, int )
|
|
// {
|
|
// /* if( childCount() == 0 ) {
|
|
// kdDebug() << "clicked: `" << bubble->anchorAt(mapFromGlobal(pos)-TQPoint(24,0)) << " (" << pos.x() << " | " << pos.y() << ")'" << endl;
|
|
// }*/
|
|
// }
|
|
|
|
bool FileList::acceptDrag( TQDropEvent* e ) const
|
|
{
|
|
return ( e->source() == viewport() || KURLDrag::canDecode(e) ); // TODO verify the files
|
|
}
|
|
|
|
void FileList::slotDropped( TQDropEvent* e, TQListViewItem*, TQListViewItem* itemAfter )
|
|
{
|
|
TQString file;
|
|
KURL::List list;
|
|
TQStringList files;
|
|
if( KURLDrag::decode( e, list ) ) // TODO local?
|
|
{
|
|
save( true );
|
|
for( KURL::List::Iterator it = list.begin(); it != list.end(); ++it )
|
|
{
|
|
// TODO verify the files (necessary when multiple files are being dropped)
|
|
// TODO implement cdda:/
|
|
file = TQDir::convertSeparators( (*it).pathOrURL() ); // TODO implement that in the url/file dialog, too?
|
|
TQFileInfo fileInfo( file );
|
|
if( fileInfo.isDir() )
|
|
{
|
|
addDir( file );
|
|
}
|
|
else
|
|
{
|
|
files.append( (*it).url() );
|
|
}
|
|
}
|
|
addFiles( files, (FileListItem*)itemAfter, true );
|
|
save( true );
|
|
}
|
|
}
|
|
|
|
void FileList::showContextMenu( TQListViewItem* item, const TQPoint& point, int )
|
|
{
|
|
// if item is null, we can abort here
|
|
if( !item ) return;
|
|
|
|
// remove all items from the context menu
|
|
contextMenu->clear();
|
|
|
|
// add a tilte to our context manu
|
|
//contextMenu->insertTitle( static_cast<FileListItem*>(item)->fileName ); // TODO sqeeze or something else
|
|
|
|
// TODO implement pasting, etc.
|
|
|
|
// is this file (of our item) beeing converted at the moment?
|
|
if( !static_cast<FileListItem*>(item)->converting ) {
|
|
edit->plug( contextMenu );
|
|
contextMenu->insertSeparator();
|
|
remove->plug( contextMenu );
|
|
//paste->plug( contextMenu );
|
|
contextMenu->insertSeparator();
|
|
start->plug( contextMenu );
|
|
}
|
|
else {
|
|
stop->plug( contextMenu );
|
|
//contextMenu->insertSeparator();
|
|
//remove->plug( contextMenu );
|
|
//paste->plug( contextMenu );
|
|
}
|
|
|
|
// show the popup menu
|
|
contextMenu->popup( point );
|
|
}
|
|
|
|
void FileList::removeSelectedItems()
|
|
{
|
|
FileListItem *item = firstChild(), *nextitem = 0;
|
|
|
|
while( item != 0 ) {
|
|
if( item->isSelected() && !item->converting ) {
|
|
nextitem = item->nextSibling();
|
|
emit decreaseTime( item->time );
|
|
delete item;
|
|
item = nextitem;
|
|
}
|
|
else {
|
|
item = item->nextSibling();
|
|
}
|
|
}
|
|
emit fileCountChanged( childCount() );
|
|
itemsSelected();
|
|
}
|
|
|
|
void FileList::convertSelectedItems()
|
|
{
|
|
FileListItem* item = firstChild();
|
|
|
|
while( item != 0 ) {
|
|
if( item->isSelected() && !item->converting ) {
|
|
emit convertItem( item );
|
|
}
|
|
item = item->nextSibling();
|
|
}
|
|
itemsSelected();
|
|
emit startedConversion();
|
|
}
|
|
|
|
void FileList::stopSelectedItems()
|
|
{
|
|
FileListItem* item = firstChild();
|
|
|
|
while( item != 0 ) {
|
|
if( item->isSelected() && item->converting ) {
|
|
emit stopItem( item );
|
|
}
|
|
item = item->nextSibling();
|
|
}
|
|
}
|
|
|
|
int FileList::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( fileInfo.filePath(), 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( fileInfo.filePath(), 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) ) {
|
|
addFiles( KURL::encode_string(directory + "/" + *it) );
|
|
count++;
|
|
pScanStatus->setProgress( count );
|
|
break;
|
|
}
|
|
}
|
|
if( filter.first() == "" ) {
|
|
addFiles( KURL::encode_string(directory + "/" + *it) );
|
|
count++;
|
|
pScanStatus->setProgress( count );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
// NOTE progressbar when adding files?
|
|
void FileList::addFiles( TQStringList fileList, FileListItem* after, bool enabled )
|
|
{
|
|
// TODO test if everything works with remote files (http://) and local files (media://)
|
|
FileListItem* lastListItem;
|
|
if( !after && !enabled ) lastListItem = lastItem();
|
|
else lastListItem = after;
|
|
TQString filePathName;
|
|
TQString device;
|
|
|
|
for( TQStringList::Iterator it = fileList.begin(); it != fileList.end(); ++it ) {
|
|
FileListItem* newItem = new FileListItem( this, lastListItem );
|
|
lastListItem = newItem;
|
|
newItem->options = options->getCurrentOptions(); // FIXME speed up
|
|
newItem->notify = notify;
|
|
newItem->local = false;
|
|
newItem->track = -1;
|
|
newItem->url = *it;
|
|
|
|
if( (*it).left( 1 ) == "/" ) {
|
|
filePathName = *it;
|
|
newItem->local = true;
|
|
}
|
|
else if( (*it).left( 7 ) == "file://" ) {
|
|
filePathName = *it;
|
|
filePathName.remove( 0, 7 );
|
|
newItem->local = true;
|
|
}
|
|
else if( (*it).left( 13 ) == "system:/home/" ) {
|
|
filePathName = *it;
|
|
filePathName.remove( 0, 13 );
|
|
filePathName = TQDir::homeDirPath() + "/" + filePathName;
|
|
newItem->local = true;
|
|
}
|
|
else if( (*it).left( 14 ) == "system:/users/" || (*it).left( 6 ) == "home:/" ) {
|
|
int length = ( (*it).left(6) == "home:/" ) ? 6 : 14;
|
|
TQString username = *it;
|
|
username.remove( 0, length );
|
|
username = username.left( username.find("/") );
|
|
filePathName = *it;
|
|
filePathName.remove( 0, length + username.length() );
|
|
KUser user( username );
|
|
filePathName = user.homeDir() + filePathName;
|
|
newItem->local = true;
|
|
}
|
|
else if( (*it).left( 14 ) == "system:/media/" || (*it).left( 7 ) == "media:/" ) {
|
|
int length = ( (*it).left(7) == "media:/" ) ? 7 : 14;
|
|
device = *it;
|
|
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;
|
|
logger->log( 1000, mp->mountedFrom() + " : " + mp->mountPoint() );
|
|
if( mp->mountedFrom() == device )
|
|
{
|
|
filePathName = ( mp->mountPoint() == "/" ) ? mp->mountPoint() : mp->mountPoint() + "/";
|
|
filePathName += (*it).right( (*it).length() - device.length() - length + 4 );
|
|
}
|
|
}
|
|
|
|
newItem->local = true;
|
|
}
|
|
// else if( (*it).left( 14 ) == "system:/trash/" || (*it).left( 7 ) == "trash:/" ) {
|
|
// }
|
|
|
|
if( newItem->local == true ) {
|
|
// logger->log( 1000, i18n("Adding file") + ": " + filePathName );
|
|
newItem->mimeType = KMimeType::findByFileContent( filePathName )->name();
|
|
newItem->fileFormat = KMimeType::findByFileContent( filePathName )->patterns().first().lower();
|
|
newItem->fileFormat.remove( 0, 2 );
|
|
// logger->log( 1000, " " + i18n("Mime type") + ": " + newItem->mimeType + " (" + i18n("Format") + ": " + newItem->fileFormat + ")" );
|
|
// newItem->mimeType="";
|
|
if( newItem->mimeType.isEmpty() || newItem->mimeType == "application/octet-stream" || newItem->mimeType == "text/plain" ) {
|
|
newItem->mimeType = KMimeType::findByURL( filePathName.lower() )->name();
|
|
newItem->fileFormat = KMimeType::findByURL( filePathName.lower() )->patterns().first().lower();
|
|
newItem->fileFormat.remove( 0, 2 );
|
|
// logger->log( 1000, " " + i18n("Mime type") + ": " + newItem->mimeType + " (" + i18n("Format") + ": " + newItem->fileFormat + ")" );
|
|
// newItem->mimeType="";
|
|
// HACK last choise is to use the extension without KDE's help
|
|
if( newItem->mimeType.isEmpty() || newItem->mimeType == "application/octet-stream" || newItem->mimeType == "text/plain" ) {
|
|
newItem->fileFormat = filePathName.right( filePathName.length() - filePathName.findRev(".") - 1 );
|
|
FormatItem *formatItem = config->getFormatItem( newItem->fileFormat );
|
|
if( formatItem ) newItem->mimeType = formatItem->mime_types.first();
|
|
// logger->log( 1000, " " + i18n("Mime type") + ": " + newItem->mimeType + " (" + i18n("Format") + ": " + newItem->fileFormat + ")" );
|
|
}
|
|
}
|
|
// logger->log( 1000, " " + i18n("Mime type") + ": " + newItem->mimeType + " (" + i18n("Format") + ": " + newItem->fileFormat + ")" );
|
|
// check whether the mime type has a decoder registered
|
|
if( !config->acceptFile( newItem->mimeType ) || ( newItem->fileFormat == "wav" && newItem->options.encodingOptions.sFormat == "wav" ) ) {
|
|
delete newItem;
|
|
continue;
|
|
}
|
|
newItem->options.filePathName = filePathName;
|
|
TQFileInfo fileInfo( filePathName );
|
|
newItem->fileName = fileInfo.fileName();
|
|
newItem->tags = tagEngine->readTags( KURL::decode_string(filePathName) );
|
|
if( newItem->tags == 0 ) {
|
|
// logger->log( 1000, " " + i18n("Reading tags failed") );
|
|
// FIXME check for wav files
|
|
FormatItem* formatItem = config->getFormatItem( newItem->mimeType );
|
|
if( formatItem && formatItem->size > 0 ) {
|
|
newItem->time = fileInfo.size() / formatItem->size;
|
|
}
|
|
else {
|
|
newItem->time = 210;
|
|
}
|
|
}
|
|
else {
|
|
// logger->log( 1000, " " + i18n("Tags successfully read") );
|
|
newItem->time = newItem->tags->length;
|
|
}
|
|
}
|
|
else {
|
|
// logger->log( 1000, " File is remote (not yet implemented) (" + *it + ")" );
|
|
filePathName = *it;
|
|
newItem->fileName = filePathName.right( filePathName.length() - filePathName.findRev("/") - 1 );
|
|
newItem->fileFormat = newItem->fileName.right( newItem->fileName.length() - newItem->fileName.findRev(".") - 1 ).lower();
|
|
// NOTE http will not work with KMimeType - this just works
|
|
if( filePathName.startsWith("http://") ) {
|
|
newItem->mimeType = KMimeType::findByURL( "file:///" + newItem->fileName.lower() )->name();
|
|
}
|
|
else {
|
|
newItem->mimeType = KMimeType::findByURL( filePathName.lower() )->name();
|
|
}
|
|
// check whether the mime type has a decoder registered
|
|
if( newItem->mimeType == "" ) {
|
|
newItem->mimeType = newItem->fileFormat;
|
|
}
|
|
if( !config->acceptFile( newItem->mimeType ) || ( newItem->fileFormat == "wav" && newItem->options.encodingOptions.sFormat == "wav" ) ) {
|
|
delete newItem;
|
|
continue;
|
|
}
|
|
newItem->options.filePathName = filePathName;
|
|
newItem->tags = 0;
|
|
newItem->time = 210; // NOTE we can't neither get the length nor guess it without accessing the file
|
|
// TODO get the file size and guess the length
|
|
}
|
|
|
|
updateItem( newItem );
|
|
emit increaseTime( newItem->time );
|
|
}
|
|
emit fileCountChanged( childCount() );
|
|
}
|
|
|
|
void FileList::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 FileList::addTracks( const TQString& device, TQValueList<int> trackList )
|
|
{
|
|
for( TQValueList<int>::Iterator it = trackList.begin(); it != trackList.end(); ++it ) {
|
|
// logger->log( 1000, i18n("Adding track") + TQString().sprintf(" %02i",*it) );
|
|
FileListItem* newItem = new FileListItem( this, lastItem() );
|
|
newItem->options = options->getCurrentOptions(); // FIXME speed up
|
|
// if( newItem->options.outputOptions.mode != OutputDirectory::Specify ) newItem->options.outputOptions.mode = OutputDirectory::MetaData;
|
|
newItem->notify = notify;
|
|
newItem->track = (*it);
|
|
newItem->fileName = i18n("Audio CD (%1)").arg(device) + ": " + i18n("Track") + TQString().sprintf(" %02i",newItem->track);
|
|
newItem->mimeType = "application/x-cda";
|
|
newItem->fileFormat = "cda";
|
|
newItem->local = true;
|
|
newItem->device = device;
|
|
newItem->tags = cdManager->getTags( device, newItem->track );
|
|
if( newItem->tags == 0 ) { // NOTE shouldn't happen
|
|
// logger->log( 1000, " " + i18n("Reading tags failed") );
|
|
newItem->time = 210;
|
|
newItem->options.filePathName = TQDir::homeDirPath() + "/" + i18n("Track") + TQString().sprintf(" %02i",newItem->track) + "." + newItem->fileFormat;
|
|
}
|
|
else {
|
|
// logger->log( 1000, " " + i18n("Tags successfully read") );
|
|
newItem->time = newItem->tags->length;
|
|
newItem->options.filePathName = TQDir::homeDirPath() + "/" + TQString().sprintf("%02i - ",newItem->track) + newItem->tags->title + "." + newItem->fileFormat;
|
|
newItem->fileName = i18n("Audio CD (%1)").arg(device) + ": " + TQString().sprintf("%02i - ",newItem->track) + newItem->tags->title;
|
|
}
|
|
updateItem( newItem );
|
|
emit increaseTime( newItem->time );
|
|
}
|
|
emit fileCountChanged( childCount() );
|
|
}
|
|
|
|
void FileList::addDisc( const TQString& device )
|
|
{
|
|
// logger->log( 1000, i18n("Adding full audio CD (%1)").arg(device) );
|
|
FileListItem* newItem = new FileListItem( this, lastItem() );
|
|
newItem->options = options->getCurrentOptions();
|
|
// if( newItem->options.outputOptions.mode != OutputDirectory::Specify ) newItem->options.outputOptions.mode = OutputDirectory::MetaData;
|
|
newItem->notify = notify;
|
|
newItem->track = 0;
|
|
newItem->fileName = i18n("Full audio CD (%1)").arg(device);
|
|
newItem->mimeType = "application/x-cda";
|
|
newItem->fileFormat = "cda";
|
|
newItem->local = true;
|
|
newItem->device = device;
|
|
newItem->tags = cdManager->getTags( device, 0 );
|
|
if( newItem->tags == 0 ) { // NOTE shouldn't happen
|
|
// logger->log( 1000, " " + i18n("Reading tags failed") );
|
|
newItem->time = 3600;
|
|
newItem->options.filePathName = TQDir::homeDirPath() + "/" + i18n("Audio CD") + "." + newItem->fileFormat;
|
|
}
|
|
else {
|
|
// logger->log( 1000, " " + i18n("Tags successfully read") );
|
|
newItem->time = newItem->tags->length;
|
|
newItem->options.filePathName = TQDir::homeDirPath() + newItem->tags->title + "." + newItem->fileFormat;
|
|
newItem->fileName = i18n("Full audio CD (%1)").arg(device) + ": " + newItem->tags->title;
|
|
}
|
|
updateItem( newItem );
|
|
emit increaseTime( newItem->time );
|
|
emit fileCountChanged( childCount() );
|
|
}
|
|
|
|
void FileList::itemFinished( FileListItem* item, int state )
|
|
{
|
|
if( state == 0 ) {
|
|
if( item ) delete item;
|
|
itemsSelected();
|
|
}
|
|
else if( state == 1 ) {
|
|
item->setText( columnByName(i18n("State")), i18n("Stopped") );
|
|
}
|
|
else {
|
|
item->setText( columnByName(i18n("State")), i18n("Failed") );
|
|
}
|
|
|
|
save( true );
|
|
|
|
FileListItem* it = firstChild();
|
|
int waitingCount = 0, convertingCount = 0;
|
|
|
|
while( it != 0 ) {
|
|
if( it->text(columnByName(i18n("State"))) != i18n("Failed") && it->text(columnByName(i18n("State"))) != i18n("Stopped") && it->text(columnByName(i18n("State"))) != i18n("Will be skipped") ) {
|
|
if( it->text(columnByName(i18n("State"))) == i18n("Waiting") /*|| it->text(columnByName(i18n("State"))) == i18n("Stopped")*/ ) {
|
|
waitingCount++;
|
|
}
|
|
else {
|
|
convertingCount++;
|
|
}
|
|
}
|
|
it = it->nextSibling();
|
|
}
|
|
|
|
if( waitingCount > 0 && queue ) {
|
|
convertNextItem();
|
|
}
|
|
else if( convertingCount == 0 ) {
|
|
queue = false;
|
|
float time = 0;
|
|
it = firstChild();
|
|
while( it != 0 ) {
|
|
// it->setText( columnByName(i18n("State")), i18n("Waiting") );
|
|
updateItem( it );
|
|
time += it->time;
|
|
it = it->nextSibling();
|
|
}
|
|
emit finished( time );
|
|
emit stoppedConversion();
|
|
emit fileCountChanged( childCount() );
|
|
}
|
|
}
|
|
|
|
void FileList::rippingFinished( const TQString& device )
|
|
{
|
|
if( !queue ) return;
|
|
|
|
int count = 0;
|
|
FileListItem *item = firstChild();
|
|
while( item != 0 ) {
|
|
if( item->converting ) {
|
|
count++;
|
|
}
|
|
item = item->nextSibling();
|
|
}
|
|
|
|
// look for "Waiting" files first ...
|
|
item = firstChild();
|
|
while( item != 0 && count < config->data.general.numFiles ) {
|
|
if( !item->converting && item->text(columnByName(i18n("State"))) == i18n("Waiting") ) {
|
|
if( item->track >= 0 && item->device == device ) {
|
|
convertItem( item );
|
|
itemsSelected();
|
|
return;
|
|
}
|
|
}
|
|
item = item->nextSibling();
|
|
}
|
|
|
|
// ... then convert the stopped, too
|
|
/* item = firstChild();
|
|
while( item != 0 && count < config->data.general.numFiles ) {
|
|
if( !item->converting && item->text(columnByName(i18n("State"))) == i18n("Stopped") ) {
|
|
if( item->track >= 0 && item->device == device ) {
|
|
convertItem( item );
|
|
itemsSelected();
|
|
return;
|
|
}
|
|
}
|
|
item = item->nextSibling();
|
|
}*/
|
|
}
|
|
|
|
void FileList::updateItem( FileListItem* item )
|
|
{
|
|
if( !item ) return;
|
|
|
|
if( !item->converting ) {
|
|
if( config->data.general.conflictHandling == 1 && TQFile::exists(KURL::decode_string(OutputDirectory::calcPath(item,config))) ) { // was: .replace("%2f","%252f")
|
|
item->setText( columnByName(i18n("State")), i18n("Will be skipped") );
|
|
}
|
|
else {
|
|
item->setText( columnByName(i18n("State")), i18n("Waiting") );
|
|
}
|
|
}
|
|
else {
|
|
item->setText( columnByName(i18n("State")), i18n("Converting") );
|
|
}
|
|
|
|
if( item->track >= 0 ) item->setText( columnByName(i18n("Input")), KURL::decode_string(item->fileName).replace("%2f","/").replace("%%","%") );
|
|
else item->setText( columnByName(i18n("Input")), KURL::decode_string(item->options.filePathName).replace("%2f","/").replace("%%","%") );
|
|
|
|
item->setText( columnByName(i18n("Output")), KURL::decode_string(OutputDirectory::uniqueFileName(OutputDirectory::calcPath(item,config))).replace("%2f","/").replace("%%","%") );
|
|
|
|
item->setText( columnByName(i18n("Quality")), config->getProfileName(item->options) );
|
|
}
|
|
|
|
void FileList::showOptionsEditorDialog()
|
|
{
|
|
// FIXME options are set to defaults
|
|
|
|
if( optionsEditor == 0 ) {
|
|
optionsEditor = new OptionsEditor( tagEngine, config, this, 0, "optionsEditor" );
|
|
if( optionsEditor == 0 ) {
|
|
// TODO error message
|
|
return;
|
|
}
|
|
// }
|
|
connect( TQT_TQOBJECT(this), TQT_SIGNAL(editItems(TQValueList<FileListItem*>)),
|
|
optionsEditor, TQT_SLOT(itemsSelected(TQValueList<FileListItem*>))
|
|
);
|
|
connect( TQT_TQOBJECT(this), TQT_SIGNAL(setPreviousItemEnabled(bool)),
|
|
optionsEditor, TQT_SLOT(setPreviousEnabled(bool))
|
|
);
|
|
connect( TQT_TQOBJECT(this), TQT_SIGNAL(setNextItemEnabled(bool)),
|
|
optionsEditor, TQT_SLOT(setNextEnabled(bool))
|
|
);
|
|
connect( optionsEditor, TQT_SIGNAL(user2Clicked()),
|
|
TQT_TQOBJECT(this), TQT_SLOT(selectPreviousItem())
|
|
);
|
|
connect( optionsEditor, TQT_SIGNAL(user1Clicked()),
|
|
TQT_TQOBJECT(this), TQT_SLOT(selectNextItem())
|
|
);
|
|
/*connect( TQT_TQOBJECT(this), TQT_SIGNAL(moveEditor(int,int)),
|
|
optionsEditor, TQT_SLOT(moveWindow(int,int))
|
|
);*/
|
|
}
|
|
itemsSelected();
|
|
optionsEditor->show();
|
|
}
|
|
|
|
// FIXME still makes some troubles (wreaks some items) and crashes
|
|
void FileList::selectPreviousItem()
|
|
{
|
|
if( selectedFiles.first() == 0 ) return;
|
|
FileListItem* item = selectedFiles.first()->itemAbove();
|
|
if( item != 0 ) {
|
|
item->setSelected( true );
|
|
repaintItem( item );
|
|
ensureItemVisible( item );
|
|
}
|
|
|
|
for( TQValueList<FileListItem*>::Iterator it = selectedFiles.begin(); it != selectedFiles.end(); ++it ) {
|
|
(*it)->setSelected( false );
|
|
repaintItem( *it );
|
|
}
|
|
|
|
itemsSelected();
|
|
}
|
|
|
|
void FileList::selectNextItem()
|
|
{
|
|
if( selectedFiles.last() == 0 ) return;
|
|
FileListItem* item = selectedFiles.last()->itemBelow();
|
|
if( item != 0 ) {
|
|
item->setSelected( true );
|
|
repaintItem( item );
|
|
ensureItemVisible( item );
|
|
}
|
|
|
|
for( TQValueList<FileListItem*>::Iterator it = selectedFiles.begin(); it != selectedFiles.end(); ++it ) {
|
|
(*it)->setSelected( false );
|
|
repaintItem( *it );
|
|
}
|
|
|
|
itemsSelected();
|
|
}
|
|
|
|
void FileList::itemsSelected()
|
|
{
|
|
selectedFiles.clear();
|
|
for( FileListItem *item = firstChild(); item != NULL; item = item->nextSibling() ) {
|
|
if( item->isSelected() ) {
|
|
selectedFiles.append( item );
|
|
}
|
|
}
|
|
|
|
if( selectedFiles.count() > 0 ) {
|
|
if( selectedFiles.first()->itemAbove() != 0 ) emit setPreviousItemEnabled( true );
|
|
else emit setPreviousItemEnabled( false );
|
|
if( selectedFiles.last()->itemBelow() != 0 ) emit setNextItemEnabled( true );
|
|
else emit setNextItemEnabled( false );
|
|
}
|
|
else {
|
|
emit setPreviousItemEnabled( false );
|
|
emit setNextItemEnabled( false );
|
|
}
|
|
|
|
emit editItems( selectedFiles );
|
|
}
|
|
|
|
/*void FileList::moveOptionsEditor( int x, int y )
|
|
{
|
|
emit moveEditor( x, y );
|
|
}*/
|
|
|
|
void FileList::startConversion()
|
|
{
|
|
// iterate through all items and set the state to "Waiting"
|
|
FileListItem* it = firstChild();
|
|
while( it != 0 ) {
|
|
// it->setText( columnByName(i18n("State")), i18n("Waiting") );
|
|
if( !it->converting && it->text(columnByName(i18n("State"))) != i18n("Will be skipped") ) {
|
|
it->setText( columnByName(i18n("State")), i18n("Waiting") );
|
|
}
|
|
it = it->nextSibling();
|
|
}
|
|
queue = true;
|
|
emit startedConversion();
|
|
convertNextItem();
|
|
}
|
|
|
|
void FileList::stopConversion()
|
|
{
|
|
queue = false;
|
|
emit stopClicked();
|
|
}
|
|
|
|
void FileList::continueConversion()
|
|
{
|
|
queue = true;
|
|
emit continueClicked();
|
|
}
|
|
|
|
void FileList::killConversion()
|
|
{
|
|
queue = false;
|
|
|
|
FileListItem *item = firstChild();
|
|
|
|
while( item != 0 ) {
|
|
if( item->converting ) {
|
|
emit stopItem( item );
|
|
}
|
|
item = item->nextSibling();
|
|
}
|
|
}
|
|
|
|
void FileList::convertNextItem()
|
|
{
|
|
if( !queue ) return;
|
|
|
|
TQStringList devices;
|
|
|
|
// look for tracks that are being ripped
|
|
int count = 0;
|
|
FileListItem *item = firstChild();
|
|
while( item != 0 ) {
|
|
if( item->converting ) {
|
|
count++;
|
|
if( item->ripping ) {
|
|
devices += item->device;
|
|
}
|
|
}
|
|
item = item->nextSibling();
|
|
}
|
|
|
|
// look for "Waiting" files first ...
|
|
item = firstChild();
|
|
while( item != 0 && count < config->data.general.numFiles ) {
|
|
if( !item->converting && item->text(columnByName(i18n("State"))) == i18n("Waiting") ) {
|
|
if( item->track >= 0 && devices.findIndex(item->device) == -1 ) {
|
|
convertItem( item );
|
|
count++;
|
|
devices += item->device;
|
|
}
|
|
else if( item->track < 0 ) {
|
|
convertItem( item );
|
|
count++;
|
|
}
|
|
}
|
|
item = item->nextSibling();
|
|
}
|
|
|
|
// ... then convert the stopped, too
|
|
// item = firstChild();
|
|
// while( item != 0 && count < config->data.general.numFiles ) {
|
|
// if( !item->converting && item->text(columnByName(i18n("State"))) == i18n("Stopped") ) {
|
|
// if( item->track >= 0 && devices.findIndex(item->device) == -1 ) {
|
|
// convertItem( item );
|
|
// count++;
|
|
// devices += item->device;
|
|
// }
|
|
// else if( item->track < 0 ) {
|
|
// convertItem( item );
|
|
// count++;
|
|
// }
|
|
// }
|
|
// item = item->nextSibling();
|
|
// }
|
|
|
|
itemsSelected();
|
|
|
|
FileListItem* it = firstChild();
|
|
int waitingCount = 0, convertingCount = 0;
|
|
|
|
while( it != 0 ) {
|
|
if( it->text(columnByName(i18n("State"))) != i18n("Failed") && it->text(columnByName(i18n("State"))) != i18n("Stopped") && it->text(columnByName(i18n("State"))) != i18n("Will be skipped") ) {
|
|
if( it->text(columnByName(i18n("State"))) == i18n("Waiting") /*|| it->text(columnByName(i18n("State"))) == i18n("Stopped")*/ ) {
|
|
waitingCount++;
|
|
}
|
|
else {
|
|
convertingCount++;
|
|
}
|
|
}
|
|
it = it->nextSibling();
|
|
}
|
|
|
|
if( waitingCount == 0 && convertingCount == 0 ) itemFinished( 0, 0 );
|
|
}
|
|
|
|
void FileList::load( bool autosave )
|
|
{
|
|
// NOTE clear the file list befor adding the saved items?
|
|
|
|
int version;
|
|
TQString name;
|
|
FileListItem* lastListItem = lastItem();
|
|
TQString filename;
|
|
if( autosave ) filename = locateLocal("data","soundkonverter/filelist.autosave.xml");
|
|
else filename = locateLocal("data","soundkonverter/filelist.xml");
|
|
|
|
TQDomDocument domTree;
|
|
TQFile opmlFile( filename );
|
|
if( !opmlFile.open( IO_ReadOnly ) ) return;
|
|
if( !domTree.setContent( &opmlFile ) ) return;
|
|
opmlFile.close();
|
|
|
|
TQDomElement root = domTree.documentElement();
|
|
if( root.attribute("type") != "filelist" ) return;
|
|
TQDomNode node, sub1Node, sub2Node;
|
|
node = root.firstChild();
|
|
|
|
while( !node.isNull() ) {
|
|
if( node.isElement() && node.nodeName() == "info" ) {
|
|
|
|
version = node.toElement().attribute("version").toInt();
|
|
|
|
}
|
|
else if( node.isElement() && node.nodeName() == "file" ) {
|
|
|
|
FileListItem* item = new FileListItem( this, lastListItem );
|
|
lastListItem = item;
|
|
|
|
item->fileName = node.toElement().attribute("fileName");
|
|
item->mimeType = node.toElement().attribute("mimeType");
|
|
item->fileFormat = node.toElement().attribute("fileFormat");
|
|
item->local = node.toElement().attribute("local").toInt();
|
|
item->track = node.toElement().attribute("track").toInt();
|
|
item->time = node.toElement().attribute("time").toInt();
|
|
|
|
item->options.filePathName = node.toElement().attribute("filePathName");
|
|
item->options.outputFilePathName = node.toElement().attribute("outputFilePathName");
|
|
|
|
sub1Node = node.toElement().firstChild();
|
|
while( !sub1Node.isNull() ) {
|
|
if( sub1Node.isElement() && sub1Node.nodeName() == "encodingOptions" ) {
|
|
|
|
item->options.encodingOptions.sFormat = sub1Node.toElement().attribute("sFormat");
|
|
item->options.encodingOptions.sQualityMode = sub1Node.toElement().attribute("sQualityMode");
|
|
item->options.encodingOptions.iQuality = sub1Node.toElement().attribute("iQuality").toInt();
|
|
item->options.encodingOptions.sBitrateMode = sub1Node.toElement().attribute("sBitrateMode");
|
|
item->options.encodingOptions.bBitrateRange = sub1Node.toElement().attribute("bBitrateRange").toInt();
|
|
item->options.encodingOptions.iMinBitrate = sub1Node.toElement().attribute("iMinBitrate").toInt();
|
|
item->options.encodingOptions.iMaxBitrate = sub1Node.toElement().attribute("iMaxBitrate").toInt();
|
|
item->options.encodingOptions.sInOutFiles = sub1Node.toElement().attribute("sInOutFiles");
|
|
|
|
sub2Node = sub1Node.toElement().firstChild();
|
|
while( !sub2Node.isNull() ) {
|
|
if( sub2Node.isElement() && sub2Node.nodeName() == "samplingRate" ) {
|
|
|
|
item->options.encodingOptions.samplingRate.bEnabled = sub2Node.toElement().attribute("bEnabled").toInt();
|
|
item->options.encodingOptions.samplingRate.iSamplingRate = sub2Node.toElement().attribute("iSamplingRate").toInt();
|
|
|
|
}
|
|
else if( sub2Node.isElement() && sub2Node.nodeName() == "channels" ) {
|
|
|
|
item->options.encodingOptions.channels.bEnabled = sub2Node.toElement().attribute("bEnabled").toInt();
|
|
item->options.encodingOptions.channels.sChannels = sub2Node.toElement().attribute("sChannels");
|
|
|
|
}
|
|
else if( sub2Node.isElement() && sub2Node.nodeName() == "replaygain" ) {
|
|
|
|
item->options.encodingOptions.replaygain.bEnabled = sub2Node.toElement().attribute("bEnabled").toInt();
|
|
|
|
}
|
|
sub2Node = sub2Node.nextSibling();
|
|
}
|
|
|
|
}
|
|
else if( sub1Node.isElement() && sub1Node.nodeName() == "outputOptions" ) {
|
|
|
|
item->options.outputOptions.mode = (OutputDirectory::Mode)sub1Node.toElement().attribute("mode").toInt();
|
|
item->options.outputOptions.directory = sub1Node.toElement().attribute("directory");
|
|
|
|
}
|
|
else if( sub1Node.isElement() && sub1Node.nodeName() == "tags" ) {
|
|
|
|
item->tags = new TagData();
|
|
|
|
item->tags->artist = sub1Node.toElement().attribute("artist");
|
|
item->tags->composer = sub1Node.toElement().attribute("composer");
|
|
item->tags->album = sub1Node.toElement().attribute("album");
|
|
item->tags->title = sub1Node.toElement().attribute("title");
|
|
item->tags->genre = sub1Node.toElement().attribute("genre");
|
|
item->tags->comment = sub1Node.toElement().attribute("comment");
|
|
item->tags->track = sub1Node.toElement().attribute("track").toInt();
|
|
item->tags->disc = sub1Node.toElement().attribute("disc").toInt();
|
|
item->tags->year = sub1Node.toElement().attribute("year").toInt();
|
|
item->tags->track_gain = sub1Node.toElement().attribute("track_gain").toFloat();
|
|
item->tags->album_gain = sub1Node.toElement().attribute("album_gain").toFloat();
|
|
item->tags->length = sub1Node.toElement().attribute("length").toInt();
|
|
item->tags->fileSize = sub1Node.toElement().attribute("fileSize").toInt();
|
|
item->tags->bitrate = sub1Node.toElement().attribute("bitrate").toInt();
|
|
item->tags->samplingRate = sub1Node.toElement().attribute("samplingRate").toInt();
|
|
|
|
}
|
|
sub1Node = sub1Node.nextSibling();
|
|
}
|
|
updateItem( item );
|
|
emit increaseTime( item->time );
|
|
}
|
|
node = node.nextSibling();
|
|
}
|
|
emit fileCountChanged( childCount() );
|
|
}
|
|
|
|
void FileList::save( bool autosave )
|
|
{
|
|
// NOTE filenames should be encoded before saving - but it works fine without it (hm...)
|
|
|
|
TQTime time;
|
|
time.start();
|
|
|
|
TQDomDocument domTree;
|
|
TQDomElement root = domTree.createElement( "soundkonverter" );
|
|
root.setAttribute( "type", "filelist" );
|
|
domTree.appendChild( root );
|
|
|
|
TQDomElement info = domTree.createElement( "info" );
|
|
info.setAttribute( "version", "300" );
|
|
root.appendChild( info );
|
|
|
|
for( FileListItem* item = firstChild(); item != 0; item = item->nextSibling() ) {
|
|
TQDomElement file = domTree.createElement( "file" );
|
|
file.setAttribute( "fileName", item->fileName );
|
|
file.setAttribute( "mimeType", item->mimeType );
|
|
file.setAttribute( "fileFormat", item->fileFormat );
|
|
file.setAttribute( "local", item->local );
|
|
file.setAttribute( "track", item->track );
|
|
file.setAttribute( "device", item->device );
|
|
file.setAttribute( "time", item->time );
|
|
|
|
file.setAttribute( "filePathName", item->options.filePathName );
|
|
file.setAttribute( "outputFilePathName", item->options.outputFilePathName );
|
|
|
|
TQDomElement encodingOptions = domTree.createElement( "encodingOptions" );
|
|
|
|
encodingOptions.setAttribute( "sFormat", item->options.encodingOptions.sFormat );
|
|
encodingOptions.setAttribute( "sQualityMode", item->options.encodingOptions.sQualityMode );
|
|
encodingOptions.setAttribute( "iQuality", item->options.encodingOptions.iQuality );
|
|
encodingOptions.setAttribute( "sBitrateMode", item->options.encodingOptions.sBitrateMode );
|
|
encodingOptions.setAttribute( "bBitrateRange", item->options.encodingOptions.bBitrateRange );
|
|
encodingOptions.setAttribute( "iMinBitrate", item->options.encodingOptions.iMinBitrate );
|
|
encodingOptions.setAttribute( "iMaxBitrate", item->options.encodingOptions.iMaxBitrate );
|
|
|
|
TQDomElement samplingRate = domTree.createElement( "samplingRate" );
|
|
|
|
samplingRate.setAttribute( "bEnabled", item->options.encodingOptions.samplingRate.bEnabled );
|
|
samplingRate.setAttribute( "iSamplingRate", item->options.encodingOptions.samplingRate.iSamplingRate );
|
|
|
|
encodingOptions.appendChild( samplingRate );
|
|
|
|
TQDomElement channels = domTree.createElement( "channels" );
|
|
|
|
channels.setAttribute( "bEnabled", item->options.encodingOptions.channels.bEnabled );
|
|
channels.setAttribute( "sChannels", item->options.encodingOptions.channels.sChannels );
|
|
|
|
encodingOptions.appendChild( channels );
|
|
|
|
TQDomElement replaygain = domTree.createElement( "replaygain" );
|
|
|
|
replaygain.setAttribute( "bEnabled", item->options.encodingOptions.replaygain.bEnabled );
|
|
|
|
encodingOptions.appendChild( replaygain );
|
|
|
|
encodingOptions.setAttribute( "sInOutFiles", item->options.encodingOptions.sInOutFiles );
|
|
|
|
file.appendChild( encodingOptions );
|
|
|
|
TQDomElement outputOptions = domTree.createElement( "outputOptions" );
|
|
|
|
outputOptions.setAttribute( "mode", int(item->options.outputOptions.mode) );
|
|
outputOptions.setAttribute( "directory", item->options.outputOptions.directory );
|
|
|
|
file.appendChild( outputOptions );
|
|
|
|
if( item->tags )
|
|
{
|
|
TQDomElement tags = domTree.createElement( "tags" );
|
|
|
|
tags.setAttribute( "artist", item->tags->artist );
|
|
tags.setAttribute( "composer", item->tags->composer );
|
|
tags.setAttribute( "album", item->tags->album );
|
|
tags.setAttribute( "title", item->tags->title );
|
|
tags.setAttribute( "genre", item->tags->genre );
|
|
tags.setAttribute( "comment", item->tags->comment );
|
|
tags.setAttribute( "track", item->tags->track );
|
|
tags.setAttribute( "disc", item->tags->disc );
|
|
tags.setAttribute( "year", item->tags->year );
|
|
tags.setAttribute( "track_gain", item->tags->track_gain );
|
|
tags.setAttribute( "album_gain", item->tags->album_gain );
|
|
tags.setAttribute( "length", item->tags->length );
|
|
tags.setAttribute( "fileSize", item->tags->fileSize );
|
|
tags.setAttribute( "bitrate", item->tags->bitrate );
|
|
tags.setAttribute( "samplingRate", item->tags->samplingRate );
|
|
|
|
file.appendChild( tags );
|
|
}
|
|
|
|
root.appendChild( file );
|
|
}
|
|
|
|
TQString filename;
|
|
if( autosave ) filename = locateLocal("data","soundkonverter/filelist.autosave.xml");
|
|
else filename = locateLocal("data","soundkonverter/filelist.xml");
|
|
|
|
TQFile opmlFile( filename );
|
|
if( !opmlFile.open( IO_WriteOnly ) ) return;
|
|
|
|
TQTextStream ts( &opmlFile );
|
|
ts << domTree.toString();
|
|
|
|
opmlFile.close();
|
|
|
|
logger->log( 1000, "save file list: " + TQString::number(time.elapsed()) );
|
|
}
|
|
|
|
void FileList::debug() // NOTE DEBUG
|
|
{
|
|
logger->log( 1000, "DEBUG begin" );
|
|
|
|
ConversionOptions conversionOptions;
|
|
|
|
TQStringList formats = config->allEncodableFormats();
|
|
|
|
for( TQStringList::Iterator a = formats.begin(); a != formats.end(); ++a )
|
|
{
|
|
logger->log( 1000, "format: " + (*a) );
|
|
FormatItem* formatItem = config->getFormatItem( *a );
|
|
if( formatItem == 0 ) continue;
|
|
|
|
for( TQValueList<ConvertPlugin*>::Iterator b = formatItem->encoders.begin(); b != formatItem->encoders.end(); ++b ) {
|
|
logger->log( 1000, " encoder: " + (*b)->enc.bin );
|
|
formatItem->encoder = (*b);
|
|
if( (*b)->enc.strength.enabled ) {
|
|
formatItem->compressionLevel = (*b)->enc.strength.default_value;
|
|
}
|
|
if( (*b)->enc.replaygain.enabled ) {
|
|
formatItem->internalReplayGain = true;
|
|
}
|
|
|
|
if( (*b)->enc.lossless.enabled ) {
|
|
options->setProfile( "Lossless" );
|
|
options->setFormat( *a );
|
|
options->setOutputDirectory( "/home/daniel/soundKonverter/test_output" );
|
|
conversionOptions = options->getCurrentOptions();
|
|
conversionOptions.encodingOptions.sInOutFiles = debug_params( conversionOptions, formatItem );
|
|
options->setCurrentOptions( conversionOptions );
|
|
addFiles( "/home/daniel/soundKonverter/test.mp3" );
|
|
}
|
|
if( (*b)->enc.lossy.enabled ) {
|
|
options->setProfile( "Medium" );
|
|
if( (*b)->enc.lossy.bitrate.cbr.enabled ) {
|
|
options->setFormat( *a );
|
|
conversionOptions = options->getCurrentOptions();
|
|
conversionOptions.encodingOptions.sQualityMode = i18n("Bitrate");
|
|
conversionOptions.encodingOptions.sBitrateMode = "cbr";
|
|
conversionOptions.encodingOptions.iQuality = 128;
|
|
conversionOptions.encodingOptions.sInOutFiles = debug_params( conversionOptions, formatItem );
|
|
options->setCurrentOptions( conversionOptions );
|
|
options->setOutputDirectory( "/home/daniel/soundKonverter/test_output" );
|
|
addFiles( "/home/daniel/soundKonverter/test.mp3" );
|
|
}
|
|
if( (*b)->enc.lossy.bitrate.abr.enabled ) {
|
|
options->setFormat( *a );
|
|
conversionOptions = options->getCurrentOptions();
|
|
conversionOptions.encodingOptions.sQualityMode = i18n("Bitrate");
|
|
conversionOptions.encodingOptions.sBitrateMode = "abr";
|
|
conversionOptions.encodingOptions.iQuality = 128;
|
|
conversionOptions.encodingOptions.sInOutFiles = debug_params( conversionOptions, formatItem );
|
|
options->setCurrentOptions( conversionOptions );
|
|
options->setOutputDirectory( "/home/daniel/soundKonverter/test_output" );
|
|
addFiles( "/home/daniel/soundKonverter/test.mp3" );
|
|
if( (*b)->enc.lossy.bitrate.abr.bitrate_range.enabled ) {
|
|
options->setFormat( *a );
|
|
conversionOptions = options->getCurrentOptions();
|
|
conversionOptions.encodingOptions.sQualityMode = i18n("Bitrate");
|
|
conversionOptions.encodingOptions.sBitrateMode = "abr";
|
|
conversionOptions.encodingOptions.iQuality = 128;
|
|
conversionOptions.encodingOptions.bBitrateRange = true;
|
|
conversionOptions.encodingOptions.iMinBitrate = 64;
|
|
conversionOptions.encodingOptions.iMaxBitrate = 192;
|
|
conversionOptions.encodingOptions.sInOutFiles = debug_params( conversionOptions, formatItem );
|
|
options->setCurrentOptions( conversionOptions );
|
|
options->setOutputDirectory( "/home/daniel/soundKonverter/test_output" );
|
|
addFiles( "/home/daniel/soundKonverter/test.mp3" );
|
|
}
|
|
}
|
|
if( (*b)->enc.lossy.quality.enabled ) {
|
|
options->setFormat( *a );
|
|
conversionOptions = options->getCurrentOptions();
|
|
conversionOptions.encodingOptions.sQualityMode = i18n("Quality");
|
|
conversionOptions.encodingOptions.iQuality = 40;
|
|
conversionOptions.encodingOptions.sInOutFiles = debug_params( conversionOptions, formatItem );
|
|
options->setCurrentOptions( conversionOptions );
|
|
options->setOutputDirectory( "/home/daniel/soundKonverter/test_output" );
|
|
addFiles( "/home/daniel/soundKonverter/test.mp3" );
|
|
}
|
|
}
|
|
}
|
|
|
|
for( TQValueList<ConvertPlugin*>::Iterator b = formatItem->decoders.begin(); b != formatItem->decoders.end(); ++b ) {
|
|
formatItem->decoder = (*b);
|
|
}
|
|
|
|
for( TQValueList<ReplayGainPlugin*>::Iterator b = formatItem->replaygains.begin(); b != formatItem->replaygains.end(); ++b ) {
|
|
formatItem->replaygain = (*b);
|
|
}
|
|
}
|
|
|
|
logger->log( 1000, "DEBUG end" );
|
|
}
|
|
|
|
TQString FileList::debug_params( ConversionOptions conversionOptions, FormatItem* formatItem ) // NOTE DEBUG
|
|
{
|
|
ConvertPlugin* plugin = formatItem->encoder;
|
|
|
|
TQString sStrength;
|
|
TQString sBitrate;
|
|
TQString sQuality;
|
|
TQString sMinBitrate;
|
|
TQString sMaxBitrate;
|
|
TQString sSamplingRate;
|
|
|
|
int t_int;
|
|
float t_float;
|
|
|
|
TQString param = "";
|
|
if( !plugin->enc.param.isEmpty() ) param.append( " " + plugin->enc.param );
|
|
if( !plugin->enc.overwrite.isEmpty() ) param.append( " " + plugin->enc.overwrite );
|
|
|
|
if( plugin->enc.strength.enabled ) {
|
|
param.append( " " + plugin->enc.strength.param );
|
|
int compressionLevel = formatItem->compressionLevel;
|
|
|
|
if( plugin->enc.strength.profiles.empty() ) {
|
|
if( plugin->enc.strength.step < 1 ) {
|
|
if( plugin->enc.strength.range_max >= plugin->enc.strength.range_min )
|
|
sStrength = TQString::number( compressionLevel );
|
|
else
|
|
sStrength = TQString::number( plugin->enc.strength.range_min - compressionLevel );
|
|
}
|
|
else {
|
|
if( plugin->enc.strength.range_max >= plugin->enc.strength.range_min )
|
|
sStrength = TQString::number( int(compressionLevel) );
|
|
else
|
|
sStrength = TQString::number( int(plugin->enc.strength.range_min - compressionLevel) );
|
|
}
|
|
if( plugin->enc.strength.separator != '.' ) sStrength.replace( TQChar('.'), plugin->enc.strength.separator );
|
|
}
|
|
else {
|
|
TQStringList::Iterator it = plugin->enc.strength.profiles.at( compressionLevel );
|
|
sStrength = *it;
|
|
}
|
|
}
|
|
|
|
if( conversionOptions.encodingOptions.sQualityMode == i18n("Bitrate") ) {
|
|
if( conversionOptions.encodingOptions.sBitrateMode == "cbr" && plugin->enc.lossy.bitrate.cbr.enabled ) {
|
|
param.append( " " + plugin->enc.lossy.bitrate.cbr.param );
|
|
sBitrate = TQString::number( conversionOptions.encodingOptions.iQuality );
|
|
}
|
|
else if( conversionOptions.encodingOptions.sBitrateMode == "abr" && plugin->enc.lossy.bitrate.abr.enabled ) {
|
|
param.append( " " + plugin->enc.lossy.bitrate.abr.param );
|
|
sBitrate = TQString::number( conversionOptions.encodingOptions.iQuality );
|
|
if( conversionOptions.encodingOptions.bBitrateRange && plugin->enc.lossy.bitrate.abr.bitrate_range.enabled ) {
|
|
param.append( " " + plugin->enc.lossy.bitrate.abr.bitrate_range.param_min );
|
|
sMinBitrate = TQString::number( conversionOptions.encodingOptions.iMinBitrate );
|
|
param.append( " " + plugin->enc.lossy.bitrate.abr.bitrate_range.param_max );
|
|
sMaxBitrate = TQString::number( conversionOptions.encodingOptions.iMaxBitrate );
|
|
}
|
|
}
|
|
}
|
|
else if( conversionOptions.encodingOptions.sQualityMode == i18n("Quality") && plugin->enc.lossy.quality.enabled ) {
|
|
param.append( " " + plugin->enc.lossy.quality.param );
|
|
if( plugin->enc.lossy.quality.profiles.empty() ) {
|
|
if( plugin->enc.lossy.quality.step < 1 ) {
|
|
if( plugin->enc.lossy.quality.range_max >= plugin->enc.lossy.quality.range_min)
|
|
t_float = ( (float)conversionOptions.encodingOptions.iQuality * ( plugin->enc.lossy.quality.range_max - plugin->enc.lossy.quality.range_min ) / 100 ) + plugin->enc.lossy.quality.range_min;
|
|
else
|
|
t_float = ( (100.0f - (float)conversionOptions.encodingOptions.iQuality) * ( plugin->enc.lossy.quality.range_min - plugin->enc.lossy.quality.range_max ) / 100 ) + plugin->enc.lossy.quality.range_max;
|
|
//t_float -= t_float%plugin->enc.quality.step;
|
|
//sQuality = TQString().sprintf( "%.2f", t_float );
|
|
sQuality = TQString::number( t_float );
|
|
}
|
|
else {
|
|
if( plugin->enc.lossy.quality.range_max >= plugin->enc.lossy.quality.range_min)
|
|
t_int = ( conversionOptions.encodingOptions.iQuality * (int)( plugin->enc.lossy.quality.range_max - plugin->enc.lossy.quality.range_min ) / 100) + (int)plugin->enc.lossy.quality.range_min;
|
|
else
|
|
t_int = ( (100 - conversionOptions.encodingOptions.iQuality) * (int)( plugin->enc.lossy.quality.range_min - plugin->enc.lossy.quality.range_max ) / 100) + (int)plugin->enc.lossy.quality.range_max;
|
|
//t_int -= t_int%plugin->enc.quality.step;
|
|
sQuality = TQString::number( t_int );
|
|
}
|
|
if( plugin->enc.bin == "oggenc" ) sQuality.replace(TQChar('.'),TDEGlobal::locale()->decimalSymbol());
|
|
else if( plugin->enc.lossy.quality.separator != '.' ) sQuality.replace(TQChar('.'),plugin->enc.lossy.quality.separator);
|
|
}
|
|
else {
|
|
TQStringList::Iterator it = plugin->enc.lossy.quality.profiles.at( int(conversionOptions.encodingOptions.iQuality*plugin->enc.lossy.quality.range_max/100) );
|
|
sQuality = *it;
|
|
}
|
|
}
|
|
else if( conversionOptions.encodingOptions.sQualityMode == i18n("Lossless") && plugin->enc.lossless.enabled ) {
|
|
param.append( " " + plugin->enc.lossless.param );
|
|
}
|
|
else if( conversionOptions.encodingOptions.sQualityMode == i18n("Hybrid") && plugin->enc.hybrid.enabled ) {
|
|
param.append( " " + plugin->enc.hybrid.param );
|
|
sBitrate = TQString::number( conversionOptions.encodingOptions.iQuality );
|
|
}
|
|
|
|
if( conversionOptions.encodingOptions.samplingRate.bEnabled && plugin->enc.lossy.samplingrate.enabled ) {
|
|
param.append( " " + plugin->enc.lossy.samplingrate.param );
|
|
if( plugin->enc.lossy.samplingrate.unit == PluginLoaderBase::Hz ) {
|
|
sSamplingRate = TQString::number( conversionOptions.encodingOptions.samplingRate.iSamplingRate );
|
|
}
|
|
else {
|
|
sSamplingRate = TQString::number( (float)conversionOptions.encodingOptions.samplingRate.iSamplingRate/1000 );
|
|
}
|
|
}
|
|
|
|
if( conversionOptions.encodingOptions.channels.bEnabled ) {
|
|
if( conversionOptions.encodingOptions.channels.sChannels == i18n("Mono") && plugin->enc.lossy.channels.mono_enabled ) {
|
|
param.append( " " + plugin->enc.lossy.channels.mono_param );
|
|
}
|
|
else if( conversionOptions.encodingOptions.channels.sChannels == i18n("Stereo") && plugin->enc.lossy.channels.stereo_enabled ) {
|
|
param.append( " " + plugin->enc.lossy.channels.stereo_param );
|
|
}
|
|
else if( conversionOptions.encodingOptions.channels.sChannels == i18n("Joint-Stereo") && plugin->enc.lossy.channels.joint_stereo_enabled ) {
|
|
param.append( " " + plugin->enc.lossy.channels.joint_stereo_param );
|
|
}
|
|
else if( conversionOptions.encodingOptions.channels.sChannels == i18n("Forced Joint-Stereo") && plugin->enc.lossy.channels.forced_joint_stereo_enabled ) {
|
|
param.append( " " + plugin->enc.lossy.channels.forced_joint_stereo_param );
|
|
}
|
|
else if( conversionOptions.encodingOptions.channels.sChannels == i18n("Dual Channels") && plugin->enc.lossy.channels.dual_channels_enabled ) {
|
|
param.append( " " + plugin->enc.lossy.channels.dual_channels_param );
|
|
}
|
|
}
|
|
|
|
if( conversionOptions.encodingOptions.replaygain.bEnabled && plugin->enc.replaygain.enabled && plugin->enc.replaygain.use && formatItem->internalReplayGain ) {
|
|
param.append( " " + plugin->enc.replaygain.use );
|
|
}
|
|
else if( plugin->enc.replaygain.enabled && plugin->enc.replaygain.avoid ) {
|
|
param.append( " " + plugin->enc.replaygain.avoid );
|
|
}
|
|
|
|
// if( !tagEngine->canWrite(conversionOptions.encodingOptions.sFormat) && item->fileListItem->tags && plugin->enc.tag.enabled ) {
|
|
if( plugin->enc.tag.enabled && conversionOptions.encodingOptions.sFormat != "aac" ) { // HACK don't write metadata to aac
|
|
if( !plugin->enc.tag.param.isEmpty() ) param.append( " " + plugin->enc.tag.param );
|
|
if( !plugin->enc.tag.artist.isEmpty() ) param.append( " " + plugin->enc.tag.artist );
|
|
if( !plugin->enc.tag.album.isEmpty() ) param.append( " " + plugin->enc.tag.album );
|
|
if( !plugin->enc.tag.comment.isEmpty() ) param.append( " " + plugin->enc.tag.comment );
|
|
if( !plugin->enc.tag.disc.isEmpty() ) param.append( " " + plugin->enc.tag.disc );
|
|
if( !plugin->enc.tag.genre.isEmpty() ) param.append( " " + plugin->enc.tag.genre );
|
|
if( !plugin->enc.tag.track.isEmpty() ) param.append( " " + plugin->enc.tag.track );
|
|
if( !plugin->enc.tag.composer.isEmpty() ) param.append( " " + plugin->enc.tag.composer );
|
|
if( !plugin->enc.tag.title.isEmpty() ) param.append( " " + plugin->enc.tag.title );
|
|
if( !plugin->enc.tag.year.isEmpty() ) param.append( " " + plugin->enc.tag.year );
|
|
}
|
|
|
|
param.replace( "%c", sStrength );
|
|
param.replace( "%b", sBitrate );
|
|
param.replace( "%q", sQuality );
|
|
param.replace( "%m", sMinBitrate );
|
|
param.replace( "%M", sMaxBitrate );
|
|
param.replace( "%s", sSamplingRate );
|
|
|
|
return conversionOptions.encodingOptions.sInOutFiles.replace( "%p", param );
|
|
}
|