From b75dc859e059d04544dcd3bb4d58a79cbd32e0be Mon Sep 17 00:00:00 2001 From: Palakis Date: Fri, 2 Jun 2017 14:45:58 +0200 Subject: [PATCH 01/13] preferences: add WIP class for broadcasting profiles --- src/preferences/broadcastprofile.cpp | 445 +++++++++++++++++++++++++++ src/preferences/broadcastprofile.h | 141 +++++++++ 2 files changed, 586 insertions(+) create mode 100644 src/preferences/broadcastprofile.cpp create mode 100644 src/preferences/broadcastprofile.h diff --git a/src/preferences/broadcastprofile.cpp b/src/preferences/broadcastprofile.cpp new file mode 100644 index 000000000000..a879eb28a3e0 --- /dev/null +++ b/src/preferences/broadcastprofile.cpp @@ -0,0 +1,445 @@ +// broadcastprofile.cpp +// Create June 2nd 2017 by Stéphane Lepin + +#include +#include "util/xml.h" + +#include "broadcastprofile.h" + +namespace { +const char* kDocumentName = "BroadcastProfile"; +const char* kBitrate = "bitrate"; +const char* kChannels = "channels"; +const char* kCustomArtist = "custom_artist"; +const char* kCustomTitle = "custom_title"; +const char* kEnableMetadata = "enable_metadata"; +const char* kEnableReconnect = "enable_reconnect"; +const char* kEnabled = "enabled"; +const char* kFormat = "format"; +const char* kHost = "host"; +const char* kLimitReconnects = "limit_reconnects"; +const char* kLogin = "login"; +const char* kMaximumRetries = "maximum_retries"; +const char* kMetadataCharset = "metadata_charset"; +const char* kMetadataFormat = "metadata_format"; +const char* kMountPoint = "mountpoint"; +const char* kNoDelayFirstReconnect = "no_delay_first_reconnect"; +const char* kOggDynamicUpdate = "ogg_dynamicupdate"; +const char* kPassword = "password"; +const char* kPort = "port"; +const char* kReconnectFirstDelay = "reconnect_first_delay"; +const char* kReconnectPeriod = "reconnect_period"; +const char* kServertype = "servertype"; +const char* kStreamDesc = "stream_desc"; +const char* kStreamGenre = "stream_genre"; +const char* kStreamName = "stream_name"; +const char* kStreamPublic = "stream_public"; +const char* kStreamWebsite = "stream_website"; + +const double kDefaultBitrate = 128; +const int kDefaultChannels = 2; +const bool kDefaultEnableMetadata = false; +const bool kDefaultEnableReconnect = true; +const bool kDefaultLimitReconnects = true; +const int kDefaultMaximumRetries = 10; +// No tr() here, see https://bugs.launchpad.net/mixxx/+bug/1419500 +const QString kDefaultMetadataFormat("$artist - $title"); +const bool kDefaultNoDelayFirstReconnect = true; +const bool kDefaultOggDynamicupdate = false; +double kDefaultReconnectFirstDelay = 0.0; +double kDefaultReconnectPeriod = 5.0; +const QString kDefaultStreamDesc = + QObject::tr("This stream is online for testing purposes!"); +const QString kDefaultStreamGenre = QObject::tr("Live Mix"); +const bool kDefaultStreamPublic = false; +} // anonymous namespace + +BroadcastProfile::BroadcastProfile(const QString& profileName) { + // TODO(Palakis, June 2nd 2017): + // Strip forbidden characters from the profile name + m_profileName = QString(profileName); + + // Try to load values from XML file, use default values otherwise + loadValues(); +} + +void BroadcastProfile::getFilename() +{ + return QString("broadcast_profile/") + m_profileName + QString(".bcp.xml"); +} + +void BroadcastProfile::fileExists() { + return QFile::exists(getFilename()); +} + +void BroadcastProfile::deleteFile() { + QFile::remove(getFilename()); +} + +void BroadcastProfile::setDefaultValues() { + m_enabled = true; + + m_host = QString(), + m_port = BROADCAST_DEFAULT_PORT; + m_serverType = QString(); + m_login = QString(); + m_password = QString(); + + m_enableReconnect = kDefaultEnableReconnect; + m_reconnectPeriod = kDefaultReconnectPeriod; + m_limitReconnects = kDefaultLimitReconnects; + + m_mountpoint = QString(); + m_streamDesc = kDefaultStreamDesc; + m_streamGenre = kDefaultStreamGenre; + m_streamName = QString(); + m_streamPublic = kDefaultStreamPublic; + m_streamWebsite = MIXXX_WEBSITE_URL; + + m_enableMetadata = kDefaultEnableMetadata; + m_metadataCharset = QString(); + m_customArtist = QString(); + m_customTitle = QString(); + m_metadataFormat = kDefaultMetadataFormat; + m_oggDynamicUpdate = kDefaultOggDynamicUpdate; + + m_bitrate = kDefaultBitrate; + m_channels = kDefaultChannels; + m_format = QString(); + + m_noDelayFirstReconnect = kDefaultNoDelayFirstReconnect; + m_reconnectFirstDelay = kDefaultReconnectFirstDelay; + m_maximumRetries = kDefaultMaximumRetries; +} + +void BroadcastProfile::loadValues() { + if(!fileExists()) { + setDefaultValues(); + return; + } + + QDomElement xmlRoot = XmlParse::openXMLFile(filename, kDocumentName); + + m_enabled = (bool)XmlParse::selectNodeInt(xmlRoot, kEnabled); + + m_host = XmlParse::selectNodeQString(xmlRoot, kHost); + m_port = XmlParse::selectNodeInt(xmlRoot, kPort); + m_serverType = XmlParse::selectNodeQString(xmlRoot, kServertype); + m_login = XmlParse::selectNodeQString(xmlRoot, kLogin); + m_password = XmlParse::selectNodeQString(xmlRoot, kPassword); + + m_enableReconnect = + (bool)XmlParse::selectNodeInt(xmlRoot, kEnableReconnect); + m_reconnectPeriod = + XmlParse::selectNodeDouble(xmlRoot, kReconnectPeriod); + + m_limitReconnects = + (bool)XmlParse::selectNodeInt(xmlRoot, kLimitReconnects); + m_maximumRetries = + XmlParse::selectNodeInt(xmlRoot, kMaximumRetries); + + m_noDelayFirstReconnect = + (bool)XmlParse::selectNodeInt(xmlRoot, kNoDelayFirstReconnect); + m_reconnectFirstDelay = + XmlParse::selectNodeDouble(xmlRoot, kReconnectFirstDelay); + + m_mountpoint = XmlParse::selectNodeQString(xmlRoot, kMountPoint); + m_streamName = XmlParse::selectNodeQString(xmlRoot, kStreamName); + m_streamDesc = XmlParse::selectNodeQString(xmlRoot, kStreamDesc); + m_streamGenre = XmlParse::selectNodeQString(xmlRoot, kStreamGenre); + m_streamPublic = (bool)XmlParse::selectNodeInt(xmlRoot, kStreamPublic); + m_streamWebsite = XmlParse::selectNodeQString(xmlRoot, kStreamWebsite); + + m_format = XmlParse::selectNodeQString(xmlRoot, kFormat); + m_bitrate = XmlParse::selectNodeInt(xmlRoot, kBitrate); + m_channels = XmlParse::selectNodeInt(xmlRoot, kChannels); + + m_enableMetadata = (bool)XmlParse::selectNodeInt(xmlRoot, kEnableMetadata); + m_metadataCharset = XmlParse::selectNodeQString(xmlRoot, kMetadataCharset); + m_customArtist = XmlParse::selectNodeQString(xmlRoot, kCustomArtist); + m_customTitle = XmlParse::selectNodeQString(xmlRoot, kCustomTitle); + m_metadataFormat = XmlParse::selectNodeQString(xmlRoot, kMetadataFormat); + m_oggDynamicUpdate = + (bool)XmlParse::selectNodeInt(xmlRoot, kMetadataFormat); +} + +void BroadcastProfile::save() { + QDomDocument doc(); + QDomElement docRoot = document.documentElement(); + + XmlParse::addElement(doc, docRoot, kEnabled, (int)m_enabled); + + XmlParse::addElement(doc, docRoot, kHost, m_host); + XmlParse::addElement(doc, docRoot, kPort, m_port); + XmlParse::addElement(doc, docRoot, kServertype, m_serverType); + XmlParse::addElement(doc, docRoot, kLogin, m_login); + XmlParse::addElement(doc, docRoot, kPassword, m_password); + + XmlParse::addElement(doc, docRoot, + kEnableReconnect, (int)m_enableReconnect); + XmlParse::addElement(doc, docRoot, + kReconnectPeriod, m_reconnectPeriod); + + XmlParse::addElement(doc, docRoot, + kLimitReconnects, (int)m_limitReconnects); + XmlParse::addElement(doc, docRoot, + kMaximumRetries, m_maximumRetries); + + XmlParse::addElement(doc, docRoot, + kNoDelayFirstReconnect, (int)m_noDelayFirstReconnect); + XmlParse::addElement(doc, docRoot, + kReconnectFirstDelay, m_reconnectFirstDelay); + + XmlParse::addElement(doc, docRoot, kMountPoint, m_mountpoint); + XmlParse::addElement(doc, docRoot, kStreamName, m_streamName); + XmlParse::addElement(doc, docRoot, kStreamDesc, m_streamDesc); + XmlParse::addElement(doc, docRoot, kStreamGenre, m_streamGenre); + XmlParse::addElement(doc, docRoot, kStreamPublic, (int)m_streamPublic); + XmlParse::addElement(doc, docRoot, kStreamWebsite, m_streamWebsite); + + XmlParse::addElement(doc, docRoot, kFormat, m_format); + XmlParse::addElement(doc, docRoot, kBitrate, m_bitrate); + XmlParse::addElement(doc, docRoot, kChannels, m_channels); + + XmlParse::addElement(doc, docRoot, kEnableMetadata, (int)m_enableMetadata); + XmlParse::addElement(doc, docRoot, kMetadataCharset, m_metadataCharset); + XmlParse::addElement(doc, docRoot, kCustomArtist, m_customArtist); + XmlParse::addElement(doc, docRoot, kCustomTitle, m_customTitle); + XmlParse::addElement(doc, docRoot, kMetadataFormat, m_metadataFormat); + XmlParse::addElement(doc, docRoot, kOggDynamicUpdate, (int)m_oggDynamicUpdate); + + QTextStream xmlFile(getFilename(), QDomNode::EncodingFromTextStream); + xmlFile.setCodec(QTextCodec::codecForName("UTF-8")); + doc.save(xmlFile, 4); +} + +void BroadcastProfile::setProfileName(const QString &profileName) { + m_profileName = QString(profileName); +} + +QString BroadcastProfile::getProfileName() { + return m_profileName; +} + +// Unused, but we keep this to reserve the name +bool BroadcastProfile::getEnabled() const { + return m_enabled; +} + +void BroadcastProfile::setEnabled(bool value) { + m_enabled = value; +} + +QString BroadcastProfile::getHost() const { + return m_host; +} + +void BroadcastProfile::setHost(const QString& value) { + m_host = QString(value); +} + +int BroadcastProfile::getPort() const { + // Valid port numbers are 0 .. 65535 (16 bit unsigned) + if (m_port < 0 || m_port > 0xFFFF) { + return BROADCAST_DEFAULT_PORT; + } + + return m_port; +} + +void BroadcastProfile::setPort(int value) { + m_port = value; +} + +QString BroadcastProfile::getServertype() const { + return m_serverType; +} + +void BroadcastProfile::setServertype(const QString& value) { + m_serverType = QString(value); +} + +QString BroadcastProfile::getLogin() const { + return m_login; +} + +void BroadcastProfile::setLogin(const QString& value) { + m_login = QString(value); +} + +// TODO(Palakis, June 2nd 2017): implement secure password storage +QString BroadcastProfile::getPassword() const { + return m_password; +} + +void BroadcastProfile::setPassword(const QString& value) { + m_password = QString(value); +} + +bool BroadcastProfile::getEnableReconnect() const { + return m_enableReconnect; +} + +void BroadcastProfile::setEnableReconnect(bool value) { + m_enableReconnect = value; +} + +double BroadcastProfile::getReconnectPeriod() const { + return m_reconnectPeriod; +} + +void BroadcastProfile::setReconnectPeriod(double value) { + m_reconnectPeriod = value; +} + +bool BroadcastProfile::getLimitReconnects() const { + return m_limitReconnects; +} + +void BroadcastProfile::setLimitReconnects(bool value) { + m_limitReconnects = value; +} + +int BroadcastProfile::getMaximumRetries() const { + return m_maximumRetries; +} + +void BroadcastProfile::setMaximumRetries(int value) { + m_maximumRetries = value; +} + +bool BroadcastProfile::getNoDelayFirstReconnect() const { + return m_noDelayFirstReconnect; +} + +void BroadcastProfile::setNoDelayFirstReconnect(bool value) { + m_noDelayFirstReconnect = value; +} + +double BroadcastProfile::getReconnectFirstDelay() const { + return m_reconnectFirstDelay; +} + +void BroadcastProfile::setReconnectFirstDelay(double value) { + m_reconnectFirstDelay = value; +} + +QString BroadcastProfile::getMountpoint() const { + return m_mountpoint; +} + +void BroadcastProfile::setMountPoint(const QString& value) { + m_mountpoint = QString(value); +} + +QString BroadcastProfile::getStreamName() const { + return m_streamName; +} + +void BroadcastProfile::setStreamName(const QString& value) { + m_streamName = QString(value); +} + +QString BroadcastProfile::getStreamDesc() const { + return m_streamDesc; +} + +void BroadcastProfile::setStreamDesc(const QString& value) { + m_streamDesc = QString(value); +} + +QString BroadcastProfile::getStreamGenre() const { + return m_streamGenre; +} + +void BroadcastProfile::setStreamGenre(const QString& value) { + m_streamGenre = QString(value); +} + +bool BroadcastProfile::getStreamPublic() const { + return m_streamPublic; +} + +void BroadcastProfile::setStreamPublic(bool value) { + m_streamPublic = value; +} + +QString BroadcastProfile::getStreamWebsite() const { + return m_streamWebsite; +} + +void BroadcastProfile::setStreamWebsite(const QString& value) { + m_streamWebsite = QString(value); +} + +QString BroadcastProfile::getFormat() const { + return m_format; +} + +void BroadcastProfile::setFormat(const QString& value) { + m_format = QString(value); +} + +int BroadcastProfile::getBitrate() const { + return m_bitrate; +} + +void BroadcastProfile::setBitrate(int value) { + m_bitrate = value; +} + +int BroadcastProfile::getChannels() { + return m_channels; +} + +void BroadcastProfile::setChannels(int value) { + m_channels = value; +} + +bool BroadcastProfile::getEnableMetadata() const { + return m_enableMetadata; +} + +void BroadcastProfile::setEnableMetadata(bool value) { + m_enableMetadata = value; +} + +QString BroadcastProfile::getMetadataCharset() const { + return m_metadataCharset; +} + +void BroadcastProfile::setMetadataCharset(const QString& value) { + m_metadataCharset = QString(value); +} + +QString BroadcastProfile::getCustomArtist() const { + return m_customArtist +} + +void BroadcastProfile::setCustomArtist(const QString& value) { + m_customArtist = QString(value); +} + +QString BroadcastProfile::getCustomTitle() const { + return m_customTitle +} + +void BroadcastProfile::setCustomTitle(const QString& value) { + m_customTitle = QString(value); +} + +QString BroadcastProfile::getMetadataFormat() const { + return m_metadataFormat; +} + +void BroadcastProfile::setMetadataFormat(const QString& value) { + m_metadataFormat = QString(value); +} + +bool BroadcastProfile::getOggDynamicUpdate() const { + return m_oggDynamicUpdate; +} + +void BroadcastProfile::setOggDynamicUpdate(bool value) { + m_oggDynamicUpdate = value; +} diff --git a/src/preferences/broadcastprofile.h b/src/preferences/broadcastprofile.h new file mode 100644 index 000000000000..035b23d681c6 --- /dev/null +++ b/src/preferences/broadcastprofile.h @@ -0,0 +1,141 @@ +// broadcastprofile.h +// Created June 2nd 2017 by Stéphane Lepin + +#ifndef BROADCASTPROFILE_H +#define BROADCASTPROFILE_H + +#include + +class BroadcastProfile +{ + public: + explicit BroadcastProfile(const QString& profileName); + void save(); + void deleteFile(); + void setProfileName(const QString& profileName); + QString getProfileName() const; + + bool getEnabled() const; + void setEnabled(bool value); + + QString getHost() const; + void setHost(const QString& value); + + int getPort() const; + void setPort(int value); + + QString getServertype() const; + void setServertype(const QString& value); + + QString getLogin() const; + void setLogin(const QString& value); + + QString getPassword() const; + void setPassword(const QString& value); + + bool getEnableReconnect() const; + void setEnableReconnect(bool value); + + double getReconnectPeriod() const; + void setReconnectPeriod(double value); + + bool getLimitReconnects() const; + void setLimitReconnects(bool value); + + int getMaximumRetries() const; + void setMaximumRetries(int value); + + bool getNoDelayFirstReconnect() const; + void setNoDelayFirstReconnect(bool value); + + double getReconnectFirstDelay() const; + void setReconnectFirstDelay(double value); + + QString getFormat() const; + void setFormat(const QString& value); + + int getBitrate() const; + void setBitrate(int value); + + int getChannels() const; + void setChannels(int value); + + QString getMountpoint() const; + void setMountPoint(const QString& value); + + QString getStreamName() const; + void setStreamName(const QString& value); + + QString getStreamDesc() const; + void setStreamDesc(const QString& value); + + QString getStreamGenre() const; + void setStreamGenre(const QString& value); + + bool getStreamPublic() const; + void setStreamPublic(bool value); + + QString getStreamWebsite() const; + void setStreamWebsite(const QString& value); + + bool getEnableMetadata() const; + void setEnableMetadata(bool value); + + QString getMetadataCharset() const; + void setMetadataCharset(const QString& value); + + QString getCustomArtist() const; + void setCustomArtist(const QString& value); + + QString getCustomTitle() const; + void setCustomTitle(const QString& value); + + QString getMetadataFormat() const; + void setMetadataFormat(const QString& value); + + bool getOggDynamicUpdate() const; + void setOggDynamicUpdate(bool value); + + private: + void setDefaultValues(); + void loadValues(); + QString getFilename(); + bool fileExists(); + + QString m_profileName; + + bool m_enabled; + + QString m_host; + int m_port; + QString m_serverType; + QString m_login; + QString m_password; + + bool m_enableReconnect; + double m_reconnectPeriod; + bool m_limitReconnects; + int m_maximumRetries; + bool m_noDelayFirstReconnect; + double m_reconnectFirstDelay; + + QString m_mountpoint; + QString m_streamName; + QString m_streamDesc; + QString m_streamGenre; + bool m_streamPublic; + QString m_streamWebsite; + + QString m_format; + int m_bitrate; + int m_channels; + + bool m_enableMetadata; + QString m_metadataCharset; + QString m_customArtist; + QString m_customTitle; + QString m_metadataFormat; + bool m_oggDynamicUpdate; +}; + +#endif // BROADCASTPROFILE_H From eb7a29d210a1ebfa119390d1fd2fc9a5463633f3 Mon Sep 17 00:00:00 2001 From: Palakis Date: Fri, 2 Jun 2017 15:16:48 +0200 Subject: [PATCH 02/13] xml profile schema: refactor tag names to SnakeCase --- src/preferences/broadcastprofile.cpp | 54 ++++++++++++++-------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/preferences/broadcastprofile.cpp b/src/preferences/broadcastprofile.cpp index a879eb28a3e0..ba76235f06c9 100644 --- a/src/preferences/broadcastprofile.cpp +++ b/src/preferences/broadcastprofile.cpp @@ -8,33 +8,33 @@ namespace { const char* kDocumentName = "BroadcastProfile"; -const char* kBitrate = "bitrate"; -const char* kChannels = "channels"; -const char* kCustomArtist = "custom_artist"; -const char* kCustomTitle = "custom_title"; -const char* kEnableMetadata = "enable_metadata"; -const char* kEnableReconnect = "enable_reconnect"; -const char* kEnabled = "enabled"; -const char* kFormat = "format"; -const char* kHost = "host"; -const char* kLimitReconnects = "limit_reconnects"; -const char* kLogin = "login"; -const char* kMaximumRetries = "maximum_retries"; -const char* kMetadataCharset = "metadata_charset"; -const char* kMetadataFormat = "metadata_format"; -const char* kMountPoint = "mountpoint"; -const char* kNoDelayFirstReconnect = "no_delay_first_reconnect"; -const char* kOggDynamicUpdate = "ogg_dynamicupdate"; -const char* kPassword = "password"; -const char* kPort = "port"; -const char* kReconnectFirstDelay = "reconnect_first_delay"; -const char* kReconnectPeriod = "reconnect_period"; -const char* kServertype = "servertype"; -const char* kStreamDesc = "stream_desc"; -const char* kStreamGenre = "stream_genre"; -const char* kStreamName = "stream_name"; -const char* kStreamPublic = "stream_public"; -const char* kStreamWebsite = "stream_website"; +const char* kBitrate = "Bitrate"; +const char* kChannels = "Channels"; +const char* kCustomArtist = "CustomArtist"; +const char* kCustomTitle = "CustomTitle"; +const char* kEnableMetadata = "EnableMetadata"; +const char* kEnableReconnect = "EnableReconnect"; +const char* kEnabled = "Enabled"; +const char* kFormat = "Format"; +const char* kHost = "Host"; +const char* kLimitReconnects = "LimitReconnects"; +const char* kLogin = "Login"; +const char* kMaximumRetries = "MaximumRetries"; +const char* kMetadataCharset = "MetadataCharset"; +const char* kMetadataFormat = "MetadataFormat"; +const char* kMountPoint = "Mountpoint"; +const char* kNoDelayFirstReconnect = "NoDelayFirstReconnect"; +const char* kOggDynamicUpdate = "OggDynamicUpdate"; +const char* kPassword = "Password"; +const char* kPort = "Port"; +const char* kReconnectFirstDelay = "ReconnectFirstDelay"; +const char* kReconnectPeriod = "ReconnectPeriod"; +const char* kServertype = "Servertype"; +const char* kStreamDesc = "StreamDesc"; +const char* kStreamGenre = "StreamGenre"; +const char* kStreamName = "StreamName"; +const char* kStreamPublic = "StreamPublic"; +const char* kStreamWebsite = "StreamWebsite"; const double kDefaultBitrate = 128; const int kDefaultChannels = 2; From abc8b813726e4937c3c401495fc0ba778a97aa9f Mon Sep 17 00:00:00 2001 From: Palakis Date: Fri, 2 Jun 2017 23:28:30 +0200 Subject: [PATCH 03/13] Fix errors in BroadcastProfile and make sure it builds I initially forgot to add broadcastprofile.cpp into the list of source files in build/depends.py, so I didn't noticed all the errors and mistakes I've made while writing this earlier. This commit aims to fix these errors and have the BroadcastProfile class to build. --- build/depends.py | 1 + src/preferences/broadcastprofile.cpp | 80 ++++++++++++++++------------ src/preferences/broadcastprofile.h | 3 +- 3 files changed, 49 insertions(+), 35 deletions(-) diff --git a/build/depends.py b/build/depends.py index b66f71c9c56d..3339b7ec6f46 100644 --- a/build/depends.py +++ b/build/depends.py @@ -680,6 +680,7 @@ def sources(self, build): "preferences/settingsmanager.cpp", "preferences/replaygainsettings.cpp", "preferences/broadcastsettings.cpp", + "preferences/broadcastprofile.cpp", "preferences/upgrade.cpp", "preferences/dlgpreferencepage.cpp", diff --git a/src/preferences/broadcastprofile.cpp b/src/preferences/broadcastprofile.cpp index ba76235f06c9..4ef8bc85b574 100644 --- a/src/preferences/broadcastprofile.cpp +++ b/src/preferences/broadcastprofile.cpp @@ -1,8 +1,12 @@ // broadcastprofile.cpp // Create June 2nd 2017 by Stéphane Lepin -#include +#include +#include +#include #include "util/xml.h" +#include "broadcast/defs_broadcast.h" +#include "defs_urls.h" #include "broadcastprofile.h" @@ -63,12 +67,12 @@ BroadcastProfile::BroadcastProfile(const QString& profileName) { loadValues(); } -void BroadcastProfile::getFilename() +QString BroadcastProfile::getFilename() { return QString("broadcast_profile/") + m_profileName + QString(".bcp.xml"); } -void BroadcastProfile::fileExists() { +bool BroadcastProfile::fileExists() { return QFile::exists(getFilename()); } @@ -101,7 +105,7 @@ void BroadcastProfile::setDefaultValues() { m_customArtist = QString(); m_customTitle = QString(); m_metadataFormat = kDefaultMetadataFormat; - m_oggDynamicUpdate = kDefaultOggDynamicUpdate; + m_oggDynamicUpdate = kDefaultOggDynamicupdate; m_bitrate = kDefaultBitrate; m_channels = kDefaultChannels; @@ -118,7 +122,7 @@ void BroadcastProfile::loadValues() { return; } - QDomElement xmlRoot = XmlParse::openXMLFile(filename, kDocumentName); + QDomElement xmlRoot = XmlParse::openXMLFile(getFilename(), kDocumentName); m_enabled = (bool)XmlParse::selectNodeInt(xmlRoot, kEnabled); @@ -164,60 +168,70 @@ void BroadcastProfile::loadValues() { } void BroadcastProfile::save() { - QDomDocument doc(); - QDomElement docRoot = document.documentElement(); + QDomDocument doc(kDocumentName); + QDomElement docRoot = doc.documentElement(); - XmlParse::addElement(doc, docRoot, kEnabled, (int)m_enabled); + XmlParse::addElement(doc, docRoot, + kEnabled, QString::number((int)m_enabled)); XmlParse::addElement(doc, docRoot, kHost, m_host); - XmlParse::addElement(doc, docRoot, kPort, m_port); + XmlParse::addElement(doc, docRoot, kPort, QString::number(m_port)); XmlParse::addElement(doc, docRoot, kServertype, m_serverType); XmlParse::addElement(doc, docRoot, kLogin, m_login); XmlParse::addElement(doc, docRoot, kPassword, m_password); - XmlParse::addElement(doc, docRoot, - kEnableReconnect, (int)m_enableReconnect); - XmlParse::addElement(doc, docRoot, - kReconnectPeriod, m_reconnectPeriod); + XmlParse::addElement(doc, docRoot, kEnableReconnect, + QString::number((int)m_enableReconnect)); + XmlParse::addElement(doc, docRoot, kReconnectPeriod, + QString::number(m_reconnectPeriod)); - XmlParse::addElement(doc, docRoot, - kLimitReconnects, (int)m_limitReconnects); - XmlParse::addElement(doc, docRoot, - kMaximumRetries, m_maximumRetries); + XmlParse::addElement(doc, docRoot, kLimitReconnects, + QString::number((int)m_limitReconnects)); + XmlParse::addElement(doc, docRoot, kMaximumRetries, + QString::number(m_maximumRetries)); - XmlParse::addElement(doc, docRoot, - kNoDelayFirstReconnect, (int)m_noDelayFirstReconnect); - XmlParse::addElement(doc, docRoot, - kReconnectFirstDelay, m_reconnectFirstDelay); + XmlParse::addElement(doc, docRoot, kNoDelayFirstReconnect, + QString::number((int)m_noDelayFirstReconnect)); + XmlParse::addElement(doc, docRoot, kReconnectFirstDelay, + QString::number(m_reconnectFirstDelay)); XmlParse::addElement(doc, docRoot, kMountPoint, m_mountpoint); XmlParse::addElement(doc, docRoot, kStreamName, m_streamName); XmlParse::addElement(doc, docRoot, kStreamDesc, m_streamDesc); XmlParse::addElement(doc, docRoot, kStreamGenre, m_streamGenre); - XmlParse::addElement(doc, docRoot, kStreamPublic, (int)m_streamPublic); + XmlParse::addElement(doc, docRoot, kStreamPublic, + QString::number((int)m_streamPublic)); XmlParse::addElement(doc, docRoot, kStreamWebsite, m_streamWebsite); XmlParse::addElement(doc, docRoot, kFormat, m_format); - XmlParse::addElement(doc, docRoot, kBitrate, m_bitrate); - XmlParse::addElement(doc, docRoot, kChannels, m_channels); + XmlParse::addElement(doc, docRoot, kBitrate, + QString::number(m_bitrate)); + XmlParse::addElement(doc, docRoot, kChannels, + QString::number(m_channels)); - XmlParse::addElement(doc, docRoot, kEnableMetadata, (int)m_enableMetadata); + XmlParse::addElement(doc, docRoot, kEnableMetadata, + QString::number((int)m_enableMetadata)); XmlParse::addElement(doc, docRoot, kMetadataCharset, m_metadataCharset); XmlParse::addElement(doc, docRoot, kCustomArtist, m_customArtist); XmlParse::addElement(doc, docRoot, kCustomTitle, m_customTitle); XmlParse::addElement(doc, docRoot, kMetadataFormat, m_metadataFormat); - XmlParse::addElement(doc, docRoot, kOggDynamicUpdate, (int)m_oggDynamicUpdate); + XmlParse::addElement(doc, docRoot, kOggDynamicUpdate, + QString::number((int)m_oggDynamicUpdate)); + + + QFile xmlFile(getFilename()); + xmlFile.open(QIODevice::WriteOnly | QIODevice::Text); - QTextStream xmlFile(getFilename(), QDomNode::EncodingFromTextStream); - xmlFile.setCodec(QTextCodec::codecForName("UTF-8")); - doc.save(xmlFile, 4); + QTextStream fileStream(&xmlFile); + doc.save(fileStream, 4); + xmlFile.close(); } void BroadcastProfile::setProfileName(const QString &profileName) { m_profileName = QString(profileName); } -QString BroadcastProfile::getProfileName() { +QString BroadcastProfile::getProfileName() const { return m_profileName; } @@ -388,7 +402,7 @@ void BroadcastProfile::setBitrate(int value) { m_bitrate = value; } -int BroadcastProfile::getChannels() { +int BroadcastProfile::getChannels() const { return m_channels; } @@ -413,7 +427,7 @@ void BroadcastProfile::setMetadataCharset(const QString& value) { } QString BroadcastProfile::getCustomArtist() const { - return m_customArtist + return m_customArtist; } void BroadcastProfile::setCustomArtist(const QString& value) { @@ -421,7 +435,7 @@ void BroadcastProfile::setCustomArtist(const QString& value) { } QString BroadcastProfile::getCustomTitle() const { - return m_customTitle + return m_customTitle; } void BroadcastProfile::setCustomTitle(const QString& value) { diff --git a/src/preferences/broadcastprofile.h b/src/preferences/broadcastprofile.h index 035b23d681c6..5534a2210af5 100644 --- a/src/preferences/broadcastprofile.h +++ b/src/preferences/broadcastprofile.h @@ -6,8 +6,7 @@ #include -class BroadcastProfile -{ +class BroadcastProfile { public: explicit BroadcastProfile(const QString& profileName); void save(); From 64499568e881c4b568ea4545fcb4f08240cc67af Mon Sep 17 00:00:00 2001 From: Palakis Date: Fri, 9 Jun 2017 09:10:32 +0200 Subject: [PATCH 04/13] (WIP) BroadcastSettings and BroadcastProfile refactor No idea if this works. I just want to make sure it is saved somewhere out of my computer. I may squash this with other commits later. --- src/encoder/encoderbroadcastsettings.cpp | 49 ++- src/engine/sidechain/enginebroadcast.cpp | 52 +-- src/preferences/broadcastprofile.cpp | 51 ++- src/preferences/broadcastprofile.h | 12 +- src/preferences/broadcastsettings.cpp | 452 ++++---------------- src/preferences/broadcastsettings.h | 96 +---- src/preferences/dialog/dlgprefbroadcast.cpp | 150 ++++--- 7 files changed, 258 insertions(+), 604 deletions(-) diff --git a/src/encoder/encoderbroadcastsettings.cpp b/src/encoder/encoderbroadcastsettings.cpp index 19f861fe52d8..dee0e3ace3ea 100644 --- a/src/encoder/encoderbroadcastsettings.cpp +++ b/src/encoder/encoderbroadcastsettings.cpp @@ -11,8 +11,7 @@ #define DEFAULT_BITRATE 128 EncoderBroadcastSettings::EncoderBroadcastSettings(BroadcastSettings settings) : -m_settings(settings) -{ +m_settings(settings) { m_qualList.append(32); m_qualList.append(48); m_qualList.append(64); @@ -26,41 +25,41 @@ m_settings(settings) m_qualList.append(256); m_qualList.append(320); } -EncoderBroadcastSettings::~EncoderBroadcastSettings() -{ - +EncoderBroadcastSettings::~EncoderBroadcastSettings() { } - -QList EncoderBroadcastSettings::getQualityValues() const -{ +QList EncoderBroadcastSettings::getQualityValues() const { return m_qualList; } // Sets the value -void EncoderBroadcastSettings::setQualityByValue(int qualityValue) -{ +void EncoderBroadcastSettings::setQualityByValue(int qualityValue) { + BroadcastProfile* profile = m_settings.getCurrentProfile(); + if (m_qualList.contains(qualityValue)) { - m_settings.setBitrate(qualityValue); + profile->setBitrate(qualityValue); } else { qWarning() << "Invalid qualityValue given to EncoderBroadcastSettings: " << qualityValue << ". Ignoring it"; } } -void EncoderBroadcastSettings::setQualityByIndex(int qualityIndex) -{ +void EncoderBroadcastSettings::setQualityByIndex(int qualityIndex) { + BroadcastProfile* profile = m_settings.getCurrentProfile(); + if (qualityIndex >= 0 && qualityIndex < m_qualList.size()) { - m_settings.setBitrate(m_qualList.at(qualityIndex)); + profile->setBitrate(m_qualList.at(qualityIndex)); } else { qWarning() << "Invalid qualityIndex given to EncoderBroadcastSettings: " << qualityIndex << ". Ignoring it"; } } -int EncoderBroadcastSettings::getQuality() const -{ - int bitrate = m_settings.getBitrate(); +int EncoderBroadcastSettings::getQuality() const { + BroadcastProfile* profile = + const_cast(m_settings).getCurrentProfile(); + + int bitrate = profile->getBitrate(); if (m_qualList.contains(bitrate)) { return bitrate; } @@ -70,18 +69,22 @@ int EncoderBroadcastSettings::getQuality() const } return DEFAULT_BITRATE; } -int EncoderBroadcastSettings::getQualityIndex() const -{ + +int EncoderBroadcastSettings::getQualityIndex() const { return m_qualList.indexOf(getQuality()); } void EncoderBroadcastSettings::setChannelMode(EncoderSettings::ChannelMode mode) { - m_settings.setChannels(static_cast(mode)); + BroadcastProfile* profile = m_settings.getCurrentProfile(); + profile->setChannels(static_cast(mode)); } -EncoderSettings::ChannelMode EncoderBroadcastSettings::getChannelMode() const -{ - switch(m_settings.getChannels()) { + +EncoderSettings::ChannelMode EncoderBroadcastSettings::getChannelMode() const { + BroadcastProfile* profile = + const_cast(m_settings).getCurrentProfile(); + + switch(profile->getChannels()) { case 1: return EncoderSettings::ChannelMode::MONO; case 2: return EncoderSettings::ChannelMode::STEREO; case 0: // fallthrough diff --git a/src/engine/sidechain/enginebroadcast.cpp b/src/engine/sidechain/enginebroadcast.cpp index b01a2b57e3d1..ddbe26cf9054 100644 --- a/src/engine/sidechain/enginebroadcast.cpp +++ b/src/engine/sidechain/enginebroadcast.cpp @@ -135,6 +135,8 @@ QByteArray EngineBroadcast::encodeString(const QString& string) { } void EngineBroadcast::updateFromPreferences() { + BroadcastProfile* profile = m_settings.getCurrentProfile(); + qDebug() << "EngineBroadcast: updating from preferences"; NetworkStreamWorker::debugState(); @@ -164,7 +166,7 @@ void EngineBroadcast::updateFromPreferences() { // Convert a bunch of QStrings to QByteArrays so we can get regular C char* // strings to pass to libshout. - QString codec = m_settings.getMetadataCharset(); + QString codec = profile->getMetadataCharset(); QByteArray baCodec = codec.toLatin1(); m_pTextCodec = QTextCodec::codecForName(baCodec); if (!m_pTextCodec) { @@ -175,9 +177,9 @@ void EngineBroadcast::updateFromPreferences() { // Indicates our metadata is in the provided charset. shout_metadata_add(m_pShoutMetaData, "charset", baCodec.constData()); - QString serverType = m_settings.getServertype(); + QString serverType = profile->getServertype(); - QString host = m_settings.getHost(); + QString host = profile->getHost(); int start = host.indexOf(QLatin1String("//")); if (start == -1) { // the host part requires preceding //. @@ -187,10 +189,10 @@ void EngineBroadcast::updateFromPreferences() { } QUrl serverUrl = host; - int port = m_settings.getPort(); + int port = profile->getPort(); serverUrl.setPort(port); - QString mountPoint = m_settings.getMountpoint(); + QString mountPoint = profile->getMountpoint(); if (!mountPoint.isEmpty()) { if (!mountPoint.startsWith('/')) { mountPoint.prepend('/'); @@ -198,43 +200,43 @@ void EngineBroadcast::updateFromPreferences() { serverUrl.setPath(mountPoint); } - QString login = m_settings.getLogin(); + QString login = profile->getLogin(); if (!login.isEmpty()) { serverUrl.setUserName(login); } qDebug() << "Using server URL:" << serverUrl; - QByteArray baPassword = m_settings.getPassword().toLatin1(); - QByteArray baFormat = m_settings.getFormat().toLatin1(); - int iBitrate = m_settings.getBitrate(); + QByteArray baPassword = profile->getPassword().toLatin1(); + QByteArray baFormat = profile->getFormat().toLatin1(); + int iBitrate = profile->getBitrate(); // Encode metadata like stream name, website, desc, genre, title/author with // the chosen TextCodec. - QByteArray baStreamName = encodeString(m_settings.getStreamName()); - QByteArray baStreamWebsite = encodeString(m_settings.getStreamWebsite()); - QByteArray baStreamDesc = encodeString(m_settings.getStreamDesc()); - QByteArray baStreamGenre = encodeString(m_settings.getStreamGenre()); + QByteArray baStreamName = encodeString(profile->getStreamName()); + QByteArray baStreamWebsite = encodeString(profile->getStreamWebsite()); + QByteArray baStreamDesc = encodeString(profile->getStreamDesc()); + QByteArray baStreamGenre = encodeString(profile->getStreamGenre()); // Whether the stream is public. - bool streamPublic = m_settings.getStreamPublic(); + bool streamPublic = profile->getStreamPublic(); // Dynamic Ogg metadata update - m_ogg_dynamic_update = m_settings.getOggDynamicUpdate(); + m_ogg_dynamic_update = profile->getOggDynamicUpdate(); - m_custom_metadata = m_settings.getEnableMetadata(); - m_customTitle = m_settings.getCustomTitle(); - m_customArtist = m_settings.getCustomArtist(); + m_custom_metadata = profile->getEnableMetadata(); + m_customTitle = profile->getCustomTitle(); + m_customArtist = profile->getCustomArtist(); - m_metadataFormat = m_settings.getMetadataFormat(); + m_metadataFormat = profile->getMetadataFormat(); - bool enableReconnect = m_settings.getEnableReconnect(); + bool enableReconnect = profile->getEnableReconnect(); if (enableReconnect) { - m_reconnectFirstDelay = m_settings.getReconnectFirstDelay(); - m_reconnectPeriod = m_settings.getReconnectPeriod(); - m_noDelayFirstReconnect = m_settings.getNoDelayFirstReconnect(); - m_limitReconnects = m_settings.getLimitReconnects(); - m_maximumRetries = m_settings.getMaximumRetries(); + m_reconnectFirstDelay = profile->getReconnectFirstDelay(); + m_reconnectPeriod = profile->getReconnectPeriod(); + m_noDelayFirstReconnect = profile->getNoDelayFirstReconnect(); + m_limitReconnects = profile->getLimitReconnects(); + m_maximumRetries = profile->getMaximumRetries(); } else { m_limitReconnects = true; m_maximumRetries = 0; diff --git a/src/preferences/broadcastprofile.cpp b/src/preferences/broadcastprofile.cpp index 4ef8bc85b574..135f41caae64 100644 --- a/src/preferences/broadcastprofile.cpp +++ b/src/preferences/broadcastprofile.cpp @@ -1,8 +1,10 @@ // broadcastprofile.cpp -// Create June 2nd 2017 by Stéphane Lepin +// Created June 2nd 2017 by Stéphane Lepin #include +#include #include +#include #include #include "util/xml.h" #include "broadcast/defs_broadcast.h" @@ -56,31 +58,32 @@ const QString kDefaultStreamDesc = QObject::tr("This stream is online for testing purposes!"); const QString kDefaultStreamGenre = QObject::tr("Live Mix"); const bool kDefaultStreamPublic = false; +const QRegExp kForbiddenChars = QRegExp("[<>:\"/\\\|\?\*]"); } // anonymous namespace BroadcastProfile::BroadcastProfile(const QString& profileName) { - // TODO(Palakis, June 2nd 2017): - // Strip forbidden characters from the profile name - m_profileName = QString(profileName); - - // Try to load values from XML file, use default values otherwise - loadValues(); + defaultValues(); + setProfileName(profileName); } -QString BroadcastProfile::getFilename() -{ - return QString("broadcast_profile/") + m_profileName + QString(".bcp.xml"); +bool BroadcastProfile::checkNameCompliance(const QString& str) { + return str.contains(kForbiddenChars); } -bool BroadcastProfile::fileExists() { - return QFile::exists(getFilename()); -} +BroadcastProfile* BroadcastProfile::loadFromFile(const QString& filename) { + QFileInfo xmlFile(filename); + if(!xmlFile.exists()) + return nullptr; -void BroadcastProfile::deleteFile() { - QFile::remove(getFilename()); + QString profileName = xmlFile.baseName(); + + BroadcastProfile* profile = new BroadcastProfile(profileName); + profile->loadValues(filename); + + return profile; } -void BroadcastProfile::setDefaultValues() { +void BroadcastProfile::defaultValues() { m_enabled = true; m_host = QString(), @@ -116,13 +119,13 @@ void BroadcastProfile::setDefaultValues() { m_maximumRetries = kDefaultMaximumRetries; } -void BroadcastProfile::loadValues() { - if(!fileExists()) { +void BroadcastProfile::loadValues(const QString& filename) { + if(!QFile::exists(filename)) { setDefaultValues(); return; } - QDomElement xmlRoot = XmlParse::openXMLFile(getFilename(), kDocumentName); + QDomElement xmlRoot = XmlParse::openXMLFile(filename, kDocumentName); m_enabled = (bool)XmlParse::selectNodeInt(xmlRoot, kEnabled); @@ -167,7 +170,7 @@ void BroadcastProfile::loadValues() { (bool)XmlParse::selectNodeInt(xmlRoot, kMetadataFormat); } -void BroadcastProfile::save() { +void BroadcastProfile::save(const QString& filename) { QDomDocument doc(kDocumentName); QDomElement docRoot = doc.documentElement(); @@ -219,7 +222,7 @@ void BroadcastProfile::save() { QString::number((int)m_oggDynamicUpdate)); - QFile xmlFile(getFilename()); + QFile xmlFile(filename); xmlFile.open(QIODevice::WriteOnly | QIODevice::Text); QTextStream fileStream(&xmlFile); @@ -229,13 +232,17 @@ void BroadcastProfile::save() { void BroadcastProfile::setProfileName(const QString &profileName) { m_profileName = QString(profileName); + + // Replace occurences of forbidden characters with a space + // to avoid problems with the underlying filesystem. + // Char list comes from MSDN article "Naming Files, Paths, and Namespaces". + m_profileName.replace(kForbiddenChars, " "); } QString BroadcastProfile::getProfileName() const { return m_profileName; } -// Unused, but we keep this to reserve the name bool BroadcastProfile::getEnabled() const { return m_enabled; } diff --git a/src/preferences/broadcastprofile.h b/src/preferences/broadcastprofile.h index 5534a2210af5..88366edece8f 100644 --- a/src/preferences/broadcastprofile.h +++ b/src/preferences/broadcastprofile.h @@ -9,8 +9,11 @@ class BroadcastProfile { public: explicit BroadcastProfile(const QString& profileName); - void save(); - void deleteFile(); + void save(const QString& filename); + + static BroadcastProfile* BroadcastProfile::loadFromFile(const QString& filename); + static bool BroadcastProfile::checkNameCompliance(const QString& str); + void setProfileName(const QString& profileName); QString getProfileName() const; @@ -97,9 +100,8 @@ class BroadcastProfile { private: void setDefaultValues(); - void loadValues(); - QString getFilename(); - bool fileExists(); + void loadValues(const QString& filename); + void defaultValues(); QString m_profileName; diff --git a/src/preferences/broadcastsettings.cpp b/src/preferences/broadcastsettings.cpp index 8f2185596d39..68ba156309b3 100644 --- a/src/preferences/broadcastsettings.cpp +++ b/src/preferences/broadcastsettings.cpp @@ -1,417 +1,113 @@ +#include +#include +#include +#include + #include "preferences/broadcastsettings.h" #include "broadcast/defs_broadcast.h" #include "defs_urls.h" namespace { const char* kConfigKey = "[Shoutcast]"; - -const char* kBitrate = "bitrate"; -const char* kChannels = "channels"; -const char* kCustomArtist = "custom_artist"; -const char* kCustomTitle = "custom_title"; -const char* kEnableMetadata = "enable_metadata"; -const char* kEnableReconnect = "enable_reconnect"; -const char* kEnabled = "enabled"; -const char* kFormat = "format"; -const char* kHost = "host"; -const char* kLimitReconnects = "limit_reconnects"; -const char* kLogin = "login"; -const char* kMaximumRetries = "maximum_retries"; -const char* kMetadataCharset = "metadata_charset"; -const char* kMetadataFormat = "metadata_format"; -const char* kMountPoint = "mountpoint"; -const char* kNoDelayFirstReconnect = "no_delay_first_reconnect"; -const char* kOggDynamicUpdate = "ogg_dynamicupdate"; -const char* kPassword = "password"; -const char* kPort = "port"; -const char* kReconnectFirstDelay = "reconnect_first_delay"; -const char* kReconnectPeriod = "reconnect_period"; -const char* kServertype = "servertype"; -const char* kStreamDesc = "stream_desc"; -const char* kStreamGenre = "stream_genre"; -const char* kStreamName = "stream_name"; -const char* kStreamPublic = "stream_public"; -const char* kStreamWebsite = "stream_website"; - -const double kDefaultBitrate = 128; -const int kDefaultChannels = 2; -const bool kDefaultEnableMetadata = false; -const bool kDefaultEnableReconnect = true; -const bool kDefaultLimitReconnects = true; -const int kDefaultMaximumRetries = 10; -// No tr() here, see https://bugs.launchpad.net/mixxx/+bug/1419500 -const QString kDefaultMetadataFormat("$artist - $title"); -const bool kDefaultNoDelayFirstReconnect = true; -const bool kDefaultOggDynamicupdate = false; -double kDefaultReconnectFirstDelay = 0.0; -double kDefaultReconnectPeriod = 5.0; -const QString kDefaultStreamDesc = QObject::tr("This stream is online for testing purposes!"); -const QString kDefaultStreamGenre = QObject::tr("Live Mix"); -const bool kDefaultStreamPublic = false; +const char* kCurrentProfile = "current_profile"; +const char* kProfilesSubfolder = "broadcast_profiles"; +const char* kDefaultProfile = "Default Profile"; } // anonymous namespace BroadcastSettings::BroadcastSettings(UserSettingsPointer pConfig) - : m_pConfig(pConfig) { -} - -int BroadcastSettings::getBitrate() const { - return m_pConfig->getValue( - ConfigKey(kConfigKey, kBitrate), getDefaultBitrate()); -} - -void BroadcastSettings::setBitrate(int value) { - m_pConfig->setValue(ConfigKey(kConfigKey, kBitrate), value); -} - -int BroadcastSettings::getDefaultBitrate() const { - return kDefaultBitrate; -} - -int BroadcastSettings::getChannels() const { - return m_pConfig->getValue( - ConfigKey(kConfigKey, kChannels), getDefaultChannels()); -} - -void BroadcastSettings::setChannels(int value) { - m_pConfig->setValue(ConfigKey(kConfigKey, kChannels), value); -} - -int BroadcastSettings::getDefaultChannels() const { - return kDefaultChannels; -} - -QString BroadcastSettings::getCustomArtist() const { - return m_pConfig->getValue( - ConfigKey(kConfigKey, kCustomArtist), getDefaultCustomArtist()); - -} - -void BroadcastSettings::setCustomArtist(const QString& value) { - m_pConfig->setValue(ConfigKey(kConfigKey, kCustomArtist), value); -} - -QString BroadcastSettings::getDefaultCustomArtist() const { - return QString(); -} - -QString BroadcastSettings::getCustomTitle() const { - return m_pConfig->getValue( - ConfigKey(kConfigKey, kCustomTitle), getDefaultCustomTitle()); -} - -void BroadcastSettings::setCustomTitle(const QString& value) { - m_pConfig->setValue(ConfigKey(kConfigKey, kCustomTitle), value); -} - -QString BroadcastSettings::getDefaultCustomTitle() const { - return QString(); -} - -bool BroadcastSettings::getEnableMetadata() const { - return m_pConfig->getValue( - ConfigKey(kConfigKey, kEnableMetadata), getDefaultEnableMetadata()); -} - -void BroadcastSettings::setEnableMetadata(bool value) { - m_pConfig->setValue(ConfigKey(kConfigKey, kEnableMetadata), value); -} - -bool BroadcastSettings::getDefaultEnableMetadata() const { - return kDefaultEnableMetadata; -} - -bool BroadcastSettings::getEnableReconnect() const { - return m_pConfig->getValue( - ConfigKey(kConfigKey, kEnableReconnect), getDefaultEnableReconnect()); -} - -void BroadcastSettings::setEnableReconnect(bool value) { - m_pConfig->setValue(ConfigKey(kConfigKey, kEnableReconnect), value); -} - -bool BroadcastSettings::getDefaultEnableReconnect() const { - return kDefaultEnableReconnect; -} - -// Unused, but we keep this to reserve the name -bool BroadcastSettings::getEnabled() const { - return m_pConfig->getValue( - ConfigKey(kConfigKey, kEnabled), true); -} - -void BroadcastSettings::setEnabled(bool value) { - m_pConfig->setValue(ConfigKey(kConfigKey, kEnabled), value); -} - -QString BroadcastSettings::getFormat() const { - return m_pConfig->getValue( - ConfigKey(kConfigKey, kFormat), getDefaultFormat()); -} - -void BroadcastSettings::setFormat(const QString& value) { - m_pConfig->setValue(ConfigKey(kConfigKey, kFormat), value); -} - -QString BroadcastSettings::getDefaultFormat() const { - return QString(); -} - -QString BroadcastSettings::getHost() const { - return m_pConfig->getValue( - ConfigKey(kConfigKey, kHost), getDefaultHost()); -} - -void BroadcastSettings::setHost(const QString& value) { - m_pConfig->setValue(ConfigKey(kConfigKey, kHost), value); -} - -QString BroadcastSettings::getDefaultHost() const { - return QString(); -} - -bool BroadcastSettings::getLimitReconnects() const { - return m_pConfig->getValue( - ConfigKey(kConfigKey, kLimitReconnects), getDefaultLimitReconnects()); -} - -void BroadcastSettings::setLimitReconnects(bool value) { - m_pConfig->setValue(ConfigKey(kConfigKey, kLimitReconnects), value); -} - -bool BroadcastSettings::getDefaultLimitReconnects() const { - return kDefaultLimitReconnects; -} - -QString BroadcastSettings::getLogin() const { - return m_pConfig->getValue( - ConfigKey(kConfigKey, kLogin), getDefaultLogin()); -} - -void BroadcastSettings::setLogin(const QString& value) { - m_pConfig->setValue(ConfigKey(kConfigKey, kLogin), value); -} - -QString BroadcastSettings::getDefaultLogin() const { - return QString(); -} - -int BroadcastSettings::getMaximumRetries() const { - return m_pConfig->getValue( - ConfigKey(kConfigKey, kMaximumRetries), getDefaultMaximumRetries()); + : m_pConfig(pConfig), + m_profiles(), + m_currentProfile(kDefaultProfile) { + loadProfiles(); } -void BroadcastSettings::setMaximumRetries(int value) { - m_pConfig->setValue(ConfigKey(kConfigKey, kMaximumRetries), value); -} - -int BroadcastSettings::getDefaultMaximumRetries() const { - return kDefaultMaximumRetries; -} - -QString BroadcastSettings::getMetadataCharset() const { - return m_pConfig->getValue( - ConfigKey(kConfigKey, kMetadataCharset)); -} - -void BroadcastSettings::setMetadataCharset(const QString& value) { - m_pConfig->setValue(ConfigKey(kConfigKey, kMetadataCharset), value); -} - -QString BroadcastSettings::getDefaultMetadataCharset() const { - return QString(); -} - -QString BroadcastSettings::getMetadataFormat() const { - return m_pConfig->getValue( - ConfigKey(kConfigKey, kMetadataFormat), getDefaultMetadataFormat()); -} - -void BroadcastSettings::setMetadataFormat(const QString& value) { - m_pConfig->setValue(ConfigKey(kConfigKey, kMetadataFormat), value); -} - -QString BroadcastSettings::getDefaultMetadataFormat() const { - return kDefaultMetadataFormat; -} - -QString BroadcastSettings::getMountpoint() const { - return m_pConfig->getValue( - ConfigKey(kConfigKey, kMountPoint)); -} - -void BroadcastSettings::setMountPoint(const QString& value) { - m_pConfig->setValue(ConfigKey(kConfigKey, kMountPoint), value); -} - -QString BroadcastSettings::getDefaultMountpoint() const { - return QString(); -} - -bool BroadcastSettings::getNoDelayFirstReconnect() const { - return m_pConfig->getValue( - ConfigKey(kConfigKey, kNoDelayFirstReconnect), - getDefaultNoDelayFirstReconnect()); -} - -void BroadcastSettings::setNoDelayFirstReconnect(bool value) { - m_pConfig->setValue(ConfigKey(kConfigKey, kNoDelayFirstReconnect), value); -} - -bool BroadcastSettings::getDefaultNoDelayFirstReconnect() const { - return kDefaultNoDelayFirstReconnect; -} - -bool BroadcastSettings::getOggDynamicUpdate() const { - return m_pConfig->getValue( - ConfigKey(kConfigKey, kOggDynamicUpdate), - getDefaultOggDynamicUpdate()); -} - -void BroadcastSettings::setOggDynamicUpdate(bool value) { - m_pConfig->setValue(ConfigKey(kConfigKey, kOggDynamicUpdate), value); -} - -bool BroadcastSettings::getDefaultOggDynamicUpdate() const { - return kDefaultOggDynamicupdate; -} - -QString BroadcastSettings::getPassword() const { - return m_pConfig->getValue( - ConfigKey(kConfigKey, kPassword), getDefaultPassword()); -} - -void BroadcastSettings::setPassword(const QString& value) { - m_pConfig->setValue(ConfigKey(kConfigKey, kPassword), value); -} - -QString BroadcastSettings::getDefaultPassword() const { - return QString(); -} - -int BroadcastSettings::getPort() const { - // Valid port numbers are 0 .. 65535 (16 bit unsigned) - int port = m_pConfig->getValue( - ConfigKey(kConfigKey, kPort), getDefaultPort()); - if (port < 0 || port > 0xFFFF) { - return getDefaultPort(); +BroadcastSettings::~BroadcastSettings() { + for(BroadcastProfile* profile : m_profiles) { + delete profile; } - return port; -} - -void BroadcastSettings::setPort(int value) { - m_pConfig->setValue(ConfigKey(kConfigKey, kPort), value); -} - -int BroadcastSettings::getDefaultPort() const { - return BROADCAST_DEFAULT_PORT; } -double BroadcastSettings::getReconnectFirstDelay() const { - return m_pConfig->getValue( - ConfigKey(kConfigKey, kReconnectFirstDelay), - getDefaultReconnectFirstDelay()); -} - -void BroadcastSettings::setReconnectFirstDelay(double value) { - m_pConfig->setValue(ConfigKey(kConfigKey, kReconnectFirstDelay), value); -} - -double BroadcastSettings::getDefaultReconnectFirstDelay() const { - return kDefaultReconnectFirstDelay; -} - -double BroadcastSettings::getReconnectPeriod() const { - return m_pConfig->getValue( - ConfigKey(kConfigKey, kReconnectPeriod), - getDefaultReconnectPeriod()); -} - -void BroadcastSettings::setReconnectPeriod(double value) { - m_pConfig->setValue(ConfigKey(kConfigKey, kReconnectPeriod), value); -} +void BroadcastSettings::loadProfiles() { + QDir profilesFolder(m_pConfig->getSettingsPath()); + bool folderCreated = profilesFolder.mkdir(kProfilesSubfolder); + profilesFolder.cd(kProfilesSubfolder); -double BroadcastSettings::getDefaultReconnectPeriod() const { - return kDefaultReconnectPeriod; -} + if(folderCreated) { + BroadcastProfile* defaultProfile = + new BroadcastProfile(kDefaultProfile); + saveProfile(defaultProfile); + setCurrentProfile(defaultProfile); + } -QString BroadcastSettings::getServertype() const { - return m_pConfig->getValue( - ConfigKey(kConfigKey, kServertype), getDefaultServertype()); -} + QStringList nameFilters("*.bcp.xml"); + QFileInfoList files = + profilesFolder.entryInfoList(nameFilters, QDir::Files, QDir::Name); -void BroadcastSettings::setServertype(const QString& value) { - m_pConfig->set(ConfigKey(kConfigKey, kServertype), - ConfigValue(value)); -} + for(QFileInfo fileInfo : files) { + BroadcastProfile* profile = + BroadcastProfile::loadFromFile(fileInfo.absoluteFilePath()); -QString BroadcastSettings::getDefaultServertype() const { - return QString(); + if(profile) + m_profiles.push_back(profile); + } } -QString BroadcastSettings::getStreamDesc() const { - return m_pConfig->getValue( - ConfigKey(kConfigKey, kStreamDesc), - getDefaultStreamDesc()); -} +void BroadcastSettings::saveProfile(BroadcastProfile* profile) { + if(!profile) + return; -void BroadcastSettings::setStreamDesc(const QString& value) { - m_pConfig->setValue(ConfigKey(kConfigKey, kStreamDesc), value); + profile->save(filenameForProfile(profile)); } -QString BroadcastSettings::getDefaultStreamDesc() const { - return kDefaultStreamDesc; -} +QString BroadcastSettings::filenameForProfile(BroadcastProfile* profile) { + if(!profile) + return QString(); -QString BroadcastSettings::getStreamGenre() const { - return m_pConfig->getValue( - ConfigKey(kConfigKey, kStreamGenre), - getDefaultStreamGenre()); -} + QDir profilesFolder(m_pConfig->getSettingsPath()); + profilesFolder.cd(kProfilesSubfolder); -void BroadcastSettings::setStreamGenre(const QString& value) { - m_pConfig->setValue(ConfigKey(kConfigKey, kStreamGenre), value); + QString filename = profile->getProfileName() + QString(".bcp.xml"); + return profilesFolder.absoluteFilePath(filename); } -QString BroadcastSettings::getDefaultStreamGenre() const { - return kDefaultStreamGenre; -} +void BroadcastSettings::setCurrentProfile(BroadcastProfile *profile) { + if(!profile) + return; -QString BroadcastSettings::getStreamName() const { - return m_pConfig->getValue( - ConfigKey(kConfigKey, kStreamName), - getDefaultStreamName()); + QString profileName = profile->getProfileName(); + m_pConfig->setValue(ConfigKey(kConfigKey, kCurrentProfile), profileName); } -void BroadcastSettings::setStreamName(const QString& value) { - m_pConfig->setValue(ConfigKey(kConfigKey, kStreamName), value); +BroadcastProfile* BroadcastSettings::getCurrentProfile() { + QString currentProfile = m_pConfig->getValue( + ConfigKey(kConfigKey, kCurrentProfile), + kDefaultProfile); + return getProfileByName(currentProfile); } -QString BroadcastSettings::getDefaultStreamName() const { - return QString(); -} - -bool BroadcastSettings::getStreamPublic() const { - return m_pConfig->getValue( - ConfigKey(kConfigKey, kStreamPublic), getDefaultStreamPublic()); -} - -void BroadcastSettings::setStreamPublic(bool value) { - m_pConfig->setValue(ConfigKey(kConfigKey, kStreamPublic), value); +BroadcastProfile* BroadcastSettings::getProfileByName(const QString& profileName) { + for(BroadcastProfile* profile : m_profiles) { + if(profile && profile->getProfileName() == profileName) + return profile; + } + return nullptr; } -bool BroadcastSettings::getDefaultStreamPublic() const { - return kDefaultStreamPublic; +void BroadcastSettings::saveAll() { + for(BroadcastProfile* profile : m_profiles) { + if(profile) + saveProfile(profile); + } } -QString BroadcastSettings::getStreamWebsite() const { - return m_pConfig->getValue( - ConfigKey(kConfigKey, kStreamWebsite), getDefaultStreamWebsite()); -} +void BroadcastSettings::deleteProfile(BroadcastProfile* profile) +{ + if(!profile) + return; -void BroadcastSettings::setStreamWebsite(const QString& value) { - m_pConfig->setValue(ConfigKey(kConfigKey, kStreamWebsite), value); -} + QFileInfo xmlFile(filenameForProfile(profile)); + if(xmlFile.exists()) + QFile::remove(xmlFile.absolutePath()); -QString BroadcastSettings::getDefaultStreamWebsite() const { - return MIXXX_WEBSITE_URL; + m_profiles.removeAll(profile); } diff --git a/src/preferences/broadcastsettings.h b/src/preferences/broadcastsettings.h index 9c759bed5b3a..baa3d66b749c 100644 --- a/src/preferences/broadcastsettings.h +++ b/src/preferences/broadcastsettings.h @@ -1,97 +1,33 @@ #ifndef PREFERENCES_BROADCASTSETTINGS_H #define PREFERENCES_BROADCASTSETTINGS_H +#include +#include + #include "preferences/usersettings.h" #include "track/track.h" +#include "broadcastprofile.h" class BroadcastSettings { public: BroadcastSettings(UserSettingsPointer pConfig); + ~BroadcastSettings(); - int getBitrate() const; - void setBitrate(int value); - int getDefaultBitrate() const; - int getChannels() const; - void setChannels(int value); - int getDefaultChannels() const; - QString getCustomArtist() const; - void setCustomArtist(const QString& value); - QString getDefaultCustomArtist() const; - QString getCustomTitle() const; - void setCustomTitle(const QString& value); - QString getDefaultCustomTitle() const; - bool getEnableMetadata() const; - void setEnableMetadata(bool value); - bool getDefaultEnableMetadata() const; - bool getEnableReconnect() const; - void setEnableReconnect(bool value); - bool getDefaultEnableReconnect() const; - bool getEnabled() const; - void setEnabled(bool value); - QString getFormat() const; - void setFormat(const QString& value); - QString getDefaultFormat() const; - QString getHost() const; - void setHost(const QString& value); - QString getDefaultHost() const; - bool getLimitReconnects() const; - void setLimitReconnects(bool value); - bool getDefaultLimitReconnects() const; - QString getLogin() const; - void setLogin(const QString& value); - QString getDefaultLogin() const; - int getMaximumRetries() const; - void setMaximumRetries(int value); - int getDefaultMaximumRetries() const; - QString getMetadataCharset() const; - void setMetadataCharset(const QString& value); - QString getDefaultMetadataCharset() const; - QString getMetadataFormat() const; - void setMetadataFormat(const QString& value); - QString getDefaultMetadataFormat() const; - QString getMountpoint() const; - void setMountPoint(const QString& value); - QString getDefaultMountpoint() const; - bool getNoDelayFirstReconnect() const; - void setNoDelayFirstReconnect(bool value); - bool getDefaultNoDelayFirstReconnect() const; - bool getOggDynamicUpdate() const; - void setOggDynamicUpdate(bool value); - bool getDefaultOggDynamicUpdate() const; - QString getPassword() const; - void setPassword(const QString& value); - QString getDefaultPassword() const; - int getPort() const; - void setPort(int value); - int getDefaultPort() const; - double getReconnectFirstDelay() const; - void setReconnectFirstDelay(double value); - double getDefaultReconnectFirstDelay() const; - double getReconnectPeriod() const; - void setReconnectPeriod(double value); - double getDefaultReconnectPeriod() const; - QString getServertype() const; - void setServertype(const QString& value); - QString getDefaultServertype() const; - QString getStreamDesc() const; - void setStreamDesc(const QString& value); - QString getDefaultStreamDesc() const; - QString getStreamGenre() const; - void setStreamGenre(const QString& value); - QString getDefaultStreamGenre() const; - QString getStreamName() const; - void setStreamName(const QString& value); - QString getDefaultStreamName() const; - bool getStreamPublic() const; - void setStreamPublic(bool value); - bool getDefaultStreamPublic() const; - QString getStreamWebsite() const; - void setStreamWebsite(const QString& value); - QString getDefaultStreamWebsite() const; + void setCurrentProfile(BroadcastProfile* profile); + BroadcastProfile* getCurrentProfile(); + BroadcastProfile* getProfileByName(const QString& profileName); + void deleteProfile(BroadcastProfile* profile); + void saveAll(); private: + void loadProfiles(); + void saveProfile(BroadcastProfile* profile); + QString filenameForProfile(BroadcastProfile* profile); + // Pointer to config object UserSettingsPointer m_pConfig; + QList m_profiles; + QString m_currentProfile; }; #endif /* PREFERENCES_BROADCASTSETTINGS_H */ diff --git a/src/preferences/dialog/dlgprefbroadcast.cpp b/src/preferences/dialog/dlgprefbroadcast.cpp index f22c03c1b4f0..9ca1b53b418a 100644 --- a/src/preferences/dialog/dlgprefbroadcast.cpp +++ b/src/preferences/dialog/dlgprefbroadcast.cpp @@ -11,6 +11,8 @@ DlgPrefBroadcast::DlgPrefBroadcast(QWidget *parent, UserSettingsPointer _config) m_settings(_config) { setupUi(this); + BroadcastProfile* profile = m_settings.getCurrentProfile(); + m_pBroadcastEnabled = new ControlProxy( BROADCAST_PREF_KEY, "enabled", this); m_pBroadcastEnabled->connectValueChanged( @@ -26,31 +28,31 @@ DlgPrefBroadcast::DlgPrefBroadcast(QWidget *parent, UserSettingsPointer _config) comboBoxServerType->addItem(tr("Shoutcast 1"), BROADCAST_SERVER_SHOUTCAST); comboBoxServerType->addItem(tr("Icecast 1"), BROADCAST_SERVER_ICECAST1); - int tmp_index = comboBoxServerType->findData(m_settings.getServertype()); + int tmp_index = comboBoxServerType->findData(profile->getServertype()); if (tmp_index < 0) { // Set default if invalid. tmp_index = 0; } comboBoxServerType->setCurrentIndex(tmp_index); // Mountpoint - mountpoint->setText(m_settings.getMountpoint()); + mountpoint->setText(profile->getMountpoint()); // Host - host->setText(m_settings.getHost()); + host->setText(profile->getHost()); // Port - QString portString = QString::number(m_settings.getPort()); + QString portString = QString::number(profile->getPort()); port->setText(portString); // Login - login->setText(m_settings.getLogin()); + login->setText(profile->getLogin()); // Password - password->setText(m_settings.getPassword()); + password->setText(profile->getPassword()); // Enable automatic reconnect - bool enableReconnect = m_settings.getEnableReconnect(); + bool enableReconnect = profile->getEnableReconnect(); checkBoxEnableReconnect->setChecked(enableReconnect); widgetReconnectControls->setEnabled(enableReconnect); connect(checkBoxEnableReconnect, SIGNAL(stateChanged(int)), @@ -58,13 +60,13 @@ DlgPrefBroadcast::DlgPrefBroadcast(QWidget *parent, UserSettingsPointer _config) // Wait until first attempt - spinBoxFirstDelay->setValue(m_settings.getReconnectFirstDelay()); + spinBoxFirstDelay->setValue(profile->getReconnectFirstDelay()); // Retry Delay - spinBoxReconnectPeriod->setValue(m_settings.getReconnectPeriod()); + spinBoxReconnectPeriod->setValue(profile->getReconnectPeriod()); // Use Maximum Retries - bool limitConnects = m_settings.getLimitReconnects(); + bool limitConnects = profile->getLimitReconnects(); checkBoxLimitReconnects->setChecked( limitConnects); spinBoxMaximumRetries->setEnabled(limitConnects); @@ -72,23 +74,23 @@ DlgPrefBroadcast::DlgPrefBroadcast(QWidget *parent, UserSettingsPointer _config) this, SLOT(checkBoxLimitReconnectsChanged(int))); // Maximum Retries - spinBoxMaximumRetries->setValue(m_settings.getMaximumRetries()); + spinBoxMaximumRetries->setValue(profile->getMaximumRetries()); // Stream "public" checkbox - stream_public->setChecked(m_settings.getStreamPublic()); + stream_public->setChecked(profile->getStreamPublic()); // Stream name - stream_name->setText(m_settings.getStreamName()); + stream_name->setText(profile->getStreamName()); // Stream website - stream_website->setText(m_settings.getStreamWebsite()); + stream_website->setText(profile->getStreamWebsite()); // Stream description - stream_desc->setText(m_settings.getStreamDesc()); + stream_desc->setText(profile->getStreamDesc()); // Stream genre - stream_genre->setText(m_settings.getStreamGenre()); + stream_genre->setText(profile->getStreamGenre()); // Encoding bitrate combobox QString kbps_pattern = QString("%1 kbps"); @@ -110,7 +112,7 @@ DlgPrefBroadcast::DlgPrefBroadcast(QWidget *parent, UserSettingsPointer _config) kbps_pattern.arg(QString::number(kbps)), kbps); } - tmp_index = comboBoxEncodingBitrate->findData(m_settings.getBitrate()); + tmp_index = comboBoxEncodingBitrate->findData(profile->getBitrate()); if (tmp_index < 0) { tmp_index = comboBoxEncodingBitrate->findData(BROADCAST_BITRATE_128KBPS); } @@ -119,7 +121,7 @@ DlgPrefBroadcast::DlgPrefBroadcast(QWidget *parent, UserSettingsPointer _config) // Encoding format combobox comboBoxEncodingFormat->addItem(tr("MP3"), BROADCAST_FORMAT_MP3); comboBoxEncodingFormat->addItem(tr("Ogg Vorbis"), BROADCAST_FORMAT_OV); - tmp_index = comboBoxEncodingFormat->findData(m_settings.getFormat()); + tmp_index = comboBoxEncodingFormat->findData(profile->getFormat()); if (tmp_index < 0) { // Set default of MP3 if invalid. tmp_index = 0; @@ -133,23 +135,23 @@ DlgPrefBroadcast::DlgPrefBroadcast(QWidget *parent, UserSettingsPointer _config) static_cast(EncoderSettings::ChannelMode::MONO)); comboBoxEncodingChannels->addItem(tr("Stereo"), static_cast(EncoderSettings::ChannelMode::STEREO)); - tmp_index = comboBoxEncodingChannels->findData(m_settings.getChannels()); + tmp_index = comboBoxEncodingChannels->findData(profile->getChannels()); if (tmp_index < 0) { // Set default to automatic if invalid. tmp_index = 0; } comboBoxEncodingChannels->setCurrentIndex(tmp_index); // Metadata format - metadata_format->setText(m_settings.getMetadataFormat()); + metadata_format->setText(profile->getMetadataFormat()); // Static artist - custom_artist->setText(m_settings.getCustomArtist()); + custom_artist->setText(profile->getCustomArtist()); // Static title - custom_title->setText(m_settings.getCustomTitle()); + custom_title->setText(profile->getCustomTitle()); // "Enable static artist and title" checkbox - bool enableMetadata = m_settings.getEnableMetadata(); + bool enableMetadata = profile->getEnableMetadata(); enableCustomMetadata->setChecked(enableMetadata); custom_artist->setEnabled(enableMetadata); custom_title->setEnabled(enableMetadata); @@ -158,11 +160,11 @@ DlgPrefBroadcast::DlgPrefBroadcast(QWidget *parent, UserSettingsPointer _config) // "Enable UTF-8 metadata" checkbox // TODO(rryan): allow arbitrary codecs in the future? - QString charset = m_settings.getMetadataCharset(); + QString charset = profile->getMetadataCharset(); enableUtf8Metadata->setChecked(charset == "UTF-8"); // OGG "dynamicupdate" checkbox - ogg_dynamicupdate->setChecked(m_settings.getOggDynamicUpdate()); + ogg_dynamicupdate->setChecked(profile->getOggDynamicUpdate()); slotApply(); } @@ -171,42 +173,44 @@ DlgPrefBroadcast::~DlgPrefBroadcast() { } void DlgPrefBroadcast::slotResetToDefaults() { + BroadcastProfile dProfile("dontsave"); + // Make sure to keep these values in sync with the constructor. enableLiveBroadcasting->setChecked(false); comboBoxServerType->setCurrentIndex(0); - mountpoint->setText(m_settings.getDefaultMountpoint()); - host->setText(m_settings.getDefaultHost()); - int iPort = m_settings.getDefaultPort(); + mountpoint->setText(dProfile.getMountpoint()); + host->setText(dProfile.getHost()); + int iPort = dProfile.getPort(); VERIFY_OR_DEBUG_ASSERT(iPort != 0 && iPort <= 0xffff) { port->setText(QString()); } else { port->setText(QString::number(iPort)); } - login->setText(m_settings.getDefaultLogin()); - password->setText(m_settings.getDefaultPassword()); + login->setText(dProfile.getLogin()); + password->setText(dProfile.getPassword()); - checkBoxEnableReconnect->setChecked(m_settings.getDefaultEnableReconnect()); + checkBoxEnableReconnect->setChecked(dProfile.getEnableReconnect()); widgetReconnectControls->setEnabled(true); - spinBoxFirstDelay->setValue(m_settings.getDefaultReconnectFirstDelay()); - spinBoxReconnectPeriod->setValue(m_settings.getDefaultReconnectPeriod()); - checkBoxLimitReconnects->setChecked(m_settings.getDefaultLimitReconnects()); - spinBoxMaximumRetries->setValue(m_settings.getDefaultMaximumRetries()); + spinBoxFirstDelay->setValue(dProfile.getReconnectFirstDelay()); + spinBoxReconnectPeriod->setValue(dProfile.getReconnectPeriod()); + checkBoxLimitReconnects->setChecked(dProfile.getLimitReconnects()); + spinBoxMaximumRetries->setValue(dProfile.getMaximumRetries()); spinBoxMaximumRetries->setEnabled(true); - stream_name->setText(m_settings.getDefaultStreamName()); - stream_website->setText(m_settings.getDefaultStreamWebsite()); - stream_desc->setText(m_settings.getDefaultStreamDesc()); - stream_genre->setText(m_settings.getDefaultStreamGenre()); - stream_public->setChecked(m_settings.getDefaultStreamPublic()); - ogg_dynamicupdate->setChecked(m_settings.getDefaultOggDynamicUpdate()); + stream_name->setText(dProfile.getStreamName()); + stream_website->setText(dProfile.getStreamWebsite()); + stream_desc->setText(dProfile.getStreamDesc()); + stream_genre->setText(dProfile.getStreamGenre()); + stream_public->setChecked(dProfile.getStreamPublic()); + ogg_dynamicupdate->setChecked(dProfile.getOggDynamicUpdate()); comboBoxEncodingBitrate->setCurrentIndex(comboBoxEncodingBitrate->findData( - m_settings.getDefaultBitrate())); + dProfile.getBitrate())); comboBoxEncodingFormat->setCurrentIndex(0); comboBoxEncodingChannels->setCurrentIndex(0); enableUtf8Metadata->setChecked(false); enableCustomMetadata->setChecked(false); - metadata_format->setText(m_settings.getDefaultMetadataFormat()); - custom_artist->setText(m_settings.getDefaultCustomArtist()); - custom_title->setText(m_settings.getDefaultCustomTitle()); + metadata_format->setText(dProfile.getMetadataFormat()); + custom_artist->setText(dProfile.getCustomArtist()); + custom_title->setText(dProfile.getCustomTitle()); custom_artist->setEnabled(false); custom_title->setEnabled(false); } @@ -235,52 +239,56 @@ void DlgPrefBroadcast::slotApply() this->setEnabled(true); } + BroadcastProfile* profile = m_settings.getCurrentProfile(); + // Combo boxes, make sure to load their data not their display strings. - m_settings.setServertype(comboBoxServerType->itemData( + profile->setServertype(comboBoxServerType->itemData( comboBoxServerType->currentIndex()).toString()); - m_settings.setBitrate(comboBoxEncodingBitrate->itemData( + profile->setBitrate(comboBoxEncodingBitrate->itemData( comboBoxEncodingBitrate->currentIndex()).toInt()); - m_settings.setFormat(comboBoxEncodingFormat->itemData( + profile->setFormat(comboBoxEncodingFormat->itemData( comboBoxEncodingFormat->currentIndex()).toString()); - m_settings.setChannels(comboBoxEncodingChannels->itemData( + profile->setChannels(comboBoxEncodingChannels->itemData( comboBoxEncodingChannels->currentIndex()).toInt()); mountpoint->setText(mountpoint->text().trimmed()); - m_settings.setMountPoint(mountpoint->text()); - m_settings.setHost(host->text()); - m_settings.setPort(port->text().toInt()); - m_settings.setLogin(login->text()); - m_settings.setPassword(password->text()); - m_settings.setEnableReconnect(checkBoxEnableReconnect->isChecked()); - m_settings.setReconnectFirstDelay(spinBoxFirstDelay->value()); - m_settings.setReconnectPeriod(spinBoxReconnectPeriod->value()); - m_settings.setLimitReconnects(checkBoxLimitReconnects->isChecked()); - m_settings.setMaximumRetries(spinBoxMaximumRetries->value()); - m_settings.setStreamName(stream_name->text()); - m_settings.setStreamWebsite(stream_website->text()); - m_settings.setStreamDesc(stream_desc->toPlainText()); - m_settings.setStreamGenre(stream_genre->text()); - m_settings.setStreamPublic(stream_public->isChecked()); - m_settings.setOggDynamicUpdate(ogg_dynamicupdate->isChecked()); + profile->setMountPoint(mountpoint->text()); + profile->setHost(host->text()); + profile->setPort(port->text().toInt()); + profile->setLogin(login->text()); + profile->setPassword(password->text()); + profile->setEnableReconnect(checkBoxEnableReconnect->isChecked()); + profile->setReconnectFirstDelay(spinBoxFirstDelay->value()); + profile->setReconnectPeriod(spinBoxReconnectPeriod->value()); + profile->setLimitReconnects(checkBoxLimitReconnects->isChecked()); + profile->setMaximumRetries(spinBoxMaximumRetries->value()); + profile->setStreamName(stream_name->text()); + profile->setStreamWebsite(stream_website->text()); + profile->setStreamDesc(stream_desc->toPlainText()); + profile->setStreamGenre(stream_genre->text()); + profile->setStreamPublic(stream_public->isChecked()); + profile->setOggDynamicUpdate(ogg_dynamicupdate->isChecked()); QString charset = ""; if (enableUtf8Metadata->isChecked()) { charset = "UTF-8"; } - QString current_charset = m_settings.getMetadataCharset(); + QString current_charset = profile->getMetadataCharset(); // Only allow setting the config value if the current value is either empty // or "UTF-8". This way users can customize the charset to something else by // setting the value in their mixxx.cfg. Not sure if this will be useful but // it's good to leave the option open. if (current_charset.length() == 0 || current_charset == "UTF-8") { - m_settings.setMetadataCharset(charset); + profile->setMetadataCharset(charset); } - m_settings.setEnableMetadata(enableCustomMetadata->isChecked()); - m_settings.setCustomArtist(custom_artist->text()); - m_settings.setCustomTitle(custom_title->text()); - m_settings.setMetadataFormat(metadata_format->text()); + profile->setEnableMetadata(enableCustomMetadata->isChecked()); + profile->setCustomArtist(custom_artist->text()); + profile->setCustomTitle(custom_title->text()); + profile->setMetadataFormat(metadata_format->text()); + + m_settings.saveAll(); } void DlgPrefBroadcast::broadcastEnabledChanged(double value) { From afff79fc278665a27f8c5cb5b73e51e251a5079f Mon Sep 17 00:00:00 2001 From: Palakis Date: Fri, 9 Jun 2017 11:28:37 +0200 Subject: [PATCH 05/13] BroadcastSettings: fix behaviour of filename gen. method --- src/preferences/broadcastprofile.cpp | 4 ++-- src/preferences/broadcastsettings.cpp | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/preferences/broadcastprofile.cpp b/src/preferences/broadcastprofile.cpp index 135f41caae64..d33a00b0cdb0 100644 --- a/src/preferences/broadcastprofile.cpp +++ b/src/preferences/broadcastprofile.cpp @@ -62,7 +62,7 @@ const QRegExp kForbiddenChars = QRegExp("[<>:\"/\\\|\?\*]"); } // anonymous namespace BroadcastProfile::BroadcastProfile(const QString& profileName) { - defaultValues(); + setDefaultValues(); setProfileName(profileName); } @@ -83,7 +83,7 @@ BroadcastProfile* BroadcastProfile::loadFromFile(const QString& filename) { return profile; } -void BroadcastProfile::defaultValues() { +void BroadcastProfile::setDefaultValues() { m_enabled = true; m_host = QString(), diff --git a/src/preferences/broadcastsettings.cpp b/src/preferences/broadcastsettings.cpp index 68ba156309b3..ee582527111d 100644 --- a/src/preferences/broadcastsettings.cpp +++ b/src/preferences/broadcastsettings.cpp @@ -63,8 +63,10 @@ QString BroadcastSettings::filenameForProfile(BroadcastProfile* profile) { if(!profile) return QString(); - QDir profilesFolder(m_pConfig->getSettingsPath()); - profilesFolder.cd(kProfilesSubfolder); + QString profilesPath(m_pConfig->getSettingsPath()); + profilesPath.append(QDir::separator() + QString(kProfilesSubfolder)); + + QDir profilesFolder(profilesPath); QString filename = profile->getProfileName() + QString(".bcp.xml"); return profilesFolder.absoluteFilePath(filename); From 744cb93adbd754ae80793ea4a00cf22bba0de666 Mon Sep 17 00:00:00 2001 From: Palakis Date: Fri, 9 Jun 2017 13:34:10 +0200 Subject: [PATCH 06/13] BroadcastProfile: fix XML load/save code Both ways didn't handled the document's root tag. Now, profile values are saved properly. --- src/preferences/broadcastprofile.cpp | 71 +++++++++++++++------------- src/preferences/broadcastprofile.h | 3 +- 2 files changed, 39 insertions(+), 35 deletions(-) diff --git a/src/preferences/broadcastprofile.cpp b/src/preferences/broadcastprofile.cpp index d33a00b0cdb0..323a7012bb1a 100644 --- a/src/preferences/broadcastprofile.cpp +++ b/src/preferences/broadcastprofile.cpp @@ -13,7 +13,8 @@ #include "broadcastprofile.h" namespace { -const char* kDocumentName = "BroadcastProfile"; +const char* kDoctype = "broadcastprofile"; +const char* kDocumentRoot = "BroadcastProfile"; const char* kBitrate = "Bitrate"; const char* kChannels = "Channels"; const char* kCustomArtist = "CustomArtist"; @@ -125,54 +126,55 @@ void BroadcastProfile::loadValues(const QString& filename) { return; } - QDomElement xmlRoot = XmlParse::openXMLFile(filename, kDocumentName); + QDomElement doc = XmlParse::openXMLFile(filename, kDoctype); + QDomElement docRoot = doc.firstChildElement(kDocumentRoot); - m_enabled = (bool)XmlParse::selectNodeInt(xmlRoot, kEnabled); + m_enabled = (bool)XmlParse::selectNodeInt(docRoot, kEnabled); - m_host = XmlParse::selectNodeQString(xmlRoot, kHost); - m_port = XmlParse::selectNodeInt(xmlRoot, kPort); - m_serverType = XmlParse::selectNodeQString(xmlRoot, kServertype); - m_login = XmlParse::selectNodeQString(xmlRoot, kLogin); - m_password = XmlParse::selectNodeQString(xmlRoot, kPassword); + m_host = XmlParse::selectNodeQString(docRoot, kHost); + m_port = XmlParse::selectNodeInt(docRoot, kPort); + m_serverType = XmlParse::selectNodeQString(docRoot, kServertype); + m_login = XmlParse::selectNodeQString(docRoot, kLogin); + m_password = XmlParse::selectNodeQString(docRoot, kPassword); m_enableReconnect = - (bool)XmlParse::selectNodeInt(xmlRoot, kEnableReconnect); + (bool)XmlParse::selectNodeInt(docRoot, kEnableReconnect); m_reconnectPeriod = - XmlParse::selectNodeDouble(xmlRoot, kReconnectPeriod); + XmlParse::selectNodeDouble(docRoot, kReconnectPeriod); m_limitReconnects = - (bool)XmlParse::selectNodeInt(xmlRoot, kLimitReconnects); + (bool)XmlParse::selectNodeInt(docRoot, kLimitReconnects); m_maximumRetries = - XmlParse::selectNodeInt(xmlRoot, kMaximumRetries); + XmlParse::selectNodeInt(docRoot, kMaximumRetries); m_noDelayFirstReconnect = - (bool)XmlParse::selectNodeInt(xmlRoot, kNoDelayFirstReconnect); + (bool)XmlParse::selectNodeInt(docRoot, kNoDelayFirstReconnect); m_reconnectFirstDelay = - XmlParse::selectNodeDouble(xmlRoot, kReconnectFirstDelay); - - m_mountpoint = XmlParse::selectNodeQString(xmlRoot, kMountPoint); - m_streamName = XmlParse::selectNodeQString(xmlRoot, kStreamName); - m_streamDesc = XmlParse::selectNodeQString(xmlRoot, kStreamDesc); - m_streamGenre = XmlParse::selectNodeQString(xmlRoot, kStreamGenre); - m_streamPublic = (bool)XmlParse::selectNodeInt(xmlRoot, kStreamPublic); - m_streamWebsite = XmlParse::selectNodeQString(xmlRoot, kStreamWebsite); - - m_format = XmlParse::selectNodeQString(xmlRoot, kFormat); - m_bitrate = XmlParse::selectNodeInt(xmlRoot, kBitrate); - m_channels = XmlParse::selectNodeInt(xmlRoot, kChannels); - - m_enableMetadata = (bool)XmlParse::selectNodeInt(xmlRoot, kEnableMetadata); - m_metadataCharset = XmlParse::selectNodeQString(xmlRoot, kMetadataCharset); - m_customArtist = XmlParse::selectNodeQString(xmlRoot, kCustomArtist); - m_customTitle = XmlParse::selectNodeQString(xmlRoot, kCustomTitle); - m_metadataFormat = XmlParse::selectNodeQString(xmlRoot, kMetadataFormat); + XmlParse::selectNodeDouble(docRoot, kReconnectFirstDelay); + + m_mountpoint = XmlParse::selectNodeQString(docRoot, kMountPoint); + m_streamName = XmlParse::selectNodeQString(docRoot, kStreamName); + m_streamDesc = XmlParse::selectNodeQString(docRoot, kStreamDesc); + m_streamGenre = XmlParse::selectNodeQString(docRoot, kStreamGenre); + m_streamPublic = (bool)XmlParse::selectNodeInt(docRoot, kStreamPublic); + m_streamWebsite = XmlParse::selectNodeQString(docRoot, kStreamWebsite); + + m_format = XmlParse::selectNodeQString(docRoot, kFormat); + m_bitrate = XmlParse::selectNodeInt(docRoot, kBitrate); + m_channels = XmlParse::selectNodeInt(docRoot, kChannels); + + m_enableMetadata = (bool)XmlParse::selectNodeInt(docRoot, kEnableMetadata); + m_metadataCharset = XmlParse::selectNodeQString(docRoot, kMetadataCharset); + m_customArtist = XmlParse::selectNodeQString(docRoot, kCustomArtist); + m_customTitle = XmlParse::selectNodeQString(docRoot, kCustomTitle); + m_metadataFormat = XmlParse::selectNodeQString(docRoot, kMetadataFormat); m_oggDynamicUpdate = - (bool)XmlParse::selectNodeInt(xmlRoot, kMetadataFormat); + (bool)XmlParse::selectNodeInt(docRoot, kMetadataFormat); } void BroadcastProfile::save(const QString& filename) { - QDomDocument doc(kDocumentName); - QDomElement docRoot = doc.documentElement(); + QDomDocument doc(kDoctype); + QDomElement docRoot = doc.createElement(kDocumentRoot); XmlParse::addElement(doc, docRoot, kEnabled, QString::number((int)m_enabled)); @@ -221,6 +223,7 @@ void BroadcastProfile::save(const QString& filename) { XmlParse::addElement(doc, docRoot, kOggDynamicUpdate, QString::number((int)m_oggDynamicUpdate)); + doc.appendChild(docRoot); QFile xmlFile(filename); xmlFile.open(QIODevice::WriteOnly | QIODevice::Text); diff --git a/src/preferences/broadcastprofile.h b/src/preferences/broadcastprofile.h index 88366edece8f..8b1eeaee053e 100644 --- a/src/preferences/broadcastprofile.h +++ b/src/preferences/broadcastprofile.h @@ -11,7 +11,8 @@ class BroadcastProfile { explicit BroadcastProfile(const QString& profileName); void save(const QString& filename); - static BroadcastProfile* BroadcastProfile::loadFromFile(const QString& filename); + static BroadcastProfile* BroadcastProfile::loadFromFile( + const QString& filename); static bool BroadcastProfile::checkNameCompliance(const QString& str); void setProfileName(const QString& profileName); From c1296be94169b717e2fd0d9bf77a597b159eed8c Mon Sep 17 00:00:00 2001 From: Palakis Date: Fri, 9 Jun 2017 14:16:07 +0200 Subject: [PATCH 07/13] BroadcastSettings: enhance default profile creation --- src/preferences/broadcastsettings.cpp | 53 ++++++++++++++++----------- src/preferences/broadcastsettings.h | 2 + 2 files changed, 34 insertions(+), 21 deletions(-) diff --git a/src/preferences/broadcastsettings.cpp b/src/preferences/broadcastsettings.cpp index ee582527111d..232cde284f51 100644 --- a/src/preferences/broadcastsettings.cpp +++ b/src/preferences/broadcastsettings.cpp @@ -28,27 +28,34 @@ BroadcastSettings::~BroadcastSettings() { } void BroadcastSettings::loadProfiles() { - QDir profilesFolder(m_pConfig->getSettingsPath()); - bool folderCreated = profilesFolder.mkdir(kProfilesSubfolder); - profilesFolder.cd(kProfilesSubfolder); - - if(folderCreated) { - BroadcastProfile* defaultProfile = - new BroadcastProfile(kDefaultProfile); - saveProfile(defaultProfile); - setCurrentProfile(defaultProfile); + QDir profilesFolder(getProfilesFolder()); + if(!profilesFolder.exists()) { + // TODO(Palakis, June 9th 2017): + // Is there a better way to do this? + profilesFolder.mkpath(profilesFolder.absolutePath()); } QStringList nameFilters("*.bcp.xml"); QFileInfoList files = profilesFolder.entryInfoList(nameFilters, QDir::Files, QDir::Name); - for(QFileInfo fileInfo : files) { - BroadcastProfile* profile = - BroadcastProfile::loadFromFile(fileInfo.absoluteFilePath()); + if(files.count() > 0) { + // Load profiles from filesystem + for(QFileInfo fileInfo : files) { + BroadcastProfile* profile = + BroadcastProfile::loadFromFile(fileInfo.absoluteFilePath()); + + if(profile) + m_profiles.push_back(profile); + } + } else { + // Create default profile + BroadcastProfile* defaultProfile = + new BroadcastProfile(kDefaultProfile); + saveProfile(defaultProfile); - if(profile) - m_profiles.push_back(profile); + m_profiles.push_back(defaultProfile); + setCurrentProfile(defaultProfile); } } @@ -59,17 +66,22 @@ void BroadcastSettings::saveProfile(BroadcastProfile* profile) { profile->save(filenameForProfile(profile)); } +QString BroadcastSettings::filenameForProfile(const QString& profileName) { + QString filename = profileName + QString(".bcp.xml"); + return QDir(getProfilesFolder()).absoluteFilePath(filename); +} + QString BroadcastSettings::filenameForProfile(BroadcastProfile* profile) { if(!profile) return QString(); + return filenameForProfile(profile->getProfileName()); +} + +QString BroadcastSettings::getProfilesFolder() { QString profilesPath(m_pConfig->getSettingsPath()); profilesPath.append(QDir::separator() + QString(kProfilesSubfolder)); - - QDir profilesFolder(profilesPath); - - QString filename = profile->getProfileName() + QString(".bcp.xml"); - return profilesFolder.absoluteFilePath(filename); + return profilesPath; } void BroadcastSettings::setCurrentProfile(BroadcastProfile *profile) { @@ -102,8 +114,7 @@ void BroadcastSettings::saveAll() { } } -void BroadcastSettings::deleteProfile(BroadcastProfile* profile) -{ +void BroadcastSettings::deleteProfile(BroadcastProfile* profile) { if(!profile) return; diff --git a/src/preferences/broadcastsettings.h b/src/preferences/broadcastsettings.h index baa3d66b749c..0f2096d4bf60 100644 --- a/src/preferences/broadcastsettings.h +++ b/src/preferences/broadcastsettings.h @@ -23,6 +23,8 @@ class BroadcastSettings { void loadProfiles(); void saveProfile(BroadcastProfile* profile); QString filenameForProfile(BroadcastProfile* profile); + QString filenameForProfile(const QString& profileName); + QString getProfilesFolder(); // Pointer to config object UserSettingsPointer m_pConfig; From 52f8d7e09d9a314d33d395f3c07a94e9d2fae738 Mon Sep 17 00:00:00 2001 From: Palakis Date: Fri, 9 Jun 2017 14:28:01 +0200 Subject: [PATCH 08/13] BroadcastSettings: add qDebug statements --- src/preferences/broadcastsettings.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/preferences/broadcastsettings.cpp b/src/preferences/broadcastsettings.cpp index 232cde284f51..b0098a2aef57 100644 --- a/src/preferences/broadcastsettings.cpp +++ b/src/preferences/broadcastsettings.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include "preferences/broadcastsettings.h" #include "broadcast/defs_broadcast.h" @@ -32,6 +33,7 @@ void BroadcastSettings::loadProfiles() { if(!profilesFolder.exists()) { // TODO(Palakis, June 9th 2017): // Is there a better way to do this? + qDebug() << "Profiles folder doesn't exist. Creating it." << endl; profilesFolder.mkpath(profilesFolder.absolutePath()); } @@ -40,6 +42,7 @@ void BroadcastSettings::loadProfiles() { profilesFolder.entryInfoList(nameFilters, QDir::Files, QDir::Name); if(files.count() > 0) { + qDebug() << "Found " << files.count() << " profiles."; // Load profiles from filesystem for(QFileInfo fileInfo : files) { BroadcastProfile* profile = @@ -49,6 +52,8 @@ void BroadcastSettings::loadProfiles() { m_profiles.push_back(profile); } } else { + qDebug() << "No profiles found. Creating default profile." << endl; + // Create default profile BroadcastProfile* defaultProfile = new BroadcastProfile(kDefaultProfile); From 84dd954aab1725b4be276e1e95030ebc2bc064cc Mon Sep 17 00:00:00 2001 From: Palakis Date: Fri, 9 Jun 2017 14:58:48 +0200 Subject: [PATCH 09/13] BroadcastProfile: remove extra qualifications in header file --- src/preferences/broadcastprofile.h | 4 ++-- src/preferences/broadcastsettings.cpp | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/preferences/broadcastprofile.h b/src/preferences/broadcastprofile.h index 8b1eeaee053e..1b77a14095d7 100644 --- a/src/preferences/broadcastprofile.h +++ b/src/preferences/broadcastprofile.h @@ -11,9 +11,9 @@ class BroadcastProfile { explicit BroadcastProfile(const QString& profileName); void save(const QString& filename); - static BroadcastProfile* BroadcastProfile::loadFromFile( + static BroadcastProfile* loadFromFile( const QString& filename); - static bool BroadcastProfile::checkNameCompliance(const QString& str); + static bool checkNameCompliance(const QString& str); void setProfileName(const QString& profileName); QString getProfileName() const; diff --git a/src/preferences/broadcastsettings.cpp b/src/preferences/broadcastsettings.cpp index b0098a2aef57..09fd88bbce69 100644 --- a/src/preferences/broadcastsettings.cpp +++ b/src/preferences/broadcastsettings.cpp @@ -31,9 +31,10 @@ BroadcastSettings::~BroadcastSettings() { void BroadcastSettings::loadProfiles() { QDir profilesFolder(getProfilesFolder()); if(!profilesFolder.exists()) { + qDebug() << "Profiles folder doesn't exist. Creating it." << endl; + // TODO(Palakis, June 9th 2017): // Is there a better way to do this? - qDebug() << "Profiles folder doesn't exist. Creating it." << endl; profilesFolder.mkpath(profilesFolder.absolutePath()); } From b2d089d9d6158c1756068501b2e122ae4fc3a906 Mon Sep 17 00:00:00 2001 From: Palakis Date: Fri, 9 Jun 2017 23:25:15 +0200 Subject: [PATCH 10/13] BroadcastProfile: fix XML file load code --- src/preferences/broadcastprofile.cpp | 66 ++++++++++++--------------- src/preferences/broadcastsettings.cpp | 11 +++-- 2 files changed, 37 insertions(+), 40 deletions(-) diff --git a/src/preferences/broadcastprofile.cpp b/src/preferences/broadcastprofile.cpp index 323a7012bb1a..f0fd439c1acf 100644 --- a/src/preferences/broadcastprofile.cpp +++ b/src/preferences/broadcastprofile.cpp @@ -121,55 +121,49 @@ void BroadcastProfile::setDefaultValues() { } void BroadcastProfile::loadValues(const QString& filename) { - if(!QFile::exists(filename)) { - setDefaultValues(); - return; - } - QDomElement doc = XmlParse::openXMLFile(filename, kDoctype); - QDomElement docRoot = doc.firstChildElement(kDocumentRoot); - m_enabled = (bool)XmlParse::selectNodeInt(docRoot, kEnabled); + m_enabled = (bool)XmlParse::selectNodeInt(doc, kEnabled); - m_host = XmlParse::selectNodeQString(docRoot, kHost); - m_port = XmlParse::selectNodeInt(docRoot, kPort); - m_serverType = XmlParse::selectNodeQString(docRoot, kServertype); - m_login = XmlParse::selectNodeQString(docRoot, kLogin); - m_password = XmlParse::selectNodeQString(docRoot, kPassword); + m_host = XmlParse::selectNodeQString(doc, kHost); + m_port = XmlParse::selectNodeInt(doc, kPort); + m_serverType = XmlParse::selectNodeQString(doc, kServertype); + m_login = XmlParse::selectNodeQString(doc, kLogin); + m_password = XmlParse::selectNodeQString(doc, kPassword); m_enableReconnect = - (bool)XmlParse::selectNodeInt(docRoot, kEnableReconnect); + (bool)XmlParse::selectNodeInt(doc, kEnableReconnect); m_reconnectPeriod = - XmlParse::selectNodeDouble(docRoot, kReconnectPeriod); + XmlParse::selectNodeDouble(doc, kReconnectPeriod); m_limitReconnects = - (bool)XmlParse::selectNodeInt(docRoot, kLimitReconnects); + (bool)XmlParse::selectNodeInt(doc, kLimitReconnects); m_maximumRetries = - XmlParse::selectNodeInt(docRoot, kMaximumRetries); + XmlParse::selectNodeInt(doc, kMaximumRetries); m_noDelayFirstReconnect = - (bool)XmlParse::selectNodeInt(docRoot, kNoDelayFirstReconnect); + (bool)XmlParse::selectNodeInt(doc, kNoDelayFirstReconnect); m_reconnectFirstDelay = - XmlParse::selectNodeDouble(docRoot, kReconnectFirstDelay); - - m_mountpoint = XmlParse::selectNodeQString(docRoot, kMountPoint); - m_streamName = XmlParse::selectNodeQString(docRoot, kStreamName); - m_streamDesc = XmlParse::selectNodeQString(docRoot, kStreamDesc); - m_streamGenre = XmlParse::selectNodeQString(docRoot, kStreamGenre); - m_streamPublic = (bool)XmlParse::selectNodeInt(docRoot, kStreamPublic); - m_streamWebsite = XmlParse::selectNodeQString(docRoot, kStreamWebsite); - - m_format = XmlParse::selectNodeQString(docRoot, kFormat); - m_bitrate = XmlParse::selectNodeInt(docRoot, kBitrate); - m_channels = XmlParse::selectNodeInt(docRoot, kChannels); - - m_enableMetadata = (bool)XmlParse::selectNodeInt(docRoot, kEnableMetadata); - m_metadataCharset = XmlParse::selectNodeQString(docRoot, kMetadataCharset); - m_customArtist = XmlParse::selectNodeQString(docRoot, kCustomArtist); - m_customTitle = XmlParse::selectNodeQString(docRoot, kCustomTitle); - m_metadataFormat = XmlParse::selectNodeQString(docRoot, kMetadataFormat); + XmlParse::selectNodeDouble(doc, kReconnectFirstDelay); + + m_mountpoint = XmlParse::selectNodeQString(doc, kMountPoint); + m_streamName = XmlParse::selectNodeQString(doc, kStreamName); + m_streamDesc = XmlParse::selectNodeQString(doc, kStreamDesc); + m_streamGenre = XmlParse::selectNodeQString(doc, kStreamGenre); + m_streamPublic = (bool)XmlParse::selectNodeInt(doc, kStreamPublic); + m_streamWebsite = XmlParse::selectNodeQString(doc, kStreamWebsite); + + m_format = XmlParse::selectNodeQString(doc, kFormat); + m_bitrate = XmlParse::selectNodeInt(doc, kBitrate); + m_channels = XmlParse::selectNodeInt(doc, kChannels); + + m_enableMetadata = (bool)XmlParse::selectNodeInt(doc, kEnableMetadata); + m_metadataCharset = XmlParse::selectNodeQString(doc, kMetadataCharset); + m_customArtist = XmlParse::selectNodeQString(doc, kCustomArtist); + m_customTitle = XmlParse::selectNodeQString(doc, kCustomTitle); + m_metadataFormat = XmlParse::selectNodeQString(doc, kMetadataFormat); m_oggDynamicUpdate = - (bool)XmlParse::selectNodeInt(docRoot, kMetadataFormat); + (bool)XmlParse::selectNodeInt(doc, kMetadataFormat); } void BroadcastProfile::save(const QString& filename) { diff --git a/src/preferences/broadcastsettings.cpp b/src/preferences/broadcastsettings.cpp index 09fd88bbce69..815c2858dc8c 100644 --- a/src/preferences/broadcastsettings.cpp +++ b/src/preferences/broadcastsettings.cpp @@ -2,8 +2,8 @@ #include #include #include -#include +#include "util/logger.h" #include "preferences/broadcastsettings.h" #include "broadcast/defs_broadcast.h" #include "defs_urls.h" @@ -13,6 +13,7 @@ const char* kConfigKey = "[Shoutcast]"; const char* kCurrentProfile = "current_profile"; const char* kProfilesSubfolder = "broadcast_profiles"; const char* kDefaultProfile = "Default Profile"; +const mixxx::Logger kLogger("BroadcastSettings"); } // anonymous namespace BroadcastSettings::BroadcastSettings(UserSettingsPointer pConfig) @@ -31,7 +32,8 @@ BroadcastSettings::~BroadcastSettings() { void BroadcastSettings::loadProfiles() { QDir profilesFolder(getProfilesFolder()); if(!profilesFolder.exists()) { - qDebug() << "Profiles folder doesn't exist. Creating it." << endl; + kLogger.warning() + << "Profiles folder doesn't exist. Creating it."; // TODO(Palakis, June 9th 2017): // Is there a better way to do this? @@ -43,7 +45,7 @@ void BroadcastSettings::loadProfiles() { profilesFolder.entryInfoList(nameFilters, QDir::Files, QDir::Name); if(files.count() > 0) { - qDebug() << "Found " << files.count() << " profiles."; + kLogger.warning() << "Found " << files.count() << " profiles."; // Load profiles from filesystem for(QFileInfo fileInfo : files) { BroadcastProfile* profile = @@ -53,7 +55,8 @@ void BroadcastSettings::loadProfiles() { m_profiles.push_back(profile); } } else { - qDebug() << "No profiles found. Creating default profile." << endl; + kLogger.warning() + << "No profiles found. Creating default profile."; // Create default profile BroadcastProfile* defaultProfile = From 55dcfc813a9ac28a48ca0f6ead908e5c78acbe54 Mon Sep 17 00:00:00 2001 From: Palakis Date: Mon, 12 Jun 2017 22:44:34 +0200 Subject: [PATCH 11/13] (WIP) Preferences: add profiles to Live Broadcasting UI --- src/preferences/dialog/dlgprefbroadcastdlg.ui | 1227 +++++++++-------- 1 file changed, 635 insertions(+), 592 deletions(-) diff --git a/src/preferences/dialog/dlgprefbroadcastdlg.ui b/src/preferences/dialog/dlgprefbroadcastdlg.ui index bd663fc00f37..5dffa2165edd 100644 --- a/src/preferences/dialog/dlgprefbroadcastdlg.ui +++ b/src/preferences/dialog/dlgprefbroadcastdlg.ui @@ -7,26 +7,13 @@ 0 0 692 - 581 + 613 Live Broadcasting Preferences - - - - - Qt::Vertical - - - - 20 - 40 - - - - + @@ -37,602 +24,658 @@ - - + + - Server connection + Settings for "Default Profile" - + + + + + Server connection + + + + + + + + Type + + + + + + + + 0 + 0 + + + + + + + + + 10 + 0 + + + + + + + + Mount + + + + + + + + + + + + + + Host + + + + + + + + + + + + + + Port + + + + + + + + 0 + 0 + + + + + + + + + + + Login + + + + + + + source + + + + + + + Password + + + + + + + + + + QLineEdit::Password + + + + + + + + - - - - - Type - - - - - - - - 0 - 0 - - - - - - - - - 10 - 0 - - - - - - - - Mount - - - - - - - - - - - - - - Host - - - - - - - - - - - - - - Port - - - - - - - - 0 - 0 - - - - - - - - - - - Login - - - - - - - source - - - - - - - Password - - - - - - - - - - QLineEdit::Password - - - - + + + Automatic reconnect + + + + + + + + Reconnect if the connection to the streaming server is lost. + + + Enable automatic reconnect + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + Reconnect period + + + + + + + Time to wait between two reconnection attempts. + + + seconds + + + 2 + + + 3600.000000000000000 + + + + + + + + 0 + 0 + + + + 1 + + + 100 + + + + + + + Maximum retries + + + + + + + + + + Limit number of reconnection attempts + + + + + + + Time to wait before the first reconnection attempt is made. + + + seconds + + + 3600.000000000000000 + + + + + + + Wait until first attempt + + + + + + + + + + + + - - - - - - - Encoding - - - - - - - - Format - - - comboBoxEncodingFormat - - - - - - - - 0 - 0 - - - - Bitrate - - - - - - - QFrame::NoFrame - - - 1 - - - Channels - - - Qt::AutoText - - - false - - - comboBoxEncodingChannels - - - - - - - - 0 - 0 - - - - - 16777215 - 16777215 - - - - - - - - - 0 - 0 - - - - - - - - - 0 - 0 - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - + + + + Encoding + + + + + + + + Format + + + comboBoxEncodingFormat + + + + + + + + 0 + 0 + + + + Bitrate + + + + + + + QFrame::NoFrame + + + 1 + + + Channels + + + Qt::AutoText + + + false + + + comboBoxEncodingChannels + + + + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + - - - - - - - - 300 - 0 - - - - Stream info - - - - - - - - - 0 - 0 - - - - Mixxx Icecast Testing - - - - - - - - 0 - 0 - - - - Stream name - - - comboBoxServerType - - - - - - - - 0 - 0 - - - - Website - - - mountpoint - - - - - - - - 0 - 0 - - - - http://www.mixxx.org - - - - - - - - 0 - 0 - - - - Description - - - stream_desc - - - - - - - - 0 - 0 - - - - - 0 - 50 - - - - - 16777215 - 50 - - - - true - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> + + + + Metadata + + + false + + + + + + + + Format + + + + + + + $artist - $title + + + + + + + Static artist + + + custom_artist + + + + + + + %mainartist + + + + + + + Static title + + + custom_title + + + + + + + %maintitle + + + + + + + + 0 + 0 + + + + Due to flaws in some streaming clients, updating Ogg Vorbis metadata dynamically can cause listener glitches and disconnections. Check this box to update the metadata anyway. + + + Dynamically update Ogg Vorbis metadata. + + + + + + + Use UTF-8 encoding for metadata. + + + + + + + Use static artist and title. + + + true + + + + + + + + + + + + + 300 + 0 + + + + Stream info + + + + + + + + + 0 + 0 + + + + Mixxx Icecast Testing + + + + + + + + 0 + 0 + + + + Stream name + + + comboBoxServerType + + + + + + + + 0 + 0 + + + + Website + + + mountpoint + + + + + + + + 0 + 0 + + + + http://www.mixxx.org + + + + + + + + 0 + 0 + + + + Description + + + stream_desc + + + + + + + + 0 + 0 + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + true + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Ubuntu'; font-size:10pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> </p> +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu'; font-size:10pt;"> </span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Lucida Grande'; font-size:13pt;"><br /></p></body></html> - - - - - - - - 0 - 0 - - - - Genre - - - stream_genre - - - - - - - - 0 - 0 - - - - Live mix - - - - - - - Public stream - - - - + + + + + + + + 0 + 0 + + + + Genre + + + stream_genre + + + + + + + + 0 + 0 + + + + Live mix + + + + + + + Public stream + + + + + + + - - + + - Metadata - - - false + Broadcasting Profiles - - - - - - - Format - - - - - - - $artist - $title - - - - - - - Static artist - - - custom_artist - - - - - - - %mainartist - - - - - - - Static title - - - custom_title - - - - - - - %maintitle - - - - - - - - 0 - 0 - - - - Due to flaws in some streaming clients, updating Ogg Vorbis metadata dynamically can cause listener glitches and disconnections. Check this box to update the metadata anyway. - - - Dynamically update Ogg Vorbis metadata. - - - - - - - Use UTF-8 encoding for metadata. - - - - - - - Use static artist and title. - - - true - - - - + + + + + QFrame::StyledPanel + + + QFrame::Sunken + + + Qt::ScrollBarAsNeeded + + - - - - Automatic reconnect + + + + Qt::Vertical - - - - - - - Reconnect if the connection to the streaming server is lost. - - - Enable automatic reconnect - - - - - - - - 0 - - - - - - - Reconnect period - - - - - - - Time to wait between two reconnection attempts. - - - seconds - - - 2 - - - 3600.000000000000000 - - - - - - - - 0 - 0 - - - - 1 - - - 100 - - - - - - - Maximum retries - - - - - - - - - - Limit number of reconnection attempts - - - - - - - Time to wait before the first reconnection attempt is made. - - - seconds - - - 3600.000000000000000 - - - - - - - Wait until first attempt - - - - - - - - - - - - + + QSizePolicy::Expanding + + + + 20 + 40 + + + From f76e2c790951bd8c68af9507f4f9dd12380f7b7c Mon Sep 17 00:00:00 2001 From: Palakis Date: Wed, 14 Jun 2017 13:09:30 +0200 Subject: [PATCH 12/13] Live Broadcasting prefs: use QListView instead --- src/preferences/dialog/dlgprefbroadcastdlg.ui | 50 +++++++++++++------ 1 file changed, 35 insertions(+), 15 deletions(-) diff --git a/src/preferences/dialog/dlgprefbroadcastdlg.ui b/src/preferences/dialog/dlgprefbroadcastdlg.ui index 5dffa2165edd..772a770f3131 100644 --- a/src/preferences/dialog/dlgprefbroadcastdlg.ui +++ b/src/preferences/dialog/dlgprefbroadcastdlg.ui @@ -7,13 +7,13 @@ 0 0 692 - 613 + 683 Live Broadcasting Preferences - + @@ -644,19 +644,39 @@ p, li { white-space: pre-wrap; } Broadcasting Profiles - - - - - QFrame::StyledPanel - - - QFrame::Sunken - - - Qt::ScrollBarAsNeeded - - + + + + + + + + + + padding: 4px 7px 4px 7px; + + + Create new profile + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 40 + 20 + + + + + From ec5263358e48cfe31fca3617087aa093d2f742b4 Mon Sep 17 00:00:00 2001 From: Palakis Date: Thu, 15 Jun 2017 02:02:10 +0200 Subject: [PATCH 13/13] (WIP) Broadcasting prefs: implement logic behind new UI --- src/encoder/encoderbroadcastsettings.cpp | 16 +- src/encoder/encoderbroadcastsettings.h | 4 +- src/engine/sidechain/enginebroadcast.cpp | 2 +- src/preferences/broadcastprofile.h | 7 +- src/preferences/broadcastsettings.cpp | 73 +++- src/preferences/broadcastsettings.h | 20 +- src/preferences/dialog/dlgprefbroadcast.cpp | 366 ++++++++++++------ src/preferences/dialog/dlgprefbroadcast.h | 13 + src/preferences/dialog/dlgprefbroadcastdlg.ui | 2 +- 9 files changed, 356 insertions(+), 147 deletions(-) diff --git a/src/encoder/encoderbroadcastsettings.cpp b/src/encoder/encoderbroadcastsettings.cpp index dee0e3ace3ea..a2235da7452f 100644 --- a/src/encoder/encoderbroadcastsettings.cpp +++ b/src/encoder/encoderbroadcastsettings.cpp @@ -10,8 +10,8 @@ #define DEFAULT_BITRATE 128 -EncoderBroadcastSettings::EncoderBroadcastSettings(BroadcastSettings settings) : -m_settings(settings) { +EncoderBroadcastSettings::EncoderBroadcastSettings(BroadcastSettings* settings) : +m_pSettings(settings) { m_qualList.append(32); m_qualList.append(48); m_qualList.append(64); @@ -34,7 +34,7 @@ QList EncoderBroadcastSettings::getQualityValues() const { // Sets the value void EncoderBroadcastSettings::setQualityByValue(int qualityValue) { - BroadcastProfile* profile = m_settings.getCurrentProfile(); + BroadcastProfile* profile = m_pSettings->getCurrentProfile(); if (m_qualList.contains(qualityValue)) { profile->setBitrate(qualityValue); @@ -45,7 +45,7 @@ void EncoderBroadcastSettings::setQualityByValue(int qualityValue) { } void EncoderBroadcastSettings::setQualityByIndex(int qualityIndex) { - BroadcastProfile* profile = m_settings.getCurrentProfile(); + BroadcastProfile* profile = m_pSettings->getCurrentProfile(); if (qualityIndex >= 0 && qualityIndex < m_qualList.size()) { profile->setBitrate(m_qualList.at(qualityIndex)); @@ -56,8 +56,7 @@ void EncoderBroadcastSettings::setQualityByIndex(int qualityIndex) { } int EncoderBroadcastSettings::getQuality() const { - BroadcastProfile* profile = - const_cast(m_settings).getCurrentProfile(); + BroadcastProfile* profile = m_pSettings->getCurrentProfile(); int bitrate = profile->getBitrate(); if (m_qualList.contains(bitrate)) { @@ -76,13 +75,12 @@ int EncoderBroadcastSettings::getQualityIndex() const { void EncoderBroadcastSettings::setChannelMode(EncoderSettings::ChannelMode mode) { - BroadcastProfile* profile = m_settings.getCurrentProfile(); + BroadcastProfile* profile = m_pSettings->getCurrentProfile(); profile->setChannels(static_cast(mode)); } EncoderSettings::ChannelMode EncoderBroadcastSettings::getChannelMode() const { - BroadcastProfile* profile = - const_cast(m_settings).getCurrentProfile(); + BroadcastProfile* profile = m_pSettings->getCurrentProfile(); switch(profile->getChannels()) { case 1: return EncoderSettings::ChannelMode::MONO; diff --git a/src/encoder/encoderbroadcastsettings.h b/src/encoder/encoderbroadcastsettings.h index 4198f970e440..fd898948d320 100644 --- a/src/encoder/encoderbroadcastsettings.h +++ b/src/encoder/encoderbroadcastsettings.h @@ -15,7 +15,7 @@ class EncoderBroadcastSettings : public EncoderSettings { public: - EncoderBroadcastSettings(BroadcastSettings settings); + EncoderBroadcastSettings(BroadcastSettings* settings); virtual ~EncoderBroadcastSettings(); // Indicates that it uses the quality slider section of the preferences @@ -39,7 +39,7 @@ class EncoderBroadcastSettings : public EncoderSettings { private: QList m_qualList; - BroadcastSettings m_settings; + BroadcastSettings* m_pSettings; }; diff --git a/src/engine/sidechain/enginebroadcast.cpp b/src/engine/sidechain/enginebroadcast.cpp index ddbe26cf9054..a05e39a89957 100644 --- a/src/engine/sidechain/enginebroadcast.cpp +++ b/src/engine/sidechain/enginebroadcast.cpp @@ -366,7 +366,7 @@ void EngineBroadcast::updateFromPreferences() { } // Initialize m_encoder - EncoderBroadcastSettings broadcastSettings(m_settings); + EncoderBroadcastSettings broadcastSettings(&m_settings); if (m_format_is_mp3) { m_encoder = EncoderFactory::getFactory().getNewEncoder( EncoderFactory::getFactory().getFormatFor(ENCODING_MP3), m_pConfig, this); diff --git a/src/preferences/broadcastprofile.h b/src/preferences/broadcastprofile.h index 1b77a14095d7..47343cccc372 100644 --- a/src/preferences/broadcastprofile.h +++ b/src/preferences/broadcastprofile.h @@ -15,6 +15,10 @@ class BroadcastProfile { const QString& filename); static bool checkNameCompliance(const QString& str); + bool hasUnsavedChanges() { + return m_hasUnsavedChanges; + } + void setProfileName(const QString& profileName); QString getProfileName() const; @@ -104,8 +108,9 @@ class BroadcastProfile { void loadValues(const QString& filename); void defaultValues(); - QString m_profileName; + bool m_hasUnsavedChanges; + QString m_profileName; bool m_enabled; QString m_host; diff --git a/src/preferences/broadcastsettings.cpp b/src/preferences/broadcastsettings.cpp index 815c2858dc8c..98b633fa627a 100644 --- a/src/preferences/broadcastsettings.cpp +++ b/src/preferences/broadcastsettings.cpp @@ -12,14 +12,21 @@ namespace { const char* kConfigKey = "[Shoutcast]"; const char* kCurrentProfile = "current_profile"; const char* kProfilesSubfolder = "broadcast_profiles"; -const char* kDefaultProfile = "Default Profile"; +const QString kDefaultProfile = QObject::tr("Untitled Profile"); const mixxx::Logger kLogger("BroadcastSettings"); } // anonymous namespace -BroadcastSettings::BroadcastSettings(UserSettingsPointer pConfig) - : m_pConfig(pConfig), +BroadcastSettings::BroadcastSettings(UserSettingsPointer pConfig, + QObject *parent) + : QAbstractListModel(parent), + m_pConfig(pConfig), m_profiles(), m_currentProfile(kDefaultProfile) { + setHeaderData(0, Qt::Horizontal, QObject::tr("Enabled"), Qt::EditRole); + setHeaderData(1, Qt::Horizontal, QObject::tr("Name"), Qt::EditRole); + setHeaderData(2, Qt::Horizontal, QObject::tr("Edit"), Qt::DisplayRole); + setHeaderData(3, Qt::Horizontal, QObject::tr("Remove"), Qt::DisplayRole); + loadProfiles(); } @@ -52,22 +59,30 @@ void BroadcastSettings::loadProfiles() { BroadcastProfile::loadFromFile(fileInfo.absoluteFilePath()); if(profile) - m_profiles.push_back(profile); + addProfile(profile); } } else { kLogger.warning() << "No profiles found. Creating default profile."; // Create default profile - BroadcastProfile* defaultProfile = - new BroadcastProfile(kDefaultProfile); - saveProfile(defaultProfile); - - m_profiles.push_back(defaultProfile); + BroadcastProfile* defaultProfile = newProfile(); setCurrentProfile(defaultProfile); } } +BroadcastProfile* BroadcastSettings::newProfile() { + QFileInfo xmlFile(filenameForProfile(kDefaultProfile)); + + if(!xmlFile.exists()) { + BroadcastProfile* profile = new BroadcastProfile(kDefaultProfile); + saveProfile(profile); + addProfile(profile); + return profile; + } + return nullptr; +} + void BroadcastSettings::saveProfile(BroadcastProfile* profile) { if(!profile) return; @@ -93,6 +108,19 @@ QString BroadcastSettings::getProfilesFolder() { return profilesPath; } +bool BroadcastSettings::addProfile(BroadcastProfile *profile) { + if(profile) { + int position = m_profiles.size(); + + beginInsertRows(QModelIndex(), position, position); + m_profiles.push_back(profile); + endInsertRows(); + + return true; + } + return false; +} + void BroadcastSettings::setCurrentProfile(BroadcastProfile *profile) { if(!profile) return; @@ -123,6 +151,11 @@ void BroadcastSettings::saveAll() { } } +void BroadcastSettings::renameProfile(BroadcastProfile* profile, + const QString& newName) { + +} + void BroadcastSettings::deleteProfile(BroadcastProfile* profile) { if(!profile) return; @@ -133,3 +166,25 @@ void BroadcastSettings::deleteProfile(BroadcastProfile* profile) { m_profiles.removeAll(profile); } + +int BroadcastSettings::rowCount(const QModelIndex &parent) const { + return m_profiles.size(); +} + +QVariant BroadcastSettings::data(const QModelIndex &index, int role) const { + int rowIndex = index.row(); + + if(!index.isValid() + || rowIndex >= m_profiles.size()) + return QVariant(); + + if(role == Qt::DisplayRole) + return m_profiles.at(rowIndex)->getProfileName(); + else + return QVariant(); +} + +/*QVariant BroadcastSettings::headerData(int section, Qt::Orientation orientation, + int role = Qt::DisplayRole) { + +}*/ diff --git a/src/preferences/broadcastsettings.h b/src/preferences/broadcastsettings.h index 0f2096d4bf60..195ffcb65d86 100644 --- a/src/preferences/broadcastsettings.h +++ b/src/preferences/broadcastsettings.h @@ -1,31 +1,45 @@ #ifndef PREFERENCES_BROADCASTSETTINGS_H #define PREFERENCES_BROADCASTSETTINGS_H +#include #include #include +#include +#include #include "preferences/usersettings.h" #include "track/track.h" #include "broadcastprofile.h" -class BroadcastSettings { +class BroadcastSettings : public QAbstractListModel { + Q_OBJECT + public: - BroadcastSettings(UserSettingsPointer pConfig); + BroadcastSettings(UserSettingsPointer pConfig, QObject *parent = nullptr); ~BroadcastSettings(); + BroadcastProfile* newProfile(); void setCurrentProfile(BroadcastProfile* profile); BroadcastProfile* getCurrentProfile(); BroadcastProfile* getProfileByName(const QString& profileName); + void renameProfile(BroadcastProfile* profile, const QString& newName); void deleteProfile(BroadcastProfile* profile); + void saveProfile(BroadcastProfile* profile); void saveAll(); + int rowCount(const QModelIndex &parent) const; + QVariant data(const QModelIndex &index, int role) const; + //QVariant headerData(int section, Qt::Orientation orientation, + // int role = Qt::DisplayRole); + private: void loadProfiles(); - void saveProfile(BroadcastProfile* profile); QString filenameForProfile(BroadcastProfile* profile); QString filenameForProfile(const QString& profileName); QString getProfilesFolder(); + bool addProfile(BroadcastProfile* profile); + // Pointer to config object UserSettingsPointer m_pConfig; QList m_profiles; diff --git a/src/preferences/dialog/dlgprefbroadcast.cpp b/src/preferences/dialog/dlgprefbroadcast.cpp index 9ca1b53b418a..1f5919c57fa9 100644 --- a/src/preferences/dialog/dlgprefbroadcast.cpp +++ b/src/preferences/dialog/dlgprefbroadcast.cpp @@ -1,24 +1,39 @@ #include +#include +#include #include "broadcast/defs_broadcast.h" #include "control/controlproxy.h" #include "defs_urls.h" #include "preferences/dialog/dlgprefbroadcast.h" #include "encoder/encodersettings.h" +#include "util/logger.h" + +namespace { +const char* kSettingsGroupHeader = "Settings for profile '%1'"; +const char* kUnsavedChangesWarning = + "Profile '%1' has unsaved changes. Do you want to save them?"; +const mixxx::Logger kLogger("DlgPrefBroadcast"); +} DlgPrefBroadcast::DlgPrefBroadcast(QWidget *parent, UserSettingsPointer _config) : DlgPreferencePage(parent), - m_settings(_config) { + m_settings(_config), + m_pProfileListSelection(nullptr), + m_valuesChanged(false) { setupUi(this); - BroadcastProfile* profile = m_settings.getCurrentProfile(); + profileList->setModel(&m_settings); + connect(btnCreateProfile, SIGNAL(clicked(bool)), + this, SLOT(btnCreateProfileClicked(bool))); + connect(profileList, SIGNAL(clicked(const QModelIndex&)), + this, SLOT(profileListItemSelected(QModelIndex))); m_pBroadcastEnabled = new ControlProxy( BROADCAST_PREF_KEY, "enabled", this); m_pBroadcastEnabled->connectValueChanged( SLOT(broadcastEnabledChanged(double))); - // Enable live broadcasting checkbox enableLiveBroadcasting->setChecked( m_pBroadcastEnabled->toBool()); @@ -28,70 +43,6 @@ DlgPrefBroadcast::DlgPrefBroadcast(QWidget *parent, UserSettingsPointer _config) comboBoxServerType->addItem(tr("Shoutcast 1"), BROADCAST_SERVER_SHOUTCAST); comboBoxServerType->addItem(tr("Icecast 1"), BROADCAST_SERVER_ICECAST1); - int tmp_index = comboBoxServerType->findData(profile->getServertype()); - if (tmp_index < 0) { // Set default if invalid. - tmp_index = 0; - } - comboBoxServerType->setCurrentIndex(tmp_index); - - // Mountpoint - mountpoint->setText(profile->getMountpoint()); - - // Host - host->setText(profile->getHost()); - - // Port - QString portString = QString::number(profile->getPort()); - port->setText(portString); - - // Login - login->setText(profile->getLogin()); - - // Password - password->setText(profile->getPassword()); - - - // Enable automatic reconnect - bool enableReconnect = profile->getEnableReconnect(); - checkBoxEnableReconnect->setChecked(enableReconnect); - widgetReconnectControls->setEnabled(enableReconnect); - connect(checkBoxEnableReconnect, SIGNAL(stateChanged(int)), - this, SLOT(checkBoxEnableReconnectChanged(int))); - - - // Wait until first attempt - spinBoxFirstDelay->setValue(profile->getReconnectFirstDelay()); - - // Retry Delay - spinBoxReconnectPeriod->setValue(profile->getReconnectPeriod()); - - // Use Maximum Retries - bool limitConnects = profile->getLimitReconnects(); - checkBoxLimitReconnects->setChecked( - limitConnects); - spinBoxMaximumRetries->setEnabled(limitConnects); - connect(checkBoxLimitReconnects, SIGNAL(stateChanged(int)), - this, SLOT(checkBoxLimitReconnectsChanged(int))); - - // Maximum Retries - spinBoxMaximumRetries->setValue(profile->getMaximumRetries()); - - - // Stream "public" checkbox - stream_public->setChecked(profile->getStreamPublic()); - - // Stream name - stream_name->setText(profile->getStreamName()); - - // Stream website - stream_website->setText(profile->getStreamWebsite()); - - // Stream description - stream_desc->setText(profile->getStreamDesc()); - - // Stream genre - stream_genre->setText(profile->getStreamGenre()); - // Encoding bitrate combobox QString kbps_pattern = QString("%1 kbps"); QList valid_kpbs; @@ -112,21 +63,9 @@ DlgPrefBroadcast::DlgPrefBroadcast(QWidget *parent, UserSettingsPointer _config) kbps_pattern.arg(QString::number(kbps)), kbps); } - tmp_index = comboBoxEncodingBitrate->findData(profile->getBitrate()); - if (tmp_index < 0) { - tmp_index = comboBoxEncodingBitrate->findData(BROADCAST_BITRATE_128KBPS); - } - comboBoxEncodingBitrate->setCurrentIndex(tmp_index < 0 ? 0 : tmp_index); - // Encoding format combobox comboBoxEncodingFormat->addItem(tr("MP3"), BROADCAST_FORMAT_MP3); comboBoxEncodingFormat->addItem(tr("Ogg Vorbis"), BROADCAST_FORMAT_OV); - tmp_index = comboBoxEncodingFormat->findData(profile->getFormat()); - if (tmp_index < 0) { - // Set default of MP3 if invalid. - tmp_index = 0; - } - comboBoxEncodingFormat->setCurrentIndex(tmp_index); // Encoding channels combobox comboBoxEncodingChannels->addItem(tr("Automatic"), @@ -135,38 +74,26 @@ DlgPrefBroadcast::DlgPrefBroadcast(QWidget *parent, UserSettingsPointer _config) static_cast(EncoderSettings::ChannelMode::MONO)); comboBoxEncodingChannels->addItem(tr("Stereo"), static_cast(EncoderSettings::ChannelMode::STEREO)); - tmp_index = comboBoxEncodingChannels->findData(profile->getChannels()); - if (tmp_index < 0) { // Set default to automatic if invalid. - tmp_index = 0; - } - comboBoxEncodingChannels->setCurrentIndex(tmp_index); - // Metadata format - metadata_format->setText(profile->getMetadataFormat()); + BroadcastProfile* profile = m_settings.getCurrentProfile(); + getValuesFromProfile(profile); - // Static artist - custom_artist->setText(profile->getCustomArtist()); + connect(checkBoxEnableReconnect, SIGNAL(stateChanged(int)), + this, SLOT(checkBoxEnableReconnectChanged(int))); - // Static title - custom_title->setText(profile->getCustomTitle()); + connect(checkBoxLimitReconnects, SIGNAL(stateChanged(int)), + this, SLOT(checkBoxLimitReconnectsChanged(int))); - // "Enable static artist and title" checkbox - bool enableMetadata = profile->getEnableMetadata(); - enableCustomMetadata->setChecked(enableMetadata); - custom_artist->setEnabled(enableMetadata); - custom_title->setEnabled(enableMetadata); connect(enableCustomMetadata, SIGNAL(stateChanged(int)), this, SLOT(enableCustomMetadataChanged(int))); - // "Enable UTF-8 metadata" checkbox - // TODO(rryan): allow arbitrary codecs in the future? - QString charset = profile->getMetadataCharset(); - enableUtf8Metadata->setChecked(charset == "UTF-8"); + // Connect each user input of each groupbox in the values groupbox + // to a local slot which purpose is to determine if changes have been made + // to the values. Used when selecting another profile without saving + // the currently selected one. + enableValueSignals(true); - // OGG "dynamicupdate" checkbox - ogg_dynamicupdate->setChecked(profile->getOggDynamicUpdate()); - - slotApply(); + //slotApply(); } DlgPrefBroadcast::~DlgPrefBroadcast() { @@ -239,7 +166,190 @@ void DlgPrefBroadcast::slotApply() this->setEnabled(true); } - BroadcastProfile* profile = m_settings.getCurrentProfile(); + setValuesToProfile(selectedProfile()); + m_settings.saveAll(); + m_valuesChanged = false; +} + +void DlgPrefBroadcast::broadcastEnabledChanged(double value) { + qDebug() << "DlgPrefBroadcast::broadcastEnabledChanged()" << value; + bool enabled = value == 1.0; // 0 and 2 are disabled + this->setEnabled(!enabled); + enableLiveBroadcasting->setChecked(enabled); +} + +void DlgPrefBroadcast::checkBoxEnableReconnectChanged(int value) { + widgetReconnectControls->setEnabled(value); +} + +void DlgPrefBroadcast::checkBoxLimitReconnectsChanged(int value) { + spinBoxMaximumRetries->setEnabled(value); +} + +void DlgPrefBroadcast::enableCustomMetadataChanged(int value) { + custom_artist->setEnabled(value); + custom_title->setEnabled(value); +} + +void DlgPrefBroadcast::btnCreateProfileClicked(bool) { + BroadcastProfile* newProf = m_settings.newProfile(); + if(newProf == nullptr) { + QMessageBox::warning(this, QObject::tr("Profile already exists"), + QObject::tr("An Untitled Profile already exists")); + } +} + +void DlgPrefBroadcast::profileListItemSelected(const QModelIndex& index) { + if(m_pProfileListSelection) { + QString title = QObject::tr("Unsaved changes"); + QString msg = + QString(kUnsavedChangesWarning) + .arg(m_pProfileListSelection->getProfileName()); + + QMessageBox::StandardButton reply = + QMessageBox::question(this, title, msg, + QMessageBox::Yes | QMessageBox::No); + if(reply == QMessageBox::Yes) { + m_settings.saveProfile(m_pProfileListSelection); + } + } + + QString selectedName = m_settings.data(index, Qt::DisplayRole).toString(); + BroadcastProfile* profile = m_settings.getProfileByName(selectedName); + if(profile) { + // Set values in form + getValuesFromProfile(profile); + } + + m_pProfileListSelection = profile; +} + +BroadcastProfile* DlgPrefBroadcast::selectedProfile() { + return m_pProfileListSelection; +} + +void DlgPrefBroadcast::getValuesFromProfile(BroadcastProfile* profile) { + if(!profile) + return; + + enableValueSignals(false); + + // Set groupbox header + QString headerText = + QString(QObject::tr(kSettingsGroupHeader)) + .arg(profile->getProfileName()); + groupBoxProfileSettings->setTitle(headerText); + + // Server type combo list + int tmp_index = comboBoxServerType->findData(profile->getServertype()); + if (tmp_index < 0) { // Set default if invalid. + tmp_index = 0; + } + comboBoxServerType->setCurrentIndex(tmp_index); + + // Mountpoint + mountpoint->setText(profile->getMountpoint()); + + // Host + host->setText(profile->getHost()); + + // Port + QString portString = QString::number(profile->getPort()); + port->setText(portString); + + // Login + login->setText(profile->getLogin()); + + // Password + password->setText(profile->getPassword()); + + // Enable automatic reconnect + bool enableReconnect = profile->getEnableReconnect(); + checkBoxEnableReconnect->setChecked(enableReconnect); + widgetReconnectControls->setEnabled(enableReconnect); + + // Wait until first attempt + spinBoxFirstDelay->setValue(profile->getReconnectFirstDelay()); + + // Retry Delay + spinBoxReconnectPeriod->setValue(profile->getReconnectPeriod()); + + // Use Maximum Retries + bool limitConnects = profile->getLimitReconnects(); + checkBoxLimitReconnects->setChecked( + limitConnects); + spinBoxMaximumRetries->setEnabled(limitConnects); + + // Maximum Retries + spinBoxMaximumRetries->setValue(profile->getMaximumRetries()); + + // Stream "public" checkbox + stream_public->setChecked(profile->getStreamPublic()); + + // Stream name + stream_name->setText(profile->getStreamName()); + + // Stream website + stream_website->setText(profile->getStreamWebsite()); + + // Stream description + stream_desc->setText(profile->getStreamDesc()); + + // Stream genre + stream_genre->setText(profile->getStreamGenre()); + + // Encoding bitrate combobox + tmp_index = comboBoxEncodingBitrate->findData(profile->getBitrate()); + if (tmp_index < 0) { + tmp_index = comboBoxEncodingBitrate->findData(BROADCAST_BITRATE_128KBPS); + } + comboBoxEncodingBitrate->setCurrentIndex(tmp_index < 0 ? 0 : tmp_index); + + // Encoding format combobox + tmp_index = comboBoxEncodingFormat->findData(profile->getFormat()); + if (tmp_index < 0) { + // Set default of MP3 if invalid. + tmp_index = 0; + } + comboBoxEncodingFormat->setCurrentIndex(tmp_index); + + // Encoding channels combobox + tmp_index = comboBoxEncodingChannels->findData(profile->getChannels()); + if (tmp_index < 0) { // Set default to automatic if invalid. + tmp_index = 0; + } + comboBoxEncodingChannels->setCurrentIndex(tmp_index); + + // Metadata format + metadata_format->setText(profile->getMetadataFormat()); + + // Static artist + custom_artist->setText(profile->getCustomArtist()); + + // Static title + custom_title->setText(profile->getCustomTitle()); + + // "Enable static artist and title" checkbox + bool enableMetadata = profile->getEnableMetadata(); + enableCustomMetadata->setChecked(enableMetadata); + custom_artist->setEnabled(enableMetadata); + custom_title->setEnabled(enableMetadata); + + // "Enable UTF-8 metadata" checkbox + // TODO(rryan): allow arbitrary codecs in the future? + QString charset = profile->getMetadataCharset(); + enableUtf8Metadata->setChecked(charset == "UTF-8"); + + // OGG "dynamicupdate" checkbox + ogg_dynamicupdate->setChecked(profile->getOggDynamicUpdate()); + + m_valuesChanged = false; + enableValueSignals(true); +} + +void DlgPrefBroadcast::setValuesToProfile(BroadcastProfile* profile) { + if(!profile) + return; // Combo boxes, make sure to load their data not their display strings. profile->setServertype(comboBoxServerType->itemData( @@ -288,26 +398,40 @@ void DlgPrefBroadcast::slotApply() profile->setCustomTitle(custom_title->text()); profile->setMetadataFormat(metadata_format->text()); - m_settings.saveAll(); + m_valuesChanged = false; } -void DlgPrefBroadcast::broadcastEnabledChanged(double value) { - qDebug() << "DlgPrefBroadcast::broadcastEnabledChanged()" << value; - bool enabled = value == 1.0; // 0 and 2 are disabled - this->setEnabled(!enabled); - enableLiveBroadcasting->setChecked(enabled); - -} - -void DlgPrefBroadcast::checkBoxEnableReconnectChanged(int value) { - widgetReconnectControls->setEnabled(value); +void DlgPrefBroadcast::formValueChanged() { + m_valuesChanged = true; } -void DlgPrefBroadcast::checkBoxLimitReconnectsChanged(int value) { - spinBoxMaximumRetries->setEnabled(value); +void DlgPrefBroadcast::enableValueSignals(bool enable) { + QMetaMethod valueChangedSlot = metaObject()->method( + metaObject()->indexOfSlot("formValueChanged()")); + + kLogger.info() << QString("--- ---"); + + QList subGroups = + groupBoxProfileSettings->findChildren(); + for(QGroupBox* subGroup : subGroups) { + kLogger.info() << QString("---"); + + QList childs = subGroup->findChildren(); + for(QWidget* child : childs) { + const QMetaObject* metaObj = child->metaObject(); + QMetaProperty userProp = metaObj->userProperty(); + + kLogger.info() << QString(metaObj->className()); + + if(userProp.isValid() && userProp.hasNotifySignal()) { + if(enable) + connect(child, userProp.notifySignal(), + this, valueChangedSlot); + else + disconnect(child, userProp.notifySignal(), + this, valueChangedSlot); + } + } + } } -void DlgPrefBroadcast::enableCustomMetadataChanged(int value) { - custom_artist->setEnabled(value); - custom_title->setEnabled(value); -} diff --git a/src/preferences/dialog/dlgprefbroadcast.h b/src/preferences/dialog/dlgprefbroadcast.h index 2f1fc4d24208..de6baa0a6836 100644 --- a/src/preferences/dialog/dlgprefbroadcast.h +++ b/src/preferences/dialog/dlgprefbroadcast.h @@ -2,6 +2,7 @@ #define DLGPREFBROADCAST_H #include +#include #include "preferences/dialog/ui_dlgprefbroadcastdlg.h" #include "control/controlobject.h" @@ -27,13 +28,25 @@ class DlgPrefBroadcast : public DlgPreferencePage, public Ui::DlgPrefBroadcastDl void checkBoxEnableReconnectChanged(int value); void checkBoxLimitReconnectsChanged(int value); void enableCustomMetadataChanged(int value); + void btnCreateProfileClicked(bool checked); + void profileListItemSelected(const QModelIndex& index); signals: void apply(const QString &); + private slots: + void formValueChanged(); + private: + BroadcastProfile* selectedProfile(); + void getValuesFromProfile(BroadcastProfile* profile); + void setValuesToProfile(BroadcastProfile* profile); + void enableValueSignals(bool enable = true); + BroadcastSettings m_settings; ControlProxy* m_pBroadcastEnabled; + BroadcastProfile* m_pProfileListSelection; + bool m_valuesChanged; }; #endif diff --git a/src/preferences/dialog/dlgprefbroadcastdlg.ui b/src/preferences/dialog/dlgprefbroadcastdlg.ui index 772a770f3131..3a4601da9dec 100644 --- a/src/preferences/dialog/dlgprefbroadcastdlg.ui +++ b/src/preferences/dialog/dlgprefbroadcastdlg.ui @@ -27,7 +27,7 @@ - Settings for "Default Profile" + Settings for profile "%s"