2010-05-10 23:50:31 +02:00
/* This file is part of Clementine.
2010-11-20 14:27:10 +01:00
Copyright 2010 , David Sansome < me @ davidsansome . com >
2010-05-10 23:50:31 +02:00
Clementine is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
Clementine is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with Clementine . If not , see < http : //www.gnu.org/licenses/>.
*/
2010-12-20 16:46:38 +01:00
# include "albumcovermanager.h"
2010-05-10 23:50:31 +02:00
# include "edittagdialog.h"
2011-01-21 00:42:28 +01:00
# include "trackselectiondialog.h"
2010-05-10 23:50:31 +02:00
# include "ui_edittagdialog.h"
2011-04-22 18:50:29 +02:00
# include "core/logging.h"
2010-12-20 15:12:40 +01:00
# include "core/utilities.h"
2011-04-02 15:34:06 +02:00
# include "covers/albumcoverloader.h"
2011-04-27 21:10:37 +02:00
# include "covers/coverproviders.h"
2010-05-10 23:50:31 +02:00
# include "library/library.h"
2010-12-20 16:46:38 +01:00
# include "library/librarybackend.h"
2011-03-12 23:29:13 +01:00
# include "musicbrainz/fingerprinter.h"
2010-05-10 23:50:31 +02:00
# include "playlist/playlistdelegates.h"
2011-01-24 01:09:57 +01:00
# include "ui/albumcoverchoicecontroller.h"
2011-01-23 21:24:17 +01:00
# include "ui/coverfromurldialog.h"
2010-05-10 23:50:31 +02:00
2010-12-20 15:12:40 +01:00
# include <QDateTime>
2011-01-24 01:09:57 +01:00
# include <QDir>
2010-12-21 14:42:06 +01:00
# include <QFuture>
# include <QFutureWatcher>
2010-12-20 15:12:40 +01:00
# include <QLabel>
2010-12-20 16:46:38 +01:00
# include <QMenu>
2010-12-25 12:54:21 +01:00
# include <QMessageBox>
2010-12-20 17:36:16 +01:00
# include <QPushButton>
2010-12-25 00:35:34 +01:00
# include <QShortcut>
2010-12-21 14:42:06 +01:00
# include <QtConcurrentRun>
2010-05-10 23:50:31 +02:00
# include <QtDebug>
2010-12-20 00:40:36 +01:00
const char * EditTagDialog : : kHintText = QT_TR_NOOP ( " (different across multiple songs) " ) ;
2010-05-10 23:50:31 +02:00
2011-07-23 20:34:41 +02:00
EditTagDialog : : EditTagDialog ( CoverProviders * cover_providers , QWidget * parent )
2010-05-10 23:50:31 +02:00
: QDialog ( parent ) ,
2010-12-20 00:40:36 +01:00
ui_ ( new Ui_EditTagDialog ) ,
2011-07-23 20:34:41 +02:00
cover_providers_ ( cover_providers ) ,
2011-01-26 00:33:27 +01:00
album_cover_choice_controller_ ( new AlbumCoverChoiceController ( this ) ) ,
2010-12-20 16:46:38 +01:00
backend_ ( NULL ) ,
2010-12-21 14:42:06 +01:00
loading_ ( false ) ,
2010-12-20 16:46:38 +01:00
ignore_edits_ ( false ) ,
2011-03-05 20:24:44 +01:00
tag_fetcher_ ( new TagFetcher ( this ) ) ,
2010-12-20 15:12:40 +01:00
cover_loader_ ( new BackgroundThreadImplementation < AlbumCoverLoader , AlbumCoverLoader > ( this ) ) ,
cover_art_id_ ( 0 ) ,
2011-01-21 00:42:28 +01:00
cover_art_is_set_ ( false ) ,
2011-01-24 18:03:36 +01:00
results_dialog_ ( new TrackSelectionDialog ( this ) )
2010-05-10 23:50:31 +02:00
{
2010-12-20 15:12:40 +01:00
cover_loader_ - > Start ( true ) ;
cover_loader_ - > Worker ( ) - > SetDefaultOutputImage ( QImage ( " :nocover.png " ) ) ;
2011-02-02 17:22:04 +01:00
connect ( cover_loader_ - > Worker ( ) . get ( ) , SIGNAL ( ImageLoaded ( quint64 , QImage , QImage ) ) ,
SLOT ( ArtLoaded ( quint64 , QImage , QImage ) ) ) ;
2011-03-12 22:19:41 +01:00
connect ( tag_fetcher_ , SIGNAL ( ResultAvailable ( Song , SongList ) ) ,
2011-03-12 23:29:13 +01:00
results_dialog_ , SLOT ( FetchTagFinished ( Song , SongList ) ) ,
2011-03-05 20:24:44 +01:00
Qt : : QueuedConnection ) ;
2011-03-12 22:19:41 +01:00
connect ( tag_fetcher_ , SIGNAL ( Progress ( Song , QString ) ) ,
results_dialog_ , SLOT ( FetchTagProgress ( Song , QString ) ) ) ;
2011-03-06 15:07:41 +01:00
connect ( results_dialog_ , SIGNAL ( SongChosen ( Song , Song ) ) ,
SLOT ( FetchTagSongChosen ( Song , Song ) ) ) ;
2011-03-13 13:52:08 +01:00
connect ( results_dialog_ , SIGNAL ( finished ( int ) ) , tag_fetcher_ , SLOT ( Cancel ( ) ) ) ;
2010-12-26 13:42:47 +01:00
2011-07-23 20:34:41 +02:00
album_cover_choice_controller_ - > SetCoverProviders ( cover_providers ) ;
2010-05-10 23:50:31 +02:00
ui_ - > setupUi ( this ) ;
2010-12-20 00:40:36 +01:00
ui_ - > splitter - > setSizes ( QList < int > ( ) < < 200 < < width ( ) - 200 ) ;
2011-08-27 16:00:49 +02:00
ui_ - > loading_label - > hide ( ) ;
2010-12-20 00:40:36 +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.
foreach ( 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 ( ) ) ) ;
}
}
}
2010-12-25 00:22:09 +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 : : Dark ) ;
QPalette summary_label_palette ( palette ( ) ) ;
summary_label_palette . setColor ( QPalette : : WindowText ,
light ? color . darker ( 150 ) : color . lighter ( 125 ) ) ;
foreach ( 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 ) ;
2010-12-20 00:40:36 +01:00
connect ( ui_ - > song_list - > selectionModel ( ) ,
SIGNAL ( selectionChanged ( QItemSelection , QItemSelection ) ) ,
SLOT ( SelectionChanged ( ) ) ) ;
2010-12-21 14:42:06 +01:00
connect ( ui_ - > button_box , SIGNAL ( clicked ( QAbstractButton * ) ) ,
SLOT ( ButtonClicked ( QAbstractButton * ) ) ) ;
2010-12-25 01:33:53 +01:00
connect ( ui_ - > rating , SIGNAL ( RatingChanged ( float ) ) ,
SLOT ( SongRated ( float ) ) ) ;
2010-12-25 12:54:21 +01:00
connect ( ui_ - > playcount_reset , SIGNAL ( clicked ( ) ) , SLOT ( ResetPlayCounts ( ) ) ) ;
2011-01-15 21:00:39 +01:00
connect ( ui_ - > fetch_tag , SIGNAL ( clicked ( ) ) , SLOT ( FetchTag ( ) ) ) ;
2010-12-20 16:46:38 +01:00
// Set up the album cover menu
cover_menu_ = new QMenu ( this ) ;
2011-01-24 19:32:09 +01:00
2011-01-26 00:33:27 +01:00
QList < QAction * > actions = album_cover_choice_controller_ - > GetAllActions ( ) ;
2011-01-24 19:32:09 +01:00
2011-01-26 00:33:27 +01:00
connect ( album_cover_choice_controller_ - > cover_from_file_action ( ) ,
SIGNAL ( triggered ( ) ) , this , SLOT ( LoadCoverFromFile ( ) ) ) ;
2011-02-02 17:22:04 +01:00
connect ( album_cover_choice_controller_ - > cover_to_file_action ( ) ,
SIGNAL ( triggered ( ) ) , this , SLOT ( SaveCoverToFile ( ) ) ) ;
2011-01-26 00:33:27 +01:00
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 ( ) ) ) ;
2011-01-24 19:32:09 +01:00
cover_menu_ - > addActions ( actions ) ;
2010-12-20 16:46:38 +01:00
ui_ - > summary_art_button - > setMenu ( cover_menu_ ) ;
2010-12-20 17:36:16 +01:00
2010-12-25 00:22:09 +01:00
ui_ - > art - > installEventFilter ( this ) ;
2011-03-14 21:01:27 +01:00
ui_ - > art - > setAcceptDrops ( true ) ;
2010-12-25 00:22:09 +01:00
2010-12-20 17:36:16 +01:00
// 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 ( ) ) ) ;
2010-12-25 00:35:34 +01:00
// 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 ( ) ) ) ;
2010-05-10 23:50:31 +02:00
}
EditTagDialog : : ~ EditTagDialog ( ) {
delete ui_ ;
}
2010-12-21 14:42:06 +01:00
bool EditTagDialog : : SetLoading ( const QString & message ) {
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 ) ;
2011-01-15 21:00:39 +01:00
ui_ - > fetch_tag - > setEnabled ( ! loading ) ;
2011-08-27 16:00:49 +02:00
ui_ - > loading_label - > setVisible ( loading ) ;
ui_ - > loading_label - > set_text ( message ) ;
2010-12-21 14:42:06 +01:00
return true ;
}
QList < EditTagDialog : : Data > EditTagDialog : : LoadData ( const SongList & songs ) const {
QList < Data > ret ;
2010-05-10 23:50:31 +02:00
2010-12-21 14:42:06 +01:00
foreach ( const Song & song , songs ) {
2010-09-02 21:12:09 +02:00
if ( song . IsEditable ( ) ) {
// Try reloading the tags from file
Song copy ( song ) ;
2011-04-28 14:27:53 +02:00
copy . InitFromFile ( copy . url ( ) . toLocalFile ( ) , copy . directory_id ( ) ) ;
2010-09-02 21:12:09 +02:00
if ( copy . is_valid ( ) )
2010-12-21 14:42:06 +01:00
ret < < Data ( copy ) ;
2010-09-02 21:12:09 +02:00
}
2010-05-10 23:50:31 +02:00
}
2010-12-21 14:42:06 +01:00
return ret ;
}
void EditTagDialog : : SetSongs ( const SongList & s , const PlaylistItemList & items ) {
// Show the loading indicator
if ( ! SetLoading ( tr ( " Loading tracks " ) + " ... " ) )
return ;
data_ . clear ( ) ;
playlist_items_ = items ;
ui_ - > song_list - > clear ( ) ;
// Reload tags in the background
QFuture < QList < Data > > future = QtConcurrent : : run ( this , & EditTagDialog : : LoadData , s ) ;
QFutureWatcher < QList < Data > > * watcher = new QFutureWatcher < QList < Data > > ( this ) ;
watcher - > setFuture ( future ) ;
connect ( watcher , SIGNAL ( finished ( ) ) , SLOT ( SetSongsFinished ( ) ) ) ;
}
void EditTagDialog : : SetSongsFinished ( ) {
QFutureWatcher < QList < Data > > * watcher = dynamic_cast < QFutureWatcher < QList < Data > > * > ( sender ( ) ) ;
if ( ! watcher )
return ;
watcher - > deleteLater ( ) ;
if ( ! SetLoading ( QString ( ) ) )
return ;
data_ = watcher - > result ( ) ;
2010-12-20 00:40:36 +01:00
if ( data_ . count ( ) = = 0 )
2010-12-21 14:42:06 +01:00
return ;
2010-05-10 23:50:31 +02:00
2010-12-20 00:40:36 +01:00
// Add the filenames to the list
foreach ( const Data & data , data_ ) {
ui_ - > song_list - > addItem ( data . current_ . basefilename ( ) ) ;
}
2010-05-10 23:50:31 +02:00
2010-12-20 00:40:36 +01:00
// Select all
2011-03-05 20:24:44 +01:00
ui_ - > song_list - > setCurrentRow ( 0 ) ;
2010-12-20 00:40:36 +01:00
ui_ - > song_list - > selectAll ( ) ;
2010-05-10 23:50:31 +02:00
2010-12-20 00:40:36 +01:00
// Hide the list if there's only one song in it
2010-12-20 17:36:16 +01:00
const bool multiple = data_ . count ( ) ! = 1 ;
ui_ - > song_list - > setVisible ( multiple ) ;
previous_button_ - > setEnabled ( multiple ) ;
next_button_ - > setEnabled ( multiple ) ;
2010-05-10 23:50:31 +02:00
}
void EditTagDialog : : SetTagCompleter ( LibraryBackend * backend ) {
2010-12-20 16:46:38 +01:00
backend_ = backend ;
2011-01-26 00:33:27 +01:00
album_cover_choice_controller_ - > SetLibrary ( backend ) ;
2011-01-24 18:53:31 +01:00
2010-05-10 23:50:31 +02:00
new TagCompleter ( backend , Playlist : : Column_Artist , ui_ - > artist ) ;
new TagCompleter ( backend , Playlist : : Column_Album , ui_ - > album ) ;
2010-12-25 14:11:09 +01:00
new TagCompleter ( backend , Playlist : : Column_AlbumArtist , ui_ - > albumartist ) ;
new TagCompleter ( backend , Playlist : : Column_Genre , ui_ - > genre ) ;
new TagCompleter ( backend , Playlist : : Column_Composer , ui_ - > composer ) ;
2010-05-10 23:50:31 +02:00
}
2010-12-20 00:40:36 +01:00
QVariant EditTagDialog : : Data : : value ( const Song & song , const QString & id ) {
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 = = " genre " ) return song . genre ( ) ;
if ( id = = " comment " ) return song . comment ( ) ;
if ( id = = " track " ) return song . track ( ) ;
if ( id = = " disc " ) return song . disc ( ) ;
if ( id = = " year " ) return song . year ( ) ;
2011-04-22 18:50:29 +02:00
qLog ( Warning ) < < " Unknown ID " < < id ;
2010-12-20 00:40:36 +01:00
return QVariant ( ) ;
}
2010-05-10 23:50:31 +02:00
2010-12-20 00:40:36 +01:00
void EditTagDialog : : Data : : set_value ( const QString & id , const QVariant & value ) {
if ( id = = " title " ) current_ . set_title ( value . toString ( ) ) ;
if ( id = = " artist " ) current_ . set_artist ( value . toString ( ) ) ;
if ( id = = " album " ) current_ . set_album ( value . toString ( ) ) ;
if ( id = = " albumartist " ) current_ . set_albumartist ( value . toString ( ) ) ;
if ( id = = " composer " ) current_ . set_composer ( value . toString ( ) ) ;
if ( id = = " genre " ) current_ . set_genre ( value . toString ( ) ) ;
if ( id = = " comment " ) current_ . set_comment ( value . toString ( ) ) ;
if ( id = = " track " ) current_ . set_track ( value . toInt ( ) ) ;
if ( id = = " disc " ) current_ . set_disc ( value . toInt ( ) ) ;
if ( id = = " year " ) current_ . set_year ( value . toInt ( ) ) ;
}
2010-05-10 23:50:31 +02:00
2010-12-20 00:40:36 +01:00
bool EditTagDialog : : DoesValueVary ( const QModelIndexList & sel , const QString & id ) const {
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 ;
}
2010-05-10 23:50:31 +02:00
2010-12-20 00:40:36 +01:00
bool EditTagDialog : : IsValueModified ( const QModelIndexList & sel , const QString & id ) const {
foreach ( const QModelIndex & i , sel ) {
if ( data_ [ i . row ( ) ] . original_value ( id ) ! = data_ [ i . row ( ) ] . current_value ( id ) )
return true ;
}
return false ;
}
2010-05-10 23:50:31 +02:00
2010-12-20 00:40:36 +01:00
void EditTagDialog : : InitFieldValue ( const FieldData & field , const QModelIndexList & sel ) {
const bool varies = DoesValueVary ( sel , field . id_ ) ;
const bool modified = IsValueModified ( sel , field . id_ ) ;
if ( ExtendedEditor * editor = dynamic_cast < ExtendedEditor * > ( field . editor_ ) ) {
editor - > clear ( ) ;
editor - > clear_hint ( ) ;
if ( varies ) {
editor - > set_hint ( EditTagDialog : : kHintText ) ;
} else {
editor - > set_text ( data_ [ sel [ 0 ] . row ( ) ] . current_value ( field . id_ ) . toString ( ) ) ;
}
}
2010-05-10 23:50:31 +02:00
2010-12-20 00:40:36 +01:00
QFont new_font ( font ( ) ) ;
new_font . setBold ( modified ) ;
field . label_ - > setFont ( new_font ) ;
field . editor_ - > setFont ( new_font ) ;
}
void EditTagDialog : : UpdateFieldValue ( const FieldData & field , const QModelIndexList & sel ) {
// Get the value from the field
QVariant value ;
if ( ExtendedEditor * editor = dynamic_cast < ExtendedEditor * > ( field . editor_ ) ) {
value = editor - > text ( ) ;
}
2010-05-10 23:50:31 +02:00
2010-12-20 00:40:36 +01:00
// Did we get it?
if ( ! value . isValid ( ) ) {
return ;
2010-05-10 23:50:31 +02:00
}
2010-12-20 00:40:36 +01:00
// Set it in each selected song
foreach ( const QModelIndex & i , sel ) {
data_ [ i . row ( ) ] . set_value ( field . id_ , value ) ;
}
// Update the boldness
const bool modified = IsValueModified ( sel , field . id_ ) ;
QFont new_font ( font ( ) ) ;
new_font . setBold ( modified ) ;
field . label_ - > setFont ( new_font ) ;
field . editor_ - > setFont ( new_font ) ;
2010-08-02 17:07:26 +02:00
}
2010-12-20 00:40:36 +01:00
void EditTagDialog : : ResetFieldValue ( const FieldData & field , const QModelIndexList & sel ) {
// Reset each selected song
foreach ( const QModelIndex & i , sel ) {
Data & data = data_ [ i . row ( ) ] ;
data . set_value ( field . id_ , data . original_value ( field . id_ ) ) ;
}
// Reset the field
InitFieldValue ( field , sel ) ;
2010-08-02 17:07:26 +02:00
}
2010-12-20 00:40:36 +01:00
void EditTagDialog : : SelectionChanged ( ) {
const QModelIndexList sel = ui_ - > song_list - > selectionModel ( ) - > selectedIndexes ( ) ;
if ( sel . isEmpty ( ) )
return ;
2010-12-20 15:12:40 +01:00
// Set the editable fields
2010-12-20 00:40:36 +01:00
ignore_edits_ = true ;
foreach ( const FieldData & field , fields_ ) {
InitFieldValue ( field , sel ) ;
}
ignore_edits_ = false ;
2010-12-20 15:12:40 +01:00
// 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 ) ;
}
}
static void SetText ( QLabel * label , int value , const QString & suffix , const QString & def = QString ( ) ) {
label - > setText ( value < = 0 ? def : ( QString : : number ( value ) + " " + suffix ) ) ;
}
void EditTagDialog : : UpdateSummaryTab ( const Song & song ) {
cover_art_id_ = cover_loader_ - > Worker ( ) - > LoadImageAsync ( song ) ;
QString summary = " <b> " + Qt : : escape ( song . PrettyTitleWithArtist ( ) ) + " </b><br/> " ;
2010-12-20 16:46:38 +01:00
bool art_is_set = true ;
2011-02-02 22:01:08 +01:00
if ( song . has_manually_unset_cover ( ) ) {
2010-12-20 15:12:40 +01:00
summary + = Qt : : escape ( tr ( " Cover art manually unset " ) ) ;
2010-12-20 16:46:38 +01:00
art_is_set = false ;
2010-12-20 15:12:40 +01:00
} else if ( ! song . art_manual ( ) . isEmpty ( ) ) {
summary + = Qt : : escape ( tr ( " Cover art set from %1 " ) . arg ( song . art_manual ( ) ) ) ;
2011-02-02 22:01:08 +01:00
} else if ( song . has_embedded_cover ( ) ) {
2010-12-20 15:12:40 +01:00
summary + = Qt : : escape ( tr ( " Cover art from embedded image " ) ) ;
} else if ( ! song . art_automatic ( ) . isEmpty ( ) ) {
summary + = Qt : : escape ( tr ( " Cover art loaded automatically from %1 " ) . arg ( song . art_manual ( ) ) ) ;
} else {
summary + = Qt : : escape ( tr ( " Cover art not set " ) ) ;
2010-12-20 16:46:38 +01:00
art_is_set = false ;
2010-12-20 15:12:40 +01:00
}
ui_ - > summary - > setText ( summary ) ;
2011-01-26 00:33:27 +01:00
album_cover_choice_controller_ - > unset_cover_action ( ) - > setEnabled ( art_is_set ) ;
album_cover_choice_controller_ - > show_cover_action ( ) - > setEnabled ( art_is_set ) ;
2010-12-20 16:46:38 +01:00
ui_ - > summary_art_button - > setEnabled ( song . id ( ) ! = - 1 ) ;
2011-02-13 19:34:30 +01:00
ui_ - > length - > setText ( Utilities : : PrettyTimeNanosec ( song . length_nanosec ( ) ) ) ;
2010-12-20 15:12:40 +01:00
SetText ( ui_ - > bpm , song . bpm ( ) , tr ( " bpm " ) ) ;
SetText ( ui_ - > samplerate , song . samplerate ( ) , " Hz " ) ;
SetText ( ui_ - > bitrate , song . bitrate ( ) , tr ( " kbps " ) ) ;
ui_ - > mtime - > setText ( QDateTime : : fromTime_t ( song . mtime ( ) ) . toString (
QLocale : : system ( ) . dateTimeFormat ( QLocale : : LongFormat ) ) ) ;
ui_ - > ctime - > setText ( QDateTime : : fromTime_t ( song . ctime ( ) ) . toString (
QLocale : : system ( ) . dateTimeFormat ( QLocale : : LongFormat ) ) ) ;
ui_ - > filesize - > setText ( Utilities : : PrettySize ( song . filesize ( ) ) ) ;
2010-12-25 00:22:09 +01:00
ui_ - > filetype - > setText ( song . TextForFiletype ( ) ) ;
2011-04-28 14:27:53 +02:00
if ( song . url ( ) . scheme ( ) = = " file " )
ui_ - > filename - > setText ( QDir : : toNativeSeparators ( song . url ( ) . toLocalFile ( ) ) ) ;
else
ui_ - > filename - > setText ( song . url ( ) . toString ( ) ) ;
2011-04-27 21:10:37 +02:00
2011-07-23 20:34:41 +02:00
album_cover_choice_controller_ - > search_for_cover_action ( ) - > setEnabled ( cover_providers_ - > HasAnyProviders ( ) ) ;
2010-12-20 15:12:40 +01:00
}
void EditTagDialog : : UpdateStatisticsTab ( const Song & song ) {
ui_ - > playcount - > setText ( QString : : number ( qMax ( 0 , song . playcount ( ) ) ) ) ;
ui_ - > skipcount - > setText ( QString : : number ( qMax ( 0 , song . skipcount ( ) ) ) ) ;
ui_ - > score - > setText ( QString : : number ( qMax ( 0 , song . score ( ) ) ) ) ;
ui_ - > rating - > set_rating ( song . rating ( ) ) ;
ui_ - > lastplayed - > setText ( song . lastplayed ( ) < = 0 ? tr ( " Never " ) :
QDateTime : : fromTime_t ( song . lastplayed ( ) ) . toString (
QLocale : : system ( ) . dateTimeFormat ( QLocale : : LongFormat ) ) ) ;
}
2011-02-02 17:22:04 +01:00
void EditTagDialog : : ArtLoaded ( quint64 id , const QImage & scaled , const QImage & original ) {
2010-12-20 15:12:40 +01:00
if ( id = = cover_art_id_ ) {
2011-02-02 17:22:04 +01:00
ui_ - > art - > setPixmap ( QPixmap : : fromImage ( scaled ) ) ;
original_ = original ;
2010-12-20 15:12:40 +01:00
}
2010-12-20 00:40:36 +01:00
}
2010-08-02 17:07:26 +02:00
2010-12-20 00:40:36 +01:00
void EditTagDialog : : FieldValueEdited ( ) {
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
foreach ( const FieldData & field , fields_ ) {
if ( field . editor_ = = w ) {
UpdateFieldValue ( field , sel ) ;
return ;
}
}
}
void EditTagDialog : : ResetField ( ) {
const QModelIndexList sel = ui_ - > song_list - > selectionModel ( ) - > selectedIndexes ( ) ;
if ( sel . isEmpty ( ) )
return ;
QWidget * w = qobject_cast < QWidget * > ( sender ( ) ) ;
// Find the field
foreach ( const FieldData & field , fields_ ) {
if ( field . editor_ = = w ) {
ignore_edits_ = true ;
ResetFieldValue ( field , sel ) ;
ignore_edits_ = false ;
return ;
}
}
2010-05-10 23:50:31 +02:00
}
2010-12-20 16:46:38 +01:00
2011-01-24 18:53:31 +01:00
Song * EditTagDialog : : GetFirstSelected ( ) {
2010-12-20 16:46:38 +01:00
const QModelIndexList sel = ui_ - > song_list - > selectionModel ( ) - > selectedIndexes ( ) ;
if ( sel . isEmpty ( ) )
2011-01-24 18:53:31 +01:00
return NULL ;
return & data_ [ sel . first ( ) . row ( ) ] . original_ ;
2011-01-24 01:09:57 +01:00
}
2010-12-20 16:46:38 +01:00
2011-01-24 01:09:57 +01:00
void EditTagDialog : : LoadCoverFromFile ( ) {
2011-01-24 18:53:31 +01:00
Song * song = GetFirstSelected ( ) ;
if ( ! song )
2010-12-20 16:46:38 +01:00
return ;
2011-01-24 18:53:31 +01:00
const QModelIndexList sel = ui_ - > song_list - > selectionModel ( ) - > selectedIndexes ( ) ;
2010-12-20 16:46:38 +01:00
2011-01-24 01:09:57 +01:00
QString cover = album_cover_choice_controller_ - > LoadCoverFromFile ( song ) ;
2010-12-20 16:46:38 +01:00
2011-01-24 18:53:31 +01:00
if ( ! cover . isEmpty ( ) )
UpdateCoverOf ( * song , sel , cover ) ;
2010-12-20 16:46:38 +01:00
}
2011-02-02 17:22:04 +01:00
void EditTagDialog : : SaveCoverToFile ( ) {
Song * song = GetFirstSelected ( ) ;
if ( ! song )
return ;
album_cover_choice_controller_ - > SaveCoverToFile ( * song , original_ ) ;
}
2011-01-23 21:24:17 +01:00
void EditTagDialog : : LoadCoverFromURL ( ) {
2011-01-24 18:53:31 +01:00
Song * song = GetFirstSelected ( ) ;
if ( ! song )
2011-01-23 21:24:17 +01:00
return ;
2011-01-24 18:53:31 +01:00
const QModelIndexList sel = ui_ - > song_list - > selectionModel ( ) - > selectedIndexes ( ) ;
2011-01-23 21:24:17 +01:00
2011-01-24 18:53:31 +01:00
QString cover = album_cover_choice_controller_ - > LoadCoverFromURL ( song ) ;
if ( ! cover . isEmpty ( ) )
UpdateCoverOf ( * song , sel , cover ) ;
2011-01-23 21:24:17 +01:00
}
2011-01-24 01:09:57 +01:00
void EditTagDialog : : SearchForCover ( ) {
2011-01-24 18:53:31 +01:00
Song * song = GetFirstSelected ( ) ;
if ( ! song )
2010-12-20 16:46:38 +01:00
return ;
2011-01-24 18:53:31 +01:00
const QModelIndexList sel = ui_ - > song_list - > selectionModel ( ) - > selectedIndexes ( ) ;
QString cover = album_cover_choice_controller_ - > SearchForCover ( song ) ;
2010-12-20 16:46:38 +01:00
2011-01-24 18:53:31 +01:00
if ( ! cover . isEmpty ( ) )
UpdateCoverOf ( * song , sel , cover ) ;
2010-12-20 16:46:38 +01:00
}
void EditTagDialog : : UnsetCover ( ) {
2011-01-24 18:53:31 +01:00
Song * song = GetFirstSelected ( ) ;
if ( ! song )
return ;
const QModelIndexList sel = ui_ - > song_list - > selectionModel ( ) - > selectedIndexes ( ) ;
QString cover = album_cover_choice_controller_ - > UnsetCover ( song ) ;
UpdateCoverOf ( * song , sel , cover ) ;
2010-12-20 16:46:38 +01:00
}
2011-01-24 01:09:57 +01:00
void EditTagDialog : : ShowCover ( ) {
2011-01-24 18:53:31 +01:00
Song * song = GetFirstSelected ( ) ;
if ( ! song ) {
2010-12-20 16:46:38 +01:00
return ;
2011-01-24 01:09:57 +01:00
}
2010-12-20 16:46:38 +01:00
2011-01-24 18:53:31 +01:00
album_cover_choice_controller_ - > ShowCover ( * song ) ;
2010-12-20 16:46:38 +01:00
}
2011-01-24 18:53:31 +01:00
void EditTagDialog : : UpdateCoverOf ( const Song & selected , const QModelIndexList & sel ,
const QString & cover ) {
if ( ! selected . is_valid ( ) | | selected . id ( ) = = - 1 )
2010-12-20 16:46:38 +01:00
return ;
2011-01-24 18:53:31 +01:00
UpdateSummaryTab ( selected ) ;
2010-12-25 01:15:05 +01:00
// Now check if we have any other songs cached that share that artist and
// album (and would therefore be changed as well)
for ( int i = 0 ; i < data_ . count ( ) ; + + i ) {
if ( i = = sel . first ( ) . row ( ) ) // Already changed this one
continue ;
2010-12-25 01:43:55 +01:00
Song * other_song = & data_ [ i ] . original_ ;
2011-01-24 18:53:31 +01:00
if ( selected . artist ( ) = = other_song - > artist ( ) & &
selected . album ( ) = = other_song - > album ( ) ) {
other_song - > set_art_manual ( cover ) ;
2010-12-25 01:15:05 +01:00
}
}
2010-12-20 16:46:38 +01:00
}
2010-12-20 17:36:16 +01:00
void EditTagDialog : : NextSong ( ) {
int row = ( ui_ - > song_list - > currentRow ( ) + 1 ) % ui_ - > song_list - > count ( ) ;
ui_ - > song_list - > setCurrentRow ( row ) ;
}
void EditTagDialog : : PreviousSong ( ) {
2010-12-25 00:35:34 +01:00
int row = ( ui_ - > song_list - > currentRow ( ) - 1 + ui_ - > song_list - > count ( ) ) % ui_ - > song_list - > count ( ) ;
2010-12-20 17:36:16 +01:00
ui_ - > song_list - > setCurrentRow ( row ) ;
}
2010-12-21 14:42:06 +01:00
void EditTagDialog : : ButtonClicked ( QAbstractButton * button ) {
if ( button = = ui_ - > button_box - > button ( QDialogButtonBox : : Discard ) ) {
reject ( ) ;
}
}
void EditTagDialog : : SaveData ( const QList < Data > & data ) {
for ( int i = 0 ; i < data . count ( ) ; + + i ) {
const Data & ref = data [ i ] ;
if ( ref . current_ . IsMetadataEqual ( ref . original_ ) )
continue ;
if ( ! ref . current_ . Save ( ) ) {
2011-04-28 14:27:53 +02:00
emit Error ( tr ( " An error occurred writing metadata to '%1' " ) . arg ( ref . current_ . url ( ) . toLocalFile ( ) ) ) ;
2010-12-21 14:42:06 +01:00
}
}
}
void EditTagDialog : : accept ( ) {
// Show the loading indicator
if ( ! SetLoading ( tr ( " Saving tracks " ) + " ... " ) )
return ;
2010-12-25 01:15:05 +01:00
// Save tags in the background
2010-12-21 14:42:06 +01:00
QFuture < void > future = QtConcurrent : : run ( this , & EditTagDialog : : SaveData , data_ ) ;
QFutureWatcher < void > * watcher = new QFutureWatcher < void > ( this ) ;
watcher - > setFuture ( future ) ;
connect ( watcher , SIGNAL ( finished ( ) ) , SLOT ( AcceptFinished ( ) ) ) ;
}
void EditTagDialog : : AcceptFinished ( ) {
QFutureWatcher < void > * watcher = dynamic_cast < QFutureWatcher < void > * > ( sender ( ) ) ;
if ( ! watcher )
return ;
watcher - > deleteLater ( ) ;
if ( ! SetLoading ( QString ( ) ) )
return ;
QDialog : : accept ( ) ;
}
2010-12-25 00:22:09 +01:00
bool EditTagDialog : : eventFilter ( QObject * o , QEvent * e ) {
2011-03-14 21:01:27 +01:00
if ( o = = ui_ - > art ) {
switch ( e - > type ( ) ) {
case QEvent : : MouseButtonRelease :
cover_menu_ - > popup ( static_cast < QMouseEvent * > ( e ) - > globalPos ( ) ) ;
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 ( ) ;
const QString cover = album_cover_choice_controller_ - > SaveCover ( song , event ) ;
if ( ! cover . isEmpty ( ) ) {
UpdateCoverOf ( * song , sel , cover ) ;
}
break ;
}
default :
break ;
}
2010-12-25 00:22:09 +01:00
}
return false ;
}
2010-12-25 01:15:05 +01:00
void EditTagDialog : : showEvent ( QShowEvent * e ) {
// Set the dialog's height to the smallest possible
resize ( width ( ) , sizeHint ( ) . height ( ) ) ;
QDialog : : showEvent ( e ) ;
}
2010-12-25 01:33:53 +01:00
void EditTagDialog : : SongRated ( float rating ) {
const QModelIndexList sel = ui_ - > song_list - > selectionModel ( ) - > selectedIndexes ( ) ;
if ( sel . isEmpty ( ) )
return ;
2010-12-25 01:43:55 +01:00
Song * song = & data_ [ sel . first ( ) . row ( ) ] . original_ ;
if ( ! song - > is_valid ( ) | | song - > id ( ) = = - 1 )
2010-12-25 01:33:53 +01:00
return ;
2010-12-25 01:43:55 +01:00
song - > set_rating ( rating ) ;
backend_ - > UpdateSongRatingAsync ( song - > id ( ) , rating ) ;
2010-12-25 01:33:53 +01:00
}
2010-12-25 12:54:21 +01:00
void EditTagDialog : : ResetPlayCounts ( ) {
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 ) ;
song - > set_score ( 0 ) ;
backend_ - > ResetStatisticsAsync ( song - > id ( ) ) ;
UpdateStatisticsTab ( * song ) ;
}
2011-01-15 21:00:39 +01:00
void EditTagDialog : : FetchTag ( ) {
2011-03-12 23:29:13 +01:00
if ( ! Fingerprinter : : GstreamerHasOfa ( ) ) {
QMessageBox : : warning ( this , tr ( " Error " ) , tr ( " Your gstreamer installation is missing the 'ofa' plugin. This is required for automatic tag fetching. Try installing the 'gstreamer-plugins-bad' package. " ) ) ;
return ;
}
2011-01-15 21:00:39 +01:00
const QModelIndexList sel = ui_ - > song_list - > selectionModel ( ) - > selectedIndexes ( ) ;
2011-03-05 20:24:44 +01:00
SongList songs ;
2011-01-21 00:42:28 +01:00
2011-03-05 20:24:44 +01:00
foreach ( const QModelIndex & index , sel ) {
Song song = data_ [ index . row ( ) ] . original_ ;
if ( ! song . is_valid ( ) ) {
continue ;
2011-01-21 00:42:28 +01:00
}
2011-03-05 20:24:44 +01:00
songs < < song ;
2011-01-15 21:00:39 +01:00
}
2011-03-05 20:24:44 +01:00
if ( songs . isEmpty ( ) )
return ;
results_dialog_ - > Init ( songs ) ;
2011-03-12 22:19:41 +01:00
tag_fetcher_ - > StartFetch ( songs ) ;
2011-03-05 20:24:44 +01:00
results_dialog_ - > show ( ) ;
2011-01-15 21:00:39 +01:00
}
2011-01-21 00:42:28 +01:00
2011-03-06 15:07:41 +01:00
void EditTagDialog : : FetchTagSongChosen ( const Song & original_song , const Song & new_metadata ) {
2011-04-28 14:27:53 +02:00
const QString filename = original_song . url ( ) . toLocalFile ( ) ;
2011-01-21 00:42:28 +01:00
2011-03-05 20:24:44 +01:00
// Find the song with this filename
for ( int i = 0 ; i < data_ . count ( ) ; + + i ) {
Data * data = & data_ [ i ] ;
2011-04-28 14:27:53 +02:00
if ( data - > original_ . url ( ) . toLocalFile ( ) ! = filename )
2011-03-05 20:24:44 +01:00
continue ;
// Is it currently being displayed in the UI?
if ( ui_ - > song_list - > currentRow ( ) = = i ) {
// Yes! We can just set the fields in the UI
ui_ - > title - > set_text ( new_metadata . title ( ) ) ;
ui_ - > artist - > set_text ( new_metadata . artist ( ) ) ;
ui_ - > album - > set_text ( new_metadata . album ( ) ) ;
ui_ - > track - > setValue ( new_metadata . track ( ) ) ;
} else {
data - > current_ . set_title ( new_metadata . title ( ) ) ;
data - > current_ . set_artist ( new_metadata . artist ( ) ) ;
data - > current_ . set_album ( new_metadata . album ( ) ) ;
data - > current_ . set_track ( new_metadata . track ( ) ) ;
}
break ;
}
2011-01-21 00:42:28 +01:00
}