diff --git a/core/audex.cpp b/core/audex.cpp index 5929291..3e91eb1 100644 --- a/core/audex.cpp +++ b/core/audex.cpp @@ -1,1002 +1,1002 @@ /* AUDEX CDDA EXTRACTOR * Copyright (C) 2007-2015 Marco Nelles (audex@maniatek.com) * * * This program 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. * * This program 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 this program. If not, see . */ #include "audex.h" /* The heart of audex */ Audex::Audex(QWidget* parent, ProfileModel *profile_model, CDDAModel *cdda_model) : QObject(parent) { Q_UNUSED(parent); this->profile_model = profile_model; this->cdda_model = cdda_model; p_profile_name = profile_model->data(profile_model->index(profile_model->currentProfileRow(), PROFILE_MODEL_COLUMN_NAME_INDEX)).toString(); p_suffix = profile_model->getSelectedEncoderSuffixFromCurrentIndex(); p_single_file = profile_model->data(profile_model->index(profile_model->currentProfileRow(), PROFILE_MODEL_COLUMN_SF_INDEX)).toBool(); encoder_wrapper = new EncoderWrapper(this, profile_model->getSelectedEncoderPatternFromCurrentIndex(), profile_model->getSelectedEncoderNameAndVersion(), Preferences::deletePartialFiles()); if (!encoder_wrapper) { qDebug() << "PANIC ERROR. Could not load object EncoderWrapper. Low mem?"; return; } cdda_extract_thread = new CDDAExtractThread(this, cdda_model->paranoia()); if (!cdda_extract_thread) { qDebug() << "PANIC ERROR. Could not load object CDDAExtractThread. Low mem?"; return; } cdda_extract_thread->setSampleOffset(Preferences::sampleOffset()); jobs = new AudexJobs(); connect(jobs, SIGNAL(newJobAvailable()), this, SLOT(start_encode())); wave_file_writer = new WaveFileWriter(); last_measuring_point_sector = -1; timer_extract = new QTimer(this); connect(timer_extract, SIGNAL(timeout()), this, SLOT(calculate_speed_extract())); timer_extract->start(4000); last_measuring_point_encoder_percent = -1; timer_encode = new QTimer(this); connect(timer_encode, SIGNAL(timeout()), this, SLOT(calculate_speed_encode())); timer_encode->start(2000); connect(encoder_wrapper, SIGNAL(progress(int)), this, SLOT(progress_encode(int))); connect(encoder_wrapper, SIGNAL(finished()), this, SLOT(finish_encode())); connect(encoder_wrapper, SIGNAL(info(const QString&)), this, SLOT(slot_info(const QString&))); connect(encoder_wrapper, SIGNAL(warning(const QString&)), this, SLOT(slot_warning(const QString&))); connect(encoder_wrapper, SIGNAL(error(const QString&, const QString&)), this, SLOT(slot_error(const QString&, const QString&))); connect(cdda_extract_thread, SIGNAL(progress(int, int, int)), this, SLOT(progress_extract(int, int, int))); connect(cdda_extract_thread, SIGNAL(output(const QByteArray&)), this, SLOT(write_to_wave(const QByteArray&))); connect(cdda_extract_thread, SIGNAL(finished()), this, SLOT(finish_extract())); connect(cdda_extract_thread, SIGNAL(terminated()), this, SLOT(finish_extract())); connect(cdda_extract_thread, SIGNAL(info(const QString&)), this, SLOT(slot_info(const QString&))); connect(cdda_extract_thread, SIGNAL(warning(const QString&)), this, SLOT(slot_warning(const QString&))); connect(cdda_extract_thread, SIGNAL(error(const QString&, const QString&)), this, SLOT(slot_error(const QString&, const QString&))); process_counter = 0; timeout_done = false; timeout_counter = 0; _finished = false; _finished_successful = false; en_track_index = 0; en_track_count = 0; ex_track_index = 0; ex_track_count = 0; current_sector = 0; current_encoder_percent = 0; overall_frames = 0; } Audex::~Audex() { delete encoder_wrapper; delete cdda_extract_thread; delete wave_file_writer; delete jobs; delete tmp_dir; } bool Audex::prepare() { if (profile_model->currentProfileIndex() < 0) { slot_error(i18n("No profile selected. Operation abort.")); return false; } qDebug() << "Using profile with index" << profile_model->currentProfileIndex(); tmp_dir = new TmpDir("audex", "work"); tmp_path = tmp_dir->tmpPath(); if (tmp_dir->error()) return false; return true; } void Audex::start() { emit changedEncodeTrack(0, 0, ""); emit info(i18n("Start ripping and encoding with profile \"%1\"...", p_profile_name)); if (check()) start_extract(); else request_finish(false); } void Audex::cancel() { request_finish(false); } const QStringList& Audex::extractProtocol() { return cdda_extract_thread->protocol(); } const QStringList& Audex::encoderProtocol() { return encoder_wrapper->protocol(); } void Audex::start_extract() { if (_finished) return; if (p_single_file) { if (ex_track_count >= 1) { if (!jobs->jobInProgress() && !jobs->pendingJobs()) request_finish(true); return; } ex_track_index++; QString artist = cdda_model->artist(); QString title = cdda_model->title(); QString year = cdda_model->year(); QString genre = cdda_model->genre(); QString suffix = p_suffix; QString basepath = Preferences::basePath(); int cdnum; if (!cdda_model->isMultiCD()) cdnum = 0; else cdnum = cdda_model->cdNum(); int nooftracks = cdda_model->numOfAudioTracks(); bool overwrite = Preferences::overwriteExistingFiles(); QString targetFilename; if (!construct_target_filename_for_singlefile(targetFilename, cdnum, nooftracks, artist, title, year, genre, suffix, basepath, overwrite)) { request_finish(false); return; } ex_track_target_filename = targetFilename; cdda_model->setCustomData("filename", targetFilename); //if empty (maybe because it already exists) skip if (!targetFilename.isEmpty()) { emit changedExtractTrack(ex_track_index, 1, artist, title); QString sourceFilename = tmp_path+QString("%1").arg(DiscIDCalculator::FreeDBId(cdda_model->discSignature()))+".wav"; ex_track_source_filename = sourceFilename; wave_file_writer->open(sourceFilename); if (Preferences::paranoiaMode()) { cdda_extract_thread->setParanoiaMode(3); } else { cdda_extract_thread->setParanoiaMode(0); } cdda_extract_thread->setNeverSkip(Preferences::neverSkip()); cdda_extract_thread->setTrackToRip(0); cdda_extract_thread->start(); process_counter++; ex_track_count++; } else { if (!jobs->jobInProgress() && !jobs->pendingJobs()) request_finish(true); } } else { if (ex_track_count >= cdda_model->numOfAudioTracksInSelection()) { if (!jobs->jobInProgress() && !jobs->pendingJobs()) request_finish(true); return; } ex_track_index++; bool skip = !cdda_model->isTrackInSelection(ex_track_index); if (!cdda_model->isAudioTrack(ex_track_index)) skip = true; if (!skip) { QString artist = cdda_model->artist(); QString title = cdda_model->title(); QString tartist = cdda_model->data(cdda_model->index(ex_track_index-1, CDDA_MODEL_COLUMN_ARTIST_INDEX)).toString(); QString ttitle = cdda_model->data(cdda_model->index(ex_track_index-1, CDDA_MODEL_COLUMN_TITLE_INDEX)).toString(); QString year = cdda_model->year(); QString genre = cdda_model->genre(); QString suffix = p_suffix; QString basepath = Preferences::basePath(); bool fat32_compatible = profile_model->data(profile_model->index(profile_model->currentProfileRow(), PROFILE_MODEL_COLUMN_FAT32COMPATIBLE_INDEX)).toBool(); bool replacespaceswithunderscores = profile_model->data(profile_model->index(profile_model->currentProfileRow(), PROFILE_MODEL_COLUMN_UNDERSCORE_INDEX)).toBool(); bool _2digitstracknum = profile_model->data(profile_model->index(profile_model->currentProfileRow(), PROFILE_MODEL_COLUMN_2DIGITSTRACKNUM_INDEX)).toBool(); int cdnum; if (!cdda_model->isMultiCD()) cdnum = 0; else cdnum = cdda_model->cdNum(); int trackoffset = cdda_model->trackOffset(); int nooftracks = cdda_model->numOfAudioTracks(); bool overwrite = Preferences::overwriteExistingFiles(); QString targetFilename; if (cdda_model->isVarious()) { if (!construct_target_filename(targetFilename, ex_track_index, cdnum, nooftracks, trackoffset, artist, title, tartist, ttitle, year, genre, suffix, basepath, fat32_compatible, replacespaceswithunderscores, _2digitstracknum, overwrite, (ex_track_index==1))) { request_finish(false); return; } } else { if (!construct_target_filename(targetFilename, ex_track_index, cdnum, nooftracks, trackoffset, artist, title, artist, ttitle, year, genre, suffix, basepath, fat32_compatible, replacespaceswithunderscores, _2digitstracknum, overwrite, (ex_track_index==1))) { request_finish(false); return; } } ex_track_target_filename = targetFilename; //if empty (maybe because it already exists) skip if (!targetFilename.isEmpty()) { emit changedExtractTrack(ex_track_index, cdda_model->numOfAudioTracks(), tartist, ttitle); - QString sourceFilename = tmp_path+QString("%1").arg(DiscIDCalculator::FreeDBId(cdda_model->discSignature()))+"."+QString("%1").arg(ex_track_index)+".wav"; + QString sourceFilename = tmp_path+QString("%1").arg(DiscIDCalculator::FreeDBId(cdda_model->discSignature()))+'.'+QString("%1").arg(ex_track_index)+".wav"; ex_track_source_filename = sourceFilename; wave_file_writer->open(sourceFilename); if (Preferences::paranoiaMode()) { cdda_extract_thread->setParanoiaMode(3); } else { cdda_extract_thread->setParanoiaMode(0); } cdda_extract_thread->setNeverSkip(Preferences::neverSkip()); cdda_extract_thread->setTrackToRip(ex_track_index); cdda_extract_thread->start(); process_counter++; ex_track_count++; } else { en_track_count++; ex_track_count++; //important to check for finish cdda_extract_thread->skipTrack(ex_track_index); start_extract(); } } else { start_extract(); } } } void Audex::finish_extract() { process_counter--; wave_file_writer->close(); if (_finished) { QFile file(ex_track_source_filename); file.remove(); if (!process_counter) execute_finish(); return; } jobs->addNewJob(ex_track_source_filename, ex_track_target_filename, ex_track_index); start_extract(); } void Audex::start_encode() { if (_finished) return; if (p_single_file) { if (en_track_count >= 1) { request_finish(true); return; } if (encoder_wrapper->isProcessing()) return; AudexJob* job = jobs->orderJob(); if (!job) return; int cdnum = cdda_model->cdNum(); int nooftracks = cdda_model->numOfAudioTracks(); QString artist = cdda_model->artist(); QString title = cdda_model->title(); QString year = cdda_model->year(); QString genre = cdda_model->genre(); QString suffix = p_suffix; CachedImage *cover = cdda_model->cover(); QString targetFilename = job->targetFilename(); en_track_target_filename = targetFilename; emit changedEncodeTrack(job->trackNo(), 1, targetFilename); en_track_count++; en_track_filename = job->sourceFilename(); en_track_index = job->trackNo(); if (!encoder_wrapper->encode(job->trackNo(), cdnum, 0, nooftracks, artist, title, artist, title, genre, year, suffix, cover, false, tmp_path, job->sourceFilename(), targetFilename)) { request_finish(false); } process_counter++; } else { if (en_track_count >= cdda_model->numOfAudioTracksInSelection()) { request_finish(true); return; } if (encoder_wrapper->isProcessing()) return; AudexJob* job = jobs->orderJob(); if (!job) return; int cdnum = cdda_model->cdNum(); int trackoffset = cdda_model->trackOffset(); int nooftracks = cdda_model->numOfAudioTracks(); QString artist = cdda_model->artist(); QString title = cdda_model->title(); QString tartist = cdda_model->data(cdda_model->index(job->trackNo()-1, CDDA_MODEL_COLUMN_ARTIST_INDEX)).toString(); QString ttitle = cdda_model->data(cdda_model->index(job->trackNo()-1, CDDA_MODEL_COLUMN_TITLE_INDEX)).toString(); QString year = cdda_model->year(); QString genre = cdda_model->genre(); QString suffix = p_suffix; CachedImage *cover = cdda_model->cover(); bool fat32_compatible = profile_model->data(profile_model->index(profile_model->currentProfileRow(), PROFILE_MODEL_COLUMN_FAT32COMPATIBLE_INDEX)).toBool(); QString targetFilename = job->targetFilename(); en_track_target_filename = targetFilename; emit changedEncodeTrack(job->trackNo(), cdda_model->numOfAudioTracks(), targetFilename); en_track_count++; en_track_filename = job->sourceFilename(); en_track_index = job->trackNo(); if (cdda_model->isVarious()) { if (!encoder_wrapper->encode(job->trackNo(), cdnum, trackoffset, nooftracks, artist, title, tartist, ttitle, genre, year, suffix, cover, fat32_compatible, tmp_path, job->sourceFilename(), targetFilename)) { request_finish(false); } } else { if (!encoder_wrapper->encode(job->trackNo(), cdnum, trackoffset, nooftracks, artist, title, artist, ttitle, genre, year, suffix, cover, fat32_compatible, tmp_path, job->sourceFilename(), targetFilename)) { request_finish(false); } } process_counter++; } } void Audex::finish_encode() { process_counter--; jobs->reportJobFinished(); cdda_model->setCustomDataPerTrack(en_track_index, "filename", en_track_target_filename); cdda_model->setCustomDataPerTrack(en_track_index, "ripped", true); QFile file(en_track_filename); file.remove(); if (_finished) { if (!process_counter) execute_finish(); return; } emit changedEncodeTrack(0, 0, ""); progress_encode(0); start_encode(); } void Audex::calculate_speed_extract() { if ((last_measuring_point_sector > -1) && (cdda_extract_thread->isProcessing())) { double new_value = (double)(current_sector-last_measuring_point_sector)/(2.0f*75.0f); if (new_value < 0.0f) new_value = 0.0f; if ((new_value < 0.2f) && (!timeout_done)) { timeout_counter += 2; if (timeout_counter >= 300) { timeout_done = true; emit timeout(); } } emit speedExtract(new_value); } else { emit speedExtract(0.0f); } last_measuring_point_sector = current_sector; } void Audex::calculate_speed_encode() { if ((last_measuring_point_encoder_percent > -1) && (encoder_wrapper->isProcessing()) && (current_encoder_percent > 0)) { int song_length = cdda_model->data(cdda_model->index(en_track_index-1, CDDA_MODEL_COLUMN_LENGTH_INDEX), CDDA_MODEL_INTERNAL_ROLE).toInt(); double new_value = (double)((double)song_length/100.0f)*((double)current_encoder_percent-(double)last_measuring_point_encoder_percent); if (new_value < 0.0f) new_value = 0.0f; emit speedEncode(new_value); } else { emit speedEncode(0.0f); } last_measuring_point_encoder_percent = current_encoder_percent; } void Audex::progress_extract(int percent_of_track, int sector, int overall_sectors_read) { if (overall_frames==0) { QSet sel = cdda_model->selectedTracks(); QSet::ConstIterator it(sel.begin()), end(sel.end()); for (; it!=end; ++it) { if ((*it < 0) || (*it > cdda_extract_thread->cddaParanoia()->numOfTracks()) || (!cdda_extract_thread->cddaParanoia()->isAudioTrack((*it)))) { continue; } overall_frames += cdda_extract_thread->cddaParanoia()->numOfFramesOfTrack((*it)); } } float fraction = 0.0f; if (overall_frames > 0) fraction = (float)overall_sectors_read / (float)overall_frames; emit progressExtractTrack(percent_of_track); emit progressExtractOverall((int)(fraction*100.0f)); current_sector = sector; } void Audex::progress_encode(int percent) { emit progressEncodeTrack(percent); if (percent > 0) { emit progressEncodeOverall( ((en_track_count>0 ? ((en_track_count-1)*100.0f) : 0) + (percent*1.0f)) / (float)cdda_model->numOfAudioTracksInSelection() ); } current_encoder_percent = percent; } void Audex::write_to_wave(const QByteArray& data) { wave_file_writer->write(data); } void Audex::slot_error(const QString& description, const QString& solution) { emit error(description, solution); request_finish(false); } void Audex::slot_warning(const QString& description) { emit warning(description); } void Audex::slot_info(const QString& description) { emit info(description); } void Audex::check_if_thread_still_running() { if (cdda_extract_thread->isRunning()) { //this could happen if the thread is stuck in paranoia_read //because of an unreadable cd cdda_extract_thread->terminate(); qDebug() << "Terminate extracting thread."; } } bool Audex::construct_target_filename(QString& targetFilename, int trackno, int cdno, int nooftracks, int gindex, const QString& artist, const QString& title, const QString& tartist, const QString& ttitle, const QString& year, const QString& genre, const QString& ext, const QString& basepath, bool fat_compatible, bool replacespaceswithunderscores, bool _2digitstracknum, bool overwrite_existing_files, bool is_first_track) { Q_UNUSED(is_first_track); PatternParser patternparser; targetFilename = ((basepath.right(1)=="/")?basepath:basepath+"/")+patternparser.parseFilenamePattern(profile_model->data(profile_model->index(profile_model->currentProfileRow(), PROFILE_MODEL_COLUMN_PATTERN_INDEX)).toString(), trackno, cdno, gindex, nooftracks, artist, title, tartist, ttitle, year, genre, ext, fat_compatible, replacespaceswithunderscores, _2digitstracknum); int lastSlash = targetFilename.lastIndexOf("/", -1); if (lastSlash == -1) { emit error(i18n("Can't find path \"%1\".", targetFilename), i18n("Please check your path (write access?)")); return false; } QString targetPath = targetFilename.mid(0, lastSlash); QString targetStrippedFilename = targetFilename.mid(lastSlash+1); target_dir = targetPath; if (!p_mkdir(targetPath)) return false; KDiskFreeSpaceInfo diskfreespace = KDiskFreeSpaceInfo::freeSpaceInfo(targetPath); quint64 free = diskfreespace.available() / 1024; if (free < 200*1024) { emit warning(i18n("Free space on \"%1\" is less than 200 MiB.", targetPath)); } QFile *file = new QFile(targetFilename); if (file->exists()) { if (overwrite_existing_files) { emit warning(i18n("Warning! File \"%1\" already exists. Overwriting.", targetStrippedFilename)); } else { emit warning(i18n("Warning! File \"%1\" already exists. Skipping.", targetStrippedFilename)); cdda_model->setCustomDataPerTrack(trackno, "filename", targetFilename); cdda_model->setCustomDataPerTrack(trackno, "ripped", true); targetFilename.clear(); } } delete file; return true; } bool Audex::construct_target_filename_for_singlefile(QString& targetFilename, int cdno, int nooftracks, const QString& artist, const QString& title, const QString& date, const QString& genre, const QString& ext, const QString& basepath, bool overwrite_existing_files) { PatternParser patternparser; targetFilename = ((basepath.right(1)=="/")?basepath:basepath+"/")+patternparser.parseSimplePattern(profile_model->data(profile_model->index(profile_model->currentProfileRow(), PROFILE_MODEL_COLUMN_SF_NAME_INDEX)).toString(), cdno, nooftracks, artist, title, date, genre, ext, false); int lastSlash = targetFilename.lastIndexOf("/", -1); if (lastSlash == -1) { emit error(i18n("Can't find path \"%1\".", targetFilename), i18n("Please check your path (write access?)")); return false; } QString targetPath = targetFilename.mid(0, lastSlash); target_dir = targetPath; QString targetStrippedFilename = targetFilename.mid(lastSlash+1); QDir *dir = new QDir(targetPath); if (!dir->exists()) { if (!dir->mkpath(targetPath)) { emit error(i18n("Unable to create folder \"%1\".", targetPath), i18n("Please check your path (write access?)")); return false; } else { emit info(i18n("Folder \"%1\" successfully created.", targetPath)); } } else { emit warning(i18n("Folder \"%1\" already exists.", targetPath)); } delete dir; KDiskFreeSpaceInfo diskfreespace = KDiskFreeSpaceInfo::freeSpaceInfo(targetPath); quint64 free = diskfreespace.available() / 1024; if (free < 800*1024) { emit warning(i18n("Free space on \"%1\" is less than 800 MiB.", targetPath)); } QFile *file = new QFile(targetFilename); if (file->exists()) { if (overwrite_existing_files) { emit warning(i18n("Warning! File \"%1\" already exists. Overwriting.", targetStrippedFilename)); } else { emit warning(i18n("Warning! File \"%1\" already exists. Skipping.", targetStrippedFilename)); cdda_model->setCustomData("filename", targetFilename); targetFilename.clear(); } } delete file; return true; } bool Audex::check() { if (tmp_dir->error()) { slot_error(i18n("Temporary folder \"%1\" error.", tmp_dir->tmpPath()), i18n("Please check.")); return false; } quint64 free = tmp_dir->freeSpace() / 1024; if (free < 800*1024) { slot_warning(i18n("Free space on temporary folder \"%1\" is less than 800 MiB.", tmp_dir->tmpPathBase())); } else if (free < 200*1024) { slot_error(i18n("Temporary folder \"%1\" needs at least 200 MiB of free space.", tmp_dir->tmpPathBase()), i18n("Please free space or set another path.")); return false; } return true; } void Audex::request_finish(bool successful) { if (!_finished) { _finished = true; _finished_successful = successful; } else { return; } if (process_counter > 0) { encoder_wrapper->cancel(); cdda_extract_thread->cancel(); QTimer::singleShot(2000, this, SLOT(check_if_thread_still_running())); } else { execute_finish(); } } void Audex::execute_finish() { if (Preferences::ejectCDTray()) { emit info(i18n("Eject CD tray")); cdda_model->eject(); } bool overwrite = Preferences::overwriteExistingFiles(); QStringList target_filename_list; for (int i = 0; i < cdda_model->rowCount(); ++i) { if (!cdda_model->isAudioTrack(i+1)) continue; if (!cdda_model->isTrackInSelection(i+1)) continue; if (!cdda_model->getCustomDataPerTrack(i+1, "ripped").toBool()) continue; target_filename_list.append(cdda_model->getCustomDataPerTrack(i+1, "filename").toString()); } QString target_single_filename; if (p_single_file) { target_single_filename = cdda_model->customData("filename").toString(); } QString co; if ((_finished_successful) && (profile_model->data(profile_model->index(profile_model->currentProfileRow(), PROFILE_MODEL_COLUMN_SC_INDEX)).toBool())) { //store the cover if (!cdda_model->isCoverEmpty()) { QImage image(cdda_model->coverImage()); if (profile_model->data(profile_model->index(profile_model->currentProfileRow(), PROFILE_MODEL_COLUMN_SC_SCALE_INDEX)).toBool()) { QSize size = profile_model->data(profile_model->index(profile_model->currentProfileRow(), PROFILE_MODEL_COLUMN_SC_SIZE_INDEX)).toSize(); image = image.scaled(size, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation); qDebug() << QString("Cover scaled to %1x%2.").arg(size.width()).arg(size.height()); } QString pattern = profile_model->data(profile_model->index(profile_model->currentProfileRow(), PROFILE_MODEL_COLUMN_SC_NAME_INDEX)).toString(); QString format = profile_model->data(profile_model->index(profile_model->currentProfileRow(), PROFILE_MODEL_COLUMN_SC_FORMAT_INDEX)).toString(); PatternParser patternparser; QString filename = patternparser.parseSimplePattern(pattern, cdda_model->cdNum(), cdda_model->numOfAudioTracks(), cdda_model->artist(), cdda_model->title(), QString("%1").arg(cdda_model->year()), cdda_model->genre(), format.toLower(), profile_model->data(profile_model->index(profile_model->currentProfileRow(), PROFILE_MODEL_COLUMN_FAT32COMPATIBLE_INDEX)).toBool()); if (p_prepare_dir(filename, target_dir, overwrite)) { if (image.save(filename, format.toAscii().data())) { emit info(i18n("Cover \"%1\" successfully saved.", QFileInfo(filename).fileName())); co = filename; } else { emit error(i18n("Unable to save cover \"%1\".", QFileInfo(filename).fileName()), i18n("Please check your path and permissions")); } } } } QString pl; if ((_finished_successful) && (profile_model->data(profile_model->index(profile_model->currentProfileRow(), PROFILE_MODEL_COLUMN_PL_INDEX)).toBool()) && (target_filename_list.count() > 0) && (!p_single_file)) { //create the playlist Playlist playlist; QString pattern = profile_model->data(profile_model->index(profile_model->currentProfileRow(), PROFILE_MODEL_COLUMN_PL_NAME_INDEX)).toString(); QString format = profile_model->data(profile_model->index(profile_model->currentProfileRow(), PROFILE_MODEL_COLUMN_PL_FORMAT_INDEX)).toString(); bool is_absFilePath = profile_model->data(profile_model->index(profile_model->currentProfileRow(), PROFILE_MODEL_COLUMN_PL_ABS_FILE_PATH_INDEX)).toBool(); bool is_utf8 = profile_model->data(profile_model->index(profile_model->currentProfileRow(), PROFILE_MODEL_COLUMN_PL_UTF8_INDEX)).toBool(); PatternParser patternparser; QString filename = patternparser.parseSimplePattern(pattern, cdda_model->cdNum(), cdda_model->numOfAudioTracks(), cdda_model->artist(), cdda_model->title(), QString("%1").arg(cdda_model->year()), cdda_model->genre(), format.toLower(), profile_model->data(profile_model->index(profile_model->currentProfileRow(), PROFILE_MODEL_COLUMN_FAT32COMPATIBLE_INDEX)).toBool()); if (p_prepare_dir(filename, target_dir, (overwrite && !cdda_model->isMultiCD() && (cdda_model->cdNum() < 1)))) { QFile file(filename); if (file.exists() && cdda_model->isMultiCD() && (cdda_model->cdNum() > 0)) { if (file.open(QFile::ReadOnly)) { QByteArray ba = file.readAll(); playlist.addPlaylist(ba); file.close(); } } if (file.open(QFile::WriteOnly | QFile::Truncate)) { for (int i = 0; i < cdda_model->rowCount(); ++i) { if (!cdda_model->isAudioTrack(i+1)) continue; if (!cdda_model->isTrackInSelection(i+1)) continue; if (!cdda_model->getCustomDataPerTrack(i+1, "ripped").toBool()) continue; PlaylistItem item; item.setFilename(cdda_model->getCustomDataPerTrack(i+1, "filename").toString()); item.setArtist(cdda_model->data(cdda_model->index(i, CDDA_MODEL_COLUMN_ARTIST_INDEX)).toString()); item.setTitle(cdda_model->data(cdda_model->index(i, CDDA_MODEL_COLUMN_TITLE_INDEX)).toString()); item.setLength(cdda_model->lengthOfTrack(i+1)); playlist.appendItem(item); } QString relFilePath; if (!is_absFilePath) { relFilePath = QFileInfo(filename).absoluteDir().absolutePath(); } if (format == "M3U") { file.write(playlist.toM3U(relFilePath, is_utf8)); } else if (format == "PLS") { file.write(playlist.toPLS(relFilePath, is_utf8)); } else if (format == "XSPF") { file.write(playlist.toXSPF()); } file.close(); emit info(i18n("Playlist \"%1\" successfully created.", QFileInfo(filename).fileName())); pl = filename; } else { emit error(i18n("Unable to save playlist \"%1\".", QFileInfo(filename).fileName()), i18n("Please check your path and permissions")); } } } QString in; if ((_finished_successful) && (profile_model->data(profile_model->index(profile_model->currentProfileRow(), PROFILE_MODEL_COLUMN_INF_INDEX)).toBool())) { PatternParser patternparser; QString filename = patternparser.parseSimplePattern(profile_model->data(profile_model->index(profile_model->currentProfileRow(), PROFILE_MODEL_COLUMN_INF_NAME_INDEX)).toString(), cdda_model->cdNum(), cdda_model->numOfAudioTracks(), cdda_model->artist(), cdda_model->title(), QString("%1").arg(cdda_model->year()), cdda_model->genre(), profile_model->data(profile_model->index(profile_model->currentProfileRow(), PROFILE_MODEL_COLUMN_INF_SUFFIX_INDEX)).toString(), profile_model->data(profile_model->index(profile_model->currentProfileRow(), PROFILE_MODEL_COLUMN_FAT32COMPATIBLE_INDEX)).toBool()); if (p_prepare_dir(filename, target_dir, overwrite)) { QFile file(filename); if (file.open(QFile::WriteOnly | QFile::Truncate)) { QTextStream out(&file); QStringList text = profile_model->data(profile_model->index(profile_model->currentProfileRow(), PROFILE_MODEL_COLUMN_INF_TEXT_INDEX)).toStringList(); patternparser.parseInfoText(text, cdda_model->artist(), cdda_model->title(), QString("%1").arg(cdda_model->year()), cdda_model->genre(), DiscIDCalculator::FreeDBId(cdda_model->discSignature()), p_size_of_all_files(target_filename_list), cdda_model->lengthOfAudioTracksInSelection(), cdda_model->numOfAudioTracksInSelection()); out << text.join("\n"); file.close(); emit info(i18n("Info file \"%1\" successfully created.", QFileInfo(filename).fileName())); in = filename; } else { emit error(i18n("Unable to save info file \"%1\".", QFileInfo(filename).fileName()), i18n("Please check your path and permissions")); } } } QString hl; if ((_finished_successful) && (profile_model->data(profile_model->index(profile_model->currentProfileRow(), PROFILE_MODEL_COLUMN_HL_INDEX)).toBool()) && (target_filename_list.count() > 0)) { QString pattern = profile_model->data(profile_model->index(profile_model->currentProfileRow(), PROFILE_MODEL_COLUMN_HL_NAME_INDEX)).toString(); QString format = profile_model->data(profile_model->index(profile_model->currentProfileRow(), PROFILE_MODEL_COLUMN_HL_FORMAT_INDEX)).toString(); PatternParser patternparser; QString filename = patternparser.parseSimplePattern(pattern, cdda_model->cdNum(), cdda_model->numOfAudioTracks(), cdda_model->artist(), cdda_model->title(), QString("%1").arg(cdda_model->year()), cdda_model->genre(), format.toLower(), profile_model->data(profile_model->index(profile_model->currentProfileRow(), PROFILE_MODEL_COLUMN_FAT32COMPATIBLE_INDEX)).toBool()); if (p_prepare_dir(filename, target_dir, (overwrite && !cdda_model->isMultiCD() && (cdda_model->cdNum() < 1)))) { QFile file(filename); bool fexists = file.exists() && cdda_model->isMultiCD() && (cdda_model->cdNum() > 0); bool success; if (fexists) success = file.open(QFile::WriteOnly | QFile::Append); else success = file.open(QFile::WriteOnly | QFile::Truncate); if (success) { QTextStream out(&file); if (fexists) out << "\n"; Hashlist hashlist; if (format == "SFV") { out << hashlist.getSFV(target_filename_list).join("\n"); } else if (format == "MD5") { out << hashlist.getMD5(target_filename_list).join("\n"); } file.close(); emit info(i18n("Hashlist \"%1\" successfully created.", QFileInfo(filename).fileName())); hl = filename; } else { emit error(i18n("Unable to save hashlist \"%1\".", QFileInfo(filename).fileName()), i18n("Please check your path and permissions")); } } } QString cs; if ( (_finished_successful) && (profile_model->data(profile_model->index(profile_model->currentProfileRow(), PROFILE_MODEL_COLUMN_CUE_INDEX)).toBool()) && (((target_filename_list.count() > 0) && !p_single_file) || p_single_file) ) { QString pattern = profile_model->data(profile_model->index(profile_model->currentProfileRow(), PROFILE_MODEL_COLUMN_CUE_NAME_INDEX)).toString(); PatternParser patternparser; QString filename = patternparser.parseSimplePattern(pattern, cdda_model->cdNum(), cdda_model->numOfAudioTracks(), cdda_model->artist(), cdda_model->title(), QString("%1").arg(cdda_model->year()), cdda_model->genre(), "cue", profile_model->data(profile_model->index(profile_model->currentProfileRow(), PROFILE_MODEL_COLUMN_FAT32COMPATIBLE_INDEX)).toBool()); if (p_prepare_dir(filename, target_dir, overwrite)) { QFile file(filename); bool success = file.open(QFile::WriteOnly | QFile::Truncate); if (success) { QTextStream out(&file); CueSheetWriter cuesheetwriter(cdda_model); if (p_single_file) { out << cuesheetwriter.cueSheet(target_single_filename).join("\n"); } else { out << cuesheetwriter.cueSheet(target_filename_list).join("\n"); } file.close(); emit info(i18n("Cue sheet \"%1\" successfully created.", QFileInfo(filename).fileName())); cs = filename; } else { emit error(i18n("Unable to save cue sheet \"%1\".", QFileInfo(filename).fileName()), i18n("Please check your path and permissions")); } } } if ((_finished_successful) && (Preferences::upload()) && (target_filename_list.count() > 0)) { QString targetpath = QFileInfo(target_filename_list.at(0)).absolutePath().mid(Preferences::basePath().length()); QStringList files_to_transfer = target_filename_list; if (!co.isEmpty()) files_to_transfer << co; if (!pl.isEmpty()) files_to_transfer << pl; if (!in.isEmpty()) files_to_transfer << in; if (!hl.isEmpty()) files_to_transfer << hl; if (!cs.isEmpty()) files_to_transfer << cs; Upload upload(Preferences::url(), this); connect(&upload, SIGNAL(info(const QString&)), this, SLOT(slot_info(const QString&))); connect(&upload, SIGNAL(error(const QString&, const QString&)), this, SLOT(slot_error(const QString&, const QString&))); upload.upload(targetpath, files_to_transfer); } //flush temporary path if (!tmp_path.isEmpty()) { QDir tmp(tmp_path); QStringList files = tmp.entryList(QStringList() << "*", QDir::Files | QDir::NoDotAndDotDot); for (int i = 0; i < files.count(); ++i) { QFile::remove(tmp_path+files[i]); qDebug() << "Deleted temporary file" << tmp_path+files[i]; } } emit finished(_finished_successful); } bool Audex::p_prepare_dir(QString& filename, const QString& targetDirIfRelative, const bool overwrite) { QString result; QFileInfo fileinfo(filename); if (fileinfo.isAbsolute()) { if (!p_mkdir(fileinfo.dir().absolutePath())) { return false; } else { result = filename; } } else { if (!targetDirIfRelative.isEmpty()) { QDir dir(targetDirIfRelative); if (!dir.isReadable()) { emit error(i18n("Unable to open folder \"%1\".", targetDirIfRelative), i18n("Please check your path and permissions")); return false; } - result = targetDirIfRelative+"/"+filename; + result = targetDirIfRelative+'/'+filename; } else { result = filename; } } if (!overwrite) { QFileInfo info(result); if (info.exists()) { emit warning(i18n("Warning! File \"%1\" already exists. Skipping.", info.fileName())); return false; } } filename = result; return true; } bool Audex::p_mkdir(const QString& absoluteFilePath) { QDir dir(absoluteFilePath); if (dir.exists()) { if (!dir.isReadable()) { emit error(i18n("Unable to open folder \"%1\".", absoluteFilePath), i18n("Please check your path and permissions")); return false; } } else { if (!dir.mkpath(absoluteFilePath)) { emit error(i18n("Unable to create folder \"%1\".", absoluteFilePath), i18n("Please check your path (write access?)")); return false; } else { emit info(i18n("Folder \"%1\" successfully created.", absoluteFilePath)); } } return true; } qreal Audex::p_size_of_all_files(const QStringList& filenames) const { qreal size = .0f; for (int i = 0; i < filenames.count(); ++i) { QFileInfo info(filenames.at(i)); size += info.size(); } return size; } diff --git a/dialogs/cddaheaderdatadialog.cpp b/dialogs/cddaheaderdatadialog.cpp index 3914651..9cbaa7b 100644 --- a/dialogs/cddaheaderdatadialog.cpp +++ b/dialogs/cddaheaderdatadialog.cpp @@ -1,168 +1,168 @@ /* AUDEX CDDA EXTRACTOR * Copyright (C) 2007-2015 Marco Nelles (audex@maniatek.com) * * * This program 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. * * This program 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 this program. If not, see . */ #include "cddaheaderdatadialog.h" #include #include #define GENRE_MAX 148 static const char *ID3_GENRES[GENRE_MAX] = { "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies", "Other", "Pop", "R&B", "Rap", "Reggae", "Rock", "Techno", "Industrial", "Alternative", "Ska", "Death Metal", "Pranks", "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal", "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental", "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise", "Alt", "Bass", "Soul", "Punk", "Space", "Meditative", "Instrumental Pop", "Instrumental Rock", "Ethnic", "Gothic", "Darkwave", "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream", "Southern Rock", "Comedy", "Cult", "Gangsta Rap", "Top 40", "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret", "New Wave", "Psychedelic", "Rave", "Showtunes", "Trailer", "Lo-Fi", "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical", "Rock & Roll", "Hard Rock", "Folk", "Folk/Rock", "National Folk", "Swing", "Fast-Fusion", "Bebob", "Latin", "Revival", "Celtic", "Bluegrass", "Avantgarde", "Gothic Rock", "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band", "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson", "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus", "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba", "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle", "Duet", "Punk Rock", "Drum Solo", "A Cappella", "Euro-House", "Dance Hall", "Goa", "Drum & Bass", "Club-House", "Hardcore", "Terror", "Indie", "BritPop", "Negerpunk", "Polsk Punk", "Beat", "Christian Gangsta Rap", "Heavy Metal", "Black Metal", "Crossover", "Contemporary Christian", "Christian Rock", "Merengue", "Salsa", "Thrash Metal", "Anime", "JPop", "Synthpop" }; CDDAHeaderDataDialog::CDDAHeaderDataDialog(CDDAModel *cddaModel, QWidget *parent) : QDialog(parent) { Q_UNUSED(parent); cdda_model = cddaModel; if (!cdda_model) { qDebug() << "CDDAModel is NULL!"; return; } setWindowTitle(i18n("Edit Data")); QVBoxLayout *mainLayout = new QVBoxLayout; setLayout(mainLayout); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Apply|QDialogButtonBox::Cancel); okButton = buttonBox->button(QDialogButtonBox::Ok); applyButton = buttonBox->button(QDialogButtonBox::Apply); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); connect(buttonBox, &QDialogButtonBox::accepted, this, &CDDAHeaderDataDialog::slotAccepted); connect(buttonBox, &QDialogButtonBox::rejected, this, &CDDAHeaderDataDialog::reject); connect(applyButton, &QPushButton::clicked, this, &CDDAHeaderDataDialog::slotApplied); QWidget *widget = new QWidget(this); mainLayout->addWidget(widget); mainLayout->addWidget(buttonBox); ui.setupUi(widget); QStringList genres; for (int i = 0; i < GENRE_MAX; ++i) genres.append(QString().fromAscii(ID3_GENRES[i])); genres.sort(); KCompletion *comp = ui.kcombobox_genre->completionObject(); comp->insertItems(genres); ui.kcombobox_genre->addItems(genres); connect(ui.kcombobox_genre, SIGNAL(returnPressed(const QString&)), comp, SLOT(addItem(const QString&))); ui.checkBox_various->setChecked(cdda_model->isVarious()); connect(ui.checkBox_various, SIGNAL(toggled(bool)), this, SLOT(trigger_changed())); ui.checkBox_multicd->setChecked(cdda_model->isMultiCD()); connect(ui.checkBox_multicd, SIGNAL(toggled(bool)), this, SLOT(enable_checkbox_multicd(bool))); connect(ui.checkBox_multicd, SIGNAL(toggled(bool)), this, SLOT(trigger_changed())); ui.qlineedit_artist->setText(cdda_model->artist()); connect(ui.qlineedit_artist, SIGNAL(textEdited(const QString&)), this, SLOT(trigger_changed())); ui.qlineedit_title->setText(cdda_model->title()); connect(ui.qlineedit_title, SIGNAL(textEdited(const QString&)), this, SLOT(trigger_changed())); ui.kintspinbox_cdnum->setValue(cdda_model->cdNum()); connect(ui.kintspinbox_cdnum, SIGNAL(valueChanged(int)), this, SLOT(trigger_changed())); ui.kintspinbox_trackoffset->setValue(cdda_model->trackOffset()); connect(ui.kintspinbox_trackoffset, SIGNAL(valueChanged(int)), this, SLOT(trigger_changed())); ui.kcombobox_genre->lineEdit()->setText(cdda_model->genre()); connect(ui.kcombobox_genre->lineEdit(), SIGNAL(textEdited(const QString&)), this, SLOT(trigger_changed())); { bool ok; int year = cdda_model->year().toInt(&ok); if (ok) ui.kintspinbox_year->setValue(year); else ui.kintspinbox_year->setValue(QDate::currentDate().year()); } connect(ui.kintspinbox_year, SIGNAL(valueChanged(int)), this, SLOT(trigger_changed())); ui.ktextedit_extdata->setText(cdda_model->extendedData().join("\n")); connect(ui.ktextedit_extdata, SIGNAL(textChanged()), this, SLOT(trigger_changed())); ui.qlineedit_freedbdiscid->setText(QString("0x%1").arg(DiscIDCalculator::FreeDBId(cdda_model->discSignature()), 0, 16)); enable_checkbox_multicd(cdda_model->isMultiCD()); applyButton->setEnabled(false); } CDDAHeaderDataDialog::~CDDAHeaderDataDialog() { } void CDDAHeaderDataDialog::slotAccepted() { save(); accept(); } void CDDAHeaderDataDialog::slotApplied() { save(); } void CDDAHeaderDataDialog::save() { cdda_model->setVarious(ui.checkBox_various->isChecked()); cdda_model->setMultiCD(ui.checkBox_multicd->isChecked()); cdda_model->setArtist(ui.qlineedit_artist->text()); cdda_model->setTitle(ui.qlineedit_title->text()); cdda_model->setCDNum(ui.kintspinbox_cdnum->value()); cdda_model->setTrackOffset(ui.kintspinbox_trackoffset->value()); cdda_model->setGenre(ui.kcombobox_genre->lineEdit()->text()); cdda_model->setYear(QString("%1").arg(ui.kintspinbox_year->value())); - cdda_model->setExtendedData(ui.ktextedit_extdata->toPlainText().split("\n")); + cdda_model->setExtendedData(ui.ktextedit_extdata->toPlainText().split('\n')); applyButton->setEnabled(false); } void CDDAHeaderDataDialog::trigger_changed() { if (ui.checkBox_various->isChecked() != cdda_model->isVarious()) { applyButton->setEnabled(true); return; } if (ui.checkBox_multicd->isChecked() != cdda_model->isMultiCD()) { applyButton->setEnabled(true); return; } if (ui.qlineedit_artist->text() != cdda_model->artist()) { applyButton->setEnabled(true); return; } if (ui.qlineedit_title->text() != cdda_model->title()) { applyButton->setEnabled(true); return; } if (ui.checkBox_various->isChecked()) if (ui.kintspinbox_cdnum->value() != cdda_model->cdNum()) { applyButton->setEnabled(true); return; } if (ui.kintspinbox_trackoffset->value() != cdda_model->trackOffset()) { applyButton->setEnabled(true); return; } if (ui.kcombobox_genre->lineEdit()->text() != cdda_model->genre()) { applyButton->setEnabled(true); return; } if (ui.kintspinbox_year->value() != cdda_model->year().toInt()) { applyButton->setEnabled(true); return; } - if (ui.ktextedit_extdata->toPlainText().split("\n") != cdda_model->extendedData()) { applyButton->setEnabled(true); return; } + if (ui.ktextedit_extdata->toPlainText().split('\n') != cdda_model->extendedData()) { applyButton->setEnabled(true); return; } applyButton->setEnabled(false); } void CDDAHeaderDataDialog::enable_checkbox_multicd(bool enabled) { ui.kintspinbox_cdnum->setEnabled(enabled); ui.label_cdnum->setEnabled(enabled); } diff --git a/dialogs/commandwizarddialog.cpp b/dialogs/commandwizarddialog.cpp index 3ca2956..a0ef318 100644 --- a/dialogs/commandwizarddialog.cpp +++ b/dialogs/commandwizarddialog.cpp @@ -1,244 +1,244 @@ /* AUDEX CDDA EXTRACTOR * Copyright (C) 2007-2015 Marco Nelles (audex@maniatek.com) * * * This program 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. * * This program 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 this program. If not, see . */ #include "commandwizarddialog.h" #include #include CommandWizardDialog::CommandWizardDialog(const QString& command, QWidget *parent) : QDialog(parent) { Q_UNUSED(parent); setWindowTitle(i18n("Command Pattern Wizard")); QVBoxLayout *mainLayout = new QVBoxLayout; setLayout(mainLayout); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel|QDialogButtonBox::Apply); okButton = buttonBox->button(QDialogButtonBox::Ok); applyButton = buttonBox->button(QDialogButtonBox::Apply); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); connect(buttonBox, &QDialogButtonBox::accepted, this, &CommandWizardDialog::slotAccepted); connect(buttonBox, &QDialogButtonBox::rejected, this, &CommandWizardDialog::reject); connect(applyButton, &QPushButton::clicked, this, &CommandWizardDialog::slotApplied); QWidget *widget = new QWidget(this); mainLayout->addWidget(widget); mainLayout->addWidget(buttonBox); ui.setupUi(widget); ui.qlineedit_command->setText(command); connect(ui.qlineedit_command, SIGNAL(textEdited(const QString&)), this, SLOT(trigger_changed())); connect(ui.qlineedit_command, SIGNAL(textChanged(const QString&)), this, SLOT(update_example())); ui.qlineedit_command->setCursorPosition(0); connect(ui.kurllabel_aboutcommandlineschemes, SIGNAL(leftClickedUrl()), this, SLOT(about_commandline_schemes())); connect(ui.kurllabel_aboutparameters, SIGNAL(leftClickedUrl()), this, SLOT(about_parameters())); connect(ui.kpushbutton_albumartist, SIGNAL(clicked()), this, SLOT(insAlbumArtist())); connect(ui.kpushbutton_albumtitle, SIGNAL(clicked()), this, SLOT(insAlbumTitle())); connect(ui.kpushbutton_trackartist, SIGNAL(clicked()), this, SLOT(insTrackArtist())); connect(ui.kpushbutton_tracktitle, SIGNAL(clicked()), this, SLOT(insTrackTitle())); connect(ui.kpushbutton_trackno, SIGNAL(clicked()), this, SLOT(insTrackNo())); connect(ui.kpushbutton_cdno, SIGNAL(clicked()), this, SLOT(insCDNo())); connect(ui.kpushbutton_date, SIGNAL(clicked()), this, SLOT(insDate())); connect(ui.kpushbutton_genre, SIGNAL(clicked()), this, SLOT(insGenre())); connect(ui.kpushbutton_cover_file, SIGNAL(clicked()), this, SLOT(insCoverFile())); connect(ui.kpushbutton_nooftracks, SIGNAL(clicked()), this, SLOT(insNoOfTracks())); connect(ui.kpushbutton_input_file, SIGNAL(clicked()), this, SLOT(insInFile())); connect(ui.kpushbutton_output_file, SIGNAL(clicked()), this, SLOT(insOutFile())); this->command = command; applyButton->setEnabled(false); update_example(); } CommandWizardDialog::~CommandWizardDialog() { } void CommandWizardDialog::slotAccepted() { save(); accept(); } void CommandWizardDialog::slotApplied() { save(); } void CommandWizardDialog::trigger_changed() { if (ui.qlineedit_command->text() != command) { applyButton->setEnabled(true); return; } applyButton->setEnabled(false); } void CommandWizardDialog::about_commandline_schemes() { QWhatsThis::showText(ui.kurllabel_aboutcommandlineschemes->mapToGlobal(ui.kurllabel_aboutcommandlineschemes->geometry().topLeft()), i18n("

The following variables will be replaced with their particular meaning in every track name.

" "

" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "
VariableDescription
$artistThe artist of the CD. If your CD is a compilation, then this tag represents the title in most cases.
$titleThe title of the CD. If your CD is a compilation, then this tag represents the subtitle in most cases.
$dateThe release date of the CD. In almost all cases this is the year.
$genreThe genre of the CD.
$cdnoThe CD number of a multi-CD album. Often compilations consist of several CDs. Note: If the multi-CD flag is not set for the current CD, than this value will be just empty.
$tartistThis is the artist of every individual track. It is especially useful on compilation CDs.
$ttitleThe track title. Normally each track on a CD has its own title, which is the name of the song.
$tracknoThe track number. First track is 1.
$coverThe cover file.
$nooftracksThe total number of audio tracks of the CD.
$iThe temporary WAV file (input file) created by Audex from CD audio track. You can use it as a normal input file for your command line encoder.
$oThe full output filename and path (output file). Use it as the output for your command line encoder.
$encoderEncoder name and version.
$audexAudex name and version.

"), ui.kurllabel_aboutcommandlineschemes); } void CommandWizardDialog::about_parameters() { QWhatsThis::showText(ui.kurllabel_aboutparameters->mapToGlobal(ui.kurllabel_aboutparameters->geometry().topLeft()), i18n("

Variables in Audex can have parameters. E.g.

" "
${cover format=\"JPG\" x=\"300\" y=\"300\" preparam=\"-ti \"}
" "

A filename of a JPG image with the size of 300x300 will be inserted. " "If no size is set, the size of the original cover file will be taken. If " "no cover is set, this variable will be replaced by nothing, otherwise " "something like /tmp/cover.123.jpg will be inserted. Possible " "formats are \"JPG\", \"PNG\" and \"GIF\" (Default: \"JPG\").

\n" "

Note: LAME discards cover files larger than 128 KiB. Please " "bear this in mind, if you set the format and size.

" "
" "

\"preparam\" and \"postparam\" define parameters inserted before " "(pre) or behind (post) the variable. These values are only shown if a value is set." "Works with all commandline variables.

" "
" "

To have a complete overview of parameters go to the Audex webpage.

" ), ui.kurllabel_aboutparameters); } void CommandWizardDialog::insAlbumArtist() { QString text = ui.qlineedit_command->text(); - text.insert(ui.qlineedit_command->cursorPosition(), "$"+QString(VAR_ALBUM_ARTIST)); + text.insert(ui.qlineedit_command->cursorPosition(), '$'+QString(VAR_ALBUM_ARTIST)); ui.qlineedit_command->setText(text); update_example(); } void CommandWizardDialog::insAlbumTitle() { QString text = ui.qlineedit_command->text(); - text.insert(ui.qlineedit_command->cursorPosition(), "$"+QString(VAR_ALBUM_TITLE)); + text.insert(ui.qlineedit_command->cursorPosition(), '$'+QString(VAR_ALBUM_TITLE)); ui.qlineedit_command->setText(text); update_example(); } void CommandWizardDialog::insTrackArtist() { QString text = ui.qlineedit_command->text(); - text.insert(ui.qlineedit_command->cursorPosition(), "$"+QString(VAR_TRACK_ARTIST)); + text.insert(ui.qlineedit_command->cursorPosition(), '$'+QString(VAR_TRACK_ARTIST)); ui.qlineedit_command->setText(text); update_example(); } void CommandWizardDialog::insTrackTitle() { QString text = ui.qlineedit_command->text(); - text.insert(ui.qlineedit_command->cursorPosition(), "$"+QString(VAR_TRACK_TITLE)); + text.insert(ui.qlineedit_command->cursorPosition(), '$'+QString(VAR_TRACK_TITLE)); ui.qlineedit_command->setText(text); update_example(); } void CommandWizardDialog::insTrackNo() { QString text = ui.qlineedit_command->text(); - text.insert(ui.qlineedit_command->cursorPosition(), "$"+QString(VAR_TRACK_NO)); + text.insert(ui.qlineedit_command->cursorPosition(), '$'+QString(VAR_TRACK_NO)); ui.qlineedit_command->setText(text); update_example(); } void CommandWizardDialog::insCDNo() { QString text = ui.qlineedit_command->text(); - text.insert(ui.qlineedit_command->cursorPosition(), "$"+QString(VAR_CD_NO)); + text.insert(ui.qlineedit_command->cursorPosition(), '$'+QString(VAR_CD_NO)); ui.qlineedit_command->setText(text); update_example(); } void CommandWizardDialog::insDate() { QString text = ui.qlineedit_command->text(); - text.insert(ui.qlineedit_command->cursorPosition(), "$"+QString(VAR_DATE)); + text.insert(ui.qlineedit_command->cursorPosition(), '$'+QString(VAR_DATE)); ui.qlineedit_command->setText(text); update_example(); } void CommandWizardDialog::insGenre() { QString text = ui.qlineedit_command->text(); - text.insert(ui.qlineedit_command->cursorPosition(), "$"+QString(VAR_GENRE)); + text.insert(ui.qlineedit_command->cursorPosition(), '$'+QString(VAR_GENRE)); ui.qlineedit_command->setText(text); update_example(); } void CommandWizardDialog::insCoverFile() { QString text = ui.qlineedit_command->text(); - text.insert(ui.qlineedit_command->cursorPosition(), "$"+QString(VAR_COVER_FILE)); + text.insert(ui.qlineedit_command->cursorPosition(), '$'+QString(VAR_COVER_FILE)); ui.qlineedit_command->setText(text); update_example(); } void CommandWizardDialog::insNoOfTracks() { QString text = ui.qlineedit_command->text(); text.insert(ui.qlineedit_command->cursorPosition(), QString("$" VAR_NO_OF_TRACKS)); ui.qlineedit_command->setText(text); update_example(); } void CommandWizardDialog::insInFile() { QString text = ui.qlineedit_command->text(); - text.insert(ui.qlineedit_command->cursorPosition(), "$"+QString(VAR_INPUT_FILE)); + text.insert(ui.qlineedit_command->cursorPosition(), '$'+QString(VAR_INPUT_FILE)); ui.qlineedit_command->setText(text); update_example(); } void CommandWizardDialog::insOutFile() { QString text = ui.qlineedit_command->text(); - text.insert(ui.qlineedit_command->cursorPosition(), "$"+QString(VAR_OUTPUT_FILE)); + text.insert(ui.qlineedit_command->cursorPosition(), '$'+QString(VAR_OUTPUT_FILE)); ui.qlineedit_command->setText(text); update_example(); } bool CommandWizardDialog::save() { command = ui.qlineedit_command->text(); applyButton->setEnabled(false); return true; } void CommandWizardDialog::update_example() { PatternParser patternparser; QString filename = patternparser.parseCommandPattern(ui.qlineedit_command->text(), "/tmp/tmp.wav", QString("%1/music/Meat Loaf/02 - Meat Loaf - Blind As A Bat.ogg").arg(QDir::homePath()), 2, 1, 1, 12, "Meat Loaf", "Bat Out Of Hell III", "Meat Loaf", "Blind As A Bat", "2006", "Rock", "ogg", NULL, false, QDir::tempPath(), "LAME 3.98.2", true); ui.qlineedit_album_example->setText(filename); ui.qlineedit_album_example->setCursorPosition(0); filename = patternparser.parseCommandPattern(ui.qlineedit_command->text(), "/tmp/tmp.wav", QString("%1/music/Alternative Hits/Volume 4/04 - Wolfsheim - Approaching Lightspeed.ogg").arg(QDir::homePath()), 4, 2, 1, 18, "Alternative Hits", "Volume 4", "Wolfsheim", "Approaching Lightspeed", "2003", "Darkwave", "ogg", NULL, false, QDir::tempPath(), "LAME 3.98.2", true); ui.qlineedit_sampler_example->setText(filename); ui.qlineedit_sampler_example->setCursorPosition(0); } diff --git a/dialogs/profiledatainfodialog.cpp b/dialogs/profiledatainfodialog.cpp index 063df6a..e35d02c 100644 --- a/dialogs/profiledatainfodialog.cpp +++ b/dialogs/profiledatainfodialog.cpp @@ -1,268 +1,268 @@ /* AUDEX CDDA EXTRACTOR * Copyright (C) 2007-2015 Marco Nelles (audex@maniatek.com) * * * This program 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. * * This program 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 this program. If not, see . */ #include "profiledatainfodialog.h" #include #include #include ProfileDataInfoDialog::ProfileDataInfoDialog(const QStringList& text, const QString& pattern, const QString& suffix, QWidget *parent) : QDialog(parent) { Q_UNUSED(parent); this->text = text; this->pattern = pattern; this->suffix = suffix; setWindowTitle(i18n("Info Settings")); QVBoxLayout *mainLayout = new QVBoxLayout; setLayout(mainLayout); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel|QDialogButtonBox::Apply); QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); applyButton = buttonBox->button(QDialogButtonBox::Apply); connect(buttonBox, &QDialogButtonBox::accepted, this, &ProfileDataInfoDialog::slotAccepted); connect(buttonBox, &QDialogButtonBox::rejected, this, &ProfileDataInfoDialog::reject); connect(applyButton, &QPushButton::clicked, this, &ProfileDataInfoDialog::slotApplied); QWidget *widget = new QWidget(this); mainLayout->addWidget(widget); mainLayout->addWidget(buttonBox); ui.setupUi(widget); connect(ui.kpushbutton_pattern, SIGNAL(clicked()), this, SLOT(pattern_wizard())); ui.kpushbutton_pattern->setIcon(QIcon::fromTheme("tools-wizard")); ui.ktextedit_text->setPlainText(text.join("\n")); connect(ui.ktextedit_text, SIGNAL(textChanged()), this, SLOT(trigger_changed())); ui.qlineedit_pattern->setText(pattern); connect(ui.qlineedit_pattern, SIGNAL(textEdited(const QString&)), this, SLOT(trigger_changed())); ui.qlineedit_suffix->setText(suffix); connect(ui.qlineedit_suffix, SIGNAL(textEdited(const QString&)), this, SLOT(trigger_changed())); ui.kpushbutton_load->setIcon(QIcon::fromTheme("document-open")); ui.kpushbutton_save->setIcon(QIcon::fromTheme("document-save")); connect(ui.kurllabel_aboutvariables, SIGNAL(leftClickedUrl()), this, SLOT(about_variables())); connect(ui.kpushbutton_load, SIGNAL(clicked()), this, SLOT(load_text())); connect(ui.kpushbutton_save, SIGNAL(clicked()), this, SLOT(save_text())); applyButton->setEnabled(false); } ProfileDataInfoDialog::~ProfileDataInfoDialog() { } void ProfileDataInfoDialog::slotAccepted() { save(); accept(); } void ProfileDataInfoDialog::slotApplied() { save(); } void ProfileDataInfoDialog::pattern_wizard() { SimplePatternWizardDialog *dialog = new SimplePatternWizardDialog(ui.qlineedit_pattern->text(), suffix, this); if (dialog->exec() != QDialog::Accepted) { delete dialog; return; } ui.qlineedit_pattern->setText(dialog->pattern); delete dialog; trigger_changed(); } void ProfileDataInfoDialog::trigger_changed() { - if (ui.ktextedit_text->toPlainText().split("\n") != text) { applyButton->setEnabled(true); return; } + if (ui.ktextedit_text->toPlainText().split('\n') != text) { applyButton->setEnabled(true); return; } if (ui.qlineedit_suffix->text() != suffix) { applyButton->setEnabled(true); return; } if (ui.qlineedit_pattern->text() != pattern) { applyButton->setEnabled(true); return; } applyButton->setEnabled(false); } void ProfileDataInfoDialog::about_variables() { QDialog *dialog = new QDialog(this); dialog->resize(QSize(700, 480)); dialog->setWindowTitle(i18n("Usable Variables For Text Template")); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok); QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); dialog->connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); dialog->connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); QTextBrowser *tb = new QTextBrowser(dialog); tb->setHtml(i18n("" "" "" "" "" "" "Variables will be replaced by a special value and can even contain parameters.
" "For example the variable " "
"
      "$artist"
      "
" "or the equivalent" "
"
      "${artist}"
      "
" "will be replaced by the relevant artist of the cd. Variables may also have attribute, for example:" "
"
      "${today format=\"yyyy-MM-dd\"}"
      "
" "This would print the current date. Setting the format will control how this is done. The example (above)" "would result int the date being printed as 2010-10-07 (if this was the current date). See below for more details.

" "You can make use of the following variables:
" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "
VariableParameterDescriptionExample
$artistPrints the relevant artist of the extracted cd.${artist }
$titlePrints the relevant title of the extracted cd.
$datePrints the relevant date (usually release year) of the extracted cd.
$genre;Prints the relevant genre of the extracted cd.
$sizeiec,precisionPrints the overall size of all extracted (compressed) music files (incl. the cover). The attribute iec can be one of the following: b, k, m, g. b means byte, k KiB, m MiB and g GiB. The attribute precision gives the number of decimal places. Default attributes are iec=\"m\" and precision=\"2\"${size iec=\"k\" precision=\"2\"}
$lengthPrints the relevant overall length of all extracted tracks. The format is min:sec.
$nooftracksPrints the total number of extracted tracks.
$discidbasePrints the discid of the current cd. The attribute base is the base of the number. The default is 16 (hexadecimal).${discid base=\"16\"}
$todayformatPrints the current date. The attribute format specifies the output (*).${today format=\"yyyy-MM-dddd\"}
$nowformatPrints the current date and/or time. The attribute format specifies the output (*).${now format=\"yyyy-MM-dddd hh:mm:ss\"}
$encoderPrints encoder name and version.
$audexPrints Audex name and version.
$brPrints a linebreak.
" "

" "(* date/time format expressions)" "" "" "" "" "" "" "" "" "" "" "" "" "
ExpressionOutput
dThe day as a number without a leading zero (1 to 31).
ddThe day as a number with a leading zero (01 to 31).
dddThe abbreviated localized day name (e.g. 'Mon' to 'Sun').
ddddThe long localized day name (e.g. 'Monday' to 'Sunday').
MThe month as a number without a leading zero (1 to 12).
MMThe month as a number with a leading zero (01 to 12).
MMMThe abbreviated localized month name (e.g. 'Jan' to 'Dec').
MMMMThe long localized month name (e.g. 'January' to 'December').
yyThe year as two digit number (00 to 99).
yyyyThe year as four digit number.
" "
" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "
ExpressionOutput
hThe hour without a leading zero (0 to 23 or 1 to 12 if AM/PM display).
hhThe hour with a leading zero (00 to 23 or 01 to 12 if AM/PM display).
HThe hour without a leading zero (0 to 23, even with AM/PM display).
HHThe hour with a leading zero (00 to 23, even with AM/PM display).
mThe minute without a leading zero (0 to 59).
mmThe minute with a leading zero (00 to 59).
sThe second without a leading zero (0 to 59).
ssThe second with a leading zero (00 to 59).
zThe milliseconds without leading zeroes (0 to 999).
zzThe milliseconds with leading zeroes (000 to 999).
AP or AInterpret as an AM/PM time. AP must be either 'AM' or 'PM'.
ap or aInterpret as an AM/PM time. ap must be either 'am' or 'pm'.
" "" "" )); mainLayout->addWidget(tb); mainLayout->addWidget(buttonBox); connect(dialog, SIGNAL(clicked()), dialog, SLOT(close())); dialog->exec(); delete dialog; } void ProfileDataInfoDialog::load_text() { QString filename = QFileDialog::getOpenFileName(this, i18n("Load Text Template"), QDir::homePath(), "*"); if (!filename.isEmpty()) { QFile file(filename); if (file.open(QFile::ReadOnly)) { QTextStream in(&file); ui.ktextedit_text->setPlainText(in.readAll()); file.close(); } } } void ProfileDataInfoDialog::save_text() { QString filename = QFileDialog::getSaveFileName(this, i18n("Save Text Template"), QDir::homePath(), "*"); if (!filename.isEmpty()) { QFile file(filename); if (file.open(QFile::WriteOnly | QFile::Truncate)) { QTextStream out(&file); out << ui.ktextedit_text->toPlainText(); file.close(); } } } bool ProfileDataInfoDialog::save() { - text = ui.ktextedit_text->toPlainText().split("\n"); + text = ui.ktextedit_text->toPlainText().split('\n'); suffix = ui.qlineedit_suffix->text(); pattern = ui.qlineedit_pattern->text(); applyButton->setEnabled(false); return true; } diff --git a/models/cddamodel.cpp b/models/cddamodel.cpp index 25463f9..62fc955 100644 --- a/models/cddamodel.cpp +++ b/models/cddamodel.cpp @@ -1,907 +1,907 @@ /* AUDEX CDDA EXTRACTOR * Copyright (C) 2007-2015 Marco Nelles (audex@maniatek.com) * * * This program 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. * * This program 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 this program. If not, see . */ #include "cddamodel.h" CDDAModel::CDDAModel(QObject *parent) : QAbstractTableModel(parent) { pn = 0; _device.clear(); _udi.clear(); devices = new CDDADevices(this); if (!devices) { qDebug() << "Unable to create devices object. low mem?"; error = Error(i18n("Unable to create devices object."), i18n("This is an internal error. Check your hardware. If all okay please make bug report."), Error::ERROR, this); return; } connect(devices, SIGNAL(audioDiscDetected(const QString&)), this, SLOT(new_audio_disc_available(const QString&))); connect(devices, SIGNAL(audioDiscRemoved(const QString&)), this, SLOT(audio_disc_removed(const QString&))); cddb = new KCDDB::Client(); if (!cddb) { qDebug() << "Unable to create KCDDB object. Low mem?"; error = Error(i18n("Unable to create KCDDB object."), i18n("This is an internal error. Check your hardware. If all okay please make bug report."), Error::ERROR, this); return; } connect(cddb, SIGNAL(finished(KCDDB::Result)), this, SLOT(lookup_cddb_done(KCDDB::Result))); cddb_transaction_pending = false; _cover = new CachedImage(); cd_info.clear(); modified = false; _empty = true; QTimer::singleShot(200, devices, SLOT(scanBus())); } CDDAModel::~CDDAModel() { delete _cover; delete cddb; delete devices; if (pn) delete pn; } int CDDAModel::rowCount(const QModelIndex &parent) const { if (!pn) return 0; return parent.isValid()?0:pn->numOfTracks(); } int CDDAModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent); return CDDA_MODEL_COLUMN_COUNT; } QVariant CDDAModel::data(const QModelIndex &index, int role) const { if (!pn) { return QVariant(); } if (!index.isValid()) { return QVariant(); } if ((index.row() < 0) || (index.row() >= numOfTracks())) { return QVariant(); } if (role == Qt::TextAlignmentRole) { return int(Qt::AlignLeft | Qt::AlignVCenter); } /*if (role == Qt::ForegroundRole) { switch (index.column()) { case CDDA_MODEL_COLUMN_ARTIST_INDEX : if (!isTrackArtistValid(index.row()+1)) return qVariantFromValue(QColor(Qt::gray)); break; case CDDA_MODEL_COLUMN_TITLE_INDEX : if (!isTrackTitleValid(index.row()+1)) return qVariantFromValue(QColor(Qt::gray)); break; } }*/ if ((role == Qt::DisplayRole) || (role == Qt::CheckStateRole && index.column()==CDDA_MODEL_COLUMN_RIP_INDEX) || (role == CDDA_MODEL_INTERNAL_ROLE) || (role == Qt::EditRole)) { switch (index.column()) { case CDDA_MODEL_COLUMN_RIP_INDEX : if (role == Qt::CheckStateRole) { return isTrackInSelection(index.row()+1)?Qt::Checked:Qt::Unchecked; } break; case CDDA_MODEL_COLUMN_TRACK_INDEX : return index.row()+1+(trackOffset()>1?trackOffset():0); case CDDA_MODEL_COLUMN_LENGTH_INDEX : if (role==CDDA_MODEL_INTERNAL_ROLE) return lengthOfTrack(index.row()+1); else return QString("%1:%2").arg(lengthOfTrack(index.row()+1) / 60, 2, 10, QChar('0')).arg(lengthOfTrack(index.row()+1) % 60, 2, 10, QChar('0')); case CDDA_MODEL_COLUMN_ARTIST_INDEX : if (isAudioTrack(index.row()+1)) { QString a = cd_info.track(index.row()).get(KCDDB::Artist).toString(); return a; } break; case CDDA_MODEL_COLUMN_TITLE_INDEX : if (isAudioTrack(index.row()+1)) { QString t = cd_info.track(index.row()).get(KCDDB::Title).toString(); if (t.isEmpty()) return i18n("Track %1", index.row()+1); return t; } break; default : ; } } return QVariant(); } bool CDDAModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (!pn) { return false; } if (!index.isValid()) { return false; } if ((index.row() < 0) || (index.row() >= numOfTracks())) { return false; } if (role == Qt::EditRole) { bool changed = false; switch (index.column()) { case CDDA_MODEL_COLUMN_ARTIST_INDEX : if (value != cd_info.track(index.row()).get(KCDDB::Artist)) { cd_info.track(index.row()).set(KCDDB::Artist, value); changed = true; } break; case CDDA_MODEL_COLUMN_TITLE_INDEX : if (value != cd_info.track(index.row()).get(KCDDB::Title)) { cd_info.track(index.row()).set(KCDDB::Title, value); changed = true; } break; default : return false; } if (changed) { emit dataChanged(index, index); modify(); } return changed; } return false; } QVariant CDDAModel::headerData(int section, Qt::Orientation orientation, int role) const { Q_UNUSED(orientation); if (orientation == Qt::Horizontal) { switch (role) { case Qt::DisplayRole : switch (section) { case CDDA_MODEL_COLUMN_RIP_INDEX : return CDDA_MODEL_COLUMN_RIP_LABEL; case CDDA_MODEL_COLUMN_TRACK_INDEX : return CDDA_MODEL_COLUMN_TRACK_LABEL; case CDDA_MODEL_COLUMN_LENGTH_INDEX : return CDDA_MODEL_COLUMN_LENGTH_LABEL; case CDDA_MODEL_COLUMN_ARTIST_INDEX : return CDDA_MODEL_COLUMN_ARTIST_LABEL; case CDDA_MODEL_COLUMN_TITLE_INDEX : return CDDA_MODEL_COLUMN_TITLE_LABEL; default : ; } break; case Qt::TextAlignmentRole : return Qt::AlignLeft; default : ; } } else if (orientation == Qt::Vertical) { if (role == Qt::DisplayRole) { return QVariant(section+1); } } return QVariant(); } Qt::ItemFlags CDDAModel::flags(const QModelIndex &index) const { Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable; if ((index.column()==CDDA_MODEL_COLUMN_ARTIST_INDEX) || (index.column()==CDDA_MODEL_COLUMN_TITLE_INDEX)) { flags |= Qt::ItemIsEditable; } if (!isAudioTrack(index.row()+1)) return Qt::ItemIsEnabled; return flags; } void CDDAModel::setArtist(const QString& a) { if (!pn) return; if (a != cd_info.get(KCDDB::Artist).toString()) { cd_info.set(KCDDB::Artist, a); modify(); reset(); } } const QString CDDAModel::artist() const { if (!pn) return QString(); QString a = cd_info.get(KCDDB::Artist).toString(); return a; } void CDDAModel::setTitle(const QString& t) { if (!pn) return; if (t != cd_info.get(KCDDB::Title).toString()) { cd_info.set(KCDDB::Title, t); modify(); reset(); } } const QString CDDAModel::title() const { if (!pn) return QString(); QString t = cd_info.get(KCDDB::Title).toString(); return t; } void CDDAModel::setCategory(const QString& c) { if (!pn) return; QStringList validCategories; validCategories << "blues" << "classical" << "country" << "data" << "folk" << "jazz" << "misc" << "newage" << "reggae" << "rock" << "soundtrack"; if (!validCategories.contains(c)) return; if (c != cd_info.get(KCDDB::Category).toString()) { cd_info.set(KCDDB::Category, c); modify(); reset(); } } const QString CDDAModel::category() const { if (!pn) return QString(); return cd_info.get(KCDDB::Category).toString(); } void CDDAModel::setGenre(const QString& g) { if (!pn) return; if (g != cd_info.get(KCDDB::Genre).toString()) { cd_info.set(KCDDB::Genre, g); modify(); reset(); } } const QString CDDAModel::genre() const { if (!pn) return QString(); return cd_info.get(KCDDB::Genre).toString(); } void CDDAModel::setYear(const QString& year) { if (!pn) return; if (year != cd_info.get(KCDDB::Year).toString()) { cd_info.set(KCDDB::Year, year); modify(); reset(); } } const QString CDDAModel::year() const { if (!pn) return QString(); return cd_info.get(KCDDB::Year).toString(); } void CDDAModel::setExtendedData(const QStringList& e) { if (!pn) return; if (e != cd_info.get(KCDDB::Comment).toStringList()) { cd_info.set(KCDDB::Comment, e); modify(); reset(); } } const QStringList CDDAModel::extendedData() const { if (!pn) return QStringList(); return cd_info.get(KCDDB::Comment).toStringList(); } void CDDAModel::setCDNum(const int n) { if (!pn) return; if (n != cd_info.get("DNO").toInt()) { cd_info.set("DNO", n); modify(); reset(); } } int CDDAModel::cdNum() const { if (!pn) return -1; if (!isMultiCD()) return 0; return cd_info.get("DNO").toInt(); } void CDDAModel::setTrackOffset(const int n) { if (!pn) return; if (n != cd_info.get("DTRACKOFFSET").toInt()) { cd_info.set("DTRACKOFFSET", n); modify(); reset(); } } int CDDAModel::trackOffset() const { if (!pn) return -1; return cd_info.get("DTRACKOFFSET").toInt(); } int CDDAModel::guessMultiCD(QString& newTitle) const { if (!pn) return -1; QString t = cd_info.get(KCDDB::Title).toString(); QRegExp rx1("[\\(|\\[]* *([c|C][d|D]|[d|D][i|I][s|S][k|c|K|C]) *[0-9]* *[\\)|\\]]* *$"); int i = rx1.indexIn(t); if (i>=0) { QString frac = t.mid(i); QRegExp rx2("(\\d+)"); rx2.indexIn(frac); bool ok; int cdnum = rx2.cap(0).toInt(&ok); if (ok) { if (cdnum<0) return -1; if (cdnum==0) cdnum = 1; newTitle = t.left(i).trimmed(); return cdnum; } } return -1; } void CDDAModel::setMultiCD(const bool multi) { if (!pn) return; if (multi != cd_info.get("DMULTICD").toBool()) { cd_info.set("DMULTICD", multi); modify(); reset(); } } bool CDDAModel::isMultiCD() const { if (!pn) return false; return cd_info.get("DMULTICD").toBool(); } void CDDAModel::setCustomData(const QString& type, const QVariant& data) { if (!pn) return; if (data != cd_info.get(type)) { cd_info.set(type, data); modify(); reset(); } } const QVariant CDDAModel::customData(const QString& type) const { if (!pn) return QVariant(); return cd_info.get(type); } void CDDAModel::setCustomDataPerTrack(const int n, const QString& type, const QVariant& data) { if (!pn) return; if (data != cd_info.track(n).get(type)) { cd_info.track(n).set(type, data); modify(); reset(); } } const QVariant CDDAModel::getCustomDataPerTrack(const int n, const QString& type) { if (!pn) return QVariant(); return cd_info.track(n).get(type); } CachedImage* CDDAModel::cover() const { return _cover; } const QImage CDDAModel::coverImage() const { return _cover->coverImage(); } quint16 CDDAModel::coverChecksum() const { return _cover->checksum(); } bool CDDAModel::setCover(const QByteArray& data) { if (_cover->load(data)) { reset(); return true; } else { error = _cover->lastError(); } return false; } bool CDDAModel::setCover(const QString& filename) { if (_cover->load(filename)) { reset(); return true; } else { error = _cover->lastError(); } return false; } bool CDDAModel::saveCoverToFile(const QString& filename) { if (_cover->save(filename)) { return true; } else { error = _cover->lastError(); } return false; } bool CDDAModel::isCoverEmpty() const { return _cover->isEmpty(); } void CDDAModel::clearCover() { if (_cover->isEmpty()) return; _cover->clear(); reset(); } const QString CDDAModel::coverSupportedMimeTypeList() const { return _cover->supportedMimeTypeList(); } bool CDDAModel::guessVarious() const { if (!pn) return false; QString a; for (int i = 0; i < cd_info.numberOfTracks(); ++i) { if ((i > 0) && (cd_info.track(i).get(KCDDB::Artist).toString().toLower() != a.toLower())) return true; a = cd_info.track(i).get(KCDDB::Artist).toString(); } return false; } void CDDAModel::setVarious(bool various) { if (!pn) return; if (various != cd_info.get("DVARIOUS").toBool()) { cd_info.set("DVARIOUS", various); modify(); } } bool CDDAModel::isVarious() { if (!pn) return false; return cd_info.get("DVARIOUS").toBool(); } void CDDAModel::swapArtistAndTitleOfTracks() { if (!pn) return; for (int i = 0; i < cd_info.numberOfTracks(); ++i) { QVariant tmp = cd_info.track(i).get(KCDDB::Artist); cd_info.track(i).set(KCDDB::Artist, cd_info.track(i).get(KCDDB::Title)); cd_info.track(i).set(KCDDB::Title, tmp); } modified = true; emit cddbDataModified(); reset(); } void CDDAModel::swapArtistAndTitle() { if (!pn) return; QVariant tmp = cd_info.get(KCDDB::Title); cd_info.set(KCDDB::Title, cd_info.get(KCDDB::Artist)); cd_info.set(KCDDB::Artist, tmp); modified = true; emit cddbDataModified(); reset(); } void CDDAModel::splitTitleOfTracks(const QString& divider) { if (!pn) return; for (int i = 0; i < cd_info.numberOfTracks(); ++i) { int splitPos = cd_info.track(i).get(KCDDB::Title).toString().indexOf(divider); if (splitPos >= 0) { // split QString title = cd_info.track(i).get(KCDDB::Title).toString().mid(splitPos+divider.length()); QString artist = cd_info.track(i).get(KCDDB::Title).toString().left(splitPos); cd_info.track(i).set(KCDDB::Artist, artist); cd_info.track(i).set(KCDDB::Title, title); } } modified = true; emit cddbDataModified(); reset(); } void CDDAModel::capitalizeTracks() { if (!pn) return; for (int i = 0; i < cd_info.numberOfTracks(); ++i) { cd_info.track(i).set(KCDDB::Artist, capitalize(cd_info.track(i).get(KCDDB::Artist).toString())); cd_info.track(i).set(KCDDB::Title, capitalize(cd_info.track(i).get(KCDDB::Title).toString())); } modified = true; emit cddbDataModified(); reset(); } void CDDAModel::capitalizeHeader() { if (!pn) return; cd_info.set(KCDDB::Artist, capitalize(cd_info.get(KCDDB::Artist).toString())); cd_info.set(KCDDB::Title, capitalize(cd_info.get(KCDDB::Title).toString())); modified = true; emit cddbDataModified(); reset(); } void CDDAModel::setTitleArtistsFromHeader() { if (!pn) return; for (int i = 0; i < cd_info.numberOfTracks(); ++i) { cd_info.track(i).set(KCDDB::Artist, cd_info.get(KCDDB::Artist)); } modified = true; emit cddbDataModified(); reset(); } int CDDAModel::numOfTracks() const { if (!pn) return 0; return pn->numOfTracks(); } int CDDAModel::numOfAudioTracks() const { int c = 0; for (int i = 1; i <= numOfTracks(); ++i) { if (isAudioTrack(i)) ++c; } return c; } int CDDAModel::numOfAudioTracksInSelection() const { return sel_tracks.count(); } int CDDAModel::length() const { if (!pn) return 0; return pn->length(); } int CDDAModel::lengthOfAudioTracks() const { int c = 0; for (int i = 1; i <= numOfTracks(); ++i) { if (isAudioTrack(i)) c += lengthOfTrack(i); } return c; } int CDDAModel::lengthOfAudioTracksInSelection() const { QSet::ConstIterator it(sel_tracks.begin()), end(sel_tracks.end()); int l = 0; for (; it != end; ++it) { if (isAudioTrack(*it)) l += lengthOfTrack(*it); } return l; } int CDDAModel::lengthOfTrack(int n) const { if (!pn) return 0; return pn->lengthOfTrack(n); } const QList CDDAModel::discSignature() const { if (!pn) return QList(); return pn->discSignature(); } bool CDDAModel::isAudioTrack(int n) const { if (!pn) return false; return pn->isAudioTrack(n); } void CDDAModel::clear() { cd_info.clear(); clearCover(); reset(); } void CDDAModel::toggle(int row) { _toggle(row+1); emit hasSelection(0 != sel_tracks.count()); emit selectionChanged(sel_tracks.count()); } bool CDDAModel::isTrackInSelection(int n) const { return sel_tracks.contains(n); } void CDDAModel::invertSelection() { for (int i = 1; i <= numOfTracks(); ++i) { if (isAudioTrack(i)) _toggle(i); } emit hasSelection(0 != sel_tracks.count()); emit selectionChanged(sel_tracks.count()); } void CDDAModel::selectAll() { sel_tracks.clear(); invertSelection(); } void CDDAModel::selectNone() { sel_tracks.clear(); emit hasSelection(false); emit selectionChanged(0); } bool CDDAModel::isModified() const { return modified; } void CDDAModel::confirm() { modified = false; } Error CDDAModel::lastError() const { return error; } void CDDAModel::lookupCDDB() { if (!pn) return; qDebug() << "lookupCDDB called"; if (cddb_transaction_pending) { qDebug() << "CDDB transaction already in progress."; return; } cddb_transaction_pending = true; emit cddbLookupStarted(); cddb->config().reparse(); cddb->setBlockingMode(false); cddb->lookup(pn->discSignature()); } bool CDDAModel::submitCDDB() { if (!pn) return true; qDebug() << "submitCDDB called"; if (cddb_transaction_pending) { qDebug() << "CDDB transaction already in progress."; error = Error(i18n("CDDB transaction already in progress."), i18n("A CDDB transaction is already in progress. Please wait until it has finished and try again."), Error::ERROR, this); return false; } cddb_transaction_pending = true; cddb->config().reparse(); cddb->setBlockingMode(true); if (category().isEmpty()) { setCategory("rock"); } KCDDB::Result result = cddb->submit(cd_info, pn->discSignature()); if (result != KCDDB::Success) { switch (result) { case KCDDB::ServerError : error = Error(KCDDB::resultToString(result), i18n("There is an error with the CDDB server. Please wait or contact the administrator of the CDDB server."), Error::ERROR, this); break; case KCDDB::HostNotFound : error = Error(KCDDB::resultToString(result), i18n("Cannot find the CDDB server. Check your network. Maybe the CDDB server is offline."), Error::ERROR, this); break; case KCDDB::NoResponse : error = Error(KCDDB::resultToString(result), i18n("Please wait, maybe the server is busy, or contact the CDDB server administrator."), Error::ERROR, this); break; case KCDDB::CannotSave : error = Error(KCDDB::resultToString(result), i18n("Please contact the CDDB server administrator."), Error::ERROR, this); break; case KCDDB::InvalidCategory : error = Error(KCDDB::resultToString(result), i18n("This should not happen. Please make a bug report."), Error::ERROR, this); break; case KCDDB::UnknownError : ; case KCDDB::NoRecordFound : ; case KCDDB::MultipleRecordFound : ; case KCDDB::Success : ; default : error = Error(KCDDB::resultToString(result), i18n("Please make a bug report and contact the CDDB server administrator."), Error::ERROR, this); break; } return false; } error = Error(); confirm(); cddb_transaction_pending = false; emit cddbDataSubmited(true); return true; } void CDDAModel::eject() { devices->eject(_udi); } void CDDAModel::new_audio_disc_available(const QString& udi) { if (pn) return; _device = devices->blockDevice(udi); _udi = udi; pn = new CDDAParanoia(this); if (!pn) { qDebug() << "Unable to create paranoia class. low mem?"; error = Error(i18n("Unable to create CDDA paranoia object."), i18n("This is an internal error. Check your hardware. If all okay please make bug report."), Error::ERROR, this); return; } pn->setDevice(_device); qDebug() << "new audio disc detected (" << udi << ", " << _device << ")"; clear(); confirm(); sel_tracks.clear(); for (int i = 1; i <= pn->numOfTracks(); ++i) { if (isAudioTrack(i)) sel_tracks.insert(i); } emit hasSelection(0 != sel_tracks.size()); emit audioDiscDetected(); } void CDDAModel::audio_disc_removed(const QString& udi) { qDebug() << "audio disc removed (" << udi << ")"; _device.clear(); _udi.clear(); if (pn) delete pn; pn = NULL; emit audioDiscRemoved(); } void CDDAModel::disc_information_modified() { qDebug() << "disc info changed"; set_default_values(); setVarious(guessVarious()); reset(); } void CDDAModel::lookup_cddb_done(KCDDB::Result result) { if ((result != KCDDB::Success) && (result != KCDDB::MultipleRecordFound)) { switch (result) { case KCDDB::ServerError : error = Error(KCDDB::resultToString(result), i18n("There is an error with the CDDB server. Please wait or contact the administrator of the CDDB server."), Error::ERROR, this); break; case KCDDB::HostNotFound : error = Error(KCDDB::resultToString(result), i18n("Cannot find the CDDB server. Check your network. Maybe the CDDB server is offline."), Error::ERROR, this); break; case KCDDB::NoResponse : error = Error(KCDDB::resultToString(result), i18n("Please wait, maybe the server is busy, or contact the CDDB server administrator."), Error::ERROR, this); break; case KCDDB::InvalidCategory : error = Error(KCDDB::resultToString(result), i18n("This should not happen. Please make a bug report."), Error::ERROR, this); break; case KCDDB::UnknownError : error = Error(KCDDB::resultToString(result), i18n("Please make a bug report and contact the CDDB server administrator."), Error::ERROR, this); break; case KCDDB::NoRecordFound : ; case KCDDB::MultipleRecordFound : ; case KCDDB::Success : ; default : error = Error(KCDDB::resultToString(result), i18n("This means no data found in the CDDB database."), Error::ERROR, this); } emit cddbLookupDone(false); return; } KCDDB::CDInfo info = cddb->lookupResponse().first(); if (cddb->lookupResponse().count() > 1) { KCDDB::CDInfoList cddb_info = cddb->lookupResponse(); KCDDB::CDInfoList::iterator it; QStringList list; for (it = cddb_info.begin(); it != cddb_info.end(); ++it) { list.append(QString("%1, %2, %3, %4").arg((it->get(KCDDB::Artist).toString())) .arg(it->get(KCDDB::Title).toString()).arg(it->get(KCDDB::Genre).toString()).arg(it->get(KCDDB::Year).toString())); } bool ok = false; // Uses a ComboBox, could use UseListViewForComboBoxItems if necessary QString res = QInputDialog::getItem( nullptr, i18n("Select CDDB Entry"), i18n("Select a CDDB entry:"), list, 0, false, &ok, NULL); if (ok) { // The user selected an item and pressed OK int c = 0; for (QStringList::Iterator it = list.begin(); it != list.end(); ++it) { if (*it==res) break; c++; } if (c < cddb_info.size()) info = cddb_info[c]; } else { emit cddbLookupDone(true); return; // user pressed cancel } } cd_info = info; set_default_values(); setVarious(guessVarious()); if (isVarious() && QLatin1String("Various") == artist()) { setArtist(i18n("Various Artists")); } QString newTitle; int cdnum = guessMultiCD(newTitle); if (cdnum > 0) { setMultiCD(true); setCDNum(cdnum); setTitle(newTitle); } reset(); cddb_transaction_pending = false; _empty = false; emit cddbLookupDone(true); } void CDDAModel::_toggle(const unsigned int track) { if (sel_tracks.contains(track)) { sel_tracks.remove(track); } else { sel_tracks.insert(track); } } const QString CDDAModel::capitalize(const QString &s) { - QStringList stringlist = s.split(" ", QString::SkipEmptyParts); + QStringList stringlist = s.split(' ', QString::SkipEmptyParts); for (int i = 0; i < stringlist.count(); i++) { QString string = stringlist[i].toLower(); int j = 0; while (((string[j] == '(') || (string[j] == '[') || (string[j] == '{') ) && (j < string.length())) j++; string[j] = string[j].toUpper(); stringlist[i] = string; } return stringlist.join(" "); } void CDDAModel::set_default_values() { if (cd_info.get(KCDDB::Year).toString().isEmpty()) cd_info.set(KCDDB::Year, QString("%1").arg(QDate::currentDate().year())); cd_info.set("DNO", 1); cd_info.set("DTRACKOFFSET", 1); cd_info.set("DMULTICD", false); } void CDDAModel::modify() { modified = true; _empty = false; emit cddbDataModified(); } diff --git a/models/profilemodel.cpp b/models/profilemodel.cpp index 4945c62..cf85e1f 100644 --- a/models/profilemodel.cpp +++ b/models/profilemodel.cpp @@ -1,962 +1,962 @@ /* AUDEX CDDA EXTRACTOR * Copyright (C) 2007-2015 Marco Nelles (audex@maniatek.com) * * * This program 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. * * This program 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 this program. If not, see . */ #include "profilemodel.h" #include ProfileModel::ProfileModel(QObject *parent) { Q_UNUSED(parent); revert(); } ProfileModel::~ProfileModel() { clear(); } int ProfileModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent); return p_cache.count(); } int ProfileModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent); return PROFILE_MODEL_COLUMN_NUM; } QVariant ProfileModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return QVariant(); } if ((index.row() < 0) || (index.row() >= p_cache.count())) { return QVariant(); } if (role == Qt::TextAlignmentRole) { return int(Qt::AlignLeft | Qt::AlignVCenter); } if ((role == Qt::DisplayRole) || (role == Qt::EditRole)) { switch (index.column()) { case PROFILE_MODEL_COLUMN_PROFILEINDEX_INDEX : return p_cache.at(index.row())[PROFILE_MODEL_PROFILEINDEX_KEY]; case PROFILE_MODEL_COLUMN_NAME_INDEX : return p_cache.at(index.row())[PROFILE_MODEL_NAME_KEY]; case PROFILE_MODEL_COLUMN_ICON_INDEX : return p_cache.at(index.row())[PROFILE_MODEL_ICON_KEY]; case PROFILE_MODEL_COLUMN_ENCODER_SELECTED_INDEX : return p_cache.at(index.row())[PROFILE_MODEL_ENCODER_SELECTED_KEY]; case PROFILE_MODEL_COLUMN_PATTERN_INDEX : return p_cache.at(index.row())[PROFILE_MODEL_PATTERN_KEY]; case PROFILE_MODEL_COLUMN_FAT32COMPATIBLE_INDEX : return p_cache.at(index.row())[PROFILE_MODEL_FAT32COMPATIBLE_KEY]; case PROFILE_MODEL_COLUMN_UNDERSCORE_INDEX : return p_cache.at(index.row())[PROFILE_MODEL_UNDERSCORE_KEY]; case PROFILE_MODEL_COLUMN_2DIGITSTRACKNUM_INDEX : return p_cache.at(index.row())[PROFILE_MODEL_2DIGITSTRACKNUM_KEY]; case PROFILE_MODEL_COLUMN_SC_INDEX : return p_cache.at(index.row())[PROFILE_MODEL_SC_KEY]; case PROFILE_MODEL_COLUMN_SC_SCALE_INDEX : return p_cache.at(index.row())[PROFILE_MODEL_SC_SCALE_KEY]; case PROFILE_MODEL_COLUMN_SC_SIZE_INDEX : return p_cache.at(index.row())[PROFILE_MODEL_SC_SIZE_KEY]; case PROFILE_MODEL_COLUMN_SC_FORMAT_INDEX : return p_cache.at(index.row())[PROFILE_MODEL_SC_FORMAT_KEY]; case PROFILE_MODEL_COLUMN_SC_NAME_INDEX : return p_cache.at(index.row())[PROFILE_MODEL_SC_NAME_KEY]; case PROFILE_MODEL_COLUMN_PL_INDEX : return p_cache.at(index.row())[PROFILE_MODEL_PL_KEY]; case PROFILE_MODEL_COLUMN_PL_FORMAT_INDEX : return p_cache.at(index.row())[PROFILE_MODEL_PL_FORMAT_KEY]; case PROFILE_MODEL_COLUMN_PL_NAME_INDEX : return p_cache.at(index.row())[PROFILE_MODEL_PL_NAME_KEY]; case PROFILE_MODEL_COLUMN_PL_ABS_FILE_PATH_INDEX : return p_cache.at(index.row())[PROFILE_MODEL_PL_ABS_FILE_PATH_KEY]; case PROFILE_MODEL_COLUMN_PL_UTF8_INDEX : return p_cache.at(index.row())[PROFILE_MODEL_PL_UTF8_KEY]; case PROFILE_MODEL_COLUMN_INF_INDEX : return p_cache.at(index.row())[PROFILE_MODEL_INF_KEY]; case PROFILE_MODEL_COLUMN_INF_TEXT_INDEX : return p_cache.at(index.row())[PROFILE_MODEL_INF_TEXT_KEY]; case PROFILE_MODEL_COLUMN_INF_NAME_INDEX : return p_cache.at(index.row())[PROFILE_MODEL_INF_NAME_KEY]; case PROFILE_MODEL_COLUMN_INF_SUFFIX_INDEX : return p_cache.at(index.row())[PROFILE_MODEL_INF_SUFFIX_KEY]; case PROFILE_MODEL_COLUMN_HL_INDEX : return p_cache.at(index.row())[PROFILE_MODEL_HL_KEY]; case PROFILE_MODEL_COLUMN_HL_FORMAT_INDEX : return p_cache.at(index.row())[PROFILE_MODEL_HL_FORMAT_KEY]; case PROFILE_MODEL_COLUMN_HL_NAME_INDEX : return p_cache.at(index.row())[PROFILE_MODEL_HL_NAME_KEY]; case PROFILE_MODEL_COLUMN_CUE_INDEX : return p_cache.at(index.row())[PROFILE_MODEL_CUE_KEY]; case PROFILE_MODEL_COLUMN_CUE_NAME_INDEX : return p_cache.at(index.row())[PROFILE_MODEL_CUE_NAME_KEY]; case PROFILE_MODEL_COLUMN_SF_INDEX : return p_cache.at(index.row())[PROFILE_MODEL_SF_KEY]; case PROFILE_MODEL_COLUMN_SF_NAME_INDEX : return p_cache.at(index.row())[PROFILE_MODEL_SF_NAME_KEY]; case PROFILE_MODEL_COLUMN_ENCODER_LAME_PARAMETERS_INDEX : return p_cache.at(index.row())[PROFILE_MODEL_COLUMN_ENCODER_LAME_PARAMETERS_KEY]; case PROFILE_MODEL_COLUMN_ENCODER_OGGENC_PARAMETERS_INDEX : return p_cache.at(index.row())[PROFILE_MODEL_COLUMN_ENCODER_OGGENC_PARAMETERS_KEY]; case PROFILE_MODEL_COLUMN_ENCODER_FLAC_PARAMETERS_INDEX : return p_cache.at(index.row())[PROFILE_MODEL_COLUMN_ENCODER_FLAC_PARAMETERS_KEY]; case PROFILE_MODEL_COLUMN_ENCODER_FAAC_PARAMETERS_INDEX : return p_cache.at(index.row())[PROFILE_MODEL_COLUMN_ENCODER_FAAC_PARAMETERS_KEY]; case PROFILE_MODEL_COLUMN_ENCODER_WAVE_PARAMETERS_INDEX : return p_cache.at(index.row())[PROFILE_MODEL_COLUMN_ENCODER_WAVE_PARAMETERS_KEY]; case PROFILE_MODEL_COLUMN_ENCODER_CUSTOM_PARAMETERS_INDEX : return p_cache.at(index.row())[PROFILE_MODEL_COLUMN_ENCODER_CUSTOM_PARAMETERS_KEY]; } } if (role == Qt::DecorationRole) { QString iconName(p_cache.at(index.row())[PROFILE_MODEL_ICON_KEY].toString()); if(!iconName.isEmpty()) { QIcon icon(iconName); if(!icon.isNull()) { return icon; } } return QIcon::fromTheme(DEFAULT_ICON); } return QVariant(); } bool ProfileModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (!index.isValid()) { return false; } if ((index.row() < 0) || (index.row() >= p_cache.count())) { return false; } if (role == Qt::EditRole) { switch (index.column()) { case PROFILE_MODEL_COLUMN_PROFILEINDEX_INDEX : break; case PROFILE_MODEL_COLUMN_ICON_INDEX : break; case PROFILE_MODEL_COLUMN_NAME_INDEX : if (value.toString().isEmpty()) { p_error = Error( i18n("Profile name must not be empty."), i18n("You have given no name for the profile. Please set one."), Error::ERROR, this); return false; } break; case PROFILE_MODEL_COLUMN_ENCODER_SELECTED_INDEX : if (value.toInt()==-1) { p_error = Error( i18n("Profile encoder is not defined."), i18n("You have given no encoder for the profile. Please set one."), Error::ERROR, this); return false; } break; case PROFILE_MODEL_COLUMN_PATTERN_INDEX : if (value.toString().isEmpty()) { p_error = Error( i18n("Profile filename pattern is not defined."), i18n("You have given no filename pattern for the profile. Please set one."), Error::ERROR, this); return false; } break; case PROFILE_MODEL_COLUMN_FAT32COMPATIBLE_INDEX : break; case PROFILE_MODEL_COLUMN_UNDERSCORE_INDEX : break; case PROFILE_MODEL_COLUMN_2DIGITSTRACKNUM_INDEX : break; case PROFILE_MODEL_COLUMN_SC_INDEX : break; case PROFILE_MODEL_COLUMN_SC_SCALE_INDEX : break; case PROFILE_MODEL_COLUMN_SC_SIZE_INDEX : break; case PROFILE_MODEL_COLUMN_SC_FORMAT_INDEX : if ((value.toString()!="JPEG") && (value.toString()!="JPG") && (value.toString()!="PNG") && (value.toString()!="TIFF") && (value.toString()!="BMP")) { p_error = Error( i18n("The image file format is unknown."), i18n("Your given image file format is unknown. Please choose on of these formats: JPG/JPEG, PNG or BMP."), Error::ERROR, this); return false; } break; case PROFILE_MODEL_COLUMN_SC_NAME_INDEX : if (value.toString().isEmpty()) { p_error = Error( i18n("Cover name must not be empty."), i18n("You have given no name for the cover. Please set one."), Error::ERROR, this); return false; } break; case PROFILE_MODEL_COLUMN_PL_INDEX : break; case PROFILE_MODEL_COLUMN_PL_FORMAT_INDEX : if ((value.toString()!="M3U") && (value.toString()!="PLS") && (value.toString()!="XSPF")) { p_error = Error( i18n("The playlist file format is unknown."), i18n("Your given playlist file format is unknown. Please choose on of these formats: M3U, PLS or XSPF."), Error::ERROR, this); return false; } break; case PROFILE_MODEL_COLUMN_PL_NAME_INDEX : if (value.toString().isEmpty()) { p_error = Error( i18n("Playlist name must not be empty."), i18n("You have given no name for the playlist. Please set one."), Error::ERROR, this); return false; } break; case PROFILE_MODEL_COLUMN_PL_ABS_FILE_PATH_INDEX : break; case PROFILE_MODEL_COLUMN_PL_UTF8_INDEX : break; case PROFILE_MODEL_COLUMN_INF_INDEX : break; case PROFILE_MODEL_COLUMN_INF_TEXT_INDEX : break; case PROFILE_MODEL_COLUMN_INF_NAME_INDEX : if (value.toString().isEmpty()) { p_error = Error( i18n("Info text name must not be empty."), i18n("You have given no name for the info text file. Please set one."), Error::ERROR, this); return false; } break; case PROFILE_MODEL_COLUMN_INF_SUFFIX_INDEX : break; if (value.toString().isEmpty()) { p_error = Error( i18n("Info text file name suffix must not be empty."), i18n("You have given no suffix for the info text file. Please set one."), Error::ERROR, this); return false; } break; case PROFILE_MODEL_COLUMN_HL_INDEX : break; case PROFILE_MODEL_COLUMN_HL_FORMAT_INDEX : if ((value.toString() != "SFV") && (value.toString() != "MD5")) { p_error = Error( i18n("The hashlist file format is unknown."), i18n("Your given hashlist file format is unknown. Please choose on of these formats: SFV, MD5."), Error::ERROR, this); return false; } break; case PROFILE_MODEL_COLUMN_HL_NAME_INDEX : break; if (value.toString().isEmpty()) { p_error = Error( i18n("Hashlist name must not be empty."), i18n("You have given no name for the hashlist. Please set one."), Error::ERROR, this); return false; } break; case PROFILE_MODEL_COLUMN_CUE_INDEX : break; case PROFILE_MODEL_COLUMN_CUE_NAME_INDEX : break; if (value.toString().isEmpty()) { p_error = Error( i18n("Cue filename name must not be empty."), i18n("You have given no name for the cue sheet. Please set one."), Error::ERROR, this); return false; } break; case PROFILE_MODEL_COLUMN_SF_INDEX : break; case PROFILE_MODEL_COLUMN_SF_NAME_INDEX : break; if (value.toString().isEmpty()) { p_error = Error( i18n("Filename name must not be empty."), i18n("You have given no name for the single audio file. Please set one."), Error::ERROR, this); return false; } break; case PROFILE_MODEL_COLUMN_ENCODER_LAME_PARAMETERS_INDEX : break; case PROFILE_MODEL_COLUMN_ENCODER_OGGENC_PARAMETERS_INDEX : break; case PROFILE_MODEL_COLUMN_ENCODER_FLAC_PARAMETERS_INDEX : break; case PROFILE_MODEL_COLUMN_ENCODER_FAAC_PARAMETERS_INDEX : break; case PROFILE_MODEL_COLUMN_ENCODER_WAVE_PARAMETERS_INDEX : break; case PROFILE_MODEL_COLUMN_ENCODER_CUSTOM_PARAMETERS_INDEX : break; default : return false; } //check if name is unique if (index.column()==PROFILE_MODEL_COLUMN_NAME_INDEX) { bool found = false; for (int i = 0; i < p_cache.count(); ++i) { if (i==index.row()) continue; if (value.toString()==p_cache.at(i)[PROFILE_MODEL_NAME_KEY].toString()) { found = true; break; } } if (found) { p_error = Error( i18n("Profile name already exists."), i18n("Your profile name %1 already exists in the set of profiles. Please choose a unique one.", value.toString()), Error::ERROR, this); return false; } } //check if profile index is unique if ((index.column()==PROFILE_MODEL_COLUMN_PROFILEINDEX_INDEX) && (value.toInt()!=-1)) { bool found = false; for (int i = 0; i < p_cache.count(); ++i) { if (i==index.row()) continue; if (value.toInt()==p_cache.at(i)[PROFILE_MODEL_PROFILEINDEX_KEY].toInt()) { found = true; break; } } if (found) { p_error = Error( i18n("Profile index already exists."), i18n("Your profile index %1 already exists in the set of profiles. Please choose a unique one.", value.toInt()), Error::ERROR, this); return false; } } switch (index.column()) { case PROFILE_MODEL_COLUMN_PROFILEINDEX_INDEX : p_cache[index.row()][PROFILE_MODEL_PROFILEINDEX_KEY] = value; break; case PROFILE_MODEL_COLUMN_NAME_INDEX : p_cache[index.row()][PROFILE_MODEL_NAME_KEY] = value; break; case PROFILE_MODEL_COLUMN_ICON_INDEX : p_cache[index.row()][PROFILE_MODEL_ICON_KEY] = value; break; case PROFILE_MODEL_COLUMN_ENCODER_SELECTED_INDEX : p_cache[index.row()][PROFILE_MODEL_ENCODER_SELECTED_KEY] = value; break; case PROFILE_MODEL_COLUMN_PATTERN_INDEX : p_cache[index.row()][PROFILE_MODEL_PATTERN_KEY] = value; break; case PROFILE_MODEL_COLUMN_FAT32COMPATIBLE_INDEX : p_cache[index.row()][PROFILE_MODEL_FAT32COMPATIBLE_KEY] = value; break; case PROFILE_MODEL_COLUMN_UNDERSCORE_INDEX : p_cache[index.row()][PROFILE_MODEL_UNDERSCORE_KEY] = value; break; case PROFILE_MODEL_COLUMN_2DIGITSTRACKNUM_INDEX : p_cache[index.row()][PROFILE_MODEL_2DIGITSTRACKNUM_KEY] = value; break; case PROFILE_MODEL_COLUMN_SC_INDEX : p_cache[index.row()][PROFILE_MODEL_SC_KEY] = value; break; case PROFILE_MODEL_COLUMN_SC_SCALE_INDEX : p_cache[index.row()][PROFILE_MODEL_SC_SCALE_KEY] = value; break; case PROFILE_MODEL_COLUMN_SC_SIZE_INDEX : p_cache[index.row()][PROFILE_MODEL_SC_SIZE_KEY] = value; break; case PROFILE_MODEL_COLUMN_SC_FORMAT_INDEX : p_cache[index.row()][PROFILE_MODEL_SC_FORMAT_KEY] = value; break; case PROFILE_MODEL_COLUMN_SC_NAME_INDEX : p_cache[index.row()][PROFILE_MODEL_SC_NAME_KEY] = value; break; case PROFILE_MODEL_COLUMN_PL_INDEX : p_cache[index.row()][PROFILE_MODEL_PL_KEY] = value; break; case PROFILE_MODEL_COLUMN_PL_FORMAT_INDEX : p_cache[index.row()][PROFILE_MODEL_PL_FORMAT_KEY] = value; break; case PROFILE_MODEL_COLUMN_PL_NAME_INDEX : p_cache[index.row()][PROFILE_MODEL_PL_NAME_KEY] = value; break; case PROFILE_MODEL_COLUMN_PL_ABS_FILE_PATH_INDEX : p_cache[index.row()][PROFILE_MODEL_PL_ABS_FILE_PATH_KEY] = value; break; case PROFILE_MODEL_COLUMN_PL_UTF8_INDEX : p_cache[index.row()][PROFILE_MODEL_PL_UTF8_KEY] = value; break; case PROFILE_MODEL_COLUMN_INF_INDEX : p_cache[index.row()][PROFILE_MODEL_INF_KEY] = value; break; case PROFILE_MODEL_COLUMN_INF_TEXT_INDEX : p_cache[index.row()][PROFILE_MODEL_INF_TEXT_KEY] = value; break; case PROFILE_MODEL_COLUMN_INF_NAME_INDEX : p_cache[index.row()][PROFILE_MODEL_INF_NAME_KEY] = value; break; case PROFILE_MODEL_COLUMN_INF_SUFFIX_INDEX : p_cache[index.row()][PROFILE_MODEL_INF_SUFFIX_KEY] = value; break; case PROFILE_MODEL_COLUMN_HL_INDEX : p_cache[index.row()][PROFILE_MODEL_HL_KEY] = value; break; case PROFILE_MODEL_COLUMN_HL_FORMAT_INDEX : p_cache[index.row()][PROFILE_MODEL_HL_FORMAT_KEY] = value; break; case PROFILE_MODEL_COLUMN_HL_NAME_INDEX : p_cache[index.row()][PROFILE_MODEL_HL_NAME_KEY] = value; break; case PROFILE_MODEL_COLUMN_CUE_INDEX : p_cache[index.row()][PROFILE_MODEL_CUE_KEY] = value; break; case PROFILE_MODEL_COLUMN_CUE_NAME_INDEX : p_cache[index.row()][PROFILE_MODEL_CUE_NAME_KEY] = value; break; case PROFILE_MODEL_COLUMN_SF_INDEX : p_cache[index.row()][PROFILE_MODEL_SF_KEY] = value; break; case PROFILE_MODEL_COLUMN_SF_NAME_INDEX : p_cache[index.row()][PROFILE_MODEL_SF_NAME_KEY] = value; break; case PROFILE_MODEL_COLUMN_ENCODER_LAME_PARAMETERS_INDEX : p_cache[index.row()][PROFILE_MODEL_COLUMN_ENCODER_LAME_PARAMETERS_KEY] = value; break; case PROFILE_MODEL_COLUMN_ENCODER_OGGENC_PARAMETERS_INDEX : p_cache[index.row()][PROFILE_MODEL_COLUMN_ENCODER_OGGENC_PARAMETERS_KEY] = value; break; case PROFILE_MODEL_COLUMN_ENCODER_FLAC_PARAMETERS_INDEX : p_cache[index.row()][PROFILE_MODEL_COLUMN_ENCODER_FLAC_PARAMETERS_KEY] = value; break; case PROFILE_MODEL_COLUMN_ENCODER_FAAC_PARAMETERS_INDEX : p_cache[index.row()][PROFILE_MODEL_COLUMN_ENCODER_FAAC_PARAMETERS_KEY] = value; break; case PROFILE_MODEL_COLUMN_ENCODER_WAVE_PARAMETERS_INDEX : p_cache[index.row()][PROFILE_MODEL_COLUMN_ENCODER_WAVE_PARAMETERS_KEY] = value; break; case PROFILE_MODEL_COLUMN_ENCODER_CUSTOM_PARAMETERS_INDEX : p_cache[index.row()][PROFILE_MODEL_COLUMN_ENCODER_CUSTOM_PARAMETERS_KEY] = value; break; default : break; } return true; } reset(); p_error = Error( i18n("Unknown error. No index found in profile model."), i18n("This is an internal error. Please report."), Error::ERROR, this); return false; } bool ProfileModel::removeRows(int row, int count, const QModelIndex& parent) { Q_UNUSED(parent); if ((row < 0) || (row >= p_cache.count())) { return false; } if (count <= 0) { return false; } int c; if (row+count > p_cache.count()) { c = p_cache.count(); } else { c = row+count; } for (int i = row; i < c; ++i) { p_cache.removeAt(i); } reset(); //update current profile index. maybe current has been deleted? setCurrentProfileIndex(p_current_profile_index); emit profilesRemovedOrInserted(); return true; } bool ProfileModel::insertRows(int row, int count, const QModelIndex& parent) { Q_UNUSED(parent); if ((row < 0) || (row > p_cache.count())) { return false; } if (count <= 0) { return false; } bool wasEmpty = (p_cache.count()==0); if (row == p_cache.count()) { for (int i = 0; i < count; ++i) p_cache.append(p_new_profile()); } else { for (int i = row; i < count; ++i) p_cache.insert(i, p_new_profile()); } reset(); if (wasEmpty) { //set first profile as current index setCurrentProfileIndex(p_cache.at(0)[PROFILE_MODEL_PROFILEINDEX_KEY].toInt()); } emit profilesRemovedOrInserted(); return true; } void ProfileModel::setCurrentProfileIndex(int profile_index) { int pi = profile_index; if (p_cache.count()==0) { pi = -1; } else if (!indexExists(profile_index)) { //set first profile as current index pi = p_cache.at(0)[PROFILE_MODEL_PROFILEINDEX_KEY].toInt(); } if (pi != p_current_profile_index) { p_current_profile_index = pi; KConfig config; KConfigGroup profilesGroup(&config, "Profiles"); profilesGroup.writeEntry("Standard", pi); profilesGroup.config()->sync(); emit currentProfileIndexChanged(pi); } } int ProfileModel::setRowAsCurrentProfileIndex(int row) { int i = p_cache.at(row).value(PROFILE_MODEL_PROFILEINDEX_KEY, -1).toInt(); setCurrentProfileIndex(i); return i; } int ProfileModel::currentProfileIndex() const { if (p_cache.count()==0) return -1; return p_current_profile_index; } int ProfileModel::currentProfileRow() const { return getRowByIndex(p_current_profile_index); } int ProfileModel::getRowByIndex(int profile_index) const { for (int i = 0; i < p_cache.count(); ++i) if (profile_index==p_cache.at(i)[PROFILE_MODEL_PROFILEINDEX_KEY].toInt()) return i; return -1; } void ProfileModel::clear() { p_cache.clear(); p_current_profile_index = -1; } bool ProfileModel::nameExists(const QString& name) const { for (int j = 0; j < p_cache.count(); ++j) if (name==p_cache.at(j)[PROFILE_MODEL_NAME_KEY].toString()) return true; return false; } bool ProfileModel::indexExists(int profile_index) const { for (int j = 0; j < p_cache.count(); ++j) if (profile_index==p_cache.at(j)[PROFILE_MODEL_PROFILEINDEX_KEY].toInt()) return true; return false; } int ProfileModel::getNewIndex() const { QSet indexes; QList::ConstIterator it(p_cache.begin()), end(p_cache.end()); for (; it != end; ++it) { indexes.insert((*it)[PROFILE_MODEL_PROFILEINDEX_KEY].toInt()); } for (int i = 0; i < INT_MAX; ++i) { if (!indexes.contains(i)) return i; } return -1; } static bool lessThan(const Profile &p1, const Profile &p2) { return (QString::localeAwareCompare(p1[PROFILE_MODEL_NAME_KEY].toString(), p2[PROFILE_MODEL_NAME_KEY].toString()) < 0); } void ProfileModel::sortItems() { qSort(p_cache.begin(), p_cache.end(), lessThan); reset(); emit profilesRemovedOrInserted(); } void ProfileModel::autoCreate() { bool flag = false; bool wasEmpty = (p_cache.count()==0); if (EncoderAssistant::available(EncoderAssistant::LAME)) { if (!nameExists(EncoderAssistant::name(EncoderAssistant::LAME) + LABEL_MOBILE_QUALITY)) { Profile p = p_new_profile(); p[PROFILE_MODEL_NAME_KEY] = EncoderAssistant::name(EncoderAssistant::LAME) + LABEL_MOBILE_QUALITY; p[PROFILE_MODEL_ICON_KEY] = EncoderAssistant::icon(EncoderAssistant::LAME); p[PROFILE_MODEL_ENCODER_SELECTED_KEY] = (int)EncoderAssistant::LAME; p[PROFILE_MODEL_COLUMN_ENCODER_LAME_PARAMETERS_KEY] = EncoderAssistant::stdParameters(EncoderAssistant::LAME, EncoderAssistant::MOBILE).toString(); p_cache.append(p); flag = true; } if (!nameExists(EncoderAssistant::name(EncoderAssistant::LAME) + LABEL_NORMAL_QUALITY)) { Profile p = p_new_profile(); p[PROFILE_MODEL_NAME_KEY] = EncoderAssistant::name(EncoderAssistant::LAME) + LABEL_NORMAL_QUALITY; p[PROFILE_MODEL_ICON_KEY] = EncoderAssistant::icon(EncoderAssistant::LAME); p[PROFILE_MODEL_ENCODER_SELECTED_KEY] = (int)EncoderAssistant::LAME; p[PROFILE_MODEL_COLUMN_ENCODER_LAME_PARAMETERS_KEY] = EncoderAssistant::stdParameters(EncoderAssistant::LAME, EncoderAssistant::NORMAL).toString(); p_cache.append(p); flag = true; } if (!nameExists(EncoderAssistant::name(EncoderAssistant::LAME) + LABEL_EXTREME_QUALITY)) { Profile p = p_new_profile(); p[PROFILE_MODEL_NAME_KEY] = EncoderAssistant::name(EncoderAssistant::LAME) + LABEL_EXTREME_QUALITY; p[PROFILE_MODEL_ICON_KEY] = EncoderAssistant::icon(EncoderAssistant::LAME); p[PROFILE_MODEL_ENCODER_SELECTED_KEY] = (int)EncoderAssistant::LAME; p[PROFILE_MODEL_COLUMN_ENCODER_LAME_PARAMETERS_KEY] = EncoderAssistant::stdParameters(EncoderAssistant::LAME, EncoderAssistant::EXTREME).toString();; p_cache.append(p); flag = true; } } if (EncoderAssistant::available(EncoderAssistant::OGGENC)) { if (!nameExists(EncoderAssistant::name(EncoderAssistant::OGGENC) + LABEL_MOBILE_QUALITY)) { Profile p = p_new_profile(); p[PROFILE_MODEL_NAME_KEY] = EncoderAssistant::name(EncoderAssistant::OGGENC) + LABEL_MOBILE_QUALITY; p[PROFILE_MODEL_ICON_KEY] = EncoderAssistant::icon(EncoderAssistant::OGGENC); p[PROFILE_MODEL_ENCODER_SELECTED_KEY] = (int)EncoderAssistant::OGGENC; p[PROFILE_MODEL_COLUMN_ENCODER_OGGENC_PARAMETERS_KEY] = EncoderAssistant::stdParameters(EncoderAssistant::OGGENC, EncoderAssistant::MOBILE).toString(); p_cache.append(p); flag = true; } if (!nameExists(EncoderAssistant::name(EncoderAssistant::OGGENC) + LABEL_NORMAL_QUALITY)) { Profile p = p_new_profile(); p[PROFILE_MODEL_NAME_KEY] = EncoderAssistant::name(EncoderAssistant::OGGENC) + LABEL_NORMAL_QUALITY; p[PROFILE_MODEL_ICON_KEY] = EncoderAssistant::icon(EncoderAssistant::OGGENC); p[PROFILE_MODEL_ENCODER_SELECTED_KEY] = (int)EncoderAssistant::OGGENC; p[PROFILE_MODEL_COLUMN_ENCODER_OGGENC_PARAMETERS_KEY] = EncoderAssistant::stdParameters(EncoderAssistant::OGGENC, EncoderAssistant::NORMAL).toString(); p_cache.append(p); flag = true; } if (!nameExists(EncoderAssistant::name(EncoderAssistant::OGGENC) + LABEL_EXTREME_QUALITY)) { Profile p = p_new_profile(); p[PROFILE_MODEL_NAME_KEY] = EncoderAssistant::name(EncoderAssistant::OGGENC) + LABEL_EXTREME_QUALITY; p[PROFILE_MODEL_ICON_KEY] = EncoderAssistant::icon(EncoderAssistant::OGGENC); p[PROFILE_MODEL_ENCODER_SELECTED_KEY] = (int)EncoderAssistant::OGGENC; p[PROFILE_MODEL_COLUMN_ENCODER_OGGENC_PARAMETERS_KEY] = EncoderAssistant::stdParameters(EncoderAssistant::OGGENC, EncoderAssistant::EXTREME).toString(); p_cache.append(p); flag = true; } } if ((!nameExists(EncoderAssistant::name(EncoderAssistant::FLAC))) && (EncoderAssistant::available(EncoderAssistant::FLAC))) { Profile p = p_new_profile(); p[PROFILE_MODEL_NAME_KEY] = EncoderAssistant::name(EncoderAssistant::FLAC); p[PROFILE_MODEL_ICON_KEY] = EncoderAssistant::icon(EncoderAssistant::FLAC); p[PROFILE_MODEL_ENCODER_SELECTED_KEY] = (int)EncoderAssistant::FLAC; p_cache.append(p); flag = true; } if (EncoderAssistant::available(EncoderAssistant::FAAC)) { if (!nameExists(EncoderAssistant::name(EncoderAssistant::FAAC) + LABEL_MOBILE_QUALITY)) { Profile p = p_new_profile(); p[PROFILE_MODEL_NAME_KEY] = EncoderAssistant::name(EncoderAssistant::FAAC) + LABEL_MOBILE_QUALITY; p[PROFILE_MODEL_ICON_KEY] = EncoderAssistant::icon(EncoderAssistant::FAAC); p[PROFILE_MODEL_ENCODER_SELECTED_KEY] = (int)EncoderAssistant::FAAC; p[PROFILE_MODEL_COLUMN_ENCODER_FAAC_PARAMETERS_KEY] = EncoderAssistant::stdParameters(EncoderAssistant::FAAC, EncoderAssistant::MOBILE).toString(); p_cache.append(p); flag = true; } if (!nameExists(EncoderAssistant::name(EncoderAssistant::FAAC) + LABEL_NORMAL_QUALITY)) { Profile p = p_new_profile(); p[PROFILE_MODEL_NAME_KEY] = EncoderAssistant::name(EncoderAssistant::FAAC) + LABEL_NORMAL_QUALITY; p[PROFILE_MODEL_ICON_KEY] = EncoderAssistant::icon(EncoderAssistant::FAAC); p[PROFILE_MODEL_ENCODER_SELECTED_KEY] = (int)EncoderAssistant::FAAC; p[PROFILE_MODEL_COLUMN_ENCODER_FAAC_PARAMETERS_KEY] = EncoderAssistant::stdParameters(EncoderAssistant::FAAC, EncoderAssistant::NORMAL).toString(); p_cache.append(p); flag = true; } if (!nameExists(EncoderAssistant::name(EncoderAssistant::FAAC) + LABEL_EXTREME_QUALITY)) { Profile p = p_new_profile(); p[PROFILE_MODEL_NAME_KEY] = EncoderAssistant::name(EncoderAssistant::FAAC) + LABEL_EXTREME_QUALITY; p[PROFILE_MODEL_ICON_KEY] = EncoderAssistant::icon(EncoderAssistant::FAAC); p[PROFILE_MODEL_ENCODER_SELECTED_KEY] = (int)EncoderAssistant::FAAC; p[PROFILE_MODEL_COLUMN_ENCODER_FAAC_PARAMETERS_KEY] = EncoderAssistant::stdParameters(EncoderAssistant::FAAC, EncoderAssistant::EXTREME).toString(); p_cache.append(p); flag = true; } } if ((!nameExists(EncoderAssistant::name(EncoderAssistant::WAVE))) && (EncoderAssistant::available(EncoderAssistant::WAVE))) { Profile p = p_new_profile(); p[PROFILE_MODEL_NAME_KEY] = EncoderAssistant::name(EncoderAssistant::WAVE); p[PROFILE_MODEL_ICON_KEY] = EncoderAssistant::icon(EncoderAssistant::WAVE); p[PROFILE_MODEL_ENCODER_SELECTED_KEY] = (int)EncoderAssistant::WAVE; p_cache.append(p); flag = true; } if (flag) { sortItems(); if (wasEmpty) { //set first profile as current index setCurrentProfileIndex(p_cache.at(0)[PROFILE_MODEL_PROFILEINDEX_KEY].toInt()); } } commit(); } EncoderAssistant::Encoder ProfileModel::getSelectedEncoderFromCurrentIndex() { return (EncoderAssistant::Encoder)data(index(currentProfileRow(), PROFILE_MODEL_COLUMN_ENCODER_SELECTED_INDEX)).toInt(); } const Parameters ProfileModel::getSelectedEncoderParametersFromCurrentIndex() { Parameters parameters; EncoderAssistant::Encoder encoder = getSelectedEncoderFromCurrentIndex(); //what parameters does the encoder start with? switch (encoder) { case EncoderAssistant::LAME : parameters.fromString(data(index(currentProfileRow(), PROFILE_MODEL_COLUMN_ENCODER_LAME_PARAMETERS_INDEX)).toString()); break; case EncoderAssistant::OGGENC : parameters.fromString(data(index(currentProfileRow(), PROFILE_MODEL_COLUMN_ENCODER_OGGENC_PARAMETERS_INDEX)).toString()); break; case EncoderAssistant::FLAC : parameters.fromString(data(index(currentProfileRow(), PROFILE_MODEL_COLUMN_ENCODER_FLAC_PARAMETERS_INDEX)).toString()); break; case EncoderAssistant::FAAC : parameters.fromString(data(index(currentProfileRow(), PROFILE_MODEL_COLUMN_ENCODER_FAAC_PARAMETERS_INDEX)).toString()); break; case EncoderAssistant::WAVE : parameters.fromString(data(index(currentProfileRow(), PROFILE_MODEL_COLUMN_ENCODER_WAVE_PARAMETERS_INDEX)).toString()); break; case EncoderAssistant::CUSTOM : parameters.fromString(data(index(currentProfileRow(), PROFILE_MODEL_COLUMN_ENCODER_CUSTOM_PARAMETERS_INDEX)).toString()); break; case EncoderAssistant::NUM : ; } return parameters; } const QString ProfileModel::getSelectedEncoderPatternFromCurrentIndex() { EncoderAssistant::Encoder encoder = getSelectedEncoderFromCurrentIndex(); Parameters parameters = getSelectedEncoderParametersFromCurrentIndex(); return EncoderAssistant::pattern(encoder, parameters); } const QString ProfileModel::getSelectedEncoderSuffixFromCurrentIndex() { EncoderAssistant::Encoder encoder = getSelectedEncoderFromCurrentIndex(); Parameters parameters = getSelectedEncoderParametersFromCurrentIndex(); switch (encoder) { case EncoderAssistant::LAME : return parameters.value(ENCODER_LAME_SUFFIX_KEY, ENCODER_LAME_SUFFIX); case EncoderAssistant::OGGENC : return parameters.value(ENCODER_OGGENC_SUFFIX_KEY, ENCODER_OGGENC_SUFFIX); case EncoderAssistant::FLAC : return parameters.value(ENCODER_FLAC_SUFFIX_KEY, ENCODER_FLAC_SUFFIX); case EncoderAssistant::FAAC : return parameters.value(ENCODER_FAAC_SUFFIX_KEY, ENCODER_FAAC_SUFFIX); case EncoderAssistant::WAVE : return parameters.value(ENCODER_WAVE_SUFFIX_KEY, ENCODER_WAVE_SUFFIX); case EncoderAssistant::CUSTOM : return parameters.value(ENCODER_CUSTOM_SUFFIX_KEY, ENCODER_CUSTOM_SUFFIX); case EncoderAssistant::NUM : return ""; } return ""; } const QString ProfileModel::getSelectedEncoderNameAndVersion() { EncoderAssistant::Encoder encoder = getSelectedEncoderFromCurrentIndex(); return QString("%1 %2").arg(EncoderAssistant::encoderName(encoder)).arg(EncoderAssistant::version(encoder)); } Error ProfileModel::lastError() const { return p_error; } void ProfileModel::commit() { KConfig config; p_save(&config); } const Profile ProfileModel::p_new_profile() { Profile p; p[PROFILE_MODEL_PROFILEINDEX_KEY] = getNewIndex(); p[PROFILE_MODEL_NAME_KEY] = DEFAULT_NAME; p[PROFILE_MODEL_ENCODER_SELECTED_KEY] = DEFAULT_ENCODER_SELECTED; p[PROFILE_MODEL_PATTERN_KEY] = DEFAULT_PATTERN; p[PROFILE_MODEL_FAT32COMPATIBLE_KEY] = DEFAULT_FAT32; p[PROFILE_MODEL_UNDERSCORE_KEY] = DEFAULT_UNDERSCORE; p[PROFILE_MODEL_2DIGITSTRACKNUM_KEY] = DEFAULT_2DIGITSTRACKNUM; p[PROFILE_MODEL_SC_KEY] = DEFAULT_SC; p[PROFILE_MODEL_SC_SCALE_KEY] = DEFAULT_SC_SCALE; p[PROFILE_MODEL_SC_SIZE_KEY] = DEFAULT_SC_SIZE; p[PROFILE_MODEL_SC_FORMAT_KEY] = DEFAULT_SC_FORMAT; p[PROFILE_MODEL_SC_NAME_KEY] = DEFAULT_SC_NAME; p[PROFILE_MODEL_PL_KEY] = DEFAULT_PL; p[PROFILE_MODEL_PL_FORMAT_KEY] = DEFAULT_PL_FORMAT; p[PROFILE_MODEL_PL_NAME_KEY] = DEFAULT_PL_NAME; p[PROFILE_MODEL_PL_ABS_FILE_PATH_KEY] = DEFAULT_PL_ABS_FILE_PATH; p[PROFILE_MODEL_PL_UTF8_KEY] = DEFAULT_PL_UTF8; p[PROFILE_MODEL_INF_KEY] = DEFAULT_INF; p[PROFILE_MODEL_INF_TEXT_KEY] = DEFAULT_INF_TEXT; p[PROFILE_MODEL_INF_NAME_KEY] = DEFAULT_INF_NAME; p[PROFILE_MODEL_INF_SUFFIX_KEY] = DEFAULT_INF_SUFFIX; p[PROFILE_MODEL_HL_KEY] = DEFAULT_HL; p[PROFILE_MODEL_HL_FORMAT_KEY] = DEFAULT_HL_FORMAT; p[PROFILE_MODEL_HL_NAME_KEY] = DEFAULT_HL_NAME; p[PROFILE_MODEL_CUE_KEY] = DEFAULT_CUE; p[PROFILE_MODEL_CUE_NAME_KEY] = DEFAULT_CUE_NAME; p[PROFILE_MODEL_SF_KEY] = DEFAULT_SF; p[PROFILE_MODEL_SF_NAME_KEY] = DEFAULT_SF_NAME; p[PROFILE_MODEL_COLUMN_ENCODER_LAME_PARAMETERS_KEY] = DEFAULT_ENCODER_PARAMETERS; p[PROFILE_MODEL_COLUMN_ENCODER_OGGENC_PARAMETERS_KEY] = DEFAULT_ENCODER_PARAMETERS; p[PROFILE_MODEL_COLUMN_ENCODER_FLAC_PARAMETERS_KEY] = DEFAULT_ENCODER_PARAMETERS; p[PROFILE_MODEL_COLUMN_ENCODER_FAAC_PARAMETERS_KEY] = DEFAULT_ENCODER_PARAMETERS; p[PROFILE_MODEL_COLUMN_ENCODER_WAVE_PARAMETERS_KEY] = DEFAULT_ENCODER_PARAMETERS; p[PROFILE_MODEL_COLUMN_ENCODER_CUSTOM_PARAMETERS_KEY] = DEFAULT_ENCODER_PARAMETERS; return p; } void ProfileModel::p_new_name(QString& name) { for (int j = 0; j < p_cache.count(); ++j) { if (name==p_cache.at(j)[PROFILE_MODEL_NAME_KEY].toString()) { - name = "_"+name; + name = '_'+name; p_new_name(name); return; } } } void ProfileModel::revert() { clear(); KConfig config; p_load(&config); } int ProfileModel::copy(const int profileRow) { if ((profileRow < 0) || (profileRow >= rowCount())) return -1; int key = getNewIndex(); Profile p = p_cache[profileRow]; QString name = p_cache[profileRow][PROFILE_MODEL_NAME_KEY].toString(); p_new_name(name); p[PROFILE_MODEL_NAME_KEY] = name; p[PROFILE_MODEL_PROFILEINDEX_KEY] = key; p_cache.append(p); reset(); emit profilesRemovedOrInserted(); return key; } bool ProfileModel::saveProfilesToFile(const QString& filename) { KConfig config(filename); p_save(&config); return true; } bool ProfileModel::loadProfilesFromFile(const QString& filename) { KConfig config(filename); p_load(&config); reset(); commit(); return true; } void ProfileModel::p_save(KConfig *config) { KConfigGroup profilesGroup(config, "Profiles"); profilesGroup.deleteGroup(); profilesGroup.writeEntry("Standard", p_current_profile_index); profilesGroup.writeEntry("Count", p_cache.count()); for (int i = 0; i < p_cache.count(); ++i) { KConfigGroup subGroup(&profilesGroup, QString("Profile %1").arg(i)); subGroup.writeEntry(PROFILE_MODEL_PROFILEINDEX_KEY, p_cache[i][PROFILE_MODEL_PROFILEINDEX_KEY]); subGroup.writeEntry(PROFILE_MODEL_NAME_KEY, p_cache[i][PROFILE_MODEL_NAME_KEY]); subGroup.writeEntry(PROFILE_MODEL_ICON_KEY, p_cache[i][PROFILE_MODEL_ICON_KEY]); subGroup.writeEntry(PROFILE_MODEL_ENCODER_SELECTED_KEY, p_cache[i][PROFILE_MODEL_ENCODER_SELECTED_KEY]); subGroup.writeEntry(PROFILE_MODEL_PATTERN_KEY, p_cache[i][PROFILE_MODEL_PATTERN_KEY]); subGroup.writeEntry(PROFILE_MODEL_FAT32COMPATIBLE_KEY, p_cache[i][PROFILE_MODEL_FAT32COMPATIBLE_KEY]); subGroup.writeEntry(PROFILE_MODEL_UNDERSCORE_KEY, p_cache[i][PROFILE_MODEL_UNDERSCORE_KEY]); subGroup.writeEntry(PROFILE_MODEL_2DIGITSTRACKNUM_KEY, p_cache[i][PROFILE_MODEL_2DIGITSTRACKNUM_KEY]); subGroup.writeEntry(PROFILE_MODEL_SC_KEY, p_cache[i][PROFILE_MODEL_SC_KEY]); subGroup.writeEntry(PROFILE_MODEL_SC_SCALE_KEY, p_cache[i][PROFILE_MODEL_SC_SCALE_KEY]); subGroup.writeEntry(PROFILE_MODEL_SC_SIZE_KEY, p_cache[i][PROFILE_MODEL_SC_SIZE_KEY]); subGroup.writeEntry(PROFILE_MODEL_SC_FORMAT_KEY, p_cache[i][PROFILE_MODEL_SC_FORMAT_KEY]); subGroup.writeEntry(PROFILE_MODEL_SC_NAME_KEY, p_cache[i][PROFILE_MODEL_SC_NAME_KEY]); subGroup.writeEntry(PROFILE_MODEL_PL_KEY, p_cache[i][PROFILE_MODEL_PL_KEY]); subGroup.writeEntry(PROFILE_MODEL_PL_FORMAT_KEY, p_cache[i][PROFILE_MODEL_PL_FORMAT_KEY]); subGroup.writeEntry(PROFILE_MODEL_PL_NAME_KEY, p_cache[i][PROFILE_MODEL_PL_NAME_KEY]); subGroup.writeEntry(PROFILE_MODEL_PL_ABS_FILE_PATH_KEY, p_cache[i][PROFILE_MODEL_PL_ABS_FILE_PATH_KEY]); subGroup.writeEntry(PROFILE_MODEL_PL_UTF8_KEY, p_cache[i][PROFILE_MODEL_PL_UTF8_KEY]); subGroup.writeEntry(PROFILE_MODEL_INF_KEY, p_cache[i][PROFILE_MODEL_INF_KEY]); subGroup.writeEntry(PROFILE_MODEL_INF_TEXT_KEY, p_cache[i][PROFILE_MODEL_INF_TEXT_KEY]); subGroup.writeEntry(PROFILE_MODEL_INF_NAME_KEY, p_cache[i][PROFILE_MODEL_INF_NAME_KEY]); subGroup.writeEntry(PROFILE_MODEL_INF_SUFFIX_KEY, p_cache[i][PROFILE_MODEL_INF_SUFFIX_KEY]); subGroup.writeEntry(PROFILE_MODEL_HL_KEY, p_cache[i][PROFILE_MODEL_HL_KEY]); subGroup.writeEntry(PROFILE_MODEL_HL_FORMAT_KEY, p_cache[i][PROFILE_MODEL_HL_FORMAT_KEY]); subGroup.writeEntry(PROFILE_MODEL_HL_NAME_KEY, p_cache[i][PROFILE_MODEL_HL_NAME_KEY]); subGroup.writeEntry(PROFILE_MODEL_CUE_KEY, p_cache[i][PROFILE_MODEL_CUE_KEY]); subGroup.writeEntry(PROFILE_MODEL_CUE_NAME_KEY, p_cache[i][PROFILE_MODEL_CUE_NAME_KEY]); subGroup.writeEntry(PROFILE_MODEL_SF_KEY, p_cache[i][PROFILE_MODEL_SF_KEY]); subGroup.writeEntry(PROFILE_MODEL_SF_NAME_KEY, p_cache[i][PROFILE_MODEL_SF_NAME_KEY]); subGroup.writeEntry(PROFILE_MODEL_COLUMN_ENCODER_LAME_PARAMETERS_KEY, p_cache[i][PROFILE_MODEL_COLUMN_ENCODER_LAME_PARAMETERS_KEY]); subGroup.writeEntry(PROFILE_MODEL_COLUMN_ENCODER_OGGENC_PARAMETERS_KEY, p_cache[i][PROFILE_MODEL_COLUMN_ENCODER_OGGENC_PARAMETERS_KEY]); subGroup.writeEntry(PROFILE_MODEL_COLUMN_ENCODER_FLAC_PARAMETERS_KEY, p_cache[i][PROFILE_MODEL_COLUMN_ENCODER_FLAC_PARAMETERS_KEY]); subGroup.writeEntry(PROFILE_MODEL_COLUMN_ENCODER_FAAC_PARAMETERS_KEY, p_cache[i][PROFILE_MODEL_COLUMN_ENCODER_FAAC_PARAMETERS_KEY]); subGroup.writeEntry(PROFILE_MODEL_COLUMN_ENCODER_WAVE_PARAMETERS_KEY, p_cache[i][PROFILE_MODEL_COLUMN_ENCODER_WAVE_PARAMETERS_KEY]); subGroup.writeEntry(PROFILE_MODEL_COLUMN_ENCODER_CUSTOM_PARAMETERS_KEY, p_cache[i][PROFILE_MODEL_COLUMN_ENCODER_CUSTOM_PARAMETERS_KEY]); } if (p_cache.count()>0) profilesGroup.config()->sync(); } void ProfileModel::p_load(KConfig *config) { KConfigGroup profilesGroup(config, "Profiles"); clear(); p_current_profile_index = profilesGroup.readEntry("Standard", -1); int profileCount = profilesGroup.readEntry("Count", QVariant(0)).toInt(); for (int i = 0; i < profileCount; ++i) { Profile p; KConfigGroup subGroup(&profilesGroup, QString("Profile %1").arg(i)); p[PROFILE_MODEL_PROFILEINDEX_KEY] = subGroup.readEntry(PROFILE_MODEL_PROFILEINDEX_KEY, DEFAULT_PROFILEINDEX); p[PROFILE_MODEL_NAME_KEY] = subGroup.readEntry(PROFILE_MODEL_NAME_KEY, DEFAULT_NAME); p[PROFILE_MODEL_ICON_KEY] = subGroup.readEntry(PROFILE_MODEL_ICON_KEY, DEFAULT_ICON); p[PROFILE_MODEL_ENCODER_SELECTED_KEY] = subGroup.readEntry(PROFILE_MODEL_ENCODER_SELECTED_KEY, DEFAULT_ENCODER_SELECTED); p[PROFILE_MODEL_PATTERN_KEY] = subGroup.readEntry(PROFILE_MODEL_PATTERN_KEY, DEFAULT_PATTERN); p[PROFILE_MODEL_FAT32COMPATIBLE_KEY] = subGroup.readEntry(PROFILE_MODEL_FAT32COMPATIBLE_KEY, DEFAULT_FAT32); p[PROFILE_MODEL_UNDERSCORE_KEY] = subGroup.readEntry(PROFILE_MODEL_UNDERSCORE_KEY, DEFAULT_UNDERSCORE); p[PROFILE_MODEL_2DIGITSTRACKNUM_KEY] = subGroup.readEntry(PROFILE_MODEL_2DIGITSTRACKNUM_KEY, DEFAULT_2DIGITSTRACKNUM); p[PROFILE_MODEL_SC_KEY] = subGroup.readEntry(PROFILE_MODEL_SC_KEY, DEFAULT_SC); p[PROFILE_MODEL_SC_SCALE_KEY] = subGroup.readEntry(PROFILE_MODEL_SC_SCALE_KEY, DEFAULT_SC_SCALE); p[PROFILE_MODEL_SC_SIZE_KEY] = subGroup.readEntry(PROFILE_MODEL_SC_SIZE_KEY, DEFAULT_SC_SIZE); p[PROFILE_MODEL_SC_FORMAT_KEY] = subGroup.readEntry(PROFILE_MODEL_SC_FORMAT_KEY, DEFAULT_SC_FORMAT); p[PROFILE_MODEL_SC_NAME_KEY] = subGroup.readEntry(PROFILE_MODEL_SC_NAME_KEY, DEFAULT_SC_NAME); p[PROFILE_MODEL_PL_KEY] = subGroup.readEntry(PROFILE_MODEL_PL_KEY, DEFAULT_PL); p[PROFILE_MODEL_PL_FORMAT_KEY] = subGroup.readEntry(PROFILE_MODEL_PL_FORMAT_KEY, DEFAULT_PL_NAME); p[PROFILE_MODEL_PL_NAME_KEY] = subGroup.readEntry(PROFILE_MODEL_PL_NAME_KEY, DEFAULT_PL_NAME); p[PROFILE_MODEL_PL_ABS_FILE_PATH_KEY] = subGroup.readEntry(PROFILE_MODEL_PL_ABS_FILE_PATH_KEY, DEFAULT_PL_ABS_FILE_PATH); p[PROFILE_MODEL_PL_UTF8_KEY] = subGroup.readEntry(PROFILE_MODEL_PL_UTF8_KEY, DEFAULT_PL_UTF8); p[PROFILE_MODEL_INF_KEY] = subGroup.readEntry(PROFILE_MODEL_INF_KEY, DEFAULT_INF); p[PROFILE_MODEL_INF_TEXT_KEY] = subGroup.readEntry(PROFILE_MODEL_INF_TEXT_KEY, DEFAULT_INF_TEXT); p[PROFILE_MODEL_INF_NAME_KEY] = subGroup.readEntry(PROFILE_MODEL_INF_NAME_KEY, DEFAULT_INF_NAME); p[PROFILE_MODEL_INF_SUFFIX_KEY] = subGroup.readEntry(PROFILE_MODEL_INF_SUFFIX_KEY, DEFAULT_INF_SUFFIX); p[PROFILE_MODEL_HL_KEY] = subGroup.readEntry(PROFILE_MODEL_HL_KEY, DEFAULT_HL); p[PROFILE_MODEL_HL_FORMAT_KEY] = subGroup.readEntry(PROFILE_MODEL_HL_FORMAT_KEY, DEFAULT_HL_FORMAT); p[PROFILE_MODEL_HL_NAME_KEY] = subGroup.readEntry(PROFILE_MODEL_HL_NAME_KEY, DEFAULT_HL_NAME); p[PROFILE_MODEL_CUE_KEY] = subGroup.readEntry(PROFILE_MODEL_CUE_KEY, DEFAULT_CUE); p[PROFILE_MODEL_CUE_NAME_KEY] = subGroup.readEntry(PROFILE_MODEL_CUE_NAME_KEY, DEFAULT_CUE_NAME); p[PROFILE_MODEL_SF_KEY] = subGroup.readEntry(PROFILE_MODEL_SF_KEY, DEFAULT_SF); p[PROFILE_MODEL_SF_NAME_KEY] = subGroup.readEntry(PROFILE_MODEL_SF_NAME_KEY, DEFAULT_SF_NAME); p[PROFILE_MODEL_COLUMN_ENCODER_LAME_PARAMETERS_KEY] = subGroup.readEntry(PROFILE_MODEL_COLUMN_ENCODER_LAME_PARAMETERS_KEY, DEFAULT_ENCODER_PARAMETERS); p[PROFILE_MODEL_COLUMN_ENCODER_OGGENC_PARAMETERS_KEY] = subGroup.readEntry(PROFILE_MODEL_COLUMN_ENCODER_OGGENC_PARAMETERS_KEY, DEFAULT_ENCODER_PARAMETERS); p[PROFILE_MODEL_COLUMN_ENCODER_FLAC_PARAMETERS_KEY] = subGroup.readEntry(PROFILE_MODEL_COLUMN_ENCODER_FLAC_PARAMETERS_KEY, DEFAULT_ENCODER_PARAMETERS); p[PROFILE_MODEL_COLUMN_ENCODER_FAAC_PARAMETERS_KEY] = subGroup.readEntry(PROFILE_MODEL_COLUMN_ENCODER_FAAC_PARAMETERS_KEY, DEFAULT_ENCODER_PARAMETERS); p[PROFILE_MODEL_COLUMN_ENCODER_WAVE_PARAMETERS_KEY] = subGroup.readEntry(PROFILE_MODEL_COLUMN_ENCODER_WAVE_PARAMETERS_KEY, DEFAULT_ENCODER_PARAMETERS); p[PROFILE_MODEL_COLUMN_ENCODER_CUSTOM_PARAMETERS_KEY] = subGroup.readEntry(PROFILE_MODEL_COLUMN_ENCODER_CUSTOM_PARAMETERS_KEY, DEFAULT_ENCODER_PARAMETERS); p_cache.append(p); } if (profileCount>0) { if (p_current_profile_index==-1) p_current_profile_index = 0; emit profilesRemovedOrInserted(); } } diff --git a/utils/cachedimage.cpp b/utils/cachedimage.cpp index 29bd88e..2bd0ce9 100644 --- a/utils/cachedimage.cpp +++ b/utils/cachedimage.cpp @@ -1,225 +1,225 @@ /* AUDEX CDDA EXTRACTOR * Copyright (C) 2007-2015 Marco Nelles (audex@maniatek.com) * * * This program 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. * * This program 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 this program. If not, see . */ #include "cachedimage.h" #include #include #include #include CachedImage::CachedImage() { } CachedImage::CachedImage(const QByteArray& data) { load(data); } CachedImage::CachedImage(const QString& filename) { load(filename); } CachedImage::CachedImage(const CachedImage& other) { _data = other._data; _format = other._format; mime_cache = other.mime_cache; } CachedImage& CachedImage::operator=(const CachedImage& other) { _data = other._data; _format = other._format; mime_cache = other.mime_cache; return *this; } bool CachedImage::operator==(const CachedImage& other) const { return (this->checksum() == other.checksum()); } bool CachedImage::operator!=(const CachedImage& other) const { return (this->checksum() != other.checksum()); } CachedImage::~CachedImage() { }; Error CachedImage::lastError() const { return _error; } bool CachedImage::isEmpty() const { return (_data.size()==0); } const QByteArray CachedImage::formatRaw() const { return _format; } int CachedImage::dataSize(const QByteArray& format, const QSize& size) { if ((compare_format(format, _format) || (format.isEmpty())) && ((size.isNull()) || (size == _size))) { return _data.size(); } else { QByteArray ba; QBuffer buffer(&ba); buffer.open(QIODevice::WriteOnly); _save(&buffer, format, size); buffer.close(); return ba.size(); } } const QByteArray CachedImage::coverRaw() const { return _data; } const QSize CachedImage::size() const { return _size; } const QImage CachedImage::coverImage() const { return QImage::fromData(_data); } quint16 CachedImage::checksum() const { return qChecksum(_data.data(), _data.size()); } const QString CachedImage::supportedMimeTypeList() { if (mime_cache.isEmpty()) { QList supp_list = QImageReader::supportedImageFormats(); QMap map; QMimeDatabase db; QMimeType mime = db.mimeTypeForData(QByteArray("")); for (int i = 0; i < supp_list.count(); ++i) { map[db.mimeTypeForUrl("dummy."+QString(supp_list[i]).toLower()).comment()].append("*."+QString(supp_list[i]).toLower()); } QString result = "*.jpg *.jpeg *.png *.gif|"+i18n("Common image formats")+" (*.jpg, *.jpeg, *.png, *.gif)"; QMap::const_iterator i = map.constBegin(); while (i != map.constEnd()) { if (i.key()==mime.comment()) { ++i; continue; } - result += "\n"; + result += '\n'; QStringList extensions = i.value(); extensions.removeDuplicates(); - result += extensions.join(" ")+"|"+i.key()+" ("+extensions.join(", ")+")"; + result += extensions.join(' ')+'|'+i.key()+" ("+extensions.join(", ")+')'; ++i; } mime_cache = result; } return mime_cache; } const QList CachedImage::supportedFormats() { return QImageReader::supportedImageFormats(); } bool CachedImage::load(const QByteArray& data) { QBuffer buffer((QByteArray*)&data); buffer.open(QIODevice::ReadOnly); QImageReader ir(&buffer); _format = ir.format(); _size = ir.size(); buffer.close(); qDebug() << "Load cover image from buffer (" << _format << ")"; if (!_format.isEmpty() && QImageReader::supportedImageFormats().contains(_format)) { _data = data; return true; } _format = ""; _size = QSize(); return false; } bool CachedImage::load(const QString& filename) { QFile file(filename); if (!file.exists()) { _error = Error(i18n("File does not exist."), i18n("Please check if the file really exists."), Error::ERROR); return false; } QImageReader ir(filename); _format = ir.format(); _size = ir.size(); qDebug() << "Load cover image from file (" << _format << ")"; if (!_format.isEmpty() && QImageReader::supportedImageFormats().contains(_format)) { if (!file.open(QIODevice::ReadOnly)) { _error = Error(i18n("Cannot open file."), i18n("Please check your file. Maybe you do not have proper permissions."), Error::ERROR); return false; } _data = file.readAll(); file.close(); } else { _error = Error(i18n("Unsupported image format"), i18n("Please check your file. Maybe it is corrupted. Otherwise try to convert your cover image with an external program to a common file format like JPEG."), Error::ERROR); _format = ""; _size = QSize(); return false; } _error = Error(); return true; } void CachedImage::clear() { _data.clear(); _format.clear(); } bool CachedImage::save(const QString& filename, const QSize& size) { QFile file(filename); if (!file.open(QIODevice::WriteOnly)) { _error = Error(i18n("Cannot open file"), i18n("Please check your permissions."), Error::ERROR); return false; } QMimeDatabase db; QByteArray format = db.suffixForFileName(filename).toLower().toAscii(); if ((compare_format(format, _format) || (format.isEmpty())) && ((size.isNull()) || (size == _size))) { qint64 r = file.write(_data); if ((r==-1) || (r < _data.size())) { _error = Error(i18n("Cannot save file"), i18n("Please check your permissions. Do you have enough space?"), Error::ERROR); file.close(); return false; } } else { if (!_save(&file, format, size)) { file.close(); return false; } } file.close(); _error = Error(); return true; } bool CachedImage::compare_format(const QByteArray& f1, const QByteArray& f2) const { if (((f1.toLower() == "jpg") || (f1.toLower() == "jpeg")) && ((f2.toLower() == "jpg") || (f2.toLower() == "jpeg"))) return true; if (((f1.toLower() == "tif") || (f1.toLower() == "tiff")) && ((f2.toLower() == "tif") || (f2.toLower() == "tiff"))) return true; return (f1.toLower() == f2.toLower()); } bool CachedImage::_save(QIODevice *device, const QByteArray& format, const QSize& size) { if ((!format.isEmpty()) && (!QImageReader::supportedImageFormats().contains(format))) { _error = Error(i18n("Unsupported image format"), i18n("Please use common image formats like JPEG, PNG or GIF as they are supported on almost all systems."), Error::ERROR); return false; } QImage image = QImage::fromData(_data); if ((size.isValid()) && (image.size() != size)) image = image.scaled(size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); bool ok; if (!format.isEmpty()) ok = image.save(device, format.data()); else ok = image.save(device); if (!ok) { _error = Error(i18n("Cannot write on device"), i18n("Please check your permissions. Do you have enough space on your device?"), Error::ERROR); return false; } _error = Error(); return true; } diff --git a/utils/coverfetcher.cpp b/utils/coverfetcher.cpp index 70e70f0..58dda1d 100644 --- a/utils/coverfetcher.cpp +++ b/utils/coverfetcher.cpp @@ -1,253 +1,253 @@ /* AUDEX CDDA EXTRACTOR * Copyright (C) 2007-2015 Marco Nelles (audex@maniatek.com) * * * This program 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. * * This program 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 this program. If not, see . */ /* Some of this code is inspired by amarok 1.4.7 * (C) 2004 Mark Kretschmann * (C) 2004 Stefan Bogner * (C) 2004 Max Howell */ #include "coverfetcher.h" #include #include #include #include CoverFetcher::CoverFetcher(QObject *parent) : QObject(parent) { Q_UNUSED(parent); _status = NOS; f_i = 0; } CoverFetcher::~CoverFetcher() { clear(); } void CoverFetcher::fetched_external_ip(KJob* job) { qDebug() << "got IP..."; if (!job) { qDebug() << "no job error ..."; emit nothingFetched(); return; } else if (job && job->error()) { qDebug() << "reply error ..."; emit nothingFetched(); return; } // http://www.telize.com/ip returns plaintext ip address KIO::StoredTransferJob* const storedJob = static_cast(job); external_ip = ((QString) storedJob->data()).trimmed(); qDebug() << "IP " << external_ip; // Max images per request on Google API is 8, thus the std::min QString url; url= QString("https://ajax.googleapis.com/ajax/services/search/images?v=1.0&q=%1&rsz=%2&userip=%3") .arg(QUrl::toPercentEncoding(search_string, "/").data()) .arg(std::min(fetch_no,8)) .arg(QUrl::toPercentEncoding(external_ip).data()); qDebug() << "searching covers (" << url << ")..."; _status = SEARCHING; emit statusChanged(SEARCHING); job = KIO::storedGet(url); connect(job, SIGNAL(result(KJob*)), SLOT(fetched_html_data(KJob*))); } void CoverFetcher::startFetchThumbnails(const QString& searchstring, const int fetchNo) { qDebug() << "Fetch Thumbs ..."; if (_status != NOS || fetchNo == 0) { emit nothingFetched(); return; } fetch_no = fetchNo; search_string = searchstring; - search_string.replace("&", ""); + search_string.replace('&', ""); // Google requires the user IP QString url("http://www.telize.com/ip"); job = KIO::storedGet(url); connect(job, SIGNAL(result(KJob*)), SLOT(fetched_external_ip(KJob*))); } void CoverFetcher::stopFetchThumbnails() { if ((_status != FETCHING_THUMBNAIL) && (_status != SEARCHING)) return; if (job) job->kill(); _status = NOS; emit statusChanged(NOS); } void CoverFetcher::startFetchCover(const int no) { if (_status != NOS) return; if ((cover_urls.count()==0) || (no >= cover_urls.count()) || (no < 0)) { emit nothingFetched(); return; } qDebug() << "fetching cover..."; _status = FETCHING_COVER; emit statusChanged(FETCHING_COVER); job = KIO::storedGet(QUrl(cover_urls[no])); connect(job, SIGNAL(result(KJob*)), SLOT(fetched_html_data(KJob*))); } const QByteArray CoverFetcher::thumbnail(int index) { if ((index < 0) || (index >= cover_thumbnails.count())) return QByteArray(); return cover_thumbnails[index]; } const QString CoverFetcher::caption(int index) { if ((index < 0) || (index >= cover_names.count())) return QString(); return cover_names[index]; } void CoverFetcher::fetched_html_data(KJob* job) { QByteArray buffer; if (job && job->error()) { qDebug() << "There was an error communicating with Google. "<< job->errorString(); emit error(i18n("There was an error communicating with Google."), i18n("Try again later. Otherwise make a bug report.")); _status = NOS; emit statusChanged(NOS); emit nothingFetched(); return; } if (job) { KIO::StoredTransferJob* const storedJob = static_cast(job); buffer = storedJob->data(); } if (buffer.count() == 0) { qDebug() << "Google server: empty response"; emit error(i18n("Google server: Empty response."), i18n("Try again later. Make a bug report.")); _status = NOS; emit statusChanged(NOS); return; } switch (_status) { case SEARCHING : { qDebug() << "searching finished."; //qDebug() << QString::fromUtf8(buffer.data()); parse_html_response(QString::fromUtf8(buffer.data())); _status = NOS; emit statusChanged(NOS); fetch_cover_thumbnail(); } break; case FETCHING_THUMBNAIL : { qDebug() << "cover thumbnail fetched."; cover_thumbnails.append(buffer); emit fetchedThumbnail(buffer, cover_names[f_i], f_i+1); ++f_i; if (((fetch_no > -1) && (f_i == fetch_no)) || (cover_urls_thumbnails.count() == 0)) { _status = NOS; emit statusChanged(NOS); f_i = 0; emit allCoverThumbnailsFetched(); } else { fetch_cover_thumbnail(); } } break; case FETCHING_COVER : { qDebug() << "cover fetched."; _status = NOS; emit statusChanged(NOS); emit fetchedCover(buffer); } break; case NOS : break; } } void CoverFetcher::parse_html_response(const QString& xml) { cover_urls_thumbnails.clear(); cover_urls.clear(); cover_names.clear(); cover_tbnids.clear(); cover_thumbnails.clear(); QScriptValue responseData; QScriptEngine engine; - responseData = engine.evaluate("("+xml+")"); + responseData = engine.evaluate('('+xml+')'); QScriptValue resultsData=responseData.property("responseData").property("results"); if (resultsData.isArray()) { QScriptValueIterator it(resultsData); while (it.hasNext()) { it.next(); if (it.flags() & QScriptValue::SkipInEnumeration) continue; QScriptValue entry = it.value(); QString link = QUrl::fromPercentEncoding(entry.property("url").toString().toAscii()); QString thumbUrl = QUrl::fromPercentEncoding(entry.property("tbUrl").toString().toAscii()); QString w = entry.property("width").toString(); QString h = entry.property("height").toString(); cover_urls << link; cover_names << i18n("%1x%2", w, h); cover_urls_thumbnails << thumbUrl; qDebug() << "URL " << link << "- " << thumbUrl<< " -"< * * This program 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. * * This program 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 this program. If not, see . */ #include "encoderassistant.h" long makeVersionNumber(int major, int minor, int patch) { long versionNumber= ((major & 0xFF) << 16) | ((minor & 0xFF) << 8) | (patch & 0xFF); return versionNumber; } const QString EncoderAssistant::name(const EncoderAssistant::Encoder encoder) { switch (encoder) { case EncoderAssistant::LAME : return ENCODER_LAME_NAME; case EncoderAssistant::OGGENC : return ENCODER_OGGENC_NAME; case EncoderAssistant::FLAC : return ENCODER_FLAC_NAME; case EncoderAssistant::FAAC : return ENCODER_FAAC_NAME; case EncoderAssistant::WAVE : return ENCODER_WAVE_NAME; case EncoderAssistant::CUSTOM : return ENCODER_CUSTOM_NAME; default : return ""; } return ""; } const QString EncoderAssistant::encoderName(const Encoder encoder) { switch (encoder) { case EncoderAssistant::LAME : return ENCODER_LAME_ENCODER_NAME; case EncoderAssistant::OGGENC : return ENCODER_OGGENC_ENCODER_NAME; case EncoderAssistant::FLAC : return ENCODER_FLAC_ENCODER_NAME; case EncoderAssistant::FAAC : return ENCODER_FAAC_ENCODER_NAME; case EncoderAssistant::WAVE : return ENCODER_WAVE_ENCODER_NAME; case EncoderAssistant::CUSTOM : return ENCODER_CUSTOM_ENCODER_NAME; default : return ""; } return ""; } const QString EncoderAssistant::icon(const EncoderAssistant::Encoder encoder) { switch (encoder) { case EncoderAssistant::LAME : return ENCODER_LAME_ICON; case EncoderAssistant::OGGENC : return ENCODER_OGGENC_ICON; case EncoderAssistant::FLAC : return ENCODER_FLAC_ICON; case EncoderAssistant::FAAC : return ENCODER_FAAC_ICON; case EncoderAssistant::WAVE : return ENCODER_WAVE_ICON; case EncoderAssistant::CUSTOM : return ENCODER_CUSTOM_ICON; default : return ""; } return ""; } bool EncoderAssistant::available(const EncoderAssistant::Encoder encoder) { switch (encoder) { case EncoderAssistant::LAME : return (KProcess::execute(ENCODER_LAME_BIN, QStringList() << ENCODER_LAME_VERSION_PARA)==0); case EncoderAssistant::OGGENC : return (KProcess::execute(ENCODER_OGGENC_BIN, QStringList() << ENCODER_OGGENC_VERSION_PARA)==0); case EncoderAssistant::FLAC : return (KProcess::execute(ENCODER_FLAC_BIN, QStringList() << ENCODER_FLAC_VERSION_PARA)==0); case EncoderAssistant::FAAC : return (KProcess::execute(ENCODER_FAAC_BIN, QStringList() << ENCODER_FAAC_VERSION_PARA)==1); case EncoderAssistant::WAVE : return (KProcess::execute(ENCODER_WAVE_BIN, QStringList() << ENCODER_WAVE_VERSION_PARA)==0); case EncoderAssistant::CUSTOM : return true; default : return false; } return false; } bool EncoderAssistant::canEmbedCover(const Encoder encoder, int *maxCoverSize) { switch (encoder) { case EncoderAssistant::LAME : if (maxCoverSize) *maxCoverSize = ENCODER_LAME_MAX_EMBED_COVER_SIZE; return true; case EncoderAssistant::OGGENC : case EncoderAssistant::FLAC : return true; case EncoderAssistant::FAAC : case EncoderAssistant::WAVE : case EncoderAssistant::CUSTOM : default : break; } if (maxCoverSize) *maxCoverSize = 0; return false; } const QString EncoderAssistant::version(const EncoderAssistant::Encoder encoder) { KProcess process; process.setOutputChannelMode(KProcess::SeparateChannels); process.setReadChannel(KProcess::StandardError); switch (encoder) { - case EncoderAssistant::LAME : process.setShellCommand(QString(ENCODER_LAME_BIN)+" "+QString(ENCODER_LAME_VERSION_PARA)); break; - case EncoderAssistant::OGGENC : process.setShellCommand(QString(ENCODER_OGGENC_BIN)+" "+QString(ENCODER_OGGENC_VERSION_PARA)); break; - case EncoderAssistant::FLAC : process.setShellCommand(QString(ENCODER_FLAC_BIN)+" "+QString(ENCODER_FLAC_VERSION_PARA)); break; - case EncoderAssistant::FAAC : process.setShellCommand(QString(ENCODER_FAAC_BIN)+" "+QString(ENCODER_FAAC_VERSION_PARA)); break; + case EncoderAssistant::LAME : process.setShellCommand(QString(ENCODER_LAME_BIN)+' '+QString(ENCODER_LAME_VERSION_PARA)); break; + case EncoderAssistant::OGGENC : process.setShellCommand(QString(ENCODER_OGGENC_BIN)+' '+QString(ENCODER_OGGENC_VERSION_PARA)); break; + case EncoderAssistant::FLAC : process.setShellCommand(QString(ENCODER_FLAC_BIN)+' '+QString(ENCODER_FLAC_VERSION_PARA)); break; + case EncoderAssistant::FAAC : process.setShellCommand(QString(ENCODER_FAAC_BIN)+' '+QString(ENCODER_FAAC_VERSION_PARA)); break; case EncoderAssistant::WAVE : return ""; case EncoderAssistant::CUSTOM : return ""; default : return ""; } process.start(); if (!process.waitForFinished()) return ""; QByteArray rawoutput = process.readAllStandardError(); if (rawoutput.size() == 0) rawoutput = process.readAllStandardOutput(); QString output(rawoutput); - QStringList list = output.trimmed().split("\n"); + QStringList list = output.trimmed().split('\n'); if (list.count()==0) return ""; - QStringList words = list[0].split(" "); + QStringList words = list[0].split(' '); if (words.count()==0) return ""; switch (encoder) { case EncoderAssistant::LAME : if ((words.contains("version")) && (words.indexOf("version")+1 0) { major = version[0].toUInt(); versionNumber = (major & 0xFF) << 16; } if (version.count() > 1) { minor = version[1].toUInt(); versionNumber = versionNumber | (minor & 0xFF) << 8; } if (version.count() > 2) { patch = version[2].toUInt(); versionNumber = versionNumber | (patch & 0xFF); } } break; case EncoderAssistant::WAVE : case EncoderAssistant::CUSTOM : default : ; } return versionNumber; } const QString EncoderAssistant::pattern(const EncoderAssistant::Encoder encoder, const Parameters& parameters) { switch (encoder) { case EncoderAssistant::LAME : { int preset = parameters.valueToInt(ENCODER_LAME_PRESET_KEY, ENCODER_LAME_PRESET); bool cbr = parameters.valueToBool(ENCODER_LAME_CBR_KEY); int bitrate = parameters.valueToInt(ENCODER_LAME_BITRATE_KEY, ENCODER_LAME_BITRATE); bool embed_cover = parameters.valueToBool(ENCODER_LAME_EMBED_COVER_KEY); QString cmd = ENCODER_LAME_BIN; switch (preset) { case 0 : cmd += " --preset medium"; break; case 1 : cmd += " --preset standard"; break; case 2 : cmd += " --preset extreme"; break; case 3 : cmd += " --preset insane"; break; case 4 : cmd += QString(" --preset")+(cbr?QString(" cbr"):QString())+QString(" %1").arg(bitrate); break; default : cmd += " --preset standard"; } QString v = EncoderAssistant::version(EncoderAssistant::LAME); if ((v.startsWith("3.95")) || (v.startsWith("3.96")) || (v.startsWith("3.97"))) { cmd += QString(" --vbr-new"); } //if we have eyeD3, use this for tagging as lame can't handle unicode if (KProcess::execute(ENCODER_LAME_HELPER_TAG, QStringList() << ENCODER_LAME_HELPER_TAG_VERSION_PARA) == 0) { cmd += QString::fromUtf8(" $" VAR_INPUT_FILE" $" VAR_OUTPUT_FILE); cmd += QString::fromUtf8(" && eyeD3 -t \"$" VAR_TRACK_TITLE"\" -a \"$" VAR_TRACK_ARTIST"\" --set-text-frame=TPE2:\"$" VAR_ALBUM_ARTIST"\" -A \"$" VAR_ALBUM_TITLE \ "\" -Y \"$" VAR_DATE"\" -n $" VAR_TRACK_NO" -N $" VAR_NO_OF_TRACKS" --set-text-frame=\"TCON:$" VAR_GENRE"\" "\ "--set-text-frame=TSSE:\"$" VAR_AUDEX" / Encoder $" VAR_ENCODER"\" ${" VAR_CD_NO" pre=\"--set-text-frame=TPOS:\"}"); if (embed_cover) { cmd += QString::fromUtf8(" ${" VAR_COVER_FILE" pre=\"--add-image=\" post=\":FRONT_COVER\"}"); } cmd += QString::fromUtf8(" --set-encoding=latin1 $" VAR_OUTPUT_FILE" && eyeD3 --to-v2.3 $" VAR_OUTPUT_FILE); } else { if (embed_cover) { cmd += QString::fromUtf8(" ${" VAR_COVER_FILE" pre=\"--ti \"}"); } cmd += QString::fromUtf8(" --add-id3v2 --id3v2-only --ignore-tag-errors --tt \"$" VAR_TRACK_TITLE"\" --ta \"$" VAR_TRACK_ARTIST \ "\" --tl \"$" VAR_ALBUM_TITLE"\" --ty \"$" VAR_DATE"\" --tn \"$" VAR_TRACK_NO"/$" VAR_NO_OF_TRACKS"\" --tc \"$" VAR_AUDEX" / Encoder $" VAR_ENCODER"\" "\ "--tg \"$" VAR_GENRE"\" ${" VAR_CD_NO" pre=\"--tv TPOS=\"}"\ " $" VAR_INPUT_FILE" $" VAR_OUTPUT_FILE); } return cmd; } case EncoderAssistant::OGGENC : { double quality = parameters.valueToDouble(ENCODER_OGGENC_QUALITY_KEY, ENCODER_OGGENC_QUALITY); bool min_bitrate = parameters.valueToBool(ENCODER_OGGENC_MINBITRATE_KEY); int min_bitrate_value = parameters.valueToInt(ENCODER_OGGENC_MINBITRATE_VALUE_KEY, ENCODER_OGGENC_MINBITRATE_VALUE); bool max_bitrate = parameters.valueToBool(ENCODER_OGGENC_MAXBITRATE_KEY); int max_bitrate_value = parameters.valueToInt(ENCODER_OGGENC_MAXBITRATE_VALUE_KEY, ENCODER_OGGENC_MAXBITRATE_VALUE); QString cmd = ENCODER_OGGENC_BIN; cmd += QString(" -q %1").arg(quality, 0, 'f', 2); if (min_bitrate) { cmd += QString(" -m %1").arg(min_bitrate_value); } if (max_bitrate) { cmd += QString(" -M %1").arg(max_bitrate_value); } cmd += QString::fromUtf8(" -c \"Artist=$" VAR_TRACK_ARTIST"\" -c \"Title=$" VAR_TRACK_TITLE"\" -c \"Album=$" VAR_ALBUM_TITLE\ "\" -c \"Date=$" VAR_DATE"\" -c \"Tracknumber=$" VAR_TRACK_NO"\" -c \"Genre=$" VAR_GENRE\ "\" ${" VAR_CD_NO" pre=\"-c Discnumber=\"}"\ " -o $" VAR_OUTPUT_FILE" $" VAR_INPUT_FILE); return cmd; } case EncoderAssistant::FLAC : { int compression = parameters.valueToInt(ENCODER_FLAC_COMPRESSION_KEY, ENCODER_FLAC_COMPRESSION); bool embed_cover = parameters.valueToBool(ENCODER_FLAC_EMBED_COVER_KEY); QString cmd = ENCODER_FLAC_BIN; if (embed_cover) { long versionNumber=EncoderAssistant::versionNumber(EncoderAssistant::FLAC); if (versionNumber >= makeVersionNumber(1,1,3) ) { cmd += QString::fromUtf8(" --picture=\\|\\|\\|\\|$" VAR_COVER_FILE); } } cmd += QString(" -%1").arg(compression); cmd += QString::fromUtf8(" -T Artist=\"$" VAR_TRACK_ARTIST"\" -T Title=\"$" VAR_TRACK_TITLE"\" -T Album=\"$" VAR_ALBUM_TITLE\ "\" -T Date=\"$" VAR_DATE"\" -T Tracknumber=\"$" VAR_TRACK_NO"\" -T Genre=\"$" VAR_GENRE\ "\" -o $" VAR_OUTPUT_FILE" $" VAR_INPUT_FILE); return cmd; } case EncoderAssistant::FAAC : { int quality = parameters.valueToInt(ENCODER_FAAC_QUALITY_KEY, ENCODER_FAAC_QUALITY); QString cmd = ENCODER_FAAC_BIN; cmd += QString(" -q %1").arg(quality); cmd += QString::fromUtf8(" --title \"$" VAR_TRACK_TITLE"\" --artist \"$" VAR_TRACK_ARTIST"\" --album \"$" VAR_ALBUM_TITLE\ "\" --year \"$" VAR_DATE"\" --track $" VAR_TRACK_NO" ${" VAR_CD_NO" pre=\"--disc \"} --genre \"$" VAR_GENRE\ "\" -o $" VAR_OUTPUT_FILE" $" VAR_INPUT_FILE); return cmd; } case EncoderAssistant::WAVE : { return QString(ENCODER_WAVE_BIN)+" $" VAR_INPUT_FILE" $" VAR_OUTPUT_FILE; } case EncoderAssistant::CUSTOM : { return parameters.value(ENCODER_CUSTOM_COMMAND_PATTERN_KEY, ENCODER_CUSTOM_COMMAND_PATTERN); } default : ; } return ""; } Parameters EncoderAssistant::stdParameters(const Encoder encoder, const Quality quality) { Parameters parameters; switch (encoder) { case EncoderAssistant::LAME : switch (quality) { case NORMAL : parameters.setValue(ENCODER_LAME_PRESET_KEY, ENCODER_LAME_PRESET); parameters.setValue(ENCODER_LAME_EMBED_COVER_KEY, ENCODER_LAME_EMBED_COVER); parameters.setValue(ENCODER_LAME_BITRATE_KEY, ENCODER_LAME_BITRATE); parameters.setValue(ENCODER_LAME_EMBED_COVER_KEY, ENCODER_LAME_EMBED_COVER); break; case MOBILE : parameters.setValue(ENCODER_LAME_PRESET_KEY, ENCODER_LAME_PRESET_M); parameters.setValue(ENCODER_LAME_EMBED_COVER_KEY, ENCODER_LAME_EMBED_COVER_M); parameters.setValue(ENCODER_LAME_BITRATE_KEY, ENCODER_LAME_BITRATE_M); parameters.setValue(ENCODER_LAME_EMBED_COVER_KEY, ENCODER_LAME_EMBED_COVER_M); break; case EXTREME : parameters.setValue(ENCODER_LAME_PRESET_KEY, ENCODER_LAME_PRESET_X); parameters.setValue(ENCODER_LAME_EMBED_COVER_KEY, ENCODER_LAME_EMBED_COVER_X); parameters.setValue(ENCODER_LAME_BITRATE_KEY, ENCODER_LAME_BITRATE_X); parameters.setValue(ENCODER_LAME_EMBED_COVER_KEY, ENCODER_LAME_EMBED_COVER_X); break; } break; case EncoderAssistant::OGGENC : switch (quality) { case NORMAL : parameters.setValue(ENCODER_OGGENC_QUALITY_KEY, ENCODER_OGGENC_QUALITY); parameters.setValue(ENCODER_OGGENC_MINBITRATE_KEY, ENCODER_OGGENC_MINBITRATE); parameters.setValue(ENCODER_OGGENC_MINBITRATE_VALUE_KEY, ENCODER_OGGENC_MINBITRATE_VALUE); parameters.setValue(ENCODER_OGGENC_MAXBITRATE_KEY, ENCODER_OGGENC_MAXBITRATE); parameters.setValue(ENCODER_OGGENC_MAXBITRATE_VALUE_KEY, ENCODER_OGGENC_MAXBITRATE_VALUE); break; case MOBILE : parameters.setValue(ENCODER_OGGENC_QUALITY_KEY, ENCODER_OGGENC_QUALITY_M); parameters.setValue(ENCODER_OGGENC_MINBITRATE_KEY, ENCODER_OGGENC_MINBITRATE_M); parameters.setValue(ENCODER_OGGENC_MINBITRATE_VALUE_KEY, ENCODER_OGGENC_MINBITRATE_VALUE_M); parameters.setValue(ENCODER_OGGENC_MAXBITRATE_KEY, ENCODER_OGGENC_MAXBITRATE_M); parameters.setValue(ENCODER_OGGENC_MAXBITRATE_VALUE_KEY, ENCODER_OGGENC_MAXBITRATE_VALUE_M); break; case EXTREME : parameters.setValue(ENCODER_OGGENC_QUALITY_KEY, ENCODER_OGGENC_QUALITY_X); parameters.setValue(ENCODER_OGGENC_MINBITRATE_KEY, ENCODER_OGGENC_MINBITRATE_X); parameters.setValue(ENCODER_OGGENC_MINBITRATE_VALUE_KEY, ENCODER_OGGENC_MINBITRATE_VALUE_X); parameters.setValue(ENCODER_OGGENC_MAXBITRATE_KEY, ENCODER_OGGENC_MAXBITRATE_X); parameters.setValue(ENCODER_OGGENC_MAXBITRATE_VALUE_KEY, ENCODER_OGGENC_MAXBITRATE_VALUE_X); break; } break; case EncoderAssistant::FLAC : parameters.setValue(ENCODER_FLAC_COMPRESSION_KEY, ENCODER_FLAC_COMPRESSION); parameters.setValue(ENCODER_FLAC_EMBED_COVER_KEY, ENCODER_FLAC_EMBED_COVER); break; case EncoderAssistant::FAAC : switch (quality) { case NORMAL : parameters.setValue(ENCODER_FAAC_QUALITY_KEY, ENCODER_FAAC_QUALITY); break; case MOBILE : parameters.setValue(ENCODER_FAAC_QUALITY_KEY, ENCODER_FAAC_QUALITY_M); break; case EXTREME : parameters.setValue(ENCODER_FAAC_QUALITY_KEY, ENCODER_FAAC_QUALITY_X); break; } break; case EncoderAssistant::WAVE : case EncoderAssistant::CUSTOM : default : ; } return parameters; } const QMap EncoderAssistant::encoderList() { QMap encoders; encoders[(int)EncoderAssistant::LAME] = ENCODER_LAME_NAME; encoders[(int)EncoderAssistant::OGGENC] = ENCODER_OGGENC_NAME; encoders[(int)EncoderAssistant::FLAC] = ENCODER_FLAC_NAME; encoders[(int)EncoderAssistant::FAAC] = ENCODER_FAAC_NAME; encoders[(int)EncoderAssistant::WAVE] = ENCODER_WAVE_NAME; encoders[(int)EncoderAssistant::CUSTOM] = ENCODER_CUSTOM_NAME; return encoders; } const QMap EncoderAssistant::availableEncoderNameList() { QMap encoders; if (EncoderAssistant::available(EncoderAssistant::LAME)) encoders[(int)EncoderAssistant::LAME] = ENCODER_LAME_NAME; if (EncoderAssistant::available(EncoderAssistant::OGGENC)) encoders[(int)EncoderAssistant::OGGENC] = ENCODER_OGGENC_NAME; if (EncoderAssistant::available(EncoderAssistant::FLAC)) encoders[(int)EncoderAssistant::FLAC] = ENCODER_FLAC_NAME; if (EncoderAssistant::available(EncoderAssistant::FAAC)) encoders[(int)EncoderAssistant::FAAC] = ENCODER_FAAC_NAME; if (EncoderAssistant::available(EncoderAssistant::WAVE)) encoders[(int)EncoderAssistant::WAVE] = ENCODER_WAVE_NAME; if (EncoderAssistant::available(EncoderAssistant::CUSTOM)) encoders[(int)EncoderAssistant::CUSTOM] = ENCODER_CUSTOM_NAME; return encoders; } const QMap EncoderAssistant::availableEncoderNameListWithVersions() { QMap encoders; - if (EncoderAssistant::available(EncoderAssistant::LAME)) encoders[(int)EncoderAssistant::LAME] = ENCODER_LAME_NAME+" "+version(LAME); - if (EncoderAssistant::available(EncoderAssistant::OGGENC)) encoders[(int)EncoderAssistant::OGGENC] = ENCODER_OGGENC_NAME+" "+version(OGGENC); - if (EncoderAssistant::available(EncoderAssistant::FLAC)) encoders[(int)EncoderAssistant::FLAC] = ENCODER_FLAC_NAME+" "+version(FLAC); - if (EncoderAssistant::available(EncoderAssistant::FAAC)) encoders[(int)EncoderAssistant::FAAC] = ENCODER_FAAC_NAME+" "+version(FAAC); - if (EncoderAssistant::available(EncoderAssistant::WAVE)) encoders[(int)EncoderAssistant::WAVE] = ENCODER_WAVE_NAME+" "+version(WAVE); - if (EncoderAssistant::available(EncoderAssistant::CUSTOM)) encoders[(int)EncoderAssistant::CUSTOM] = ENCODER_CUSTOM_NAME+" "+version(CUSTOM); + if (EncoderAssistant::available(EncoderAssistant::LAME)) encoders[(int)EncoderAssistant::LAME] = ENCODER_LAME_NAME+' '+version(LAME); + if (EncoderAssistant::available(EncoderAssistant::OGGENC)) encoders[(int)EncoderAssistant::OGGENC] = ENCODER_OGGENC_NAME+' '+version(OGGENC); + if (EncoderAssistant::available(EncoderAssistant::FLAC)) encoders[(int)EncoderAssistant::FLAC] = ENCODER_FLAC_NAME+' '+version(FLAC); + if (EncoderAssistant::available(EncoderAssistant::FAAC)) encoders[(int)EncoderAssistant::FAAC] = ENCODER_FAAC_NAME+' '+version(FAAC); + if (EncoderAssistant::available(EncoderAssistant::WAVE)) encoders[(int)EncoderAssistant::WAVE] = ENCODER_WAVE_NAME+' '+version(WAVE); + if (EncoderAssistant::available(EncoderAssistant::CUSTOM)) encoders[(int)EncoderAssistant::CUSTOM] = ENCODER_CUSTOM_NAME+' '+version(CUSTOM); return encoders; } diff --git a/utils/encoderwrapper.cpp b/utils/encoderwrapper.cpp index afb4223..9a64af0 100644 --- a/utils/encoderwrapper.cpp +++ b/utils/encoderwrapper.cpp @@ -1,169 +1,169 @@ /* AUDEX CDDA EXTRACTOR * Copyright (C) 2007-2015 Marco Nelles (audex@maniatek.com) * * * This program 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. * * This program 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 this program. If not, see . */ #include "encoderwrapper.h" #include EncoderWrapper::EncoderWrapper(QObject* parent, const QString& commandPattern, const QString& encoderName, const bool deleteFractionFiles) : QObject(parent) { command_pattern = commandPattern; encoder_name = encoderName; delete_fraction_files = deleteFractionFiles; connect(&proc, SIGNAL(readyReadStandardError()), this, SLOT(parseOutput())); connect(&proc, SIGNAL(readyReadStandardOutput()), this, SLOT(parseOutput())); connect(&proc, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(processFinished(int, QProcess::ExitStatus))); connect(&proc, SIGNAL(error(QProcess::ProcessError)), this, SLOT(processError(QProcess::ProcessError))); proc.setOutputChannelMode(KProcess::SeparateChannels); proc.setReadChannel(KProcess::StandardError); termination = false; processing = 0; not_found_counter = 0; } EncoderWrapper::~EncoderWrapper() { } bool EncoderWrapper::encode(int n, int cdno, int trackoffset, int nooftracks, const QString& artist, const QString& album, const QString& tartist, const QString& ttitle, const QString& genre, const QString& date, const QString& suffix, CachedImage *cover, bool fat_compatible, const QString& tmppath, const QString& input, const QString& output) { if (!processing) processing = 1; else return false; termination = false; if (command_pattern.isEmpty()) { emit error(i18n("Command pattern is empty.")); return false; } PatternParser patternparser; QString command = patternparser.parseCommandPattern(command_pattern, input, output, n, cdno, trackoffset, nooftracks, artist, album, tartist, ttitle, date, genre, suffix, cover, fat_compatible, tmppath, encoder_name); qDebug() << "executing command " << command; proc.setShellCommand(command); proc.start(); proc.waitForStarted(); processing_filename = output; emit info(i18n("Encoding track %1...", n)); return true; } void EncoderWrapper::cancel() { if (!processing) return; //we need to suppress normal error messages, because with a cancel the user known what he does termination = true; proc.terminate(); if (delete_fraction_files) { QFile file(processing_filename); if (file.exists()) { file.remove(); emit warning(i18n("Deleted partial file \"%1\".", processing_filename.mid(processing_filename.lastIndexOf("/")+1))); qDebug() << "deleted partial file" << processing_filename; } } emit error(i18n("User canceled encoding.")); qDebug() << "Interrupt encoding."; } bool EncoderWrapper::isProcessing() { return (processing>0); } const QStringList& EncoderWrapper::protocol() { return _protocol; } void EncoderWrapper::parseOutput() { QByteArray rawoutput = proc.readAllStandardError(); if (rawoutput.size() == 0) rawoutput = proc.readAllStandardOutput(); bool found = false; if (rawoutput.size() > 0) { - QString output(rawoutput); QStringList list = output.trimmed().split("\n"); + QString output(rawoutput); QStringList list = output.trimmed().split('\n'); _protocol << list; for (int i = 0; i < list.count(); ++i) { if (list.at(i).contains('%')) { QString line = list.at(i); int startPos = line.indexOf(QRegExp("\\d+[,.]?\\d*\\%")); if (startPos == -1) continue; QString p = line.mid(startPos); p = p.left(p.indexOf('%')); bool conversionSuccessful = false; double percent = p.toDouble(&conversionSuccessful); if ((conversionSuccessful) && (percent >= 0) && (percent <= 100)) { emit progress((int)percent); found = true; not_found_counter = 0; } } } } if (!found) { if (not_found_counter > 5) emit progress(-1); else ++not_found_counter; } } void EncoderWrapper::processFinished(int exitCode, QProcess::ExitStatus exitStatus) { processing = 0; if (termination) { emit finished(); return; } if ((exitStatus == QProcess::NormalExit) && (exitCode==0)) { emit info(i18n("Encoding OK (\"%1\").", processing_filename)); } else { emit error(i18n("An error occurred while encoding file \"%1\".", processing_filename), i18n("Please check your profile.")); } emit finished(); qDebug() << "encoding finished."; } void EncoderWrapper::processError(QProcess::ProcessError err) { if (termination) return; switch (err) { case QProcess::FailedToStart : emit error(i18n("%1 failed to start.", encoder), i18n("Either it is missing, or you may have insufficient permissions to invoke the program.")); break; case QProcess::Crashed : emit error(i18n("%1 crashed some time after starting successfully.", encoder), i18n("Please check your profile.")); break; case QProcess::Timedout : emit error(i18n("%1 timed out. This should not happen.", encoder), i18n("Please check your profile.")); break; case QProcess::WriteError : emit error(i18n("An error occurred when attempting to write to %1.", encoder), i18n("For example, the process may not be running, or it may have closed its input channel.")); break; case QProcess::ReadError : emit error(i18n("An error occurred when attempting to read from %1.", encoder), i18n("For example, the process may not be running.")); break; case QProcess::UnknownError : emit error(i18n("An unknown error occurred to %1. This should not happen.", encoder), i18n("Please check your profile.")); break; } emit finished(); qDebug() << "encoding finished."; } diff --git a/utils/hashlist.cpp b/utils/hashlist.cpp index 98f8807..9bc270d 100644 --- a/utils/hashlist.cpp +++ b/utils/hashlist.cpp @@ -1,81 +1,81 @@ /* AUDEX CDDA EXTRACTOR * Copyright (C) 2007-2015 Marco Nelles (audex@maniatek.com) * * * This program 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. * * This program 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 this program. If not, see . */ #include "hashlist.h" Hashlist::Hashlist() { } const QStringList Hashlist::getSFV(const QStringList& filenames) { QStringList list; for (int i = 0; i < filenames.count(); ++i) { //uses mmap for performance int fd = open(filenames.at(i).toUtf8().constData(), O_RDONLY); if (fd == -1) continue; quint64 size = lseek(fd, 0, SEEK_END); char *t_data = (char*)mmap(0, size, PROT_READ, MAP_SHARED, fd, 0); CRC32 crc32; crc32.update((const unsigned char *)t_data, (int)lseek(fd, 0, SEEK_END)); QFileInfo info(filenames.at(i)); - list << info.fileName()+" "+QString("%1").arg(crc32.result(), 0, 16); + list << info.fileName()+' '+QString("%1").arg(crc32.result(), 0, 16); close(fd); } return list; } const QStringList Hashlist::getMD5(const QStringList& filenames) { QStringList list; for (int i = 0; i < filenames.count(); ++i) { QFile file(filenames.at(i)); if (!file.exists()) continue; if (!file.open(QFile::ReadOnly)) continue; QCryptographicHash md5sum(QCryptographicHash::Md5); QByteArray buf; while (!file.atEnd()) { buf = file.read(16*1024); md5sum.addData(buf); } QFileInfo info(filenames.at(i)); list << QString("%1").arg(QString(md5sum.result().toHex()))+" "+info.fileName(); file.close(); } return list; } diff --git a/utils/patternparser.cpp b/utils/patternparser.cpp index 35b2d99..9f7e634 100644 --- a/utils/patternparser.cpp +++ b/utils/patternparser.cpp @@ -1,666 +1,666 @@ /* AUDEX CDDA EXTRACTOR * Copyright (C) 2007-2015 Marco Nelles (audex@maniatek.com) * * * This program 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. * * This program 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 this program. If not, see . */ #include "patternparser.h" #include #include SaxHandler::SaxHandler() : QXmlDefaultHandler() { trackno = 1; cdno = 0; trackoffset = 0; fat32compatible = false; discid = 0; size = 0; length = 0; nooftracks = 0; is_filename_pattern = false; is_command_pattern = false; is_simple_pattern = false; is_text_pattern = false; cover = NULL; /*TEMP*/found_suffix = false; } SaxHandler::~SaxHandler() { } bool SaxHandler::startElement(const QString& namespaceURI, const QString &localName, const QString& qName, const QXmlAttributes& atts) { Q_UNUSED(namespaceURI); Q_UNUSED(localName); if (qName == VAR_FILENAME_PATTERN) { is_filename_pattern = true; return true; } if (qName == VAR_COMMAND_PATTERN) { is_command_pattern = true; return true; } if (qName == VAR_SIMPLE_PATTERN) { is_simple_pattern = true; return true; } if (qName == VAR_TEXT_PATTERN) { is_text_pattern = true; return true; } p_element.clear(); if (qName == VAR_ALBUM_ARTIST) { if ((is_filename_pattern) || (is_simple_pattern)) { QString s = artist; if ((fat32compatible) || (IS_TRUE(atts.value("fat32compatible")))) s = make_fat32_compatible(s); else s = make_compatible(s); if ((replacespaceswithunderscores) || (IS_TRUE(atts.value("underscores")))) s = replace_spaces_with_underscores(s); // int QString::toInt(bool *ok, int base) const // If a conversion error occurs, *\a{ok} is set to \c false; otherwise // *\a{ok} is set to \c true. // http://code.qt.io/cgit/qt/qtbase.git/tree/src/corelib/tools/qstring.cpp#n6418 bool ok; int left = atts.value("left").toInt(&ok); if ((ok) && (left > 0)) s = s.left(left); if (IS_TRUE(atts.value("replace_char_list"))) s = replace_char_list(atts, s); if (IS_TRUE(atts.value("lowercase"))) s = s.toLower(); else if (IS_TRUE(atts.value("uppercase"))) s = s.toUpper(); p_element += s; } else if (is_command_pattern) { p_element += make_compatible_2(artist); } else { p_element += artist; } } if (qName == VAR_ALBUM_TITLE) { if ((is_filename_pattern) || (is_simple_pattern)) { QString s = title; if ((fat32compatible) || (IS_TRUE(atts.value("fat32compatible")))) s = make_fat32_compatible(s); else s = make_compatible(s); if ((replacespaceswithunderscores) || (IS_TRUE(atts.value("underscores")))) s = replace_spaces_with_underscores(s); bool ok; int left = atts.value("left").toInt(&ok); if ((ok) && (left > 0)) s = s.left(left); if (IS_TRUE(atts.value("replace_char_list"))) s = replace_char_list(atts, s); if (IS_TRUE(atts.value("lowercase"))) s = s.toLower(); else if (IS_TRUE(atts.value("uppercase"))) s = s.toUpper(); p_element += s; } else if (is_command_pattern) { p_element += make_compatible_2(title); } else { p_element += title; } } if (qName == VAR_DATE) { if ((is_filename_pattern) || (is_simple_pattern)) { QString s = date; if ((fat32compatible) || (IS_TRUE(atts.value("fat32compatible")))) s = make_fat32_compatible(s); else s = make_compatible(s); if ((replacespaceswithunderscores) || (IS_TRUE(atts.value("underscores")))) s = replace_spaces_with_underscores(s); bool ok; int left = atts.value("left").toInt(&ok); if ((ok) && (left > 0)) s = s.left(left); if (IS_TRUE(atts.value("replace_char_list"))) s = replace_char_list(atts, s); if (IS_TRUE(atts.value("lowercase"))) s = s.toLower(); else if (IS_TRUE(atts.value("uppercase"))) s = s.toUpper(); p_element += s; } else if (is_command_pattern) { p_element += make_compatible_2(date); } else { p_element += date; } } if (qName == VAR_GENRE) { if ((is_filename_pattern) || (is_simple_pattern)) { QString s = genre; if ((fat32compatible) || (IS_TRUE(atts.value("fat32compatible")))) s = make_fat32_compatible(s); else s = make_compatible(s); if ((replacespaceswithunderscores) || (IS_TRUE(atts.value("underscores")))) s = replace_spaces_with_underscores(s); bool ok; int left = atts.value("left").toInt(&ok); if ((ok) && (left > 0)) s = s.left(left); if (IS_TRUE(atts.value("replace_char_list"))) s = replace_char_list(atts, s); if (IS_TRUE(atts.value("lowercase"))) s = s.toLower(); else if (IS_TRUE(atts.value("uppercase"))) s = s.toUpper(); p_element += s; } else if (is_command_pattern) { p_element += make_compatible_2(genre); } else { p_element += genre; } } if (qName == VAR_ENCODER) { p_element += encoder; } if ((is_filename_pattern) || (is_command_pattern) || (is_simple_pattern)) { if (qName == VAR_CD_NO) { if (cdno > 0) { bool ok; int l = atts.value("length").toInt(&ok); QChar fc = '0'; if (!atts.value("fillchar").isEmpty()) fc = atts.value("fillchar").at(0); if (ok) p_element += QString("%1").arg(cdno, l, 10, fc); else p_element += QString("%1").arg(cdno); } } } if ((is_filename_pattern) || (is_command_pattern)) { if (qName == VAR_TRACK_ARTIST) { if (is_filename_pattern) { QString s = tartist; if ((fat32compatible) || (IS_TRUE(atts.value("fat32compatible")))) s = make_fat32_compatible(s); else s = make_compatible(s); if ((replacespaceswithunderscores) || (IS_TRUE(atts.value("underscores")))) s = replace_spaces_with_underscores(s); bool ok; int left = atts.value("left").toInt(&ok); if ((ok) && (left > 0)) s = s.left(left); if (IS_TRUE(atts.value("lowercase"))) s = s.toLower(); else if (IS_TRUE(atts.value("uppercase"))) s = s.toUpper(); if (IS_TRUE(atts.value("replace_char_list"))) s = replace_char_list(atts, s); p_element += s; } else if (is_command_pattern) { p_element += make_compatible_2(tartist); } else { p_element += tartist; } } if (qName == VAR_TRACK_TITLE) { if (is_filename_pattern) { QString s = ttitle; if ((fat32compatible) || (IS_TRUE(atts.value("fat32compatible")))) s = make_fat32_compatible(s); else s = make_compatible(s); if ((replacespaceswithunderscores) || (IS_TRUE(atts.value("underscores")))) s = replace_spaces_with_underscores(s); bool ok; int left = atts.value("left").toInt(&ok); if ((ok) && (left > 0)) s = s.left(left); if (IS_TRUE(atts.value("replace_char_list"))) s = replace_char_list(atts, s); if (IS_TRUE(atts.value("lowercase"))) s = s.toLower(); else if (IS_TRUE(atts.value("uppercase"))) s = s.toUpper(); p_element += s; } else if (is_command_pattern) { p_element += make_compatible_2(ttitle); } else { p_element += ttitle; } } if (qName == VAR_TRACK_NO) { int t; if (trackoffset > 1) t = trackno+trackoffset; else t = trackno; bool ok; int l = atts.value("length").toInt(&ok); QChar fc = '0'; if (!atts.value("fillchar").isEmpty()) fc = atts.value("fillchar").at(0); if (ok) { p_element += QString("%1").arg(t, l, 10, fc); } else { if (_2digitstracknum) { p_element += QString("%1").arg(t, 2, 10, QChar('0')); } else { p_element += QString("%1").arg(t); } } } } if ((is_filename_pattern) || (is_simple_pattern)) { if (qName == VAR_SUFFIX) { /*TEMP*/found_suffix = true; p_element += suffix; } } if (is_command_pattern) { if (qName == VAR_INPUT_FILE) p_element += "\""+input+"\""; if (qName == VAR_OUTPUT_FILE) p_element += "\""+output+"\""; if (qName == VAR_COVER_FILE) { QString format = STANDARD_EMBED_COVER_FORMAT; if (!atts.value("format").isEmpty()) format = atts.value("format"); // cover set by setCover if ((cover) && (!cover->supportedFormats().contains(format.toAscii().toLower()))) format = STANDARD_EMBED_COVER_FORMAT; QString filename; bool stop = false; if (demomode) { filename = tmppath+"audexcover.123."+format.toLower(); } else { int x = -1; int y = -1; bool ok; if (!atts.value("x").isEmpty()) { // when *ok is false, QString::toInt() often return 0 x = atts.value("x").toInt(&ok); if (!ok) x = -1; } if (!atts.value("y").isEmpty()) { y = atts.value("y").toInt(&ok); if (!ok) y = -1; } QByteArray ba = QCryptographicHash::hash(QString(artist+title+date+QString("%1").arg(x*y)+format).toUtf8(), QCryptographicHash::Md5); QString mda5 = ba.toHex(); - if (!stop) filename = tmppath+"cover."+QString("%1").arg(mda5)+"."+format.toLower(); + if (!stop) filename = tmppath+"cover."+QString("%1").arg(mda5)+'.'+format.toLower(); QFileInfo finfo(filename); if ((!finfo.exists()) && (!stop)) { bool success; if ((!cover) || ((cover) && (cover->isEmpty()))) { if (IS_TRUE(atts.value("usenocover"))) { QImage c = QImage(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QString("audex/images/nocover.png"))); if ((x != -1) && (y != -1)) { c = c.scaled(x, y, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); } success = c.save(filename, format.toAscii()); } else { stop = true; } } else { success = cover->save(filename, QSize(x, y)); } if (!stop) { if (!success) { qDebug() << "WARNING! Could not create temporary cover file" << filename; } else { qDebug() << "Successfully created temporary cover file" << filename << "(" << QFile(filename).size() / 1024 << "KiB)"; } } } } if (!stop) { p_element = "\""+filename+"\""; } } } if (is_text_pattern) { if (qName == VAR_CD_SIZE) { QChar iec; if (!atts.value("iec").isEmpty()) iec = atts.value("iec").at(0); if ((iec!='b') && (iec!='k') && (iec!='m') && (iec!='g')) iec = 'm'; bool ok; int p = atts.value("precision").toInt(&ok); if (!ok) p = 2; if (iec=='b') p_element += QString("%1").arg(size, 0, 'f', p); else if (iec=='k') p_element += QString("%1").arg(size / 1024.0f, 0, 'f', p); else if (iec=='m') p_element += QString("%1").arg(size / (1024.0f*1024.0f), 0, 'f', p); else if (iec=='g') p_element += QString("%1").arg(size / (1024.0f*1024.0f*1024.0f), 0, 'f', p); } if (qName == VAR_CD_LENGTH) p_element += QString("%1:%2").arg(length / 60, 2, 10, QChar('0')).arg(length % 60, 2, 10, QChar('0')); if (qName == VAR_TODAY) { QString format; if (!atts.value("format").isEmpty()) format = atts.value("format"); if (format.isEmpty()) { p_element += QString("%1").arg(QDate::currentDate().toString()); } else { p_element += QString("%1").arg(QDate::currentDate().toString(format)); } } if (qName == VAR_NOW) { QString format; if (!atts.value("format").isEmpty()) format = atts.value("format"); if (format.isEmpty()) { p_element += QString("%1").arg(QDateTime::currentDateTime().toString()); } else { p_element += QString("%1").arg(QDateTime::currentDateTime().toString(format)); } } - if (qName == VAR_LINEBREAK) p_element += "\n"; + if (qName == VAR_LINEBREAK) p_element += '\n'; if (qName == VAR_DISCID) { bool ok; int base = atts.value("base").toInt(&ok); if (!ok) base = 16; p_element += QString("%1").arg(discid, 0, base); } } if (qName == VAR_NO_OF_TRACKS) p_element += QString("%1").arg(nooftracks); if (qName == VAR_AUDEX) p_element += QString("Audex Version %1").arg(AUDEX_VERSION); if ((!p_element.isEmpty()) && (is_command_pattern)) { QString pre = atts.value("pre"); QString post = atts.value("post"); p_text += pre+p_element+post; } else { p_text += p_element; } return true; } bool SaxHandler::endElement(const QString& namespaceURI, const QString& localName, const QString& qName) { Q_UNUSED(namespaceURI); Q_UNUSED(localName); if (qName == VAR_FILENAME_PATTERN) { is_filename_pattern = false; p_text.replace("//", "/"); p_text = p_text.simplified(); return true; } if (qName == VAR_COMMAND_PATTERN) { is_command_pattern = false; p_text.replace("//", "/"); p_text = p_text.simplified(); return true; } if (qName == VAR_SIMPLE_PATTERN) { is_simple_pattern = false; p_text.replace("//", "/"); p_text = p_text.simplified(); return true; } if (qName == VAR_TEXT_PATTERN) { is_text_pattern = false; return true; } return true; } bool SaxHandler::characters(const QString& ch) { p_text += ch; return true; } bool SaxHandler::fatalError(const QXmlParseException& exception) { qDebug() << QString("XML pattern parse error: Column %1 (%2)").arg(exception.columnNumber()).arg(exception.message()); return false; } const QString SaxHandler::make_compatible(const QString& string) { QString s = string; for (int i=0; i | const QString SaxHandler::make_fat32_compatible(const QString& string) { QString s = string; for (int i=0; i': case '|': s[i] = '_'; break; default: break; } } return s; } const QString SaxHandler::replace_spaces_with_underscores(const QString& string) { QString s = string; - s.replace(" ", "_"); + s.replace(' ', '_'); return s; } const QString SaxHandler::replace_char_list(const QXmlAttributes& atts, const QString& string) { int i; QString from, to, result; qDebug() << "starting replacement for: " << string; from = atts.value("replace_char_list_from"); to = atts.value("replace_char_list_to"); if (from.count() != to.count()) { qDebug() << "Could not replace if list length are not equal"; return string; } result = string; for (i=0; i < from.count(); i++) { result.replace(from.at(i), to.at(i)); } qDebug() << "finished: " << result; return result; } PatternParser::PatternParser(QObject *parent) : QObject(parent) { Q_UNUSED(parent); } PatternParser::~PatternParser() { } const QString PatternParser::parseFilenamePattern(const QString& pattern, int trackno, int cdno, int trackoffset, int nooftracks, const QString& artist, const QString& title, const QString& tartist, const QString& ttitle, const QString& date, const QString& genre, const QString& suffix, bool fat32compatible, bool replacespaceswithunderscores, bool _2digitstracknum) { SaxHandler handler; handler.setTrackNo(trackno); handler.setCDNo(cdno); handler.setTrackOffset(trackoffset); handler.setNoOfTracks(nooftracks); handler.setArtist(artist); handler.setTitle(title); handler.setTrackArtist(tartist); handler.setTrackTitle(ttitle); handler.setDate(date); handler.setGenre(genre); handler.setSuffix(suffix); handler.setFAT32Compatible(fat32compatible); handler.setReplaceSpacesWithUnderscores(replacespaceswithunderscores); handler.set2DigitsTrackNum(_2digitstracknum); QXmlInputSource inputSource; inputSource.setData(""+p_xmlize_pattern(pattern)+""); QXmlSimpleReader reader; reader.setContentHandler(&handler); reader.setErrorHandler(&handler); reader.parse(inputSource); return handler.text(); } const QString PatternParser::parseCommandPattern(const QString& pattern, const QString& input, const QString& output, int trackno, int cdno, int trackoffset, int nooftracks, const QString& artist, const QString& title, const QString& tartist, const QString& ttitle, const QString& date, const QString& genre, const QString& suffix, CachedImage *cover, bool fatcompatible, const QString& tmppath, const QString& encoder, const bool demomode) { SaxHandler handler; handler.setInputFile(input); handler.setOutputFile(output); handler.setTrackNo(trackno); handler.setCDNo(cdno); handler.setTrackOffset(trackoffset); handler.setNoOfTracks(nooftracks); handler.setArtist(artist); handler.setTitle(title); handler.setTrackArtist(tartist); handler.setTrackTitle(ttitle); handler.setDate(date); handler.setGenre(genre); handler.setSuffix(suffix); // cover is initialized! handler.setCover(cover); handler.setFAT32Compatible(fatcompatible); handler.setTMPPath(tmppath); handler.setDemoMode(demomode); handler.set2DigitsTrackNum(false); handler.setEncoder(encoder); QXmlInputSource inputSource; inputSource.setData(""+p_xmlize_pattern(pattern)+""); QXmlSimpleReader reader; reader.setContentHandler(&handler); reader.setErrorHandler(&handler); reader.parse(inputSource); return handler.text(); } const QString PatternParser::parseSimplePattern(const QString& pattern, int cdno, const int nooftracks, const QString& artist, const QString& title, const QString& date, const QString& genre, const QString& suffix, bool fat32compatible) { SaxHandler handler; handler.setCDNo(cdno); handler.setNoOfTracks(nooftracks); handler.setArtist(artist); handler.setTitle(title); handler.setDate(date); handler.setGenre(genre); handler.setSuffix(suffix); handler.setFAT32Compatible(fat32compatible); handler.setReplaceSpacesWithUnderscores(false); handler.set2DigitsTrackNum(false); QXmlInputSource inputSource; inputSource.setData(""+p_xmlize_pattern(pattern)+""); QXmlSimpleReader reader; reader.setContentHandler(&handler); reader.setErrorHandler(&handler); reader.parse(inputSource); return handler.text(); } void PatternParser::parseInfoText(QStringList& text, const QString& artist, const QString& title, const QString& date, const QString& genre, const quint32 discid, const qreal size, const int length, const int nooftracks) { SaxHandler handler; handler.setArtist(artist); handler.setTitle(title); handler.setDate(date); handler.setGenre(genre); handler.setDiscid(discid); handler.setSize(size); handler.setLength(length); handler.setNoOfTracks(nooftracks); handler.set2DigitsTrackNum(false); QXmlInputSource inputSource; inputSource.setData(""+p_xmlize_pattern(text.join("\n"))+""); QXmlSimpleReader reader; reader.setContentHandler(&handler); reader.setErrorHandler(&handler); reader.parse(inputSource); text = handler.text().split('\n'); } const QString PatternParser::p_xmlize_pattern(const QString& pattern) { QString newpattern; QString name; QString attr; int s = 0; for (int i = 0; i < pattern.length(); ++i) { if (pattern[i] == '&') { newpattern += "&"; continue; } switch (s) { //outside var case 0 : if (pattern[i] == '$') { name.clear(); s = 1; continue; } break; //inside var case 1 : if (pattern[i] == '{') { s = 3; } else if (pattern[i] == '$') { newpattern += '$'; s = 0; } else { s = 2; name += pattern[i]; } continue; //inside simple var case 2 : if (!pattern[i].isLetter()) { - if (!name.trimmed().isEmpty()) newpattern += "<"+name+" />"; + if (!name.trimmed().isEmpty()) newpattern += '<'+name+" />"; name.clear(); s = 0; if (pattern[i] == '$') { name.clear(); s = 1; continue; } else { newpattern += pattern[i]; } continue; } name += pattern[i]; continue; //inside extended var case 3 : if (pattern[i] == '}') { - if (!name.trimmed().isEmpty()) newpattern += "<"+name+" />"; + if (!name.trimmed().isEmpty()) newpattern += '<'+name+" />"; name.clear(); s = 0; continue; } name += pattern[i]; continue; } newpattern += pattern[i]; } //rest at the end? - if ((s==2) && (!name.trimmed().isEmpty())) newpattern += "<"+name+" />"; + if ((s==2) && (!name.trimmed().isEmpty())) newpattern += '<'+name+" />"; return newpattern; } diff --git a/utils/tmpdir.cpp b/utils/tmpdir.cpp index bb6809e..86aad8a 100644 --- a/utils/tmpdir.cpp +++ b/utils/tmpdir.cpp @@ -1,116 +1,116 @@ /* AUDEX CDDA EXTRACTOR * Copyright (C) 2007-2015 Marco Nelles (audex@maniatek.com) * * * This program 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. * * This program 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 this program. If not, see . */ #include "tmpdir.h" #include #include TmpDir::TmpDir(const QString& appName, const QString& sub) : QObject() { QStringList dirs = QStandardPaths::standardLocations(QStandardPaths::TempLocation); p_tmp_path_base = dirs.size()?dirs[0]:"/var/tmp/"; qDebug() << "Found temporary path" << p_tmp_path_base; p_error = false; PID pid; p_tmp_path = p_tmp_path_base; if (p_tmp_path.right(1) != "/") p_tmp_path += "/"; - p_tmp_path += appName+"."+QString("%1").arg(pid.getPID())+"/"; + p_tmp_path += appName+"."+QString("%1").arg(pid.getPID())+'/'; p_tmp_path_app = p_tmp_path; if (!sub.isEmpty()) { - p_tmp_path += sub+"/"; + p_tmp_path += sub+'/'; } qDebug() << "Temporary folder in use:" << p_tmp_path; p_error = !p_create_dir(p_tmp_path); } TmpDir::~TmpDir() { //do we have a sub component in the path? if (p_tmp_path_app != p_tmp_path) { if (p_remove_dir(p_tmp_path)) { qDebug() << QString("Deleting temporary folder \"%1\"").arg(p_tmp_path); } else { qDebug() << QString("Deleting temporary folder \"%1\" failed").arg(p_tmp_path); } } QDir dir(p_tmp_path_app); if ((dir.exists()) && (!dir.rmdir(p_tmp_path_app))) { qDebug() << QString("Temporary folder \"%1\" not removed yet.").arg(p_tmp_path_app); } } const QString TmpDir::tmpPath() { p_error = !p_create_dir(p_tmp_path); return p_tmp_path; } quint64 TmpDir::freeSpace() const { KDiskFreeSpaceInfo diskfreespace = KDiskFreeSpaceInfo::freeSpaceInfo(p_tmp_path); return diskfreespace.available(); } bool TmpDir::p_create_dir(const QString &dirName) { QDir *dir = new QDir(dirName); if (!dir->exists()) { if (!dir->mkpath(dirName)) { return false; } } return true; } bool TmpDir::p_remove_dir(const QString &dirName) { bool result = true; QDir dir(dirName); if (dir.exists(dirName)) { Q_FOREACH(QFileInfo info, dir.entryInfoList(QDir::NoDotAndDotDot | QDir::System | QDir::Hidden | QDir::AllDirs | QDir::Files, QDir::DirsFirst)) { if (info.isDir()) { result = p_remove_dir(info.absoluteFilePath()); } else { result = QFile::remove(info.absoluteFilePath()); } if (!result) { return result; } } result = dir.rmdir(dirName); } return result; } diff --git a/utils/upload.cpp b/utils/upload.cpp index 9dccc1a..f98dbab 100644 --- a/utils/upload.cpp +++ b/utils/upload.cpp @@ -1,74 +1,74 @@ /* AUDEX CDDA EXTRACTOR * Copyright (C) 2007-2015 Marco Nelles (audex@maniatek.com) * * * This program 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. * * This program 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 this program. If not, see . */ #include "upload.h" #include #include Upload::Upload(const QUrl &url, QObject *parent) : QObject(parent) { Q_UNUSED(parent); base_url = url; } Upload::~Upload() { } void Upload::upload(const QString& targetpath, const QStringList& filelist) { //first create the targetpath on the ftp server QString dir, olddir; int i = 0; forever { olddir = dir; dir = targetpath.section('/', 0, i, QString::SectionSkipEmpty); if (olddir==dir) break; ++i; QUrl url = base_url; - url.setPath(base_url.path()+"/"+dir); + url.setPath(base_url.path()+'/'+dir); //qDebug() << url; KIO::Job *job = KIO::mkdir(url); if (!job->exec()) { //if it already exists jump over if (job->error()!=113) { emit error(job->errorText(), ""); qDebug() << job->errorText(); return; } } } for (int i = 0; i < filelist.count(); ++i) { QUrl url = base_url; QFileInfo fi(filelist.at(i)); - url.setPath(base_url.path()+"/"+targetpath+"/"+fi.fileName()); + url.setPath(base_url.path()+'/'+targetpath+'/'+fi.fileName()); emit info(i18n("Uploading file %1 to server. Please wait...", fi.fileName())); KIO::Job *job = KIO::copy(QUrl(filelist.at(i)), url); if (!job->exec()) { emit error(job->errorText(), ""); qDebug() << job->errorText(); return; } emit info(i18n("Finished uploading file %1 to server.", fi.fileName())); } } diff --git a/widgets/cddaheaderwidget.cpp b/widgets/cddaheaderwidget.cpp index c3f3180..ede8029 100644 --- a/widgets/cddaheaderwidget.cpp +++ b/widgets/cddaheaderwidget.cpp @@ -1,863 +1,863 @@ /* AUDEX CDDA EXTRACTOR * Copyright (C) 2007-2015 Marco Nelles (audex@maniatek.com) * * * This program 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. * * This program 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 this program. If not, see . */ #include "cddaheaderwidget.h" #include #include #include static QImage mirrorImage(const QImage &img, MirrorStyle mirrorStyle = MirrorOverX, FadeStyle fadeStyle = FadeDown) { /**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Qt Software Information (qt-info@nokia.com) ** ** This function is part of the Graphics Dojo project on Qt Labs. ** ** This file may be used under the terms of the GNU General Public ** License version 2.0 or 3.0 as published by the Free Software Foundation ** and appearing in the file LICENSE.GPL included in the packaging of ** this file. Please review the following information to ensure GNU ** General Public Licensing requirements will be met: ** http://www.fsf.org/licensing/licenses/info/GPLv2.html and ** http://www.gnu.org/copyleft/gpl.html. ** ** If you are unsure which license is appropriate for your use, please ** contact the sales department at qt-sales@nokia.com. ** ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ** ****************************************************************************/ QImage tmpImage = img; if (mirrorStyle != NoMirror) tmpImage = tmpImage.mirrored(mirrorStyle == MirrorOverY, mirrorStyle == MirrorOverX); if (fadeStyle != NoFade) { QPoint p1, p2; if (fadeStyle == FadeDown) p2.setY(tmpImage.height()); else if (fadeStyle == FadeUp) p1.setY(tmpImage.height()); else if (fadeStyle == FadeRight) p2.setX(tmpImage.width()); else if (fadeStyle == FadeLeft) p1.setX(tmpImage.width()); QLinearGradient gradient(p1, p2); gradient.setColorAt(0, Qt::white); gradient.setColorAt(0.2, QColor(0, 0, 0, 20)); gradient.setColorAt(1, Qt::transparent); QPainter p(&tmpImage); p.setCompositionMode(QPainter::CompositionMode_DestinationIn); p.fillRect(0, 0, tmpImage.width(), tmpImage.height(), gradient); p.end(); } return tmpImage; } static QImage fadeImage(const QImage &img, float val, const QColor &color) { /* This function is part of the KDE libraries Copyright (C) 1998, 1999, 2001, 2002 Daniel M. Duley (C) 1998, 1999 Christian Tibirna (C) 1998, 1999 Dirk Mueller */ QImage tmpImage = img; if (tmpImage.width() == 0 || tmpImage.height() == 0) return tmpImage; // We don't handle bitmaps if (tmpImage.depth() == 1) return tmpImage; unsigned char tbl[256]; for (int i = 0; i < 256; ++i) tbl[i] = (int)(val * i + 0.5); int red = color.red(); int green = color.green(); int blue = color.blue(); QRgb col; int r, g, b, cr, cg, cb; if (tmpImage.depth() <= 8) { // pseudo color for (int i=0; i red) r = cr - tbl[cr-red]; else r = cr + tbl[red-cr]; if (cg > green) g = cg - tbl[cg-green]; else g = cg + tbl[green-cg]; if (cb > blue) b = cb - tbl[cb-blue]; else b = cb + tbl[blue-cb]; tmpImage.setColor(i, qRgba(r, g, b, qAlpha(col))); } } else { // truecolor for (int y=0; y red) r = cr - tbl[cr-red]; else r = cr + tbl[red-cr]; if (cg > green) g = cg - tbl[cg-green]; else g = cg + tbl[green-cg]; if (cb > blue) b = cb - tbl[cb-blue]; else b = cb + tbl[blue-cb]; *data++ = qRgba(r, g, b, qAlpha(col)); } } } return tmpImage; } /**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Qt Software Information (qt-info@nokia.com) ** ** The following five functions are part of the Graphics Dojo project ** on Trolltech Labs. ** ** This file may be used under the terms of the GNU General Public ** License version 2.0 or 3.0 as published by the Free Software Foundation ** and appearing in the file LICENSE.GPL included in the packaging of ** this file. Please review the following information to ensure GNU ** General Public Licensing requirements will be met: ** http://www.fsf.org/licensing/licenses/info/GPLv2.html and ** http://www.gnu.org/copyleft/gpl.html. ** ** If you are unsure which license is appropriate for your use, please ** contact the sales department at qt-sales@nokia.com. ** ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ** ****************************************************************************/ static inline int sign(int x) { return x < 0 ? -1 : 1; } static inline int blend(int a, int b, int blendA, int blendB) { return blendA * a + blendB * b; } // bilinear blend static inline int blend(unsigned int *s, int blendX, int blendY, int shift) { unsigned int src[] = { (s[0] >> shift) & 0xff, (s[1] >> shift) & 0xff, (s[2] >> shift) & 0xff, (s[3] >> shift) & 0xff }; int da = blend(src[0], src[1], FP_FACTOR - blendX, blendX); int db = blend(src[2], src[3], FP_FACTOR - blendX, blendX); return blend(da, db, FP_FACTOR - blendY, blendY) / (FP_FACTOR * FP_FACTOR); } static void processScanlines(QImage &img, int sy, int ey, int sx, int ex) { int dx = sign(ex - sx); int dy = sign(ey - sy); QRgb *data = (QRgb *)img.bits(); int width = img.width(); int height = img.height(); if (dy == 1 && sy >= height) return; if (dx == 1 && sx >= width) return; if (dy != 1 && sy < 0) return; if (dx != 1 && sx < 0) return; int actual_sy = (dy == 1) ? qMax(0, sy) : qMin(height - 1, sy); int actual_ey = (dy == 1) ? qMin(height, ey) : qMax(-1, ey); int actual_sx = (dx == 1) ? qMax(0, sx) : qMin(width - 1, sx); int actual_ex = (dx == 1) ? qMin(width, ex) : qMax(-1, ex); if (dy == 1 && actual_sy >= actual_ey) return; if (dy != 1 && actual_sy <= actual_ey) return; if (dx == 1 && actual_sx >= actual_ex) return; if (dx != 1 && actual_sx <= actual_ex) return; for (int y = actual_sy; y != actual_ey; y += dy) { QRgb *dst = data + y * width; int srcY = y * FP_FACTOR + (sy - y) * 8; int scanLine = srcY / FP_FACTOR; QRgb *srcA = scanLine >= 0 && scanLine < height ? data + scanLine * width : 0; ++scanLine; QRgb *srcB = scanLine >= 0 && scanLine < height ? data + scanLine * width : 0; if (!srcA && !srcB) { for (int x = sx; x != ex; x += dx) dst[x] = 0; continue; } int blendY = srcY % FP_FACTOR; for (int x = actual_sx; x != actual_ex; x += dx) { int srcX = x * FP_FACTOR + (sx - x) * 8; int da = srcX / FP_FACTOR; int db = da + 1; int blendX = srcX % FP_FACTOR; QRgb src[4] = { srcA ? srcA[da] : 0, srcA ? srcA[db] : 0, srcB ? srcB[da] : 0, srcB ? srcB[db] : 0 }; int red = blend(src, blendX, blendY, 16); int green = blend(src, blendX, blendY, 8); int blue = blend(src, blendX, blendY, 0); red = blend(red, qRed(dst[x]), FP_FACTOR-32, 128)/FP_FACTOR; green = blend(green, qGreen(dst[x]), FP_FACTOR-32, 128)/FP_FACTOR; blue = blend(blue, qBlue(dst[x]), FP_FACTOR-32, 128)/FP_FACTOR; red = qMin(red, 255); green = qMin(green, 255); blue = qMin(blue, 255); dst[x] = qRgba(red, green, blue, qAlpha(dst[x])); } } } static void radialBlur(QImage &img, int cx, int cy) { int w = img.width(); int h = img.height(); processScanlines(img, cy-1, -1, cx-1, -1); processScanlines(img, cy-1, -1, cx, w); processScanlines(img, cy, h, cx-1, -1); processScanlines(img, cy, h, cx, w); } CDDAHeaderWidget ::CDDAHeaderWidget(CDDAModel *cddaModel, QWidget* parent, const int coverSize, const int padding) : QWidget(parent) { cdda_model = cddaModel; if (!cdda_model) { qDebug() << "CDDAModel is NULL!"; return; } connect(cdda_model, SIGNAL(modelReset()), this, SLOT(update())); setup_actions(); qDebug() << "coverSize:" << coverSize; this->cover_size = coverSize; this->i_cover_checksum = 1; this->padding = padding; animation_up = false; animation_down = false; scale_up = false; scale_down = false; fade_in = false; fade_out = false; scale_factor = 1.0; opacity_factor = 1.0; setMouseTracking(true); cursor_on_cover = false; cursor_on_link1 = false; cursor_on_link2 = false; connect(this, SIGNAL(coverDown()), this, SLOT(cover_is_down())); connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(context_menu(const QPoint&))); cover_browser_dialog = NULL; fetching_cover_in_progress = false; setContextMenuPolicy(Qt::CustomContextMenu); timer.setInterval(40); connect(&timer, SIGNAL(timeout()), this, SLOT(trigger_repaint())); setMinimumSize(QSize(cover_size+(padding*2), (int)(cover_size*1.4)+(padding*2))); tmp_dir = new TmpDir("audex", "cover"); update(); } CDDAHeaderWidget::~CDDAHeaderWidget() { delete action_collection; delete tmp_dir; } QSize CDDAHeaderWidget::sizeHint() const { return QSize((cover_size*1.5)+(padding*2), (int)(cover_size*1.4)+(padding*2)); } void CDDAHeaderWidget::setCover(CachedImage *cover) { if (cover) { i_cover_checksum = cover->checksum(); } else { i_cover_checksum = 0; } if (this->i_cover.isNull()) { if (cover) { this->i_cover = cover->coverImage().convertToFormat(QImage::Format_ARGB32_Premultiplied); } else { QImage image = QImage(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QString("audex/images/nocover.png"))); this->i_cover = image.convertToFormat(QImage::Format_ARGB32_Premultiplied); } animation_up = true; fade_in = true; scale_factor = 0.7; opacity_factor = 0.0; } else { if (cover) { this->i_cover_holding = cover->coverImage().convertToFormat(QImage::Format_ARGB32_Premultiplied); } else { QImage image = QImage(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QString("audex/images/nocover.png"))); this->i_cover_holding = image.convertToFormat(QImage::Format_ARGB32_Premultiplied); } animation_down = true; scale_down = true; scale_factor = 1.0; opacity_factor = 1.0; } timer.start(); } bool CDDAHeaderWidget::isEnabled() const { return enabled; } void CDDAHeaderWidget::setEnabled(bool enabled) { this->enabled = enabled; repaint(); } void CDDAHeaderWidget::googleAuto() { qDebug() << "Google AUTO cover fetch" ; if ((cdda_model->empty()) || (fetching_cover_in_progress)) return; QApplication::restoreOverrideCursor(); cursor_on_cover = false; fetching_cover_in_progress = true; action_collection->action("fetch")->setEnabled(false); cover_browser_dialog = new CoverBrowserDialog(this); connect(cover_browser_dialog, SIGNAL(allCoverThumbnailsFetched()), this, SLOT(fetch_first_cover())); connect(cover_browser_dialog, SIGNAL(nothingFetched()), this, SLOT(auto_fetch_cover_failed())); QString artist = cdda_model->artist(); QString title = cdda_model->title(); int lastColonPos = title.lastIndexOf(':'); while (lastColonPos > 0) { title = title.left(lastColonPos); lastColonPos = title.lastIndexOf(':'); } cover_browser_dialog->fetchThumbnails(QString("%1 %2").arg(artist).arg(title), 1); } void CDDAHeaderWidget::paintEvent(QPaintEvent *event) { Q_UNUSED(event); QPainter p; p.begin(this); if (enabled) { bool vertical=rect().height()>rect().width() && rect().width()<((cover_size+padding)*2); int xOffset=vertical ? padding : (padding*2)+cover_size, yOffset=vertical ? (padding*2)+cover_size+24 : padding; QImage scaled_cover = i_cover.scaled((int)(scale_factor*cover_size), (int)(scale_factor*cover_size), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); QImage faded_cover = fadeImage(scaled_cover, 1-opacity_factor, palette().background().color()); p.drawImage((cover_size/2-(scaled_cover.width()/2))+padding, (cover_size/2-(scaled_cover.height()/2))+padding, faded_cover); cover_rect = QRect(padding, padding, scaled_cover.width(), scaled_cover.height()); QImage mirror_img = mirrorImage(faded_cover); //we shear it a along the x axis to produce the nice leaning to the side effect. (valid only for MirrorOverX) //mirror_img = mirror_img.transformed(QMatrix().shear(0.2, 0.0), Qt::SmoothTransformation); radialBlur(mirror_img, 50, 50); p.drawImage((cover_size/2-(scaled_cover.width()/2))+padding, (cover_size/2-(scaled_cover.height()/2))+padding+mirror_img.height()+5, mirror_img); p.setBrush(palette().text()); QFont font(QApplication::font()); int pixelSize(font.pixelSize()==-1 ? (font.pointSize()*QX11Info::appDpiX()+36)/72 : font.pixelSize()), width=rect().width()-(xOffset+1); font.setPixelSize((int)((((double)pixelSize)*1.5)+0.5)); font.setBold(true); p.setFont(font); yOffset+=p.fontMetrics().lineSpacing()*1.2; p.drawText(xOffset, yOffset, p.fontMetrics().elidedText(cdda_model->artist(), Qt::ElideRight, width)); font.setPixelSize(pixelSize); font.setBold(true); font.setItalic(true); p.setFont(font); yOffset+=pixelSize; p.drawText(xOffset, yOffset, p.fontMetrics().elidedText(cdda_model->title(), Qt::ElideRight, width)); yOffset+=p.fontMetrics().lineSpacing()*1.5; font.setBold(false); font.setItalic(false); p.setFont(font); QFontMetrics fm(font); QString yearLabel(i18n("Released: ")), genreLabel(i18n("Genre: ")), cdNoLabel(i18n("CD Number: ")); int maxWidth(fm.width(yearLabel)); if ((width=fm.width(genreLabel))>maxWidth) maxWidth = width; if (cdda_model->isMultiCD() && (width=fm.width(cdNoLabel))) maxWidth = width; width = rect().width()-(xOffset+1); if (!cdda_model->year().isEmpty()) { p.drawText(xOffset, yOffset, yearLabel); p.drawText(xOffset+maxWidth, yOffset, fm.elidedText(cdda_model->year(), Qt::ElideRight, width-maxWidth)); yOffset += fm.lineSpacing(); } if (!cdda_model->genre().isEmpty()) { p.drawText(xOffset, yOffset, genreLabel); p.drawText(xOffset+maxWidth, yOffset, fm.elidedText(cdda_model->genre(), Qt::ElideRight, width-maxWidth)); yOffset += fm.lineSpacing(); } if (cdda_model->isMultiCD()) { p.drawText(xOffset, yOffset, cdNoLabel); p.drawText(xOffset+maxWidth, yOffset, QString().setNum(cdda_model->cdNum())); yOffset += fm.lineSpacing(); } font.setUnderline(true); p.setFont(font); //links fm = QFontMetrics(font); QString link1 = i18n("Edit Data"); QString link2 = i18n("Wikipedia"); KColorScheme kcs(QPalette::Active); p.setPen(kcs.foreground(KColorScheme::LinkText).color()); link1_rect = fm.boundingRect(link1); link2_rect = fm.boundingRect(link2); yOffset = vertical ? yOffset+fm.lineSpacing() : (yOffset>(padding+cover_size) ? yOffset : (padding+cover_size)); p.drawText(xOffset, yOffset, link1); p.drawText(xOffset+(link1_rect.height()/2)+link1_rect.width(), yOffset, link2); link1_rect = QRect(xOffset, yOffset+link1_rect.y(), link1_rect.width(), link1_rect.height()); link2_rect = QRect(xOffset+(link1_rect.height()/2)+link1_rect.width(), yOffset+link2_rect.y(), link2_rect.width(), link2_rect.height()); } else { //disabled QFont font(QApplication::font()); if (-1==font.pixelSize()) { font.setPointSizeF(font.pointSizeF()*1.5); } else { font.setPixelSize(font.pixelSize()*1.5); } font.setBold(true); font.setItalic(true); p.setFont(font); p.drawText(rect(), Qt::AlignCenter | Qt::AlignVCenter, i18n("No audio CD detected")); } p.end(); } void CDDAHeaderWidget::mouseMoveEvent(QMouseEvent *event) { if (cover_rect.contains(event->pos())) { if (!cursor_on_cover) { QApplication::setOverrideCursor(QCursor(Qt::PointingHandCursor)); cursor_on_cover = true; } } else if (link1_rect.contains(event->pos())) { if (!cursor_on_link1) { QApplication::setOverrideCursor(QCursor(Qt::PointingHandCursor)); cursor_on_link1 = true; } } else if (link2_rect.contains(event->pos())) { if (!cursor_on_link2) { QApplication::setOverrideCursor(QCursor(Qt::PointingHandCursor)); cursor_on_link2 = true; } } else { if (cursor_on_cover) { QApplication::restoreOverrideCursor(); cursor_on_cover = false; } else if (cursor_on_link1) { QApplication::restoreOverrideCursor(); cursor_on_link1 = false; } else if (cursor_on_link2) { QApplication::restoreOverrideCursor(); cursor_on_link2 = false; } } } void CDDAHeaderWidget::mousePressEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton) { if ((cursor_on_cover) && (!fetching_cover_in_progress)) { if (cdda_model->isCoverEmpty()) { if (cdda_model->empty()) { load(); } else { google(); } } else { view_cover(); } } if (cursor_on_link1) edit_data(); if (cursor_on_link2) wikipedia(); } } void CDDAHeaderWidget::update() { action_collection->action("fetch")->setEnabled(!cdda_model->empty()); bool activate = false; if (cdda_model->isCoverEmpty()) { if (i_cover_checksum) setCover(NULL); } else { qDebug() << "current cover checksum:" << i_cover_checksum; qDebug() << "new cover checksum:" << cdda_model->coverChecksum(); if (i_cover_checksum != cdda_model->coverChecksum()) setCover(cdda_model->cover()); activate = true; } action_collection->action("save")->setEnabled(activate); action_collection->action("view")->setEnabled(activate); action_collection->action("remove")->setEnabled(activate); repaint(); } void CDDAHeaderWidget::trigger_repaint() { if (animation_down) { if (scale_down) { scale_factor -= 0.08; if (qFuzzyCompare(scale_factor, .7) || scale_factor < .7) { scale_down = false; fade_out = true; } } else if (fade_out) { opacity_factor -= 0.16; if (qFuzzyCompare(opacity_factor, 0) || opacity_factor < 0) { opacity_factor = 0; fade_out = false; animation_down = false; timer.stop(); emit coverDown(); } } } else if (animation_up) { if (fade_in) { opacity_factor += 0.16; if (qFuzzyCompare(opacity_factor, 1) || opacity_factor > 1) { opacity_factor = 1; fade_in = false; scale_up = true; } } else if (scale_up) { scale_factor += 0.08; if (qFuzzyCompare(scale_factor, 1) || scale_factor > 1) { scale_up = false; animation_up = false; timer.stop(); emit coverUp(); } } } repaint(); } void CDDAHeaderWidget::cover_is_down() { this->i_cover = i_cover_holding; animation_up = true; fade_in = true; scale_factor = .7; opacity_factor = 0.0; timer.start(); } void CDDAHeaderWidget::google() { qDebug() << "Google cover fetch" ; if ((cdda_model->empty()) || (fetching_cover_in_progress)) return; QApplication::restoreOverrideCursor(); cursor_on_cover = false; fetching_cover_in_progress = true; action_collection->action("fetch")->setEnabled(false); cover_browser_dialog = new CoverBrowserDialog(this); connect(cover_browser_dialog, SIGNAL(coverFetched(const QByteArray&)), this, SLOT(set_cover(const QByteArray&))); connect(cover_browser_dialog, SIGNAL(nothingFetched()), this, SLOT(fetch_cover_failed())); QString artist = cdda_model->artist(); QString title = cdda_model->title(); int lastColonPos = title.lastIndexOf(':'); while (lastColonPos > 0) { title = title.left(lastColonPos); lastColonPos = title.lastIndexOf(':'); } cover_browser_dialog->fetchThumbnails(QString("%1 %2").arg(artist).arg(title)); if (cover_browser_dialog->exec() != QDialog::Accepted) { fetching_cover_in_progress = false; delete cover_browser_dialog; cover_browser_dialog = NULL; action_collection->action("fetch")->setEnabled(true); } } void CDDAHeaderWidget::load() { qDebug() << "Supported cover image file MIME types:" << cdda_model->coverSupportedMimeTypeList(); QString filename = QFileDialog::getOpenFileName(this, i18n("Load Cover"), QDir::homePath(), cdda_model->coverSupportedMimeTypeList()); if (!filename.isEmpty()) { if (!cdda_model->setCover(filename)) { ErrorDialog::show(this, cdda_model->lastError().message(), cdda_model->lastError().details()); } } } void CDDAHeaderWidget::save() { - QString filename = QFileDialog::getSaveFileName(this, i18n("Save Cover"), QDir::homePath()+"/"+cdda_model->title()+".jpg", cdda_model->coverSupportedMimeTypeList()); + QString filename = QFileDialog::getSaveFileName(this, i18n("Save Cover"), QDir::homePath()+'/'+cdda_model->title()+".jpg", cdda_model->coverSupportedMimeTypeList()); if (!filename.isEmpty()) { if (!cdda_model->saveCoverToFile(filename)) { ErrorDialog::show(this, cdda_model->lastError().message(), cdda_model->lastError().details()); } } } void CDDAHeaderWidget::view_cover() { QString tmp_path = tmp_dir->tmpPath(); if (tmp_dir->error()) { QStringList dirs = QStandardPaths::standardLocations(QStandardPaths::TempLocation); tmp_path = dirs.size()?dirs[0]:"/var/tmp/"; if (tmp_path.right(1) != "/") tmp_path += "/"; qDebug() << "Temporary folder in use:" << tmp_path; } QString filename = tmp_path+QString("%1.jpeg").arg(cdda_model->coverChecksum()); cdda_model->saveCoverToFile(filename); QDesktopServices::openUrl(QUrl(filename)); } void CDDAHeaderWidget::remove() { cdda_model->clearCover(); update(); } void CDDAHeaderWidget::edit_data() { QApplication::restoreOverrideCursor(); cursor_on_link1 = false; CDDAHeaderDataDialog *dialog = new CDDAHeaderDataDialog(cdda_model, this); if (dialog->exec() != QDialog::Accepted) { delete dialog; return; } delete dialog; update(); emit headerDataChanged(); } void CDDAHeaderWidget::wikipedia() { int locale = Preferences::wikipediaLocale(); QString l; if (locale==0) l = "en"; if (locale==1) l = "de"; if (locale==2) l = "fr"; if (locale==3) l = "pl"; if (locale==4) l = "ja"; if (locale==5) l = "it"; if (locale==6) l = "nl"; if (locale==7) l = "es"; if (locale==8) l = "pt"; if (locale==9) l = "sv"; if (l.isEmpty()) l = "en"; QDesktopServices::openUrl(QUrl(QString("http://%1.wikipedia.org/wiki/").arg(l) + QUrl::toPercentEncoding(cdda_model->artist()))); } void CDDAHeaderWidget::set_cover(const QByteArray& cover) { if (!cover.isEmpty()) cdda_model->setCover(cover); fetching_cover_in_progress = false; action_collection->action("fetch")->setEnabled(true); if (cover_browser_dialog) { delete cover_browser_dialog; cover_browser_dialog = NULL; } if (!cover.isEmpty()) update(); } void CDDAHeaderWidget::fetch_first_cover() { if (cover_browser_dialog) { if (cover_browser_dialog->count() == 0) { qDebug() << "no cover found"; ErrorDialog::show(this, i18n("No cover found."), i18n("Check your artist name and title. Otherwise you can load a custom cover from an image file.")); delete cover_browser_dialog; cover_browser_dialog = NULL; fetching_cover_in_progress = false; action_collection->action("fetch")->setEnabled(true); } else { connect(cover_browser_dialog, SIGNAL(coverFetched(const QByteArray&)), this, SLOT(set_cover(const QByteArray&))); cover_browser_dialog->startFetchCover(0); } } } void CDDAHeaderWidget::fetchCoverFinished(bool showDialog) { if (cover_browser_dialog) { if (showDialog) { ErrorDialog::show(this, i18n("No cover found."), i18n("Check your artist name and title. Otherwise you can load a custom cover from an image file.")); } delete cover_browser_dialog; cover_browser_dialog = NULL; } fetching_cover_in_progress = false; action_collection->action("fetch")->setEnabled(true); } void CDDAHeaderWidget::auto_fetch_cover_failed() { fetchCoverFinished(false); } void CDDAHeaderWidget::fetch_cover_failed() { fetchCoverFinished(true); } void CDDAHeaderWidget::context_menu(const QPoint& point) { qDebug() << "context menu requested at point" << point; if ((cursor_on_cover) && (!fetching_cover_in_progress)) { QApplication::restoreOverrideCursor(); cursor_on_cover = false; QMenu contextMenu(this); QMouseEvent *mevent = new QMouseEvent(QEvent::MouseButtonPress, point, Qt::RightButton, Qt::RightButton, Qt::NoModifier); contextMenu.clear(); contextMenu.addAction(action_collection->action("fetch")); contextMenu.addAction(action_collection->action("load")); contextMenu.addAction(action_collection->action("save")); contextMenu.addSeparator(); contextMenu.addAction(action_collection->action("view")); contextMenu.addSeparator(); contextMenu.addAction(action_collection->action("remove")); contextMenu.exec(mevent->globalPos()); } } void CDDAHeaderWidget::setup_actions() { action_collection = new KActionCollection(this); QAction * fetchCoverAction = new QAction(this); fetchCoverAction->setText(i18n("Fetch cover from Google...")); action_collection->addAction("fetch", fetchCoverAction); connect(fetchCoverAction, SIGNAL(triggered(bool)), this, SLOT(google())); QAction * loadCoverAction = new QAction(this); loadCoverAction->setText(i18n("Set Custom Cover...")); action_collection->addAction("load", loadCoverAction); connect(loadCoverAction, SIGNAL(triggered(bool)), this, SLOT(load())); QAction * saveCoverAction = new QAction(this); saveCoverAction->setText(i18n("Save Cover To File...")); action_collection->addAction("save", saveCoverAction); connect(saveCoverAction, SIGNAL(triggered(bool)), this, SLOT(save())); QAction * viewCoverAction = new QAction(this); viewCoverAction->setText(i18n("Show Full Size Cover...")); action_collection->addAction("view", viewCoverAction); connect(viewCoverAction, SIGNAL(triggered(bool)), this, SLOT(view_cover())); QAction * removeCoverAction = new QAction(this); removeCoverAction->setText(i18n("Remove Cover")); action_collection->addAction("remove", removeCoverAction); connect(removeCoverAction, SIGNAL(triggered(bool)), this, SLOT(remove())); }