diff --git a/build/depends.py b/build/depends.py index 6e0dee6ecc72..74b356262e3b 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/encoder/encoderbroadcastsettings.cpp b/src/encoder/encoderbroadcastsettings.cpp index 19f861fe52d8..a2235da7452f 100644 --- a/src/encoder/encoderbroadcastsettings.cpp +++ b/src/encoder/encoderbroadcastsettings.cpp @@ -10,9 +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); @@ -26,41 +25,40 @@ 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_pSettings->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_pSettings->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 = m_pSettings->getCurrentProfile(); + + int bitrate = profile->getBitrate(); if (m_qualList.contains(bitrate)) { return bitrate; } @@ -70,18 +68,21 @@ 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_pSettings->getCurrentProfile(); + profile->setChannels(static_cast(mode)); } -EncoderSettings::ChannelMode EncoderBroadcastSettings::getChannelMode() const -{ - switch(m_settings.getChannels()) { + +EncoderSettings::ChannelMode EncoderBroadcastSettings::getChannelMode() const { + BroadcastProfile* profile = m_pSettings->getCurrentProfile(); + + switch(profile->getChannels()) { case 1: return EncoderSettings::ChannelMode::MONO; case 2: return EncoderSettings::ChannelMode::STEREO; case 0: // fallthrough 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 b01a2b57e3d1..a05e39a89957 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; @@ -364,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.cpp b/src/preferences/broadcastprofile.cpp new file mode 100644 index 000000000000..f0fd439c1acf --- /dev/null +++ b/src/preferences/broadcastprofile.cpp @@ -0,0 +1,463 @@ +// broadcastprofile.cpp +// Created June 2nd 2017 by Stéphane Lepin + +#include +#include +#include +#include +#include +#include "util/xml.h" +#include "broadcast/defs_broadcast.h" +#include "defs_urls.h" + +#include "broadcastprofile.h" + +namespace { +const char* kDoctype = "broadcastprofile"; +const char* kDocumentRoot = "BroadcastProfile"; +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; +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 QRegExp kForbiddenChars = QRegExp("[<>:\"/\\\|\?\*]"); +} // anonymous namespace + +BroadcastProfile::BroadcastProfile(const QString& profileName) { + setDefaultValues(); + setProfileName(profileName); +} + +bool BroadcastProfile::checkNameCompliance(const QString& str) { + return str.contains(kForbiddenChars); +} + +BroadcastProfile* BroadcastProfile::loadFromFile(const QString& filename) { + QFileInfo xmlFile(filename); + if(!xmlFile.exists()) + return nullptr; + + QString profileName = xmlFile.baseName(); + + BroadcastProfile* profile = new BroadcastProfile(profileName); + profile->loadValues(filename); + + return profile; +} + +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(const QString& filename) { + QDomElement doc = XmlParse::openXMLFile(filename, kDoctype); + + m_enabled = (bool)XmlParse::selectNodeInt(doc, kEnabled); + + 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(doc, kEnableReconnect); + m_reconnectPeriod = + XmlParse::selectNodeDouble(doc, kReconnectPeriod); + + m_limitReconnects = + (bool)XmlParse::selectNodeInt(doc, kLimitReconnects); + m_maximumRetries = + XmlParse::selectNodeInt(doc, kMaximumRetries); + + m_noDelayFirstReconnect = + (bool)XmlParse::selectNodeInt(doc, kNoDelayFirstReconnect); + m_reconnectFirstDelay = + 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(doc, kMetadataFormat); +} + +void BroadcastProfile::save(const QString& filename) { + QDomDocument doc(kDoctype); + QDomElement docRoot = doc.createElement(kDocumentRoot); + + XmlParse::addElement(doc, docRoot, + kEnabled, QString::number((int)m_enabled)); + + XmlParse::addElement(doc, docRoot, kHost, m_host); + 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, + QString::number((int)m_enableReconnect)); + XmlParse::addElement(doc, docRoot, kReconnectPeriod, + QString::number(m_reconnectPeriod)); + + XmlParse::addElement(doc, docRoot, kLimitReconnects, + QString::number((int)m_limitReconnects)); + XmlParse::addElement(doc, docRoot, kMaximumRetries, + QString::number(m_maximumRetries)); + + 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, + QString::number((int)m_streamPublic)); + XmlParse::addElement(doc, docRoot, kStreamWebsite, m_streamWebsite); + + XmlParse::addElement(doc, docRoot, kFormat, m_format); + XmlParse::addElement(doc, docRoot, kBitrate, + QString::number(m_bitrate)); + XmlParse::addElement(doc, docRoot, kChannels, + QString::number(m_channels)); + + 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, + QString::number((int)m_oggDynamicUpdate)); + + doc.appendChild(docRoot); + + QFile xmlFile(filename); + xmlFile.open(QIODevice::WriteOnly | QIODevice::Text); + + QTextStream fileStream(&xmlFile); + doc.save(fileStream, 4); + xmlFile.close(); +} + +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; +} + +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() const { + 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..47343cccc372 --- /dev/null +++ b/src/preferences/broadcastprofile.h @@ -0,0 +1,148 @@ +// 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(const QString& filename); + + static BroadcastProfile* loadFromFile( + const QString& filename); + static bool checkNameCompliance(const QString& str); + + bool hasUnsavedChanges() { + return m_hasUnsavedChanges; + } + + 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(const QString& filename); + void defaultValues(); + + bool m_hasUnsavedChanges; + + 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 diff --git a/src/preferences/broadcastsettings.cpp b/src/preferences/broadcastsettings.cpp index 8f2185596d39..98b633fa627a 100644 --- a/src/preferences/broadcastsettings.cpp +++ b/src/preferences/broadcastsettings.cpp @@ -1,417 +1,190 @@ +#include +#include +#include +#include + +#include "util/logger.h" #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 QString kDefaultProfile = QObject::tr("Untitled Profile"); +const mixxx::Logger kLogger("BroadcastSettings"); } // 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()); +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(); } -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()); -} - -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()); +BroadcastSettings::~BroadcastSettings() { + for(BroadcastProfile* profile : m_profiles) { + delete profile; + } } -void BroadcastSettings::setOggDynamicUpdate(bool value) { - m_pConfig->setValue(ConfigKey(kConfigKey, kOggDynamicUpdate), value); -} +void BroadcastSettings::loadProfiles() { + QDir profilesFolder(getProfilesFolder()); + if(!profilesFolder.exists()) { + kLogger.warning() + << "Profiles folder doesn't exist. Creating it."; -bool BroadcastSettings::getDefaultOggDynamicUpdate() const { - return kDefaultOggDynamicupdate; -} + // TODO(Palakis, June 9th 2017): + // Is there a better way to do this? + profilesFolder.mkpath(profilesFolder.absolutePath()); + } -QString BroadcastSettings::getPassword() const { - return m_pConfig->getValue( - ConfigKey(kConfigKey, kPassword), getDefaultPassword()); + QStringList nameFilters("*.bcp.xml"); + QFileInfoList files = + profilesFolder.entryInfoList(nameFilters, QDir::Files, QDir::Name); + + if(files.count() > 0) { + kLogger.warning() << "Found " << files.count() << " profiles."; + // Load profiles from filesystem + for(QFileInfo fileInfo : files) { + BroadcastProfile* profile = + BroadcastProfile::loadFromFile(fileInfo.absoluteFilePath()); + + if(profile) + addProfile(profile); + } + } else { + kLogger.warning() + << "No profiles found. Creating default profile."; + + // Create default profile + BroadcastProfile* defaultProfile = newProfile(); + setCurrentProfile(defaultProfile); + } } -void BroadcastSettings::setPassword(const QString& value) { - m_pConfig->setValue(ConfigKey(kConfigKey, kPassword), value); -} +BroadcastProfile* BroadcastSettings::newProfile() { + QFileInfo xmlFile(filenameForProfile(kDefaultProfile)); -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(); + if(!xmlFile.exists()) { + BroadcastProfile* profile = new BroadcastProfile(kDefaultProfile); + saveProfile(profile); + addProfile(profile); + return profile; } - return port; -} - -void BroadcastSettings::setPort(int value) { - m_pConfig->setValue(ConfigKey(kConfigKey, kPort), value); + return nullptr; } -int BroadcastSettings::getDefaultPort() const { - return BROADCAST_DEFAULT_PORT; -} +void BroadcastSettings::saveProfile(BroadcastProfile* profile) { + if(!profile) + return; -double BroadcastSettings::getReconnectFirstDelay() const { - return m_pConfig->getValue( - ConfigKey(kConfigKey, kReconnectFirstDelay), - getDefaultReconnectFirstDelay()); + profile->save(filenameForProfile(profile)); } -void BroadcastSettings::setReconnectFirstDelay(double value) { - m_pConfig->setValue(ConfigKey(kConfigKey, kReconnectFirstDelay), value); +QString BroadcastSettings::filenameForProfile(const QString& profileName) { + QString filename = profileName + QString(".bcp.xml"); + return QDir(getProfilesFolder()).absoluteFilePath(filename); } -double BroadcastSettings::getDefaultReconnectFirstDelay() const { - return kDefaultReconnectFirstDelay; -} +QString BroadcastSettings::filenameForProfile(BroadcastProfile* profile) { + if(!profile) + return QString(); -double BroadcastSettings::getReconnectPeriod() const { - return m_pConfig->getValue( - ConfigKey(kConfigKey, kReconnectPeriod), - getDefaultReconnectPeriod()); + return filenameForProfile(profile->getProfileName()); } -void BroadcastSettings::setReconnectPeriod(double value) { - m_pConfig->setValue(ConfigKey(kConfigKey, kReconnectPeriod), value); +QString BroadcastSettings::getProfilesFolder() { + QString profilesPath(m_pConfig->getSettingsPath()); + profilesPath.append(QDir::separator() + QString(kProfilesSubfolder)); + return profilesPath; } -double BroadcastSettings::getDefaultReconnectPeriod() const { - return kDefaultReconnectPeriod; -} +bool BroadcastSettings::addProfile(BroadcastProfile *profile) { + if(profile) { + int position = m_profiles.size(); -QString BroadcastSettings::getServertype() const { - return m_pConfig->getValue( - ConfigKey(kConfigKey, kServertype), getDefaultServertype()); -} + beginInsertRows(QModelIndex(), position, position); + m_profiles.push_back(profile); + endInsertRows(); -void BroadcastSettings::setServertype(const QString& value) { - m_pConfig->set(ConfigKey(kConfigKey, kServertype), - ConfigValue(value)); + return true; + } + return false; } -QString BroadcastSettings::getDefaultServertype() const { - return QString(); -} +void BroadcastSettings::setCurrentProfile(BroadcastProfile *profile) { + if(!profile) + return; -QString BroadcastSettings::getStreamDesc() const { - return m_pConfig->getValue( - ConfigKey(kConfigKey, kStreamDesc), - getDefaultStreamDesc()); + QString profileName = profile->getProfileName(); + m_pConfig->setValue(ConfigKey(kConfigKey, kCurrentProfile), profileName); } -void BroadcastSettings::setStreamDesc(const QString& value) { - m_pConfig->setValue(ConfigKey(kConfigKey, kStreamDesc), value); +BroadcastProfile* BroadcastSettings::getCurrentProfile() { + QString currentProfile = m_pConfig->getValue( + ConfigKey(kConfigKey, kCurrentProfile), + kDefaultProfile); + return getProfileByName(currentProfile); } -QString BroadcastSettings::getDefaultStreamDesc() const { - return kDefaultStreamDesc; +BroadcastProfile* BroadcastSettings::getProfileByName(const QString& profileName) { + for(BroadcastProfile* profile : m_profiles) { + if(profile && profile->getProfileName() == profileName) + return profile; + } + return nullptr; } -QString BroadcastSettings::getStreamGenre() const { - return m_pConfig->getValue( - ConfigKey(kConfigKey, kStreamGenre), - getDefaultStreamGenre()); +void BroadcastSettings::saveAll() { + for(BroadcastProfile* profile : m_profiles) { + if(profile) + saveProfile(profile); + } } -void BroadcastSettings::setStreamGenre(const QString& value) { - m_pConfig->setValue(ConfigKey(kConfigKey, kStreamGenre), value); -} +void BroadcastSettings::renameProfile(BroadcastProfile* profile, + const QString& newName) { -QString BroadcastSettings::getDefaultStreamGenre() const { - return kDefaultStreamGenre; } -QString BroadcastSettings::getStreamName() const { - return m_pConfig->getValue( - ConfigKey(kConfigKey, kStreamName), - getDefaultStreamName()); -} +void BroadcastSettings::deleteProfile(BroadcastProfile* profile) { + if(!profile) + return; -void BroadcastSettings::setStreamName(const QString& value) { - m_pConfig->setValue(ConfigKey(kConfigKey, kStreamName), value); -} + QFileInfo xmlFile(filenameForProfile(profile)); + if(xmlFile.exists()) + QFile::remove(xmlFile.absolutePath()); -QString BroadcastSettings::getDefaultStreamName() const { - return QString(); + m_profiles.removeAll(profile); } -bool BroadcastSettings::getStreamPublic() const { - return m_pConfig->getValue( - ConfigKey(kConfigKey, kStreamPublic), getDefaultStreamPublic()); +int BroadcastSettings::rowCount(const QModelIndex &parent) const { + return m_profiles.size(); } -void BroadcastSettings::setStreamPublic(bool value) { - m_pConfig->setValue(ConfigKey(kConfigKey, kStreamPublic), value); -} +QVariant BroadcastSettings::data(const QModelIndex &index, int role) const { + int rowIndex = index.row(); -bool BroadcastSettings::getDefaultStreamPublic() const { - return kDefaultStreamPublic; -} + if(!index.isValid() + || rowIndex >= m_profiles.size()) + return QVariant(); -QString BroadcastSettings::getStreamWebsite() const { - return m_pConfig->getValue( - ConfigKey(kConfigKey, kStreamWebsite), getDefaultStreamWebsite()); + if(role == Qt::DisplayRole) + return m_profiles.at(rowIndex)->getProfileName(); + else + return QVariant(); } -void BroadcastSettings::setStreamWebsite(const QString& value) { - m_pConfig->setValue(ConfigKey(kConfigKey, kStreamWebsite), value); -} +/*QVariant BroadcastSettings::headerData(int section, Qt::Orientation orientation, + int role = Qt::DisplayRole) { -QString BroadcastSettings::getDefaultStreamWebsite() const { - return MIXXX_WEBSITE_URL; -} +}*/ diff --git a/src/preferences/broadcastsettings.h b/src/preferences/broadcastsettings.h index 9c759bed5b3a..195ffcb65d86 100644 --- a/src/preferences/broadcastsettings.h +++ b/src/preferences/broadcastsettings.h @@ -1,97 +1,49 @@ #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 : public QAbstractListModel { + Q_OBJECT -class BroadcastSettings { 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 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; + 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(); + 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; + QString m_currentProfile; }; #endif /* PREFERENCES_BROADCASTSETTINGS_H */ diff --git a/src/preferences/dialog/dlgprefbroadcast.cpp b/src/preferences/dialog/dlgprefbroadcast.cpp index f22c03c1b4f0..1f5919c57fa9 100644 --- a/src/preferences/dialog/dlgprefbroadcast.cpp +++ b/src/preferences/dialog/dlgprefbroadcast.cpp @@ -1,22 +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); + 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()); @@ -26,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(m_settings.getServertype()); - if (tmp_index < 0) { // Set default if invalid. - tmp_index = 0; - } - comboBoxServerType->setCurrentIndex(tmp_index); - - // Mountpoint - mountpoint->setText(m_settings.getMountpoint()); - - // Host - host->setText(m_settings.getHost()); - - // Port - QString portString = QString::number(m_settings.getPort()); - port->setText(portString); - - // Login - login->setText(m_settings.getLogin()); - - // Password - password->setText(m_settings.getPassword()); - - - // Enable automatic reconnect - bool enableReconnect = m_settings.getEnableReconnect(); - checkBoxEnableReconnect->setChecked(enableReconnect); - widgetReconnectControls->setEnabled(enableReconnect); - connect(checkBoxEnableReconnect, SIGNAL(stateChanged(int)), - this, SLOT(checkBoxEnableReconnectChanged(int))); - - - // Wait until first attempt - spinBoxFirstDelay->setValue(m_settings.getReconnectFirstDelay()); - - // Retry Delay - spinBoxReconnectPeriod->setValue(m_settings.getReconnectPeriod()); - - // Use Maximum Retries - bool limitConnects = m_settings.getLimitReconnects(); - checkBoxLimitReconnects->setChecked( - limitConnects); - spinBoxMaximumRetries->setEnabled(limitConnects); - connect(checkBoxLimitReconnects, SIGNAL(stateChanged(int)), - this, SLOT(checkBoxLimitReconnectsChanged(int))); - - // Maximum Retries - spinBoxMaximumRetries->setValue(m_settings.getMaximumRetries()); - - - // Stream "public" checkbox - stream_public->setChecked(m_settings.getStreamPublic()); - - // Stream name - stream_name->setText(m_settings.getStreamName()); - - // Stream website - stream_website->setText(m_settings.getStreamWebsite()); - - // Stream description - stream_desc->setText(m_settings.getStreamDesc()); - - // Stream genre - stream_genre->setText(m_settings.getStreamGenre()); - // Encoding bitrate combobox QString kbps_pattern = QString("%1 kbps"); QList valid_kpbs; @@ -110,21 +63,9 @@ DlgPrefBroadcast::DlgPrefBroadcast(QWidget *parent, UserSettingsPointer _config) kbps_pattern.arg(QString::number(kbps)), kbps); } - tmp_index = comboBoxEncodingBitrate->findData(m_settings.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(m_settings.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"), @@ -133,80 +74,70 @@ 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()); - 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()); + BroadcastProfile* profile = m_settings.getCurrentProfile(); + getValuesFromProfile(profile); - // Static artist - custom_artist->setText(m_settings.getCustomArtist()); + connect(checkBoxEnableReconnect, SIGNAL(stateChanged(int)), + this, SLOT(checkBoxEnableReconnectChanged(int))); - // Static title - custom_title->setText(m_settings.getCustomTitle()); + connect(checkBoxLimitReconnects, SIGNAL(stateChanged(int)), + this, SLOT(checkBoxLimitReconnectsChanged(int))); - // "Enable static artist and title" checkbox - bool enableMetadata = m_settings.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 = m_settings.getMetadataCharset(); - enableUtf8Metadata->setChecked(charset == "UTF-8"); - - // OGG "dynamicupdate" checkbox - ogg_dynamicupdate->setChecked(m_settings.getOggDynamicUpdate()); + // 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); - slotApply(); + //slotApply(); } 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,71 +166,272 @@ void DlgPrefBroadcast::slotApply() this->setEnabled(true); } + 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. - 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()); -} - -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); + profile->setEnableMetadata(enableCustomMetadata->isChecked()); + profile->setCustomArtist(custom_artist->text()); + profile->setCustomTitle(custom_title->text()); + profile->setMetadataFormat(metadata_format->text()); + m_valuesChanged = false; } -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 bd663fc00f37..3a4601da9dec 100644 --- a/src/preferences/dialog/dlgprefbroadcastdlg.ui +++ b/src/preferences/dialog/dlgprefbroadcastdlg.ui @@ -7,26 +7,13 @@ 0 0 692 - 581 + 683 Live Broadcasting Preferences - - - - - Qt::Vertical - - - - 20 - 40 - - - - + @@ -37,602 +24,678 @@ - - + + - Server connection + Settings for profile "%s" - + + + + + 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 + + + padding: 4px 7px 4px 7px; - - custom_artist - - - - - - - %mainartist - - - - - - Static title - - - custom_title + Create new profile - - - - %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. + + + + Qt::Horizontal - - - - - - Use static artist and title. + + QSizePolicy::Expanding - - true + + + 40 + 20 + - + - - - - 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 + + +