CppCMS
|
00001 00002 // 00003 // Copyright (C) 2008-2012 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com> 00004 // 00005 // See accompanying file COPYING.TXT file for licensing details. 00006 // 00008 #ifndef CPPCMS_FORM_H 00009 #define CPPCMS_FORM_H 00010 00011 #include <cppcms/defs.h> 00012 #include <booster/noncopyable.h> 00013 00014 #include <string> 00015 #include <set> 00016 #include <map> 00017 #include <list> 00018 #include <vector> 00019 #include <stack> 00020 #include <ostream> 00021 #include <sstream> 00022 #include <cppcms/http_context.h> 00023 #include <cppcms/http_request.h> 00024 #include <cppcms/http_response.h> 00025 #include <booster/copy_ptr.h> 00026 #include <booster/perl_regex.h> 00027 #include <booster/shared_ptr.h> 00028 #include <cppcms/cppcms_error.h> 00029 #include <cppcms/util.h> 00030 #include <cppcms/localization.h> 00031 00032 namespace cppcms { 00033 00034 namespace http { 00035 class file; 00036 } 00037 00038 namespace widgets { 00039 class base_widget; 00040 } 00041 00045 struct form_flags { 00049 typedef enum { 00050 as_html = 0, 00051 as_xhtml= 1, 00052 } html_type; 00053 00057 typedef enum { 00058 as_p = 0 , 00059 as_table= 1 , 00060 as_ul = 2 , 00061 as_dl = 3 , 00062 as_space= 4 00063 } html_list_type; 00064 00068 typedef enum { 00069 first_part = 0, 00070 second_part = 1 00071 } widget_part_type; 00072 }; 00073 00077 class CPPCMS_API form_context : public form_flags 00078 { 00079 public: 00083 form_context(); 00084 00088 form_context(form_context const &other); 00089 00093 form_context const &operator = (form_context const &other); 00094 00102 form_context( std::ostream &output, 00103 html_type ht = form_flags::as_html, 00104 html_list_type hlt=form_flags::as_p); 00105 00109 ~form_context(); 00110 00114 void html(html_type t); 00115 00119 void html_list(html_list_type t); 00120 00124 void widget_part(widget_part_type t); 00125 00129 void out(std::ostream &out); 00130 00134 html_type html() const; 00135 00139 html_list_type html_list() const; 00140 00144 widget_part_type widget_part() const; 00145 00149 std::ostream &out() const; 00150 00151 private: 00152 uint32_t html_type_; 00153 uint32_t html_list_type_; 00154 uint32_t widget_part_type_; 00155 std::ostream *output_; 00156 uint32_t reserved_1; 00157 uint32_t reserved_2; 00158 struct _data; 00159 booster::hold_ptr<_data> d; 00160 00161 }; 00162 00163 00169 class CPPCMS_API base_form : public form_flags { 00170 public: 00176 virtual void render(form_context &context) = 0; 00177 00183 virtual void load(http::context &context) = 0; 00184 00189 virtual bool validate() = 0; 00190 00194 virtual void clear() = 0; 00195 00199 virtual void parent(base_form *subform) = 0; 00200 00204 virtual base_form *parent() = 0; 00205 00206 base_form(); 00207 virtual ~base_form(); 00208 }; 00209 00216 class CPPCMS_API form : public booster::noncopyable, 00217 public base_form 00218 { 00219 public: 00220 form(); 00221 virtual ~form(); 00222 00227 virtual void render(form_context &context); 00228 00232 virtual void load(http::context &cont); 00233 00238 virtual bool validate(); 00239 00243 virtual void clear(); 00244 00249 void add(form &subform); 00250 00256 void attach(form *subform); 00257 00262 void add(widgets::base_widget &widget); 00263 00269 void attach(widgets::base_widget *widget); 00270 00276 CPPCMS_DEPRECATED inline form &operator + (form &f) 00277 { 00278 add(f); 00279 return *this; 00280 } 00281 00287 CPPCMS_DEPRECATED inline form &operator + (widgets::base_widget &f) 00288 { 00289 add(f); 00290 return *this; 00291 } 00292 00297 virtual void parent(base_form *subform); 00298 00303 virtual form *parent(); 00304 00320 class CPPCMS_API iterator : public std::iterator<std::input_iterator_tag,widgets::base_widget> 00321 { 00322 public: 00326 iterator(); 00327 00331 iterator(form &); 00332 00336 ~iterator(); 00337 00341 iterator(iterator const &other); 00342 00346 iterator const &operator = (iterator const &other); 00347 00351 widgets::base_widget *operator->() const 00352 { 00353 return get(); 00354 } 00355 00359 widgets::base_widget &operator*() const 00360 { 00361 return *get(); 00362 } 00363 00367 bool operator==(iterator const &other) const 00368 { 00369 return equal(other); 00370 } 00371 00375 bool operator!=(iterator const &other) const 00376 { 00377 return !equal(other); 00378 } 00379 00386 iterator operator++(int /*unused*/) 00387 { 00388 iterator tmp(*this); 00389 next(); 00390 return tmp; 00391 } 00392 00397 iterator &operator++() 00398 { 00399 next(); 00400 return *this; 00401 } 00402 00403 private: 00404 00405 friend class form; 00406 00407 bool equal(iterator const &other) const; 00408 void zero(); 00409 void next(); 00410 widgets::base_widget *get() const; 00411 00412 std::stack<unsigned> return_positions_; 00413 form *current_; 00414 unsigned offset_; 00415 struct _data; 00416 booster::copy_ptr<_data> d; 00417 00418 }; 00419 00423 iterator begin(); 00424 00428 iterator end(); 00429 00430 00431 private: 00432 friend class iterator; 00433 00434 struct _data; 00435 // Widget and ownership - true means I own it. 00436 typedef std::pair<base_form *,bool> widget_type; 00437 std::vector<widget_type> elements_; 00438 form *parent_; 00439 booster::hold_ptr<_data> d; 00440 }; 00441 00442 00443 00447 namespace widgets { 00448 00456 00457 class CPPCMS_API base_widget : 00458 public base_form, 00459 public booster::noncopyable 00460 { 00461 public: 00465 base_widget(); 00466 00467 virtual ~base_widget(); 00468 00478 bool set(); 00479 00483 bool valid(); 00484 00488 std::string id(); 00489 00493 std::string name(); 00494 00498 locale::message message(); 00499 00503 bool has_message(); 00504 00509 locale::message error_message(); 00510 00514 bool has_error_message(); 00515 00519 locale::message help(); 00520 00524 bool has_help(); 00525 00529 bool disabled(); 00530 00534 void disabled(bool); 00535 00539 std::string attributes_string(); 00540 00546 void set(bool); 00547 00554 void valid(bool); 00555 00559 void id(std::string); 00560 00566 void name(std::string); 00567 00574 void message(std::string); 00575 00582 void message(locale::message const &); 00583 00589 void error_message(std::string); 00590 00596 void error_message(locale::message const &); 00597 00601 void help(std::string); 00602 00606 void help(locale::message const &msg); 00607 00618 void attributes_string(std::string v); 00619 00620 00625 virtual void render(form_context &context); 00626 00631 virtual void render_input(form_context &context) = 0; 00632 00636 virtual void clear(); 00637 00641 virtual bool validate(); 00642 00646 virtual void render_attributes(form_context &context); 00647 00652 virtual void parent(base_form *subform); 00653 00658 virtual form *parent(); 00659 00665 void pre_load(http::context &); 00666 00667 protected: 00672 void auto_generate(form_context *context = 0); 00673 00674 private: 00675 void generate(int position,form_context *context = 0); 00676 00677 std::string id_; 00678 std::string name_; 00679 locale::message message_; 00680 locale::message error_message_; 00681 locale::message help_; 00682 std::string attr_; 00683 form *parent_; 00684 00685 uint32_t is_valid_ : 1; 00686 uint32_t is_set_ : 1; 00687 uint32_t is_disabled_ : 1; 00688 uint32_t is_generation_done_ : 1; 00689 uint32_t has_message_ : 1; 00690 uint32_t has_error_ : 1; 00691 uint32_t has_help_ : 1; 00692 uint32_t reserverd_ : 25; 00693 00694 struct _data; 00695 booster::hold_ptr<_data> d; 00696 }; 00697 00707 class CPPCMS_API base_text : virtual public base_widget { 00708 public: 00709 00710 base_text(); 00711 virtual ~base_text(); 00712 00716 std::string value(); 00717 00721 void value(std::string v); 00722 00727 void non_empty(); 00728 00737 void limits(int min,int max); 00738 00742 std::pair<int,int> limits(); 00743 00752 void validate_charset(bool ); 00753 00757 bool validate_charset(); 00758 00770 virtual bool validate(); 00771 00776 virtual void load(http::context &); 00777 00778 private: 00779 std::string value_; 00780 int low_; 00781 int high_; 00782 bool validate_charset_; 00783 size_t code_points_; 00784 struct _data; 00785 booster::hold_ptr<_data> d; 00786 }; 00787 00796 00797 class CPPCMS_API base_html_input : virtual public base_widget { 00798 public: 00803 base_html_input(std::string const &type); 00804 00808 virtual ~base_html_input(); 00809 00813 virtual void render_input(form_context &context); 00814 00815 protected: 00819 virtual void render_value(form_context &context) = 0; 00820 00821 private: 00822 struct _data; 00823 booster::hold_ptr<_data> d; 00824 std::string type_; 00825 }; 00826 00830 class CPPCMS_API text : public base_html_input, public base_text 00831 { 00832 public: 00836 text(); 00837 00842 text(std::string const &type); 00843 00844 ~text(); 00845 00849 void size(int n); 00850 00854 int size(); 00855 00856 00857 virtual void render_attributes(form_context &context); 00858 virtual void render_value(form_context &context); 00859 00860 private: 00861 int size_; 00862 struct _data; 00863 booster::hold_ptr<_data> d; 00864 }; 00865 00876 class CPPCMS_API hidden : public text 00877 { 00878 public: 00879 hidden(); 00880 ~hidden(); 00886 virtual void render(form_context &context); 00887 private: 00888 struct _data; 00889 booster::hold_ptr<_data> d; 00890 }; 00891 00892 00897 class CPPCMS_API textarea : public base_text 00898 { 00899 public: 00900 textarea(); 00901 ~textarea(); 00902 00906 int rows(); 00907 00911 int cols(); 00912 00916 void rows(int n); 00917 00921 void cols(int n); 00922 00923 virtual void render_input(form_context &context); 00924 00925 private: 00926 int rows_,cols_; 00927 00928 struct _data; 00929 booster::hold_ptr<_data> d; 00930 }; 00931 00941 template<typename T> 00942 class numeric: public base_html_input { 00943 public: 00944 numeric() : 00945 base_html_input("text"), 00946 check_low_(false), 00947 check_high_(false), 00948 non_empty_(false) 00949 { 00950 } 00951 00955 void non_empty() 00956 { 00957 non_empty_=true; 00958 } 00959 00960 00970 T value() 00971 { 00972 if(!set()) 00973 throw cppcms_error("Value not loaded"); 00974 return value_; 00975 } 00976 00980 void value(T v) 00981 { 00982 set(true); 00983 value_=v; 00984 } 00985 00989 void low(T a) 00990 { 00991 min_=a; 00992 check_low_=true; 00993 non_empty(); 00994 } 00995 00999 void high(T b) 01000 { 01001 max_=b; 01002 check_high_=true; 01003 non_empty(); 01004 } 01005 01009 void range(T a,T b) 01010 { 01011 low(a); 01012 high(b); 01013 } 01014 01018 virtual void render_value(form_context &context) 01019 { 01020 if(set()) 01021 context.out()<<"value=\""<<value_<<"\" "; 01022 else 01023 context.out()<<"value=\""<<util::escape(loaded_string_)<<"\" "; 01024 } 01025 01026 virtual void clear() 01027 { 01028 base_html_input::clear(); 01029 loaded_string_.clear(); 01030 } 01031 01035 virtual void load(http::context &context) 01036 { 01037 pre_load(context); 01038 01039 loaded_string_.clear(); 01040 01041 set(false); 01042 valid(true); 01043 01044 http::request::form_type::const_iterator p; 01045 http::request::form_type const &request=context.request().post_or_get(); 01046 p=request.find(name()); 01047 if(p==request.end()) { 01048 return; 01049 } 01050 else { 01051 loaded_string_=p->second; 01052 if(loaded_string_.empty()) 01053 return; 01054 01055 std::istringstream ss(loaded_string_); 01056 ss.imbue(context.locale()); 01057 ss>>value_; 01058 if(ss.fail() || !ss.eof()) 01059 valid(false); 01060 else 01061 set(true); 01062 } 01063 } 01064 01068 virtual bool validate() 01069 { 01070 if(!valid()) 01071 return false; 01072 if(!set()) { 01073 if(non_empty_) { 01074 valid(false); 01075 return false; 01076 } 01077 return true; 01078 } 01079 if(check_low_ && value_ <min_) { 01080 valid(false); 01081 return false; 01082 } 01083 if(check_high_ && value_ > max_) { 01084 valid(false); 01085 return false; 01086 } 01087 return true; 01088 } 01089 01090 private: 01091 01092 T min_,max_,value_; 01093 01094 bool check_low_; 01095 bool check_high_; 01096 bool non_empty_; 01097 std::string loaded_string_; 01098 }; 01099 01102 // 01103 class CPPCMS_API password: public text { 01104 public: 01105 password(); 01106 01107 ~password(); 01108 01114 void check_equal(password &p2); 01115 virtual bool validate(); 01116 01117 private: 01118 struct _data; 01119 booster::hold_ptr<_data> d; 01120 password *password_to_check_; 01121 }; 01122 01123 01127 class CPPCMS_API regex_field : public text { 01128 public: 01129 regex_field(); 01133 regex_field(booster::regex const &e); 01134 01138 regex_field(std::string const &e); 01139 01140 01144 void regex(booster::regex const &e); 01145 01146 ~regex_field(); 01147 01148 virtual bool validate(); 01149 01150 private: 01151 booster::regex expression_; 01152 struct _data; 01153 booster::hold_ptr<_data> d; 01154 }; 01155 01159 class CPPCMS_API email : public regex_field { 01160 public: 01161 01162 email(); 01163 ~email(); 01164 01165 private: 01166 struct _data; 01167 booster::hold_ptr<_data> d; 01168 }; 01169 01173 class CPPCMS_API checkbox: public base_html_input { 01174 public: 01180 checkbox(std::string const &type); 01181 01185 checkbox(); 01186 virtual ~checkbox(); 01187 01191 bool value(); 01192 01196 void value(bool is_set); 01197 01201 std::string identification(); 01202 01207 void identification(std::string const &); 01208 01209 virtual void render_value(form_context &context); 01210 virtual void load(http::context &context); 01211 01212 private: 01213 struct _data; 01214 booster::hold_ptr<_data> d; 01215 std::string identification_; 01216 bool value_; 01217 }; 01218 01222 class CPPCMS_API select_multiple : public base_widget { 01223 public: 01224 select_multiple(); 01225 ~select_multiple(); 01226 01231 void add(std::string const &msg,bool selected=false); 01232 01237 void add(std::string const &msg,std::string const &id,bool selected=false); 01238 01243 void add(locale::message const &msg,bool selected=false); 01244 01249 void add(locale::message const &msg,std::string const &id,bool selected=false); 01250 01254 std::vector<bool> selected_map(); 01255 01260 std::set<std::string> selected_ids(); 01261 01265 unsigned at_least(); 01266 01270 void at_least(unsigned v); 01271 01275 unsigned at_most(); 01276 01280 void at_most(unsigned v); 01281 01285 void non_empty(); 01286 01290 unsigned rows(); 01291 01295 void rows(unsigned n); 01296 01297 virtual void render_input(form_context &context); 01298 virtual bool validate(); 01299 virtual void load(http::context &context); 01300 virtual void clear(); 01301 01302 private: 01303 struct _data; 01304 booster::hold_ptr<_data> d; 01305 01306 struct element { 01307 element(); 01308 element(std::string const &v,locale::message const &msg,bool sel); 01309 element(std::string const &v,std::string const &msg,bool sel); 01310 uint32_t selected : 1; 01311 uint32_t need_translation : 1; 01312 uint32_t original_select : 1; 01313 uint32_t reserved : 29; 01314 std::string id; 01315 std::string str_option; 01316 locale::message tr_option; 01317 friend std::ostream &operator<<(std::ostream &out,element const &el); 01318 }; 01319 01320 std::vector<element> elements_; 01321 01322 unsigned low_; 01323 unsigned high_; 01324 unsigned rows_; 01325 01326 }; 01327 01332 class CPPCMS_API select_base : public base_widget { 01333 public: 01334 select_base(); 01335 virtual ~select_base(); 01336 01340 void add(std::string const &string); 01341 01345 void add(std::string const &string,std::string const &id); 01346 01350 void add(locale::message const &msg); 01351 01355 void add(locale::message const &msg,std::string const &id); 01356 01361 int selected(); 01362 01367 std::string selected_id(); 01368 01372 void selected(int no); 01373 01377 void selected_id(std::string id); 01378 01382 void non_empty(); 01383 01384 virtual void render_input(form_context &context) = 0; 01385 virtual bool validate(); 01386 virtual void load(http::context &context); 01387 virtual void clear(); 01388 01389 protected: 01390 struct CPPCMS_API element { 01391 01392 element(); 01393 element(std::string const &v,locale::message const &msg); 01394 element(std::string const &v,std::string const &msg); 01395 element(element const &); 01396 element const &operator=(element const &); 01397 ~element(); 01398 01399 uint32_t need_translation : 1; 01400 uint32_t reserved : 31; 01401 std::string id; 01402 std::string str_option; 01403 locale::message tr_option; 01404 01405 private: 01406 struct _data; 01407 booster::copy_ptr<_data> d; 01408 01409 }; 01410 01411 std::vector<element> elements_; 01412 01413 private: 01414 struct _data; 01415 booster::hold_ptr<_data> d; 01416 01417 int selected_; 01418 int default_selected_; 01419 01420 uint32_t non_empty_ : 1; 01421 uint32_t reserverd : 32; 01422 }; 01423 01427 class CPPCMS_API select : public select_base { 01428 public: 01429 select(); 01430 virtual ~select(); 01431 virtual void render_input(form_context &context); 01432 01433 private: 01434 struct _data; 01435 booster::hold_ptr<_data> d; 01436 }; 01437 01441 class CPPCMS_API radio : public select_base { 01442 public: 01443 radio(); 01444 virtual ~radio(); 01445 virtual void render_input(form_context &context); 01446 01450 bool vertical(); 01451 01459 void vertical(bool); 01460 01461 private: 01462 uint32_t vertical_ : 1; 01463 uint32_t reserved_ : 31; 01464 01465 struct _data; 01466 booster::hold_ptr<_data> d; 01467 }; 01468 01475 class CPPCMS_API file : public base_html_input { 01476 public: 01480 void non_empty(); 01481 01487 void limits(int min,int max); 01488 01492 std::pair<int,int> limits(); 01493 01502 void filename(booster::regex const &fn); 01503 01507 booster::regex filename(); 01508 01512 void validate_filename_charset(bool); 01513 01517 bool validate_filename_charset(); 01518 01523 booster::shared_ptr<http::file> value(); 01524 01528 void mime(std::string const &); 01529 01533 void mime(booster::regex const &expr); 01534 01540 void add_valid_magic(std::string const &); 01541 01542 virtual void load(http::context &context); 01543 virtual void render_value(form_context &context); 01544 virtual bool validate(); 01545 01546 file(); 01547 ~file(); 01548 01549 private: 01550 01551 int size_min_; 01552 int size_max_; 01553 01554 std::vector<std::string> magics_; 01555 01556 std::string mime_string_; 01557 booster::regex mime_regex_; 01558 booster::regex filename_regex_; 01559 01560 uint32_t check_charset_ : 1; 01561 uint32_t check_non_empty_ : 1; 01562 uint32_t reserved_ : 30; 01563 01564 booster::shared_ptr<http::file> file_; 01565 01566 struct _data; 01567 booster::hold_ptr<_data> d; 01568 }; 01569 01570 01574 class CPPCMS_API submit : public base_html_input { 01575 public: 01576 submit(); 01577 ~submit(); 01578 01582 bool value(); 01583 01587 void value(std::string val); 01588 01592 void value(locale::message const &msg); 01593 01594 virtual void render_value(form_context &context); 01595 virtual void load(http::context &context); 01596 01597 private: 01598 struct _data; 01599 booster::hold_ptr<_data> d; 01600 bool pressed_; 01601 locale::message value_; 01602 }; 01603 01604 01605 01606 01607 } // widgets 01608 01609 01610 } //cppcms 01611 01612 #endif // CPPCMS_FORM_H