1
0
mirror of https://github.com/clementine-player/Clementine synced 2025-01-31 11:35:24 +01:00

UI integration, needs beautification

Incorporates the 'Select Destiny' feature from 062889b, fetches values provided by user to populate file tags, UI adjustments
This commit is contained in:
asiviero 2014-01-13 03:32:25 -02:00
parent 34c178af65
commit a5021e656b
3 changed files with 381 additions and 214 deletions

View File

@ -1,26 +1,30 @@
/* This file is part of Clementine. /* This file is part of Clementine.
Copyright 2014, Andre Siviero <altsiviero@gmail.com> Copyright 2014, Andre Siviero <altsiviero@gmail.com>
Clementine is free software: you can redistribute it and/or modify Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
Clementine is distributed in the hope that it will be useful, Clementine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>. along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "ripcd.h" #include "ripcd.h"
#include "config.h" #include "config.h"
#include "ui_ripcd.h" #include "ui_ripcd.h"
#include "transcoder/transcoder.h" #include "transcoder/transcoder.h"
#include "transcoder/transcoderoptionsdialog.h"
#include "ui/iconloader.h"
#include <QSettings> #include <QSettings>
#include <QCheckBox> #include <QCheckBox>
#include <QFileDialog>
#include <QFrame> #include <QFrame>
#include <QLineEdit> #include <QLineEdit>
#include <QtDebug> #include <QtDebug>
@ -44,66 +48,153 @@
# undef AddJob # undef AddJob
#endif #endif
RipCD::RipCD(QWidget* parent) static bool ComparePresetsByName(const TranscoderPreset& left,
: QDialog(parent), const TranscoderPreset& right) {
transcoder_(new Transcoder(this)), return left.name_ < right.name_;
queued_(0), }
finished_success_(0),
finished_failed_(0), const char* RipCD::kSettingsGroup = "Transcoder";
checkboxes_(QList<QCheckBox*>()), const int RipCD::kProgressInterval = 500;
generated_files_(QList<QString>()) const int RipCD::kMaxDestinationItems = 10;
{
RipCD::RipCD(QWidget* parent) :
QDialog(parent), transcoder_(new Transcoder(this)), queued_(0), finished_success_(
0), finished_failed_(0), ui_(new Ui_RipCD()), checkboxes_(
QList<QCheckBox*>()), generated_files_(QList<QString>()), tracks_to_rip_(
QList<int>()), track_names_(QList<QLineEdit*>()) {
// Init // Init
ui_.setupUi(this); ui_->setupUi(this);
connect(ui_.ripButton,SIGNAL(clicked()),this,SLOT(clickedRipButton())); cancel_button_ = ui_->button_box->button(QDialogButtonBox::Cancel);
connect(ui_->ripButton, SIGNAL(clicked()), this, SLOT(clickedRipButton()));
connect(cancel_button_, SIGNAL(clicked()), SLOT(Cancel()));
connect(transcoder_, SIGNAL(JobComplete(QString,bool)), SLOT(JobComplete(QString,bool))); connect(transcoder_, SIGNAL(JobComplete(QString,bool)), SLOT(JobComplete(QString,bool)));
connect(transcoder_, SIGNAL(AllJobsComplete()), SLOT(AllJobsComplete())); connect(transcoder_, SIGNAL(AllJobsComplete()), SLOT(AllJobsComplete()));
connect(transcoder_, SIGNAL(JobOutputName(QString)), SLOT(AppendOutput(QString))); connect(transcoder_, SIGNAL(JobOutputName(QString)),
SLOT(AppendOutput(QString)));
connect(this, SIGNAL(RippingComplete()), SLOT(threadedTranscoding())); connect(this, SIGNAL(RippingComplete()), SLOT(threadedTranscoding()));
connect(this, SIGNAL(signalUpdateProgress()), SLOT(UpdateProgress()));
connect(ui_->options, SIGNAL(clicked()), SLOT(Options()));
connect(ui_->select, SIGNAL(clicked()), SLOT(AddDestination()));
setWindowTitle(tr("Rip CD")); setWindowTitle(tr("Rip CD"));
//track_t i_first_track; //track_t i_first_track;
p_cdio = cdio_open(NULL, DRIVER_UNKNOWN); p_cdio = cdio_open(NULL, DRIVER_UNKNOWN);
//i_first_track = cdio_get_first_track_num(p_cdio); //i_first_track = cdio_get_first_track_num(p_cdio);
i_tracks = cdio_get_num_tracks(p_cdio); i_tracks = cdio_get_num_tracks(p_cdio);
ui_.tableWidget->setRowCount(i_tracks); ui_->tableWidget->setRowCount(i_tracks);
for(int i=1; i<=i_tracks; i++) { for (int i = 1; i <= i_tracks; i++) {
qDebug() << i; QCheckBox *_t = new QCheckBox(tr(""), ui_->tableWidget);
QCheckBox *_t = new QCheckBox(tr(""), ui_.tableWidget); _t->click();
checkboxes_.append(_t); checkboxes_.append(_t);
ui_.tableWidget->setCellWidget(i-1,0,_t); ui_->tableWidget->setCellWidget(i - 1, 0, _t);
ui_.tableWidget->setCellWidget(i-1,1,new QLabel(QString::number(i))); ui_->tableWidget->setCellWidget(i - 1, 1, new QLabel(QString::number(i)));
QString _str_track; QString _str_track;
_str_track = "Track %1"; _str_track = "Track %1";
ui_.tableWidget->setCellWidget(i-1,2,new QLineEdit(_str_track.arg(QString::number(i)),ui_.tableWidget)); QLineEdit *_ql = new QLineEdit(_str_track.arg(QString::number(i)),
ui_->tableWidget);
track_names_.append(_ql);
ui_->tableWidget->setCellWidget(i - 1, 2, _ql);
}
// Get presets
QList < TranscoderPreset > presets = Transcoder::GetAllPresets();
qSort(presets.begin(), presets.end(), ComparePresetsByName);
foreach (const TranscoderPreset& preset, presets) {
ui_->format->addItem(
QString("%1 (.%2)").arg(preset.name_, preset.extension_),
QVariant::fromValue(preset));
}
// Load settings
QSettings s;
s.beginGroup(kSettingsGroup);
last_add_dir_ = s.value("last_add_dir", QDir::homePath()).toString();
QString last_output_format = s.value("last_output_format", "ogg").toString();
for (int i = 0; i < ui_->format->count(); ++i) {
if (last_output_format
== ui_->format->itemData(i).value<TranscoderPreset>().extension_) {
ui_->format->setCurrentIndex(i);
break;
}
}
ui_->progress_bar->setValue(0);
ui_->progress_bar->setMaximum(100);
}
void RipCD::write_WAV_header(FILE *stream, int32_t i_bytecount) {
fwrite("RIFF", sizeof(char), 4, stream);
put_num(i_bytecount + 44 - 8, stream, 4); /* 4-7 */
fwrite("WAVEfmt ", sizeof(char), 8, stream); /* 8-15 */
put_num(16, stream, 4); /* 16-19 */
put_num(1, stream, 2); /* 20-21 */
put_num(2, stream, 2); /* 22-23 */
put_num(44100, stream, 4); /* 24-27 */
put_num(44100 * 2 * 2, stream, 4); /* 28-31 */
put_num(4, stream, 2); /* 32-33 */
put_num(16, stream, 2); /* 34-35 */
fwrite("data", sizeof(char), 4, stream); /* 36-39 */
put_num(i_bytecount, stream, 4); /* 40-43 */
}
void RipCD::put_num(long int num, FILE *stream, int bytes) {
unsigned int i;
unsigned char c;
for (i = 0; bytes--; i++) {
c = (num >> (i << 3)) & 0xff;
if (fwrite(&c, sizeof(char), 1, stream) == -1) {
perror("Could not write to output.");
exit(1);
}
} }
} }
void RipCD::clickedRipButton() { int RipCD::nTracksToRip() {
QtConcurrent::run(this,&RipCD::toThreadClickedRipButton); int k = 0;
for (int i = 0; i < checkboxes_.length(); i++) {
if (checkboxes_.value(i)->isChecked() == true) {
k++;
}
}
return k;
} }
void RipCD::toThreadClickedRipButton() { void RipCD::toThreadClickedRipButton() {
QString source_directory = "/tmp/"; QString source_directory = "/tmp/";
//track_t i_tracks = cdio_get_num_tracks(p_cdio);
for(int i=1; i <= i_tracks; i++) { finished_success_ = 0;
qDebug() << "Going for track " << i; finished_failed_ = 0;
lsn_t i_first_lsn = cdio_get_track_lsn(p_cdio,i); ui_->progress_bar->setMaximum(nTracksToRip() * 2 * 100);
lsn_t i_last_lsn = cdio_get_track_last_lsn(p_cdio,i);
emit(signalUpdateProgress());
// Set up the progressbar
for (int i = 1; i <= i_tracks; i++) {
if (checkboxes_.value(i - 1)->isChecked() == false) {
continue;
}
tracks_to_rip_.append(i);
lsn_t i_first_lsn = cdio_get_track_lsn(p_cdio, i);
lsn_t i_last_lsn = cdio_get_track_last_lsn(p_cdio, i);
// lsn_t i_last_lsn = i_first_lsn+300; // debug // lsn_t i_last_lsn = i_first_lsn+300; // debug
lsn_t i_cursor; lsn_t i_cursor;
int16_t *p_readbuf = (int16_t *)calloc(CDIO_CD_FRAMESIZE_RAW,1); int16_t *p_readbuf = (int16_t *) calloc(CDIO_CD_FRAMESIZE_RAW, 1);
FILE *fp = fopen(QString(source_directory + "track" + QString("0%1").arg(i).right(2) + ".wav").toUtf8().constData(),"w");
write_WAV_header(fp,(i_last_lsn-i_first_lsn+1) * CDIO_CD_FRAMESIZE_RAW); QString filename = source_directory + "track"
for ( i_cursor = i_first_lsn; i_cursor <= i_last_lsn; i_cursor ++) { + QString("0%1").arg(i).right(2) + ".wav";
cdio_read_audio_sector(p_cdio,p_readbuf,i_cursor); FILE *fp = fopen(filename.toUtf8().constData(), "w");
if( !p_readbuf ) { write_WAV_header(fp,
(i_last_lsn - i_first_lsn + 1) * CDIO_CD_FRAMESIZE_RAW);
for (i_cursor = i_first_lsn; i_cursor <= i_last_lsn; i_cursor++) {
cdio_read_audio_sector(p_cdio, p_readbuf, i_cursor);
if (!p_readbuf) {
qDebug() << "Read error. Stopping."; qDebug() << "Read error. Stopping.";
break; break;
} else { } else {
@ -111,80 +202,139 @@ void RipCD::toThreadClickedRipButton() {
} }
} }
finished_success_++;
emit(signalUpdateProgress());
fclose(fp); fclose(fp);
free(p_readbuf); free(p_readbuf);
p_readbuf = NULL; p_readbuf = NULL;
//TranscoderPreset preset(Transcoder::PresetForFileType(Song::Type_OggVorbis));
TranscoderPreset preset =
ui_->format->itemData(ui_->format->currentIndex()).value<
TranscoderPreset>();
QString outfilename = GetOutputFileName(filename, preset);
transcoder_->AddJob(filename.toUtf8().constData(), preset, outfilename);
} }
emit(RippingComplete()); emit (RippingComplete());}
// Returns the rightmost non-empty part of 'path'.
QString RipCD::TrimPath(const QString& path) const {
return path.section('/', -1, -1, QString::SectionSkipEmpty);
}
QString RipCD::GetOutputFileName(const QString& input,
const TranscoderPreset &preset) const {
QString path =
ui_->destination->itemData(ui_->destination->currentIndex()).toString();
if (path.isEmpty()) {
// Keep the original path.
return input.section('.', 0, -2) + '.' + preset.extension_;
} else {
QString file_name = TrimPath(input);
file_name = file_name.section('.', 0, -2);
return path + '/' + file_name + '.' + preset.extension_;
}
}
void RipCD::UpdateProgress() {
int progress = (finished_success_ + finished_failed_) * 100;
QMap<QString, float> current_jobs = transcoder_->GetProgress();
foreach (float value, current_jobs.values()) {
progress += qBound(0, int(value * 100), 99);
}
ui_->progress_bar->setValue(progress);
} }
void RipCD::threadedTranscoding() { void RipCD::threadedTranscoding() {
QString source_directory = "/tmp/";
//track_t i_tracks = cdio_get_num_tracks(p_cdio);
TranscoderPreset preset(Transcoder::PresetForFileType(Song::Type_OggVorbis));
for(int i=1; i <= i_tracks; i++) {
transcoder_->AddJob(QString(source_directory + "track" + QString("0%1").arg(i).right(2) + ".wav").toUtf8().constData(), preset);
}
qDebug() << "Total jobs: " << transcoder_->QueuedJobsCount();
transcoder_->Start(); transcoder_->Start();
TranscoderPreset preset =
ui_->format->itemData(ui_->format->currentIndex()).value<TranscoderPreset>();
// Save the last output format
QSettings s;
s.beginGroup(kSettingsGroup);
s.setValue("last_output_format", preset.extension_);
} }
void RipCD::put_num(long int num, FILE *stream, int bytes) { void RipCD::clickedRipButton() {
unsigned int i; QtConcurrent::run(this, &RipCD::toThreadClickedRipButton);
unsigned char c;
for (i=0; bytes--; i++) {
c = (num >> (i<<3)) & 0xff;
if (fwrite(&c, sizeof(char), 1, stream)==-1) {
perror("Could not write to output.");
exit(1);
}
}
}
void RipCD::write_WAV_header(FILE *stream,int32_t i_bytecount) {
fwrite("RIFF",sizeof(char),4,stream);
put_num(i_bytecount+44-8, stream, 4); /* 4-7 */
fwrite("WAVEfmt ",sizeof(char),8,stream); /* 8-15 */
put_num(16, stream, 4); /* 16-19 */
put_num(1, stream, 2); /* 20-21 */
put_num(2, stream, 2); /* 22-23 */
put_num(44100, stream, 4); /* 24-27 */
put_num(44100*2*2, stream, 4); /* 28-31 */
put_num(4, stream, 2); /* 32-33 */
put_num(16, stream, 2); /* 34-35 */
fwrite("data",sizeof(char),4,stream); /* 36-39 */
put_num(i_bytecount, stream, 4); /* 40-43 */
}
void RipCD::AllJobsComplete() {
qDebug() << "All Jobs Complete emmited";
// TODO Handle this properly
// having a little trouble on wav files, works fine on ogg
qSort(generated_files_);
int i;
for(i = 1; i <= i_tracks; i++) {
qDebug() << generated_files_.value(i-1);
TagLib::FileRef f(generated_files_.value(i-1).toUtf8().constData());
if(checkboxes_.value(i-1)->isChecked() == true) {
f.tag()->setArtist(ui_.artistLineEdit->text().toUtf8().constData());
}
f.save();
}
// Resets list
generated_files_.QList<QString>::~QList<QString>();
generated_files_ = QList<QString>();
} }
void RipCD::JobComplete(const QString& filename, bool success) { void RipCD::JobComplete(const QString& filename, bool success) {
qDebug() << "Completed"; (*(success ? &finished_success_ : &finished_failed_))++;
emit(signalUpdateProgress());
}
void RipCD::AllJobsComplete() {
// having a little trouble on wav files, works fine on ogg-vorbis
qSort(generated_files_);
int i;
for (i = 0; i < generated_files_.length(); i++) {
TagLib::FileRef f(generated_files_.value(i).toUtf8().constData());
f.tag()->setTitle(
track_names_.value(tracks_to_rip_.value(i) - 1)->text().toUtf8().constData());
f.tag()->setAlbum(ui_->albumLineEdit->text().toUtf8().constData());
f.tag()->setArtist(ui_->artistLineEdit->text().toUtf8().constData());
f.tag()->setGenre(ui_->genreLineEdit->text().toUtf8().constData());
f.tag()->setYear(ui_->yearLineEdit->text().toInt());
f.tag()->setTrack(tracks_to_rip_.value(i) - 1);
// Need to check this
//f.tag()->setDisc(ui_->discLineEdit->text().toInt());
f.save();
}
// Resets lists
generated_files_.clear();
tracks_to_rip_.clear();
} }
void RipCD::AppendOutput(const QString &filename) { void RipCD::AppendOutput(const QString &filename) {
qDebug() << filename;
generated_files_.append(filename); generated_files_.append(filename);
} }
void RipCD::Options() {
TranscoderPreset preset =
ui_->format->itemData(ui_->format->currentIndex()).value<TranscoderPreset>();
TranscoderOptionsDialog dialog(preset.type_, this);
if (dialog.is_valid()) {
dialog.exec();
}
}
// Adds a folder to the destination box.
void RipCD::AddDestination() {
int index = ui_->destination->currentIndex();
QString initial_dir = (
!ui_->destination->itemData(index).isNull() ?
ui_->destination->itemData(index).toString() : QDir::homePath());
QString dir = QFileDialog::getExistingDirectory(this, tr("Add folder"),
initial_dir);
if (!dir.isEmpty()) {
// Keep only a finite number of items in the box.
while (ui_->destination->count() >= kMaxDestinationItems) {
ui_->destination->removeItem(1); // The oldest folder item.
}
QIcon icon = IconLoader::Load("folder");
QVariant data = QVariant::fromValue(dir);
// Do not insert duplicates.
int duplicate_index = ui_->destination->findData(data);
if (duplicate_index == -1) {
ui_->destination->addItem(icon, dir, data);
ui_->destination->setCurrentIndex(ui_->destination->count() - 1);
} else {
ui_->destination->setCurrentIndex(duplicate_index);
}
}
}
void RipCD::Cancel() {
transcoder_->Cancel();
}

View File

@ -1,19 +1,19 @@
/* This file is part of Clementine. /* This file is part of Clementine.
Copyright 2014, Andre Siviero <altsiviero@gmail.com> Copyright 2014, Andre Siviero <altsiviero@gmail.com>
Clementine is free software: you can redistribute it and/or modify Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
Clementine is distributed in the hope that it will be useful, Clementine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>. along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef RIPCD_H #ifndef RIPCD_H
#define RIPCD_H #define RIPCD_H
@ -24,39 +24,60 @@
#include <cdio/cdio.h> #include <cdio/cdio.h>
#include "ui_ripcd.h" #include "ui_ripcd.h"
class Ui_RipCD;
class Transcoder; class Transcoder;
class RipCD : public QDialog struct TranscoderPreset;
{
class RipCD: public QDialog {
Q_OBJECT Q_OBJECT
// QThread thread; // QThread thread;
public: public:
RipCD(QWidget* parent = 0); RipCD(QWidget* parent = 0);
static const char* kSettingsGroup;
static const int kProgressInterval;
static const int kMaxDestinationItems;
private: private:
Transcoder* transcoder_; Transcoder* transcoder_;
int queued_; int queued_;
int finished_success_; int finished_success_;
int finished_failed_; int finished_failed_;
track_t i_tracks; track_t i_tracks;
Ui::RipCD ui_; Ui_RipCD* ui_;
CdIo_t *p_cdio; CdIo_t *p_cdio;
void write_WAV_header(FILE *stream,int32_t i_bytecount);
void put_num(long int num, FILE *stream, int bytes);
void toThreadClickedRipButton();
QList<QCheckBox*> checkboxes_; QList<QCheckBox*> checkboxes_;
QList<QString> generated_files_; QList<QString> generated_files_;
QList<int> tracks_to_rip_;
QList<QLineEdit*> track_names_;
QString last_add_dir_;
QPushButton* cancel_button_;
signals: void write_WAV_header(FILE *stream, int32_t i_bytecount);
void put_num(long int num, FILE *stream, int bytes);
int nTracksToRip();
void toThreadClickedRipButton();
QString TrimPath(const QString& path) const;
QString GetOutputFileName(const QString& input,
const TranscoderPreset& preset) const;
signals:
void RippingComplete(); void RippingComplete();
private slots: void signalUpdateProgress();
private slots:
void UpdateProgress();
void threadedTranscoding(); void threadedTranscoding();
void clickedRipButton(); void clickedRipButton();
void JobComplete(const QString& filename, bool success); void JobComplete(const QString& filename, bool success);
void AllJobsComplete(); void AllJobsComplete();
void AppendOutput(const QString &filename); void AppendOutput(const QString &filename);
void Options();
void AddDestination();
void Cancel();
}; };
#endif // RIPCD_H #endif // RIPCD_H

View File

@ -16,7 +16,7 @@
<property name="windowTitle"> <property name="windowTitle">
<string>Dialog</string> <string>Dialog</string>
</property> </property>
<widget class="QDialogButtonBox" name="buttonBox"> <widget class="QDialogButtonBox" name="button_box">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>240</x> <x>240</x>
@ -60,14 +60,14 @@
</widget> </widget>
</item> </item>
<item row="0" column="0"> <item row="0" column="0">
<widget class="QLabel" name="title_label"> <widget class="QLabel" name="album_label">
<property name="text"> <property name="text">
<string>Title</string> <string>Album</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="1" colspan="6"> <item row="0" column="1" colspan="6">
<widget class="QLineEdit" name="titleLineEdit"/> <widget class="QLineEdit" name="albumLineEdit"/>
</item> </item>
<item row="2" column="6"> <item row="2" column="6">
<widget class="QLineEdit" name="discLineEdit"> <widget class="QLineEdit" name="discLineEdit">
@ -117,7 +117,7 @@
<item row="0" column="0"> <item row="0" column="0">
<widget class="QTableWidget" name="tableWidget"> <widget class="QTableWidget" name="tableWidget">
<property name="columnCount"> <property name="columnCount">
<number>5</number> <number>4</number>
</property> </property>
<attribute name="horizontalHeaderVisible"> <attribute name="horizontalHeaderVisible">
<bool>true</bool> <bool>true</bool>
@ -146,11 +146,6 @@
<string>Title</string> <string>Title</string>
</property> </property>
</column> </column>
<column>
<property name="text">
<string>Artist</string>
</property>
</column>
<column> <column>
<property name="text"> <property name="text">
<string>Duration</string> <string>Duration</string>
@ -173,76 +168,6 @@
<string>&amp;Rip</string> <string>&amp;Rip</string>
</property> </property>
</widget> </widget>
<widget class="QWidget" name="layoutWidget">
<property name="geometry">
<rect>
<x>120</x>
<y>310</y>
<width>461</width>
<height>29</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QComboBox" name="format">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="options">
<property name="text">
<string>Options...</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QLabel" name="label">
<property name="geometry">
<rect>
<x>10</x>
<y>310</y>
<width>90</width>
<height>29</height>
</rect>
</property>
<property name="text">
<string>Audio format</string>
</property>
</widget>
<widget class="QLabel" name="label_2">
<property name="geometry">
<rect>
<x>10</x>
<y>350</y>
<width>79</width>
<height>27</height>
</rect>
</property>
<property name="text">
<string>Destination</string>
</property>
</widget>
<widget class="QComboBox" name="destination">
<property name="geometry">
<rect>
<x>120</x>
<y>350</y>
<width>461</width>
<height>27</height>
</rect>
</property>
<item>
<property name="text">
<string>Alongside the originals</string>
</property>
</item>
</widget>
<widget class="QProgressBar" name="progress_bar"> <widget class="QProgressBar" name="progress_bar">
<property name="geometry"> <property name="geometry">
<rect> <rect>
@ -253,11 +178,82 @@
</rect> </rect>
</property> </property>
</widget> </widget>
<widget class="QGroupBox" name="output_group">
<property name="geometry">
<rect>
<x>10</x>
<y>300</y>
<width>571</width>
<height>96</height>
</rect>
</property>
<property name="title">
<string>Output options</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Audio format</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="format">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="options">
<property name="text">
<string>Options...</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Destination</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="destination">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<item>
<property name="text">
<string>Alongside the originals</string>
</property>
</item>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="select">
<property name="text">
<string>Select...</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget> </widget>
<resources/> <resources/>
<connections> <connections>
<connection> <connection>
<sender>buttonBox</sender> <sender>button_box</sender>
<signal>accepted()</signal> <signal>accepted()</signal>
<receiver>RipCD</receiver> <receiver>RipCD</receiver>
<slot>accept()</slot> <slot>accept()</slot>
@ -273,7 +269,7 @@
</hints> </hints>
</connection> </connection>
<connection> <connection>
<sender>buttonBox</sender> <sender>button_box</sender>
<signal>rejected()</signal> <signal>rejected()</signal>
<receiver>RipCD</receiver> <receiver>RipCD</receiver>
<slot>reject()</slot> <slot>reject()</slot>