Main Page   Namespace List   Class Hierarchy   Compound List   File List   Compound Members   File Members  

component_manager_generic.cpp

Go to the documentation of this file.
00001 /*
00002         ClanGUI, copyrights by various people. Have a look in the CREDITS file.
00003         
00004         This sourcecode is distributed using the Library GNU Public Licence,
00005         version 2 or (at your option) any later version. Please read LICENSE
00006         for details.
00007 */
00008 
00009 #include "precomp.h"
00010 #include "API/Core/System/clanstring.h"
00011 #include "API/Core/Resources/resource_manager.h"
00012 #include "API/Core/IOData/inputsource.h"
00013 #include "API/GUI/component_style.h"
00014 #include "component_manager_generic.h"
00015 #include "component_tokenizer.h"
00016 #include "componentfile_preprocess.h"
00017 
00018 std::map<std::string, CL_ComponentType *> CL_ComponentManager::component_types;
00019 
00020 CL_ComponentManager *CL_ComponentManager::create(const char *resource_id, CL_ResourceManager *res_manager, CL_StyleManager *style)
00021 {
00022         return new CL_ComponentManager_Generic(resource_id, res_manager, style);
00023 }
00024 
00025 CL_ComponentManager *CL_ComponentManager::create(const char *filename, bool is_datafile, CL_StyleManager *style)
00026 {
00027         return new CL_ComponentManager_Generic(filename, is_datafile, style);
00028 }
00029 
00030 CL_ComponentManager_Generic::CL_ComponentManager_Generic(const char *filename, CL_ResourceManager *resources, CL_StyleManager *style)
00031 {
00032         this->filename = filename;
00033         this->resources = resources;
00034         style_manager = style;
00035 //      init_style_manager(style_id);
00036 
00037         input = resources->get_resource_provider()->open_source(filename);
00038         parse();
00039 }
00040 
00041 CL_ComponentManager_Generic::CL_ComponentManager_Generic(const char *filename, bool is_datafile, CL_StyleManager *style)
00042 {
00043         this->filename = filename;
00044         style_manager = style;
00045 //      init_style_manager(style_id);
00046 
00047         if (is_datafile)
00048         {
00049                 input = CL_InputSourceProvider::create_datafile_provider(filename)->open_source(filename);
00050         }
00051         else
00052         {
00053                 input = CL_InputSourceProvider::create_file_provider(".")->open_source(filename);
00054         }
00055         
00056         parse();
00057 }
00058 
00059 CL_ComponentManager_Generic::~CL_ComponentManager_Generic()
00060 {
00061         std::vector<CL_Component *> components;
00062         get_root_component_list(components);
00063         
00064         std::vector<CL_Component *>::iterator it;
00065         for (it = components.begin(); it != components.end(); it++)
00066                 delete *it;
00067 }
00068 
00069 void CL_ComponentManager_Generic::init_style_manager(const char *style_id)
00070 {
00071 /*
00072         if (style_id == NULL)
00073         {
00074                 style_manager = CL_StyleManager::default_style_manager;
00075         }
00076         else
00077         {
00078                 std::map<std::string, CL_StyleManager *>::iterator style_it = CL_StyleManager::style_managers.find(style_id);
00079                 if (style_it == CL_StyleManager::style_managers.end()) throw CL_Error("Specified style manager does not exist");
00080                 style_manager = (*style_it).second;
00081         }
00082 */
00083 }
00084 
00085 void CL_ComponentManager_Generic::create_components(std::multimap<int, CL_ComponentInfo *> &creation_sort_map)
00086 {
00087         std::multimap<int, CL_ComponentInfo *>::iterator it;
00088         for (it=creation_sort_map.begin();it!=creation_sort_map.end();it++)
00089         {
00090                 CL_ComponentInfo *info = (*it).second;
00091 
00092                 if (info->component == NULL)
00093                 {
00094                         info->component = style_manager->create_component(
00095                                 info->type,
00096                                 info->options,
00097                                 NULL);
00098                 }
00099 
00100                 if (!info->children.empty())
00101                 {
00102                         if (!info->component_type->is_container()) 
00103                         {
00104                                 throw CL_Error("Internal component manager error");
00105                         }
00106 
00107                         std::list<CL_ComponentInfo *>::iterator c_it;
00108                         for (c_it=info->children.begin();c_it!=info->children.end();c_it++)
00109                         {
00110                                 CL_ComponentInfo *child_info = *c_it;
00111                                 if (child_info->component == NULL)
00112                                 {
00113                                         child_info->component = style_manager->create_component(
00114                                                 child_info->type,
00115                                                 child_info->options,
00116                                                 info->component);
00117                                 }
00118 
00119                                 info->component->add_child(child_info->component, true);
00120                         }
00121                         info->children.clear();
00122                 }
00123         }
00124 }
00125 
00126 CL_Component *CL_ComponentManager_Generic::get_component(const char *component_id)
00127 {
00128         std::map<std::string, CL_ComponentManager_Generic::CL_ComponentInfo>::iterator it = component_map.find(component_id);
00129         if (it != component_map.end()) 
00130         {
00131                 return (*it).second.component;
00132         }
00133         throw CL_Error("Unable to locate component");
00134 }
00135 
00136 void CL_ComponentManager_Generic::get_root_component_list(std::vector<CL_Component *> &components)
00137 {
00138         std::map<std::string, CL_ComponentInfo>::iterator it;
00139         for (it = component_map.begin(); it != component_map.end();it++)
00140         {
00141                 if ((*it).second.component->get_parent() == NULL)
00142                 {
00143                         components.push_back((*it).second.component);
00144                 }
00145         }
00146 }
00147 
00148 std::string CL_ComponentManager_Generic::preprocess_templates()
00149 {
00150         char *temp_data = new char[input->size()+1];
00151         input->read(temp_data, input->size());
00152         temp_data[input->size()] = 0;
00153         std::string file_data(temp_data);
00154         delete[] temp_data;
00155 
00156         CL_Componentfile_Preprocess preprocessor(file_data, filename);
00157         return preprocessor;
00158 }
00159 
00160 void CL_ComponentManager_Generic::parse()
00161 {
00162         CL_ComponentTokenizer lexer(preprocess_templates(), filename);
00163 
00164         typedef std::pair<std::string, CL_ComponentInfo> named_component_t;
00165         std::stack<named_component_t> component_stack;
00166         std::multimap<int, CL_ComponentInfo *> creation_sort_map;
00167         std::map<std::string, int> component_id_enumerator;
00168 
00169         enum EParseState
00170         {
00171                 PARSE_GLOBAL,
00172                 PARSE_COMPONENT_TYPE,
00173                 PARSE_COMPONENT_NAME,
00174                 PARSE_COMPONENT,
00175                 PARSE_VARIABLE_NAME,
00176                 PARSE_VARIABLE_VALUE
00177         };
00178         EParseState state = PARSE_GLOBAL;
00179         EParseState prev_state = PARSE_GLOBAL;
00180         std::string component_type;
00181         std::string component_name;
00182         std::string variable_name;
00183         std::list<std::string> variable_value;
00184         std::string toplevel_style = "";
00185 
00186         while (true)
00187         {
00188                 const std::string &token = lexer.peek_next_token();
00189                 if (token == "") break;
00190 
00191                 CL_ComponentType *comp_type = NULL;
00192                 switch (state)
00193                 {
00194                 case PARSE_GLOBAL:
00195                         if (token == "style")
00196                         {
00197                                 if (lexer.peek_next_token() != "=")
00198                                 {
00199                                         throw CL_Error(lexer.write_error("Missing '=' following global style-declaration"));
00200                                 }
00201                                 prev_state = PARSE_GLOBAL;
00202                                 state = PARSE_VARIABLE_VALUE;
00203                                 variable_name = token;
00204                         }
00205                         else if ((comp_type = is_component_type(token)))
00206                         {
00207                                 state = PARSE_COMPONENT_TYPE;
00208                                 component_type = token;
00209                                 component_name = "";
00210 
00211                                 CL_ComponentManager_Generic::CL_ComponentInfo info;
00212                                 info.type = token;
00213                                 info.component = NULL;
00214                                 info.component_type = comp_type;
00215                                 component_stack.push(named_component_t("", info));
00216                         }
00217                         else
00218                         {
00219                                 throw CL_Error(lexer.write_error("Syntax error"));
00220                         }
00221                         break;
00222                 case PARSE_COMPONENT_TYPE:
00223                         if (token == "{")
00224                         {
00225                                 int next_id = component_id_enumerator[token]++;
00226                                 char buf[20];
00227                                 sprintf(buf, "%d", next_id);
00228                                 if (strlen(buf) == 1) component_name = token+"0"+buf;
00229                                 else component_name = token+buf;
00230                                 component_stack.top().first = component_name;
00231 
00232                                 state = PARSE_COMPONENT;
00233                         }
00234                         else
00235                         {
00236                                 component_name = token;
00237                                 component_stack.top().first = component_name;
00238                                 state = PARSE_COMPONENT_NAME;
00239                         }
00240                         break;
00241                 case PARSE_COMPONENT_NAME:
00242                         if (token != "{")
00243                         {
00244                                 char buf[1000];
00245                                 sprintf(buf, "Missing '{' following declaration of component '%s'", component_name.c_str());
00246                                 throw CL_Error(lexer.write_error(buf));
00247                         }
00248                         state = PARSE_COMPONENT;
00249                         break;
00250                 case PARSE_COMPONENT:
00251                         {
00252                                 comp_type = is_component_type(token);
00253                                 if (comp_type != NULL)
00254                                 {
00255                                         if (component_stack.empty())
00256                                         {
00257                                                 throw CL_Error("Internal component manager parser error");
00258                                         }
00259                                         if (!component_stack.top().second.component_type->is_container()) throw CL_Error("Tried to add child to non-container component");
00260 
00261                                         CL_ComponentManager_Generic::CL_ComponentInfo info;
00262                                         info.type = token;
00263                                         info.component = NULL;
00264                                         info.component_type = comp_type;
00265 
00266                                         component_stack.push(named_component_t("", info));
00267                                         component_type = token;
00268                                         component_name = "";
00269                                         state = PARSE_COMPONENT_TYPE;
00270                                 }
00271                                 else if (token == "}")
00272                                 {
00273                                         if (component_stack.empty())
00274                                         {
00275                                                 throw CL_Error(lexer.write_error("Found '}' outside component"));
00276                                         }
00277                                         named_component_t comp = component_stack.top();
00278                                         component_stack.pop();
00279 
00280                                         std::pair<std::map<std::string, CL_ComponentManager_Generic::CL_ComponentInfo>::iterator, bool> it = 
00281                                                 component_map.insert(
00282                                                         std::make_pair(comp.first, comp.second));
00283                                         
00284                                         if (!it.second)
00285                                         {
00286                                                 throw CL_Error("All component names must be unique");
00287                                         }
00288 
00289                                         // This creation map is used to make sure that components get
00290                                         // pointers to their parent upon creation.
00291                                         // This map controls the ordering of component-creations using
00292                                         // component-nesting level as sorter.
00293                                         creation_sort_map.insert(std::make_pair(
00294                                                 component_stack.size(),
00295                                                 &(*it.first).second));
00296 
00297                                         if (!component_stack.empty())
00298                                         {
00299                                                 named_component_t &parent_comp = component_stack.top();
00300                                                 if (!parent_comp.second.component_type->is_container())
00301                                                 {
00302                                                         throw CL_Error(lexer.write_error("Found component inside other component (must be container)"));
00303                                                 }
00304                                                 else
00305                                                 {
00306                                                         parent_comp.second.children.push_back(&(*it.first).second);
00307                                                 }
00308                                         }
00309                                         else
00310                                         {
00311                                                 state = PARSE_GLOBAL;
00312                                         }
00313                                 }
00314                                 else if (token.length() == 1 && lexer.is_operator(token[0]))
00315                                 {
00316                                         throw CL_Error(lexer.write_error("Expected variable-name or component-type"));
00317                                 }
00318                                 else
00319                                 {
00320                                         prev_state = PARSE_COMPONENT;
00321                                         state = PARSE_VARIABLE_NAME;
00322                                         variable_name = token;
00323                                         variable_value.clear();
00324                                 }
00325                         }
00326                         break;
00327                 case PARSE_VARIABLE_NAME:
00328                         if (token == "=")
00329                         {
00330                                 state = PARSE_VARIABLE_VALUE;
00331                         }
00332                         else if (token == ";")
00333                         {
00334                                 if (!component_stack.top().second.component_type->has_option(variable_name))
00335                                 {
00336                                         char buf[1000];
00337                                         sprintf(buf, "Failed to add '%s' to component of type '%s'",
00338                                                 variable_name.c_str(),
00339                                                 component_stack.top().second.type.c_str());
00340                                         throw CL_Error(lexer.write_error(buf));
00341                                 }
00342                                 #ifdef BORLAND
00343                                 component_stack.top().second.options.options.insert(std::make_pair(std::string(variable_name), std::string("")));
00344                                 #else
00345                                 component_stack.top().second.options.options.insert(std::make_pair<std::string, std::string>(variable_name, ""));
00346                                 #endif
00347                                 variable_name = "";
00348                                 variable_value.clear();
00349                                 state = prev_state;
00350                         }
00351                         else
00352                         {
00353                                 throw CL_Error(lexer.write_error("Expected ';' following variable declaration"));
00354                         }
00355                         break;
00356                 case PARSE_VARIABLE_VALUE:
00357                         if (token != ";")
00358                         {
00359                                 variable_value.push_back(token);
00360                         }
00361                         else
00362                         {
00363                                 if (component_stack.empty())
00364                                 {
00365                                         globals.push_back(variable_pair_t(variable_name, evaluate_expression(variable_value)));
00366                                 }
00367                                 else if (!component_stack.top().second.component_type->has_option(variable_name))
00368                                 {
00369                                         std::string variable_value_str;
00370                                         int size_list = variable_value.size();
00371                                         std::list<std::string>::iterator it;
00372                                         for (it=variable_value.begin();it!=variable_value.end();it++)
00373                                         {
00374                                                 variable_value_str.append(*it);
00375                                                 size_list--;
00376                                                 if (size_list > 0) variable_value_str.append(1, ' ');
00377                                         }
00378                                         char buf[1000];
00379                                         sprintf(buf, "Failed to add '%s = %s' to component of type '%s'",
00380                                                 variable_name.c_str(), 
00381                                                 variable_value_str.c_str(),
00382                                                 component_stack.top().second.type.c_str());
00383                                         throw CL_Error(lexer.write_error(buf));
00384                                 }
00385                                 else
00386                                 {
00387                                         component_stack.top().second.options.options.insert(std::make_pair(variable_name, evaluate_expression(variable_value)));
00388                                 }
00389                                 variable_name = "";
00390                                 variable_value.clear();
00391                                 state = prev_state;
00392                         }
00393                         break;
00394                 }
00395                 lexer.pop_to_peek();
00396         }
00397         create_components(creation_sort_map);
00398 }
00399 
00400 CL_ComponentType *CL_ComponentManager_Generic::is_component_type(const std::string &token)
00401 {
00402         std::map<std::string, CL_ComponentType *>::iterator it = CL_ComponentManager::component_types.find(token);
00403         if (it == CL_ComponentManager::component_types.end()) return NULL;
00404 
00405         return (*it).second;
00406 }
00407 
00408 std::string CL_ComponentManager_Generic::concatenate_stringlist(std::list<std::string> &expression)
00409 {
00410         std::string result;
00411         int size_list = expression.size();
00412         std::list<std::string>::iterator it;
00413         for (it=expression.begin();it!=expression.end();it++)
00414         {
00415                 result.append(*it);
00416                 size_list--;
00417                 if (size_list > 0) result.append(1, ' ');
00418         }
00419         return result;
00420 }
00421 
00422 std::string CL_ComponentManager_Generic::evaluate_expression(std::list<std::string> &expression)
00423 {
00424         bool is_expression = true;
00425         std::string result;
00426         std::list<std::string>::iterator it = expression.begin();
00427         for (;it!=expression.end();it++)
00428         {
00429                 std::string &s = *it;
00430                 if (s == "+" || s == "-" || s == "*" || s == "/" || s == "(" || s == ")")
00431                 {
00432                         continue;
00433                 }
00434                 const char *str = s.c_str();
00435                 for (;*str;str++)
00436                 {
00437                         if ((*str < '0' || *str > '9') && *str != '.')
00438                         {
00439                                 break;
00440                         }
00441                 }
00442                 if (*str)
00443                 {
00444                         is_expression = false;
00445                         break;
00446                 }
00447         }
00448 
00449         if (!is_expression)
00450         {
00451                 return concatenate_stringlist(expression);
00452         }
00453 
00454         std::string test = concatenate_stringlist(expression);
00455         /*
00456                 Please note:
00457                 This expression evaluation function is NOT FINISHED!
00458                 This is a totally basic no-operator-precedence implementation
00459                 that disregards paranthesis and just plain sucks, but 
00460                 I don't have the willpower to complete it - someone else feel free :-)
00461         */
00462         int op = 0;
00463         float result_val = 0.0f;
00464         for (it=expression.begin();it!=expression.end();it++)
00465         {
00466                 std::string &s = *it;
00467                 if (s == "+") op = 0;
00468                 else if (s == "-") op = 1;
00469                 else if (s == "*") op = 2;
00470                 else if (s == "/") op = 3;
00471                 else if (s == "(" || s == ")")
00472                 {
00473                         continue;
00474                 }
00475                 else
00476                 {
00477                         if (op == -1) throw CL_Error("Could not evaluate expression");
00478                         float val = atof(s.c_str());
00479                         switch (op)
00480                         {
00481                         case 0:
00482                                 result_val += val;
00483                                 break;
00484                         case 1:
00485                                 result_val -= val;
00486                                 break;
00487                         case 2:
00488                                 result_val *= val;
00489                                 break;
00490                         case 3:
00491                                 result_val /= val;
00492                                 break;
00493                         default:
00494                                 result_val = val;
00495                                 break;
00496                         }
00497                         op = -1;
00498                 }
00499         }
00500 
00501         int rval = int(result_val+0.5);
00502         return CL_String(rval);
00503 }

Generated at Wed Apr 4 19:53:59 2001 for ClanLib by doxygen1.2.6 written by Dimitri van Heesch, © 1997-2001