Commit 363e28b4 authored by Bart van der Velden's avatar Bart van der Velden

- Add partial FileTypeResolver implementation

- Add some FileTypeResolver unit tests
- Add some test data
- Add a way to test FileTypeResolver from the Qt UI (#65)
parent ae3c345b
......@@ -59,19 +59,20 @@ if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR})
endif()
#-----------------------------------------------------------------------------
# Set the path to the CMake modules
# Set some paths
# Set the path to the CMake modules
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules)
# Set output path
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
# Set library path
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
# Set the path to the test data
set(TEST_DATA_PATH ${CMAKE_CURRENT_SOURCE_DIR}/data/testdata)
#-----------------------------------------------------------------------------
# Enable modules
#-----------------------------------------------------------------------------
# Set output paths
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
#-----------------------------------------------------------------------------
# Global compiler flags
include(PedanticCompilerWarnings)
......
......@@ -29,6 +29,12 @@ configure_file (
"${PROJECT_BINARY_DIR}/src/version.cpp"
)
# Configure a header file to set some settings that are useful for unit testing
configure_file (
"${PROJECT_SOURCE_DIR}/src/testconfig.h.in"
"${PROJECT_BINARY_DIR}/src/testconfig.h"
)
# Start with a clean list of libraries to link to
set(EXTRA_LIBS "")
......@@ -160,13 +166,10 @@ if(CMAKE_DEBUG)
endforeach()
endif()
# Add the binary tree to the search path for include files
# so that we will find MusicCollectionConfig.h
include_directories("${PROJECT_BINARY_DIR}/src")
#--------------------------------------------------------------------
# Add libraries
include_directories(${PROJECT_BINARY_DIR}/src)
include_directories(utils)
add_subdirectory(utils)
include_directories(collection)
......
......@@ -15,21 +15,52 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*****************************************************************************/
/* Credits:
* The content of this file is based on the createFile implementation in Amarok combined with an
* example on Qt5 mime types provided by Jeff Tranter at
* http://www.ics.com/blog/whats-new-qt-5-qmimedatabase-and-qmimetype
*/
#include "FileTypeResolver.h"
// Qt includes
#include <QFile>
#include <QMimeType>
#include <QMimeDatabase>
// TagLib includes
#include <mpegfile.h>
#include <oggfile.h>
#include <vorbisfile.h>
using namespace std;
using namespace mc::collection;
using namespace TagLib;
TagLib::File* FileTypeResolver::createFile(
TagLib::FileName fileName,
bool readProperties,
TagLib::AudioProperties::ReadStyle propertiesStyle) const
/* createFile creates the derived File type, e.g. TagLib::MPEG::File, based on
* fileName's extension and/or content.
*/
File* FileTypeResolver::createFile(
FileName fileName,
bool readAudioProperties /* = true */,
AudioProperties::ReadStyle audioPropertiesStyle /* = AudioProperties::Average */) const
{
//QMimeDatabase mimeDatabase;
//QMimeType mimeType;
File* result = 0;
QMimeDatabase mimeDatabase;
TagLib::File* result = 0;
//if ()
QString fn = QFile::decodeName(fileName);
QMimeType mimeType = mimeDatabase.mimeTypeForFile(fn);
QString mtn = mimeType.name();
if (mimeType.name() == QString("audio/mpeg"))
{
result = new MPEG::File(fileName, readAudioProperties, audioPropertiesStyle);
}
else if ((mimeType.name() == QString("audio/vorbis")) ||
(mimeType.name() == QString("audio/x-vorbis+ogg")) ||
(mimeType.name() == QString("audio/ogg")))
{
result = new Ogg::Vorbis::File(fileName, readAudioProperties, audioPropertiesStyle);
}
return result;
}
......@@ -31,10 +31,18 @@ namespace mc
{
public:
//! The TagLib virtual function to override
/*! createFile creates the derived File type, e.g. TagLib::MPEG::File, based on
* fileName's extension and/or content.
* \param fileName the file to examine
* \param readAudioProperties
* \param audioPropertiesStyle determines how much to read from the file, this strongly
* determines the time needed
*/
virtual TagLib::File* createFile(
TagLib::FileName fileName,
bool readAudioProperties,
TagLib::AudioProperties::ReadStyle audioPropertiesStyle) const;
bool readAudioProperties = true,
TagLib::AudioProperties::ReadStyle audioPropertiesStyle =
TagLib::AudioProperties::Average) const;
public:
virtual ~FileTypeResolver()
{
......
#include <gtest/gtest.h>
#include "../FileTypeResolver.h"
#include <QString>
#include <QDir>
#include "testconfig.h"
#include <mpegfile.h>
#include <oggfile.h>
#include <vorbisfile.h>
using namespace std;
using namespace mc::collection;
using namespace TagLib;
QString datapath(const QString& relPath)
{
return QDir::toNativeSeparators(QString(MUSICCOLLECTION_TEST_DIR) + '/' + relPath );
}
TEST(FileTypeResolverTest, EmptyPath)
{
FileTypeResolver ftr;
TagLib::File* file = ftr.createFile(
"", false, TagLib::AudioProperties::Fast);
File* file = ftr.createFile("");
EXPECT_EQ(0, file);
file = ftr.createFile("ThisDoesNotExist", false, TagLib::AudioProperties::Average);
file = ftr.createFile("ThisDoesNotExist");
EXPECT_EQ(0, file);
}
TEST(FileTypeResolverTest, FileDoesNotExist)
{
FileTypeResolver ftr;
File* file = ftr.createFile("ThisDoesNotExist");
EXPECT_EQ(0, file);
}
TEST(FileTypeResolverTest, FileDoesNotExistMp3Ext)
{
FileTypeResolver ftr;
File* file = ftr.createFile("ThisDoesNotExist.mp3");
ASSERT_TRUE(file != 0);
ASSERT_TRUE(dynamic_cast<MPEG::File*>(file) != 0);
}
TEST(FileTypeResolverTest, JapaneseOggFile)
{
FileTypeResolver ftr;
File* file = ftr.createFile(QFile::encodeName(datapath("data/testdata/テスト.ogg")).constData());
ASSERT_TRUE(file != 0);
ASSERT_TRUE(dynamic_cast<Ogg::Vorbis::File*>(file) != 0);
}
TEST(FileTypeResolverTest, ArabicOggFile)
{
FileTypeResolver ftr;
File* file = ftr.createFile(QFile::encodeName(datapath("data/testdata/اختبار.ogg")).constData());
ASSERT_TRUE(file != 0);
ASSERT_TRUE(dynamic_cast<Ogg::Vorbis::File*>(file) != 0);
}
TEST(FileTypeResolverTest, RussianOggFile)
{
FileTypeResolver ftr;
File* file = ftr.createFile(QFile::encodeName(datapath("data/testdata/тест.ogg")).constData());
ASSERT_TRUE(file != 0);
ASSERT_TRUE(dynamic_cast<Ogg::Vorbis::File*>(file) != 0);
}
/*****************************************************************************
* Copyright 2012-2013 Bart van der Velden <bart@muckingabout.eu> *
* Copyright 2014 Bart van der Velden <bart@muckingabout.eu> *
* *
* 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 *
......@@ -15,5 +15,4 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*****************************************************************************/
#define MusicCollection_VERSION_MAJOR @MusicCollection_VERSION_MAJOR@
#define MusicCollection_VERSION_MINOR @MusicCollection_VERSION_MINOR@
#define MUSICCOLLECTION_TEST_DIR "@TEST_DATA_PATH@"
......@@ -32,28 +32,28 @@ const char* About::kUrl = "https://gitorious.org/musiccollection";
About::About(QWidget *parent)
: QDialog(parent)
{
mUi.setupUi(this);
m_ui.setupUi(this);
setWindowTitle(tr("About %1").arg(QCoreApplication::applicationName()));
mUi.title->setText(QCoreApplication::applicationName());
mUi.version->setText(tr("Version %1").arg(QCoreApplication::applicationVersion()));
m_ui.title->setText(QCoreApplication::applicationName());
m_ui.version->setText(tr("Version %1").arg(QCoreApplication::applicationVersion()));
QFont title_font;
title_font.setBold(true);
title_font.setPointSize(title_font.pointSize() + 4);
mUi.title->setFont(title_font);
m_ui.title->setFont(title_font);
mAuthors << Contributor(QString::fromUtf8("Bart van der Velden"), "bart@muckingabout.eu", 0);
mThanksTo
m_authors << Contributor(QString::fromUtf8("Bart van der Velden"), "bart@muckingabout.eu", 0);
m_thanksTo
<< Contributor("The Clementine Music Player Project", 0, "http://www.clementine-player.org/")
<< Contributor("The Amarok Project", 0, "http://amarok.kde.org/");
qSort(mAuthors);
qSort(mThanksTo);
qSort(m_authors);
qSort(m_thanksTo);
mUi.content->setHtml(MakeHtml());
m_ui.content->setHtml(MakeHtml());
mUi.buttonBox->button(QDialogButtonBox::Close)->setShortcut(QKeySequence::Close);
m_ui.buttonBox->button(QDialogButtonBox::Close)->setShortcut(QKeySequence::Close);
}
QString About::MakeHtml() const
......@@ -61,12 +61,12 @@ QString About::MakeHtml() const
QString ret = QString("<p><a href=\"%1\">%2</a></p>"
"<p><b>%3:</b>").arg(kUrl, kUrl, tr("Authors"));
foreach (const Contributor& contributor, mAuthors)
foreach (const Contributor& contributor, m_authors)
ret += "<br />" + MakeHtml(contributor);
ret += QString("</p><p><b>%3:</b>").arg(tr("Thanks to"));
foreach (const Contributor& contributor, mThanksTo)
foreach (const Contributor& contributor, m_thanksTo)
ret += "<br />" + MakeHtml(contributor);
return ret;
......@@ -76,14 +76,14 @@ QString About::MakeHtml(const Contributor& contributor) const
{
const QString mailTemplate = " &lt;<a href=\"mailto:%1\">%2</a>&gt;";
const QString urlTemplate = " &lt;<a href=\"%1\">%2</a>&gt;";
QString retVal = contributor.mName;
if (!contributor.mEmail.isNull())
QString retVal = contributor.m_name;
if (!contributor.m_email.isNull())
{
retVal += QString(mailTemplate).arg(contributor.mEmail, contributor.mEmail);
retVal += QString(mailTemplate).arg(contributor.m_email, contributor.m_email);
}
if (!contributor.mUrl.isNull())
if (!contributor.m_url.isNull())
{
retVal += QString(urlTemplate).arg(contributor.mUrl, contributor.mUrl);
retVal += QString(urlTemplate).arg(contributor.m_url, contributor.m_url);
}
return retVal;
}
......@@ -39,13 +39,13 @@ public:
struct Contributor
{
Contributor(const QString& name, const QString& email, const QString& url)
: mName(name), mEmail(email), mUrl(url) {}
: m_name(name), m_email(email), m_url(url) {}
bool operator <(const Contributor& other) const { return mName < other.mName; }
bool operator <(const Contributor& other) const { return m_name < other.m_name; }
QString mName;
QString mEmail;
QString mUrl;
QString m_name;
QString m_email;
QString m_url;
};
private:
......@@ -53,10 +53,10 @@ private:
QString MakeHtml(const Contributor& contributor) const;
private:
Ui::About mUi;
Ui::About m_ui;
QList<Contributor> mAuthors; // The list of authors
QList<Contributor> mThanksTo; // The list of people/projects to thank
QList<Contributor> m_authors; // The list of authors
QList<Contributor> m_thanksTo; // The list of people/projects to thank
};
#endif // MUSICCOLLECTION_UI_ABOUT_H_INCLUDED
......@@ -18,26 +18,49 @@
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "ui/about.h"
#include <QFileDialog>
#include "FileTypeResolver.h"
#include "taglib.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
mUi(new Ui::MainWindow)
m_ui(new Ui::MainWindow)
{
mUi->setupUi(this);
connect(mUi->pushButton, SIGNAL(clicked()), SLOT(ShowAboutDialog()));
m_ui->setupUi(this);
// Connect signals and slots
connect(m_ui->aboutButton, SIGNAL(clicked()), SLOT(ShowAboutDialog()));
connect(m_ui->browseButton, SIGNAL(clicked()), SLOT(BrowseForFile()));
connect(m_ui->lookupButton, &QPushButton::clicked, this, &MainWindow::LookupFile);
}
MainWindow::~MainWindow()
{
delete mUi;
delete m_ui;
}
void MainWindow::BrowseForFile()
{
QString filename = QFileDialog::getOpenFileName(this, tr("Select File"));
if (!filename.isEmpty())
{
m_ui->filenameLineEdit->setText(filename);
}
}
void MainWindow::LookupFile()
{
mc::collection::FileTypeResolver ftr;
ftr.createFile(m_ui->filenameLineEdit->text().toStdString().c_str());
}
void MainWindow::ShowAboutDialog()
{
if (!mAboutDialog)
if (!m_aboutDialog)
{
mAboutDialog.reset(new About);
m_aboutDialog.reset(new About);
}
mAboutDialog->show();
m_aboutDialog->show();
}
......@@ -40,11 +40,13 @@ public:
private slots:
void BrowseForFile();
void LookupFile();
void ShowAboutDialog();
private:
Ui::MainWindow* mUi;
boost::scoped_ptr<About> mAboutDialog;
Ui::MainWindow* m_ui;
boost::scoped_ptr<About> m_aboutDialog;
};
......
......@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>582</width>
<height>446</height>
<width>633</width>
<height>451</height>
</rect>
</property>
<property name="sizePolicy">
......@@ -25,19 +25,71 @@
<rect>
<x>10</x>
<y>0</y>
<width>561</width>
<height>71</height>
<width>611</width>
<height>111</height>
</rect>
</property>
<property name="title">
<string>GroupBox</string>
</property>
<widget class="QPushButton" name="browseButton">
<property name="geometry">
<rect>
<x>510</x>
<y>19</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>&amp;Browse...</string>
</property>
</widget>
<widget class="QLabel" name="label">
<property name="geometry">
<rect>
<x>5</x>
<y>19</y>
<width>20</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>&amp;File:</string>
</property>
<property name="buddy">
<cstring>filenameLineEdit</cstring>
</property>
</widget>
<widget class="QLineEdit" name="filenameLineEdit">
<property name="geometry">
<rect>
<x>31</x>
<y>20</y>
<width>473</width>
<height>20</height>
</rect>
</property>
</widget>
<widget class="QPushButton" name="lookupButton">
<property name="geometry">
<rect>
<x>30</x>
<y>50</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>Lookup</string>
</property>
</widget>
</widget>
<widget class="QPushButton" name="pushButton">
<widget class="QPushButton" name="aboutButton">
<property name="geometry">
<rect>
<x>100</x>
<y>130</y>
<x>490</x>
<y>360</y>
<width>75</width>
<height>23</height>
</rect>
......@@ -52,7 +104,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>582</width>
<width>633</width>
<height>18</height>
</rect>
</property>
......
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