diff --git a/src/ui/ripcd.cpp b/src/ui/ripcd.cpp index c61557f26..9b7677672 100644 --- a/src/ui/ripcd.cpp +++ b/src/ui/ripcd.cpp @@ -1,26 +1,30 @@ /* 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 - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. + Clementine is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. - Clementine is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + Clementine is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with Clementine. If not, see <http://www.gnu.org/licenses/>. -*/ + You should have received a copy of the GNU General Public License + along with Clementine. If not, see <http://www.gnu.org/licenses/>. + */ #include "ripcd.h" #include "config.h" #include "ui_ripcd.h" #include "transcoder/transcoder.h" +#include "transcoder/transcoderoptionsdialog.h" +#include "ui/iconloader.h" + #include <QSettings> #include <QCheckBox> +#include <QFileDialog> #include <QFrame> #include <QLineEdit> #include <QtDebug> @@ -44,66 +48,153 @@ # undef AddJob #endif -RipCD::RipCD(QWidget* parent) -: QDialog(parent), - transcoder_(new Transcoder(this)), - queued_(0), - finished_success_(0), - finished_failed_(0), - checkboxes_(QList<QCheckBox*>()), - generated_files_(QList<QString>()) -{ +static bool ComparePresetsByName(const TranscoderPreset& left, + const TranscoderPreset& right) { + return left.name_ < right.name_; +} + +const char* RipCD::kSettingsGroup = "Transcoder"; +const int RipCD::kProgressInterval = 500; +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 - ui_.setupUi(this); - connect(ui_.ripButton,SIGNAL(clicked()),this,SLOT(clickedRipButton())); + ui_->setupUi(this); + 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(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(signalUpdateProgress()), SLOT(UpdateProgress())); + + connect(ui_->options, SIGNAL(clicked()), SLOT(Options())); + connect(ui_->select, SIGNAL(clicked()), SLOT(AddDestination())); + setWindowTitle(tr("Rip CD")); - - - //track_t i_first_track; p_cdio = cdio_open(NULL, DRIVER_UNKNOWN); //i_first_track = cdio_get_first_track_num(p_cdio); i_tracks = cdio_get_num_tracks(p_cdio); - ui_.tableWidget->setRowCount(i_tracks); - for(int i=1; i<=i_tracks; i++) { - qDebug() << i; - QCheckBox *_t = new QCheckBox(tr(""), ui_.tableWidget); + ui_->tableWidget->setRowCount(i_tracks); + for (int i = 1; i <= i_tracks; i++) { + QCheckBox *_t = new QCheckBox(tr(""), ui_->tableWidget); + _t->click(); checkboxes_.append(_t); - ui_.tableWidget->setCellWidget(i-1,0,_t); - ui_.tableWidget->setCellWidget(i-1,1,new QLabel(QString::number(i))); + ui_->tableWidget->setCellWidget(i - 1, 0, _t); + ui_->tableWidget->setCellWidget(i - 1, 1, new QLabel(QString::number(i))); QString _str_track; _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() { - QtConcurrent::run(this,&RipCD::toThreadClickedRipButton); - +int RipCD::nTracksToRip() { + int k = 0; + for (int i = 0; i < checkboxes_.length(); i++) { + if (checkboxes_.value(i)->isChecked() == true) { + k++; + } + } + return k; } void RipCD::toThreadClickedRipButton() { QString source_directory = "/tmp/"; - //track_t i_tracks = cdio_get_num_tracks(p_cdio); - for(int i=1; i <= i_tracks; i++) { - qDebug() << "Going for track " << 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); + + finished_success_ = 0; + finished_failed_ = 0; + ui_->progress_bar->setMaximum(nTracksToRip() * 2 * 100); + + 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_cursor; - 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); - 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 ) { + int16_t *p_readbuf = (int16_t *) calloc(CDIO_CD_FRAMESIZE_RAW, 1); + + QString filename = source_directory + "track" + + QString("0%1").arg(i).right(2) + ".wav"; + FILE *fp = fopen(filename.toUtf8().constData(), "w"); + 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."; break; } else { @@ -111,80 +202,139 @@ void RipCD::toThreadClickedRipButton() { } } + finished_success_++; + emit(signalUpdateProgress()); fclose(fp); free(p_readbuf); 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() { - 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(); + 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) { - unsigned int i; - unsigned char c; +void RipCD::clickedRipButton() { + QtConcurrent::run(this, &RipCD::toThreadClickedRipButton); - 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) { - 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) { - qDebug() << 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(); +} diff --git a/src/ui/ripcd.h b/src/ui/ripcd.h index 85941fd7c..6020a793c 100644 --- a/src/ui/ripcd.h +++ b/src/ui/ripcd.h @@ -1,19 +1,19 @@ /* 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 - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. + Clementine is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. - Clementine is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + Clementine is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with Clementine. If not, see <http://www.gnu.org/licenses/>. -*/ + You should have received a copy of the GNU General Public License + along with Clementine. If not, see <http://www.gnu.org/licenses/>. + */ #ifndef RIPCD_H #define RIPCD_H @@ -24,39 +24,60 @@ #include <cdio/cdio.h> #include "ui_ripcd.h" +class Ui_RipCD; class Transcoder; -class RipCD : public QDialog -{ +struct TranscoderPreset; + +class RipCD: public QDialog { Q_OBJECT // QThread thread; -public: + public: RipCD(QWidget* parent = 0); + static const char* kSettingsGroup; + static const int kProgressInterval; + static const int kMaxDestinationItems; -private: + private: Transcoder* transcoder_; - int queued_; - int finished_success_; - int finished_failed_; - track_t i_tracks; - Ui::RipCD ui_; + int queued_; + int finished_success_; + int finished_failed_; + track_t i_tracks; + Ui_RipCD* ui_; 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<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(); -private slots: + void signalUpdateProgress(); + + private slots: + void UpdateProgress(); void threadedTranscoding(); void clickedRipButton(); void JobComplete(const QString& filename, bool success); void AllJobsComplete(); void AppendOutput(const QString &filename); + void Options(); + void AddDestination(); + void Cancel(); }; #endif // RIPCD_H diff --git a/src/ui/ripcd.ui b/src/ui/ripcd.ui index bf21e2952..560752d70 100644 --- a/src/ui/ripcd.ui +++ b/src/ui/ripcd.ui @@ -16,7 +16,7 @@ <property name="windowTitle"> <string>Dialog</string> </property> - <widget class="QDialogButtonBox" name="buttonBox"> + <widget class="QDialogButtonBox" name="button_box"> <property name="geometry"> <rect> <x>240</x> @@ -60,14 +60,14 @@ </widget> </item> <item row="0" column="0"> - <widget class="QLabel" name="title_label"> + <widget class="QLabel" name="album_label"> <property name="text"> - <string>Title</string> + <string>Album</string> </property> </widget> </item> <item row="0" column="1" colspan="6"> - <widget class="QLineEdit" name="titleLineEdit"/> + <widget class="QLineEdit" name="albumLineEdit"/> </item> <item row="2" column="6"> <widget class="QLineEdit" name="discLineEdit"> @@ -117,7 +117,7 @@ <item row="0" column="0"> <widget class="QTableWidget" name="tableWidget"> <property name="columnCount"> - <number>5</number> + <number>4</number> </property> <attribute name="horizontalHeaderVisible"> <bool>true</bool> @@ -146,11 +146,6 @@ <string>Title</string> </property> </column> - <column> - <property name="text"> - <string>Artist</string> - </property> - </column> <column> <property name="text"> <string>Duration</string> @@ -173,76 +168,6 @@ <string>&Rip</string> </property> </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"> <property name="geometry"> <rect> @@ -253,11 +178,82 @@ </rect> </property> </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> <resources/> <connections> <connection> - <sender>buttonBox</sender> + <sender>button_box</sender> <signal>accepted()</signal> <receiver>RipCD</receiver> <slot>accept()</slot> @@ -273,7 +269,7 @@ </hints> </connection> <connection> - <sender>buttonBox</sender> + <sender>button_box</sender> <signal>rejected()</signal> <receiver>RipCD</receiver> <slot>reject()</slot>