Coin Logo Coin3D is Free Software,
published under the BSD 3-clause license.
https://bitbucket.org/Coin3D/
http://www.kongsberg.com/kogt/
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
DynamicNodeKit.h
Go to the documentation of this file.
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 
16 class SoNodekitCatalog;
17 class SoFieldData;
18 struct cc_xml_elt;
19 
20 template <class Base>
21 class DynamicNodeKit : public Base {
22  typedef Base inherited;
23 
24  /*
25  Misc stuff from the coin init macros:
26  */
27 public:
28  static SoType getClassTypeId(void);
29  virtual SoType getTypeId(void) const;
30  static const SoNodekitCatalog * getClassNodekitCatalog(void);
31  virtual const SoNodekitCatalog * getNodekitCatalog(void) const;
32 protected:
33  static const SoFieldData ** getFieldDataPtr(void);
34  virtual const SoFieldData * getFieldData(void) const;
35  static const SoNodekitCatalog ** getClassNodekitCatalogPtr(void);
36 private:
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  */
50 public:
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 
65 protected:
66  virtual ~DynamicNodeKit();
67 
68 private:
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 /*
79 End class definition, start template method implementation
80 */
81 
82 //only compile when instanciating with new types
83 #ifndef DYNAMIC_NODEKIT_NO_GENERATE_FUNCTIONS
85 template <class Base> const SoFieldData ** DynamicNodeKit<Base>::parentFieldData = NULL;
86 template <class Base> SoFieldData * DynamicNodeKit<Base>::fieldData = NULL;
87 template <class Base> unsigned int DynamicNodeKit<Base>::classinstances = 0;
88 template <class Base> SoNodekitCatalog * DynamicNodeKit<Base>::classcatalog = NULL;
89 template <class Base> const SoNodekitCatalog ** DynamicNodeKit<Base>::parentcatalogptr = NULL;
90 
91 template <class Base>
92 inline
93 const SoNodekitCatalog *
95 {
97 }
98 
99 template <class Base>
100 inline
101 const SoNodekitCatalog **
103 {
104  return const_cast<const class SoNodekitCatalog **>(&DynamicNodeKit<Base>::classcatalog);
105 }
106 
107 template <class Base>
108 inline
109 void
111 {
115 }
116 
117 template <class Base>
118 inline
119 SoType
122 }
123 
124 template <class Base>
125 inline
126 SoType
129 }
130 
131 template <class Base>
132 inline
133 const SoFieldData **
135 {
136  return const_cast<const SoFieldData **>(&DynamicNodeKit<Base>::fieldData);
137 }
138 
139 template <class Base>
140 inline
141 void
143 {
150 }
151 
152 template <class Base>
153 inline
154 void *
156 {
157  return new DynamicNodeKit<Base>;
158 }
159 
160 //End default implementations
161 
162 //overloaded:
163 template <class Base>
164 inline
165 const SoFieldData *
167 {
168  return dynamicFieldData;
169 }
170 
171 // overloaded:
172 template <class Base>
173 inline
174 const SoNodekitCatalog *
176 {
177  return this->dynamicCatalog;
178 }
179 
180 template <class Base>
181 inline
182 void
184 {
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,
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 */
207 
208  DynamicNodeKit<Base>::parentcatalogptr = Base::getClassNodekitCatalogPtr();
209  }
210 }
211 
212 template <class Base>
213 inline
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 
228 template <class Base>
229 inline
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 
244 template <class Base>
245 inline
246 void
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 
267 template <class Base>
268 inline
269 bool
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 
284 template <class Base>
285 inline
286 bool
287 DynamicNodeKit<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 
303 template <class Base>
304 inline
305 bool
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 
316 template <class Base>
317 inline
318 bool
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();//instanciates all the parts that are not null by default
327 
328  this->isEditing = false;
329  this->finished = true;
330  return true;
331 }
332 
333 template <class Base>
334 inline
335 bool
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 
367 template <class Base>
368 inline
369 bool
370 DynamicNodeKit<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 
397 template <class Base>
398 inline
399 SoNode *
400 DynamicNodeKit<Base>::getAnyPart(const SbName & partname, SbBool makeifneeded, SbBool leafcheck, SbBool publiccheck)
401 {
402  return inherited::getAnyPart(partname, makeifneeded, leafcheck, publiccheck);
403 }
404 
405 template <class Base>
406 inline
407 SbBool
408 DynamicNodeKit<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
static SoType fromName(const SbName name)
SoType DynamicNodeKit< Base >::classTypeId STATIC_SOTYPE_INIT
Definition: DynamicNodeKit.h:84
SbBool set(const char *valuestring)
void * createInstance(void) const
static const SoNodekitCatalog * getClassNodekitCatalog(void)
Definition: DynamicNodeKit.h:94
DynamicNodeKit(void)
Definition: DynamicNodeKit.h:214
bool startEditing()
Definition: DynamicNodeKit.h:306
virtual const SoFieldData * getFieldData(void) const
Definition: DynamicNodeKit.h:166
static const SoFieldData ** getFieldDataPtr(void)
Definition: DynamicNodeKit.h:134
void copy(const SoFieldData *src)
int getNumFields(void) const
const char * getString(void) const
virtual SbBool setAnyPart(const SbName &partname, SoNode *from, SbBool anypart=1)
Definition: DynamicNodeKit.h:408
bool addPart(SbString name, SbString typeString, SbBool isDefaultNull, SbString parentName, SbString rightSiblingName, SbBool isPublic)
Definition: DynamicNodeKit.h:287
virtual void copyContents(const SoFieldContainer *from, SbBool copyconn)
Definition: DynamicNodeKit.h:247
virtual const SoFieldData * getFieldData(void) const
virtual const SoNodekitCatalog * getNodekitCatalog(void) const
Definition: DynamicNodeKit.h:175
void cc_coin_atexit_static_internal(coin_atexit_f *fp)
static SoType badType(void)
bool finishEditing()
Definition: DynamicNodeKit.h:319
SbBool isOfType(SoType type) const
static const SoType createType(const SoType parent, const SbName name, const instantiationMethod method=NULL, const uint16_t data=0)
void setContainer(SoFieldContainer *cont)
static void initClass(void)
Definition: DynamicNodeKit.h:183
static void incNextActionMethodIndex(void)
virtual SoType getTypeId(void) const=0
void cc_xml_doc_delete_x(cc_xml_doc *doc)
int getFieldType(void) const
SbName getName(void) const
static SoType getClassTypeId(void)
Definition: DynamicNodeKit.h:120
static const SoNodekitCatalog ** getClassNodekitCatalogPtr(void)
Definition: DynamicNodeKit.h:102
virtual ~DynamicNodeKit()
Definition: DynamicNodeKit.h:230
static SbBool removeType(const SbName &name)
SoNodekitCatalog * clone(SoType type) const
virtual SoNode * getAnyPart(const SbName &partname, SbBool makeifneeded, SbBool leafcheck=0, SbBool publiccheck=0)
Definition: DynamicNodeKit.h:400
static SoType getClassTypeId(void)
Definition: DynamicNodeKit.h:21
int getNumEntries(void) const
static int getNextActionMethodIndex(void)
void setFieldType(int type)
virtual SoType getTypeId(void) const
Definition: DynamicNodeKit.h:127
bool setNodekitDescription(SbString xmlDescription)
Definition: DynamicNodeKit.h:336
bool addField(SbString name, SbString typeString, SbString defaultValue)
Definition: DynamicNodeKit.h:270