--- /dev/null
+# ifndef FORMS_H
+# define FORMS_H
+
+#include <QPair>
+#include <QString>
+#include <QVariant>
+#include <QVariantMap>
+
+#include "http.h"
+#include "utils.h"
+
+/* Form Errors */
+typedef QMap<QString, QString> ErrorDict;
+class ValidationError {
+ private:
+ QString msg;
+
+ public:
+ ValidationError(QString _msg): msg(_msg) {}
+
+ QString getMsg() { return msg; }
+};
+
+
+/* Widgets */
+class Widget : public QObject {
+ Q_OBJECT;
+ public:
+ Widget(QObject *parent=0): QObject(parent) {}
+
+ virtual ~Widget() {};
+
+ virtual QString render(QString name, QVariant value) const = 0;
+
+ virtual QVariant valueFromDatadict(const QueryDict &data, const FilesDict &, QString name) const {
+ return QVariant(data.value(name, ""));
+ }
+};
+
+class TextInput : public Widget {
+ public:
+ TextInput(QObject *parent=0): Widget(parent) {}
+
+ virtual QString render(QString name, QVariant value) const;
+
+};
+
+typedef QPair<QString, QString> SelectOption;
+class Select : public Widget {
+ private:
+ QList<SelectOption> choices;
+ bool show_empty_row;
+
+ public:
+ Select(bool _show_empty_row=true, QObject *parent=0): Widget(parent), show_empty_row(_show_empty_row) {}
+
+ Select(const QList<SelectOption> &_choices, bool _show_empty_row=true, QObject *parent=0): Widget(parent), choices(_choices), show_empty_row(_show_empty_row) {}
+
+ void addOption(const SelectOption &option) {
+ choices.append(option);
+ }
+
+ virtual QString render(QString name, QVariant value) const;
+
+ virtual const QList<SelectOption> &getChoicesRef() const { return choices; }
+};
+
+class CheckboxInput : public Widget {
+ public:
+ CheckboxInput(QObject *parent=0): Widget(parent) {}
+
+ virtual QString render(QString name, QVariant value) const;
+
+ virtual QVariant valueFromDatadict(const QueryDict &data, const FilesDict &files, QString name) const;
+};
+
+class FileInput : public Widget {
+ public:
+ FileInput(QObject *parent=0): Widget(parent) {}
+
+ virtual QString render(QString name, QVariant value) const;
+
+ virtual QVariant valueFromDatadict(const QueryDict &data, const FilesDict &files, QString name) const;
+};
+
+
+/* Fields */
+class Field : public QObject {
+ Q_OBJECT;
+ protected:
+ QString label;
+ bool required;
+ QVariant initial;
+ Widget *widget;
+
+ public:
+ Field(QString _label, bool _required, QVariant _initial, QObject *parent=0)
+ : QObject(parent), label(_label), required(_required), initial(_initial) {}
+
+ virtual ~Field() {};
+
+ virtual QString render(const QueryDict &data, QString field_template="%1") const;
+
+ virtual QVariant clean(QVariant value) const;
+
+ virtual QString getLabel() const { return label; }
+
+ virtual bool isRequired() const { return required; }
+
+ virtual QVariant getInitial() const { return initial; }
+
+ virtual Widget *getWidgetPtr() { return widget; }
+};
+
+class CharField : public Field {
+ public:
+ CharField(QString _label, bool _required, QVariant _initial="", QObject *parent=0);
+
+};
+
+class IntegerField : public Field {
+ public:
+ IntegerField(QString _label, bool _required, QVariant _initial="", QObject *parent=0);
+
+ virtual QVariant clean(QVariant value) const;
+};
+
+class FloatField : public Field {
+ public:
+ FloatField(QString _label, bool _required, QVariant _initial="", QObject *parent=0);
+
+ virtual QVariant clean(QVariant value) const;
+};
+
+class ChoiceField : public Field {
+ private:
+ const QList<SelectOption> &choices;
+
+ public:
+ ChoiceField(QString _label, const QList<SelectOption> &_choices, bool _required, QVariant _initial="", QObject *parent=0);
+
+ virtual QVariant clean(QVariant value) const;
+};
+
+class BooleanField : public Field {
+ public:
+ BooleanField(QString _label, bool _required, QVariant _initial=false, QObject *parent=0);
+
+ virtual QVariant clean(QVariant value) const;
+};
+
+class FileField : public Field {
+ public:
+ FileField(QString _label, bool _required, QObject *parent=0);
+
+ virtual QVariant clean(QVariant value) const;
+};
+
+
+/* Form */
+class Form : public QObject {
+ Q_OBJECT;
+ private:
+ bool is_bound;
+ QueryDict data;
+ FilesDict files;
+ ErrorDict errors;
+ QVariantMap cleaned_data;
+
+ public:
+ Form(QObject *parent=0): QObject(parent), is_bound(false) {}
+
+ virtual ~Form() {}
+
+ void bindData(const QueryDict &_data) {
+ is_bound = true;
+ data = _data;
+ }
+
+ void bindFiles(const FilesDict &_files) {
+ is_bound = true;
+ files = _files;
+ }
+
+ bool isBound() const { return is_bound; }
+
+ void addField(QString name, Field *field);
+
+ void setError(QString field_name, QString msg);
+
+ void fullClean();
+
+ bool isValid();
+
+ QString renderField(QString field_name, QString field_template="<p>\n\t%1\n\t%2\n\t%3\n</p>\n", QString label_template="<label for=\"%1\">%2</label>\n", QString error_template="<span class=\"errors\">%1</span>\n") const;
+
+ QList<QString> fieldNames() const;
+
+ const QVariantMap &getCleanedDataRef() const { return cleaned_data; }
+
+ Field *operator[](QString field_name) const;
+};
+
+
+# endif