00001 #include "GUI.h"
00002
00003 #include "WidgetCreator.h"
00004
00005 #include "utils.h"
00006
00007 #include <fstream>
00008 #include <stack>
00009 #include <sstream>
00010
00011 namespace xfltk {
00012
00013 struct ParserInfo {
00014
00015 GUI& gui;
00016
00017 XML_Parser& parser;
00018
00019 std::stack<WidgetCreator*> creators_stack;
00020
00024 unsigned errors_len;
00025
00026 unsigned skip_tag;
00027
00028 ParserInfo(GUI& gui, XML_Parser& parser): gui(gui), parser(parser), errors_len(0u), skip_tag(0u) {};
00029
00033 bool tag_begin() {
00034 if (skip_tag == 0u) return true;
00035 ++skip_tag;
00036 return false;
00037 };
00038
00042 bool tag_end() {
00043 if (skip_tag != 0u) {
00044 --skip_tag;
00045 return false;
00046 }
00047 return true;
00048 };
00049
00053 void tag_skip() {
00054 ++skip_tag;
00055 };
00056
00057 };
00058
00059 void XMLCALL
00060 startElement(void *userData, const char *name, const char **atts) {
00061 ParserInfo* p = (ParserInfo*)userData;
00062 if (!p->tag_begin()) return;
00063 WidgetCreator* wc = WidgetFactory::getCreator(name, p->gui);
00064 if (!wc) {
00065 p->gui.errors.append(new InvalidTagError(name, XML_GetCurrentLineNumber(p->parser), Error::skip_tag));
00066 p->tag_skip();
00067 return;
00068 }
00069 const char* id = utils::find_pair(atts, "id");
00070 p->creators_stack.push(wc);
00071 fltk::Widget* w = wc->create_begin(atts);
00072 if (!p->gui.root())
00073 p->gui._root = w;
00074 if (id)
00075 p->gui.setWidget(utils::strcopy(id), w);
00076 }
00077
00078 static void XMLCALL
00079 endElement(void *userData, const char *name) {
00080 ParserInfo* p = (ParserInfo*)userData;
00081 if (!p->tag_end()) return;
00082 p->creators_stack.top()->create_end();
00083 delete p->creators_stack.top();
00084 p->creators_stack.pop();
00085 }
00086
00087 GUI::GUI(std::istream& in_stream): _root(0) {
00088 in_stream >> *this;
00089 }
00090
00091 GUI::GUI(const char* file_name): _root(0) {
00092 readFromFile(file_name);
00093 }
00094
00095 void GUI::clear() {
00096 for (widget_map_type::iterator i = widget_map.begin(); i != widget_map.end(); ++i)
00097 delete[] i->first;
00098 widget_map.clear();
00099 delete _root;
00100 _root = 0;
00101 }
00102
00103 GUI::~GUI() {
00104 clear();
00105 }
00106
00107 fltk::Widget* GUI::operator[](const char* name) {
00108 widget_map_type::iterator res = widget_map.find(name);
00109 return (res == widget_map.end()) ? 0 : res->second;
00110 }
00111
00112 std::istream& operator>>(std::istream& in_stream, GUI& g) {
00113 g.clear();
00114 g.errors.clear();
00115
00116
00117 XML_Parser parser = XML_ParserCreate(NULL);
00118 ParserInfo parser_info(g, parser);
00119
00120 void *buff = XML_GetBuffer(parser, BUFSIZ);
00121 if (buff == NULL) {
00122
00123 }
00124 int done;
00125 XML_SetUserData(parser, &parser_info);
00126 XML_SetElementHandler(parser, startElement, endElement);
00127
00128 do {
00129 size_t len = in_stream.read((char*)buff, BUFSIZ).gcount();
00130
00131 done = len < sizeof(buff);
00132 if (XML_ParseBuffer(parser, len, done) == XML_STATUS_ERROR) {
00133 g.errors.append(
00134 new GeneralStaticError( XML_ErrorString(XML_GetErrorCode(parser)),
00135 XML_GetCurrentLineNumber(parser), Error::skip_all)
00136 );
00137 return in_stream;
00138 }
00139 } while (!done);
00140
00141 XML_ParserFree(parser);
00142 return in_stream;
00143 }
00144
00145 void GUI::readFromFile(const char* file_name) {
00146 std::ifstream file(file_name);
00147
00148
00149
00150
00151 file >> *this;
00152 }
00153
00154 }