2018-02-27 18:06:05 +01:00
/*
* Strawberry Music Player
* This file was part of Clementine .
* Copyright 2010 , David Sansome < me @ davidsansome . com >
2020-09-23 00:55:34 +02:00
* Copyright 2018 - 2020 , Jonas Kvinge < jonas @ jkvinge . net >
2018-02-27 18:06:05 +01:00
*
* Strawberry 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 .
*
* Strawberry 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 Strawberry . If not , see < http : //www.gnu.org/licenses/>.
2018-08-09 18:39:44 +02:00
*
2018-02-27 18:06:05 +01:00
*/
# include "config.h"
2020-07-19 22:43:58 +02:00
# include <functional>
2018-05-01 00:41:33 +02:00
# include <algorithm>
# include <iterator>
2018-02-27 18:06:05 +01:00
# include <limits>
2018-05-01 00:41:33 +02:00
# include <QtGlobal>
2020-07-18 16:28:39 +02:00
# include <QtConcurrent>
2020-07-19 19:07:12 +02:00
# include <QFuture>
2018-05-01 00:41:33 +02:00
# include <QObject>
# include <QWidget>
# include <QDialog>
# include <QItemSelectionModel>
# include <QAbstractItemModel>
# include <QDir>
# include <QAction>
# include <QDateTime>
# include <QList>
# include <QVariant>
# include <QString>
# include <QStringBuilder>
# include <QUrl>
# include <QPixmap>
# include <QPalette>
# include <QColor>
# include <QFont>
2018-02-27 18:06:05 +01:00
# include <QLabel>
2018-05-01 00:41:33 +02:00
# include <QLineEdit>
# include <QListWidget>
# include <QLocale>
2018-02-27 18:06:05 +01:00
# include <QMenu>
# include <QMessageBox>
# include <QShortcut>
2018-05-01 00:41:33 +02:00
# include <QSize>
# include <QSpinBox>
2020-09-23 00:52:41 +02:00
# include <QCheckBox>
2018-05-01 00:41:33 +02:00
# include <QSplitter>
# include <QTabWidget>
# include <QTextEdit>
# include <QPlainTextEdit>
# include <QKeySequence>
# include <QDialogButtonBox>
# include <QPushButton>
# include <QAbstractButton>
# include <QtEvents>
# include <QSettings>
2018-02-27 18:06:05 +01:00
# include <QtDebug>
# include "core/application.h"
2018-05-01 00:41:33 +02:00
# include "core/closure.h"
# include "core/iconloader.h"
2018-02-27 18:06:05 +01:00
# include "core/logging.h"
# include "core/tagreaderclient.h"
# include "core/utilities.h"
2018-05-01 00:41:33 +02:00
# include "widgets/busyindicator.h"
# include "widgets/lineedit.h"
2018-02-27 18:06:05 +01:00
# include "collection/collectionbackend.h"
2018-05-01 00:41:33 +02:00
# include "playlist/playlist.h"
2018-02-27 18:06:05 +01:00
# include "playlist/playlistdelegates.h"
2018-07-16 07:23:37 +02:00
# if defined(HAVE_GSTREAMER) && defined(HAVE_CHROMAPRINT)
# include "musicbrainz / tagfetcher.h"
# endif
2018-05-01 00:41:33 +02:00
# include "covermanager/albumcoverchoicecontroller.h"
2018-02-27 18:06:05 +01:00
# include "covermanager/albumcoverloader.h"
2020-04-20 18:03:18 +02:00
# include "covermanager/albumcoverloaderoptions.h"
# include "covermanager/albumcoverloaderresult.h"
2018-02-27 18:06:05 +01:00
# include "covermanager/coverproviders.h"
2018-05-01 00:41:33 +02:00
# include "edittagdialog.h"
# include "trackselectiondialog.h"
# include "ui_edittagdialog.h"
2020-02-09 02:29:35 +01:00
# include "tagreadermessages.pb.h"
2018-02-27 18:06:05 +01:00
const char * EditTagDialog : : kHintText = QT_TR_NOOP ( " (different across multiple songs) " ) ;
const char * EditTagDialog : : kSettingsGroup = " EditTagDialog " ;
EditTagDialog : : EditTagDialog ( Application * app , QWidget * parent )
: QDialog ( parent ) ,
ui_ ( new Ui_EditTagDialog ) ,
app_ ( app ) ,
album_cover_choice_controller_ ( new AlbumCoverChoiceController ( this ) ) ,
loading_ ( false ) ,
ignore_edits_ ( false ) ,
2018-07-16 07:23:37 +02:00
# if defined(HAVE_GSTREAMER) && defined(HAVE_CHROMAPRINT)
2018-02-27 18:06:05 +01:00
tag_fetcher_ ( new TagFetcher ( this ) ) ,
# endif
cover_art_id_ ( 0 ) ,
cover_art_is_set_ ( false ) ,
2019-02-20 21:27:53 +01:00
results_dialog_ ( new TrackSelectionDialog ( this ) ) ,
pending_ ( 0 )
2019-02-09 14:51:12 +01:00
{
2018-02-27 18:06:05 +01:00
2020-04-20 18:03:18 +02:00
cover_options_ . default_output_image_ = AlbumCoverLoader : : ScaleAndPad ( cover_options_ , QImage ( " :/pictures/cdcase.png " ) ) . first ;
2018-02-27 18:06:05 +01:00
2020-04-20 18:03:18 +02:00
connect ( app_ - > album_cover_loader ( ) , SIGNAL ( AlbumCoverLoaded ( quint64 , AlbumCoverLoaderResult ) ) , SLOT ( AlbumCoverLoaded ( quint64 , AlbumCoverLoaderResult ) ) ) ;
2018-02-27 18:06:05 +01:00
2018-07-16 07:23:37 +02:00
# if defined(HAVE_GSTREAMER) && defined(HAVE_CHROMAPRINT)
2018-02-27 18:06:05 +01:00
connect ( tag_fetcher_ , SIGNAL ( ResultAvailable ( Song , SongList ) ) , results_dialog_ , SLOT ( FetchTagFinished ( Song , SongList ) ) , Qt : : QueuedConnection ) ;
2019-06-29 19:57:20 +02:00
connect ( tag_fetcher_ , SIGNAL ( Progress ( Song , QString ) ) , results_dialog_ , SLOT ( FetchTagProgress ( Song , QString ) ) ) ;
2018-02-27 18:06:05 +01:00
connect ( results_dialog_ , SIGNAL ( SongChosen ( Song , Song ) ) , SLOT ( FetchTagSongChosen ( Song , Song ) ) ) ;
connect ( results_dialog_ , SIGNAL ( finished ( int ) ) , tag_fetcher_ , SLOT ( Cancel ( ) ) ) ;
# endif
2019-07-07 21:14:24 +02:00
album_cover_choice_controller_ - > Init ( app_ ) ;
2018-02-27 18:06:05 +01:00
ui_ - > setupUi ( this ) ;
ui_ - > splitter - > setSizes ( QList < int > ( ) < < 200 < < width ( ) - 200 ) ;
ui_ - > loading_label - > hide ( ) ;
ui_ - > fetch_tag - > setIcon ( QPixmap : : fromImage ( QImage ( " :/pictures/musicbrainz.png " ) ) ) ;
2018-07-16 07:23:37 +02:00
# if defined(HAVE_GSTREAMER) && defined(HAVE_CHROMAPRINT)
ui_ - > fetch_tag - > setEnabled ( true ) ;
# else
ui_ - > fetch_tag - > setEnabled ( false ) ;
# endif
2018-02-27 18:06:05 +01:00
2019-02-20 21:27:53 +01:00
// An editable field is one that has a label as a buddy.
// The label is important because it gets turned bold when the field is changed.
2018-02-27 18:06:05 +01:00
for ( QLabel * label : findChildren < QLabel * > ( ) ) {
QWidget * widget = label - > buddy ( ) ;
if ( widget ) {
// Store information about the field
fields_ < < FieldData ( label , widget , widget - > objectName ( ) ) ;
// Connect the Reset signal
if ( dynamic_cast < ExtendedEditor * > ( widget ) ) {
connect ( widget , SIGNAL ( Reset ( ) ) , SLOT ( ResetField ( ) ) ) ;
}
// Connect the edited signal
if ( qobject_cast < QLineEdit * > ( widget ) ) {
connect ( widget , SIGNAL ( textChanged ( QString ) ) , SLOT ( FieldValueEdited ( ) ) ) ;
}
else if ( qobject_cast < QPlainTextEdit * > ( widget ) ) {
connect ( widget , SIGNAL ( textChanged ( ) ) , SLOT ( FieldValueEdited ( ) ) ) ;
}
else if ( qobject_cast < QSpinBox * > ( widget ) ) {
connect ( widget , SIGNAL ( valueChanged ( int ) ) , SLOT ( FieldValueEdited ( ) ) ) ;
}
2020-09-23 00:52:41 +02:00
else if ( qobject_cast < QCheckBox * > ( widget ) ) {
connect ( widget , SIGNAL ( stateChanged ( int ) ) , SLOT ( FieldValueEdited ( ) ) ) ;
}
2018-02-27 18:06:05 +01:00
}
}
// Set the colour of all the labels on the summary page
const bool light = palette ( ) . color ( QPalette : : Base ) . value ( ) > 128 ;
const QColor color = palette ( ) . color ( QPalette : : WindowText ) ;
QPalette summary_label_palette ( palette ( ) ) ;
summary_label_palette . setColor ( QPalette : : WindowText , light ? color . lighter ( 150 ) : color . darker ( 150 ) ) ;
for ( QLabel * label : ui_ - > summary_tab - > findChildren < QLabel * > ( ) ) {
if ( label - > property ( " field_label " ) . toBool ( ) ) {
label - > setPalette ( summary_label_palette ) ;
}
}
// Pretend the summary text is just a label
ui_ - > summary - > setMaximumHeight ( ui_ - > art - > height ( ) - ui_ - > summary_art_button - > height ( ) - 4 ) ;
2018-05-01 00:41:33 +02:00
connect ( ui_ - > song_list - > selectionModel ( ) , SIGNAL ( selectionChanged ( QItemSelection , QItemSelection ) ) , SLOT ( SelectionChanged ( ) ) ) ;
2018-02-27 18:06:05 +01:00
connect ( ui_ - > button_box , SIGNAL ( clicked ( QAbstractButton * ) ) , SLOT ( ButtonClicked ( QAbstractButton * ) ) ) ;
connect ( ui_ - > playcount_reset , SIGNAL ( clicked ( ) ) , SLOT ( ResetPlayCounts ( ) ) ) ;
2018-07-16 07:23:37 +02:00
# if defined(HAVE_GSTREAMER) && defined(HAVE_CHROMAPRINT)
2018-02-27 18:06:05 +01:00
connect ( ui_ - > fetch_tag , SIGNAL ( clicked ( ) ) , SLOT ( FetchTag ( ) ) ) ;
2018-07-16 07:23:37 +02:00
# endif
2018-02-27 18:06:05 +01:00
// Set up the album cover menu
cover_menu_ = new QMenu ( this ) ;
QList < QAction * > actions = album_cover_choice_controller_ - > GetAllActions ( ) ;
connect ( album_cover_choice_controller_ - > cover_from_file_action ( ) , SIGNAL ( triggered ( ) ) , this , SLOT ( LoadCoverFromFile ( ) ) ) ;
connect ( album_cover_choice_controller_ - > cover_to_file_action ( ) , SIGNAL ( triggered ( ) ) , this , SLOT ( SaveCoverToFile ( ) ) ) ;
connect ( album_cover_choice_controller_ - > cover_from_url_action ( ) , SIGNAL ( triggered ( ) ) , this , SLOT ( LoadCoverFromURL ( ) ) ) ;
connect ( album_cover_choice_controller_ - > search_for_cover_action ( ) , SIGNAL ( triggered ( ) ) , this , SLOT ( SearchForCover ( ) ) ) ;
connect ( album_cover_choice_controller_ - > unset_cover_action ( ) , SIGNAL ( triggered ( ) ) , this , SLOT ( UnsetCover ( ) ) ) ;
connect ( album_cover_choice_controller_ - > show_cover_action ( ) , SIGNAL ( triggered ( ) ) , this , SLOT ( ShowCover ( ) ) ) ;
cover_menu_ - > addActions ( actions ) ;
ui_ - > summary_art_button - > setMenu ( cover_menu_ ) ;
ui_ - > art - > installEventFilter ( this ) ;
ui_ - > art - > setAcceptDrops ( true ) ;
// Add the next/previous buttons
previous_button_ = new QPushButton ( IconLoader : : Load ( " go-previous " ) , tr ( " Previous " ) , this ) ;
next_button_ = new QPushButton ( IconLoader : : Load ( " go-next " ) , tr ( " Next " ) , this ) ;
ui_ - > button_box - > addButton ( previous_button_ , QDialogButtonBox : : ResetRole ) ;
ui_ - > button_box - > addButton ( next_button_ , QDialogButtonBox : : ResetRole ) ;
connect ( previous_button_ , SIGNAL ( clicked ( ) ) , SLOT ( PreviousSong ( ) ) ) ;
connect ( next_button_ , SIGNAL ( clicked ( ) ) , SLOT ( NextSong ( ) ) ) ;
// Set some shortcuts for the buttons
new QShortcut ( QKeySequence : : Back , previous_button_ , SLOT ( click ( ) ) ) ;
new QShortcut ( QKeySequence : : Forward , next_button_ , SLOT ( click ( ) ) ) ;
new QShortcut ( QKeySequence : : MoveToPreviousPage , previous_button_ , SLOT ( click ( ) ) ) ;
new QShortcut ( QKeySequence : : MoveToNextPage , next_button_ , SLOT ( click ( ) ) ) ;
// Show the shortcuts as tooltips
previous_button_ - > setToolTip ( QString ( " %1 (%2 / %3) " ) . arg (
previous_button_ - > text ( ) ,
QKeySequence ( QKeySequence : : Back ) . toString ( QKeySequence : : NativeText ) ,
QKeySequence ( QKeySequence : : MoveToPreviousPage ) . toString ( QKeySequence : : NativeText ) ) ) ;
next_button_ - > setToolTip ( QString ( " %1 (%2 / %3) " ) . arg (
next_button_ - > text ( ) ,
QKeySequence ( QKeySequence : : Forward ) . toString ( QKeySequence : : NativeText ) ,
QKeySequence ( QKeySequence : : MoveToNextPage ) . toString ( QKeySequence : : NativeText ) ) ) ;
new TagCompleter ( app_ - > collection_backend ( ) , Playlist : : Column_Artist , ui_ - > artist ) ;
new TagCompleter ( app_ - > collection_backend ( ) , Playlist : : Column_Album , ui_ - > album ) ;
new TagCompleter ( app_ - > collection_backend ( ) , Playlist : : Column_AlbumArtist , ui_ - > albumartist ) ;
new TagCompleter ( app_ - > collection_backend ( ) , Playlist : : Column_Genre , ui_ - > genre ) ;
new TagCompleter ( app_ - > collection_backend ( ) , Playlist : : Column_Composer , ui_ - > composer ) ;
new TagCompleter ( app_ - > collection_backend ( ) , Playlist : : Column_Performer , ui_ - > performer ) ;
new TagCompleter ( app_ - > collection_backend ( ) , Playlist : : Column_Grouping , ui_ - > grouping ) ;
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
}
EditTagDialog : : ~ EditTagDialog ( ) {
delete ui_ ;
}
bool EditTagDialog : : SetLoading ( const QString & message ) {
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
const bool loading = ! message . isEmpty ( ) ;
if ( loading = = loading_ ) return false ;
loading_ = loading ;
ui_ - > button_box - > setEnabled ( ! loading ) ;
ui_ - > tab_widget - > setEnabled ( ! loading ) ;
ui_ - > song_list - > setEnabled ( ! loading ) ;
2018-07-16 07:23:37 +02:00
# if defined(HAVE_GSTREAMER) && defined(HAVE_CHROMAPRINT)
2018-02-27 18:06:05 +01:00
ui_ - > fetch_tag - > setEnabled ( ! loading ) ;
2018-07-16 07:23:37 +02:00
# endif
2018-02-27 18:06:05 +01:00
ui_ - > loading_label - > setVisible ( loading ) ;
ui_ - > loading_label - > set_text ( message ) ;
return true ;
2018-03-10 13:02:56 +01:00
2018-02-27 18:06:05 +01:00
}
QList < EditTagDialog : : Data > EditTagDialog : : LoadData ( const SongList & songs ) const {
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
QList < Data > ret ;
for ( const Song & song : songs ) {
if ( song . IsEditable ( ) ) {
// Try reloading the tags from file
Song copy ( song ) ;
TagReaderClient : : Instance ( ) - > ReadFileBlocking ( copy . url ( ) . toLocalFile ( ) , & copy ) ;
if ( copy . is_valid ( ) ) {
copy . MergeUserSetData ( song ) ;
ret < < Data ( copy ) ;
}
}
}
return ret ;
2020-09-23 00:52:41 +02:00
2018-02-27 18:06:05 +01:00
}
void EditTagDialog : : SetSongs ( const SongList & s , const PlaylistItemList & items ) {
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
// Show the loading indicator
if ( ! SetLoading ( tr ( " Loading tracks " ) + " ... " ) ) return ;
data_ . clear ( ) ;
playlist_items_ = items ;
ui_ - > song_list - > clear ( ) ;
// Reload tags in the background
2020-11-14 02:13:22 +01:00
# if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
QFuture < QList < Data > > future = QtConcurrent : : run ( & EditTagDialog : : LoadData , this , s ) ;
# else
QFuture < QList < Data > > future = QtConcurrent : : run ( this , & EditTagDialog : : LoadData , s ) ;
# endif
2020-07-19 19:07:12 +02:00
NewClosure ( future , this , SLOT ( SetSongsFinished ( QFuture < QList < EditTagDialog : : Data > > ) ) , future ) ;
2019-02-20 21:27:53 +01:00
2018-02-27 18:06:05 +01:00
}
2020-07-19 19:07:12 +02:00
void EditTagDialog : : SetSongsFinished ( QFuture < QList < Data > > future ) {
2018-02-27 18:06:05 +01:00
if ( ! SetLoading ( QString ( ) ) ) return ;
2020-07-19 19:07:12 +02:00
data_ = future . result ( ) ;
2018-02-27 18:06:05 +01:00
if ( data_ . count ( ) = = 0 ) {
// If there were no valid songs, disable everything
ui_ - > song_list - > setEnabled ( false ) ;
ui_ - > tab_widget - > setEnabled ( false ) ;
// Show a summary with empty information
UpdateSummaryTab ( Song ( ) ) ;
ui_ - > tab_widget - > setCurrentWidget ( ui_ - > summary_tab ) ;
SetSongListVisibility ( false ) ;
return ;
}
// Add the filenames to the list
2020-04-23 21:08:28 +02:00
for ( const Data & tag_data : data_ ) {
ui_ - > song_list - > addItem ( tag_data . current_ . basefilename ( ) ) ;
2018-02-27 18:06:05 +01:00
}
// Select all
ui_ - > song_list - > setCurrentRow ( 0 ) ;
ui_ - > song_list - > selectAll ( ) ;
// Hide the list if there's only one song in it
SetSongListVisibility ( data_ . count ( ) ! = 1 ) ;
2019-02-20 21:27:53 +01:00
2018-02-27 18:06:05 +01:00
}
void EditTagDialog : : SetSongListVisibility ( bool visible ) {
2020-09-23 00:52:41 +02:00
2018-02-27 18:06:05 +01:00
ui_ - > song_list - > setVisible ( visible ) ;
previous_button_ - > setEnabled ( visible ) ;
next_button_ - > setEnabled ( visible ) ;
2020-09-23 00:52:41 +02:00
2018-02-27 18:06:05 +01:00
}
QVariant EditTagDialog : : Data : : value ( const Song & song , const QString & id ) {
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
if ( id = = " title " ) return song . title ( ) ;
if ( id = = " artist " ) return song . artist ( ) ;
if ( id = = " album " ) return song . album ( ) ;
if ( id = = " albumartist " ) return song . albumartist ( ) ;
if ( id = = " composer " ) return song . composer ( ) ;
if ( id = = " performer " ) return song . performer ( ) ;
if ( id = = " grouping " ) return song . grouping ( ) ;
if ( id = = " genre " ) return song . genre ( ) ;
if ( id = = " comment " ) return song . comment ( ) ;
2019-07-08 22:21:12 +02:00
if ( id = = " lyrics " ) return song . lyrics ( ) ;
2018-02-27 18:06:05 +01:00
if ( id = = " track " ) return song . track ( ) ;
if ( id = = " disc " ) return song . disc ( ) ;
if ( id = = " year " ) return song . year ( ) ;
2020-09-23 00:52:41 +02:00
if ( id = = " compilation " ) return song . compilation ( ) ;
2018-02-27 18:06:05 +01:00
qLog ( Warning ) < < " Unknown ID " < < id ;
return QVariant ( ) ;
}
void EditTagDialog : : Data : : set_value ( const QString & id , const QVariant & value ) {
if ( id = = " title " ) current_ . set_title ( value . toString ( ) ) ;
else if ( id = = " artist " ) current_ . set_artist ( value . toString ( ) ) ;
else if ( id = = " album " ) current_ . set_album ( value . toString ( ) ) ;
else if ( id = = " albumartist " ) current_ . set_albumartist ( value . toString ( ) ) ;
else if ( id = = " composer " ) current_ . set_composer ( value . toString ( ) ) ;
else if ( id = = " performer " ) current_ . set_performer ( value . toString ( ) ) ;
else if ( id = = " grouping " ) current_ . set_grouping ( value . toString ( ) ) ;
else if ( id = = " genre " ) current_ . set_genre ( value . toString ( ) ) ;
else if ( id = = " comment " ) current_ . set_comment ( value . toString ( ) ) ;
2019-07-08 22:21:12 +02:00
else if ( id = = " lyrics " ) current_ . set_lyrics ( value . toString ( ) ) ;
2018-02-27 18:06:05 +01:00
else if ( id = = " track " ) current_ . set_track ( value . toInt ( ) ) ;
else if ( id = = " disc " ) current_ . set_disc ( value . toInt ( ) ) ;
else if ( id = = " year " ) current_ . set_year ( value . toInt ( ) ) ;
2020-09-23 00:52:41 +02:00
else if ( id = = " compilation " ) current_ . set_compilation ( value . toBool ( ) ) ;
2018-02-27 18:06:05 +01:00
else qLog ( Warning ) < < " Unknown ID " < < id ;
}
bool EditTagDialog : : DoesValueVary ( const QModelIndexList & sel , const QString & id ) const {
2020-09-23 00:52:41 +02:00
2018-02-27 18:06:05 +01:00
QVariant value = data_ [ sel . first ( ) . row ( ) ] . current_value ( id ) ;
for ( int i = 1 ; i < sel . count ( ) ; + + i ) {
if ( value ! = data_ [ sel [ i ] . row ( ) ] . current_value ( id ) ) return true ;
}
return false ;
2020-09-23 00:52:41 +02:00
2018-02-27 18:06:05 +01:00
}
bool EditTagDialog : : IsValueModified ( const QModelIndexList & sel , const QString & id ) const {
for ( const QModelIndex & i : sel ) {
if ( data_ [ i . row ( ) ] . original_value ( id ) ! = data_ [ i . row ( ) ] . current_value ( id ) )
return true ;
}
return false ;
2018-03-10 13:02:56 +01:00
2018-02-27 18:06:05 +01:00
}
void EditTagDialog : : InitFieldValue ( const FieldData & field , const QModelIndexList & sel ) {
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
const bool varies = DoesValueVary ( sel , field . id_ ) ;
if ( ExtendedEditor * editor = dynamic_cast < ExtendedEditor * > ( field . editor_ ) ) {
editor - > clear ( ) ;
editor - > clear_hint ( ) ;
if ( varies ) {
editor - > set_hint ( tr ( EditTagDialog : : kHintText ) ) ;
2020-09-23 00:52:41 +02:00
editor - > set_partially ( ) ;
2018-02-27 18:06:05 +01:00
}
else {
2020-09-23 00:52:41 +02:00
editor - > set_value ( data_ [ sel [ 0 ] . row ( ) ] . current_value ( field . id_ ) ) ;
2018-02-27 18:06:05 +01:00
}
}
2020-09-23 00:52:41 +02:00
else {
qLog ( Error ) < < " Missing editor for " < < field . editor_ - > objectName ( ) ;
}
2018-02-27 18:06:05 +01:00
UpdateModifiedField ( field , sel ) ;
2018-03-10 13:02:56 +01:00
2018-02-27 18:06:05 +01:00
}
void EditTagDialog : : UpdateFieldValue ( const FieldData & field , const QModelIndexList & sel ) {
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
// Get the value from the field
QVariant value ;
2020-09-23 00:52:41 +02:00
2018-02-27 18:06:05 +01:00
if ( ExtendedEditor * editor = dynamic_cast < ExtendedEditor * > ( field . editor_ ) ) {
2020-09-23 00:52:41 +02:00
value = editor - > value ( ) ;
}
else {
qLog ( Error ) < < " Missing editor for " < < field . editor_ - > objectName ( ) ;
2018-02-27 18:06:05 +01:00
}
// Did we get it?
if ( ! value . isValid ( ) ) {
return ;
}
// Set it in each selected song
for ( const QModelIndex & i : sel ) {
data_ [ i . row ( ) ] . set_value ( field . id_ , value ) ;
}
UpdateModifiedField ( field , sel ) ;
2018-03-10 13:02:56 +01:00
2018-02-27 18:06:05 +01:00
}
void EditTagDialog : : UpdateModifiedField ( const FieldData & field , const QModelIndexList & sel ) {
const bool modified = IsValueModified ( sel , field . id_ ) ;
// Update the boldness
QFont new_font ( font ( ) ) ;
new_font . setBold ( modified ) ;
field . label_ - > setFont ( new_font ) ;
field . editor_ - > setFont ( new_font ) ;
2018-03-10 13:02:56 +01:00
2018-02-27 18:06:05 +01:00
}
void EditTagDialog : : ResetFieldValue ( const FieldData & field , const QModelIndexList & sel ) {
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
// Reset each selected song
for ( const QModelIndex & i : sel ) {
2020-04-23 21:08:28 +02:00
Data & tag_data = data_ [ i . row ( ) ] ;
tag_data . set_value ( field . id_ , tag_data . original_value ( field . id_ ) ) ;
2018-02-27 18:06:05 +01:00
}
// Reset the field
InitFieldValue ( field , sel ) ;
2018-03-10 13:02:56 +01:00
2018-02-27 18:06:05 +01:00
}
void EditTagDialog : : SelectionChanged ( ) {
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
const QModelIndexList sel = ui_ - > song_list - > selectionModel ( ) - > selectedIndexes ( ) ;
if ( sel . isEmpty ( ) )
return ;
// Set the editable fields
UpdateUI ( sel ) ;
// If we're editing multiple songs then we have to disable certain tabs
const bool multiple = sel . count ( ) > 1 ;
ui_ - > tab_widget - > setTabEnabled ( ui_ - > tab_widget - > indexOf ( ui_ - > summary_tab ) , ! multiple ) ;
if ( ! multiple ) {
const Song & song = data_ [ sel . first ( ) . row ( ) ] . original_ ;
UpdateSummaryTab ( song ) ;
UpdateStatisticsTab ( song ) ;
}
2018-03-10 13:02:56 +01:00
2018-02-27 18:06:05 +01:00
}
void EditTagDialog : : UpdateUI ( const QModelIndexList & sel ) {
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
ignore_edits_ = true ;
for ( const FieldData & field : fields_ ) {
InitFieldValue ( field , sel ) ;
}
ignore_edits_ = false ;
2018-03-10 13:02:56 +01:00
2018-02-27 18:06:05 +01:00
}
static void SetText ( QLabel * label , int value , const QString & suffix , const QString & def = QString ( ) ) {
label - > setText ( value < = 0 ? def : ( QString : : number ( value ) + " " + suffix ) ) ;
}
static void SetDate ( QLabel * label , uint time ) {
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
if ( time = = std : : numeric_limits < uint > : : max ( ) ) { // -1
label - > setText ( QObject : : tr ( " Unknown " ) ) ;
}
else {
2020-07-18 04:09:36 +02:00
label - > setText ( QDateTime : : fromSecsSinceEpoch ( time ) . toString ( QLocale : : system ( ) . dateTimeFormat ( QLocale : : LongFormat ) ) ) ;
2018-02-27 18:06:05 +01:00
}
2018-03-10 13:02:56 +01:00
2018-02-27 18:06:05 +01:00
}
void EditTagDialog : : UpdateSummaryTab ( const Song & song ) {
cover_art_id_ = app_ - > album_cover_loader ( ) - > LoadImageAsync ( cover_options_ , song ) ;
QString summary = " <b> " + song . PrettyTitleWithArtist ( ) . toHtmlEscaped ( ) + " </b><br/> " ;
bool art_is_set = true ;
if ( song . has_manually_unset_cover ( ) ) {
summary + = tr ( " Cover art manually unset " ) . toHtmlEscaped ( ) ;
art_is_set = false ;
}
else if ( ! song . art_manual ( ) . isEmpty ( ) ) {
2019-07-07 21:14:24 +02:00
summary + = tr ( " Cover art set from %1 " ) . arg ( song . art_manual ( ) . toString ( ) ) . toHtmlEscaped ( ) ;
2018-02-27 18:06:05 +01:00
}
else if ( song . has_embedded_cover ( ) ) {
summary + = tr ( " Cover art from embedded image " ) ;
}
else if ( ! song . art_automatic ( ) . isEmpty ( ) ) {
2019-07-07 21:14:24 +02:00
summary + = tr ( " Cover art loaded automatically from %1 " ) . arg ( song . art_automatic ( ) . toString ( ) ) . toHtmlEscaped ( ) ;
2018-02-27 18:06:05 +01:00
}
else {
summary + = tr ( " Cover art not set " ) . toHtmlEscaped ( ) ;
art_is_set = false ;
}
ui_ - > summary - > setText ( summary ) ;
album_cover_choice_controller_ - > unset_cover_action ( ) - > setEnabled ( art_is_set ) ;
album_cover_choice_controller_ - > show_cover_action ( ) - > setEnabled ( art_is_set ) ;
ui_ - > summary_art_button - > setEnabled ( song . id ( ) ! = - 1 ) ;
ui_ - > length - > setText ( Utilities : : PrettyTimeNanosec ( song . length_nanosec ( ) ) ) ;
SetText ( ui_ - > samplerate , song . samplerate ( ) , " Hz " ) ;
SetText ( ui_ - > bitdepth , song . bitdepth ( ) , " Bit " ) ;
SetText ( ui_ - > bitrate , song . bitrate ( ) , tr ( " kbps " ) ) ;
SetDate ( ui_ - > mtime , song . mtime ( ) ) ;
SetDate ( ui_ - > ctime , song . ctime ( ) ) ;
if ( song . filesize ( ) = = - 1 ) {
ui_ - > filesize - > setText ( tr ( " Unknown " ) ) ;
}
else {
ui_ - > filesize - > setText ( Utilities : : PrettySize ( song . filesize ( ) ) ) ;
}
ui_ - > filetype - > setText ( song . TextForFiletype ( ) ) ;
2019-07-09 21:43:56 +02:00
if ( song . url ( ) . isLocalFile ( ) )
2018-02-27 18:06:05 +01:00
ui_ - > filename - > setText ( QDir : : toNativeSeparators ( song . url ( ) . toLocalFile ( ) ) ) ;
else
ui_ - > filename - > setText ( song . url ( ) . toString ( ) ) ;
album_cover_choice_controller_ - > search_for_cover_action ( ) - > setEnabled ( app_ - > cover_providers ( ) - > HasAnyProviders ( ) ) ;
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
}
void EditTagDialog : : UpdateStatisticsTab ( const Song & song ) {
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
ui_ - > playcount - > setText ( QString : : number ( qMax ( 0 , song . playcount ( ) ) ) ) ;
ui_ - > skipcount - > setText ( QString : : number ( qMax ( 0 , song . skipcount ( ) ) ) ) ;
2020-07-18 04:09:36 +02:00
ui_ - > lastplayed - > setText ( song . lastplayed ( ) < = 0 ? tr ( " Never " ) : QDateTime : : fromSecsSinceEpoch ( song . lastplayed ( ) ) . toString ( QLocale : : system ( ) . dateTimeFormat ( QLocale : : LongFormat ) ) ) ;
2018-03-10 13:02:56 +01:00
2018-02-27 18:06:05 +01:00
}
2020-04-20 18:03:18 +02:00
void EditTagDialog : : AlbumCoverLoaded ( const quint64 id , const AlbumCoverLoaderResult & result ) {
2019-09-15 20:27:32 +02:00
2018-02-27 18:06:05 +01:00
if ( id = = cover_art_id_ ) {
2020-04-20 18:03:18 +02:00
ui_ - > art - > setPixmap ( QPixmap : : fromImage ( result . image_scaled ) ) ;
original_ = result . image_original ;
2018-02-27 18:06:05 +01:00
}
2018-03-10 13:02:56 +01:00
2018-02-27 18:06:05 +01:00
}
void EditTagDialog : : FieldValueEdited ( ) {
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
if ( ignore_edits_ ) return ;
const QModelIndexList sel = ui_ - > song_list - > selectionModel ( ) - > selectedIndexes ( ) ;
if ( sel . isEmpty ( ) )
return ;
QWidget * w = qobject_cast < QWidget * > ( sender ( ) ) ;
// Find the field
for ( const FieldData & field : fields_ ) {
if ( field . editor_ = = w ) {
UpdateFieldValue ( field , sel ) ;
return ;
}
}
2018-03-10 13:02:56 +01:00
2018-02-27 18:06:05 +01:00
}
void EditTagDialog : : ResetField ( ) {
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
const QModelIndexList sel = ui_ - > song_list - > selectionModel ( ) - > selectedIndexes ( ) ;
if ( sel . isEmpty ( ) )
return ;
QWidget * w = qobject_cast < QWidget * > ( sender ( ) ) ;
// Find the field
for ( const FieldData & field : fields_ ) {
if ( field . editor_ = = w ) {
ignore_edits_ = true ;
ResetFieldValue ( field , sel ) ;
ignore_edits_ = false ;
return ;
}
}
2018-03-10 13:02:56 +01:00
2018-02-27 18:06:05 +01:00
}
Song * EditTagDialog : : GetFirstSelected ( ) {
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
const QModelIndexList sel = ui_ - > song_list - > selectionModel ( ) - > selectedIndexes ( ) ;
if ( sel . isEmpty ( ) ) return nullptr ;
return & data_ [ sel . first ( ) . row ( ) ] . original_ ;
2018-03-10 13:02:56 +01:00
2018-02-27 18:06:05 +01:00
}
void EditTagDialog : : LoadCoverFromFile ( ) {
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
Song * song = GetFirstSelected ( ) ;
if ( ! song ) return ;
const QModelIndexList sel = ui_ - > song_list - > selectionModel ( ) - > selectedIndexes ( ) ;
2019-07-07 21:14:24 +02:00
QUrl cover_url = album_cover_choice_controller_ - > LoadCoverFromFile ( song ) ;
2018-02-27 18:06:05 +01:00
2019-07-07 21:14:24 +02:00
if ( ! cover_url . isEmpty ( ) ) UpdateCoverOf ( * song , sel , cover_url ) ;
2018-03-10 13:02:56 +01:00
2018-02-27 18:06:05 +01:00
}
void EditTagDialog : : SaveCoverToFile ( ) {
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
Song * song = GetFirstSelected ( ) ;
if ( ! song ) return ;
2019-03-11 23:07:11 +01:00
album_cover_choice_controller_ - > SaveCoverToFileManual ( * song , original_ ) ;
2018-03-10 13:02:56 +01:00
2018-02-27 18:06:05 +01:00
}
void EditTagDialog : : LoadCoverFromURL ( ) {
Song * song = GetFirstSelected ( ) ;
if ( ! song ) return ;
const QModelIndexList sel = ui_ - > song_list - > selectionModel ( ) - > selectedIndexes ( ) ;
2019-07-07 21:14:24 +02:00
QUrl cover_url = album_cover_choice_controller_ - > LoadCoverFromURL ( song ) ;
2018-02-27 18:06:05 +01:00
2019-07-07 21:14:24 +02:00
if ( ! cover_url . isEmpty ( ) ) UpdateCoverOf ( * song , sel , cover_url ) ;
2020-09-23 00:52:41 +02:00
2018-02-27 18:06:05 +01:00
}
void EditTagDialog : : SearchForCover ( ) {
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
Song * song = GetFirstSelected ( ) ;
if ( ! song ) return ;
const QModelIndexList sel = ui_ - > song_list - > selectionModel ( ) - > selectedIndexes ( ) ;
2019-07-07 21:14:24 +02:00
QUrl cover_url = album_cover_choice_controller_ - > SearchForCover ( song ) ;
2018-02-27 18:06:05 +01:00
2019-07-07 21:14:24 +02:00
if ( ! cover_url . isEmpty ( ) ) UpdateCoverOf ( * song , sel , cover_url ) ;
2020-09-23 00:52:41 +02:00
2018-02-27 18:06:05 +01:00
}
void EditTagDialog : : UnsetCover ( ) {
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
Song * song = GetFirstSelected ( ) ;
if ( ! song ) return ;
const QModelIndexList sel = ui_ - > song_list - > selectionModel ( ) - > selectedIndexes ( ) ;
2019-07-07 21:14:24 +02:00
QUrl cover_url = album_cover_choice_controller_ - > UnsetCover ( song ) ;
UpdateCoverOf ( * song , sel , cover_url ) ;
2020-09-23 00:52:41 +02:00
2018-02-27 18:06:05 +01:00
}
void EditTagDialog : : ShowCover ( ) {
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
Song * song = GetFirstSelected ( ) ;
if ( ! song ) {
return ;
}
album_cover_choice_controller_ - > ShowCover ( * song ) ;
2020-09-23 00:52:41 +02:00
2018-02-27 18:06:05 +01:00
}
2019-07-07 21:14:24 +02:00
void EditTagDialog : : UpdateCoverOf ( const Song & selected , const QModelIndexList & sel , const QUrl & cover_url ) {
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
if ( ! selected . is_valid ( ) | | selected . id ( ) = = - 1 ) return ;
UpdateSummaryTab ( selected ) ;
2018-05-01 00:41:33 +02:00
// Now check if we have any other songs cached that share that artist and album (and would therefore be changed as well)
2018-02-27 18:06:05 +01:00
for ( int i = 0 ; i < data_ . count ( ) ; + + i ) {
2020-10-19 21:05:59 +02:00
if ( i ! = sel . first ( ) . row ( ) ) {
Song * other_song = & data_ [ i ] . original_ ;
if ( selected . effective_albumartist ( ) = = other_song - > effective_albumartist ( ) & & selected . album ( ) = = other_song - > album ( ) ) {
other_song - > set_art_manual ( cover_url ) ;
}
2018-02-27 18:06:05 +01:00
}
2020-10-19 21:05:59 +02:00
data_ [ i ] . current_ . set_art_manual ( data_ [ i ] . original_ . art_manual ( ) ) ;
2018-02-27 18:06:05 +01:00
}
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
}
void EditTagDialog : : NextSong ( ) {
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
if ( ui_ - > song_list - > count ( ) = = 0 ) {
return ;
}
int row = ( ui_ - > song_list - > currentRow ( ) + 1 ) % ui_ - > song_list - > count ( ) ;
ui_ - > song_list - > setCurrentRow ( row ) ;
2020-09-23 00:52:41 +02:00
2018-02-27 18:06:05 +01:00
}
void EditTagDialog : : PreviousSong ( ) {
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
if ( ui_ - > song_list - > count ( ) = = 0 ) {
return ;
}
int row = ( ui_ - > song_list - > currentRow ( ) - 1 + ui_ - > song_list - > count ( ) ) % ui_ - > song_list - > count ( ) ;
ui_ - > song_list - > setCurrentRow ( row ) ;
2020-09-23 00:52:41 +02:00
2018-02-27 18:06:05 +01:00
}
void EditTagDialog : : ButtonClicked ( QAbstractButton * button ) {
2020-09-23 00:52:41 +02:00
2018-02-27 18:06:05 +01:00
if ( button = = ui_ - > button_box - > button ( QDialogButtonBox : : Discard ) ) {
reject ( ) ;
}
2020-09-23 00:52:41 +02:00
2018-02-27 18:06:05 +01:00
}
2020-04-23 21:08:28 +02:00
void EditTagDialog : : SaveData ( const QList < Data > & tag_data ) {
2018-10-02 00:38:52 +02:00
2020-04-23 21:08:28 +02:00
for ( int i = 0 ; i < tag_data . count ( ) ; + + i ) {
const Data & ref = tag_data [ i ] ;
2018-02-27 18:06:05 +01:00
if ( ref . current_ . IsMetadataEqual ( ref . original_ ) ) continue ;
2019-02-20 21:27:53 +01:00
pending_ + + ;
TagReaderReply * reply = TagReaderClient : : Instance ( ) - > SaveFile ( ref . current_ . url ( ) . toLocalFile ( ) , ref . current_ ) ;
NewClosure ( reply , SIGNAL ( Finished ( bool ) ) , this , SLOT ( SongSaveComplete ( TagReaderReply * , QString , Song ) ) , reply , ref . current_ . url ( ) . toLocalFile ( ) , ref . current_ ) ;
2018-02-27 18:06:05 +01:00
}
2019-02-20 21:27:53 +01:00
if ( pending_ < = 0 ) AcceptFinished ( ) ;
2018-02-27 18:06:05 +01:00
}
void EditTagDialog : : accept ( ) {
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
// Show the loading indicator
if ( ! SetLoading ( tr ( " Saving tracks " ) + " ... " ) ) return ;
2019-02-20 21:27:53 +01:00
SaveData ( data_ ) ;
2018-02-27 18:06:05 +01:00
}
void EditTagDialog : : AcceptFinished ( ) {
if ( ! SetLoading ( QString ( ) ) ) return ;
QDialog : : accept ( ) ;
}
bool EditTagDialog : : eventFilter ( QObject * o , QEvent * e ) {
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
if ( o = = ui_ - > art ) {
switch ( e - > type ( ) ) {
case QEvent : : MouseButtonRelease :
2020-07-18 04:09:36 +02:00
# if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
cover_menu_ - > popup ( static_cast < QMouseEvent * > ( e ) - > globalPosition ( ) . toPoint ( ) ) ;
# else
2018-02-27 18:06:05 +01:00
cover_menu_ - > popup ( static_cast < QMouseEvent * > ( e ) - > globalPos ( ) ) ;
2020-07-18 04:09:36 +02:00
# endif
2018-02-27 18:06:05 +01:00
break ;
case QEvent : : DragEnter : {
QDragEnterEvent * event = static_cast < QDragEnterEvent * > ( e ) ;
if ( AlbumCoverChoiceController : : CanAcceptDrag ( event ) ) {
event - > acceptProposedAction ( ) ;
}
break ;
}
case QEvent : : Drop : {
const QDropEvent * event = static_cast < QDropEvent * > ( e ) ;
const QModelIndexList sel = ui_ - > song_list - > selectionModel ( ) - > selectedIndexes ( ) ;
Song * song = GetFirstSelected ( ) ;
2019-07-07 21:14:24 +02:00
const QUrl cover_url = album_cover_choice_controller_ - > SaveCover ( song , event ) ;
if ( ! cover_url . isEmpty ( ) ) {
UpdateCoverOf ( * song , sel , cover_url ) ;
2018-02-27 18:06:05 +01:00
}
break ;
}
default :
break ;
}
}
return false ;
2020-09-23 00:52:41 +02:00
2018-02-27 18:06:05 +01:00
}
void EditTagDialog : : showEvent ( QShowEvent * e ) {
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
// Set the dialog's height to the smallest possible
resize ( width ( ) , sizeHint ( ) . height ( ) ) ;
// Restore the tab that was current last time.
QSettings s ;
s . beginGroup ( kSettingsGroup ) ;
2020-11-22 03:37:15 +01:00
if ( s . contains ( " geometry " ) ) {
restoreGeometry ( s . value ( " geometry " ) . toByteArray ( ) ) ;
}
2018-02-27 18:06:05 +01:00
ui_ - > tab_widget - > setCurrentIndex ( s . value ( " current_tab " ) . toInt ( ) ) ;
2020-11-22 03:37:15 +01:00
s . endGroup ( ) ;
2018-02-27 18:06:05 +01:00
QDialog : : showEvent ( e ) ;
2020-09-23 00:52:41 +02:00
2018-02-27 18:06:05 +01:00
}
void EditTagDialog : : hideEvent ( QHideEvent * e ) {
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
// Save the current tab
QSettings s ;
s . beginGroup ( kSettingsGroup ) ;
2020-11-22 03:37:15 +01:00
s . setValue ( " geometry " , saveGeometry ( ) ) ;
2018-02-27 18:06:05 +01:00
s . setValue ( " current_tab " , ui_ - > tab_widget - > currentIndex ( ) ) ;
2020-11-22 03:37:15 +01:00
s . endGroup ( ) ;
2018-02-27 18:06:05 +01:00
QDialog : : hideEvent ( e ) ;
2020-09-23 00:52:41 +02:00
2018-02-27 18:06:05 +01:00
}
void EditTagDialog : : ResetPlayCounts ( ) {
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
const QModelIndexList sel = ui_ - > song_list - > selectionModel ( ) - > selectedIndexes ( ) ;
if ( sel . isEmpty ( ) )
return ;
Song * song = & data_ [ sel . first ( ) . row ( ) ] . original_ ;
if ( ! song - > is_valid ( ) | | song - > id ( ) = = - 1 ) return ;
if ( QMessageBox : : question ( this , tr ( " Reset play counts " ) , tr ( " Are you sure you want to reset this song's statistics? " ) , QMessageBox : : Reset , QMessageBox : : Cancel ) ! = QMessageBox : : Reset ) {
return ;
}
song - > set_playcount ( 0 ) ;
song - > set_skipcount ( 0 ) ;
song - > set_lastplayed ( - 1 ) ;
2020-08-10 21:27:27 +02:00
if ( song - > is_collection_song ( ) )
app_ - > collection_backend ( ) - > ResetStatisticsAsync ( song - > id ( ) ) ;
2018-02-27 18:06:05 +01:00
UpdateStatisticsTab ( * song ) ;
2020-08-10 21:27:27 +02:00
2018-02-27 18:06:05 +01:00
}
void EditTagDialog : : FetchTag ( ) {
2018-10-02 00:38:52 +02:00
2019-10-03 23:29:52 +02:00
# if defined(HAVE_GSTREAMER) && defined(HAVE_CHROMAPRINT)
2018-02-27 18:06:05 +01:00
const QModelIndexList sel = ui_ - > song_list - > selectionModel ( ) - > selectedIndexes ( ) ;
SongList songs ;
for ( const QModelIndex & index : sel ) {
Song song = data_ [ index . row ( ) ] . original_ ;
if ( ! song . is_valid ( ) ) {
continue ;
}
songs < < song ;
}
if ( songs . isEmpty ( ) ) return ;
results_dialog_ - > Init ( songs ) ;
tag_fetcher_ - > StartFetch ( songs ) ;
results_dialog_ - > show ( ) ;
2018-03-10 13:02:56 +01:00
2019-10-03 23:29:52 +02:00
# endif
2018-02-27 18:06:05 +01:00
}
void EditTagDialog : : FetchTagSongChosen ( const Song & original_song , const Song & new_metadata ) {
2018-10-02 00:38:52 +02:00
2019-10-03 23:29:52 +02:00
# if defined(HAVE_GSTREAMER) && defined(HAVE_CHROMAPRINT)
2018-02-27 18:06:05 +01:00
const QString filename = original_song . url ( ) . toLocalFile ( ) ;
// Find the song with this filename
2019-02-20 21:27:53 +01:00
auto data_it = std : : find_if ( data_ . begin ( ) , data_ . end ( ) , [ & filename ] ( const Data & d ) {
return d . original_ . url ( ) . toLocalFile ( ) = = filename ;
} ) ;
2018-02-27 18:06:05 +01:00
if ( data_it = = data_ . end ( ) ) {
qLog ( Warning ) < < " Could not find song to filename: " < < filename ;
return ;
}
// Update song data
data_it - > current_ . set_title ( new_metadata . title ( ) ) ;
data_it - > current_ . set_artist ( new_metadata . artist ( ) ) ;
data_it - > current_ . set_album ( new_metadata . album ( ) ) ;
data_it - > current_ . set_track ( new_metadata . track ( ) ) ;
data_it - > current_ . set_year ( new_metadata . year ( ) ) ;
// Is it currently being displayed in the UI?
if ( ui_ - > song_list - > currentRow ( ) = = std : : distance ( data_ . begin ( ) , data_it ) ) {
// Yes! Additionally update UI
const QModelIndexList sel = ui_ - > song_list - > selectionModel ( ) - > selectedIndexes ( ) ;
UpdateUI ( sel ) ;
}
2019-02-20 21:27:53 +01:00
2019-10-03 23:29:52 +02:00
# else
Q_UNUSED ( original_song )
Q_UNUSED ( new_metadata )
2018-02-27 18:06:05 +01:00
# endif
2019-02-20 21:27:53 +01:00
2019-10-03 23:29:52 +02:00
}
2019-07-02 00:48:09 +02:00
void EditTagDialog : : SongSaveComplete ( TagReaderReply * reply , const QString & filename , const Song & song ) {
2019-02-20 21:27:53 +01:00
pending_ - - ;
if ( ! reply - > message ( ) . save_file_response ( ) . success ( ) ) {
2019-02-22 20:24:38 +01:00
QString message = tr ( " An error occurred writing metadata to '%1' " ) . arg ( filename ) ;
2019-02-20 21:27:53 +01:00
emit Error ( message ) ;
}
2020-08-10 21:27:27 +02:00
else if ( song . is_collection_song ( ) ) {
2019-11-03 23:23:04 +01:00
app_ - > collection_backend ( ) - > AddOrUpdateSongs ( SongList ( ) < < song ) ;
2019-02-20 21:27:53 +01:00
}
if ( pending_ < = 0 ) AcceptFinished ( ) ;
2019-07-22 20:53:05 +02:00
reply - > deleteLater ( ) ;
2019-06-22 08:36:02 +02:00
2019-02-20 21:27:53 +01:00
}