diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json
index 568931e074..8b33fede2e 100644
--- a/domain-server/resources/describe-settings.json
+++ b/domain-server/resources/describe-settings.json
@@ -67,10 +67,44 @@
"label": "Audio",
"assignment-types": [0],
"settings": [
+ {
+ "name": "zones",
+ "type": "table",
+ "label": "Zones",
+ "help": "In this table you can define a set of zones in which you can specify various audio properties.",
+ "number": false,
+ "can_add": true,
+ "can_delete": true,
+ "key": {
+ "name": "name",
+ "label": "Name",
+ "placeholder": "Zone name"
+ },
+ "columns": [
+ {
+ "name": "x_range",
+ "label": "X range",
+ "can_set": true,
+ "placeholder": "0-16384"
+ },
+ {
+ "name": "y_range",
+ "label": "Y range",
+ "can_set": true,
+ "placeholder": "0-16384"
+ },
+ {
+ "name": "z_range",
+ "label": "Z range",
+ "can_set": true,
+ "placeholder": "0-16384"
+ }
+ ]
+ },
{
"name": "enable_filter",
"type": "checkbox",
- "label": "Enable Positional Filter",
+ "label": "Positional filter",
"help": "positional audio stream uses lowpass filter",
"default": true
},
diff --git a/domain-server/resources/web/js/settings.js b/domain-server/resources/web/js/settings.js
index fb6901b34d..d6646a87da 100644
--- a/domain-server/resources/web/js/settings.js
+++ b/domain-server/resources/web/js/settings.js
@@ -25,10 +25,12 @@ var viewHelpers = {
form_group += ""
form_group += "
"
form_group += "";
form_group += "
"
+ } else if (setting.type === 'table') {
+ form_group += makeTable(setting, setting_name, setting_value);
} else {
input_type = _.has(setting, 'type') ? setting.type : "text"
@@ -39,7 +41,7 @@ var viewHelpers = {
_.each(setting.options, function(option) {
form_group += ""
+ (option.value == setting_value ? 'selected' : '') + ">" + option.label + ""
})
form_group += ""
@@ -74,17 +76,101 @@ $(document).ready(function(){
*/
$('[data-clampedwidth]').each(function () {
- var elem = $(this);
- var parentPanel = elem.data('clampedwidth');
- var resizeFn = function () {
- var sideBarNavWidth = $(parentPanel).width() - parseInt(elem.css('paddingLeft')) - parseInt(elem.css('paddingRight')) - parseInt(elem.css('marginLeft')) - parseInt(elem.css('marginRight')) - parseInt(elem.css('borderLeftWidth')) - parseInt(elem.css('borderRightWidth'));
- elem.css('width', sideBarNavWidth);
- };
+ var elem = $(this);
+ var parentPanel = elem.data('clampedwidth');
+ var resizeFn = function () {
+ var sideBarNavWidth = $(parentPanel).width() - parseInt(elem.css('paddingLeft')) - parseInt(elem.css('paddingRight')) - parseInt(elem.css('marginLeft')) - parseInt(elem.css('marginRight')) - parseInt(elem.css('borderLeftWidth')) - parseInt(elem.css('borderRightWidth'));
+ elem.css('width', sideBarNavWidth);
+ };
- resizeFn();
- $(window).resize(resizeFn);
+ resizeFn();
+ $(window).resize(resizeFn);
})
-
+
+ $('#settings-form').on('click', '.add-row', function(){
+ var row = $(this).parents("tr")
+ var data = row.parent().children(".row-data")
+
+ // Check key spaces
+ var name = row.children(".key").children("input").val()
+ if (name.indexOf(' ') !== -1) {
+ showAlertMessage("Key contains spaces", false)
+ return
+ }
+ // Check keys with the same name
+ var equals = false;
+ _.each(data.children(".key"), function(element) {
+ if ($(element).text() === name) {
+ equals = true
+ return
+ }
+ })
+ if (equals) {
+ showAlertMessage("Two keys cannot be identical.", false)
+ return
+ }
+
+ // Check empty fields
+ var empty = false;
+ _.each(row.children(".row-data").children("input"), function(element) {
+ if ($(element).val().length === 0) {
+ empty = true
+ return
+ }
+ })
+ if (empty) {
+ showAlertMessage("Empty field(s)")
+ return
+ }
+
+ var input_clone = row.clone()
+ // Change input row to data row
+ var full_name = row.parents("table").attr("name") + "." + name
+ row.attr("class", "row-data")
+
+ _.each(row.children(), function(element) {
+ if ($(element).hasClass("number")) { // Index row
+ var numbers = data.children(".number")
+ if (numbers.length > 0) {
+ $(element).html(parseInt(numbers.last().text()) + 1)
+ } else {
+ $(element).html(1)
+ }
+ } else if ($(element).hasClass("buttons")) { // Change buttons
+ var prevSpan = $(element).parent().prev().children(".buttons").children("span")
+ var span = $(element).children("span")
+ if (prevSpan.hasClass("del-row")) {
+ span.removeClass("glyphicon-ok add-row")
+ span.addClass("glyphicon-remove del-row")
+ } else {
+ span.remove()
+ }
+ } else if ($(element).hasClass("key")) {
+ var input = $(element).children("input")
+ $(element).html(input.val())
+ input.remove()
+ } else if($(element).hasClass("row-data")) { // Hide inputs
+ var input = $(element).children("input")
+ input.attr("type", "hidden")
+ input.attr("name", full_name + "." + $(element).attr("name"))
+ input.attr("value", input.val())
+ input.attr("data-changed", "true")
+
+ $(element).html($(element).html() + input.val())
+ } else {
+ console.log("Unknown table element")
+ }
+ })
+ row.parent().append(input_clone)
+ showAlertMessage("Row added", true)
+ })
+
+ $('#settings-form').on('click', '.del-row', function(){
+ var row = $(this).parents("tr")
+ row.empty()
+ row.html("");
+ })
+
$('#settings-form').on('change', 'input', function(){
// this input was changed, add the changed data attribute to it
$(this).attr('data-changed', true)
@@ -94,7 +180,7 @@ $(document).ready(function(){
$('#advanced-toggle-button').click(function(){
Settings.showAdvanced = !Settings.showAdvanced
- var advancedSelector = $('.advanced-setting')
+ var advancedSelector = $('.advanced-setting')
if (Settings.showAdvanced) {
advancedSelector.show()
@@ -193,6 +279,82 @@ $('body').on('click', '.save-button', function(e){
return false;
});
+function makeTable(setting, setting_name, setting_value) {
+ var html = ""
+ html += "
" + setting.label + "
"
+ html += "
"
+ html += "
" + setting.help + "
"
+ html += "
"
+ html += "
"
+
+ // Column names
+ html += ""
+
+ // Rows
+ var row_num = 1
+ _.each(setting_value, function(row, name) {
+ html += ""
+ if (setting.number === true) {
+ html += "" + row_num + " | "
+ }
+ html += "" + name + " | "
+ _.each(setting.columns, function(col) {
+ html += ""
+ if (row.hasOwnProperty(col.name)) {
+ html += row[col.name]
+ }
+ html += " | "
+ })
+ if (setting.can_delete === true) {
+ html += " | "
+ } else if (setting.can_add === true) {
+ html += " | "
+ }
+ html += "
"
+ row_num++
+ })
+
+ // Inputs
+ if (setting.can_add === true) {
+ html += makeTableInputs(setting)
+ }
+
+ html += "
"
+ html += "
"
+
+ return html;
+}
+
+function makeTableInputs(setting) {
+ var html = ""
+ if (setting.number === true) {
+ html += " | "
+ }
+ html += "\
+ \
+ | "
+ _.each(setting.columns, function(col) {
+ html += "\
+ \
+ | "
+ })
+ html += " | "
+ html += "
"
+
+ return html
+}
+
function badgeSidebarForDifferences(changedInput) {
// figure out which group this input is in
var panelParentID = changedInput.closest('.panel').attr('id')
@@ -242,7 +404,7 @@ function showRestartModal() {
}, 1000);
}
-function cleanupFormValues(node) {
+function cleanupFormValues(node) {
if (node.type && node.type === 'checkbox') {
return { name: node.name, value: node.checked ? true : false };
} else {
diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp
index 7c92f1cc51..6a63168579 100644
--- a/domain-server/src/DomainServerSettingsManager.cpp
+++ b/domain-server/src/DomainServerSettingsManager.cpp
@@ -29,6 +29,7 @@ const QString SETTINGS_DESCRIPTION_RELATIVE_PATH = "/resources/describe-settings
const QString DESCRIPTION_SETTINGS_KEY = "settings";
const QString SETTING_DEFAULT_KEY = "default";
const QString DESCRIPTION_NAME_KEY = "name";
+const QString SETTING_DESCRIPTION_TYPE_KEY = "type";
DomainServerSettingsManager::DomainServerSettingsManager() :
_descriptionArray(),
@@ -232,66 +233,92 @@ QJsonObject DomainServerSettingsManager::responseObjectForType(const QString& ty
return responseObject;
}
+bool DomainServerSettingsManager::settingExists(const QString& groupName, const QString& settingName,
+ const QJsonArray& descriptionArray, QJsonValue& settingDescription) {
+ foreach(const QJsonValue& groupValue, descriptionArray) {
+ QJsonObject groupObject = groupValue.toObject();
+ if (groupObject[DESCRIPTION_NAME_KEY].toString() == groupName) {
+
+ foreach(const QJsonValue& settingValue, groupObject[DESCRIPTION_SETTINGS_KEY].toArray()) {
+ QJsonObject settingObject = settingValue.toObject();
+ if (settingObject[DESCRIPTION_NAME_KEY].toString() == settingName) {
+ settingDescription = settingObject[SETTING_DEFAULT_KEY];
+ return true;
+ }
+ }
+ }
+ }
+ settingDescription = QJsonValue::Undefined;
+ return false;
+}
-const QString SETTING_DESCRIPTION_TYPE_KEY = "type";
+void DomainServerSettingsManager::updateSetting(const QString& key, const QJsonValue& newValue, QVariantMap& settingMap,
+ const QJsonValue& settingDescription) {
+ if (newValue.isString()) {
+ if (newValue.toString().isEmpty()) {
+ // this is an empty value, clear it in settings variant so the default is sent
+ settingMap.remove(key);
+ } else {
+ // make sure the resulting json value has the right type
+ const QString settingType = settingDescription.toObject()[SETTING_DESCRIPTION_TYPE_KEY].toString();
+ const QString INPUT_DOUBLE_TYPE = "double";
+ const QString INPUT_INTEGER_TYPE = "int";
+
+ if (settingType == INPUT_DOUBLE_TYPE) {
+ settingMap[key] = newValue.toString().toDouble();
+ } else if (settingType == INPUT_INTEGER_TYPE) {
+ settingMap[key] = newValue.toString().toInt();
+ } else {
+ settingMap[key] = newValue.toString();
+ }
+ }
+ } else if (newValue.isBool()) {
+ settingMap[key] = newValue.toBool();
+ } else if (newValue.isObject()) {
+ if (!settingMap.contains(key)) {
+ // we don't have a map below this key yet, so set it up now
+ settingMap[key] = QVariantMap();
+ }
+
+ QVariantMap& thisMap = *reinterpret_cast(settingMap[key].data());
+ foreach(const QString childKey, newValue.toObject().keys()) {
+ updateSetting(childKey, newValue.toObject()[childKey], thisMap, settingDescription.toObject()[key]);
+ }
+
+ if (settingMap[key].toMap().isEmpty()) {
+ // we've cleared all of the settings below this value, so remove this one too
+ settingMap.remove(key);
+ }
+ }
+}
void DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJsonObject& postedObject,
QVariantMap& settingsVariant,
- QJsonArray descriptionArray) {
- foreach(const QString& key, postedObject.keys()) {
+ const QJsonArray& descriptionArray) {
+ // Iterate on the setting groups
+ foreach(const QString& groupKey, postedObject.keys()) {
+ QJsonValue groupValue = postedObject[groupKey];
- QJsonValue rootValue = postedObject[key];
+ if (!settingsVariant.contains(groupKey)) {
+ // we don't have a map below this key yet, so set it up now
+ settingsVariant[groupKey] = QVariantMap();
+ }
- // we don't continue if this key is not present in our descriptionObject
- foreach(const QJsonValue& groupValue, descriptionArray) {
- if (groupValue.toObject()[DESCRIPTION_NAME_KEY].toString() == key) {
- QJsonObject groupObject = groupValue.toObject();
- if (rootValue.isString()) {
- if (rootValue.toString().isEmpty()) {
- // this is an empty value, clear it in settings variant so the default is sent
- settingsVariant.remove(key);
- } else {
- QString settingType = groupObject[SETTING_DESCRIPTION_TYPE_KEY].toString();
-
- const QString INPUT_DOUBLE_TYPE = "double";
- const QString INPUT_INTEGER_TYPE = "int";
-
- // make sure the resulting json value has the right type
-
- if (settingType == INPUT_DOUBLE_TYPE) {
- settingsVariant[key] = rootValue.toString().toDouble();
- } else if (settingType == INPUT_INTEGER_TYPE) {
- settingsVariant[key] = rootValue.toString().toInt();
- } else {
- settingsVariant[key] = rootValue.toString();
- }
- }
- } else if (rootValue.isBool()) {
- settingsVariant[key] = rootValue.toBool();
- } else if (rootValue.isObject()) {
- // there's a JSON Object to explore, so attempt to recurse into it
- QJsonObject nextDescriptionObject = groupObject;
-
- if (nextDescriptionObject.contains(DESCRIPTION_SETTINGS_KEY)) {
- if (!settingsVariant.contains(key)) {
- // we don't have a map below this key yet, so set it up now
- settingsVariant[key] = QVariantMap();
- }
-
- QVariantMap& thisMap = *reinterpret_cast(settingsVariant[key].data());
-
- recurseJSONObjectAndOverwriteSettings(rootValue.toObject(),
- thisMap,
- nextDescriptionObject[DESCRIPTION_SETTINGS_KEY].toArray());
-
- if (thisMap.isEmpty()) {
- // we've cleared all of the settings below this value, so remove this one too
- settingsVariant.remove(key);
- }
- }
- }
+ // Iterate on the settings
+ foreach(const QString& settingKey, groupValue.toObject().keys()) {
+ QJsonValue settingValue = groupValue.toObject()[settingKey];
+
+ QJsonValue thisDescription;
+ if (settingExists(groupKey, settingKey, descriptionArray, thisDescription)) {
+ QVariantMap& thisMap = *reinterpret_cast(settingsVariant[groupKey].data());
+ updateSetting(settingKey, settingValue, thisMap, thisDescription);
}
}
+
+ if (settingsVariant[groupKey].toMap().empty()) {
+ // we've cleared all of the settings below this value, so remove this one too
+ settingsVariant.remove(groupKey);
+ }
}
}
diff --git a/domain-server/src/DomainServerSettingsManager.h b/domain-server/src/DomainServerSettingsManager.h
index c2e8a7d90d..a21e0dc93a 100644
--- a/domain-server/src/DomainServerSettingsManager.h
+++ b/domain-server/src/DomainServerSettingsManager.h
@@ -32,7 +32,11 @@ public:
private:
QJsonObject responseObjectForType(const QString& typeValue, bool isAuthenticated = false);
void recurseJSONObjectAndOverwriteSettings(const QJsonObject& postedObject, QVariantMap& settingsVariant,
- QJsonArray descriptionArray);
+ const QJsonArray& descriptionArray);
+ bool settingExists(const QString& groupName, const QString& settingName,
+ const QJsonArray& descriptionArray, QJsonValue& settingDescription);
+ void updateSetting(const QString& key, const QJsonValue& newValue, QVariantMap& settingMap,
+ const QJsonValue& settingDescription);
void persistToFile();
QJsonArray _descriptionArray;