SmallChange  1.0.0
A collection of extensions to Coin3D
Loading...
Searching...
No Matches
DynamicNodeKit.h
1#ifndef DynamicNodeKit_H
2#define DynamicNodeKit_H
3
4#include <Inventor/nodekits/SoBaseKit.h>
5#include <Inventor/nodekits/SoSubKit.h>
6
7#include <Inventor/fields/SoFieldData.h>
8#include <Inventor/nodekits/SoNodekitCatalog.h>
9
10#include <Inventor/C/XML/parser.h>
11#include <Inventor/C/XML/document.h>
12#include <Inventor/C/XML/element.h>
13#include <Inventor/C/XML/attribute.h>
14
15
16class SoNodekitCatalog;
17class SoFieldData;
18struct cc_xml_elt;
19
20template <class Base>
21class DynamicNodeKit : public Base {
22 typedef Base inherited;
23
24 /*
25 Misc stuff from the coin init macros:
26 */
27public:
28 static SoType getClassTypeId(void);
29 virtual SoType getTypeId(void) const;
30 static const SoNodekitCatalog * getClassNodekitCatalog(void);
31 virtual const SoNodekitCatalog * getNodekitCatalog(void) const;
32protected:
33 static const SoFieldData ** getFieldDataPtr(void);
34 virtual const SoFieldData * getFieldData(void) const;
35 static const SoNodekitCatalog ** getClassNodekitCatalogPtr(void);
36private:
37 static SoType classTypeId;
38 static void atexit_cleanup(void);
39 static const SoFieldData ** parentFieldData;
40 static SoFieldData * fieldData;
41 static unsigned int classinstances;
42 static void * createInstance(void);
43 static SoNodekitCatalog * classcatalog;
44 static const SoNodekitCatalog ** parentcatalogptr;
45 static void atexit_cleanupkit(void);
46
47 /*
48 Functions that we add:
49 */
50public:
51 DynamicNodeKit(void);
52 static void initClass(void);
53 virtual void copyContents(const SoFieldContainer * from, SbBool copyconn);
54
55 bool startEditing();
56 bool addField(SbString name, SbString typeString, SbString defaultValue);
57 bool addPart(SbString name, SbString typeString, SbBool isDefaultNull, SbString parentName, SbString rightSiblingName, SbBool isPublic);
58 bool setNodekitDescription(SbString xmlDescription);
59 bool finishEditing();
60
61 //We need public functions for [get|set]AnyPart, so that the script wrapper can call them
62 virtual SoNode * getAnyPart(const SbName & partname, SbBool makeifneeded, SbBool leafcheck = 0, SbBool publiccheck = 0);
63 virtual SbBool setAnyPart(const SbName & partname, SoNode * from, SbBool anypart = 1);
64
65protected:
66 virtual ~DynamicNodeKit();
67
68private:
69 SoNodekitCatalog * dynamicCatalog;
70 SoFieldData * dynamicFieldData;
71 bool addPartsFromXml(cc_xml_elt * element, const char * parentName, const char * rightSiblingName);
72
73 int staticPartCount;
74 bool finished;
75 bool isEditing;
76};
77
78/*
79End class definition, start template method implementation
80*/
81
82//only compile when instantiating with new types
83#ifndef DYNAMIC_NODEKIT_NO_GENERATE_FUNCTIONS
84template <class Base> SoType DynamicNodeKit<Base>::classTypeId STATIC_SOTYPE_INIT;
85template <class Base> const SoFieldData ** DynamicNodeKit<Base>::parentFieldData = NULL;
86template <class Base> SoFieldData * DynamicNodeKit<Base>::fieldData = NULL;
87template <class Base> unsigned int DynamicNodeKit<Base>::classinstances = 0;
88template <class Base> SoNodekitCatalog * DynamicNodeKit<Base>::classcatalog = NULL;
89template <class Base> const SoNodekitCatalog ** DynamicNodeKit<Base>::parentcatalogptr = NULL;
90
91template <class Base>
92inline
93const SoNodekitCatalog *
95{
97}
98
99template <class Base>
100inline
101const SoNodekitCatalog **
103{
104 return const_cast<const class SoNodekitCatalog **>(&DynamicNodeKit<Base>::classcatalog);
105}
106
107template <class Base>
108inline
109void
111{
115}
116
117template <class Base>
118inline
119SoType
122}
123
124template <class Base>
125inline
126SoType
129}
130
131template <class Base>
132inline
133const SoFieldData **
135{
136 return const_cast<const SoFieldData **>(&DynamicNodeKit<Base>::fieldData);
137}
138
139template <class Base>
140inline
141void
143{
147 SoType::removeType(DynamicNodeKit<Base>::classTypeId.getName());
148 DynamicNodeKit<Base>::classTypeId STATIC_SOTYPE_INIT;
150}
151
152template <class Base>
153inline
154void *
156{
157 return new DynamicNodeKit<Base>;
158}
159
160//End default implementations
161
162//overloaded:
163template <class Base>
164inline
165const SoFieldData *
167{
168 return dynamicFieldData;
169}
170
171// overloaded:
172template <class Base>
173inline
174const SoNodekitCatalog *
176{
177 return this->dynamicCatalog;
178}
179
180template <class Base>
181inline
182void
184{
185 if (DynamicNodeKit<Base>::getClassTypeId() == SoType::badType()){
186 SoType parentType = Base::getClassTypeId();
187 SbName parentName = parentType.getName();
188
189 //FIXME: find a good naming scheme, will be used as script constructor name
190 SbString classNameString = "Dynamic";
191 classNameString += parentName;
192
193 const char * classname = classNameString.getString();
194
195 /* Set up entry in the type system. */
197 SoType::createType(parentType,
198 classname,
200 SoNode::getNextActionMethodIndex());
201 SoNode::incNextActionMethodIndex();
202
203 /* Store parent's fielddata pointer for later use in the constructor. */
204 DynamicNodeKit<Base>::parentFieldData = Base::getFieldDataPtr();
205 /* Make sure also external nodes are cleaned up */
206 cc_coin_atexit_static_internal((coin_atexit_f*)DynamicNodeKit<Base>::atexit_cleanup);
207
208 DynamicNodeKit<Base>::parentcatalogptr = Base::getClassNodekitCatalogPtr();
209 }
210}
211
212template <class Base>
213inline
214DynamicNodeKit<Base>::DynamicNodeKit(void) : inherited()
215{
216 SO_KIT_CONSTRUCTOR(DynamicNodeKit);//FIXME: expand
217
218 this->dynamicFieldData = new SoFieldData;
219 this->dynamicFieldData->copy(inherited::getFieldData());//clone from parent?
220
221 this->dynamicCatalog = inherited::getNodekitCatalog()->clone(DynamicNodeKit<Base>::getClassTypeId());
222 this->staticPartCount = dynamicCatalog->getNumEntries();
223
224 this->finished = false;
225 this->isEditing = false;
226}
227
228template <class Base>
229inline
231{
232 //remove dynamic fields and parts and delete the fieldData and catalog
233 const int n = this->dynamicFieldData->getNumFields();
234 for (int i = 0; i < n; i++) {
235 SoField * f = this->dynamicFieldData->getField(this, i);
236 if ((*this->getFieldDataPtr())->getIndex(this, f) == -1) { //don't delete fields from parent
237 delete f;
238 }
239 }
240 delete this->dynamicFieldData;
241 delete this->dynamicCatalog;
242}
243
244template <class Base>
245inline
246void
247DynamicNodeKit<Base>::copyContents(const SoFieldContainer * from, SbBool copyconn)
248{
249 //FIXME: verify that this makes sense
250 assert(from->isOfType(DynamicNodeKit<Base>::getClassTypeId()) && "wrong type in copyContents");
251
252 const SoFieldData * src = from->getFieldData();
253 const int n = src->getNumFields();
254 for (int i = 0; i < n; i++) {
255 const SoField * f = src->getField(from, i);
256 if (this->dynamicFieldData->getIndex(this, f) == -1) { //only add new fields
257 SoField * cp = (SoField*) f->getTypeId().createInstance();
258 cp->setFieldType(f->getFieldType());
259 cp->setContainer(this);
260 this->dynamicFieldData->addField(this, src->getFieldName(i), cp);
261 }
262 }
263 //FIXME: copy the catalog as well? seems like this is handled by SoBase::copyContents...
264 inherited::copyContents(from, copyconn);
265}
266
267template <class Base>
268inline
269bool
270DynamicNodeKit<Base>::addField(SbString name, SbString typeString, SbString defaultValue)
271{
272 if (!this->isEditing){
273 return false;
274 }
275 //FIXME: check typestring
276 SoType type = SoType::fromName(typeString);
277 SoField * f = static_cast<SoField *>(type.createInstance());
278 f->setContainer(this);
279 if (defaultValue != "") f->set(defaultValue.getString());
280 this->dynamicFieldData->addField(this, name.getString(), f);
281 return true;
282}
283
284template <class Base>
285inline
286bool
287DynamicNodeKit<Base>::addPart(SbString name, SbString typeString, SbBool isDefaultNull, SbString parentName, SbString rightSiblingName, SbBool isPublic)
288{
289 if (!this->isEditing){
290 return false;
291 }
292 //FIXME: check typestring
293 SoType type = SoType::fromName(typeString);
294 this->dynamicCatalog->addEntry(name, type, type, isDefaultNull, parentName, rightSiblingName, FALSE, SoType::badType(), SoType::badType(), isPublic);
295
296 SoSFNode * f = new SoSFNode;//FIXME: support list parts, abstract parts
297 f->setContainer(this);
298 f->setValue(NULL);
299 this->dynamicFieldData->addField(this, name.getString(), f);
300 return true;
301}
302
303template <class Base>
304inline
305bool
307{
308 if (this->finished){
309 //FIXME: support more than one edit
310 return false;
311 }
312 this->isEditing = true;
313 return true;
314}
315
316template <class Base>
317inline
318bool
320{
321 if (!this->isEditing || this->finished){
322 return false;
323 }
324
325 this->createFieldList();//adds all entries from catalog to SoBaseKit::pimpl->instancelist
326 this->createDefaultParts();//instantiates all the parts that are not null by default
327
328 this->isEditing = false;
329 this->finished = true;
330 return true;
331}
332
333template <class Base>
334inline
335bool
336DynamicNodeKit<Base>::setNodekitDescription(SbString xmlDescription)
337{
338 if (this->finished || this->isEditing){
339 return false;
340 }
341 //FIXME: check xml against a dtd or similar
342 cc_xml_document * xmldoc = cc_xml_read_buffer(xmlDescription.getString());
343
344 cc_xml_element * root = cc_xml_doc_get_root(xmldoc);
345 if (strcmp(cc_xml_elt_get_type(root), "DynamicNodeKitDescription")){
346 return false;
347 }
348
349 this->startEditing();
350
351 int numFields = cc_xml_elt_get_num_children_of_type(root, "Field");
352 for (int i = 0; i < numFields; i++){
353 cc_xml_element * fieldElement = cc_xml_elt_get_child_of_type(root, "Field", i);
354 const char * name = cc_xml_attr_get_value(cc_xml_elt_get_attribute(fieldElement, "name"));
355 const char * type = cc_xml_attr_get_value(cc_xml_elt_get_attribute(fieldElement, "type"));
356 const char * value = cc_xml_elt_get_cdata(fieldElement);
357 this->addField(name, type, value);
358 }
359
360 this->addPartsFromXml(root, "this", "");
361 this->finishEditing();
362
363 cc_xml_doc_delete_x(xmldoc);//should free up everything cc_xml has allocated
364 return true;
365}
366
367template <class Base>
368inline
369bool
370DynamicNodeKit<Base>::addPartsFromXml(cc_xml_element * element, const char * parentName, const char * rightSiblingName)
371{
372 const char * name = parentName;
373 if (!strcmp(cc_xml_elt_get_type(element), "Part")){//true except for first call
374 name = cc_xml_attr_get_value(cc_xml_elt_get_attribute(element, "name"));
375 const char * type = cc_xml_attr_get_value(cc_xml_elt_get_attribute(element, "type"));
376 cc_xml_attribute * isDefaultNullAttr = cc_xml_elt_get_attribute(element, "isNullByDefault");
377 const char * isDefaultNull = isDefaultNullAttr ? cc_xml_attr_get_value(isDefaultNullAttr) : "false";
378 cc_xml_attribute * isPublicAttr = cc_xml_elt_get_attribute(element, "isPublic");
379 const char * isPublic = isPublicAttr ? cc_xml_attr_get_value(isPublicAttr) : "false";
380 this->addPart(name, type, strcmp(isDefaultNull, "false"), parentName, rightSiblingName, strcmp(isPublic, "false"));
381 }
382
383 int numChildren = cc_xml_elt_get_num_children_of_type(element, "Part");
384 for (int i = 0; i < numChildren; i++){
385 cc_xml_element * partElement = cc_xml_elt_get_child_of_type(element, "Part", i);
386 const char * nextSiblingName = "";
387 if (i < numChildren - 1){
388 cc_xml_element * siblingElement = cc_xml_elt_get_child_of_type(element, "Part", i + 1);
389 nextSiblingName = cc_xml_attr_get_value(cc_xml_elt_get_attribute(siblingElement, "name"));
390 }
391 this->addPartsFromXml(partElement, name, nextSiblingName);//recurse
392 }
393 return true;
394}
395
396
397template <class Base>
398inline
399SoNode *
400DynamicNodeKit<Base>::getAnyPart(const SbName & partname, SbBool makeifneeded, SbBool leafcheck, SbBool publiccheck)
401{
402 return inherited::getAnyPart(partname, makeifneeded, leafcheck, publiccheck);
403}
404
405template <class Base>
406inline
407SbBool
408DynamicNodeKit<Base>::setAnyPart(const SbName & partname, SoNode * from, SbBool anypart)
409{
410 return inherited::setAnyPart(partname, from, anypart);
411}
412
413#endif //SMALLCHANGE_INTERNAL
414
415#endif // DynamicNodeKit_H
Definition DynamicNodeKit.h:21