diff options
Diffstat (limited to 'src/filelist.cpp')
-rwxr-xr-x | src/filelist.cpp | 1445 |
1 files changed, 1445 insertions, 0 deletions
diff --git a/src/filelist.cpp b/src/filelist.cpp new file mode 100755 index 0000000..c4e6b5d --- /dev/null +++ b/src/filelist.cpp @@ -0,0 +1,1445 @@ + +#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 <klocale.h> +#include <kpopupmenu.h> +#include <kaction.h> +#include <kactioncollection.h> +#include <kmimetype.h> +#include <kurl.h> +#include <kmountpoint.h> +#include <kstandarddirs.h> +#include <kurldrag.h> +#include <kapplication.h> + +#include <qlayout.h> +#include <qfileinfo.h> +#include <qsimplerichtext.h> +#include <qpainter.h> +#include <qapplication.h> +#include <qdragobject.h> +#include <qheader.h> +#include <qdir.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( KListView* parent, FileListItem* after ) + : KListViewItem( parent, after ) +{ + tags = 0; + converting = false; + time = 0; + ripping = false; +} + +FileListItem::FileListItem( KListView* parent ) + : KListViewItem( parent ) +{ + tags = 0; + converting = false; + time = 0; + ripping = false; +} + +FileListItem::~FileListItem() +{} + +void FileListItem::paintCell( QPainter *p, const QColorGroup &cg, int column, int width, int alignment ) +{ + // NOTE speed up this function + // NOTE calculate the red color + + QColorGroup _cg( cg ); + QColor c; + + if( column == ((FileList*)listView())->columnByName(i18n("Input")) || column == ((FileList*)listView())->columnByName(i18n("Output")) ) + { + int margin = listView()->itemMargin(); + int w = width - 2*margin; + int h = height(); + QRect textRect = p->boundingRect( margin, 0, w, h, alignment, text(column) ); + + if( textRect.width() > w ) { + alignment = Qt::AlignRight | Qt::SingleLine; + } + + /*if ( textRect.width() <= w ) { + p->drawText( margin, 0, w, h, alignment | Qt::SingleLine | Qt::ExpandTabs, text(column), -1 ); + } + else { + textRect = p->boundingRect( margin, 0, w, h, Qt::AlignLeft, "... " ); + p->drawText( margin, 0, textRect.width(), h, Qt::AlignLeft | Qt::SingleLine | Qt::ExpandTabs, "...", -1 ); + p->drawText( margin+textRect.width(), 0, w-textRect.width(), h, Qt::AlignRight | Qt::SingleLine | Qt::ExpandTabs, text(column), -1 ); + }*/ + } + + if( isSelected() && converting ) { + _cg.setColor( QColorGroup::Highlight, QColor( 215, 62, 62 ) ); + QListViewItem::paintCell( p, _cg, column, width, alignment ); + return; + } + else if( converting && column != listView()->sortColumn() ) { + _cg.setColor( QColorGroup::Base, QColor( 255, 234, 234 ) ); + QListViewItem::paintCell( p, _cg, column, width, alignment ); + return; + } + else if( converting && column == listView()->sortColumn() ) { + _cg.setColor( QColorGroup::Base, QColor( 247, 227, 227 ) ); + QListViewItem::paintCell( p, _cg, column, width, alignment ); + return; + } + + KListViewItem::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, QWidget* parent, const char* name ) + : KListView( 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( QListView::Extended ); + setAllColumnsShowFocus( true ); + setResizeMode( LastColumn ); + setSorting( -1 ); // NOTE if commented out, items aren't moveable anymore + + setMinimumHeight( 200 ); + + QGridLayout* grid = new QGridLayout( this, 2, 1, 11, 6 ); + grid->setRowStretch( 0, 1 ); + grid->setRowStretch( 2, 1 ); + grid->setColStretch( 0, 1 ); + grid->setColStretch( 2, 1 ); + pScanStatus = new KProgress( this, "pScanStatus" ); + pScanStatus->setMinimumHeight( pScanStatus->height() ); + pScanStatus->setFormat( "%v / %m" ); + pScanStatus->hide(); + grid->addWidget( pScanStatus, 1, 1 ); + grid->setColStretch( 1, 2 ); + + contextMenu = new KPopupMenu( this ); + connect( this, SIGNAL(contextMenuRequested( QListViewItem*, const QPoint&, int )), + this, SLOT(showContextMenu( QListViewItem*, const QPoint&, int )) + ); + + // we haven't got access to the action collection of soundKonverter, so let's create a new one + actionCollection = new KActionCollection( this ); + + edit = new KAction( i18n("Edit options ..."), "view_text", 0, this, SLOT(showOptionsEditorDialog()), actionCollection, "edit_options" ); + start = new KAction( i18n("Start conversion"), "run", 0, this, SLOT(convertSelectedItems()), actionCollection, "start_conversion" ); + stop = new KAction( i18n("Stop conversion"), "stop", 0, this, SLOT(stopSelectedItems()), actionCollection, "stop_conversion" ); + remove = new KAction( i18n("Remove"), "edittrash", Key_Delete, this, SLOT(removeSelectedItems()), actionCollection, "remove" ); + paste = new KAction( i18n("Paste"), "editpaste", 0, this, 0, actionCollection, "paste" ); // TODO paste + + connect( this, SIGNAL(selectionChanged()), + this, SLOT(itemsSelected()) + ); + +// connect( this, SIGNAL(clicked(QListViewItem*,const QPoint&,int)), +// this, SLOT(clickedSomewhere(QListViewItem*,const QPoint&,int)) +// ); + + bubble = new QSimpleRichText( 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>" ), QApplication::font() ); + + connect( header(), SIGNAL(sizeChange( int, int, int )), + SLOT(columnResizeEvent( int, int, int )) + ); + connect( this, SIGNAL( dropped(QDropEvent*, QListViewItem*, QListViewItem*) ), + SLOT( slotDropped(QDropEvent*, QListViewItem*, QListViewItem*) ) + ); + +// if( QFile::exists(locateLocal("data","soundkonverter/filelist.autosave.xml")) ) load( true ); + +// debug(); // NOTE DEBUG +} + +FileList::~FileList() +{ + delete optionsEditor; +} + +int FileList::columnByName( const QString& name ) +{ + for( int i = 0; i < columns(); ++i ) { + if( columnText( i ) == name ) return i; + } + return -1; +} + +void FileList::viewportPaintEvent( QPaintEvent* e ) +{ + KListView::viewportPaintEvent( e ); + + // the bubble help + if( childCount() == 0 ) { + QPainter p( viewport() ); + + bubble->setWidth( width() - 50 ); + + const uint w = bubble->width() + 20; + const uint h = bubble->height() + 20; + + p.setBrush( colorGroup().background() ); + p.drawRoundRect( 15, 15, w, h, (8*200)/w, (8*200)/h ); + bubble->draw( &p, 20, 20, QRect(), colorGroup() ); + } +} + +void FileList::viewportResizeEvent( QResizeEvent* ) +{ + // 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( QListViewItem*, const QPoint& pos, int ) +// { +// /* if( childCount() == 0 ) { +// kdDebug() << "clicked: `" << bubble->anchorAt(mapFromGlobal(pos)-QPoint(24,0)) << " (" << pos.x() << " | " << pos.y() << ")'" << endl; +// }*/ +// } + +bool FileList::acceptDrag( QDropEvent* e ) const +{ + return ( e->source() == viewport() || KURLDrag::canDecode(e) ); // TODO verify the files +} + +void FileList::slotDropped( QDropEvent* e, QListViewItem*, QListViewItem* itemAfter ) +{ + QString file; + KURL::List list; + QStringList 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 = QDir::convertSeparators( (*it).pathOrURL() ); // TODO implement that in the url/file dialog, too? + QFileInfo fileInfo( file ); + if( fileInfo.isDir() ) + { + addDir( file ); + } + else + { + files.append( (*it).url() ); + } + } + addFiles( files, (FileListItem*)itemAfter, true ); + save( true ); + } +} + +void FileList::showContextMenu( QListViewItem* item, const QPoint& 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 QString& directory, QStringList filter, bool recursive, bool fast, int count ) +{ // NOTE speed up? + QDir dir( directory ); + dir.setFilter( QDir::Files | QDir::Dirs | QDir::NoSymLinks | QDir::Readable ); + + QStringList list = dir.entryList(); + + for( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) { + if( *it == "." || *it == ".." ) continue; + QFileInfo fileInfo( directory + "/" + *it ); + if( fast ) { + if( fileInfo.isDir() && recursive ) { + count = listDir( 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( QStringList::Iterator jt = filter.begin(); jt != filter.end(); ++jt ) { + if( (*it).endsWith("."+(*jt),false) ) { + count++; + pScanStatus->setTotalSteps( count ); + break; + } + } + if( filter.first() == "" ) { + count++; + pScanStatus->setTotalSteps( count ); + } + } + } + else { + if( fileInfo.isDir() && recursive ) { + count = listDir( 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( QStringList::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( QStringList 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; + QString filePathName; + QString device; + + for( QStringList::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 = QDir::homeDirPath() + "/" + filePathName; + newItem->local = true; + } + else if( (*it).left( 14 ) == "system:/users/" || (*it).left( 6 ) == "home:/" ) { + int length = ( (*it).left(6) == "home:/" ) ? 6 : 14; + QString 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 KSharedPtr<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; + QFileInfo 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 QString& directory, const QStringList& filter, bool recursive ) +{ + pScanStatus->setProgress( 0 ); + pScanStatus->setTotalSteps( 0 ); + pScanStatus->show(); // show the status while scanning the directories + kapp->processEvents(); + + int count = listDir( directory, filter, recursive, true ); + listDir( directory, filter, recursive ); + + pScanStatus->hide(); // hide the status bar, when the scan is done +} + +void FileList::addTracks( const QString& device, QValueList<int> trackList ) +{ + for( QValueList<int>::Iterator it = trackList.begin(); it != trackList.end(); ++it ) { +// logger->log( 1000, i18n("Adding track") + QString().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") + QString().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 = QDir::homeDirPath() + "/" + i18n("Track") + QString().sprintf(" %02i",newItem->track) + "." + newItem->fileFormat; + } + else { +// logger->log( 1000, " " + i18n("Tags successfully read") ); + newItem->time = newItem->tags->length; + newItem->options.filePathName = QDir::homeDirPath() + "/" + QString().sprintf("%02i - ",newItem->track) + newItem->tags->title + "." + newItem->fileFormat; + newItem->fileName = i18n("Audio CD (%1)").arg(device) + ": " + QString().sprintf("%02i - ",newItem->track) + newItem->tags->title; + } + updateItem( newItem ); + emit increaseTime( newItem->time ); + } + emit fileCountChanged( childCount() ); +} + +void FileList::addDisc( const QString& 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 = QDir::homeDirPath() + "/" + i18n("Audio CD") + "." + newItem->fileFormat; + } + else { +// logger->log( 1000, " " + i18n("Tags successfully read") ); + newItem->time = newItem->tags->length; + newItem->options.filePathName = QDir::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 QString& 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 && QFile::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( this, SIGNAL(editItems(QValueList<FileListItem*>)), + optionsEditor, SLOT(itemsSelected(QValueList<FileListItem*>)) + ); + connect( this, SIGNAL(setPreviousItemEnabled(bool)), + optionsEditor, SLOT(setPreviousEnabled(bool)) + ); + connect( this, SIGNAL(setNextItemEnabled(bool)), + optionsEditor, SLOT(setNextEnabled(bool)) + ); + connect( optionsEditor, SIGNAL(user2Clicked()), + this, SLOT(selectPreviousItem()) + ); + connect( optionsEditor, SIGNAL(user1Clicked()), + this, SLOT(selectNextItem()) + ); + /*connect( this, SIGNAL(moveEditor(int,int)), + optionsEditor, 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( QValueList<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( QValueList<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; + + QStringList 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; + QString name; + FileListItem* lastListItem = lastItem(); + QString filename; + if( autosave ) filename = locateLocal("data","soundkonverter/filelist.autosave.xml"); + else filename = locateLocal("data","soundkonverter/filelist.xml"); + + QDomDocument domTree; + QFile opmlFile( filename ); + if( !opmlFile.open( IO_ReadOnly ) ) return; + if( !domTree.setContent( &opmlFile ) ) return; + opmlFile.close(); + + QDomElement root = domTree.documentElement(); + if( root.attribute("type") != "filelist" ) return; + QDomNode 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...) + + QTime time; + time.start(); + + QDomDocument domTree; + QDomElement root = domTree.createElement( "soundkonverter" ); + root.setAttribute( "type", "filelist" ); + domTree.appendChild( root ); + + QDomElement info = domTree.createElement( "info" ); + info.setAttribute( "version", "300" ); + root.appendChild( info ); + + for( FileListItem* item = firstChild(); item != 0; item = item->nextSibling() ) { + QDomElement 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 ); + + QDomElement 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 ); + + QDomElement samplingRate = domTree.createElement( "samplingRate" ); + + samplingRate.setAttribute( "bEnabled", item->options.encodingOptions.samplingRate.bEnabled ); + samplingRate.setAttribute( "iSamplingRate", item->options.encodingOptions.samplingRate.iSamplingRate ); + + encodingOptions.appendChild( samplingRate ); + + QDomElement channels = domTree.createElement( "channels" ); + + channels.setAttribute( "bEnabled", item->options.encodingOptions.channels.bEnabled ); + channels.setAttribute( "sChannels", item->options.encodingOptions.channels.sChannels ); + + encodingOptions.appendChild( channels ); + + QDomElement 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 ); + + QDomElement 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 ) + { + QDomElement 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 ); + } + + QString filename; + if( autosave ) filename = locateLocal("data","soundkonverter/filelist.autosave.xml"); + else filename = locateLocal("data","soundkonverter/filelist.xml"); + + QFile opmlFile( filename ); + if( !opmlFile.open( IO_WriteOnly ) ) return; + + QTextStream ts( &opmlFile ); + ts << domTree.toString(); + + opmlFile.close(); + + logger->log( 1000, "save file list: " + QString::number(time.elapsed()) ); +} + +void FileList::debug() // NOTE DEBUG +{ + logger->log( 1000, "DEBUG begin" ); + + ConversionOptions conversionOptions; + + QStringList formats = config->allEncodableFormats(); + + for( QStringList::Iterator a = formats.begin(); a != formats.end(); ++a ) + { + logger->log( 1000, "format: " + (*a) ); + FormatItem* formatItem = config->getFormatItem( *a ); + if( formatItem == 0 ) continue; + + for( QValueList<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( QValueList<ConvertPlugin*>::Iterator b = formatItem->decoders.begin(); b != formatItem->decoders.end(); ++b ) { + formatItem->decoder = (*b); + } + + for( QValueList<ReplayGainPlugin*>::Iterator b = formatItem->replaygains.begin(); b != formatItem->replaygains.end(); ++b ) { + formatItem->replaygain = (*b); + } + } + + logger->log( 1000, "DEBUG end" ); +} + +QString FileList::debug_params( ConversionOptions conversionOptions, FormatItem* formatItem ) // NOTE DEBUG +{ + ConvertPlugin* plugin = formatItem->encoder; + + QString sStrength; + QString sBitrate; + QString sQuality; + QString sMinBitrate; + QString sMaxBitrate; + QString sSamplingRate; + + int t_int; + float t_float; + + QString 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 = QString::number( compressionLevel ); + else + sStrength = QString::number( plugin->enc.strength.range_min - compressionLevel ); + } + else { + if( plugin->enc.strength.range_max >= plugin->enc.strength.range_min ) + sStrength = QString::number( int(compressionLevel) ); + else + sStrength = QString::number( int(plugin->enc.strength.range_min - compressionLevel) ); + } + if( plugin->enc.strength.separator != '.' ) sStrength.replace( QChar('.'), plugin->enc.strength.separator ); + } + else { + QStringList::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 = QString::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 = QString::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 = QString::number( conversionOptions.encodingOptions.iMinBitrate ); + param.append( " " + plugin->enc.lossy.bitrate.abr.bitrate_range.param_max ); + sMaxBitrate = QString::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 = QString().sprintf( "%.2f", t_float ); + sQuality = QString::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 = QString::number( t_int ); + } + if( plugin->enc.bin == "oggenc" ) sQuality.replace(QChar('.'),KGlobal::locale()->decimalSymbol()); + else if( plugin->enc.lossy.quality.separator != '.' ) sQuality.replace(QChar('.'),plugin->enc.lossy.quality.separator); + } + else { + QStringList::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 = QString::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 = QString::number( conversionOptions.encodingOptions.samplingRate.iSamplingRate ); + } + else { + sSamplingRate = QString::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 ); +} |