cgv
Loading...
Searching...
No Matches
base_provider_generator.cxx
1#include "base_provider.h"
2#include "base_provider_generator.h"
3#include <cgv/gui/trigger.h>
4#include <cgv/utils/file.h>
6#include <cgv/utils/tokenizer.h>
7
8using namespace cgv::utils;
9
10namespace cgv {
11 namespace gui {
12
18
21{
22 return "base_provider_generator";
23}
24
30
32void base_provider_generator::on_set(void* member_ptr)
33{
34 if (member_ptr != &check_file_update)
35 return;
37 connect(get_animation_trigger().shoot, this, &base_provider_generator::timer_event);
38 else
39 disconnect(get_animation_trigger().shoot, this, &base_provider_generator::timer_event);
40}
41
42std::string error_start(const std::string& content, const token& T)
43{
44 std::string error("error (");
45 const char* end = T.end;
46 if (&content[content.size()-1] < end)
47 end = &content[content.size()-1];
48
49 unsigned line_nr = 1;
50 for (const char* p = &content[0]; p<end;++p)
51 if (*p == '\n')
52 ++line_nr;
53
54 error += to_string(line_nr);
55 error += ") : ";
56 return error;
57}
58
59void base_provider_generator::timer_event(double,double)
60{
61 for (std::map<std::string,long long>::const_iterator i = gui_files.begin(); i != gui_files.end(); ++i) {
62 long long lwt = cgv::utils::file::get_last_write_time(i->first);
63 if (lwt > i->second)
64 parse_gui_file(i->first);
65 }
66}
67
69bool base_provider_generator::parse_gui_file(const std::string& file_name)
70{
71 std::string content;
72 if (!cgv::utils::file::read(file_name, content, true))
73 return false;
74 gui_files[file_name] = cgv::utils::file::get_last_write_time(file_name);
75 std::vector<token> T;
76 tokenizer(content).set_sep(":(){}").set_skip("\"","\"").bite_all(T);
77 unsigned i=0;
78 while (i < T.size()) {
79 bool is_type;
80 if (!((is_type = (T[i] == "type")) || T[i] == "name")) {
81 std::cerr << error_start(content, T[i]) << "expected type or name" << std::endl;
82 ++i;
83 continue;
84 }
85 if (++i >= T.size()) {
86 std::cerr << error_start(content, T[i-1]) << "incomplete definition" << std::endl;
87 continue;
88 }
89 if (T[i] != "(") {
90 std::cerr << error_start(content, T[i]) << "expected ( " << std::endl;
91 continue;
92 }
93 if (++i >= T.size()) {
94 std::cerr << error_start(content, T[i-1]) << "incomplete definition" << std::endl;
95 continue;
96 }
97 if (T[i] == ")" || T[i] == "{" || T[i] == "}" || T[i] == ":") {
98 std::cerr << error_start(content, T[i]) << "unexpected token" << std::endl;
99 continue;
100 }
101 std::string key = to_string(T[i]);
102 if (++i >= T.size()) {
103 std::cerr << error_start(content, T[i-1]) << "incomplete definition" << std::endl;
104 continue;
105 }
106 if (T[i] != ")") {
107 std::cerr << error_start(content, T[i]) << "expected )" << std::endl;
108 continue;
109 }
110 if (++i >= T.size()) {
111 std::cerr << error_start(content, T[i-1]) << "incomplete definition" << std::endl;
112 continue;
113 }
114 std::string options;
115 if (T[i] == ":") {
116 if (++i >= T.size()) {
117 std::cerr << error_start(content, T[i-1]) << "incomplete definition" << std::endl;
118 continue;
119 }
120 options = to_string(T[i]);
121 ++i;
122 }
123 if (T[i] != "{") {
124 std::cerr << error_start(content, T[i]) << "expected {" << std::endl;
125 continue;
126 }
127 unsigned j = i+1;
128 unsigned k = 1;
129 while (j < T.size()) {
130 if (T[j] == "{")
131 ++k;
132 else if (T[j] == "}") {
133 --k;
134 if (k==0)
135 break;
136 }
137 ++j;
138 }
139 const char* end_ptr;
140 if (j == T.size()) {
141 std::cerr << error_start(content, T[j-1]) << "missing }" << std::endl;
142 end_ptr = &content[content.size()];
143 }
144 else
145 end_ptr = T[j-1].end;
146
147 std::string def(T[i+1].begin, end_ptr-T[i+1].begin);
148 if (is_type) {
149 defs_by_type[key] = gui_definition(def,options);
150 // std::cout << "add by type def for " << key << ":\n" << defs_by_type[key] << "\n" << std::endl;
151 // update guis of matched objects
152 for (pvd_map_iter pi=providers.begin(); pi != providers.end(); ++pi) {
153 if (!pi->second->is_named_gui_assignment() && pi->first->get_type_name() == key)
154 pi->second->set_gui_definition(def);
155 pi->second->multi_set(options, true);
156 }
157 }
158 else {
159 defs_by_name[key] = gui_definition(def,options);
160 // std::cout << "add by name def for " << key << ":\n" << defs_by_name[key] << "\n" << std::endl;
161 // update guis of matched objects
162 for (pvd_map_iter pi=providers.begin(); pi != providers.end(); ++pi) {
163 if (pi->first->get_named() && pi->first->get_named()->get_name() == key) {
164 pi->second->set_gui_definition(def);
165 pi->second->multi_set(options, true);
166 pi->second->set_named_gui_assignment(true);
167 }
168 }
169 }
170
171 i = j+1;
172 }
173 // try to match unmatched objects
174 for (i=0; i<unmatched_objects.size(); ++i)
176 unmatched_objects.erase(unmatched_objects.begin()+i);
177 --i;
178 }
179
180 return true;
181}
182
185{
186 if (object->get_named()) {
187 const std::string& name = object->get_named()->get_name();
188 def_map_iter iter = defs_by_name.find(name);
189 if (iter != defs_by_name.end()) {
190 base_provider_ptr pvd(new base_provider(object, iter->second.definition));
191 if (!iter->second.options.empty())
192 pvd->multi_set(iter->second.options, true);
194 providers[object] = pvd;
195 return true;
196 }
197 }
198 def_map_iter iter = defs_by_type.find(object->get_type_name());
199 if (iter != defs_by_type.end()) {
200 base_provider_ptr pvd(new base_provider(object, iter->second.definition));
201 if (!iter->second.options.empty())
202 pvd->multi_set(iter->second.options, true);
204 providers[object] = pvd;
205 return true;
206 }
207 return false;
208}
209
211void base_provider_generator::register_object(cgv::base::base_ptr object, const std::string& options)
212{
213 if (object->get_interface<provider>())
214 return;
215 if (!generate_object_gui(object))
216 unmatched_objects.push_back(object);
217}
218
219
222{
223 pvd_map_iter iter = providers.find(object);
224 if (iter == providers.end())
225 return;
226 cgv::base::unregister_object(iter->second);
227 providers.erase(iter);
228
229 for (unsigned i=0; i<unmatched_objects.size(); ++i)
230 if (unmatched_objects[i] == object) {
231 unmatched_objects.erase(unmatched_objects.begin()+i);
232 --i;
233 }
234}
235
236 }
237}
More advanced text processing for splitting text into lines or tokens.
bool generate_object_gui(cgv::base::base_ptr object)
check whether gui description is available for object and if yes generate a base_provider
def_map_type defs_by_type
mappings from type to gui definitions
bool parse_gui_file(const std::string &file_name)
parse file and extract gui definitions
def_map_type::const_iterator def_map_iter
iterator type for map
def_map_type defs_by_name
mappings from name to gui definitions
pvd_map_type providers
store map to base_providers
void register_object(cgv::base::base_ptr object, const std::string &options)
if object is registered that does not provide its own gui but matches type or name of a parsed gui de...
void unregister_object(cgv::base::base_ptr object, const std::string &options)
remove also the base_provider of an object if created
bool self_reflect(cgv::reflect::reflection_handler &rh)
used for simple self reflection
void on_set(void *member_ptr)
this callback is called when the set_void method has changed a member and can be overloaded in derive...
std::vector< cgv::base::base_ptr > unmatched_objects
keep track of unmatched objects
base_provider_generator()
construct from instance and gui definition
std::string get_type_name() const
overload to return the type name of this object. By default the type interface is queried over get_ty...
std::map< std::string, long long > gui_files
store read gui files with last write times
bool check_file_update
whether to check files
pvd_map_type::iterator pvd_map_iter
iterator type of base_provider map
derive from this class to provide a gui to the current viewer
Definition provider.h:64
the self reflection handler is passed to the virtual self_reflect() method of cgv::base::base.
bool reflect_member(const std::string &member_name, T &member_ref, bool hard_cast=false)
call this to reflect a member by member name and reference to the member.
the tokenizer allows to split text into tokens in a convenient way.
Definition tokenizer.h:68
tokenizer & set_sep(const std::string &sep, bool merge)
set the list of separators and specify whether succeeding separators are merged into single tokens
Definition tokenizer.cxx:59
tokenizer & set_skip(const std::string &open, const std::string &close)
set several character pairs that enclose tokens that are not split
Definition tokenizer.cxx:44
void unregister_object(base_ptr object, const std::string &options)
unregister an object and send event to all current registration ref_listeners()
Definition register.cxx:617
void register_object(base_ptr object, const std::string &options)
register an object and send event to all current registration ref_listeners()
Definition register.cxx:581
trigger & get_animation_trigger()
return the global trigger used for animation, which runs by default with 60 Hz
Definition trigger.cxx:81
namespace that holds tools that dont fit any other namespace
std::string to_string(const std::string &v, unsigned int w, unsigned int p, bool)
specialization of conversion from string to strings
the cgv namespace
Definition print.h:11
each gui definition consists of the textual definition as well as an options string
representation of a token in a text by two pointers begin and end, that point to the first character ...
Definition token.h:18