Store the device's transcode preference in the database

This commit is contained in:
David Sansome 2010-08-29 15:32:36 +00:00
parent ae47b271f3
commit d8ea4660e7
12 changed files with 153 additions and 42 deletions

View File

@ -262,5 +262,6 @@
<file>icons/32x32/ipodtouchicon.png</file> <file>icons/32x32/ipodtouchicon.png</file>
<file>icons/48x48/ipodtouchicon.png</file> <file>icons/48x48/ipodtouchicon.png</file>
<file>icons/32x32/wiimotedev.png</file> <file>icons/32x32/wiimotedev.png</file>
<file>schema-17.sql</file>
</qresource> </qresource>
</RCC> </RCC>

6
data/schema-17.sql Normal file
View File

@ -0,0 +1,6 @@
ALTER TABLE devices ADD COLUMN transcode_mode NOT NULL DEFAULT 3;
ALTER TABLE devices ADD COLUMN transcode_format NOT NULL DEFAULT 5;
UPDATE schema_version SET version=17;

View File

@ -29,7 +29,7 @@
#include <QVariant> #include <QVariant>
const char* Database::kDatabaseFilename = "clementine.db"; const char* Database::kDatabaseFilename = "clementine.db";
const int Database::kSchemaVersion = 16; const int Database::kSchemaVersion = 17;
int Database::sNextConnectionId = 1; int Database::sNextConnectionId = 1;
QMutex Database::sNextConnectionIdMutex; QMutex Database::sNextConnectionIdMutex;

View File

@ -39,7 +39,8 @@ DeviceDatabaseBackend::DeviceList DeviceDatabaseBackend::GetAllDevices() {
DeviceList ret; DeviceList ret;
QSqlQuery q("SELECT ROWID, unique_id, friendly_name, size, icon" QSqlQuery q("SELECT ROWID, unique_id, friendly_name, size, icon,"
" transcode_mode, transcode_format"
" FROM devices", db); " FROM devices", db);
q.exec(); q.exec();
if (db_->CheckErrors(q.lastError())) return ret; if (db_->CheckErrors(q.lastError())) return ret;
@ -51,6 +52,8 @@ DeviceDatabaseBackend::DeviceList DeviceDatabaseBackend::GetAllDevices() {
dev.friendly_name_ = q.value(2).toString(); dev.friendly_name_ = q.value(2).toString();
dev.size_ = q.value(3).toLongLong(); dev.size_ = q.value(3).toLongLong();
dev.icon_name_ = q.value(4).toString(); dev.icon_name_ = q.value(4).toString();
dev.transcode_mode_ = TranscodeMode(q.value(5).toInt());
dev.transcode_format_ = Song::FileType(q.value(6).toInt());
ret << dev; ret << dev;
} }
return ret; return ret;
@ -63,12 +66,17 @@ int DeviceDatabaseBackend::AddDevice(const Device &device) {
ScopedTransaction t(&db); ScopedTransaction t(&db);
// Insert the device into the devices table // Insert the device into the devices table
QSqlQuery q("INSERT INTO devices (unique_id, friendly_name, size, icon)" QSqlQuery q("INSERT INTO devices ("
" VALUES (:unique_id, :friendly_name, :size, :icon)", db); " unique_id, friendly_name, size, icon,"
" transcode_mode, transcode_format)"
" VALUES (:unique_id, :friendly_name, :size, :icon,"
" :transcode_mode, :transcode_format)", db);
q.bindValue(":unique_id", device.unique_id_); q.bindValue(":unique_id", device.unique_id_);
q.bindValue(":friendly_name", device.friendly_name_); q.bindValue(":friendly_name", device.friendly_name_);
q.bindValue(":size", device.size_); q.bindValue(":size", device.size_);
q.bindValue(":icon", device.icon_name_); q.bindValue(":icon", device.icon_name_);
q.bindValue(":transcode_mode", device.transcode_mode_);
q.bindValue(":transcode_format", device.transcode_format_);
q.exec(); q.exec();
if (db_->CheckErrors(q.lastError())) return -1; if (db_->CheckErrors(q.lastError())) return -1;
int id = q.lastInsertId().toInt(); int id = q.lastInsertId().toInt();
@ -108,17 +116,22 @@ void DeviceDatabaseBackend::RemoveDevice(int id) {
t.Commit(); t.Commit();
} }
void DeviceDatabaseBackend::SetDeviceIdentity(int id, const QString &friendly_name, void DeviceDatabaseBackend::SetDeviceOptions(int id,
const QString &icon_name) { const QString &friendly_name, const QString &icon_name,
TranscodeMode mode, Song::FileType format) {
QMutexLocker l(db_->Mutex()); QMutexLocker l(db_->Mutex());
QSqlDatabase db(db_->Connect()); QSqlDatabase db(db_->Connect());
QSqlQuery q("UPDATE devices" QSqlQuery q("UPDATE devices"
" SET friendly_name=:friendly_name," " SET friendly_name=:friendly_name,"
" icon=:icon_name" " icon=:icon_name,"
" transcode_mode=:transcode_mode,"
" transcode_format=:transcode_format"
" WHERE ROWID=:id", db); " WHERE ROWID=:id", db);
q.bindValue(":friendly_name", friendly_name); q.bindValue(":friendly_name", friendly_name);
q.bindValue(":icon_name", icon_name); q.bindValue(":icon_name", icon_name);
q.bindValue(":transcode_mode", mode);
q.bindValue(":transcode_format", format);
q.bindValue(":id", id); q.bindValue(":id", id);
q.exec(); q.exec();
db_->CheckErrors(q.lastError()); db_->CheckErrors(q.lastError());

View File

@ -21,6 +21,8 @@
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include "core/song.h"
class Database; class Database;
class DeviceDatabaseBackend : public QObject { class DeviceDatabaseBackend : public QObject {
@ -29,6 +31,13 @@ class DeviceDatabaseBackend : public QObject {
public: public:
Q_INVOKABLE DeviceDatabaseBackend(QObject* parent = 0); Q_INVOKABLE DeviceDatabaseBackend(QObject* parent = 0);
// Values are saved in the database - don't change
enum TranscodeMode {
Transcode_Always = 1,
Transcode_Never = 2,
Transcode_Unsupported = 3,
};
struct Device { struct Device {
Device() : id_(-1) {} Device() : id_(-1) {}
@ -37,6 +46,9 @@ public:
QString friendly_name_; QString friendly_name_;
quint64 size_; quint64 size_;
QString icon_name_; QString icon_name_;
TranscodeMode transcode_mode_;
Song::FileType transcode_format_;
}; };
typedef QList<Device> DeviceList; typedef QList<Device> DeviceList;
@ -49,8 +61,9 @@ public:
int AddDevice(const Device& device); int AddDevice(const Device& device);
void RemoveDevice(int id); void RemoveDevice(int id);
void SetDeviceIdentity(int id, const QString& friendly_name, void SetDeviceOptions(int id,
const QString& icon_name); const QString& friendly_name, const QString& icon_name,
TranscodeMode mode, Song::FileType format);
private: private:
boost::shared_ptr<Database> db_; boost::shared_ptr<Database> db_;

View File

@ -60,6 +60,8 @@ const int DeviceManager::kDeviceIconOverlaySize = 16;
DeviceManager::DeviceInfo::DeviceInfo() DeviceManager::DeviceInfo::DeviceInfo()
: database_id_(-1), : database_id_(-1),
transcode_mode_(DeviceDatabaseBackend::Transcode_Unsupported),
transcode_format_(Song::Type_Mpeg),
task_percentage_(-1) task_percentage_(-1)
{ {
} }
@ -70,6 +72,8 @@ DeviceDatabaseBackend::Device DeviceManager::DeviceInfo::SaveToDb() const {
ret.size_ = size_; ret.size_ = size_;
ret.id_ = database_id_; ret.id_ = database_id_;
ret.icon_name_ = icon_name_; ret.icon_name_ = icon_name_;
ret.transcode_mode_ = transcode_mode_;
ret.transcode_format_ = transcode_format_;
QStringList unique_ids; QStringList unique_ids;
foreach (const Backend& backend, backends_) { foreach (const Backend& backend, backends_) {
@ -84,6 +88,8 @@ void DeviceManager::DeviceInfo::InitFromDb(const DeviceDatabaseBackend::Device &
database_id_ = dev.id_; database_id_ = dev.id_;
friendly_name_ = dev.friendly_name_; friendly_name_ = dev.friendly_name_;
size_ = dev.size_; size_ = dev.size_;
transcode_mode_ = dev.transcode_mode_;
transcode_format_ = dev.transcode_format_;
QStringList icon_names = dev.icon_name_.split(','); QStringList icon_names = dev.icon_name_.split(',');
QVariantList icons; QVariantList icons;
@ -321,6 +327,12 @@ QVariant DeviceManager::data(const QModelIndex& index, int role) const {
return QDir::toNativeSeparators(ret); return QDir::toNativeSeparators(ret);
} }
case Role_TranscodeMode:
return info.transcode_mode_;
case Role_TranscodeFormat:
return info.transcode_format_;
default: default:
return QVariant(); return QVariant();
} }
@ -604,16 +616,20 @@ void DeviceManager::Forget(int row) {
} }
} }
void DeviceManager::SetDeviceIdentity(int row, const QString &friendly_name, void DeviceManager::SetDeviceOptions(int row,
const QString &icon_name) { const QString& friendly_name, const QString& icon_name,
DeviceDatabaseBackend::TranscodeMode mode, Song::FileType format) {
DeviceInfo& info = devices_[row]; DeviceInfo& info = devices_[row];
info.friendly_name_ = friendly_name; info.friendly_name_ = friendly_name;
info.LoadIcon(QVariantList() << icon_name, friendly_name); info.LoadIcon(QVariantList() << icon_name, friendly_name);
info.transcode_mode_ = mode;
info.transcode_format_ = format;
emit dataChanged(index(row, 0), index(row, 0)); emit dataChanged(index(row, 0), index(row, 0));
if (info.database_id_ != -1) if (info.database_id_ != -1)
backend_->SetDeviceIdentity(info.database_id_, friendly_name, icon_name); backend_->SetDeviceOptions(info.database_id_, friendly_name, icon_name,
mode, format);
} }
void DeviceManager::DeviceTaskStarted(int id) { void DeviceManager::DeviceTaskStarted(int id) {

View File

@ -49,6 +49,8 @@ public:
Role_IconName, Role_IconName,
Role_UpdatingPercentage, Role_UpdatingPercentage,
Role_MountPath, Role_MountPath,
Role_TranscodeMode,
Role_TranscodeFormat,
LastRole, LastRole,
}; };
@ -81,8 +83,9 @@ public:
void Forget(int row); void Forget(int row);
void UnmountAsync(int row); void UnmountAsync(int row);
void SetDeviceIdentity(int row, const QString& friendly_name, void SetDeviceOptions(int row,
const QString& icon_name); const QString& friendly_name, const QString& icon_name,
DeviceDatabaseBackend::TranscodeMode mode, Song::FileType format);
// QAbstractListModel // QAbstractListModel
int rowCount(const QModelIndex &parent) const; int rowCount(const QModelIndex &parent) const;
@ -148,6 +151,9 @@ private:
QString icon_name_; QString icon_name_;
QIcon icon_; QIcon icon_;
DeviceDatabaseBackend::TranscodeMode transcode_mode_;
Song::FileType transcode_format_;
int task_percentage_; int task_percentage_;
}; };

View File

@ -20,6 +20,7 @@
#include "deviceproperties.h" #include "deviceproperties.h"
#include "ui_deviceproperties.h" #include "ui_deviceproperties.h"
#include "core/utilities.h" #include "core/utilities.h"
#include "transcoder/transcoder.h"
#include "ui/iconloader.h" #include "ui/iconloader.h"
#include <QFutureWatcher> #include <QFutureWatcher>
@ -56,8 +57,8 @@ void DeviceProperties::SetDeviceManager(DeviceManager *manager) {
} }
void DeviceProperties::ShowDevice(int row) { void DeviceProperties::ShowDevice(int row) {
// Only load the icons the first time the dialog is shown
if (ui_->icon->count() == 0) { if (ui_->icon->count() == 0) {
// Only load the icons the first time the dialog is shown
QStringList icon_names = QStringList() QStringList icon_names = QStringList()
<< "drive-removable-media-usb-pendrive" << "drive-removable-media-usb-pendrive"
<< "multimedia-player-ipod-mini-blue" << "multimedia-player-ipod-mini-blue"
@ -85,6 +86,12 @@ void DeviceProperties::ShowDevice(int row) {
IconLoader::Load(icon_name), QString(), ui_->icon); IconLoader::Load(icon_name), QString(), ui_->icon);
item->setData(Qt::UserRole, icon_name); item->setData(Qt::UserRole, icon_name);
} }
// Load the transcode formats the first time the dialog is shown
foreach (const TranscoderPreset& preset, Transcoder::GetAllPresets()) {
ui_->transcode_format->addItem(preset.name_, preset.type_);
}
ui_->transcode_format->model()->sort(0);
} }
index_ = manager_->index(row); index_ = manager_->index(row);
@ -179,6 +186,29 @@ void DeviceProperties::UpdateFormats() {
boost::shared_ptr<ConnectedDevice> device = boost::shared_ptr<ConnectedDevice> device =
manager_->GetConnectedDevice(index_.row()); manager_->GetConnectedDevice(index_.row());
// Transcode mode
DeviceDatabaseBackend::TranscodeMode mode = DeviceDatabaseBackend::TranscodeMode(
index_.data(DeviceManager::Role_TranscodeMode).toInt());
switch (mode) {
case DeviceDatabaseBackend::Transcode_Always:
ui_->transcode_all->setChecked(true);
break;
case DeviceDatabaseBackend::Transcode_Never:
ui_->transcode_off->setChecked(true);
break;
case DeviceDatabaseBackend::Transcode_Unsupported:
default:
ui_->transcode_unsupported->setChecked(true);
break;
}
// Transcode format
TranscoderPreset preset = Transcoder::PresetForFileType(Song::FileType(
index_.data(DeviceManager::Role_TranscodeFormat).toInt()));
ui_->transcode_format->setCurrentIndex(ui_->transcode_format->findText(preset.name_));
// If there's no lister then the device is physically disconnected // If there's no lister then the device is physically disconnected
if (!lister) { if (!lister) {
ui_->formats_stack->setCurrentWidget(ui_->formats_page_not_connected); ui_->formats_stack->setCurrentWidget(ui_->formats_page_not_connected);
@ -212,8 +242,22 @@ void DeviceProperties::UpdateFormats() {
void DeviceProperties::accept() { void DeviceProperties::accept() {
QDialog::accept(); QDialog::accept();
manager_->SetDeviceIdentity(index_.row(), ui_->name->text(), // Transcode mode
ui_->icon->currentItem()->data(Qt::UserRole).toString()); DeviceDatabaseBackend::TranscodeMode mode = DeviceDatabaseBackend::Transcode_Unsupported;
if (ui_->transcode_all->isChecked())
mode = DeviceDatabaseBackend::Transcode_Always;
else if (ui_->transcode_off->isChecked())
mode = DeviceDatabaseBackend::Transcode_Never;
else if (ui_->transcode_unsupported->isChecked())
mode = DeviceDatabaseBackend::Transcode_Unsupported;
// Transcode format
Song::FileType format = Song::FileType(ui_->transcode_format->itemData(
ui_->transcode_format->currentIndex()).toInt());
manager_->SetDeviceOptions(index_.row(),
ui_->name->text(), ui_->icon->currentItem()->data(Qt::UserRole).toString(),
mode, format);
} }
void DeviceProperties::OpenDevice() { void DeviceProperties::OpenDevice() {
@ -231,6 +275,10 @@ void DeviceProperties::UpdateFormatsFinished() {
ui_->supported_formats_container->setVisible(!list.isEmpty()); ui_->supported_formats_container->setVisible(!list.isEmpty());
ui_->transcode_unsupported->setEnabled(!list.isEmpty()); ui_->transcode_unsupported->setEnabled(!list.isEmpty());
if (ui_->transcode_unsupported->isChecked() && list.isEmpty()) {
ui_->transcode_off->setChecked(true);
}
// Populate supported types list // Populate supported types list
ui_->supported_formats->clear(); ui_->supported_formats->clear();
foreach (Song::FileType type, list) { foreach (Song::FileType type, list) {

View File

@ -20,6 +20,8 @@
#include <QDialog> #include <QDialog>
#include <QPersistentModelIndex> #include <QPersistentModelIndex>
#include "core/song.h"
class DeviceManager; class DeviceManager;
class Ui_DeviceProperties; class Ui_DeviceProperties;

View File

@ -54,7 +54,7 @@ TranscodeDialog::TranscodeDialog(QWidget *parent)
log_ui_->setupUi(log_dialog_); log_ui_->setupUi(log_dialog_);
// Get presets // Get presets
QList<TranscoderPreset> presets = transcoder_->presets(); QList<TranscoderPreset> presets = Transcoder::GetAllPresets();
qSort(presets.begin(), presets.end(), ComparePresetsByName); qSort(presets.begin(), presets.end(), ComparePresetsByName);
foreach (const TranscoderPreset& preset, presets) { foreach (const TranscoderPreset& preset, presets) {
ui_->format->addItem( ui_->format->addItem(

View File

@ -29,11 +29,13 @@ int Transcoder::JobFinishedEvent::sEventType = -1;
TranscoderPreset::TranscoderPreset( TranscoderPreset::TranscoderPreset(
Song::FileType type,
const QString& name, const QString& name,
const QString& extension, const QString& extension,
const QString& codec_mimetype, const QString& codec_mimetype,
const QString& muxer_mimetype) const QString& muxer_mimetype)
: name_(name), : type_(type),
name_(name),
extension_(extension), extension_(extension),
codec_mimetype_(codec_mimetype), codec_mimetype_(codec_mimetype),
muxer_mimetype_(muxer_mimetype) muxer_mimetype_(muxer_mimetype)
@ -165,36 +167,39 @@ Transcoder::Transcoder(QObject* parent)
{ {
if (JobFinishedEvent::sEventType == -1) if (JobFinishedEvent::sEventType == -1)
JobFinishedEvent::sEventType = QEvent::registerEventType(); JobFinishedEvent::sEventType = QEvent::registerEventType();
}
presets_ << PresetForFileType(Song::Type_Flac); QList<TranscoderPreset> Transcoder::GetAllPresets() {
presets_ << PresetForFileType(Song::Type_Mp4); QList<TranscoderPreset> ret;
presets_ << PresetForFileType(Song::Type_Mpeg); ret << PresetForFileType(Song::Type_Flac);
presets_ << PresetForFileType(Song::Type_OggVorbis); ret << PresetForFileType(Song::Type_Mp4);
presets_ << PresetForFileType(Song::Type_OggFlac); ret << PresetForFileType(Song::Type_Mpeg);
presets_ << PresetForFileType(Song::Type_OggSpeex); ret << PresetForFileType(Song::Type_OggVorbis);
presets_ << PresetForFileType(Song::Type_Asf); ret << PresetForFileType(Song::Type_OggFlac);
presets_ << PresetForFileType(Song::Type_Wav); ret << PresetForFileType(Song::Type_OggSpeex);
presets_ << TranscoderPreset("3GP AAC", "3gp", "audio/mpeg, mpegversion=(int)4", "application/x-3gp"); ret << PresetForFileType(Song::Type_Asf);
ret << PresetForFileType(Song::Type_Wav);
return ret;
} }
TranscoderPreset Transcoder::PresetForFileType(Song::FileType type) { TranscoderPreset Transcoder::PresetForFileType(Song::FileType type) {
switch (type) { switch (type) {
case Song::Type_Flac: case Song::Type_Flac:
return TranscoderPreset("FLAC", "flac", "audio/x-flac"); return TranscoderPreset(type, "FLAC", "flac", "audio/x-flac");
case Song::Type_Mp4: case Song::Type_Mp4:
return TranscoderPreset("M4A AAC", "mp4", "audio/mpeg, mpegversion=(int)4", "audio/mp4"); return TranscoderPreset(type, "M4A AAC", "mp4", "audio/mpeg, mpegversion=(int)4", "audio/mp4");
case Song::Type_Mpeg: case Song::Type_Mpeg:
return TranscoderPreset("MP3", "mp3", "audio/mpeg, mpegversion=(int)1, layer=(int)3"); return TranscoderPreset(type, "MP3", "mp3", "audio/mpeg, mpegversion=(int)1, layer=(int)3");
case Song::Type_OggVorbis: case Song::Type_OggVorbis:
return TranscoderPreset("Ogg Vorbis", "ogg", "audio/x-vorbis", "application/ogg"); return TranscoderPreset(type, "Ogg Vorbis", "ogg", "audio/x-vorbis", "application/ogg");
case Song::Type_OggFlac: case Song::Type_OggFlac:
return TranscoderPreset("Ogg Flac", "ogg", "audio/x-flac", "application/ogg"); return TranscoderPreset(type, "Ogg Flac", "ogg", "audio/x-flac", "application/ogg");
case Song::Type_OggSpeex: case Song::Type_OggSpeex:
return TranscoderPreset("Ogg Speex", "spx", "audio/x-speex", "application/ogg"); return TranscoderPreset(type, "Ogg Speex", "spx", "audio/x-speex", "application/ogg");
case Song::Type_Asf: case Song::Type_Asf:
return TranscoderPreset("Windows Media audio", "wma", "audio/x-wma", "video/x-ms-asf"); return TranscoderPreset(type, "Windows Media audio", "wma", "audio/x-wma", "video/x-ms-asf");
case Song::Type_Wav: case Song::Type_Wav:
return TranscoderPreset("Wav", "wav", QString(), "audio/x-wav"); return TranscoderPreset(type, "Wav", "wav", QString(), "audio/x-wav");
default: default:
qWarning() << "Unsupported format in Transcoder::PresetForFileType:" << type; qWarning() << "Unsupported format in Transcoder::PresetForFileType:" << type;
return TranscoderPreset(); return TranscoderPreset();

View File

@ -31,12 +31,14 @@
struct TranscoderPreset { struct TranscoderPreset {
TranscoderPreset() {} TranscoderPreset() : type_(Song::Type_Unknown) {}
TranscoderPreset(const QString& name, TranscoderPreset(Song::FileType type,
const QString& name,
const QString& extension, const QString& extension,
const QString& codec_mimetype, const QString& codec_mimetype,
const QString& muxer_mimetype_ = QString()); const QString& muxer_mimetype_ = QString());
Song::FileType type_;
QString name_; QString name_;
QString extension_; QString extension_;
QString codec_mimetype_; QString codec_mimetype_;
@ -52,8 +54,8 @@ class Transcoder : public QObject {
Transcoder(QObject* parent = 0); Transcoder(QObject* parent = 0);
static TranscoderPreset PresetForFileType(Song::FileType type); static TranscoderPreset PresetForFileType(Song::FileType type);
static QList<TranscoderPreset> GetAllPresets();
QList<TranscoderPreset> presets() const { return presets_; }
int max_threads() const { return max_threads_; } int max_threads() const { return max_threads_; }
void set_max_threads(int count) { max_threads_ = count; } void set_max_threads(int count) { max_threads_ = count; }
@ -132,7 +134,6 @@ class Transcoder : public QObject {
typedef QList<boost::shared_ptr<JobState> > JobStateList; typedef QList<boost::shared_ptr<JobState> > JobStateList;
int max_threads_; int max_threads_;
QList<TranscoderPreset> presets_;
QList<Job> queued_jobs_; QList<Job> queued_jobs_;
JobStateList current_jobs_; JobStateList current_jobs_;
}; };