1 // (c) 2004 Mark Kretschmann <markey@web.de>
2 // (c) 2004 Pierpaolo Di Panfilo <pippo_dp@libero.it>
3 // (c) 2005-2006 Alexandre Pereira de Oliveira <aleprj@gmail.com>
4 // See COPYING file for licensing information.
7 // FIXME Config check for this seems to be missing
8 #define HAVE_TUNEPIMP false
12 #include "contextbrowser.h"
13 #include "collectionbrowser.h"
14 #include "querybuilder.h"
15 #include "coverfetcher.h"
16 #include "metabundle.h"
18 #include "playlistitem.h"
19 #include "statusbar.h" //for status messages
20 #include "tagdialog.h"
21 #include "tagguesser.h"
22 #include "ui_tagguesserconfigdialog.h"
23 #include "trackpickerdialog.h"
25 #include <tfile.h> //TagLib::File::isWritable
27 #include <kapplication.h>
28 #include <kcombobox.h>
31 #include <khtmlview.h>
32 #include <kiconloader.h>
33 #include <klineedit.h>
34 #include <kmessagebox.h>
35 #include <knuminput.h>
37 #include <kstandarddirs.h>
38 #include <ktabwidget.h>
39 #include <ktextedit.h>
48 #include <QPushButton>
53 class TagDialogWriter
: public ThreadManager::Job
56 TagDialogWriter( const QMap
<QString
, MetaBundle
> tagsToChange
);
61 QList
<MetaBundle
> m_tags
;
65 QStringList m_failedURLs
;
68 TagDialog::TagDialog( const KUrl
& url
, QWidget
* parent
)
69 : TagDialogBase( parent
)
70 , m_bundle( url
, true )
78 TagDialog::TagDialog( const KUrl::List list
, QWidget
* parent
)
79 : TagDialogBase( parent
)
89 TagDialog::TagDialog( const MetaBundle
& mb
, PlaylistItem
* item
, QWidget
* parent
)
90 : TagDialogBase( parent
)
92 , m_playlistItem( item
)
99 TagDialog::~TagDialog()
103 Amarok::config( "TagDialog" ).writeEntry( "CurrentTab", kTabWidget
->currentPageIndex() );
107 TagDialog::setTab( int id
)
109 kTabWidget
->setCurrentPage( id
);
113 ////////////////////////////////////////////////////////////////////////////////
115 ////////////////////////////////////////////////////////////////////////////////
118 TagDialog::cancelPressed() //SLOT
120 QApplication::restoreOverrideCursor(); // restore the cursor before closing the dialog
126 TagDialog::accept() //SLOT
128 pushButton_ok
->setEnabled( false ); //visual feedback
136 TagDialog::openPressed() //SLOT
138 Amarok::invokeBrowser( m_path
);
143 TagDialog::previousTrack()
147 if( !m_playlistItem
->itemAbove() ) return;
151 m_playlistItem
= static_cast<PlaylistItem
*>( m_playlistItem
->itemAbove() );
153 loadTags( m_playlistItem
->url() );
157 storeTags( *m_currentURL
);
159 if( m_currentURL
!= m_urlList
.begin() )
161 loadTags( *m_currentURL
);
169 TagDialog::nextTrack()
173 if( !m_playlistItem
->itemBelow() ) return;
177 m_playlistItem
= static_cast<PlaylistItem
*>( m_playlistItem
->itemBelow() );
179 loadTags( m_playlistItem
->url() );
183 storeTags( *m_currentURL
);
185 KUrl::List::iterator next
= m_currentURL
;
187 if( next
!= m_urlList
.end() )
189 loadTags( *m_currentURL
);
196 TagDialog::perTrack()
198 m_perTrack
= !m_perTrack
;
201 // just switched to per track mode
203 setSingleTrackMode();
204 loadTags( *m_currentURL
);
209 storeTags( *m_currentURL
);
210 setMultipleTracksMode();
211 readMultipleTracks();
219 TagDialog::enableItems()
221 checkBox_perTrack
->setChecked( m_perTrack
);
222 pushButton_previous
->setEnabled( m_perTrack
&& m_currentURL
!= m_urlList
.begin() );
223 KUrl::List::ConstIterator next
= m_currentURL
;
225 pushButton_next
->setEnabled( m_perTrack
&& next
!= m_urlList
.end());
226 if( m_urlList
.count() == 1 )
228 checkBox_perTrack
->setEnabled( false );
232 checkBox_perTrack
->setEnabled( true );
238 TagDialog::checkModified() //SLOT
240 pushButton_ok
->setEnabled( hasChanged() || storedTags
.count() > 0 || storedScores
.count() > 0
241 || storedLyrics
.count() > 0 || storedRatings
.count() > 0 || newLabels
.count() > 0 );
245 TagDialog::loadCover( const QString
&artist
, const QString
&album
)
247 if ( m_bundle
.artist() != artist
|| m_bundle
.album()!=album
)
250 // draw the album cover on the dialog
251 QString cover
= CollectionDB::instance()->albumImage( m_bundle
);
253 if( m_currentCover
!= cover
)
255 pixmap_cover
->setPixmap( QPixmap( cover
, "PNG" ) );
256 m_currentCover
= cover
;
258 pixmap_cover
->setInformation( m_bundle
.artist(), m_bundle
.album() );
259 const int s
= AmarokConfig::coverPreviewSize();
260 pixmap_cover
->setMinimumSize( s
, s
);
261 pixmap_cover
->setMaximumSize( s
, s
);
266 TagDialog::setFileNameSchemes() //SLOT
268 KDialog
*kDialog
= new KDialog(this);
269 Ui::TagGuesserConfigDialog
* dialog
= new Ui::TagGuesserConfigDialog();
270 dialog
->setupUi(kDialog
);
276 TagDialog::guessFromFilename() //SLOT
278 TagGuesser
guesser( m_bundle
.url().path() );
279 if( !guesser
.title().isNull() )
280 kLineEdit_title
->setText( guesser
.title() );
281 if( !guesser
.artist().isNull() )
282 kComboBox_artist
->setCurrentText( guesser
.artist() );
283 if( !guesser
.album().isNull() )
284 kComboBox_album
->setCurrentText( guesser
.album() );
285 if( !guesser
.track().isNull() )
286 qSpinBox_track
->setValue( guesser
.track().toInt() );
287 if( !guesser
.comment().isNull() )
288 kTextEdit_comment
->setText( guesser
.comment() );
289 if( !guesser
.year().isNull() )
290 qSpinBox_year
->setValue( guesser
.year().toInt() );
291 if( !guesser
.composer().isNull() )
292 kComboBox_composer
->setCurrentText( guesser
.composer() );
293 if( !guesser
.genre().isNull() )
294 kComboBox_genre
->setCurrentText( guesser
.genre() );
298 TagDialog::musicbrainzQuery() //SLOT
301 kDebug() << k_funcinfo
<< endl
;
303 m_mbTrack
= m_bundle
.url();
304 KTRMLookup
* ktrm
= new KTRMLookup( m_mbTrack
.path(), true );
305 connect( ktrm
, SIGNAL( sigResult( KTRMResultList
, QString
) ), SLOT( queryDone( KTRMResultList
, QString
) ) );
306 connect( pushButton_cancel
, SIGNAL( clicked() ), ktrm
, SLOT( deleteLater() ) );
308 pushButton_musicbrainz
->setEnabled( false );
309 pushButton_musicbrainz
->setText( i18n( "Generating audio fingerprint..." ) );
310 QApplication::setOverrideCursor( KCursor::workingCursor() );
315 TagDialog::queryDone( KTRMResultList results
, QString error
) //SLOT
319 if ( !error
.isEmpty() ) {
320 KMessageBox::sorry( this, i18n( "Tunepimp (MusicBrainz tagging library) returned the following error: \"%1\".", error
) );
323 if ( !results
.isEmpty() )
325 TrackPickerDialog
* t
= new TrackPickerDialog( m_mbTrack
.fileName(), results
, this );
327 connect( t
, SIGNAL( finished() ), SLOT( resetMusicbrainz() ) ); // clear m_mbTrack
330 KMessageBox::sorry( this, i18n( "The track was not found in the MusicBrainz database." ) );
331 resetMusicbrainz(); // clear m_mbTrack
335 QApplication::restoreOverrideCursor();
336 pushButton_musicbrainz
->setEnabled( true );
337 pushButton_musicbrainz
->setText( m_buttonMbText
);
345 TagDialog::fillSelected( KTRMResult selected
) //SLOT
348 kDebug() << k_funcinfo
<< endl
;
351 if ( m_bundle
.url() == m_mbTrack
) {
352 if ( !selected
.title().isEmpty() ) kLineEdit_title
->setText( selected
.title() );
353 if ( !selected
.artist().isEmpty() ) kComboBox_artist
->setCurrentText( selected
.artist() );
354 if ( !selected
.album().isEmpty() ) kComboBox_album
->setCurrentText( selected
.album() );
355 if ( selected
.track() != 0 ) qSpinBox_track
->setValue( selected
.track() );
356 if ( selected
.year() != 0 ) qSpinBox_year
->setValue( selected
.year() );
359 mb
.setPath( m_mbTrack
.path() );
360 if ( !selected
.title().isEmpty() ) mb
.setTitle( selected
.title() );
361 if ( !selected
.artist().isEmpty() ) mb
.setArtist( selected
.artist() );
362 if ( !selected
.album().isEmpty() ) mb
.setAlbum( selected
.album() );
363 if ( selected
.track() != 0 ) mb
.setTrack( selected
.track() );
364 if ( selected
.year() != 0 ) mb
.setYear( selected
.year() );
366 storedTags
.replace( m_mbTrack
.path(), mb
);
373 void TagDialog::resetMusicbrainz() //SLOT
380 ////////////////////////////////////////////////////////////////////////////////
382 ////////////////////////////////////////////////////////////////////////////////
384 void TagDialog::init()
388 // delete itself when closing
389 setAttribute( Qt::WA_DeleteOnClose
);
391 KConfigGroup config
= Amarok::config( "TagDialog" );
393 kTabWidget
->addTab( summaryTab
, i18n( "Summary" ) );
394 kTabWidget
->addTab( tagsTab
, i18n( "Tags" ) );
395 kTabWidget
->addTab( lyricsTab
, i18n( "Lyrics" ) );
396 kTabWidget
->addTab( statisticsTab
, i18n( "Statistics" ) );
397 kTabWidget
->addTab( labelsTab
, i18n( "Labels" ) );
398 kTabWidget
->setCurrentPage( config
.readEntry( "CurrentTab", 0 ) );
400 const QStringList artists
= CollectionDB::instance()->artistList();
401 kComboBox_artist
->insertStringList( artists
);
402 kComboBox_artist
->completionObject()->insertItems( artists
);
403 kComboBox_artist
->completionObject()->setIgnoreCase( true );
404 kComboBox_artist
->setCompletionMode( KGlobalSettings::CompletionPopup
);
406 const QStringList albums
= CollectionDB::instance()->albumList();
407 kComboBox_album
->insertStringList( albums
);
408 kComboBox_album
->completionObject()->insertItems( albums
);
409 kComboBox_album
->completionObject()->setIgnoreCase( true );
410 kComboBox_album
->setCompletionMode( KGlobalSettings::CompletionPopup
);
412 const QStringList composers
= CollectionDB::instance()->composerList();
413 kComboBox_composer
->insertStringList( composers
);
414 kComboBox_composer
->completionObject()->insertItems( composers
);
415 kComboBox_composer
->completionObject()->setIgnoreCase( true );
416 kComboBox_composer
->setCompletionMode( KGlobalSettings::CompletionPopup
);
418 kComboBox_rating
->insertStringList( MetaBundle::ratingList() );
420 // const QStringList genres = MetaBundle::genreList();
421 const QStringList genres
= CollectionDB::instance()->genreList();
422 kComboBox_genre
->insertStringList( genres
);
423 kComboBox_genre
->completionObject()->insertItems( genres
);
424 kComboBox_genre
->completionObject()->setIgnoreCase( true );
426 const QStringList labels
= CollectionDB::instance()->labelList();
427 //TODO: figure out a way to add auto-completion support to kTestEdit_selectedLabels
429 //m_labelCloud = new KHTMLPart( labels_favouriteLabelsFrame );
430 m_labelCloud
= new HTMLView( labels_favouriteLabelsFrame
);
431 m_labelCloud
->view()->setSizePolicy( QSizePolicy::Ignored
, QSizePolicy::Ignored
, false );
432 //m_labelCloud->view()->setVScrollBarMode( Q3ScrollView::AlwaysOff );
433 //m_labelCloud->view()->setHScrollBarMode( Q3ScrollView::AlwaysOff );
435 new QVBoxLayout( labels_favouriteLabelsFrame
);
436 labels_favouriteLabelsFrame
->layout()->add( m_labelCloud
->view() );
437 const QStringList favoriteLabels
= CollectionDB::instance()->favoriteLabels();
438 QString html
= generateHTML( favoriteLabels
);
439 m_labelCloud
->set( html
);
440 connect( m_labelCloud
->browserExtension(), SIGNAL( openUrlRequest( const KUrl
&, const KParts::URLArgs
& ) ),
441 this, SLOT( openUrlRequest( const KUrl
& ) ) );
443 // looks better to have a blank label than 0, we can't do this in
444 // the UI file due to bug in Designer
445 qSpinBox_track
->setSpecialValueText( " " );
446 qSpinBox_year
->setSpecialValueText( " " );
447 qSpinBox_score
->setSpecialValueText( " " );
448 qSpinBox_discNumber
->setSpecialValueText( " " );
450 if( !AmarokConfig::useRatings() )
452 kComboBox_rating
->hide();
455 if( !AmarokConfig::useScores() )
457 qSpinBox_score
->hide();
461 //HACK due to deficiency in Qt that will be addressed in version 4
462 // QSpinBox doesn't emit valueChanged if you edit the value with
463 // the lineEdit until you change the keyboard focus
464 connect( qSpinBox_year
, SIGNAL(valueChanged( int )), SLOT(checkModified()) );
465 connect( qSpinBox_track
, SIGNAL(valueChanged( int )), SLOT(checkModified()) );
466 connect( qSpinBox_score
, SIGNAL(valueChanged( int )), SLOT(checkModified()) );
467 connect( qSpinBox_discNumber
, SIGNAL(valueChanged( int )), SLOT(checkModified()) );
469 // Connects for modification check
470 connect( kLineEdit_title
, SIGNAL(textChanged( const QString
& )), SLOT(checkModified()) );
471 connect( kComboBox_composer
,SIGNAL(activated( int )), SLOT(checkModified()) );
472 connect( kComboBox_composer
,SIGNAL(textChanged( const QString
& )), SLOT(checkModified()) );
473 connect( kComboBox_artist
, SIGNAL(activated( int )), SLOT(checkModified()) );
474 connect( kComboBox_artist
, SIGNAL(textChanged( const QString
& )), SLOT(checkModified()) );
475 connect( kComboBox_album
, SIGNAL(activated( int )), SLOT(checkModified()) );
476 connect( kComboBox_album
, SIGNAL(textChanged( const QString
& )), SLOT(checkModified()) );
477 connect( kComboBox_genre
, SIGNAL(activated( int )), SLOT(checkModified()) );
478 connect( kComboBox_genre
, SIGNAL(textChanged( const QString
& )), SLOT(checkModified()) );
479 connect( kComboBox_rating
, SIGNAL(activated( int )), SLOT(checkModified()) );
480 connect( kComboBox_rating
, SIGNAL(textChanged( const QString
& )), SLOT(checkModified()) );
481 connect( qSpinBox_track
, SIGNAL(valueChanged( int )), SLOT(checkModified()) );
482 connect( qSpinBox_year
, SIGNAL(valueChanged( int )), SLOT(checkModified()) );
483 connect( qSpinBox_score
, SIGNAL(valueChanged( int )), SLOT(checkModified()) );
484 connect( kTextEdit_comment
, SIGNAL(textChanged()), SLOT(checkModified()) );
485 connect( kTextEdit_lyrics
, SIGNAL(textChanged()), SLOT(checkModified()) );
486 connect( kTextEdit_selectedLabels
, SIGNAL(textChanged()), SLOT(checkModified()) );
488 // Remember original button text
489 m_buttonMbText
= pushButton_musicbrainz
->text();
491 connect( pushButton_cancel
, SIGNAL(clicked()), SLOT(cancelPressed()) );
492 connect( pushButton_ok
, SIGNAL(clicked()), SLOT(accept()) );
493 connect( pushButton_open
, SIGNAL(clicked()), SLOT(openPressed()) );
494 connect( pushButton_previous
, SIGNAL(clicked()), SLOT(previousTrack()) );
495 connect( pushButton_next
, SIGNAL(clicked()), SLOT(nextTrack()) );
496 connect( checkBox_perTrack
, SIGNAL(clicked()), SLOT(perTrack()) );
498 // set an icon for the open-in-konqui button
499 pushButton_open
->setIconSet( KIcon( Amarok::icon( "files" ) ) );
501 //Update lyrics on Context Browser
502 connect( this, SIGNAL(lyricsChanged( const QString
& )), ContextBrowser::instance(), SLOT( lyricsChanged( const QString
& ) ) );
505 connect( CollectionDB::instance(), SIGNAL( coverFetched( const QString
&, const QString
& ) ),
506 this, SLOT( loadCover( const QString
&, const QString
& ) ) );
507 connect( CollectionDB::instance(), SIGNAL( coverChanged( const QString
&, const QString
& ) ),
508 this, SLOT( loadCover( const QString
&, const QString
& ) ) );
513 connect( pushButton_musicbrainz
, SIGNAL(clicked()), SLOT(musicbrainzQuery()) );
515 pushButton_musicbrainz
->setToolTip( i18n("Please install MusicBrainz to enable this functionality") );
518 connect( pushButton_guessTags
, SIGNAL(clicked()), SLOT( guessFromFilename() ) );
519 connect( pushButton_setFilenameSchemes
, SIGNAL(clicked()), SLOT( setFileNameSchemes() ) );
521 if( m_urlList
.count() ) { //editing multiple tracks
523 setMultipleTracksMode();
524 readMultipleTracks();
526 checkBox_perTrack
->setChecked( m_perTrack
);
527 if( m_urlList
.count() == 1 )
529 checkBox_perTrack
->setEnabled( false );
530 pushButton_previous
->setEnabled( false );
531 pushButton_next
->setEnabled( false );
535 checkBox_perTrack
->setEnabled( true );
536 pushButton_previous
->setEnabled( m_perTrack
);
537 pushButton_next
->setEnabled( m_perTrack
);
543 checkBox_perTrack
->hide();
545 if( !m_playlistItem
) {
546 //We have already loaded the metadata (from the file) in the constructor
547 pushButton_previous
->hide();
548 pushButton_next
->hide();
552 //Reload the metadata from the file, to be sure it's accurate
553 loadTags( m_playlistItem
->url() );
556 loadLyrics( m_bundle
.url() );
557 loadLabels( m_bundle
.url() );
562 // make it as small as possible
563 resize( sizeHint().width(), minimumSize().height() );
568 inline const QString
TagDialog::unknownSafe( QString s
) {
569 return ( s
.isNull() || s
.isEmpty() || s
== "?" || s
== "-" )
574 const QStringList
TagDialog::statisticsData() {
576 QStringList data
, values
;
577 const uint artist_id
= CollectionDB::instance()->artistID( m_bundle
.artist() );
578 const uint album_id
= CollectionDB::instance()->albumID ( m_bundle
.album() );
582 if ( !m_bundle
.artist().isEmpty() ) {
583 // tracks by this artist
585 qb
.addReturnFunctionValue( QueryBuilder::funcCount
, QueryBuilder::tabSong
, QueryBuilder::valTitle
);
586 qb
.addMatch( QueryBuilder::tabSong
, QueryBuilder::valArtistID
, QString::number( artist_id
) );
588 data
+= i18n( "Tracks by this Artist" );
592 // albums by this artist
594 qb
.addReturnFunctionValue( QueryBuilder::funcCount
, QueryBuilder::tabAlbum
, QueryBuilder::valID
);
595 qb
.addMatch( QueryBuilder::tabSong
, QueryBuilder::valArtistID
, QString::number( artist_id
) );
596 qb
.groupBy( QueryBuilder::tabSong
, QueryBuilder::valAlbumID
);
597 qb
.excludeMatch( QueryBuilder::tabAlbum
, i18n( "Unknown" ) );
598 qb
.setOptions( QueryBuilder::optNoCompilations
);
600 data
+= i18n( "Albums by this Artist" );
601 data
+= QString::number( values
.count() );
604 // Favorite track by this artist
606 qb
.addReturnValue( QueryBuilder::tabSong
, QueryBuilder::valTitle
);
607 qb
.addReturnValue( QueryBuilder::tabStats
, QueryBuilder::valScore
);
608 qb
.addMatch( QueryBuilder::tabSong
, QueryBuilder::valArtistID
, QString::number( artist_id
) );
612 data
+= i18n( "Favorite by this Artist" );
613 data
+= values
.isEmpty() ? QString() : values
[0];
615 if ( !m_bundle
.album().isEmpty() ) {
616 // Favorite track on this album
618 qb
.addReturnValue( QueryBuilder::tabSong
, QueryBuilder::valTitle
);
619 qb
.addReturnValue( QueryBuilder::tabStats
, QueryBuilder::valScore
);
620 qb
.addMatch( QueryBuilder::tabSong
, QueryBuilder::valAlbumID
, QString::number( album_id
) );
624 data
+= i18n( "Favorite on this Album" );
625 data
+= values
.isEmpty() ? QString() : values
[0];
629 const QString sArtists
= CollectionDB::instance()->similarArtists( m_bundle
.artist(), 4 ).join(", ");
630 if ( !sArtists
.isEmpty() ) {
631 data
+= i18n( "Related Artists" );
638 void TagDialog::readTags()
640 bool local
= m_bundle
.url().isLocalFile();
642 setCaption( KDialog::makeStandardCaption( i18n("Track Information: %1 by %2", m_bundle
.title(), m_bundle
.artist() ) ) );
645 if ( m_bundle
.album().isEmpty() ) {
646 if( !m_bundle
.title().isEmpty() ) {
647 if( !m_bundle
.artist().isEmpty() )
648 niceTitle
= i18n( "<b>%1</b> by <b>%2</b>", m_bundle
.title(), m_bundle
.artist() );
650 niceTitle
= QString( "<b>%1</b>").arg( m_bundle
.title() );
652 else niceTitle
= m_bundle
.prettyTitle();
655 niceTitle
= i18n( "<b>%1</b> by <b>%2</b> on <b>%3</b>" ,
656 m_bundle
.title(), m_bundle
.artist(), m_bundle
.album() );
658 trackArtistAlbumLabel
->setText( niceTitle
);
659 trackArtistAlbumLabel2
->setText( niceTitle
);
661 kLineEdit_title
->setText( m_bundle
.title() );
662 kComboBox_artist
->setCurrentText( m_bundle
.artist() );
663 kComboBox_album
->setCurrentText( m_bundle
.album() );
664 kComboBox_genre
->setCurrentText( m_bundle
.genre() );
665 kComboBox_rating
->setCurrentIndex( m_bundle
.rating() ? m_bundle
.rating() - 1 : 0 );
666 qSpinBox_track
->setValue( m_bundle
.track() );
667 kComboBox_composer
->setCurrentText( m_bundle
.composer() );
668 qSpinBox_year
->setValue( m_bundle
.year() );
669 qSpinBox_score
->setValue( static_cast<int>(m_bundle
.score()) );
670 qSpinBox_discNumber
->setValue( m_bundle
.discNumber() );
671 kTextEdit_comment
->setText( m_bundle
.comment() );
673 bool extended
= m_bundle
.hasExtendedMetaInformation();
674 qSpinBox_discNumber
->setEnabled( extended
);
675 kComboBox_composer
->setEnabled( extended
);
678 QString summaryText
, statisticsText
;
679 const QString body2cols
= "<tr><td><nobr>%1</nobr></td><td><b>%2</b></td></tr>";
680 const QString body1col
= "<tr><td colspan=2>%1</td></td></tr>";
681 const QString emptyLine
= "<tr><td colspan=2></td></tr>";
683 summaryText
= "<table width=100%><tr><td width=50%><table>";
684 summaryText
+= body2cols
.arg( i18n("Length:"), unknownSafe( m_bundle
.prettyLength() ) );
685 summaryText
+= body2cols
.arg( i18n("Bitrate:"), unknownSafe( m_bundle
.prettyBitrate() ) );
686 summaryText
+= body2cols
.arg( i18n("Samplerate:"), unknownSafe( m_bundle
.prettySampleRate() ) );
687 summaryText
+= body2cols
.arg( i18n("Size:"), unknownSafe( m_bundle
.prettyFilesize() ) );
688 summaryText
+= body2cols
.arg( i18n("Format:"), unknownSafe( m_bundle
.type() ) );
690 summaryText
+= "</table></td><td width=50%><table>";
691 if( AmarokConfig::useScores() )
692 summaryText
+= body2cols
.arg( i18n("Score:"), QString::number( static_cast<int>( m_bundle
.score() ) ) );
693 if( AmarokConfig::useRatings() )
694 summaryText
+= body2cols
.arg( i18n("Rating:"), m_bundle
.prettyRating() );
696 summaryText
+= body2cols
.arg( i18n("Playcount:"), QString::number( m_bundle
.playCount() ) );
697 summaryText
+= body2cols
.arg( i18n("First Played:"),
698 m_bundle
.playCount() ? KGlobal::locale()->formatDate( CollectionDB::instance()->getFirstPlay( m_bundle
.url().path() ).date() , KLocale::ShortDate
) : i18n("Never") );
699 summaryText
+= body2cols
.arg( i18nc("a single item (singular)", "Last Played:"),
700 m_bundle
.playCount() ? KGlobal::locale()->formatDate( CollectionDB::instance()->getLastPlay( m_bundle
.url().path() ).date() , KLocale::ShortDate
) : i18n("Never") );
702 summaryText
+= "</table></td></tr></table>";
703 summaryLabel
->setText( summaryText
);
705 statisticsText
= "<table>";
707 QStringList sData
= statisticsData();
708 for ( uint i
= 0; i
<sData
.count(); i
+=2 ) {
709 statisticsText
+= body2cols
.arg( sData
[i
], sData
[i
+1] );
712 statisticsText
+= "</table>";
714 statisticsLabel
->setText( statisticsText
);
716 kLineEdit_location
->setText( local
? m_bundle
.url().path() : m_bundle
.url().url() );
719 kTextEdit_lyrics
->setText( m_lyrics
);
721 loadCover( m_bundle
.artist(), m_bundle
.album() );
724 // enable only for local files
725 kLineEdit_title
->setReadOnly( !local
);
726 kComboBox_artist
->setEnabled( local
);
727 kComboBox_album
->setEnabled( local
);
728 kComboBox_genre
->setEnabled( local
);
729 kComboBox_rating
->setEnabled( local
);
730 qSpinBox_track
->setEnabled( local
);
731 qSpinBox_year
->setEnabled( local
);
732 qSpinBox_score
->setEnabled( local
);
733 kTextEdit_comment
->setEnabled( local
);
734 kTextEdit_selectedLabels
->setEnabled( local
);
735 m_labelCloud
->view()->setEnabled( local
);
739 pushButton_musicbrainz
->show();
740 pushButton_guessTags
->show();
741 pushButton_setFilenameSchemes
->show();
745 pushButton_musicbrainz
->hide();
746 pushButton_guessTags
->hide();
747 pushButton_setFilenameSchemes
->hide();
750 // If it's a local file, write the directory to m_path, else disable the "open in konqui" button
752 m_path
= m_bundle
.url().directory();
754 pushButton_open
->setEnabled( false );
756 pushButton_ok
->setEnabled( storedTags
.count() > 0 || storedScores
.count() > 0
757 || storedLyrics
.count() > 0 || storedRatings
.count() > 0
758 || newLabels
.count() > 0 );
761 // Don't enable button if a query is in progress already (or if the file isn't local)
762 pushButton_musicbrainz
->setEnabled( m_bundle
.url().isLocalFile() && m_mbTrack
.isEmpty() );
764 pushButton_musicbrainz
->setEnabled( false );
767 if( m_playlistItem
) {
768 pushButton_previous
->setEnabled( m_playlistItem
->itemAbove() );
769 pushButton_next
->setEnabled( m_playlistItem
->itemBelow() );
775 TagDialog::setMultipleTracksMode()
778 kTabWidget
->setTabEnabled( summaryTab
, false );
779 kTabWidget
->setTabEnabled( lyricsTab
, false );
781 kComboBox_artist
->setCurrentText( "" );
782 kComboBox_album
->setCurrentText( "" );
783 kComboBox_genre
->setCurrentText( "" );
784 kComboBox_composer
->setCurrentText( "" );
785 kLineEdit_title
->setText( "" );
786 kTextEdit_comment
->setText( "" );
787 qSpinBox_track
->setValue( qSpinBox_track
->minimum() );
788 qSpinBox_discNumber
->setValue( qSpinBox_discNumber
->minimum() );
789 qSpinBox_year
->setValue( qSpinBox_year
->minimum() );
791 qSpinBox_score
->setValue( qSpinBox_score
->minimum() );
792 kComboBox_rating
->setCurrentItem( 0 );
794 kLineEdit_title
->setEnabled( false );
795 qSpinBox_track
->setEnabled( false );
797 pushButton_musicbrainz
->hide();
798 pushButton_guessTags
->hide();
799 pushButton_setFilenameSchemes
->hide();
801 locationLabel
->hide();
802 kLineEdit_location
->hide();
803 pushButton_open
->hide();
804 pixmap_cover
->hide();
808 TagDialog::setSingleTrackMode()
811 kTabWidget
->setTabEnabled( summaryTab
, true );
812 kTabWidget
->setTabEnabled( lyricsTab
, true );
814 kLineEdit_title
->setEnabled( true );
815 qSpinBox_track
->setEnabled( true );
817 pushButton_musicbrainz
->show();
818 pushButton_guessTags
->show();
819 pushButton_setFilenameSchemes
->show();
821 locationLabel
->show();
822 kLineEdit_location
->show();
823 pushButton_open
->show();
824 pixmap_cover
->show();
829 TagDialog::readMultipleTracks()
832 setCaption( KDialog::makeStandardCaption( i18np("1 Track", "Information for %1 Tracks", m_urlList
.count()) ) );
834 //Check which fields are the same for all selected tracks
835 const KUrl::List::ConstIterator end
= m_urlList
.end();
836 KUrl::List::ConstIterator it
= m_urlList
.begin();
838 m_bundle
= MetaBundle();
840 MetaBundle first
= bundleForURL( *it
);
842 bool artist
=true, album
=true, genre
=true, comment
=true, year
=true,
843 score
=true, rating
=true, composer
=true, discNumber
=true;
844 int songCount
=0, ratingCount
=0, ratingSum
=0, scoreCount
=0;
845 float scoreSum
= 0.f
;
846 for ( ; it
!= end
; ++it
) {
847 MetaBundle mb
= bundleForURL( *it
);
851 ratingSum
+=mb
.rating();
853 if ( mb
.score() > 0.f
) {
855 scoreSum
+=mb
.score();
858 if( !mb
.url().isLocalFile() ) {
859 // If we have a non local file, don't even lose more time comparing
860 artist
= album
= genre
= comment
= year
= false;
861 score
= rating
= composer
= discNumber
= false;
864 if ( artist
&& mb
.artist()!=first
.artist() )
866 if ( album
&& mb
.album()!=first
.album() )
868 if ( genre
&& mb
.genre()!=first
.genre() )
870 if ( comment
&& mb
.comment()!=first
.comment() )
872 if ( year
&& mb
.year()!=first
.year() )
874 if ( composer
&& mb
.composer()!=first
.composer() )
876 if ( discNumber
&& mb
.discNumber()!=first
.discNumber() )
878 if ( score
&& mb
.score()!=first
.score() )
880 if ( rating
&& mb
.rating()!=first
.rating() )
883 // Set them in the dialog and in m_bundle ( so we don't break hasChanged() )
885 m_bundle
.setArtist( first
.artist() );
886 kComboBox_artist
->setCurrentText( first
.artist() );
889 m_bundle
.setAlbum( first
.album() );
890 kComboBox_album
->setCurrentText( first
.album() );
893 m_bundle
.setGenre( first
.genre() );
894 kComboBox_genre
->setCurrentText( first
.genre() );
897 m_bundle
.setComment( first
.comment() );
898 kTextEdit_comment
->setText( first
.comment() );
901 m_bundle
.setComposer( first
.composer() );
902 kComboBox_composer
->setCurrentText( first
.composer() );
905 m_bundle
.setYear( first
.year() );
906 qSpinBox_year
->setValue( first
.year() );
909 m_bundle
.setDiscNumber( first
.discNumber() );
910 qSpinBox_discNumber
->setValue( first
.discNumber() );
913 m_bundle
.setScore( first
.score() );
914 qSpinBox_score
->setValue( static_cast<int>( first
.score() ) );
917 m_bundle
.setRating( first
.rating() );
918 kComboBox_rating
->setCurrentIndex( first
.rating() ? first
.rating() - 1 : 0 );
921 m_currentURL
= m_urlList
.begin();
923 trackArtistAlbumLabel2
->setText( i18np( "Editing 1 file", "Editing %1 files", songCount
) );
925 const QString body
= "<tr><td><nobr>%1:</nobr></td><td><b>%2</b></td></tr>";
926 QString statisticsText
= "<table>";
928 if( AmarokConfig::useRatings() ) {
929 statisticsText
+= body
.arg( i18n( "Rated Songs:" ) , QString::number( ratingCount
) );
931 statisticsText
+= body
.arg( i18n( "Average Rating:" ) , QString::number( (float)ratingSum
/ (float)ratingCount
/2.0, 'f', 1 ) );
934 if( AmarokConfig::useRatings() ) {
935 statisticsText
+= body
.arg( i18n( "Scored Songs:" ) , QString::number( scoreCount
) );
937 statisticsText
+= body
.arg( i18n( "Average Score:" ) , QString::number( scoreSum
/ scoreCount
, 'f', 1 ) );
941 statisticsText
+= "</table>";
943 statisticsLabel
->setText( statisticsText
);
945 QStringList commonLabels
= getCommonLabels();
947 oldForeach ( commonLabels
)
949 if ( !text
.isEmpty() )
953 kTextEdit_selectedLabels
->setText( text
);
954 m_commaSeparatedLabels
= text
;
956 // This will reset a wrongly enabled Ok button
961 TagDialog::getCommonLabels()
964 QMap
<QString
, int> counterMap
;
965 const KUrl::List::ConstIterator end
= m_urlList
.end();
966 KUrl::List::ConstIterator iter
= m_urlList
.begin();
967 for(; iter
!= end
; ++iter
)
969 QStringList labels
= labelsForURL( *iter
);
972 if ( counterMap
.contains( *it
) )
973 counterMap
[ *it
] = counterMap
[ *it
] +1;
975 counterMap
[ *it
] = 1;
978 int n
= m_urlList
.count();
980 QMap
<QString
, int>::ConstIterator
counterEnd( counterMap
.end() );
981 for(QMap
<QString
, int>::ConstIterator it
= counterMap
.begin(); it
!= counterEnd
; ++it
)
983 if ( it
.data() == n
)
984 result
.append( it
.key() );
990 equalString( const QString
&a
, const QString
&b
)
992 return (a
.isEmpty() && b
.isEmpty()) ? true : a
== b
;
996 TagDialog::hasChanged()
1002 TagDialog::changes()
1004 int result
=TagDialog::NOCHANGE
;
1005 bool modified
= false;
1006 modified
|= !equalString( kComboBox_artist
->lineEdit()->text(), m_bundle
.artist() );
1007 modified
|= !equalString( kComboBox_album
->lineEdit()->text(), m_bundle
.album() );
1008 modified
|= !equalString( kComboBox_genre
->lineEdit()->text(), m_bundle
.genre() );
1009 modified
|= qSpinBox_year
->value() != m_bundle
.year();
1010 modified
|= qSpinBox_discNumber
->value() != m_bundle
.discNumber();
1011 modified
|= !equalString( kComboBox_composer
->lineEdit()->text(), m_bundle
.composer() );
1013 modified
|= !equalString( kTextEdit_comment
->text(), m_bundle
.comment() );
1015 if (!m_urlList
.count() || m_perTrack
) { //ignore these on MultipleTracksMode
1016 modified
|= !equalString( kLineEdit_title
->text(), m_bundle
.title() );
1017 modified
|= qSpinBox_track
->value() != m_bundle
.track();
1020 result
|= TagDialog::TAGSCHANGED
;
1022 if (qSpinBox_score
->value() != m_bundle
.score())
1023 result
|= TagDialog::SCORECHANGED
;
1024 if (kComboBox_rating
->currentIndex() != ( m_bundle
.rating() ? m_bundle
.rating() - 1 : 0 ) )
1025 result
|= TagDialog::RATINGCHANGED
;
1027 if (!m_urlList
.count() || m_perTrack
) { //ignore these on MultipleTracksMode
1028 if ( !equalString( kTextEdit_lyrics
->text(), m_lyrics
) )
1029 result
|= TagDialog::LYRICSCHANGED
;
1032 if ( !equalString( kTextEdit_selectedLabels
->text(), m_commaSeparatedLabels
) )
1033 result
|= TagDialog::LABELSCHANGED
;
1039 TagDialog::storeTags()
1041 storeTags( m_bundle
.url() );
1045 TagDialog::storeTags( const KUrl
&kurl
)
1047 int result
= changes();
1048 QString url
= kurl
.path();
1049 if( result
& TagDialog::TAGSCHANGED
) {
1050 MetaBundle
mb( m_bundle
);
1052 mb
.setTitle( kLineEdit_title
->text() );
1053 mb
.setComposer( kComboBox_composer
->currentText() );
1054 mb
.setArtist( kComboBox_artist
->currentText() );
1055 mb
.setAlbum( kComboBox_album
->currentText() );
1056 mb
.setComment( kTextEdit_comment
->text() );
1057 mb
.setGenre( kComboBox_genre
->currentText() );
1058 mb
.setTrack( qSpinBox_track
->value() );
1059 mb
.setYear( qSpinBox_year
->value() );
1060 mb
.setDiscNumber( qSpinBox_discNumber
->value() );
1061 mb
.setLength( m_bundle
.length() );
1062 mb
.setBitrate( m_bundle
.bitrate() );
1063 mb
.setSampleRate( m_bundle
.sampleRate() );
1064 storedTags
.replace( url
, mb
);
1066 if( result
& TagDialog::SCORECHANGED
)
1067 storedScores
.replace( url
, qSpinBox_score
->value() );
1068 if( result
& TagDialog::RATINGCHANGED
)
1069 storedRatings
.replace( url
, kComboBox_rating
->currentIndex() ? kComboBox_rating
->currentIndex() + 1 : 0 );
1070 if( result
& TagDialog::LYRICSCHANGED
) {
1071 if ( kTextEdit_lyrics
->text().isEmpty() )
1072 storedLyrics
.replace( url
, QString() );
1075 QDomElement e
= doc
.createElement( "lyrics" );
1076 e
.setAttribute( "artist", kComboBox_artist
->currentText() );
1077 e
.setAttribute( "title", kLineEdit_title
->text() );
1078 QDomText t
= doc
.createTextNode( kTextEdit_lyrics
->text() );
1080 doc
.appendChild( e
);
1081 storedLyrics
.replace( url
, doc
.toString() );
1084 if( result
& TagDialog::LABELSCHANGED
) {
1085 generateDeltaForLabelList( labelListFromText( kTextEdit_selectedLabels
->text() ) );
1086 QStringList tmpLabels
;
1087 if ( newLabels
.find( url
) != newLabels
.end() )
1088 tmpLabels
= newLabels
[ url
];
1090 tmpLabels
= originalLabels
[ url
];
1092 oldForeach( m_removedLabels
)
1094 tmpLabels
.remove( *it
);
1096 oldForeach( m_addedLabels
)
1098 if( tmpLabels
.find( *it
) == tmpLabels
.end() )
1099 tmpLabels
.append( *it
);
1101 newLabels
.replace( url
, tmpLabels
);
1106 TagDialog::storeTags( const KUrl
&url
, int changes
, const MetaBundle
&mb
)
1108 if ( changes
& TagDialog::TAGSCHANGED
)
1109 storedTags
.replace( url
.path(), mb
);
1110 if ( changes
& TagDialog::SCORECHANGED
)
1111 storedScores
.replace( url
.path(), mb
.score() );
1112 if ( changes
& TagDialog::RATINGCHANGED
)
1113 storedRatings
.replace( url
.path(), mb
.rating() );
1117 TagDialog::storeLabels( const KUrl
&url
, const QStringList
&labels
)
1119 newLabels
.replace( url
.path(), labels
);
1124 TagDialog::loadTags( const KUrl
&url
)
1126 m_bundle
= bundleForURL( url
);
1132 TagDialog::loadLyrics( const KUrl
&url
)
1134 QString xml
= lyricsForURL(url
.path() );
1137 if( doc
.setContent( xml
) )
1138 m_lyrics
= doc
.documentElement().text();
1144 TagDialog::loadLabels( const KUrl
&url
)
1147 m_labels
= labelsForURL( url
);
1148 originalLabels
[ url
.path() ] = m_labels
;
1150 oldForeach( m_labels
)
1152 if ( !text
.isEmpty() )
1153 text
.append( ", " );
1156 kTextEdit_selectedLabels
->setText( text
);
1157 m_commaSeparatedLabels
= text
;
1161 TagDialog::bundleForURL( const KUrl
&url
)
1163 if( storedTags
.find( url
.path() ) != storedTags
.end() )
1164 return storedTags
[ url
.path() ];
1166 return MetaBundle( url
, url
.isLocalFile() );
1170 TagDialog::scoreForURL( const KUrl
&url
)
1172 if( storedScores
.find( url
.path() ) != storedScores
.end() )
1173 return storedScores
[ url
.path() ];
1175 return CollectionDB::instance()->getSongPercentage( url
.path() );
1179 TagDialog::ratingForURL( const KUrl
&url
)
1181 if( storedRatings
.find( url
.path() ) != storedRatings
.end() )
1182 return storedRatings
[ url
.path() ];
1184 return CollectionDB::instance()->getSongRating( url
.path() );
1188 TagDialog::lyricsForURL( const KUrl
&url
)
1190 if( storedLyrics
.find( url
.path() ) != storedLyrics
.end() )
1191 return storedLyrics
[ url
.path() ];
1193 return CollectionDB::instance()->getLyrics( url
.path() );
1197 TagDialog::labelsForURL( const KUrl
&url
)
1199 if( newLabels
.find( url
.path() ) != newLabels
.end() )
1200 return newLabels
[ url
.path() ];
1201 if( originalLabels
.find( url
.path() ) != originalLabels
.end() )
1202 return originalLabels
[ url
.path() ];
1203 QStringList tmp
= CollectionDB::instance()->getLabels( url
.path(), CollectionDB::typeUser
);
1204 originalLabels
[ url
.path() ] = tmp
;
1209 TagDialog::saveTags()
1220 QMap
<QString
, float>::ConstIterator
endScore( storedScores
.end() );
1221 for(QMap
<QString
, float>::ConstIterator it
= storedScores
.begin(); it
!= endScore
; ++it
) {
1222 CollectionDB::instance()->setSongPercentage( it
.key(), it
.data() );
1224 QMap
<QString
, int>::ConstIterator
endRating( storedRatings
.end() );
1225 for(QMap
<QString
, int>::ConstIterator it
= storedRatings
.begin(); it
!= endRating
; ++it
) {
1226 CollectionDB::instance()->setSongRating( it
.key(), it
.data() );
1228 QMap
<QString
, QString
>::ConstIterator
endLyrics( storedLyrics
.end() );
1229 for(QMap
<QString
, QString
>::ConstIterator it
= storedLyrics
.begin(); it
!= endLyrics
; ++it
) {
1230 CollectionDB::instance()->setLyrics( it
.key(), it
.data(),
1231 CollectionDB::instance()->uniqueIdFromUrl( KUrl( it
.key() ) ) );
1232 emit
lyricsChanged( it
.key() );
1234 QMap
<QString
, QStringList
>::ConstIterator
endLabels( newLabels
.end() );
1235 for(QMap
<QString
, QStringList
>::ConstIterator it
= newLabels
.begin(); it
!= endLabels
; ++it
) {
1236 CollectionDB::instance()->setLabels( it
.key(), it
.data(),
1237 CollectionDB::instance()->uniqueIdFromUrl( KUrl( it
.key() ) ), CollectionDB::typeUser
);
1239 CollectionDB::instance()->cleanLabels();
1241 ThreadManager::instance()->queueJob( new TagDialogWriter( storedTags
) );
1246 TagDialog::applyToAllTracks()
1248 generateDeltaForLabelList( labelListFromText( kTextEdit_selectedLabels
->text() ) );
1250 const KUrl::List::ConstIterator end
= m_urlList
.end();
1251 for ( KUrl::List::ConstIterator it
= m_urlList
.begin(); it
!= end
; ++it
) {
1253 /* we have to update the values if they changed, so:
1254 1) !kLineEdit_field->text().isEmpty() && kLineEdit_field->text() != mb.field
1255 i.e.: The user wrote something on the field, and it's different from
1256 what we have in the tag.
1257 2) !m_bundle.field().isEmpty() && kLineEdit_field->text().isEmpty()
1258 i.e.: The user was shown some value for the field (it was the same
1259 for all selected tracks), and he deliberately emptied it.
1260 TODO: All this mess is because the dialog uses "" to represent what the user
1261 doesn't want to change, maybe we can think of something better?
1264 MetaBundle mb
= bundleForURL( *it
);
1267 if( !kComboBox_artist
->currentText().isEmpty() && kComboBox_artist
->currentText() != mb
.artist() ||
1268 kComboBox_artist
->currentText().isEmpty() && !m_bundle
.artist().isEmpty() ) {
1269 mb
.setArtist( kComboBox_artist
->currentText() );
1270 changed
|= TagDialog::TAGSCHANGED
;
1273 if( !kComboBox_album
->currentText().isEmpty() && kComboBox_album
->currentText() != mb
.album() ||
1274 kComboBox_album
->currentText().isEmpty() && !m_bundle
.album().isEmpty() ) {
1275 mb
.setAlbum( kComboBox_album
->currentText() );
1276 changed
|= TagDialog::TAGSCHANGED
;
1278 if( !kComboBox_genre
->currentText().isEmpty() && kComboBox_genre
->currentText() != mb
.genre() ||
1279 kComboBox_genre
->currentText().isEmpty() && !m_bundle
.genre().isEmpty() ) {
1280 mb
.setGenre( kComboBox_genre
->currentText() );
1281 changed
|= TagDialog::TAGSCHANGED
;
1283 if( !kTextEdit_comment
->text().isEmpty() && kTextEdit_comment
->text() != mb
.comment() ||
1284 kTextEdit_comment
->text().isEmpty() && !m_bundle
.comment().isEmpty() ) {
1285 mb
.setComment( kTextEdit_comment
->text() );
1286 changed
|= TagDialog::TAGSCHANGED
;
1288 if( !kComboBox_composer
->currentText().isEmpty() && kComboBox_composer
->currentText() != mb
.composer() ||
1289 kComboBox_composer
->currentText().isEmpty() && !m_bundle
.composer().isEmpty() ) {
1290 mb
.setComposer( kComboBox_composer
->currentText() );
1291 changed
|= TagDialog::TAGSCHANGED
;
1294 if( qSpinBox_year
->value() && qSpinBox_year
->value() != mb
.year() ||
1295 !qSpinBox_year
->value() && m_bundle
.year() ) {
1296 mb
.setYear( qSpinBox_year
->value() );
1297 changed
|= TagDialog::TAGSCHANGED
;
1299 if( qSpinBox_discNumber
->value() && qSpinBox_discNumber
->value() != mb
.discNumber() ||
1300 !qSpinBox_discNumber
->value() && m_bundle
.discNumber() ) {
1301 mb
.setDiscNumber( qSpinBox_discNumber
->value() );
1302 changed
|= TagDialog::TAGSCHANGED
;
1305 if( qSpinBox_score
->value() && qSpinBox_score
->value() != mb
.score() ||
1306 !qSpinBox_score
->value() && m_bundle
.score() )
1308 mb
.setScore( qSpinBox_score
->value() );
1309 changed
|= TagDialog::SCORECHANGED
;
1312 if( kComboBox_rating
->currentIndex() && kComboBox_rating
->currentIndex() != m_bundle
.rating() - 1 ||
1313 !kComboBox_rating
->currentIndex() && m_bundle
.rating() )
1315 mb
.setRating( kComboBox_rating
->currentIndex() ? kComboBox_rating
->currentIndex() + 1 : 0 );
1316 changed
|= TagDialog::RATINGCHANGED
;
1318 storeTags( *it
, changed
, mb
);
1320 QStringList tmpLabels
= labelsForURL( *it
);
1322 for( QStringList::Iterator iter
= m_removedLabels
.begin(); iter
!= m_removedLabels
.end(); ++iter
)
1324 tmpLabels
.remove( *iter
);
1326 for( QStringList::Iterator iter
= m_addedLabels
.begin(); iter
!= m_addedLabels
.end(); ++iter
)
1328 if( tmpLabels
.find( *iter
) == tmpLabels
.end() )
1329 tmpLabels
.append( *iter
);
1331 storeLabels( *it
, tmpLabels
);
1336 TagDialog::labelListFromText( const QString
&text
)
1338 QStringList tmp
= QStringList::split( ',', text
);
1339 //insert each string into a map to remove duplicates
1340 QMap
<QString
, int> map
;
1343 QString tmpString
= (*it
).trimmed();
1344 if ( !tmpString
.isEmpty() )
1345 map
.replace( tmpString
, 0 );
1348 QMap
<QString
, int>::ConstIterator
endMap( map
.end() );
1349 for(QMap
<QString
, int>::ConstIterator it
= map
.begin(); it
!= endMap
; ++it
) {
1350 result
.append( it
.key() );
1356 TagDialog::generateDeltaForLabelList( const QStringList
&list
)
1358 m_addedLabels
.clear();
1359 m_removedLabels
.clear();
1362 if ( !m_labels
.contains( *it
) )
1363 m_addedLabels
.append( *it
);
1365 oldForeach( m_labels
)
1367 if ( !list
.contains( *it
) )
1368 m_removedLabels
.append( *it
);
1374 TagDialog::generateHTML( const QStringList
&labels
)
1376 //the first column of each row is the label name, the second the number of assigned songs
1377 //loop through it to find the highest number of songs, can be removed if somebody figures out a better sql query
1378 QMap
<QString
, QPair
<QString
, int> > mapping
;
1379 QStringList sortedLabels
;
1381 oldForeach( labels
)
1383 QString label
= *it
;
1384 sortedLabels
<< label
.toLower();
1386 int value
= ( *it
).toInt();
1389 mapping
[label
.toLower()] = QPair
<QString
, int>( label
, value
);
1391 sortedLabels
.sort();
1392 QString html
= "<html><body>";
1393 oldForeach( sortedLabels
)
1396 //generate a number in the range 1..10 based on how much the label is used
1397 int labelUse
= ( mapping
[key
].second
* 10 ) / max
;
1398 if ( labelUse
== 0 )
1400 html
.append( QString( "<span class='label size%1'><a href=\"label:%2\">%3</a></span> " )
1401 .arg( QString::number( labelUse
), mapping
[key
].first
, mapping
[key
].first
) );
1403 html
.append( "</html></body>" );
1404 debug() << "Dumping HTML for label cloud: " << html
<< endl
;
1409 TagDialog::openUrlRequest(const KUrl
&url
) //SLOT
1412 if ( url
.protocol() == "label" )
1414 QString text
= kTextEdit_selectedLabels
->text();
1415 QStringList currentLabels
= labelListFromText( text
);
1416 if ( currentLabels
.contains( url
.path() ) )
1418 if ( !text
.isEmpty() )
1419 text
.append( ", " );
1420 text
.append( url
.path() );
1421 kTextEdit_selectedLabels
->setText( text
);
1426 TagDialog::writeTag( MetaBundle
&mb
, bool updateCB
)
1428 QByteArray path
= QFile::encodeName( mb
.url().path() );
1429 if ( !TagLib::File::isWritable( path
) ) {
1430 Amarok::StatusBar::instance()->longMessage( i18n(
1431 "The file %1 is not writable.", mb
.url().fileName() ), KDE::StatusBar::Error
);
1436 QApplication::setOverrideCursor( Qt::WaitCursor
);
1438 bool result
= mb
.save();
1439 mb
.updateFilesize();
1442 //update the collection db
1443 CollectionDB::instance()->updateTags( mb
.url().path(), mb
, updateCB
);
1445 QApplication::restoreOverrideCursor();
1450 TagDialogWriter::TagDialogWriter( const QMap
<QString
, MetaBundle
> tagsToChange
)
1451 : ThreadManager::Job( "TagDialogWriter" ),
1452 m_successCount ( 0 ),
1455 QApplication::setOverrideCursor( Qt::WaitCursor
);
1456 QMap
<QString
, MetaBundle
>::ConstIterator end
= tagsToChange
.end();
1457 for(QMap
<QString
, MetaBundle
>::ConstIterator it
= tagsToChange
.begin(); it
!= end
; ++it
) {
1458 MetaBundle mb
= it
.data();
1464 TagDialogWriter::doJob()
1466 for( int i
= 0, size
=m_tags
.size(); i
<size
; ++i
) {
1467 QByteArray path
= QFile::encodeName( m_tags
[i
].url().path() );
1468 if ( !TagLib::File::isWritable( path
) ) {
1469 Amarok::StatusBar::instance()->longMessageThreadSafe( i18n(
1470 "The file %1 is not writable.", m_tags
[i
].url().fileName() ), KDE::StatusBar::Error
);
1475 bool result
= m_tags
[i
].save();
1476 m_tags
[i
].updateFilesize();
1482 m_failedURLs
+= m_tags
[i
].prettyUrl();
1484 m_failed
+= !result
;
1490 TagDialogWriter::completeJob()
1492 for( int i
= 0, size
=m_tags
.size(); i
<size
; ++i
) {
1493 if ( !m_failed
[i
] ) {
1494 CollectionDB::instance()->updateTags( m_tags
[i
].url().path(), m_tags
[i
], false /* don't update browsers*/ );
1495 Playlist::instance()->updateMetaData( m_tags
[i
] );
1498 QApplication::restoreOverrideCursor();
1499 if ( m_successCount
)
1500 CollectionView::instance()->databaseChanged();
1502 Amarok::StatusBar::instance()->longMessage( i18n(
1503 "Sorry, the tag for the following files could not be changed:\n", m_failedURLs
.join( ";\n" ) ), KDE::StatusBar::Error
);
1507 #include "tagdialog.moc"