Commit ff328c0f authored by Frerich Raabe's avatar Frerich Raabe

- Added button to the tag editor which makes JuK try to suggest sensible

  values for the tag fields by looking at the filename

svn path=/trunk/kdemultimedia/juk/; revision=214220
parent d17c6407
bin_PROGRAMS = juk
bin_PROGRAMS = juk tagguessertest
juk_SOURCES = directorylistbase.ui genrelisteditorbase.ui \
gstreamerplayer.cpp artsplayer.cpp directorylist.cpp stringhash.cpp \
......@@ -7,7 +7,9 @@ juk_SOURCES = directorylistbase.ui genrelisteditorbase.ui \
playlistitem.cpp playlist.cpp playlistsplitter.cpp listboxpixmap.cpp \
playlistbox.cpp tageditor.cpp cache.cpp genrelistreader.cpp \
genrelistlist.cpp genrelist.cpp genre.cpp player.cpp tag.cpp customaction.cpp \
slideraction.cpp keydialog.cpp juk.cpp main.cpp
slideraction.cpp keydialog.cpp juk.cpp main.cpp tagguesser.cpp
tagguessertest_SOURCES = tagguessertest.cpp tagguesser.cpp
INCLUDES= $(all_includes) -I$(arts_includes)
......@@ -24,6 +26,9 @@ endif
juk_LDADD = $(gstlibs) -lid3 -lsoundserver_idl $(LIB_KDEUI) $(LIB_KDECORE) $(LIB_KFILE) $(LIB_QT)
juk_LDFLAGS = $(all_libraries) $(KDE_RPATH)
tagguessertest_LDADD = $(LIB_KDECORE)
tagguessertest_LDFLAGS = $(all_libraries)
SUBDIRS = pics data
rcdir = $(kde_datadir)/juk
......
......@@ -24,6 +24,7 @@
#include <kconfig.h>
#include <klocale.h>
#include <kdebug.h>
#include <kpushbutton.h>
#include <qlabel.h>
#include <qcheckbox.h>
......@@ -32,6 +33,7 @@
#include "tageditor.h"
#include "tag.h"
#include "tagguesser.h"
#include "collectionlist.h"
#include "genrelistlist.h"
......@@ -365,6 +367,9 @@ void TagEditor::setupLayout()
m_commentBox = new KEdit(this, "commentBox");
m_commentBox->setTextFormat(Qt::PlainText);
addItem(i18n("Comment:"), m_commentBox, rightColumnLayout);
m_suggestButton = new KPushButton(i18n("S&uggest"), this, "suggestButton");
rightColumnLayout->addWidget(m_suggestButton, 0 /*no stretching */, Qt::AlignRight);
}
connect(m_artistNameBox, SIGNAL(textChanged(const QString&)), this, SLOT(slotDataChanged()));
......@@ -376,6 +381,7 @@ void TagEditor::setupLayout()
connect(m_yearSpin, SIGNAL(valueChanged(int)), this, SLOT(slotDataChanged()));
connect(m_trackSpin, SIGNAL(valueChanged(int)), this, SLOT(slotDataChanged()));
connect(m_commentBox, SIGNAL(textChanged()), this, SLOT(slotDataChanged()));
connect(m_suggestButton, SIGNAL(clicked()), this, SLOT(slotSuggestClicked()));
}
void TagEditor::save(const PlaylistItemList &list)
......@@ -535,4 +541,21 @@ void TagEditor::slotDataChanged(bool c)
m_dataChanged = c;
}
void TagEditor::slotSuggestClicked()
{
PlaylistItem *item = m_items.getFirst();
if(!item)
return;
Tag *tag = item->tag();
Q_ASSERT(tag);
TagGuesser guesser(tag->absFilePath());
m_trackNameBox->setText(guesser.title());
m_artistNameBox->setEditText(guesser.artist());
m_albumNameBox->setEditText(guesser.album());
m_trackSpin->setValue(guesser.track().toInt());
m_commentBox->setText(guesser.comment());
}
#include "tageditor.moc"
......@@ -28,6 +28,7 @@ class KComboBox;
class KLineEdit;
class KIntSpinBox;
class KEdit;
class KPushButton;
class QCheckBox;
class QBoxLayout;
......@@ -64,6 +65,7 @@ private:
private slots:
void slotDataChanged(bool c = true);
void slotSuggestClicked();
private:
typedef QMap<QWidget *, QCheckBox *> BoxMap;
......@@ -81,6 +83,7 @@ private:
KLineEdit *m_lengthBox;
KLineEdit *m_bitrateBox;
KEdit *m_commentBox;
KPushButton *m_suggestButton;
PlaylistItemList m_items;
......
/*
* tagguesser.cpp - (c) 2003 Frerich Raabe <raabe@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include "tagguesser.h"
#include <kapplication.h>
#include <kconfig.h>
#include <kdeversion.h>
#if KDE_VERSION > KDE_MAKE_VERSION(3,1,0)
# include <kmacroexpander.h>
#endif
#include <qmap.h>
#include <qregexp.h>
#include <qurl.h>
FileNameScheme::FileNameScheme(const QString &s)
: m_regExp(),
m_titleField(-1),
m_artistField(-1),
m_albumField(-1),
m_trackField(-1),
m_commentField(-1)
{
int fieldNumber = 1;
int i = s.find('%');
while (i > -1) {
switch (s[ i + 1 ]) {
case 't': m_titleField = fieldNumber++;
break;
case 'a': m_artistField = fieldNumber++;
break;
case 'A': m_albumField = fieldNumber++;
break;
case 'T': m_trackField = fieldNumber++;
break;
case 'c': m_commentField = fieldNumber++;
break;
default:
break;
}
i = s.find('%', i + 1);
}
m_regExp.setPattern(composeRegExp(s));
}
bool FileNameScheme::matches(const QString &fileName) const
{
return m_regExp.exactMatch(fileName);
}
QString FileNameScheme::title() const
{
if(m_titleField == -1)
return QString::null;
return m_regExp.capturedTexts()[ m_titleField ];
}
QString FileNameScheme::artist() const
{
if(m_artistField == -1)
return QString::null;
return m_regExp.capturedTexts()[ m_artistField ];
}
QString FileNameScheme::album() const
{
if(m_albumField == -1)
return QString::null;
return m_regExp.capturedTexts()[ m_albumField ];
}
QString FileNameScheme::track() const
{
if(m_trackField == -1)
return QString::null;
return m_regExp.capturedTexts()[ m_trackField ];
}
QString FileNameScheme::comment() const
{
if(m_commentField == -1)
return QString::null;
return m_regExp.capturedTexts()[ m_commentField ];
}
QString FileNameScheme::composeRegExp(const QString &s) const
{
QMap<QChar, QString> substitutions;
substitutions[ 't' ] = "([\\w\\s']+)";
substitutions[ 'a' ] = "([\\w\\s]+)";
substitutions[ 'A' ] = "([\\w\\s]+)";
substitutions[ 'T' ] = "(\\d+)";
substitutions[ 'c' ] = "([\\w\\s]+)";
QString regExp = QRegExp::escape(s.simplifyWhiteSpace());
regExp = ".*" + regExp;
regExp.replace(' ', "\\s+");
#if KDE_VERSION > KDE_MAKE_VERSION(3,1,0)
KMacroExpander::expandMacros(regExp, substitutions);
#else
QMap<QChar, QString>::ConstIterator it = substitutions.begin();
QMap<QChar, QString>::ConstIterator end = substitutions.end();
for (; it != end; ++it)
regExp.replace("%" + QString(it.key()), it.data());
#endif
regExp += "\\.[^\\.]+";
return regExp;
}
TagGuesser::TagGuesser()
{
loadSchemes();
}
TagGuesser::TagGuesser(const QString &absFileName)
{
loadSchemes();
guess(absFileName);
}
void TagGuesser::loadSchemes()
{
QStringList schemes = kapp->config()->readListEntry( "Filename schemes" );
if ( schemes.isEmpty() ) {
schemes += "%a/%A/[%T] %t";
schemes += "%a - (%T) - %t [%c]";
schemes += "%a - (%T) - %t (%c)";
schemes += "%a - (%T) - %t";
schemes += "%a - [%T] - %t [%c]";
schemes += "%a - [%T] - %t (%c)";
schemes += "%a - [%T] - %t";
schemes += "%a - %T - %t [%c]";
schemes += "%a - %T - %t (%c)";
schemes += "%a - %T - %t";
schemes += "(%T) %a - %t [%c]";
schemes += "(%T) %a - %t (%c)";
schemes += "(%T) %a - %t";
schemes += "[%T] %a - %t [%c]";
schemes += "[%T] %a - %t (%c)";
schemes += "[%T] %a - %t";
schemes += "%T %a - %t [%c]";
schemes += "%T %a - %t (%c)";
schemes += "%T %a - %t";
schemes += "(%a) %t [%c]";
schemes += "(%a) %t (%c)";
schemes += "(%a) %t";
schemes += "%a - %t [%c]";
schemes += "%a - %t (%c)";
schemes += "%a - %t";
}
QStringList::ConstIterator it = schemes.begin();
QStringList::ConstIterator end = schemes.end();
for ( ; it != end; ++it )
m_schemes += FileNameScheme( *it );
}
void TagGuesser::guess(const QString &absFileName)
{
FileNameScheme::List::ConstIterator it = m_schemes.begin();
FileNameScheme::List::ConstIterator end = m_schemes.end();
for (; it != end; ++it) {
const FileNameScheme schema(*it);
if(schema.matches(absFileName)) {
m_title = schema.title();
m_artist = schema.artist();
m_album = schema.album();
m_track = schema.track();
m_comment = schema.comment();
break;
}
}
}
// vim:ts=4:sw=4:noet
/*
* tagguesser.h - (c) 2003 Frerich Raabe <raabe@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#ifndef ID3TAGGUESSER_H
#define ID3TAGGUESSER_H
#include <qregexp.h>
#include <qstringlist.h>
class FileNameScheme
{
public:
typedef QValueList<FileNameScheme> List;
FileNameScheme() { }
FileNameScheme(const QString &s);
bool matches(const QString &s) const;
QString title() const;
QString artist() const;
QString album() const;
QString track() const;
QString comment() const;
private:
QString composeRegExp(const QString &s) const;
mutable QRegExp m_regExp;
int m_titleField;
int m_artistField;
int m_albumField;
int m_trackField;
int m_commentField;
};
class TagGuesser
{
public:
TagGuesser();
TagGuesser(const QString &absFileName);
void guess(const QString &absFileName);
QString title() const { return m_title; }
QString artist() const { return m_artist; }
QString album() const { return m_album; }
QString track() const { return m_track; }
QString comment() const { return m_comment; }
private:
void loadSchemes();
FileNameScheme::List m_schemes;
QString m_title;
QString m_artist;
QString m_album;
QString m_track;
QString m_comment;
};
#endif // ID3TAGGUESSER_H
// vim:ts=4:sw=4:noet
#include "tagguesser.h"
#include <kaboutdata.h>
#include <kcmdlineargs.h>
#include <kapplication.h>
#include <iostream>
using std::cout;
using std::endl;
void check( const QString &filename, const QString &title,
const QString &artist, const QString &track,
const QString &comment, const QString &album = QString::null )
{
cout << "Checking " << filename.latin1() << "...";
TagGuesser guesser( filename );
if ( guesser.title() != title ) {
cout << "Error: In filename " << filename.latin1() << ", expected title " << title.latin1() << ", got title " << guesser.title().latin1() << endl;
exit( 1 );
}
if ( guesser.artist() != artist ) {
cout << "Error: In filename " << filename.latin1() << ", expected artist " << artist.latin1() << ", got artist " << guesser.artist().latin1() << endl;
exit( 1 );
}
if ( guesser.track() != track ) {
cout << "Error: In filename " << filename.latin1() << ", expected track " << track.latin1() << ", got track " << guesser.track().latin1() << endl;
exit( 1 );
}
if ( guesser.comment() != comment ) {
cout << "Error: In filename " << filename.latin1() << ", expected comment " << comment.latin1() << ", got comment " << guesser.comment().latin1() << endl;
exit( 1 );
}
if ( guesser.album() != album ) {
cout << "Error: In filename " << filename.latin1() << ", expected album " << album.latin1() << ", got album " << guesser.album().latin1() << endl;
exit( 1 );
}
cout << "OK" << endl;
}
int main( int argc, char **argv )
{
KAboutData aboutData("tagguessertest", "tagguessertest", "0.1");
KCmdLineArgs::init(argc, argv, &aboutData);
KApplication app;
check( "/home/frerich/Chemical Brothers - (01) - Block rockin' beats [Live].mp3",
"Block rockin' beats", "Chemical Brothers", "01", "Live" );
check( "/home/frerich/Chemical Brothers - (01) - Block rockin' beats (Live).mp3",
"Block rockin' beats", "Chemical Brothers", "01", "Live" );
check( "/home/frerich/Chemical Brothers - (01) - Block rockin' beats.mp3",
"Block rockin' beats", "Chemical Brothers", "01", QString::null );
check( "/home/frerich/Chemical Brothers - [01] - Block rockin' beats [Live].mp3",
"Block rockin' beats", "Chemical Brothers", "01", "Live" );
check( "/home/frerich/Chemical Brothers - [01] - Block rockin' beats (Live).mp3",
"Block rockin' beats", "Chemical Brothers", "01", "Live" );
check( "/home/frerich/Chemical Brothers - [01] - Block rockin' beats.mp3",
"Block rockin' beats", "Chemical Brothers", "01", QString::null );
check( "/home/frerich/Chemical Brothers - 01 - Block rockin' beats [Live].mp3",
"Block rockin' beats", "Chemical Brothers", "01", "Live" );
check( "/home/frerich/Chemical Brothers - 01 - Block rockin' beats (Live).mp3",
"Block rockin' beats", "Chemical Brothers", "01", "Live" );
check( "/home/frerich/Chemical Brothers - 01 - Block rockin' beats.mp3",
"Block rockin' beats", "Chemical Brothers", "01", QString::null );
check( "/home/frerich/(01) Chemical Brothers - Block rockin' beats [Live].mp3",
"Block rockin' beats", "Chemical Brothers", "01", "Live" );
check( "/home/frerich/(01) Chemical Brothers - Block rockin' beats (Live).mp3",
"Block rockin' beats", "Chemical Brothers", "01", "Live" );
check( "/home/frerich/(01) Chemical Brothers - Block rockin' beats.mp3",
"Block rockin' beats", "Chemical Brothers", "01", QString::null );
check( "/home/frerich/[01] Chemical Brothers - Block rockin' beats [Live].mp3",
"Block rockin' beats", "Chemical Brothers", "01", "Live" );
check( "/home/frerich/[01] Chemical Brothers - Block rockin' beats (Live).mp3",
"Block rockin' beats", "Chemical Brothers", "01", "Live" );
check( "/home/frerich/[01] Chemical Brothers - Block rockin' beats.mp3",
"Block rockin' beats", "Chemical Brothers", "01", QString::null );
check( "/home/frerich/01 Chemical Brothers - Block rockin' beats [Live].mp3",
"Block rockin' beats", "Chemical Brothers", "01", "Live" );
check( "/home/frerich/01 Chemical Brothers - Block rockin' beats (Live).mp3",
"Block rockin' beats", "Chemical Brothers", "01", "Live" );
check( "/home/frerich/01 Chemical Brothers - Block rockin' beats.mp3",
"Block rockin' beats", "Chemical Brothers", "01", QString::null );
check( "/home/frerich/(Chemical Brothers) Block rockin' beats [Live].mp3",
"Block rockin' beats", "Chemical Brothers", QString::null, "Live" );
check( "/home/frerich/(Chemical Brothers) Block rockin' beats (Live).mp3",
"Block rockin' beats", "Chemical Brothers", QString::null, "Live" );
check( "/home/frerich/(Chemical Brothers) Block rockin' beats.mp3",
"Block rockin' beats", "Chemical Brothers", QString::null, QString::null );
check( "/home/frerich/Chemical Brothers - Block rockin' beats [Live].mp3",
"Block rockin' beats", "Chemical Brothers", QString::null, "Live" );
check( "/home/frerich/Chemical Brothers - Block rockin' beats (Live).mp3",
"Block rockin' beats", "Chemical Brothers", QString::null, "Live" );
check( "/home/frerich/Chemical Brothers - Block rockin' beats.mp3",
"Block rockin' beats", "Chemical Brothers", QString::null, QString::null );
check( "/home/frerich/mp3/Chemical Brothers/Dig your own hole/[01] Block rockin' beats.mp3",
"Block rockin' beats", "Chemical Brothers", "01", QString::null, "Dig your own hole");
cout << "All OK" << endl;
return 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment