From 00284e5f4445a7bbab482196901c5927ea7d5488 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Remko=20Tron=C3=A7on?= <git@el-tramo.be>
Date: Thu, 22 Aug 2013 23:07:51 +0200
Subject: FormField element refactoring.

This should make FormField easier to use.

Change-Id: Ia5eeedcdb673e2fe5e38fd23d5ab00970178bc44

diff --git a/Swift/QtUI/QtFormResultItemModel.cpp b/Swift/QtUI/QtFormResultItemModel.cpp
index b052334..8920128 100644
--- a/Swift/QtUI/QtFormResultItemModel.cpp
+++ b/Swift/QtUI/QtFormResultItemModel.cpp
@@ -4,6 +4,12 @@
  * See Documentation/Licenses/BSD-simplified.txt for more information.
  */
 
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
 #include "QtFormResultItemModel.h"
 
 #include <boost/algorithm/string/join.hpp>
@@ -69,15 +75,16 @@ const std::string QtFormResultItemModel::getFieldValue(const Form::FormItem& ite
 	foreach(FormField::ref field, item) {
 		if (field->getName() == name) {
 			std::string delimiter = "";
-			if (boost::dynamic_pointer_cast<TextMultiFormField>(field)) {
+			if (field->getType() == FormField::TextMultiType) {
 				delimiter = "\n";
-			} else if (boost::dynamic_pointer_cast<JIDMultiFormField>(field)) {
+			}
+			else if (field->getType() == FormField::JIDMultiType) {
 				delimiter = ", ";
-			} else if (boost::dynamic_pointer_cast<ListMultiFormField>(field)) {
+			} 
+			else if (field->getType() == FormField::ListMultiType) {
 				delimiter = ", ";
 			}
-
-			return boost::algorithm::join(field->getRawValues(), delimiter);
+			return boost::algorithm::join(field->getValues(), delimiter);
 		}
 	}
 
diff --git a/Swift/QtUI/QtFormWidget.cpp b/Swift/QtUI/QtFormWidget.cpp
index 4216863..9b213cf 100644
--- a/Swift/QtUI/QtFormWidget.cpp
+++ b/Swift/QtUI/QtFormWidget.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2011 Kevin Smith
+ * Copyright (c) 2010-2013 Kevin Smith
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
@@ -17,6 +17,8 @@
 
 #include <Swift/QtUI/QtSwiftUtil.h>
 #include <Swiften/Base/foreach.h>
+#include <boost/algorithm/string/join.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
 
 namespace Swift {
 
@@ -54,18 +56,16 @@ QtFormWidget::~QtFormWidget() {
 QListWidget* QtFormWidget::createList(FormField::ref field) {
 	QListWidget* listWidget = new QListWidget(this);
 	listWidget->setSortingEnabled(false);
-	listWidget->setSelectionMode(boost::dynamic_pointer_cast<ListMultiFormField>(field) ? QAbstractItemView::MultiSelection : QAbstractItemView::SingleSelection);
-	boost::shared_ptr<ListMultiFormField> listMultiField = boost::dynamic_pointer_cast<ListMultiFormField>(field);
-	boost::shared_ptr<ListSingleFormField> listSingleField = boost::dynamic_pointer_cast<ListSingleFormField>(field);
+	listWidget->setSelectionMode(field->getType() == FormField::ListMultiType ? QAbstractItemView::MultiSelection : QAbstractItemView::SingleSelection);
 	std::vector<bool> selected;
 	foreach (FormField::Option option, field->getOptions()) {
 		listWidget->addItem(option.label.c_str());
-		if (listSingleField) {
-			selected.push_back(option.value == listSingleField->getValue());
+		if (field->getType() == FormField::ListMultiType) {
+			selected.push_back(!field->getValues().empty() && option.value == field->getValues()[0]);
 		}
-		else if (listMultiField) {
+		else if (field->getType() == FormField::ListMultiType) {
 			std::string text = option.value;
-			selected.push_back(std::find(listMultiField->getValue().begin(), listMultiField->getValue().end(), text) != listMultiField->getValue().end());
+			selected.push_back(std::find(field->getValues().begin(), field->getValues().end(), text) != field->getValues().end());
 		}
 
 	}
@@ -78,67 +78,47 @@ QListWidget* QtFormWidget::createList(FormField::ref field) {
 
 QWidget* QtFormWidget::createWidget(FormField::ref field) {
 	QWidget* widget = NULL;
-	boost::shared_ptr<BooleanFormField> booleanField = boost::dynamic_pointer_cast<BooleanFormField>(field);
-	if (booleanField) {
+	if (field->getType() == FormField::BooleanType) {
 		QCheckBox* checkWidget = new QCheckBox(this);
-		checkWidget->setCheckState(booleanField->getValue() ? Qt::Checked : Qt::Unchecked);
+		checkWidget->setCheckState(field->getBoolValue() ? Qt::Checked : Qt::Unchecked);
 		widget = checkWidget;
 	}
-	boost::shared_ptr<FixedFormField> fixedField = boost::dynamic_pointer_cast<FixedFormField>(field);
-	if (fixedField) {
-		QString value = fixedField->getValue().c_str();
+	if (field->getType() == FormField::FixedType) {
+		QString value = field->getFixedValue().c_str();
 		widget = new QLabel(value, this);
 	}
-	boost::shared_ptr<ListSingleFormField> listSingleField = boost::dynamic_pointer_cast<ListSingleFormField>(field);
-	if (listSingleField) {
+	if (field->getType() == FormField::ListSingleType) {
 		widget = createList(field);
 	}
-	boost::shared_ptr<TextMultiFormField> textMultiField = boost::dynamic_pointer_cast<TextMultiFormField>(field);
-	if (textMultiField) {
-		QString value = textMultiField->getValue().c_str();
+	if (field->getType() == FormField::TextMultiType) {
+		QString value = field->getTextMultiValue().c_str();
 		QTextEdit* textWidget = new QTextEdit(this);
 		textWidget->setPlainText(value);
 		widget = textWidget;
 	}
-	boost::shared_ptr<TextPrivateFormField> textPrivateField = boost::dynamic_pointer_cast<TextPrivateFormField>(field);
-	if (textPrivateField) {
-		QString value = textPrivateField->getValue().c_str();
+	if (field->getType() == FormField::TextPrivateType) {
+		QString value = field->getTextPrivateValue().c_str();
 		QLineEdit* lineWidget = new QLineEdit(value, this);
 		lineWidget->setEchoMode(QLineEdit::Password);
 		widget = lineWidget;
 	}
-	boost::shared_ptr<TextSingleFormField> textSingleField = boost::dynamic_pointer_cast<TextSingleFormField>(field);
-	if (textSingleField) {
-		QString value = textSingleField->getValue().c_str();
+	if (field->getType() == FormField::TextSingleType) {
+		QString value = field->getTextSingleValue().c_str();
 		widget = new QLineEdit(value, this);
 	}
-	boost::shared_ptr<JIDSingleFormField> jidSingleField = boost::dynamic_pointer_cast<JIDSingleFormField>(field);
-	if (jidSingleField) {
-		QString value = jidSingleField->getValue().toString().c_str();
+	if (field->getType() == FormField::JIDSingleType) {
+		QString value = field->getJIDSingleValue().toString().c_str();
 		widget = new QLineEdit(value, this);
 	}
-	boost::shared_ptr<JIDMultiFormField> jidMultiField = boost::dynamic_pointer_cast<JIDMultiFormField>(field);
-	if (jidMultiField) {
-		QString text;
-		bool prev = false;
-		foreach (JID line, jidMultiField->getValue()) {
-			if (prev) {
-				text += "\n";
-			}
-			prev = true;
-			text += line.toString().c_str();
-		}
+	if (field->getType() == FormField::JIDMultiType) {
+		QString text = boost::join(field->getValues(), "\n").c_str();
 		QTextEdit* textWidget = new QTextEdit(this);
 		textWidget->setPlainText(text);
 		widget = textWidget;
 	}
-	boost::shared_ptr<ListMultiFormField> listMultiField = boost::dynamic_pointer_cast<ListMultiFormField>(field);
-	if (listMultiField) {
+	if (field->getType() == FormField::ListMultiType) {
 		widget = createList(field);
 	}
-	boost::shared_ptr<HiddenFormField> hiddenField = boost::dynamic_pointer_cast<HiddenFormField>(field);
-	if (hiddenField) {
-	}
 	fields_[field->getName()] = widget;
 	return widget;
 }
@@ -146,101 +126,51 @@ QWidget* QtFormWidget::createWidget(FormField::ref field) {
 Form::ref QtFormWidget::getCompletedForm() {
 	Form::ref result(new Form(Form::SubmitType));
 	foreach (boost::shared_ptr<FormField> field, form_->getFields()) {
-		boost::shared_ptr<FormField> resultField;
-		boost::shared_ptr<BooleanFormField> booleanField = boost::dynamic_pointer_cast<BooleanFormField>(field);
-		if (booleanField) {
-			resultField = FormField::ref(BooleanFormField::create(qobject_cast<QCheckBox*>(fields_[field->getName()])->checkState() == Qt::Checked));
+		boost::shared_ptr<FormField> resultField = boost::make_shared<FormField>(field->getType());
+		if (field->getType() == FormField::BooleanType) {
+			resultField->setBoolValue(qobject_cast<QCheckBox*>(fields_[field->getName()])->checkState() == Qt::Checked);
 		}
-		boost::shared_ptr<FixedFormField> fixedField = boost::dynamic_pointer_cast<FixedFormField>(field);
-		if (fixedField) {
-			resultField = FormField::ref(FixedFormField::create(fixedField->getValue()));
+		if (field->getType() == FormField::FixedType || field->getType() == FormField::HiddenType) {
+			resultField->addValue(field->getValues().empty() ? "" : field->getValues()[0]);
 		}
-		boost::shared_ptr<ListSingleFormField> listSingleField = boost::dynamic_pointer_cast<ListSingleFormField>(field);
-		if (listSingleField) {
+		if (field->getType() == FormField::ListSingleType) {
 			QListWidget* listWidget = qobject_cast<QListWidget*>(fields_[field->getName()]);
 			if (listWidget->selectedItems().size() > 0) {
 				int i = listWidget->row(listWidget->selectedItems()[0]);
-				resultField = FormField::ref(ListSingleFormField::create(field->getOptions()[i].value));
-			}
-			else {
-				resultField = FormField::ref(ListSingleFormField::create());
+				resultField->addValue(field->getOptions()[i].value);
 			}
 		}
-		boost::shared_ptr<TextMultiFormField> textMultiField = boost::dynamic_pointer_cast<TextMultiFormField>(field);
-		if (textMultiField) {
+		if (field->getType() == FormField::TextMultiType) {
 			QTextEdit* widget = qobject_cast<QTextEdit*>(fields_[field->getName()]);
 			QString string = widget->toPlainText();
-			if (string.isEmpty()) {
-				resultField = FormField::ref(TextMultiFormField::create());
-			}
-			else {
-				resultField = FormField::ref(TextMultiFormField::create(Q2PSTRING(string)));
-			}
-		}
-		boost::shared_ptr<TextPrivateFormField> textPrivateField = boost::dynamic_pointer_cast<TextPrivateFormField>(field);
-		if (textPrivateField) {
-			QLineEdit* widget = qobject_cast<QLineEdit*>(fields_[field->getName()]);
-			QString string = widget->text();
-			if (string.isEmpty()) {
-				resultField = FormField::ref(TextPrivateFormField::create());
-			}
-			else {
-				resultField = FormField::ref(TextPrivateFormField::create(Q2PSTRING(string)));
+			if (!string.isEmpty()) {
+				resultField->setTextMultiValue(Q2PSTRING(string));
 			}
 		}
-		boost::shared_ptr<TextSingleFormField> textSingleField = boost::dynamic_pointer_cast<TextSingleFormField>(field);
-		if (textSingleField) {
+		if (field->getType() == FormField::TextPrivateType || field->getType() == FormField::TextSingleType || field->getType() == FormField::JIDSingleType) {
 			QLineEdit* widget = qobject_cast<QLineEdit*>(fields_[field->getName()]);
 			QString string = widget->text();
-			if (string.isEmpty()) {
-				resultField = FormField::ref(TextSingleFormField::create());
-			}
-			else {
-				resultField = FormField::ref(TextSingleFormField::create(Q2PSTRING(string)));
+			if (!string.isEmpty()) {
+				resultField->addValue(Q2PSTRING(string));
 			}
 		}
-		boost::shared_ptr<JIDSingleFormField> jidSingleField = boost::dynamic_pointer_cast<JIDSingleFormField>(field);
-		if (jidSingleField) {
-			QLineEdit* widget = qobject_cast<QLineEdit*>(fields_[field->getName()]);
-			QString string = widget->text();
-			JID jid(Q2PSTRING(string));
-			if (string.isEmpty()) {
-				resultField = FormField::ref(JIDSingleFormField::create());
-			}
-			else {
-				resultField = FormField::ref(JIDSingleFormField::create(jid));
-			}
-		}
-		boost::shared_ptr<JIDMultiFormField> jidMultiField = boost::dynamic_pointer_cast<JIDMultiFormField>(field);
-		if (jidMultiField) {
+		if (field->getType() == FormField::JIDMultiType) {
 			QTextEdit* widget = qobject_cast<QTextEdit*>(fields_[field->getName()]);
 			QString string = widget->toPlainText();
-			if (string.isEmpty()) {
-				resultField = FormField::ref(JIDMultiFormField::create());
-			}
-			else {
+			if (!string.isEmpty()) {
 				QStringList lines = string.split("\n");
-				std::vector<JID> value;
 				foreach (QString line, lines) {
-					value.push_back(JID(Q2PSTRING(line)));
+					resultField->addValue(Q2PSTRING(line));
 				}
-				resultField = FormField::ref(JIDMultiFormField::create(value));
 			}
 		}
-		boost::shared_ptr<ListMultiFormField> listMultiField = boost::dynamic_pointer_cast<ListMultiFormField>(field);
-		if (listMultiField) {
+		if (field->getType() == FormField::ListMultiType) {
 			QListWidget* listWidget = qobject_cast<QListWidget*>(fields_[field->getName()]);
-			std::vector<std::string> values;
 			foreach (QListWidgetItem* item, listWidget->selectedItems()) {
-				values.push_back(field->getOptions()[listWidget->row(item)].value);
+				resultField->addValue(field->getOptions()[listWidget->row(item)].value);
 			}
-			resultField = FormField::ref(ListMultiFormField::create(values));
-		}
-		boost::shared_ptr<HiddenFormField> hiddenField = boost::dynamic_pointer_cast<HiddenFormField>(field);
-		if (hiddenField) {
-			resultField = FormField::ref(HiddenFormField::create(hiddenField->getValue()));
 		}
-		resultField->setName(field->getName());
+		field->setName(field->getName());
 		result->addField(resultField);
 	}
 	return result;
diff --git a/Swift/QtUI/UserSearch/QtUserSearchWindow.cpp b/Swift/QtUI/UserSearch/QtUserSearchWindow.cpp
index 02b238e..73514fd 100644
--- a/Swift/QtUI/UserSearch/QtUserSearchWindow.cpp
+++ b/Swift/QtUI/UserSearch/QtUserSearchWindow.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Kevin Smith
+ * Copyright (c) 2010-2013 Kevin Smith
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
@@ -179,12 +179,12 @@ JID QtUserSearchWindow::getContactJID() const {
 			Form::FormItem item = dynamic_cast<QtFormResultItemModel*>(model_)->getForm()->getItems().at(row);
 			JID fallbackJid;
 			foreach(FormField::ref field, item) {
-				if (boost::dynamic_pointer_cast<JIDSingleFormField>(field)) {
-					jid = JID(field->getRawValues().at(0));
+				if (field->getType() == FormField::JIDSingleType) {
+					jid = JID(field->getJIDSingleValue());
 					break;
 				}
 				if (field->getName() == "jid") {
-					fallbackJid = field->getRawValues().at(0);
+					fallbackJid = field->getValues()[0];
 				}
 			}
 			if (!jid.isValid()) {
diff --git a/Swiften/Disco/CapsInfoGenerator.cpp b/Swiften/Disco/CapsInfoGenerator.cpp
index cb93182..4332f76 100644
--- a/Swiften/Disco/CapsInfoGenerator.cpp
+++ b/Swiften/Disco/CapsInfoGenerator.cpp
@@ -49,7 +49,7 @@ CapsInfo CapsInfoGenerator::generateCapsInfo(const DiscoInfo& discoInfo) const {
 				continue;
 			}
 			serializedCaps += field->getName() + "<";
-			std::vector<std::string> values(field->getRawValues());
+			std::vector<std::string> values(field->getValues());
 			std::sort(values.begin(), values.end());
 			foreach(const std::string& value, values) {
 				serializedCaps += value + "<";
diff --git a/Swiften/Disco/UnitTest/CapsInfoGeneratorTest.cpp b/Swiften/Disco/UnitTest/CapsInfoGeneratorTest.cpp
index a1b1a7b..67d27c0 100644
--- a/Swiften/Disco/UnitTest/CapsInfoGeneratorTest.cpp
+++ b/Swiften/Disco/UnitTest/CapsInfoGeneratorTest.cpp
@@ -51,32 +51,25 @@ class CapsInfoGeneratorTest : public CppUnit::TestFixture {
 			discoInfo.addFeature("http://jabber.org/protocol/muc");
 
 			Form::ref extension(new Form(Form::ResultType));
-			FormField::ref field = HiddenFormField::create("urn:xmpp:dataforms:softwareinfo");
+			FormField::ref field = boost::make_shared<FormField>(FormField::HiddenType, "urn:xmpp:dataforms:softwareinfo");
 			field->setName("FORM_TYPE");
 			extension->addField(field);
-			std::vector<std::string> ipVersions;
-			ipVersions.push_back("ipv6");
-			ipVersions.push_back("ipv4");
-			field = ListMultiFormField::create(ipVersions);
-			field->addRawValue("ipv6");
-			field->addRawValue("ipv4");
+			field = boost::make_shared<FormField>(FormField::ListMultiType);
+			field->addValue("ipv6");
+			field->addValue("ipv4");
 			field->setName("ip_version");
 			extension->addField(field);
-			field = TextSingleFormField::create("Psi");
-			field->addRawValue("Psi");
+			field = boost::make_shared<FormField>(FormField::TextSingleType, "Psi");
 			field->setName("software");
 			extension->addField(field);
-			field = TextSingleFormField::create("0.11");
-			field->addRawValue("0.11");
+			field = boost::make_shared<FormField>(FormField::TextSingleType, "0.11");
 			field->setName("software_version");
 			extension->addField(field);
-			field = TextSingleFormField::create("Mac");
+			field = boost::make_shared<FormField>(FormField::TextSingleType, "Mac");
 			field->setName("os");
-			field->addRawValue("Mac");
 			extension->addField(field);
-			field = TextSingleFormField::create("10.5.1");
+			field = boost::make_shared<FormField>(FormField::TextSingleType, "10.5.1");
 			field->setName("os_version");
-			field->addRawValue("10.5.1");
 			extension->addField(field);
 			discoInfo.addExtension(extension);
 
diff --git a/Swiften/Elements/Form.cpp b/Swiften/Elements/Form.cpp
index cf9ecf6..c4ae410 100644
--- a/Swiften/Elements/Form.cpp
+++ b/Swiften/Elements/Form.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Remko Tronçon
+ * Copyright (c) 2010-2013 Remko Tronçon
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
@@ -11,8 +11,10 @@ namespace Swift {
 
 std::string Form::getFormType() const {
 	FormField::ref field = getField("FORM_TYPE");
-	boost::shared_ptr<HiddenFormField> f = boost::dynamic_pointer_cast<HiddenFormField>(field);
-	return (f ? f->getValue() : "");
+	if (field && field->getType() == FormField::HiddenType) {
+		return field->getValues().empty() ? "" : field->getValues()[0];
+	}
+	return "";
 }
 
 FormField::ref Form::getField(const std::string& name) const {
diff --git a/Swiften/Elements/FormField.cpp b/Swiften/Elements/FormField.cpp
new file mode 100644
index 0000000..27ced82
--- /dev/null
+++ b/Swiften/Elements/FormField.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Elements/FormField.h>
+
+#include <boost/algorithm/string/split.hpp>
+#include <boost/algorithm/string/join.hpp>
+#include <boost/algorithm/string/classification.hpp>
+
+using namespace Swift;
+
+FormField::~FormField() {
+}
+
+std::string FormField::getTextMultiValue() const {
+	assert(type == TextMultiType || type == UnknownType);
+	return boost::algorithm::join(values, "\n");
+}
+
+void FormField::setTextMultiValue(const std::string& value) {
+	assert(type == TextMultiType || type == UnknownType);
+	values.clear();
+	boost::split(values, value, boost::is_any_of("\n"));
+}
+
+void FormField::setBoolValue(bool b) {
+	assert(type == BooleanType || type == UnknownType);
+	values.clear();
+	values.push_back(b ? "1" : "0");
+}
diff --git a/Swiften/Elements/FormField.h b/Swiften/Elements/FormField.h
index fbd1ebe..26e70bb 100644
--- a/Swiften/Elements/FormField.h
+++ b/Swiften/Elements/FormField.h
@@ -1,12 +1,9 @@
 /*
- * Copyright (c) 2010 Remko Tronçon
+ * Copyright (c) 2010-2013 Remko Tronçon
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
 
-// FIXME: We currently keep 2 values: the raw values, and the actual value.
-// We should only store the raw values, and deduce the actual values from this
-
 #pragma once
 
 #include <vector>
@@ -20,7 +17,25 @@ namespace Swift {
 		public:
 			typedef boost::shared_ptr<FormField> ref;
 
-			virtual ~FormField() {}
+			enum Type {
+				UnknownType,
+				BooleanType,
+				FixedType,
+				HiddenType,
+				ListSingleType,
+				TextMultiType,
+				TextPrivateType,
+				TextSingleType,
+				JIDSingleType,
+				JIDMultiType,
+				ListMultiType
+			};
+
+			FormField(Type type = UnknownType) : type(type), required(false) {}
+			FormField(Type type, const std::string& value) : type(type), required(false) {
+				addValue(value);
+			}
+			virtual ~FormField();
 
 			struct Option {
 				Option(const std::string& label, const std::string& value) : label(label), value(value) {}
@@ -48,67 +63,72 @@ namespace Swift {
 				return options;
 			}
 
-			const std::vector<std::string>& getRawValues() const {
-				return rawValues;
+			const std::vector<std::string>& getValues() const {
+				return values;
 			}
 
-			void addRawValue(const std::string& value) {
-				rawValues.push_back(value);
+			void addValue(const std::string& value) {
+				values.push_back(value);
 			}
 
-		protected:
-			FormField() : required(false) {}
+			Type getType() const {
+				return type;
+			}
 
-		private:
-			std::string name;
-			std::string label;
-			std::string description;
-			bool required;
-			std::vector<Option> options;
-			std::vector<std::string> rawValues;
-	};
+			void setType(Type type) {
+				this->type = type;
+			}
 
-	template<typename T> class GenericFormField : public FormField {
-		public:
-			const T& getValue() const {
-				return value;
+			// Type specific
+
+			bool getBoolValue() const {
+				assert(type == BooleanType || type == UnknownType);
+				if (values.empty()) {
+					return false;
+				}
+				return values[0] == "true" || values[0] == "1";
 			}
 
-			void setValue(const T& value) {
-				this->value = value;
+			void setBoolValue(bool b);
+
+			JID getJIDSingleValue() const {
+				assert(type == JIDSingleType || type == UnknownType);
+				return values.empty() ? JID() : JID(values[0]);
 			}
 
+			JID getJIDMultiValue(size_t index) const {
+				assert(type == JIDMultiType || type == UnknownType);
+				return values.empty() ? JID() : JID(values[index]);
+			}
+
+			std::string getTextPrivateValue() const {
+				assert(type == TextPrivateType || type == UnknownType);
+				return values.empty() ? "" : values[0];
+			}
+
+			std::string getFixedValue() const {
+				assert(type == FixedType || type == UnknownType);
+				return values.empty() ? "" : values[0];
+			}
+
+			std::string getTextSingleValue() const {
+				assert(type == TextSingleType || type == UnknownType);
+				return values.empty() ? "" : values[0];
+			}
+
+			std::string getTextMultiValue() const;
+			void setTextMultiValue(const std::string& value);
+
 		protected:
-			GenericFormField() : value() {}
-			GenericFormField(const T& value) : value(value) {}
 
 		private:
-			T value;
-	};
-
-#define SWIFTEN_DECLARE_FORM_FIELD(name, valueType) \
-	class name##FormField : public GenericFormField< valueType > { \
-		public: \
-			typedef boost::shared_ptr<name##FormField> ref; \
-			static ref create(const valueType& value) { \
-				return ref(new name##FormField(value)); \
-			} \
-			static ref create() { \
-				return ref(new name##FormField()); \
-			} \
-		private: \
-			name##FormField(valueType value) : GenericFormField< valueType >(value) {} \
-			name##FormField() : GenericFormField< valueType >() {} \
+			Type type;
+			std::string name;
+			std::string label;
+			std::string description;
+			bool required;
+			std::vector<Option> options;
+			std::vector<std::string> values;
 	};
 
-	SWIFTEN_DECLARE_FORM_FIELD(Boolean, bool)
-	SWIFTEN_DECLARE_FORM_FIELD(Fixed, std::string)
-	SWIFTEN_DECLARE_FORM_FIELD(Hidden, std::string)
-	SWIFTEN_DECLARE_FORM_FIELD(ListSingle, std::string)
-	SWIFTEN_DECLARE_FORM_FIELD(TextMulti, std::string)
-	SWIFTEN_DECLARE_FORM_FIELD(TextPrivate, std::string)
-	SWIFTEN_DECLARE_FORM_FIELD(TextSingle, std::string)
-	SWIFTEN_DECLARE_FORM_FIELD(JIDSingle, JID)
-	SWIFTEN_DECLARE_FORM_FIELD(JIDMulti, std::vector<JID>)
-	SWIFTEN_DECLARE_FORM_FIELD(ListMulti, std::vector<std::string>)
 }
diff --git a/Swiften/Elements/UnitTest/FormTest.cpp b/Swiften/Elements/UnitTest/FormTest.cpp
index 1134182..3000c22 100644
--- a/Swiften/Elements/UnitTest/FormTest.cpp
+++ b/Swiften/Elements/UnitTest/FormTest.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Remko Tronçon
+ * Copyright (c) 2010-2013 Remko Tronçon
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
@@ -7,6 +7,7 @@
 #include <cppunit/extensions/HelperMacros.h>
 #include <cppunit/extensions/TestFactoryRegistry.h>
 #include <boost/shared_ptr.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
 
 #include <Swiften/Elements/Form.h>
 
@@ -23,13 +24,13 @@ class FormTest : public CppUnit::TestFixture {
 		void testGetFormType() {
 			Form form;
 
-			form.addField(FixedFormField::create("Foo"));
+			form.addField(boost::make_shared<FormField>(FormField::FixedType, "Foo"));
 
-			FormField::ref field = HiddenFormField::create("jabber:bot");
+			FormField::ref field = boost::make_shared<FormField>(FormField::HiddenType, "jabber:bot");
 			field->setName("FORM_TYPE");
 			form.addField(field);
 
-			form.addField(FixedFormField::create("Bar"));
+			form.addField(boost::make_shared<FormField>(FormField::FixedType, "Bar"));
 
 			CPPUNIT_ASSERT_EQUAL(std::string("jabber:bot"), form.getFormType());
 		}
@@ -37,7 +38,7 @@ class FormTest : public CppUnit::TestFixture {
 		void testGetFormType_InvalidFormType() {
 			Form form;
 
-			FormField::ref field = FixedFormField::create("jabber:bot");
+			FormField::ref field = boost::make_shared<FormField>(FormField::FixedType, "jabber:bot");
 			field->setName("FORM_TYPE");
 			form.addField(field);
 
@@ -47,7 +48,7 @@ class FormTest : public CppUnit::TestFixture {
 		void testGetFormType_NoFormType() {
 			Form form;
 
-			form.addField(FixedFormField::create("Foo"));
+			form.addField(boost::make_shared<FormField>(FormField::FixedType, "Foo"));
 
 			CPPUNIT_ASSERT_EQUAL(std::string(""), form.getFormType());
 		}
diff --git a/Swiften/Parser/PayloadParsers/FormParser.cpp b/Swiften/Parser/PayloadParsers/FormParser.cpp
index 2df0a85..7c29189 100644
--- a/Swiften/Parser/PayloadParsers/FormParser.cpp
+++ b/Swiften/Parser/PayloadParsers/FormParser.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Remko Tronçon
+ * Copyright (c) 2010-2013 Remko Tronçon
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
@@ -10,7 +10,7 @@
 
 namespace Swift {
 
-FormParser::FormParser() : level_(TopLevel), parsingItem_(false), parsingReported_(false) {
+FormParser::FormParser() : level_(TopLevel), parsingItem_(false), parsingReported_(false), parsingOption_(false) {
 }
 
 void FormParser::handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) {
@@ -36,67 +36,62 @@ void FormParser::handleStartElement(const std::string& element, const std::strin
 		else if (element == "instructions") {
 			currentText_.clear();
 		}
-		else if (element == "field") {
-			std::string type;
-			FormField::ref correspondingReportedField;
-			if (!parsingItem_) {
-				type = attributes.getAttribute("type");
-			} else {
-				foreach(FormField::ref field, getPayloadInternal()->getReportedFields()) {
-					if (field->getName() == attributes.getAttribute("var")) {
-						correspondingReportedField = field;
-						break;
-					}
-				}
-			}
-			if (type == "boolean" || boost::dynamic_pointer_cast<BooleanFormField>(correspondingReportedField)) {
-				currentFieldParseHelper_ = BooleanFormFieldParseHelper::create();
-			}
-			else if (type == "fixed" || boost::dynamic_pointer_cast<FixedFormField>(correspondingReportedField)) {
-				currentFieldParseHelper_ = FixedFormFieldParseHelper::create();
+		else if (element == "reported") {
+			parsingReported_ = true;
+		}
+		else if (element == "item") {
+			parsingItem_ = true;
+		}
+	}
+	else if (level_ == FieldLevel && currentField_) {
+		currentText_.clear();
+		if (element == "option") {
+			currentOptionLabel_ = attributes.getAttribute("label");
+			currentOptionValue_ = "";
+			parsingOption_ = true;
+		}
+	}
+	if (level_ >= PayloadLevel) {
+		if (element == "field") {
+			currentField_ = boost::make_shared<FormField>();
+			std::string type = attributes.getAttribute("type");
+			FormField::Type fieldType = FormField::UnknownType;
+			if (type == "boolean") {
+				fieldType = FormField::BooleanType; 
 			}
-			else if (type == "hidden" || boost::dynamic_pointer_cast<HiddenFormField>(correspondingReportedField)) {
-				currentFieldParseHelper_ = HiddenFormFieldParseHelper::create();
+			if (type == "fixed") {
+				fieldType = FormField::FixedType; 
 			}
-			else if (type == "jid-multi" || boost::dynamic_pointer_cast<JIDMultiFormField>(correspondingReportedField)) {
-				currentFieldParseHelper_ = JIDMultiFormFieldParseHelper::create();
+			if (type == "hidden") {
+				fieldType = FormField::HiddenType; 
 			}
-			else if (type == "jid-single" || boost::dynamic_pointer_cast<JIDSingleFormField>(correspondingReportedField)) {
-				currentFieldParseHelper_ = JIDSingleFormFieldParseHelper::create();
+			if (type == "list-single") {
+				fieldType = FormField::ListSingleType; 
 			}
-			else if (type == "list-multi" || boost::dynamic_pointer_cast<ListMultiFormField>(correspondingReportedField)) {
-				currentFieldParseHelper_ = ListMultiFormFieldParseHelper::create();
+			if (type == "text-multi") {
+				fieldType = FormField::TextMultiType; 
 			}
-			else if (type == "list-single" || boost::dynamic_pointer_cast<ListSingleFormField>(correspondingReportedField)) {
-				currentFieldParseHelper_ = ListSingleFormFieldParseHelper::create();
+			if (type == "text-private") {
+				fieldType = FormField::TextPrivateType; 
 			}
-			else if (type == "text-multi" || boost::dynamic_pointer_cast<TextMultiFormField>(correspondingReportedField)) {
-				currentFieldParseHelper_ = TextMultiFormFieldParseHelper::create();
+			if (type == "text-single") {
+				fieldType = FormField::TextSingleType; 
 			}
-			else if (type == "text-private" || boost::dynamic_pointer_cast<TextPrivateFormField>(correspondingReportedField)) {
-				currentFieldParseHelper_ = TextPrivateFormFieldParseHelper::create();
+			if (type == "jid-single") {
+				fieldType = FormField::JIDSingleType; 
 			}
-			else /*if (type == "text-single") || undefined */ {
-				currentFieldParseHelper_ = TextSingleFormFieldParseHelper::create();
+			if (type == "jid-multi") {
+				fieldType = FormField::JIDMultiType; 
 			}
-			if (currentFieldParseHelper_) {
-				currentFieldParseHelper_->getField()->setName(attributes.getAttribute("var"));
-				currentFieldParseHelper_->getField()->setLabel(attributes.getAttribute("label"));
+			if (type == "list-multi") {
+				fieldType = FormField::ListMultiType; 
 			}
+			currentField_->setType(fieldType);
+			currentField_->setName(attributes.getAttribute("var"));
+			currentField_->setLabel(attributes.getAttribute("label"));
 		}
-		else if (element == "reported") {
-			parsingReported_ = true;
-			level_ = PayloadLevel - 1;
-		}
-		else if (element == "item") {
-			parsingItem_ = true;
-			level_ = PayloadLevel - 1;
-		}
-	}
-	else if (level_ == FieldLevel && currentFieldParseHelper_) {
-		currentText_.clear();
-		if (element == "option") {
-			currentOptionLabel_ = attributes.getAttribute("label");
+		else if (element == "value") {
+			currentText_.clear();
 		}
 	}
 	++level_;
@@ -123,42 +118,48 @@ void FormParser::handleEndElement(const std::string& element, const std::string&
 				getPayloadInternal()->setInstructions(currentInstructions + "\n" + currentText_);
 			}
 		}
-		else if (element == "field") {
-			if (currentFieldParseHelper_) {
-				if (parsingReported_) {
-					getPayloadInternal()->addReportedField(currentFieldParseHelper_->getField());
-				} else if (parsingItem_) {
-					currentFields_.push_back(currentFieldParseHelper_->getField());
-				} else {
-					getPayloadInternal()->addField(currentFieldParseHelper_->getField());
-				}
-				currentFieldParseHelper_.reset();
-			}
+		else if (element == "reported") {
+			parsingReported_ = false;
+		}
+		else if (element == "item") {
+			parsingItem_ = false;
+			getPayloadInternal()->addItem(currentFields_);
+			currentFields_.clear();
 		}
 	}
-	else if (level_ == FieldLevel && currentFieldParseHelper_) {
+	else if (currentField_) {
 		if (element == "required") {
-			currentFieldParseHelper_->getField()->setRequired(true);
+			currentField_->setRequired(true);
 		}
 		else if (element == "desc") {
-			currentFieldParseHelper_->getField()->setDescription(currentText_);
+			currentField_->setDescription(currentText_);
 		}
 		else if (element == "option") {
-			currentFieldParseHelper_->getField()->addOption(FormField::Option(currentOptionLabel_, currentText_));
+			currentField_->addOption(FormField::Option(currentOptionLabel_, currentOptionValue_));
+			parsingOption_ = false;
 		}
 		else if (element == "value") {
-			currentFieldParseHelper_->addValue(currentText_);
+			if (parsingOption_) {
+				currentOptionValue_ = currentText_;
+			}
+			else {
+				currentField_->addValue(currentText_);
+			}
 		}
 	}
-	if (element == "reported") {
-		parsingReported_ = false;
-		level_++;
-	}
-	else if (element == "item") {
-		parsingItem_ = false;
-		level_++;
-		getPayloadInternal()->addItem(currentFields_);
-		currentFields_.clear();
+	if (level_ >= PayloadLevel && currentField_) {
+		if (element == "field") {
+			if (parsingReported_) {
+				getPayloadInternal()->addReportedField(currentField_);
+			} 
+			else if (parsingItem_) {
+				currentFields_.push_back(currentField_);
+			} 
+			else {
+				getPayloadInternal()->addField(currentField_);
+			}
+			currentField_.reset();
+		}
 	}
 }
 
diff --git a/Swiften/Parser/PayloadParsers/FormParser.h b/Swiften/Parser/PayloadParsers/FormParser.h
index ec480a5..0b23a81 100644
--- a/Swiften/Parser/PayloadParsers/FormParser.h
+++ b/Swiften/Parser/PayloadParsers/FormParser.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Remko Tronçon
+ * Copyright (c) 2010-2013 Remko Tronçon
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
@@ -18,86 +18,6 @@ namespace Swift {
 			virtual void handleEndElement(const std::string& element, const std::string&);
 			virtual void handleCharacterData(const std::string& data);
 
-		private:
-			class FieldParseHelper {
-				public:
-					virtual ~FieldParseHelper() {}
-					virtual void addValue(const std::string&) = 0;
-					virtual boost::shared_ptr<FormField> getField() const {
-						return field;
-					}
-				protected:
-					boost::shared_ptr<FormField> field;
-			};
-			class BoolFieldParseHelper : public FieldParseHelper {
-					virtual void addValue(const std::string& s) {
-						boost::dynamic_pointer_cast< GenericFormField<bool> >(getField())->setValue(s == "1" || s == "true");
-						getField()->addRawValue(s);
-					}
-			};
-			class StringFieldParseHelper : public FieldParseHelper {
-					virtual void addValue(const std::string& s) {
-						boost::shared_ptr<GenericFormField<std::string> > field = boost::dynamic_pointer_cast< GenericFormField<std::string> >(getField());
-						if (field->getValue().empty()) {
-							field->setValue(s);
-						}
-						else {
-							field->setValue(field->getValue() + "\n" + s);
-						}
-						getField()->addRawValue(s);
-					}
-			};
-			class JIDFieldParseHelper : public FieldParseHelper {
-					virtual void addValue(const std::string& s) {
-						getField()->addRawValue(s);
-						boost::dynamic_pointer_cast< GenericFormField<JID> >(getField())->setValue(JID(s));
-					}
-			};
-			class StringListFieldParseHelper : public FieldParseHelper {
-					virtual void addValue(const std::string& s) {
-						// FIXME: Inefficient, but too much hassle to do efficiently
-						boost::shared_ptr<GenericFormField< std::vector<std::string> > > field = boost::dynamic_pointer_cast< GenericFormField<std::vector<std::string > > >(getField());
-						std::vector<std::string> l = field->getValue();
-						l.push_back(s);
-						field->setValue(l);
-						getField()->addRawValue(s);
-					}
-			};
-			class JIDListFieldParseHelper : public FieldParseHelper {
-					virtual void addValue(const std::string& s) {
-						// FIXME: Inefficient, but too much hassle to do efficiently
-						boost::shared_ptr< GenericFormField< std::vector<JID> > > field = boost::dynamic_pointer_cast< GenericFormField<std::vector<JID > > >(getField());
-						std::vector<JID> l = field->getValue();
-						l.push_back(JID(s));
-						field->setValue(l);
-						getField()->addRawValue(s);
-					}
-			};
-			
-#define SWIFTEN_DECLARE_FORM_FIELD_PARSE_HELPER(name, baseParser) \
-	class name##FormFieldParseHelper : public baseParser##FieldParseHelper { \
-		public: \
-			typedef boost::shared_ptr<name##FormFieldParseHelper> ref; \
-			static ref create() { \
-				return ref(new name##FormFieldParseHelper()); \
-			} \
-		private: \
-			name##FormFieldParseHelper() : baseParser##FieldParseHelper() { \
-				field = name##FormField::create(); \
-			} \
-	}
-
-			SWIFTEN_DECLARE_FORM_FIELD_PARSE_HELPER(Boolean, Bool);
-			SWIFTEN_DECLARE_FORM_FIELD_PARSE_HELPER(Fixed, String);
-			SWIFTEN_DECLARE_FORM_FIELD_PARSE_HELPER(Hidden, String);
-			SWIFTEN_DECLARE_FORM_FIELD_PARSE_HELPER(ListSingle, String);
-			SWIFTEN_DECLARE_FORM_FIELD_PARSE_HELPER(TextMulti, String);
-			SWIFTEN_DECLARE_FORM_FIELD_PARSE_HELPER(TextPrivate, String);
-			SWIFTEN_DECLARE_FORM_FIELD_PARSE_HELPER(TextSingle, String);
-			SWIFTEN_DECLARE_FORM_FIELD_PARSE_HELPER(JIDSingle, JID);
-			SWIFTEN_DECLARE_FORM_FIELD_PARSE_HELPER(JIDMulti, JIDList);
-			SWIFTEN_DECLARE_FORM_FIELD_PARSE_HELPER(ListMulti, StringList);
-
 			enum Level { 
 				TopLevel = 0, 
 				PayloadLevel = 1,
@@ -106,9 +26,11 @@ namespace Swift {
 			int level_;
 			std::string currentText_;
 			std::string currentOptionLabel_;
-			boost::shared_ptr<FieldParseHelper> currentFieldParseHelper_;
+			std::string currentOptionValue_;
 			bool parsingItem_;
 			bool parsingReported_;
+			bool parsingOption_;
+			FormField::ref currentField_;
 			std::vector<FormField::ref> currentFields_;
 	};
 }
diff --git a/Swiften/Parser/PayloadParsers/StreamInitiationParser.cpp b/Swiften/Parser/PayloadParsers/StreamInitiationParser.cpp
index 20bad8c..ff0a061 100644
--- a/Swiften/Parser/PayloadParsers/StreamInitiationParser.cpp
+++ b/Swiften/Parser/PayloadParsers/StreamInitiationParser.cpp
@@ -96,8 +96,8 @@ void StreamInitiationParser::handleEndElement(const std::string& element, const
 						}
 					}
 					else if (form->getType() == Form::SubmitType) {
-						if (field->getRawValues().size() > 0) {
-							getPayloadInternal()->setRequestedMethod(field->getRawValues()[0]);
+						if (!field->getValues().empty()) {
+							getPayloadInternal()->setRequestedMethod(field->getValues()[0]);
 						}
 					}
 				}
diff --git a/Swiften/Parser/PayloadParsers/UnitTest/FormParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/FormParserTest.cpp
index c36fbeb..bc8f1bc 100644
--- a/Swiften/Parser/PayloadParsers/UnitTest/FormParserTest.cpp
+++ b/Swiften/Parser/PayloadParsers/UnitTest/FormParserTest.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Remko Tronçon
+ * Copyright (c) 2010-2013 Remko Tronçon
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
@@ -54,13 +54,13 @@ class FormParserTest : public CppUnit::TestFixture {
 						"</field>"
 						"<field label=\"Password for special access\" type=\"text-private\" var=\"password\"/>"
 						"<field label=\"What features will the bot support?\" type=\"list-multi\" var=\"features\">"
-							"<value>news</value>"
-							"<value>search</value>"
 							"<option label=\"Contests\"><value>contests</value></option>"
 							"<option label=\"News\"><value>news</value></option>"
 							"<option label=\"Polls\"><value>polls</value></option>"
 							"<option label=\"Reminders\"><value>reminders</value></option>"
 							"<option label=\"Search\"><value>search</value></option>"
+							"<value>news</value>"
+							"<value>search</value>"
 						"</field>"
 						"<field label=\"Maximum number of subscribers\" type=\"list-single\" var=\"maxsubs\">"
 							"<value>20</value>"
@@ -84,37 +84,35 @@ class FormParserTest : public CppUnit::TestFixture {
 			Form* payload = dynamic_cast<Form*>(parser.getPayload().get());
 
 			CPPUNIT_ASSERT_EQUAL(10, static_cast<int>(payload->getFields().size()));
-			CPPUNIT_ASSERT_EQUAL(std::string("jabber:bot"), boost::dynamic_pointer_cast<HiddenFormField>(payload->getFields()[0])->getValue());
+			CPPUNIT_ASSERT_EQUAL(std::string("jabber:bot"), payload->getFields()[0]->getValues()[0]);
 			CPPUNIT_ASSERT_EQUAL(std::string("FORM_TYPE"), payload->getFields()[0]->getName());
 			CPPUNIT_ASSERT(!payload->getFields()[0]->getRequired());
 
-			CPPUNIT_ASSERT_EQUAL(std::string("Section 1: Bot Info"), boost::dynamic_pointer_cast<FixedFormField>(payload->getFields()[1])->getValue());
+			CPPUNIT_ASSERT_EQUAL(std::string("Section 1: Bot Info"), payload->getFields()[1]->getValues()[0]);
 
 			CPPUNIT_ASSERT_EQUAL(std::string("The name of your bot"), payload->getFields()[2]->getLabel());
 
-			CPPUNIT_ASSERT_EQUAL(std::string("This is a bot.\nA quite good one actually"), boost::dynamic_pointer_cast<TextMultiFormField>(payload->getFields()[3])->getValue());
+			CPPUNIT_ASSERT_EQUAL(std::string("This is a bot.\nA quite good one actually"), payload->getFields()[3]->getTextMultiValue());
 
-			CPPUNIT_ASSERT_EQUAL(true, boost::dynamic_pointer_cast<BooleanFormField>(payload->getFields()[4])->getValue());
+			CPPUNIT_ASSERT_EQUAL(true, payload->getFields()[4]->getBoolValue());
 			CPPUNIT_ASSERT(payload->getFields()[4]->getRequired());
-			CPPUNIT_ASSERT_EQUAL(std::string("1"),  boost::dynamic_pointer_cast<BooleanFormField>(payload->getFields()[4])->getRawValues()[0]);
-
-			CPPUNIT_ASSERT_EQUAL(std::string("news"), boost::dynamic_pointer_cast<ListMultiFormField>(payload->getFields()[6])->getValue()[0]);
-			CPPUNIT_ASSERT_EQUAL(std::string("news"), payload->getFields()[6]->getRawValues()[0]);
-			CPPUNIT_ASSERT_EQUAL(std::string("search"), boost::dynamic_pointer_cast<ListMultiFormField>(payload->getFields()[6])->getValue()[1]);
-			CPPUNIT_ASSERT_EQUAL(std::string("search"), payload->getFields()[6]->getRawValues()[1]);
+			CPPUNIT_ASSERT_EQUAL(std::string("1"),  payload->getFields()[4]->getValues()[0]);
+			CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(payload->getFields()[6]->getValues().size()));
+			CPPUNIT_ASSERT_EQUAL(std::string("news"), payload->getFields()[6]->getValues()[0]);
+			CPPUNIT_ASSERT_EQUAL(std::string("search"), payload->getFields()[6]->getValues()[1]);
 			CPPUNIT_ASSERT_EQUAL(5, static_cast<int>(payload->getFields()[6]->getOptions().size()));
 			CPPUNIT_ASSERT_EQUAL(std::string("Contests"), payload->getFields()[6]->getOptions()[0].label);
 			CPPUNIT_ASSERT_EQUAL(std::string("contests"), payload->getFields()[6]->getOptions()[0].value);
 			CPPUNIT_ASSERT_EQUAL(std::string("News"), payload->getFields()[6]->getOptions()[1].label);
 			CPPUNIT_ASSERT_EQUAL(std::string("news"), payload->getFields()[6]->getOptions()[1].value);
 
-			CPPUNIT_ASSERT_EQUAL(std::string("20"), boost::dynamic_pointer_cast<ListSingleFormField>(payload->getFields()[7])->getValue());
+			CPPUNIT_ASSERT_EQUAL(std::string("20"), payload->getFields()[7]->getValues()[0]);
 
-			CPPUNIT_ASSERT_EQUAL(JID("foo@bar.com"), boost::dynamic_pointer_cast<JIDMultiFormField>(payload->getFields()[8])->getValue()[0]);
-			CPPUNIT_ASSERT_EQUAL(JID("baz@fum.org"), boost::dynamic_pointer_cast<JIDMultiFormField>(payload->getFields()[8])->getValue()[1]);
+			CPPUNIT_ASSERT_EQUAL(JID("foo@bar.com"), payload->getFields()[8]->getJIDMultiValue(0));
+			CPPUNIT_ASSERT_EQUAL(JID("baz@fum.org"), payload->getFields()[8]->getJIDMultiValue(1));
 			CPPUNIT_ASSERT_EQUAL(std::string("Tell all your friends about your new bot!"), payload->getFields()[8]->getDescription());
 
-			CPPUNIT_ASSERT_EQUAL(std::string("foo"), boost::dynamic_pointer_cast<TextSingleFormField>(payload->getFields()[9])->getValue());
+			CPPUNIT_ASSERT_EQUAL(std::string("foo"), payload->getFields()[9]->getValues()[0]);
 		}
 
 		void testParse_FormItems() {
@@ -157,29 +155,28 @@ class FormParserTest : public CppUnit::TestFixture {
 			Form::FormItem item = items[0];
 			CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), item.size());
 
-			CPPUNIT_ASSERT_EQUAL(std::string("Benvolio"), item[0]->getRawValues()[0]);
+			CPPUNIT_ASSERT_EQUAL(std::string("Benvolio"), item[0]->getValues()[0]);
 			CPPUNIT_ASSERT_EQUAL(std::string("first"), item[0]->getName());
-			CPPUNIT_ASSERT_EQUAL(std::string("Montague"), item[1]->getRawValues()[0]);
+			CPPUNIT_ASSERT_EQUAL(std::string("Montague"), item[1]->getValues()[0]);
 			CPPUNIT_ASSERT_EQUAL(std::string("last"), item[1]->getName());
-			JIDSingleFormField::ref jidField = boost::dynamic_pointer_cast<JIDSingleFormField>(item[2]);
-			CPPUNIT_ASSERT(jidField);
-			CPPUNIT_ASSERT_EQUAL(JID("benvolio@montague.net"), jidField->getValue());
+			boost::shared_ptr<FormField> jidField = item[2];
+			CPPUNIT_ASSERT_EQUAL(JID("benvolio@montague.net"), jidField->getJIDSingleValue());
 			CPPUNIT_ASSERT_EQUAL(std::string("jid"), item[2]->getName());
-			CPPUNIT_ASSERT_EQUAL(std::string("male"), item[3]->getRawValues()[0]);
+			CPPUNIT_ASSERT_EQUAL(std::string("male"), item[3]->getValues()[0]);
 			CPPUNIT_ASSERT_EQUAL(std::string("x-gender"), item[3]->getName());
 
 			item = items[1];
 			CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), item.size());
 
-			CPPUNIT_ASSERT_EQUAL(std::string("Romeo"), item[0]->getRawValues()[0]);
+			CPPUNIT_ASSERT_EQUAL(std::string("Romeo"), item[0]->getValues()[0]);
 			CPPUNIT_ASSERT_EQUAL(std::string("first"), item[0]->getName());
-			CPPUNIT_ASSERT_EQUAL(std::string("Montague"), item[1]->getRawValues()[0]);
+			CPPUNIT_ASSERT_EQUAL(std::string("Montague"), item[1]->getValues()[0]);
 			CPPUNIT_ASSERT_EQUAL(std::string("last"), item[1]->getName());
-			jidField = boost::dynamic_pointer_cast<JIDSingleFormField>(item[2]);
+			jidField = item[2];
 			CPPUNIT_ASSERT(jidField);
-			CPPUNIT_ASSERT_EQUAL(JID("romeo@montague.net"), jidField->getValue());
+			CPPUNIT_ASSERT_EQUAL(JID("romeo@montague.net"), jidField->getJIDSingleValue());
 			CPPUNIT_ASSERT_EQUAL(std::string("jid"), item[2]->getName());
-			CPPUNIT_ASSERT_EQUAL(std::string("male"), item[3]->getRawValues()[0]);
+			CPPUNIT_ASSERT_EQUAL(std::string("male"), item[3]->getValues()[0]);
 			CPPUNIT_ASSERT_EQUAL(std::string("x-gender"), item[3]->getName());
 		}
 };
diff --git a/Swiften/Parser/PayloadParsers/UnitTest/SearchPayloadParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/SearchPayloadParserTest.cpp
index ef48ced..59ea3ff 100644
--- a/Swiften/Parser/PayloadParsers/UnitTest/SearchPayloadParserTest.cpp
+++ b/Swiften/Parser/PayloadParsers/UnitTest/SearchPayloadParserTest.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Remko Tronçon
+ * Copyright (c) 2010-2013 Remko Tronçon
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
@@ -155,25 +155,25 @@ class SearchPayloadParserTest : public CppUnit::TestFixture {
 			Form::FormItem item = items[0];
 			CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), item.size());
 
-			CPPUNIT_ASSERT_EQUAL(std::string("Benvolio"), item[0]->getRawValues()[0]);
+			CPPUNIT_ASSERT_EQUAL(std::string("Benvolio"), item[0]->getValues()[0]);
 			CPPUNIT_ASSERT_EQUAL(std::string("first"), item[0]->getName());
-			CPPUNIT_ASSERT_EQUAL(std::string("Montague"), item[1]->getRawValues()[0]);
+			CPPUNIT_ASSERT_EQUAL(std::string("Montague"), item[1]->getValues()[0]);
 			CPPUNIT_ASSERT_EQUAL(std::string("last"), item[1]->getName());
-			CPPUNIT_ASSERT_EQUAL(std::string("benvolio@montague.net"), item[2]->getRawValues()[0]);
+			CPPUNIT_ASSERT_EQUAL(std::string("benvolio@montague.net"), item[2]->getValues()[0]);
 			CPPUNIT_ASSERT_EQUAL(std::string("jid"), item[2]->getName());
-			CPPUNIT_ASSERT_EQUAL(std::string("male"), item[3]->getRawValues()[0]);
+			CPPUNIT_ASSERT_EQUAL(std::string("male"), item[3]->getValues()[0]);
 			CPPUNIT_ASSERT_EQUAL(std::string("x-gender"), item[3]->getName());
 
 			item = items[1];
 			CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), item.size());
 
-			CPPUNIT_ASSERT_EQUAL(std::string("Romeo"), item[0]->getRawValues()[0]);
+			CPPUNIT_ASSERT_EQUAL(std::string("Romeo"), item[0]->getValues()[0]);
 			CPPUNIT_ASSERT_EQUAL(std::string("first"), item[0]->getName());
-			CPPUNIT_ASSERT_EQUAL(std::string("Montague"), item[1]->getRawValues()[0]);
+			CPPUNIT_ASSERT_EQUAL(std::string("Montague"), item[1]->getValues()[0]);
 			CPPUNIT_ASSERT_EQUAL(std::string("last"), item[1]->getName());
-			CPPUNIT_ASSERT_EQUAL(std::string("romeo@montague.net"), item[2]->getRawValues()[0]);
+			CPPUNIT_ASSERT_EQUAL(std::string("romeo@montague.net"), item[2]->getValues()[0]);
 			CPPUNIT_ASSERT_EQUAL(std::string("jid"), item[2]->getName());
-			CPPUNIT_ASSERT_EQUAL(std::string("male"), item[3]->getRawValues()[0]);
+			CPPUNIT_ASSERT_EQUAL(std::string("male"), item[3]->getValues()[0]);
 			CPPUNIT_ASSERT_EQUAL(std::string("x-gender"), item[3]->getName());
 		}
 };
diff --git a/Swiften/SConscript b/Swiften/SConscript
index b2c47f1..3edb463 100644
--- a/Swiften/SConscript
+++ b/Swiften/SConscript
@@ -120,6 +120,7 @@ if env["SCONS_STAGE"] == "build" :
 			"Elements/DiscoInfo.cpp",
 			"Elements/Presence.cpp",
 			"Elements/Form.cpp",
+			"Elements/FormField.cpp",
 			"Elements/StreamFeatures.cpp",
 			"Elements/Element.cpp",
 			"Elements/IQ.cpp",
diff --git a/Swiften/Serializer/PayloadSerializers/FormSerializer.cpp b/Swiften/Serializer/PayloadSerializers/FormSerializer.cpp
index ba658e3..cf0f4ea 100644
--- a/Swiften/Serializer/PayloadSerializers/FormSerializer.cpp
+++ b/Swiften/Serializer/PayloadSerializers/FormSerializer.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Kevin Smith
+ * Copyright (c) 2010-2013 Kevin Smith
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
@@ -37,6 +37,10 @@ FormSerializer::FormSerializer() : GenericPayloadSerializer<Form>() {
 }
 
 std::string FormSerializer::serializePayload(boost::shared_ptr<Form> form)  const {
+	if (!form) {
+		return "";
+	}
+
 	boost::shared_ptr<XMLElement> formElement(new XMLElement("x", "jabber:x:data"));
 	std::string type;
 	switch (form->getType()) {
@@ -92,66 +96,27 @@ boost::shared_ptr<XMLElement> FormSerializer::fieldToXML(boost::shared_ptr<FormF
 
 	// Set the value and type
 	std::string fieldType;
-	if (boost::dynamic_pointer_cast<BooleanFormField>(field)) {
-		fieldType = "boolean";
-		boost::shared_ptr<XMLElement> valueElement(new XMLElement("value"));
-		valueElement->addNode(XMLTextNode::create(boost::dynamic_pointer_cast<BooleanFormField>(field)->getValue() ? "1" : "0"));
-		fieldElement->addNode(valueElement);
-	}
-	else if (boost::dynamic_pointer_cast<FixedFormField>(field)) {
-		fieldType = "fixed";
-		serializeValueAsString<FixedFormField>(field, fieldElement);
-	}
-	else if (boost::dynamic_pointer_cast<HiddenFormField>(field)) {
-		fieldType = "hidden";
-		serializeValueAsString<HiddenFormField>(field, fieldElement);
-	}
-	else if (boost::dynamic_pointer_cast<ListSingleFormField>(field)) {
-		fieldType = "list-single";
-		serializeValueAsString<ListSingleFormField>(field, fieldElement);
-	}
-	else if (boost::dynamic_pointer_cast<TextPrivateFormField>(field)) {
-		fieldType = "text-private";
-		serializeValueAsString<TextPrivateFormField>(field, fieldElement);
-	}
-	else if (boost::dynamic_pointer_cast<TextSingleFormField>(field)) {
-		fieldType = "text-single";
-		serializeValueAsString<TextSingleFormField>(field, fieldElement);
-	}
-	else if (boost::dynamic_pointer_cast<JIDMultiFormField>(field)) {
-		fieldType = "jid-multi";
-		std::vector<JID> jids = boost::dynamic_pointer_cast<JIDMultiFormField>(field)->getValue();
-		foreach(const JID& jid, jids) {
-			boost::shared_ptr<XMLElement> valueElement(new XMLElement("value"));
-			valueElement->addNode(XMLTextNode::create(jid.toString()));
-			fieldElement->addNode(valueElement);
-		}
-	}
-	else if (boost::dynamic_pointer_cast<JIDSingleFormField>(field)) {
-		fieldType = "jid-single";
-		boost::shared_ptr<XMLElement> valueElement(new XMLElement("value"));
-		valueElement->addNode(XMLTextNode::create(boost::dynamic_pointer_cast<JIDSingleFormField>(field)->getValue().toString()));
-		if ( boost::dynamic_pointer_cast<JIDSingleFormField>(field)->getValue().isValid()) fieldElement->addNode(valueElement);
-	}
-	else if (boost::dynamic_pointer_cast<ListMultiFormField>(field)) {
-		fieldType = "list-multi";
-		std::vector<std::string> lines = boost::dynamic_pointer_cast<ListMultiFormField>(field)->getValue();
-		foreach(const std::string& line, lines) {
-			boost::shared_ptr<XMLElement> valueElement(new XMLElement("value"));
-			valueElement->addNode(XMLTextNode::create(line));
-			fieldElement->addNode(valueElement);
-		}
-	}
-	else if (boost::dynamic_pointer_cast<TextMultiFormField>(field)) {
-		fieldType = "text-multi";
-		multiLineify(boost::dynamic_pointer_cast<TextMultiFormField>(field)->getValue(), "value", fieldElement);
-	}
-	else {
-		assert(false);
+	switch (field->getType()) {
+		case FormField::UnknownType: fieldType = ""; break;
+		case FormField::BooleanType: fieldType = "boolean"; break;
+		case FormField::FixedType: fieldType = "fixed"; break;
+		case FormField::HiddenType: fieldType = "hidden"; break;
+		case FormField::ListSingleType: fieldType = "list-single"; break;
+		case FormField::TextMultiType: fieldType = "text-multi"; break;
+		case FormField::TextPrivateType: fieldType = "text-private"; break;
+		case FormField::TextSingleType: fieldType = "text-single"; break;
+		case FormField::JIDSingleType: fieldType = "jid-single"; break;
+		case FormField::JIDMultiType: fieldType = "jid-multi"; break;
+		case FormField::ListMultiType: fieldType = "list-multi"; break;
 	}
 	if (!fieldType.empty() && withTypeAttribute) {
 		fieldElement->setAttribute("type", fieldType);
 	}
+	foreach (const std::string& value, field->getValues()) {
+		boost::shared_ptr<XMLElement> valueElement = boost::make_shared<XMLElement>("value");
+		valueElement->addNode(boost::make_shared<XMLTextNode>(value));
+		fieldElement->addNode(valueElement);
+	}
 
 	foreach (const FormField::Option& option, field->getOptions()) {
 		boost::shared_ptr<XMLElement> optionElement(new XMLElement("option"));
diff --git a/Swiften/Serializer/PayloadSerializers/FormSerializer.h b/Swiften/Serializer/PayloadSerializers/FormSerializer.h
index bb31c97..f0f365c 100644
--- a/Swiften/Serializer/PayloadSerializers/FormSerializer.h
+++ b/Swiften/Serializer/PayloadSerializers/FormSerializer.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Kevin Smith
+ * Copyright (c) 2010-2013 Kevin Smith
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
diff --git a/Swiften/Serializer/PayloadSerializers/StreamInitiationSerializer.cpp b/Swiften/Serializer/PayloadSerializers/StreamInitiationSerializer.cpp
index 030b024..973ced9 100644
--- a/Swiften/Serializer/PayloadSerializers/StreamInitiationSerializer.cpp
+++ b/Swiften/Serializer/PayloadSerializers/StreamInitiationSerializer.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Remko Tronçon
+ * Copyright (c) 2010-2013 Remko Tronçon
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
@@ -52,7 +52,7 @@ std::string StreamInitiationSerializer::serializePayload(boost::shared_ptr<Strea
 	boost::shared_ptr<XMLElement> featureElement(new XMLElement("feature", FEATURE_NEG_NS));
 	if (streamInitiation->getProvidedMethods().size() > 0) {
 		Form::ref form(new Form(Form::FormType));
-		ListSingleFormField::ref field = ListSingleFormField::create();
+		FormField::ref field = boost::make_shared<FormField>(FormField::ListSingleType);
 		field->setName("stream-method");
 		foreach(const std::string& method, streamInitiation->getProvidedMethods()) {
 			field->addOption(FormField::Option("", method));
@@ -62,7 +62,8 @@ std::string StreamInitiationSerializer::serializePayload(boost::shared_ptr<Strea
 	}
 	else if (!streamInitiation->getRequestedMethod().empty()) {
 		Form::ref form(new Form(Form::SubmitType));
-		ListSingleFormField::ref field = ListSingleFormField::create(streamInitiation->getRequestedMethod());
+		FormField::ref field = boost::make_shared<FormField>(FormField::ListSingleType);
+		field->addValue(streamInitiation->getRequestedMethod());
 		field->setName("stream-method");
 		form->addField(field);
 		featureElement->addNode(boost::make_shared<XMLRawTextNode>(FormSerializer().serialize(form)));
diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/FormSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/FormSerializerTest.cpp
index 4608522..e4ce2c8 100644
--- a/Swiften/Serializer/PayloadSerializers/UnitTest/FormSerializerTest.cpp
+++ b/Swiften/Serializer/PayloadSerializers/UnitTest/FormSerializerTest.cpp
@@ -1,11 +1,12 @@
 /*
- * Copyright (c) 2010 Remko Tronçon
+ * Copyright (c) 2010-2013 Remko Tronçon
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
 
 #include <cppunit/extensions/HelperMacros.h>
 #include <cppunit/extensions/TestFactoryRegistry.h>
+#include <boost/smart_ptr/make_shared.hpp>
 
 #include <Swiften/Serializer/PayloadSerializers/FormSerializer.h>
 using namespace Swift;
@@ -36,37 +37,37 @@ class FormSerializerTest : public CppUnit::TestFixture {
 			FormSerializer testling;
 			boost::shared_ptr<Form> form(new Form(Form::FormType));
 
-			FormField::ref field = HiddenFormField::create("jabber:bot");
+			FormField::ref field = boost::make_shared<FormField>(FormField::HiddenType, "jabber:bot");
 			field->setName("FORM_TYPE");
 			form->addField(field);
 
-			form->addField(FixedFormField::create("Section 1: Bot Info"));
+			form->addField(boost::make_shared<FormField>(FormField::FixedType, "Section 1: Bot Info"));
 
-			field = TextSingleFormField::create();
+			field = boost::make_shared<FormField>(FormField::TextSingleType);
 			field->setName("botname");
 			field->setLabel("The name of your bot");
 			form->addField(field);
 
-			field = TextMultiFormField::create("This is a bot.\nA quite good one actually");
+			field = boost::make_shared<FormField>(FormField::TextMultiType);
+			field->setTextMultiValue("This is a bot.\nA quite good one actually");
 			field->setName("description");
 			field->setLabel("Helpful description of your bot");
 			form->addField(field);
 
-			field = BooleanFormField::create(true);
+			field = boost::make_shared<FormField>(FormField::BooleanType, "1");
 			field->setName("public");
 			field->setLabel("Public bot?");
 			field->setRequired(true);
 			form->addField(field);
 
-			field = TextPrivateFormField::create();
+			field = boost::make_shared<FormField>(FormField::TextPrivateType);
 			field->setName("password");
 			field->setLabel("Password for special access");
 			form->addField(field);
 
-			std::vector<std::string> values;
-			values.push_back("news");
-			values.push_back("search");
-			field = ListMultiFormField::create(values);
+			field = boost::make_shared<FormField>(FormField::ListMultiType);
+			field->addValue("news");
+			field->addValue("search");
 			field->setName("features");
 			field->setLabel("What features will the bot support?");
 			field->addOption(FormField::Option("Contests", "contests"));
@@ -76,7 +77,7 @@ class FormSerializerTest : public CppUnit::TestFixture {
 			field->addOption(FormField::Option("Search", "search"));
 			form->addField(field);
 
-			field = ListSingleFormField::create("20");
+			field = boost::make_shared<FormField>(FormField::ListSingleType, "20");
 			field->setName("maxsubs");
 			field->setLabel("Maximum number of subscribers");
 			field->addOption(FormField::Option("10", "10"));
@@ -88,9 +89,9 @@ class FormSerializerTest : public CppUnit::TestFixture {
 			form->addField(field);
 
 			std::vector<JID> jids;
-			jids.push_back(JID("foo@bar.com"));
-			jids.push_back(JID("baz@fum.org"));
-			field = JIDMultiFormField::create(jids);
+			field = boost::make_shared<FormField>(FormField::JIDMultiType);
+			field->addValue("foo@bar.com");
+			field->addValue("baz@fum.org");
 			field->setName("invitelist");
 			field->setLabel("People to invite");
 			field->setDescription("Tell all your friends about your new bot!");
@@ -140,62 +141,62 @@ class FormSerializerTest : public CppUnit::TestFixture {
 			boost::shared_ptr<Form> form(new Form(Form::ResultType));
 
 
-			FormField::ref field = HiddenFormField::create("jabber:iq:search");
+			FormField::ref field = boost::make_shared<FormField>(FormField::HiddenType, "jabber:iq:search");
 			field->setName("FORM_TYPE");
 			form->addField(field);
 
 			// reported fields
-			field = TextSingleFormField::create();
+			field = boost::make_shared<FormField>(FormField::TextSingleType);
 			field->setName("first");
 			field->setLabel("Given Name");
 			form->addReportedField(field);
 
-			field = TextSingleFormField::create();
+			field = boost::make_shared<FormField>(FormField::TextSingleType);
 			field->setName("last");
 			field->setLabel("Family Name");
 			form->addReportedField(field);
 
-			field = JIDSingleFormField::create();
+			field = boost::make_shared<FormField>(FormField::JIDSingleType);
 			field->setName("jid");
 			field->setLabel("Jabber ID");
 			form->addReportedField(field);
 
-			field = ListSingleFormField::create();
+			field = boost::make_shared<FormField>(FormField::ListSingleType);
 			field->setName("x-gender");
 			field->setLabel("Gender");
 			form->addReportedField(field);
 
 			Form::FormItem firstItem;
-			field = TextSingleFormField::create("Benvolio");
+			field = boost::make_shared<FormField>(FormField::TextSingleType, "Benvolio");
 			field->setName("first");
 			firstItem.push_back(field);
 
-			field = TextSingleFormField::create("Montague");
+			field = boost::make_shared<FormField>(FormField::TextSingleType, "Montague");
 			field->setName("last");
 			firstItem.push_back(field);
 
-			field = JIDSingleFormField::create(JID("benvolio@montague.net"));
+			field = boost::make_shared<FormField>(FormField::JIDSingleType, JID("benvolio@montague.net"));
 			field->setName("jid");
 			firstItem.push_back(field);
 
-			field = ListSingleFormField::create("male");
+			field = boost::make_shared<FormField>(FormField::ListSingleType, "male");
 			field->setName("x-gender");
 			firstItem.push_back(field);
 
 			Form::FormItem secondItem;
-			field = TextSingleFormField::create("Romeo");
+			field = boost::make_shared<FormField>(FormField::TextSingleType, "Romeo");
 			field->setName("first");
 			secondItem.push_back(field);
 
-			field = TextSingleFormField::create("Montague");
+			field = boost::make_shared<FormField>(FormField::TextSingleType, "Montague");
 			field->setName("last");
 			secondItem.push_back(field);
 
-			field = JIDSingleFormField::create(JID("romeo@montague.net"));
+			field = boost::make_shared<FormField>(FormField::JIDSingleType, JID("romeo@montague.net"));
 			field->setName("jid");
 			secondItem.push_back(field);
 
-			field = ListSingleFormField::create("male");
+			field = boost::make_shared<FormField>(FormField::ListSingleType, "male");
 			field->setName("x-gender");
 			secondItem.push_back(field);
 
diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/InBandRegistrationPayloadSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/InBandRegistrationPayloadSerializerTest.cpp
index df43e69..7cbce35 100644
--- a/Swiften/Serializer/PayloadSerializers/UnitTest/InBandRegistrationPayloadSerializerTest.cpp
+++ b/Swiften/Serializer/PayloadSerializers/UnitTest/InBandRegistrationPayloadSerializerTest.cpp
@@ -1,11 +1,12 @@
 /*
- * Copyright (c) 2010 Remko Tronçon
+ * Copyright (c) 2010-2013 Remko Tronçon
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
 
 #include <cppunit/extensions/HelperMacros.h>
 #include <cppunit/extensions/TestFactoryRegistry.h>
+#include <boost/smart_ptr/make_shared.hpp>
 
 #include <Swiften/Serializer/PayloadSerializers/InBandRegistrationPayloadSerializer.h>
 
@@ -38,7 +39,7 @@ class InBandRegistrationPayloadSerializerTest : public CppUnit::TestFixture {
 			boost::shared_ptr<Form> form(new Form(Form::FormType));
 			form->setTitle("Contest Registration");
 
-			FormField::ref field = HiddenFormField::create("jabber:iq:register");
+			FormField::ref field = boost::make_shared<FormField>(FormField::HiddenType, "jabber:iq:register");
 			field->setName("FORM_TYPE");
 			form->addField(field);
 			registration->setForm(form);
diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/SearchPayloadSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/SearchPayloadSerializerTest.cpp
index 42bff72..29e20c9 100644
--- a/Swiften/Serializer/PayloadSerializers/UnitTest/SearchPayloadSerializerTest.cpp
+++ b/Swiften/Serializer/PayloadSerializers/UnitTest/SearchPayloadSerializerTest.cpp
@@ -1,11 +1,12 @@
 /*
- * Copyright (c) 2010 Remko Tronçon
+ * Copyright (c) 2010-2013 Remko Tronçon
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
 
 #include <cppunit/extensions/HelperMacros.h>
 #include <cppunit/extensions/TestFactoryRegistry.h>
+#include <boost/smart_ptr/make_shared.hpp>
 
 #include <Swiften/Serializer/PayloadSerializers/SearchPayloadSerializer.h>
 
@@ -78,62 +79,62 @@ class SearchPayloadSerializerTest : public CppUnit::TestFixture {
 			SearchPayload::ref payload(new SearchPayload());
 			boost::shared_ptr<Form> form(new Form(Form::ResultType));
 
-			FormField::ref field = HiddenFormField::create("jabber:iq:search");
+			FormField::ref field = boost::make_shared<FormField>(FormField::HiddenType, "jabber:iq:search");
 			field->setName("FORM_TYPE");
 			form->addField(field);
 
 			// reported fields
-			field = TextSingleFormField::create();
+			field = boost::make_shared<FormField>(FormField::TextSingleType);
 			field->setName("first");
 			field->setLabel("Given Name");
 			form->addReportedField(field);
 
-			field = TextSingleFormField::create();
+			field = boost::make_shared<FormField>(FormField::TextSingleType);
 			field->setName("last");
 			field->setLabel("Family Name");
 			form->addReportedField(field);
 
-			field = JIDSingleFormField::create();
+			field = boost::make_shared<FormField>(FormField::JIDSingleType);
 			field->setName("jid");
 			field->setLabel("Jabber ID");
 			form->addReportedField(field);
 
-			field = ListSingleFormField::create();
+			field = boost::make_shared<FormField>(FormField::ListSingleType);
 			field->setName("x-gender");
 			field->setLabel("Gender");
 			form->addReportedField(field);
 
 			Form::FormItem firstItem;
-			field = TextSingleFormField::create("Benvolio");
+			field = boost::make_shared<FormField>(FormField::TextSingleType, "Benvolio");
 			field->setName("first");
 			firstItem.push_back(field);
 
-			field = TextSingleFormField::create("Montague");
+			field = boost::make_shared<FormField>(FormField::TextSingleType, "Montague");
 			field->setName("last");
 			firstItem.push_back(field);
 
-			field = TextSingleFormField::create("benvolio@montague.net");
+			field = boost::make_shared<FormField>(FormField::TextSingleType, "benvolio@montague.net");
 			field->setName("jid");
 			firstItem.push_back(field);
 
-			field = ListSingleFormField::create("male");
+			field = boost::make_shared<FormField>(FormField::ListSingleType, "male");
 			field->setName("x-gender");
 			firstItem.push_back(field);
 
 			Form::FormItem secondItem;
-			field = TextSingleFormField::create("Romeo");
+			field = boost::make_shared<FormField>(FormField::TextSingleType, "Romeo");
 			field->setName("first");
 			secondItem.push_back(field);
 
-			field = TextSingleFormField::create("Montague");
+			field = boost::make_shared<FormField>(FormField::TextSingleType, "Montague");
 			field->setName("last");
 			secondItem.push_back(field);
 
-			field = TextSingleFormField::create("romeo@montague.net");
+			field = boost::make_shared<FormField>(FormField::TextSingleType, "romeo@montague.net");
 			field->setName("jid");
 			secondItem.push_back(field);
 
-			field = ListSingleFormField::create("male");
+			field = boost::make_shared<FormField>(FormField::ListSingleType, "male");
 			field->setName("x-gender");
 			secondItem.push_back(field);
 
-- 
cgit v0.10.2-6-g49f6