Merge pull request #3556 from Atlante45/attenuation_zones

Table structure for DS settings
This commit is contained in:
Stephen Birarda 2014-10-08 14:12:12 -07:00
commit dc139a63da
4 changed files with 294 additions and 67 deletions

View file

@ -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
},

View file

@ -25,10 +25,12 @@ var viewHelpers = {
form_group += "<label class='" + label_class + "'>" + setting.label + "</label>"
form_group += "<div class='checkbox" + (isLocked ? " disabled" : "") + "'>"
form_group += "<label for='" + setting_name + "'>"
form_group += "<input type='checkbox' name='" + setting_name + "' " +
form_group += "<input type='checkbox' name='" + setting_name + "' " +
(setting_value ? "checked" : "") + (isLocked ? " disabled" : "") + "/>"
form_group += " " + setting.help + "</label>";
form_group += "</div>"
} 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='" + option.value + "'" +
(option.value == setting_value ? 'selected' : '') + ">" + option.label + "</option>"
(option.value == setting_value ? 'selected' : '') + ">" + option.label + "</option>"
})
form_group += "</select>"
@ -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("<input type='hidden' class='form-control' name='" + row.attr("name") + "' data-changed='true' value=''>");
})
$('#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 = "<div class='panel panel-default'>"
html += "<div class='panel-heading'>" + setting.label + "</div>"
html += "<div class='panel-body'>"
html += "<p>" + setting.help + "</p>"
html += "</div>"
html += "<table class='table' name='" + setting_name + "'>"
// Column names
html += "<tr class='headers'>"
if (setting.number === true) {
html += "<td class='number'><strong>#</strong></td>" // Row number
}
html += "<td class='key'><strong>" + setting.key.label + "</strong></td>" // Key
_.each(setting.columns, function(col) {
html += "<td class='data'><strong>" + col.label + "</strong></td>" // Data
})
if (setting.can_delete === true || setting.can_add === true) {
html += "<td class='buttons'></td>" // Buttons
}
html += "</tr>"
// Rows
var row_num = 1
_.each(setting_value, function(row, name) {
html += "<tr class='row-data' name='" + setting_name + "." + name + "'>"
if (setting.number === true) {
html += "<td class='number'>" + row_num + "</td>"
}
html += "<td class='key'>" + name + "</td>"
_.each(setting.columns, function(col) {
html += "<td class='row-data'>"
if (row.hasOwnProperty(col.name)) {
html += row[col.name]
}
html += "</td>"
})
if (setting.can_delete === true) {
html += "<td class='buttons'><span class='glyphicon glyphicon-remove del-row'></span></td>"
} else if (setting.can_add === true) {
html += "<td class='buttons'></td>"
}
html += "</tr>"
row_num++
})
// Inputs
if (setting.can_add === true) {
html += makeTableInputs(setting)
}
html += "</table>"
html += "</div>"
return html;
}
function makeTableInputs(setting) {
var html = "<tr class='inputs'>"
if (setting.number === true) {
html += "<td class='number'></td>"
}
html += "<td class='key' name='" + setting.key.name + "'>\
<input type='text' class='form-control' placeholder='" + setting.key.placeholder + "' value=''>\
</td>"
_.each(setting.columns, function(col) {
html += "<td class='row-data'name='" + col.name + "'>\
<input type='text' class='form-control' placeholder='" + col.placeholder + "' value=''>\
</td>"
})
html += "<td class='buttons'><span class='glyphicon glyphicon-ok add-row'></span></td>"
html += "</tr>"
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 {

View file

@ -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<QVariantMap*>(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<QVariantMap*>(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<QVariantMap*>(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);
}
}
}

View file

@ -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;