672 lines
22 KiB
C++
672 lines
22 KiB
C++
/*
|
|
* Cantata
|
|
*
|
|
* Copyright (c) 2011-2022 Craig Drummond <craig.p.drummond@gmail.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 2 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; see the file COPYING. If not, write to
|
|
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include "rgdialog.h"
|
|
#ifdef ENABLE_DEVICES_SUPPORT
|
|
#include "devices/device.h"
|
|
#include "models/devicesmodel.h"
|
|
#endif
|
|
#include "gui/settings.h"
|
|
#include "tags/tags.h"
|
|
#include "tagreader.h"
|
|
#include "support/utils.h"
|
|
#include "support/messagebox.h"
|
|
#include "support/monoicon.h"
|
|
#include "jobcontroller.h"
|
|
#include "widgets/basicitemdelegate.h"
|
|
#include "support/action.h"
|
|
#include "mpd-interface/cuefile.h"
|
|
#include <QComboBox>
|
|
#include <QTreeWidget>
|
|
#include <QLabel>
|
|
#include <QProgressBar>
|
|
#include <QBoxLayout>
|
|
#include <QHeaderView>
|
|
#include <QCloseEvent>
|
|
#include <QCoreApplication>
|
|
#include <QEventLoop>
|
|
#include <algorithm>
|
|
|
|
enum Columns
|
|
{
|
|
COL_ARTIST,
|
|
COL_ALBUM,
|
|
COL_TITLE,
|
|
COL_ALBUMGAIN,
|
|
COL_TRACKGAIN,
|
|
COL_ALBUMPEAK,
|
|
COL_TRACKPEAK
|
|
};
|
|
|
|
static int iCount=0;
|
|
|
|
int RgDialog::instanceCount()
|
|
{
|
|
return iCount;
|
|
}
|
|
|
|
static inline void setResizeMode(QHeaderView *hdr, int idx, QHeaderView::ResizeMode mode)
|
|
{
|
|
hdr->setSectionResizeMode(idx, mode);
|
|
}
|
|
|
|
RgDialog::RgDialog(QWidget *parent)
|
|
: SongDialog(parent, "RgDialog", QSize(800, 400))
|
|
, state(State_Idle)
|
|
, totalToScan(0)
|
|
, tagReader(0)
|
|
, autoScanTags(false)
|
|
{
|
|
iCount++;
|
|
setButtons(User1|Ok|Cancel);
|
|
setCaption(tr("ReplayGain"));
|
|
setAttribute(Qt::WA_DeleteOnClose);
|
|
QWidget *mainWidget = new QWidget(this);
|
|
QBoxLayout *layout=new QBoxLayout(QBoxLayout::TopToBottom, mainWidget);
|
|
combo = new QComboBox(this);
|
|
view = new QTreeWidget(this);
|
|
statusLabel = new QLabel(this);
|
|
statusLabel->setVisible(false);
|
|
progress = new QProgressBar(this);
|
|
progress->setVisible(false);
|
|
combo->addItem(tr("Show All Tracks"), true);
|
|
combo->addItem(tr("Show Untagged Tracks"), false);
|
|
view->setRootIsDecorated(false);
|
|
view->setAllColumnsShowFocus(true);
|
|
view->setItemDelegate(new BasicItemDelegate(view));
|
|
view->setAlternatingRowColors(false);
|
|
view->setContextMenuPolicy(Qt::ActionsContextMenu);
|
|
view->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
|
removeAct=new Action(tr("Remove From List"), view);
|
|
removeAct->setEnabled(false);
|
|
view->addAction(removeAct);
|
|
QTreeWidgetItem *hdr = view->headerItem();
|
|
hdr->setText(COL_ARTIST, tr("Artist"));
|
|
hdr->setText(COL_ALBUM, tr("Album"));
|
|
hdr->setText(COL_TITLE, tr("Title"));
|
|
hdr->setText(COL_ALBUMGAIN, tr("Album Gain"));
|
|
hdr->setText(COL_TRACKGAIN, tr("Track Gain"));
|
|
hdr->setText(COL_ALBUMPEAK, tr("Album Peak"));
|
|
hdr->setText(COL_TRACKPEAK, tr("Track Peak"));
|
|
|
|
QHeaderView *hv=view->header();
|
|
setResizeMode(hv, COL_ARTIST, QHeaderView::ResizeToContents);
|
|
setResizeMode(hv, COL_ALBUM, QHeaderView::ResizeToContents);
|
|
setResizeMode(hv, COL_TITLE, QHeaderView::Stretch);
|
|
setResizeMode(hv, COL_ALBUMGAIN, QHeaderView::Fixed);
|
|
setResizeMode(hv, COL_TRACKGAIN, QHeaderView::Fixed);
|
|
setResizeMode(hv, COL_ALBUMPEAK, QHeaderView::Fixed);
|
|
setResizeMode(hv, COL_TRACKPEAK, QHeaderView::Fixed);
|
|
hv->setStretchLastSection(false);
|
|
|
|
layout->setMargin(0);
|
|
layout->addWidget(combo);
|
|
layout->addWidget(view);
|
|
layout->addWidget(statusLabel);
|
|
layout->addWidget(progress);
|
|
setMainWidget(mainWidget);
|
|
setButtonGuiItem(Ok, StdGuiItem::save());
|
|
setButtonGuiItem(Cancel, StdGuiItem::close());
|
|
setButtonGuiItem(User1, GuiItem(tr("Scan"), FontAwesome::search));
|
|
enableButton(Ok, false);
|
|
enableButton(User1, false);
|
|
qRegisterMetaType<Tags::ReplayGain>("Tags::ReplayGain");
|
|
connect(combo, SIGNAL(currentIndexChanged(int)), SLOT(toggleDisplay()));
|
|
connect(view, SIGNAL(itemSelectionChanged()), SLOT(controlRemoveAct()));
|
|
connect(removeAct, SIGNAL(triggered()), SLOT(removeItems()));
|
|
|
|
italic=font();
|
|
italic.setItalic(true);
|
|
JobController::self()->setMaxActive(1);
|
|
}
|
|
|
|
RgDialog::~RgDialog()
|
|
{
|
|
clearScanners();
|
|
iCount--;
|
|
}
|
|
|
|
void RgDialog::show(const QList<Song> &songs, const QString &udi, bool autoScan)
|
|
{
|
|
if (songs.isEmpty()) {
|
|
deleteLater();
|
|
return;
|
|
}
|
|
|
|
for (const Song &s: songs) {
|
|
if (!CueFile::isCue(s.file)) {
|
|
origSongs.append(s);
|
|
}
|
|
}
|
|
|
|
if (origSongs.isEmpty()) {
|
|
deleteLater();
|
|
return;
|
|
}
|
|
|
|
autoScanTags=autoScan;
|
|
std::sort(origSongs.begin(), origSongs.end());
|
|
|
|
#ifdef ENABLE_DEVICES_SUPPORT
|
|
if (udi.isEmpty()) {
|
|
base=MPDConnection::self()->getDetails().dir;
|
|
} else {
|
|
Device *dev=getDevice(udi, parentWidget());
|
|
|
|
if (!dev) {
|
|
deleteLater();
|
|
return;
|
|
}
|
|
|
|
base=dev->path();
|
|
}
|
|
#else
|
|
base=MPDConnection::self()->getDetails().dir;
|
|
#endif
|
|
|
|
if (!songsOk(origSongs, base, udi.isEmpty())) {
|
|
return;
|
|
}
|
|
|
|
state=State_Idle;
|
|
enableButton(User1, origSongs.count());
|
|
view->clear();
|
|
for (const Song &s: origSongs) {
|
|
if (s.isLocalFile()) {
|
|
base = QString();
|
|
}
|
|
QString aa = s.albumArtist();
|
|
const QString &al = s.album;
|
|
const QString &t = s.title;
|
|
if (aa.isEmpty() && al.isEmpty() && t.isEmpty()) {
|
|
new QTreeWidgetItem(view, QStringList() << "-" << "-" << Utils::getFile(s.file));
|
|
} else {
|
|
new QTreeWidgetItem(view, QStringList() << s.albumArtist() << s.album << s.title);
|
|
}
|
|
}
|
|
Dialog::show();
|
|
startReadingTags();
|
|
}
|
|
|
|
void RgDialog::slotButtonClicked(int button)
|
|
{
|
|
if (State_Saving==state) {
|
|
return;
|
|
}
|
|
|
|
switch (button) {
|
|
case Ok:
|
|
//if (MessageBox::Yes==MessageBox::questionYesNo(this, tr("Update ReplayGain tags in tracks?"), tr("Update Tags"),
|
|
// GuiItem(tr("Update Tags")), StdGuiItem::cancel())) {
|
|
if (saveTags()) {
|
|
stopScanning();
|
|
accept();
|
|
}
|
|
//}
|
|
break;
|
|
case User1:
|
|
startScanning();
|
|
break;
|
|
case Cancel:
|
|
switch (state) {
|
|
case State_ScanningFiles:
|
|
if (MessageBox::Yes==MessageBox::questionYesNo(this, tr("Abort scanning of tracks?"), tr("Abort"),
|
|
GuiItem(tr("Abort")), StdGuiItem::no())) {
|
|
stopScanning();
|
|
// Need to call this - if not, when dialog is closed by window X control, it is not deleted!!!!
|
|
Dialog::slotButtonClicked(button);
|
|
state=State_Idle;
|
|
}
|
|
break;
|
|
case State_ScanningTags:
|
|
if (MessageBox::Yes==MessageBox::questionYesNo(this, tr("Abort reading of existing tags?"), tr("Abort"),
|
|
GuiItem(tr("Abort")), StdGuiItem::no())) {
|
|
stopReadingTags();
|
|
// Need to call this - if not, when dialog is closed by window X control, it is not deleted!!!!
|
|
Dialog::slotButtonClicked(button);
|
|
state=State_Idle;
|
|
}
|
|
break;
|
|
default:
|
|
case State_Idle:
|
|
stopScanning();
|
|
reject();
|
|
// Need to call this - if not, when dialog is closed by window X control, it is not deleted!!!!
|
|
Dialog::slotButtonClicked(button);
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void RgDialog::startScanning()
|
|
{
|
|
bool all=origTags.isEmpty() ||
|
|
(origTags.count()==origSongs.count()
|
|
? MessageBox::Yes==MessageBox::questionYesNo(this, tr("Scan <b>all</b> tracks?<br/><br/><i>All tracks have existing ReplayGain tags.</i>"), QString(),
|
|
GuiItem(tr("Scan")), StdGuiItem::cancel())
|
|
: MessageBox::No==MessageBox::questionYesNo(this, tr("Do you wish to scan all tracks, or only tracks without existing tags?"), QString(),
|
|
GuiItem(tr("Untagged Tracks")), GuiItem(tr("All Tracks"))));
|
|
if (!all && origTags.count()==origSongs.count()) {
|
|
return;
|
|
}
|
|
setButtonGuiItem(Cancel, StdGuiItem::cancel());
|
|
state=State_ScanningFiles;
|
|
enableButton(Ok, false);
|
|
enableButton(User1, false);
|
|
progress->setValue(0);
|
|
progress->setVisible(true);
|
|
statusLabel->setText(tr("Scanning tracks..."));
|
|
statusLabel->setVisible(true);
|
|
clearScanners();
|
|
totalToScan=0;
|
|
QMap<QString, QList<int> > groupedTracks;
|
|
for (int i=0; i<origSongs.count(); ++i) {
|
|
if (!removedItems.contains(i) && (all || !origTags.contains(i))) {
|
|
const Song &sng=origSongs.at(i);
|
|
QString aa = sng.albumArtist();
|
|
const QString &al = sng.album;
|
|
groupedTracks[aa.isEmpty() && al.isEmpty() ? (Utils::getFile(sng.file)+" -- "+QString::number(i)) : (sng.albumArtist()+" -- "+sng.album)].append(i);
|
|
}
|
|
}
|
|
QMap<QString, QList<int> >::ConstIterator it(groupedTracks.constBegin());
|
|
QMap<QString, QList<int> >::ConstIterator end(groupedTracks.constEnd());
|
|
|
|
for (; it!=end; ++it) {
|
|
createScanner(*it);
|
|
totalToScan++;
|
|
}
|
|
progress->setRange(0, 100*totalToScan);
|
|
}
|
|
|
|
void RgDialog::stopScanning()
|
|
{
|
|
state=State_Idle;
|
|
enableButton(User1, true);
|
|
progress->setVisible(false);
|
|
statusLabel->setVisible(false);
|
|
|
|
JobController::self()->cancel();
|
|
clearScanners();
|
|
setButtonGuiItem(Cancel, StdGuiItem::close());
|
|
}
|
|
|
|
void RgDialog::createScanner(const QList<int> &indexes)
|
|
{
|
|
QMap<int, QString> fileMap;
|
|
for (int i: indexes) {
|
|
fileMap[i]=origSongs.at(i).filePath(base);
|
|
}
|
|
|
|
AlbumScanner *s=new AlbumScanner(fileMap);
|
|
connect(s, SIGNAL(progress(int)), this, SLOT(scannerProgress(int)));
|
|
connect(s, SIGNAL(done()), this, SLOT(scannerDone()));
|
|
scanners[s]=0;
|
|
JobController::self()->add(s);
|
|
}
|
|
|
|
void RgDialog::clearScanners()
|
|
{
|
|
QList<AlbumScanner *> scannerList=scanners.keys();
|
|
for (AlbumScanner *sc: scannerList) {
|
|
sc->stop();
|
|
}
|
|
scanners.clear();
|
|
}
|
|
|
|
void RgDialog::startReadingTags()
|
|
{
|
|
if (tagReader) {
|
|
return;
|
|
}
|
|
setButtonGuiItem(Cancel, StdGuiItem::cancel());
|
|
state=State_ScanningTags;
|
|
enableButton(Ok, false);
|
|
enableButton(User1, false);
|
|
progress->setRange(0, origSongs.count());
|
|
progress->setVisible(true);
|
|
statusLabel->setText(tr("Reading existing tags..."));
|
|
statusLabel->setVisible(true);
|
|
tagReader=new TagReader();
|
|
tagReader->setDetails(origSongs, base);
|
|
connect(tagReader, SIGNAL(progress(int, Tags::ReplayGain)), this, SLOT(songTags(int, Tags::ReplayGain)));
|
|
connect(tagReader, SIGNAL(done()), this, SLOT(tagReaderDone()));
|
|
JobController::self()->add(tagReader);
|
|
}
|
|
|
|
void RgDialog::stopReadingTags()
|
|
{
|
|
if (!tagReader) {
|
|
return;
|
|
}
|
|
|
|
state=State_Idle;
|
|
enableButton(User1, true);
|
|
progress->setVisible(false);
|
|
statusLabel->setVisible(false);
|
|
disconnect(tagReader, SIGNAL(progress(int, Tags::ReplayGain)), this, SLOT(songTags(int, Tags::ReplayGain)));
|
|
disconnect(tagReader, SIGNAL(done()), this, SLOT(tagReaderDone()));
|
|
tagReader->requestAbort();
|
|
tagReader=0;
|
|
autoScanTags=false;
|
|
}
|
|
|
|
bool RgDialog::saveTags()
|
|
{
|
|
state=State_Saving;
|
|
enableButton(Ok, false);
|
|
enableButton(Close, false);
|
|
enableButton(Cancel, false);
|
|
enableButton(User1, false);
|
|
|
|
QStringList failed;
|
|
|
|
progress->setVisible(true);
|
|
progress->setRange(0, tagsToSave.count());
|
|
|
|
int count=0;
|
|
bool someTimedout=false;
|
|
QMap<int, Tags::ReplayGain>::ConstIterator it=tagsToSave.constBegin();
|
|
QMap<int, Tags::ReplayGain>::ConstIterator end=tagsToSave.constEnd();
|
|
|
|
for (; it!=end; ++it) {
|
|
QString filePath=origSongs.at(it.key()).filePath(base);
|
|
switch (Tags::updateReplaygain(filePath, it.value())) {
|
|
case Tags::Update_Failed:
|
|
failed.append(filePath);
|
|
break;
|
|
case Tags::Update_BadFile:
|
|
failed.append(tr("%1 (Corrupt tags?)", "filename (Corrupt tags?)").arg(filePath));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
progress->setValue(progress->value()+1);
|
|
if (0==count++%10) {
|
|
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
|
}
|
|
}
|
|
|
|
if (failed.count()) {
|
|
MessageBox::errorListEx(this, tr("Failed to update the tags of the following tracks:"), failed);
|
|
}
|
|
|
|
return !someTimedout;
|
|
}
|
|
|
|
void RgDialog::updateView()
|
|
{
|
|
int finished=0;
|
|
quint64 totalProgress=0;
|
|
QMap<AlbumScanner *, int>::ConstIterator it=scanners.constBegin();
|
|
QMap<AlbumScanner *, int>::ConstIterator end=scanners.constEnd();
|
|
|
|
for (; it!=end; ++it) {
|
|
if (100==it.value()) {
|
|
finished++;
|
|
}
|
|
totalProgress+=(*it);
|
|
}
|
|
|
|
if (finished==totalToScan) {
|
|
progress->setVisible(false);
|
|
statusLabel->setVisible(false);
|
|
state=State_Idle;
|
|
setButtonGuiItem(Cancel, StdGuiItem::close());
|
|
enableButton(Ok, !tagsToSave.isEmpty());
|
|
} else {
|
|
progress->setValue(totalProgress);
|
|
}
|
|
}
|
|
|
|
#ifdef ENABLE_DEVICES_SUPPORT
|
|
Device * RgDialog::getDevice(const QString &udi, QWidget *p)
|
|
{
|
|
Device *dev=DevicesModel::self()->device(udi);
|
|
if (!dev) {
|
|
MessageBox::error(p ? p : this, tr("Device has been removed!"));
|
|
reject();
|
|
return 0;
|
|
}
|
|
if (!dev->isConnected()) {
|
|
MessageBox::error(p ? p : this, tr("Device is not connected."));
|
|
reject();
|
|
return 0;
|
|
}
|
|
if (!dev->isIdle()) {
|
|
MessageBox::error(p ? p : this, tr("Device is busy?"));
|
|
reject();
|
|
return 0;
|
|
}
|
|
return dev;
|
|
}
|
|
#endif
|
|
|
|
void RgDialog::scannerProgress(int p)
|
|
{
|
|
AlbumScanner *s=qobject_cast<AlbumScanner *>(sender());
|
|
if (!s) {
|
|
return;
|
|
}
|
|
|
|
scanners[s]=p;
|
|
updateView();
|
|
}
|
|
|
|
void RgDialog::scannerDone()
|
|
{
|
|
AlbumScanner *s=qobject_cast<AlbumScanner *>(sender());
|
|
if (!s) {
|
|
return;
|
|
}
|
|
|
|
const QMap<int, AlbumScanner::Values> &trackValues=s->trackValues();
|
|
QMap<int, AlbumScanner::Values>::ConstIterator it(trackValues.constBegin());
|
|
QMap<int, AlbumScanner::Values>::ConstIterator end(trackValues.constEnd());
|
|
|
|
if (s->success()) {
|
|
for(; it!=end; ++it) {
|
|
Tags::ReplayGain updatedTags(it.value().gain, s->albumValues().gain, it.value().peak, s->albumValues().peak);
|
|
QTreeWidgetItem *item=view->topLevelItem(it.key());
|
|
if (it.value().ok) {
|
|
item->setText(COL_TRACKGAIN, tr("%1 dB").arg(Utils::formatNumber(updatedTags.trackGain, 2)));
|
|
if (!Utils::equal(updatedTags.trackPeak, 0.0)) {
|
|
item->setText(COL_TRACKPEAK, Utils::formatNumber(updatedTags.trackPeak, 6));
|
|
}
|
|
} else {
|
|
item->setText(COL_TRACKGAIN, tr("Failed"));
|
|
item->setText(COL_TRACKPEAK, tr("Failed"));
|
|
}
|
|
if (s->albumValues().ok) {
|
|
item->setText(COL_ALBUMGAIN, tr("%1 dB").arg(Utils::formatNumber(updatedTags.albumGain, 2)));
|
|
if (!Utils::equal(updatedTags.albumPeak, 0.0)) {
|
|
item->setText(COL_ALBUMPEAK, Utils::formatNumber(updatedTags.albumPeak, 6));
|
|
}
|
|
} else {
|
|
item->setText(COL_ALBUMGAIN, tr("Failed"));
|
|
item->setText(COL_ALBUMPEAK, tr("Failed"));
|
|
}
|
|
|
|
if (it.value().ok && origTags.contains(it.key())) {
|
|
Tags::ReplayGain t=origTags[it.key()];
|
|
bool diff=false;
|
|
bool diffAlbum=false;
|
|
if (!Utils::equal(t.trackGain, updatedTags.trackGain, 0.01)) {
|
|
item->setFont(COL_TRACKGAIN, italic);
|
|
item->setToolTip(COL_TRACKGAIN, tr("Original: %1 dB").arg(Utils::formatNumber(t.trackGain, 2)));
|
|
diff=true;
|
|
}
|
|
if (!Utils::equal(updatedTags.trackPeak, 0.0) && !Utils::equal(t.trackPeak, updatedTags.trackPeak, 0.000001)) {
|
|
item->setFont(COL_TRACKPEAK, italic);
|
|
item->setToolTip(COL_TRACKPEAK, tr("Original: %1").arg(Utils::formatNumber(t.trackPeak, 6)));
|
|
diff=true;
|
|
}
|
|
if (!Utils::equal(t.albumGain, updatedTags.albumGain, 0.01)) {
|
|
item->setFont(COL_ALBUMGAIN, italic);
|
|
item->setToolTip(COL_ALBUMGAIN, tr("Original: %1 dB").arg(Utils::formatNumber(t.albumGain, 2)));
|
|
diffAlbum=true;
|
|
}
|
|
if (!Utils::equal(updatedTags.albumPeak, 0.0) && !Utils::equal(t.albumPeak, updatedTags.albumPeak, 0.000001)) {
|
|
item->setFont(COL_ALBUMPEAK, italic);
|
|
item->setToolTip(COL_ALBUMPEAK, tr("Original: %1").arg(Utils::formatNumber(t.albumPeak, 6)));
|
|
diffAlbum=true;
|
|
}
|
|
if (diff || diffAlbum) {
|
|
if (diff) {
|
|
item->setFont(COL_ARTIST, italic);
|
|
item->setFont(COL_TITLE, italic);
|
|
}
|
|
if (diffAlbum) {
|
|
item->setFont(COL_ALBUM, italic);
|
|
}
|
|
tagsToSave.insert(it.key(), updatedTags);
|
|
} else {
|
|
tagsToSave.remove(it.key());
|
|
}
|
|
} else if (it.value().ok) {
|
|
item->setFont(COL_ARTIST, italic);
|
|
item->setFont(COL_ALBUM, italic);
|
|
item->setFont(COL_TITLE, italic);
|
|
item->setFont(COL_TRACKGAIN, italic);
|
|
item->setFont(COL_TRACKPEAK, italic);
|
|
item->setFont(COL_ALBUMGAIN, italic);
|
|
item->setFont(COL_ALBUMPEAK, italic);
|
|
tagsToSave.insert(it.key(), updatedTags);
|
|
} else {
|
|
tagsToSave.remove(it.key());
|
|
}
|
|
}
|
|
} else {
|
|
for(; it!=end; ++it) {
|
|
QTreeWidgetItem *item=view->topLevelItem(it.key());
|
|
item->setText(COL_TRACKGAIN, tr("Failed"));
|
|
item->setText(COL_TRACKPEAK, tr("Failed"));
|
|
item->setText(COL_ALBUMGAIN, tr("Failed"));
|
|
item->setText(COL_ALBUMPEAK, tr("Failed"));
|
|
tagsToSave.remove(it.key());
|
|
}
|
|
}
|
|
|
|
scanners[s]=100;
|
|
updateView();
|
|
JobController::self()->finishedWith(s);
|
|
}
|
|
|
|
void RgDialog::songTags(int index, Tags::ReplayGain tags)
|
|
{
|
|
if (index>=0 && index<origSongs.count()) {
|
|
progress->setValue(progress->value()+1);
|
|
if (!tags.isEmpty()) {
|
|
origTags[index]=tags;
|
|
|
|
QTreeWidgetItem *item=view->topLevelItem(index);
|
|
if (!item) {
|
|
return;
|
|
}
|
|
item->setText(COL_TRACKGAIN, tr("%1 dB").arg(Utils::formatNumber(tags.trackGain, 2)));
|
|
if (!Utils::equal(tags.trackPeak, 0.0)) {
|
|
item->setText(COL_TRACKPEAK, Utils::formatNumber(tags.trackPeak, 6));
|
|
}
|
|
item->setText(COL_ALBUMGAIN, tr("%1 dB").arg(Utils::formatNumber(tags.albumGain, 2)));
|
|
if (!Utils::equal(tags.albumPeak, 0.0)) {
|
|
item->setText(COL_ALBUMPEAK, Utils::formatNumber(tags.albumPeak, 6));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void RgDialog::tagReaderDone()
|
|
{
|
|
TagReader *t=qobject_cast<TagReader *>(sender());
|
|
if (!t) {
|
|
return;
|
|
}
|
|
|
|
JobController::self()->finishedWith(t);
|
|
tagReader=0;
|
|
|
|
state=State_Idle;
|
|
enableButton(User1, true);
|
|
progress->setVisible(false);
|
|
statusLabel->setVisible(false);
|
|
|
|
if (autoScanTags) {
|
|
autoScanTags=false;
|
|
startScanning();
|
|
}
|
|
}
|
|
|
|
void RgDialog::toggleDisplay()
|
|
{
|
|
bool showAll=combo->itemData(combo->currentIndex()).toBool();
|
|
|
|
for (int i=0; i<view->topLevelItemCount(); ++i) {
|
|
QTreeWidgetItem *item=view->topLevelItem(i);
|
|
if (!removedItems.contains(view->indexOfTopLevelItem(item))) {
|
|
item->setHidden(showAll ? false : origTags.contains(i));
|
|
}
|
|
}
|
|
}
|
|
|
|
void RgDialog::controlRemoveAct()
|
|
{
|
|
removeAct->setEnabled(view->topLevelItemCount()>1 && !view->selectedItems().isEmpty());
|
|
}
|
|
|
|
void RgDialog::removeItems()
|
|
{
|
|
if (view->topLevelItemCount()<1) {
|
|
return;
|
|
}
|
|
|
|
if (MessageBox::Yes==MessageBox::questionYesNo(this, tr("Remove the selected tracks from the list?"),
|
|
tr("Remove Tracks"), StdGuiItem::remove(), StdGuiItem::cancel())) {
|
|
QList<QTreeWidgetItem *> selection=view->selectedItems();
|
|
for (QTreeWidgetItem *item: selection) {
|
|
int index=view->indexOfTopLevelItem(item);
|
|
item->setHidden(true);
|
|
removedItems.insert(index);
|
|
if (tagsToSave.contains(index)) {
|
|
tagsToSave.remove(index);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void RgDialog::closeEvent(QCloseEvent *event)
|
|
{
|
|
if (State_Idle!=state) {
|
|
slotButtonClicked(Cancel);
|
|
if (State_Idle!=state) {
|
|
event->ignore();
|
|
}
|
|
} else {
|
|
Dialog::closeEvent(event);
|
|
}
|
|
}
|
|
|
|
#include "moc_rgdialog.cpp"
|