summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'Sluift/ElementConvertors/FormConvertor.cpp')
-rw-r--r--Sluift/ElementConvertors/FormConvertor.cpp331
1 files changed, 331 insertions, 0 deletions
diff --git a/Sluift/ElementConvertors/FormConvertor.cpp b/Sluift/ElementConvertors/FormConvertor.cpp
new file mode 100644
index 0000000..1720037
--- /dev/null
+++ b/Sluift/ElementConvertors/FormConvertor.cpp
@@ -0,0 +1,331 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/ElementConvertors/FormConvertor.h>
+
+#include <lua.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+#include <boost/numeric/conversion/cast.hpp>
+#include <Sluift/Lua/Check.h>
+#include <Sluift/Lua/Value.h>
+#include <Swiften/Base/foreach.h>
+#include <boost/assign/list_of.hpp>
+#include <sstream>
+
+using namespace Swift;
+
+namespace {
+ // TODO: add __newindex to set a field value
+ int formIndex(lua_State* L) {
+ lua_getfield(L, 1, "fields");
+ if (lua_type(L, -1) != LUA_TTABLE) {
+ return 0;
+ }
+ int index = Lua::absoluteOffset(L, -1);
+ lua_pushnil(L);
+ for (lua_pushnil(L); lua_next(L, index) != 0; ) {
+ lua_getfield(L, -1, "name");
+ if (lua_equal(L, -1, 2)) {
+ lua_pop(L, 1);
+ return 1;
+ }
+ lua_pop(L, 2);
+ }
+ return 0;
+ }
+
+ Lua::Table convertFieldToLua(boost::shared_ptr<FormField> field) {
+ Lua::Table luaField = boost::assign::map_list_of("name", Lua::valueRef(field->getName()));
+ std::string type;
+ switch (field->getType()) {
+ case FormField::UnknownType: type = ""; break;
+ case FormField::BooleanType: type = "boolean"; break;
+ case FormField::FixedType: type = "fixed"; break;
+ case FormField::HiddenType: type = "hidden"; break;
+ case FormField::ListSingleType: type = "list-single"; break;
+ case FormField::TextMultiType: type = "text-multi"; break;
+ case FormField::TextPrivateType: type = "text-private"; break;
+ case FormField::TextSingleType: type = "text-single"; break;
+ case FormField::JIDSingleType: type = "jid-single"; break;
+ case FormField::JIDMultiType: type = "jid-multi"; break;
+ case FormField::ListMultiType: type = "list-multi"; break;
+ }
+ if (!type.empty()) {
+ luaField["type"] = Lua::valueRef(type);
+ }
+ if (!field->getLabel().empty()) {
+ luaField["label"] = Lua::valueRef(field->getLabel());
+ }
+ if (field->getRequired()) {
+ luaField["required"] = Lua::boolRef(field->getRequired());
+ }
+ if (!field->getDescription().empty()) {
+ luaField["description"] = Lua::valueRef(field->getDescription());
+ }
+
+ if (field->getType() == FormField::ListMultiType || field->getType() == FormField::JIDMultiType || field->getType() == FormField::TextMultiType) {
+ luaField["values"] = Lua::valueRef(Lua::Array(field->getValues().begin(), field->getValues().end()));
+ }
+ else if (field->getType() == FormField::BooleanType) {
+ luaField["value"] = Lua::boolRef(field->getBoolValue());
+ }
+ else if (!field->getValues().empty()) {
+ luaField["value"] = Lua::valueRef(field->getValues()[0]);
+ }
+
+ if (!field->getOptions().empty()) {
+ Lua::Array options;
+ foreach(const FormField::Option& option, field->getOptions()) {
+ Lua::Table luaOption = boost::assign::map_list_of
+ ("label", Lua::valueRef(option.label))
+ ("value", Lua::valueRef(option.value));
+ options.push_back(luaOption);
+ }
+ luaField["options"] = valueRef(options);
+ }
+ return luaField;
+ }
+
+ Lua::Array convertFieldListToLua(const std::vector< boost::shared_ptr<FormField> >& fieldList) {
+ Lua::Array fields;
+ foreach(boost::shared_ptr<FormField> field, fieldList) {
+ fields.push_back(convertFieldToLua(field));
+ }
+ return fields;
+ }
+
+
+ boost::shared_ptr<FormField> convertFieldFromLua(lua_State* L) {
+ boost::shared_ptr<FormField> result = boost::make_shared<FormField>();
+ FormField::Type fieldType = FormField::UnknownType;
+ boost::optional<std::string> type = Lua::getStringField(L, -1, "type");
+ if (type) {
+ if (*type == "boolean") {
+ fieldType = FormField::BooleanType;
+ }
+ if (*type == "fixed") {
+ fieldType = FormField::FixedType;
+ }
+ if (*type == "hidden") {
+ fieldType = FormField::HiddenType;
+ }
+ if (*type == "list-single") {
+ fieldType = FormField::ListSingleType;
+ }
+ if (*type == "text-multi") {
+ fieldType = FormField::TextMultiType;
+ }
+ if (*type == "text-private") {
+ fieldType = FormField::TextPrivateType;
+ }
+ if (*type == "text-single") {
+ fieldType = FormField::TextSingleType;
+ }
+ if (*type == "jid-single") {
+ fieldType = FormField::JIDSingleType;
+ }
+ if (*type == "jid-multi") {
+ fieldType = FormField::JIDMultiType;
+ }
+ if (*type == "list-multi") {
+ fieldType = FormField::ListMultiType;
+ }
+ }
+ result->setType(fieldType);
+ if (boost::optional<std::string> name = Lua::getStringField(L, -1, "name")) {
+ result->setName(*name);
+ }
+ if (boost::optional<std::string> description = Lua::getStringField(L, -1, "description")) {
+ result->setDescription(*description);
+ }
+ if (boost::optional<std::string> label = Lua::getStringField(L, -1, "label")) {
+ result->setLabel(*label);
+ }
+ if (boost::optional<bool> required = Lua::getBooleanField(L, -1, "required")) {
+ result->setRequired(*required);
+ }
+ if (boost::optional<std::string> value = Lua::getStringField(L, -1, "value")) {
+ result->addValue(*value);
+ }
+ else if (boost::optional<bool> value = Lua::getBooleanField(L, -1, "value")) {
+ result->setBoolValue(*value);
+ }
+ else {
+ lua_getfield(L, -1, "values");
+ if (lua_istable(L, -1)) {
+ for (lua_pushnil(L); lua_next(L, -2); ) {
+ if (lua_isstring(L, -1)) {
+ result->addValue(lua_tostring(L, -1));
+ }
+ lua_pop(L, 1);
+ }
+ }
+ lua_pop(L, 1);
+ }
+ lua_getfield(L, -1, "options");
+ if (lua_istable(L, -1)) {
+ for (lua_pushnil(L); lua_next(L, -2); ) {
+ if (lua_istable(L, -1)) {
+ FormField::Option option("", "");
+ if (boost::optional<std::string> value = Lua::getStringField(L, -1, "value")) {
+ option.value = *value;
+ }
+ if (boost::optional<std::string> label = Lua::getStringField(L, -1, "label")) {
+ option.label = *label;
+ }
+ result->addOption(option);
+ }
+ lua_pop(L, 1);
+ }
+ }
+ lua_pop(L, 1);
+ return result;
+ }
+
+ std::vector< boost::shared_ptr<FormField> > convertFieldListFromLua(lua_State* L) {
+ std::vector< boost::shared_ptr<FormField> > result;
+ for (lua_pushnil(L); lua_next(L, -2);) {
+ result.push_back(convertFieldFromLua(L));
+ lua_pop(L, 1);
+ }
+ return result;
+ }
+
+ boost::shared_ptr<Form> convertFormFromLua(lua_State* L) {
+ boost::shared_ptr<Form> result = boost::make_shared<Form>();
+ if (boost::optional<std::string> title = Lua::getStringField(L, -1, "title")) {
+ result->setTitle(*title);
+ }
+ if (boost::optional<std::string> instructions = Lua::getStringField(L, -1, "instructions")) {
+ result->setInstructions(*instructions);
+ }
+ if (boost::optional<std::string> type = Lua::getStringField(L, -1, "type")) {
+ Form::Type formType = Form::FormType;
+ if (*type == "submit") {
+ formType = Form::SubmitType;
+ }
+ else if (*type == "cancel") {
+ formType = Form::CancelType;
+ }
+ else if (*type == "result") {
+ formType = Form::ResultType;
+ }
+ result->setType(formType);
+ }
+
+ lua_getfield(L, -1, "fields");
+ if (lua_istable(L, -1)) {
+ foreach (boost::shared_ptr<FormField> formField, convertFieldListFromLua(L)) {
+ result->addField(formField);
+ }
+ }
+ lua_pop(L, 1);
+
+ lua_getfield(L, -1, "reported_fields");
+ if (lua_istable(L, -1)) {
+ foreach (boost::shared_ptr<FormField> formField, convertFieldListFromLua(L)) {
+ result->addReportedField(formField);
+ }
+ }
+ lua_pop(L, 1);
+
+ lua_getfield(L, -1, "items");
+ if (lua_istable(L, -1)) {
+ for (lua_pushnil(L); lua_next(L, -2);) {
+ result->addItem(convertFieldListFromLua(L));
+ lua_pop(L, 1);
+ }
+ }
+ lua_pop(L, 1);
+
+ return result;
+ }
+
+ void convertFormToLua(lua_State* L, boost::shared_ptr<Form> payload) {
+ std::string type;
+ switch (payload->getType()) {
+ case Form::FormType: type = "form"; break;
+ case Form::SubmitType: type = "submit"; break;
+ case Form::CancelType: type = "cancel"; break;
+ case Form::ResultType: type = "result"; break;
+ }
+
+ Lua::Table result = boost::assign::map_list_of("type", Lua::valueRef(type));
+ if (!payload->getTitle().empty()) {
+ result["title"] = Lua::valueRef(payload->getTitle());
+ }
+ if (!payload->getInstructions().empty()) {
+ result["instructions"] = Lua::valueRef(payload->getInstructions());
+ }
+ if (!payload->getFields().empty()) {
+ result["fields"] = valueRef(convertFieldListToLua(payload->getFields()));
+ }
+ if (!payload->getReportedFields().empty()) {
+ result["reported_fields"] = valueRef(convertFieldListToLua(payload->getReportedFields()));
+ }
+
+ if (!payload->getItems().empty()) {
+ Lua::Array luaItems;
+ foreach(const Form::FormItem& item, payload->getItems()) {
+ if (!item.empty()) {
+ luaItems.push_back(convertFieldListToLua(item));
+ }
+ }
+ result["items"] = valueRef(luaItems);
+ }
+
+ Lua::pushValue(L, result);
+ lua_newtable(L);
+ lua_pushcfunction(L, formIndex);
+ lua_setfield(L, -2, "__index");
+ lua_setmetatable(L, -2);
+ }
+
+ int createSubmission(lua_State* L) {
+ boost::shared_ptr<Form> form = convertFormFromLua(L);
+
+ // Remove all redundant elements
+ form->setInstructions("");
+ form->setTitle("");
+ form->clearItems();
+ form->clearReportedFields();
+ std::vector< boost::shared_ptr<FormField> > fields(form->getFields());
+ form->clearFields();
+ foreach (boost::shared_ptr<FormField> field, fields) {
+ if (field->getType() == FormField::FixedType) {
+ continue;
+ }
+ field->clearOptions();
+ field->setLabel("");
+ field->setType(FormField::UnknownType);
+ field->setDescription("");
+ form->addField(field);
+ }
+
+ // Convert back
+ convertFormToLua(L, form);
+ Lua::registerTableToString(L, -1);
+ return 1;
+ }
+}
+
+FormConvertor::FormConvertor() : GenericLuaElementConvertor<Form>("form") {
+}
+
+FormConvertor::~FormConvertor() {
+}
+
+boost::shared_ptr<Form> FormConvertor::doConvertFromLua(lua_State* L) {
+ return convertFormFromLua(L);
+}
+
+void FormConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<Form> payload) {
+ convertFormToLua(L, payload);
+
+ lua_pushcfunction(L, createSubmission);
+ lua_setfield(L, -2, "create_submission");
+
+}