1 /**************************************************************************\
2  * Copyright (c) Kongsberg Oil & Gas Technologies AS
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * Redistributions of source code must retain the above copyright notice,
10  * this list of conditions and the following disclaimer.
11  *
12  * Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in the
14  * documentation and/or other materials provided with the distribution.
15  *
16  * Neither the name of the copyright holder nor the names of its
17  * contributors may be used to endorse or promote products derived from
18  * this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 \**************************************************************************/
32 
33 #include <Inventor/scxml/ScXMLStateElt.h>
34 
35 /*!
36   \class ScXMLStateElt ScXMLStateElt.h Inventor/scxml/ScXMLStateElt.h
37   \brief implements the &lt;state&gt; SCXML element.
38 
39   \since Coin 3.0
40   \ingroup scxml
41 */
42 
43 #include <cassert>
44 #include <cstring>
45 #include <algorithm>
46 #include <vector>
47 
48 #include <boost/scoped_ptr.hpp>
49 
50 #include <Inventor/errors/SoDebugError.h>
51 #include <Inventor/C/tidbits.h>
52 #include <Inventor/C/XML/element.h>
53 #include <Inventor/scxml/ScXML.h>
54 #include <Inventor/scxml/ScXMLDocument.h>
55 #include <Inventor/scxml/ScXMLInvokeElt.h>
56 #include <Inventor/scxml/ScXMLParallelElt.h>
57 #include <Inventor/scxml/ScXMLOnExitElt.h>
58 #include <Inventor/scxml/ScXMLOnEntryElt.h>
59 #include <Inventor/scxml/ScXMLTransitionElt.h>
60 #include <Inventor/scxml/ScXMLInitialElt.h>
61 #include <Inventor/scxml/ScXMLFinalElt.h>
62 #include <Inventor/scxml/ScXMLHistoryElt.h>
63 #include <Inventor/scxml/ScXMLAnchorElt.h>
64 #include <Inventor/scxml/ScXMLDataModelElt.h>
65 #include <Inventor/scxml/ScXMLScxmlElt.h>
66 
67 #include "scxml/ScXMLCommonP.h"
68 
69 #ifndef COIN_WORKAROUND_NO_USING_STD_FUNCS
70 using std::strcmp;
71 using std::strcpy;
72 using std::strlen;
73 #endif // !COIN_WORKAROUND_NO_USING_STD_FUNCS
74 
75 // *************************************************************************
76 
77 class ScXMLStateEltReader : public ScXMLEltReader {
78 public:
79   ScXMLStateEltReader(void);
80   virtual ScXMLElt * read(ScXMLElt * container, cc_xml_elt * xmlelt, ScXMLDocument * doc, ScXMLStateMachine * sm);
81 };
82 
ScXMLStateEltReader(void)83 ScXMLStateEltReader::ScXMLStateEltReader(void)
84 : ScXMLEltReader("state")
85 {
86 }
87 
88 namespace { namespace ScXMLStateNS {
89 
90 template <class Type>
91 Type *
clone(Type * objptr)92 clone(Type * objptr)
93 {
94   return coin_assert_cast<Type *>(objptr->clone());
95 }
96 
97 } }
98 
99 ScXMLElt *
read(ScXMLElt * container,cc_xml_elt * xmlelt,ScXMLDocument * doc,ScXMLStateMachine * sm)100 ScXMLStateEltReader::read(ScXMLElt * container, cc_xml_elt * xmlelt, ScXMLDocument * doc, ScXMLStateMachine * sm)
101 {
102   assert(container && xmlelt);
103 
104   ScXMLStateElt * state = new ScXMLStateElt;
105   state->setContainer(container);
106   this->setXMLAttributes(state, xmlelt);
107 
108   // handle XML attributes
109   if (unlikely(!state->handleXMLAttributes())) {
110     SoDebugError::post("ScXMLStateEltReader::read",
111                        "invalid XML attributes");
112     delete state;
113     return NULL;
114   }
115 
116   // handle external reference
117   const char * extref = state->getSrcAttribute();
118   if ((extref != NULL) && (extref[0] != '\0')) {
119     SbString reference(extref);
120     char * eltnameref = const_cast<char *>(strchr(reference.getString(), '#'));
121     if (eltnameref) {
122       eltnameref[0] = '\0';
123       ++eltnameref;
124     }
125     ScXMLDocument * refdoc = ScXMLDocument::readFile(reference.getString());
126     if (refdoc) {
127       ScXMLElt * parentelt = refdoc->getRoot();
128       if (eltnameref) {
129         parentelt = refdoc->getStateById(SbName(eltnameref));
130       }
131       if (parentelt) {
132         if (parentelt->isOfType(ScXMLScxmlElt::getClassTypeId())) {
133           ScXMLScxmlElt * parent =
134             coin_assert_cast<ScXMLScxmlElt *>(parentelt);
135           int c = 0;
136 #if 0
137           if (parent->getInitial()) {
138             ScXMLInitialElt * initialelt =
139               coin_assert_cast<ScXMLInitialElt *>(parent->getInitial()->clone());
140             state->setInitial(initialelt);
141           }
142 #endif
143           for (c = 0; c < parent->getNumStates(); ++c) {
144             ScXMLStateElt * stateelt = ::ScXMLStateNS::clone(parent->getState(c));
145 //            coin_assert_cast<ScXMLStateElt *>(parent->getState(c)->clone());
146             state->addState(stateelt);
147           }
148           for (c = 0; c < parent->getNumParallels(); ++c) {
149             ScXMLParallelElt * parallelelt =
150               coin_assert_cast<ScXMLParallelElt *>(parent->getParallel(c)->clone());
151             state->addParallel(parallelelt);
152           }
153           for (c = 0; c < parent->getNumFinals(); ++c) {
154             ScXMLFinalElt * finalelt =
155               coin_assert_cast<ScXMLFinalElt *>(parent->getFinal(c)->clone());
156             state->addFinal(finalelt);
157           }
158           if (parent->getDataModel()) {
159             ScXMLDataModelElt * datamodelelt =
160               coin_assert_cast<ScXMLDataModelElt *>(parent->getDataModel()->clone());
161             state->setDataModel(datamodelelt);
162           }
163 #if 0
164           for (c = 0; c < parent->getNumScripts(); ++c) {
165             ScXMLScriptElt * scriptelt =
166               coin_assert_cast<ScXMLScriptElt *>(parent->getScript(c)->clone());
167             state->addScript(scriptelt);
168           }
169 #endif
170         }
171         else if (parentelt->isOfType(ScXMLStateElt::getClassTypeId())) {
172           ScXMLStateElt * parent =
173             coin_assert_cast<ScXMLStateElt *>(parentelt);
174           int c = 0;
175           if (parent->getOnEntry()) {
176             ScXMLOnEntryElt * onentryelt =
177               coin_assert_cast<ScXMLOnEntryElt *>(parent->getOnEntry()->clone());
178             state->setOnEntry(onentryelt);
179           }
180           if (parent->getOnExit()) {
181             ScXMLOnExitElt * onexitelt =
182               coin_assert_cast<ScXMLOnExitElt *>(parent->getOnExit()->clone());
183             state->setOnExit(onexitelt);
184           }
185           for (c = 0; c < parent->getNumTransitions(); ++c) {
186             ScXMLTransitionElt * transitionelt =
187               coin_assert_cast<ScXMLTransitionElt *>(parent->getTransition(c)->clone());
188             state->addTransition(transitionelt);
189           }
190 #if 0
191           if (parent->getInitial()) {
192             ScXMLInitialElt * initialelt =
193               coin_assert_cast<ScXMLInitialElt *>(parent->getInitial()->clone());
194             state->setInitial(initialelt);
195           }
196 #endif
197           for (c = 0; c < parent->getNumStates(); ++c) {
198             ScXMLStateElt * stateelt =
199               coin_assert_cast<ScXMLStateElt *>(parent->getState(c)->clone());
200             state->addState(stateelt);
201           }
202           for (c = 0; c < parent->getNumParallels(); ++c) {
203             ScXMLParallelElt * parallelelt =
204               coin_assert_cast<ScXMLParallelElt *>(parent->getParallel(c)->clone());
205             state->addParallel(parallelelt);
206           }
207           for (c = 0; c < parent->getNumFinals(); ++c) {
208             ScXMLFinalElt * finalelt =
209               coin_assert_cast<ScXMLFinalElt *>(parent->getFinal(c)->clone());
210             state->addFinal(finalelt);
211           }
212           for (c = 0; c < parent->getNumHistories(); ++c) {
213             ScXMLHistoryElt * historyelt =
214               coin_assert_cast<ScXMLHistoryElt *>(parent->getHistory(c)->clone());
215             state->addHistory(historyelt);
216           }
217           for (c = 0; c < parent->getNumAnchors(); ++c) {
218             ScXMLAnchorElt * anchorelt =
219               coin_assert_cast<ScXMLAnchorElt *>(parent->getAnchor(c)->clone());
220             state->addAnchor(anchorelt);
221           }
222           if (parent->getDataModel()) {
223             ScXMLDataModelElt * datamodelelt =
224               coin_assert_cast<ScXMLDataModelElt *>(parent->getDataModel()->clone());
225             state->setDataModel(datamodelelt);
226           }
227         }
228         else if (parentelt->isOfType(ScXMLParallelElt::getClassTypeId())) {
229           ScXMLParallelElt * parent =
230             coin_assert_cast<ScXMLParallelElt *>(parentelt);
231           int c = 0;
232           if (parent->getOnEntry()) {
233             ScXMLOnEntryElt * onentryelt =
234               coin_assert_cast<ScXMLOnEntryElt *>(parent->getOnEntry()->clone());
235             state->setOnEntry(onentryelt);
236           }
237           if (parent->getOnExit()) {
238             ScXMLOnExitElt * onexitelt =
239               coin_assert_cast<ScXMLOnExitElt *>(parent->getOnExit()->clone());
240             state->setOnExit(onexitelt);
241           }
242           for (c = 0; c < parent->getNumTransitions(); ++c) {
243             ScXMLTransitionElt * transitionelt =
244               coin_assert_cast<ScXMLTransitionElt *>(parent->getTransition(c)->clone());
245             state->addTransition(transitionelt);
246           }
247 #if 0
248           if (parent->getInitial()) {
249             ScXMLInitialElt * initialelt =
250               coin_assert_cast<ScXMLInitialElt *>(parent->getInitial()->clone());
251             state->setInitial(initialelt);
252           }
253 #endif
254           for (c = 0; c < parent->getNumStates(); ++c) {
255             ScXMLStateElt * stateelt =
256               coin_assert_cast<ScXMLStateElt *>(parent->getState(c)->clone());
257             state->addState(stateelt);
258           }
259           for (c = 0; c < parent->getNumParallels(); ++c) {
260             ScXMLParallelElt * parallelelt =
261               coin_assert_cast<ScXMLParallelElt *>(parent->getParallel(c)->clone());
262             state->addParallel(parallelelt);
263           }
264           for (c = 0; c < parent->getNumFinals(); ++c) {
265             ScXMLFinalElt * finalelt =
266               coin_assert_cast<ScXMLFinalElt *>(parent->getFinal(c)->clone());
267             state->addFinal(finalelt);
268           }
269           for (c = 0; c < parent->getNumHistories(); ++c) {
270             ScXMLHistoryElt * historyelt =
271               coin_assert_cast<ScXMLHistoryElt *>(parent->getHistory(c)->clone());
272             state->addHistory(historyelt);
273           }
274           for (c = 0; c < parent->getNumAnchors(); ++c) {
275             ScXMLAnchorElt * anchorelt =
276               coin_assert_cast<ScXMLAnchorElt *>(parent->getAnchor(c)->clone());
277             state->addAnchor(anchorelt);
278           }
279           if (parent->getDataModel()) {
280             ScXMLDataModelElt * datamodelelt =
281               coin_assert_cast<ScXMLDataModelElt *>(parent->getDataModel()->clone());
282             state->setDataModel(datamodelelt);
283           }
284         }
285         else if (parentelt->isOfType(ScXMLFinalElt::getClassTypeId())) {
286           // huh?
287         }
288       }
289       delete refdoc;
290     }
291   }
292 
293   // read in all children, and recurse down
294   const int numchildren = cc_xml_elt_get_num_children(xmlelt);
295   for (int c = 0; c < numchildren; ++c) {
296     cc_xml_elt * element = cc_xml_elt_get_child(xmlelt, c);
297     const char * elementtype = cc_xml_elt_get_type(element);
298 
299     if (strcmp(elementtype, COIN_XML_CDATA_TYPE) == 0) {
300       // ignore CDATA
301       continue;
302     }
303 
304     if (strcmp(elementtype, "state") == 0) {
305       // <state> - zero or more times
306       ScXMLEltReader * statereader = ScXMLStateElt::getElementReader();
307       assert(statereader);
308       ScXMLElt * stateobj = statereader->read(state, element, doc, sm);
309       if (unlikely(!stateobj)) {
310         delete state;
311         return NULL;
312       }
313 
314       assert(stateobj->isOfType(ScXMLStateElt::getClassTypeId()));
315       state->addState(static_cast<ScXMLStateElt *>(stateobj));
316     }
317 
318     else if (strcmp(elementtype, "onentry") == 0) {
319       // <onentry> - zero or one time
320       if (unlikely(state->getOnEntry())) {
321         SoDebugError::post("ScXMLStateEltReader::read",
322                            "<state> elements can only contain one <onentry> element");
323         delete state;
324         return NULL;
325       }
326 
327       ScXMLEltReader * onentryreader = ScXMLOnEntryElt::getElementReader();
328       assert(onentryreader);
329       ScXMLElt * onentryobj = onentryreader->read(state, element, doc, sm);
330       if (unlikely(!onentryobj)) {
331         delete state;
332         return NULL;
333       }
334 
335       assert(onentryobj->isOfType(ScXMLOnEntryElt::getClassTypeId()));
336       state->setOnEntry(static_cast<ScXMLOnEntryElt *>(onentryobj));
337     }
338 
339     else if (strcmp(elementtype, "onexit") == 0) {
340       // <onexit> - zero or one time
341       if (unlikely(state->getOnExit())) {
342         SoDebugError::post("ScXMLStateEltReader::read",
343                            "<state> elements can only contain one <onexit> element");
344         delete state;
345         return NULL;
346       }
347 
348       ScXMLEltReader * onexitreader = ScXMLOnExitElt::getElementReader();
349       assert(onexitreader);
350       ScXMLElt * onexitobj = onexitreader->read(state, element, doc, sm);
351       if (unlikely(!onexitobj)) {
352         delete state;
353         return NULL;
354       }
355 
356       assert(onexitobj->isOfType(ScXMLOnExitElt::getClassTypeId()));
357       state->setOnExit(static_cast<ScXMLOnExitElt *>(onexitobj));
358     }
359 
360     else if (strcmp(elementtype, "transition") == 0) {
361       // <transition> - zero or more times
362       ScXMLEltReader * transitionreader = ScXMLTransitionElt::getElementReader();
363       assert(transitionreader);
364       ScXMLElt * transitionobj = transitionreader->read(state, element, doc, sm);
365       if (unlikely(!transitionobj)) {
366         delete state;
367         return NULL;
368       }
369 
370       assert(transitionobj->isOfType(ScXMLTransitionElt::getClassTypeId()));
371       state->addTransition(static_cast<ScXMLTransitionElt *>(transitionobj));
372     }
373 
374     else if (strcmp(elementtype, "initial") == 0) {
375       // <initial> - must occur iff states+parallels >= 1
376       // or if initial attribute is not set
377       ScXMLEltReader * initialreader = ScXMLInitialElt::getElementReader();
378       assert(initialreader);
379       ScXMLElt * initialobj = initialreader->read(state, element, doc, sm);
380       if (unlikely(!initialobj)) {
381         delete state;
382         return NULL;
383       }
384 
385       assert(initialobj->isOfType(ScXMLInitialElt::getClassTypeId()));
386       state->setInitial(static_cast<ScXMLInitialElt *>(initialobj));
387     }
388 
389     else if (strcmp(elementtype, "parallel") == 0) {
390       // <parallel> - zero or more times
391       ScXMLEltReader * parallelreader = ScXMLParallelElt::getElementReader();
392       assert(parallelreader);
393       ScXMLElt * parallelobj = parallelreader->read(state, element, doc, sm);
394       if (unlikely(!parallelobj)) {
395         delete state;
396         return NULL;
397       }
398 
399       assert(parallelobj->isOfType(ScXMLParallelElt::getClassTypeId()));
400       state->addParallel(static_cast<ScXMLParallelElt *>(parallelobj));
401     }
402 
403     else if (strcmp(elementtype, "final") == 0) {
404       // <final> - zero or more times
405       ScXMLEltReader * finalreader = ScXMLFinalElt::getElementReader();
406       assert(finalreader);
407       ScXMLElt * finalobj = finalreader->read(state, element, doc, sm);
408       if (unlikely(!finalobj)) {
409         delete state;
410         return NULL;
411       }
412 
413       assert(finalobj->isOfType(ScXMLFinalElt::getClassTypeId()));
414       state->addFinal(static_cast<ScXMLFinalElt *>(finalobj));
415     }
416 
417     else if (strcmp(elementtype, "history") == 0) {
418       // <history> - zero or more times
419       ScXMLEltReader * historyreader = ScXMLHistoryElt::getElementReader();
420       assert(historyreader);
421       ScXMLElt * historyobj = historyreader->read(state, element, doc, sm);
422       if (unlikely(!historyobj)) {
423         delete state;
424         return NULL;
425       }
426 
427       assert(historyobj->isOfType(ScXMLHistoryElt::getClassTypeId()));
428       state->addHistory(static_cast<ScXMLHistoryElt *>(historyobj));
429     }
430 
431     else if (strcmp(elementtype, "anchor") == 0) {
432       // <anchor> - zero or more times
433       ScXMLEltReader * anchorreader = ScXMLAnchorElt::getElementReader();
434       assert(anchorreader);
435       ScXMLElt * anchorobj = anchorreader->read(state, element, doc, sm);
436       if (unlikely(!anchorobj)) {
437         delete state;
438         return NULL;
439       }
440 
441       assert(anchorobj->isOfType(ScXMLAnchorElt::getClassTypeId()));
442       state->addAnchor(static_cast<ScXMLAnchorElt *>(anchorobj));
443     }
444 
445     else if (strcmp(elementtype, "datamodel") == 0) {
446       // <datamodel> - zero or one time
447       if (unlikely(state->getDataModel())) {
448         SoDebugError::post("ScXMLStateEltReader::read",
449                            "<state> elements can only contain one <datamodel> element");
450         delete state;
451         return NULL;
452       }
453 
454       ScXMLEltReader * datamodelreader = ScXMLDataModelElt::getElementReader();
455       assert(datamodelreader);
456       ScXMLElt * datamodelobj = datamodelreader->read(state, element, doc, sm);
457       if (unlikely(!datamodelobj)) {
458         delete state;
459         return NULL;
460       }
461 
462       assert(datamodelobj->isOfType(ScXMLDataModelElt::getClassTypeId()));
463       state->setDataModel(static_cast<ScXMLDataModelElt *>(datamodelobj));
464     }
465 
466 #if 0
467     // <invoke> - one time iff states+parallel == 0
468     else if (strcmp(elementtype, "invoke") == 0) {
469       ScXMLObject * invokeobj = ScXMLP::readScXMLInvokeElt(state, element, xmlns);
470       if (invokeobj) {
471         assert(invokeobj->isOfType(ScXMLInvokeElt::getClassTypeId()));
472         state->addInvoke(static_cast<ScXMLInvokeElt *>(invokeobj));
473       } else {
474         SoDebugError::post("ScXML::readFile", "error reading <%s> element", elementtype);
475         delete state;
476         return NULL;
477       }
478     }
479 #endif
480     else {
481       SoDebugError::post("ScXMLStateEltReader::read",
482                          "unexpected XML element '<%s>' found in <state>",
483                          elementtype);
484       delete state;
485       return NULL;
486     }
487   }
488   return state;
489 }
490 
491 // *************************************************************************
492 
493 class ScXMLStateElt::PImpl {
494 public:
PImpl(void)495   PImpl(void)
496   : onentryptr(NULL),
497     onexitptr(NULL),
498     initialptr(NULL),
499     datamodelptr(NULL),
500     invokeptr(NULL)
501     //srcref(NULL)
502   {
503   }
504 
~PImpl(void)505   ~PImpl(void)
506   {
507     SCXML__CLEAR_STD_VECTOR(this->transitionlist, ScXMLTransitionElt *);
508     SCXML__CLEAR_STD_VECTOR(this->statelist, ScXMLStateElt *);
509     SCXML__CLEAR_STD_VECTOR(this->parallellist, ScXMLParallelElt *);
510     SCXML__CLEAR_STD_VECTOR(this->finallist, ScXMLFinalElt *);
511     SCXML__CLEAR_STD_VECTOR(this->historylist, ScXMLHistoryElt *);
512     SCXML__CLEAR_STD_VECTOR(this->anchorlist, ScXMLAnchorElt *);
513   }
514 
515   boost::scoped_ptr<ScXMLOnEntryElt> onentryptr;
516   boost::scoped_ptr<ScXMLOnExitElt> onexitptr;
517   std::vector<ScXMLTransitionElt *> transitionlist;
518   boost::scoped_ptr<ScXMLInitialElt> initialptr;
519   std::vector<ScXMLStateElt *> statelist;
520   std::vector<ScXMLParallelElt *> parallellist;
521   std::vector<ScXMLFinalElt *> finallist;
522   std::vector<ScXMLHistoryElt *> historylist;
523   std::vector<ScXMLAnchorElt *> anchorlist;
524   boost::scoped_ptr<ScXMLDataModelElt> datamodelptr;
525   boost::scoped_ptr<ScXMLInvokeElt> invokeptr;
526   //boost::scoped_ptr<ScXMLDocument> srcref;
527 };
528 
529 #define PRIVATE(obj) ((obj)->pimpl)
530 
531 SCXML_ELEMENT_SOURCE(ScXMLStateElt);
532 
533 /*!
534 */
535 void
initClass(void)536 ScXMLStateElt::initClass(void)
537 {
538   SCXML_OBJECT_INIT_CLASS(ScXMLStateElt, ScXMLAbstractStateElt, "ScXMLAbstractStateElt");
539   SCXML_ELEMENT_REGISTER_READER(ScXMLStateElt, "state", ScXMLStateEltReader);
540 }
541 
542 /*!
543 */
544 void
cleanClass(void)545 ScXMLStateElt::cleanClass(void)
546 {
547   SCXML_ELEMENT_UNREGISTER_READER(ScXMLStateElt);
548   ScXMLStateElt::classTypeId = SoType::badType();
549 }
550 
551 /*!
552   Constructor.
553 */
ScXMLStateElt(void)554 ScXMLStateElt::ScXMLStateElt(void)
555 : src(NULL),
556   initial(NULL)
557 {
558 }
559 
560 /*!
561   Destructor.
562 */
~ScXMLStateElt(void)563 ScXMLStateElt::~ScXMLStateElt(void)
564 {
565   this->setSrcAttribute(NULL);
566   this->setInitialAttribute(NULL);
567 }
568 
569 /*!
570   Sets the XML 'src' attribute for the SCXML &lt;state&gt; element.
571   To get the attribute value intepreted and taken action upon, you will
572   also need to [FIXME]
573 */
574 void
setSrcAttribute(const char * srcstr)575 ScXMLStateElt::setSrcAttribute(const char * srcstr)
576 {
577   if (this->src && strcmp(this->src, "") != 0) {
578     // FIXME: remove externally sources states?
579   }
580 
581   SCXML__SET_ATTRIBUTE_VALUE(this->src, "src", srcstr);
582 
583   if ((this->src != NULL) && (strcmp(this->src, "") != 0)) {
584     // FIXME: scan string for #
585     // FIXME: load/import [externally] referenced states
586   }
587 }
588 
589 /*!
590   \fn const char * ScXMLStateElt::getSrcAttribute(void) const
591 
592   Returns the XML 'src' attribute for this SCXML &lt;state&gt; element.
593 */
594 
595 /*!
596   Sets the XML 'initial' attribute for the SCXML &lt;state&gt; element.
597   If this value is set, the state should not contain an &lt;initial&gt;
598   element, and vice versa.
599 
600   When set, this value must be the value of a descendant an identifier for
601   a child state.
602 
603   \sa ScXMLInitialElt
604 */
605 void
setInitialAttribute(const char * initialstr)606 ScXMLStateElt::setInitialAttribute(const char * initialstr)
607 {
608   SCXML__SET_ATTRIBUTE_VALUE(this->initial, "initial", initialstr);
609 }
610 
611 /*!
612   \fn const char * ScXMLStateElt::getInitialAttribute(void) const
613 
614   Returns the XML 'initial' attribute for the SCXML &lt;state&gt; element.
615 */
616 
617 // Doc in parent
618 SbBool
handleXMLAttributes(void)619 ScXMLStateElt::handleXMLAttributes(void)
620 {
621   if (!inherited::handleXMLAttributes()) return FALSE;
622 
623   this->setInitialAttribute(this->getXMLAttribute("initial"));
624   this->setSrcAttribute(this->getXMLAttribute("src"));
625 
626   return TRUE;
627 }
628 
629 void
copyContents(const ScXMLElt * rhs)630 ScXMLStateElt::copyContents(const ScXMLElt * rhs)
631 {
632   inherited::copyContents(rhs);
633   const ScXMLStateElt * orig = coin_assert_cast<const ScXMLStateElt *>(rhs);
634   this->setInitialAttribute(orig->getInitialAttribute());
635   this->setSrcAttribute(orig->getSrcAttribute());
636   int c = 0;
637   if (orig->getOnEntry()) {
638     ScXMLOnEntryElt * onentry =
639       coin_assert_cast<ScXMLOnEntryElt *>(orig->getOnEntry()->clone());
640     this->setOnEntry(onentry);
641   }
642   if (orig->getOnExit()) {
643     ScXMLOnExitElt * onexit =
644       coin_assert_cast<ScXMLOnExitElt *>(orig->getOnExit()->clone());
645     this->setOnExit(onexit);
646   }
647   for (c = 0; c < orig->getNumTransitions(); ++c) {
648     ScXMLTransitionElt * transition =
649       coin_assert_cast<ScXMLTransitionElt *>(orig->getTransition(c)->clone());
650     this->addTransition(transition);
651   }
652   if (orig->getInitial()) {
653     ScXMLInitialElt * initial =
654       coin_assert_cast<ScXMLInitialElt *>(orig->getInitial()->clone());
655     this->setInitial(initial);
656   }
657   for (c = 0; c < orig->getNumStates(); ++c) {
658     ScXMLStateElt * state =
659       coin_assert_cast<ScXMLStateElt *>(orig->getState(c)->clone());
660     this->addState(state);
661   }
662   for (c = 0; c < orig->getNumParallels(); ++c) {
663     ScXMLParallelElt * parallel =
664       coin_assert_cast<ScXMLParallelElt *>(orig->getParallel(c)->clone());
665     this->addParallel(parallel);
666   }
667   for (c = 0; c < orig->getNumFinals(); ++c) {
668     ScXMLFinalElt * final =
669       coin_assert_cast<ScXMLFinalElt *>(orig->getFinal(c)->clone());
670     this->addFinal(final);
671   }
672   for (c = 0; c < orig->getNumHistories(); ++c) {
673     ScXMLHistoryElt * history =
674       coin_assert_cast<ScXMLHistoryElt *>(orig->getHistory(c)->clone());
675     this->addHistory(history);
676   }
677   for (c = 0; c < orig->getNumAnchors(); ++c) {
678     ScXMLAnchorElt * anchor =
679       coin_assert_cast<ScXMLAnchorElt *>(orig->getAnchor(c)->clone());
680     this->addAnchor(anchor);
681   }
682   if (orig->getDataModel()) {
683     ScXMLDataModelElt * datamodel =
684       coin_assert_cast<ScXMLDataModelElt *>(orig->getDataModel()->clone());
685     this->setDataModel(datamodel);
686   }
687 }
688 
689 const ScXMLElt *
search(const char * attrname,const char * attrvalue) const690 ScXMLStateElt::search(const char * attrname, const char * attrvalue) const
691 {
692   const ScXMLElt * hit = inherited::search(attrname, attrvalue);
693   if (hit) {
694     return hit;
695   }
696   if (strcmp(attrname, "initial") == 0) { // 'initialstate' is dropped
697     if (this->initial && strcmp(attrvalue, this->initial) == 0) {
698       return this;
699     }
700   }
701   else if (strcmp(attrname, "src") == 0) {
702     if (this->src && strcmp(attrvalue, this->src) == 0) {
703       return this;
704     }
705   }
706 
707   if (PRIVATE(this)->onentryptr.get()) {
708     hit = PRIVATE(this)->onentryptr->search(attrname, attrvalue);
709     if (hit) {
710       return hit;
711     }
712   }
713   if (PRIVATE(this)->onexitptr.get()) {
714     hit = PRIVATE(this)->onexitptr->search(attrname, attrvalue);
715     if (hit) {
716       return hit;
717     }
718   }
719   {
720     std::vector<ScXMLTransitionElt *>::const_iterator it = PRIVATE(this)->transitionlist.begin();
721     while (it != PRIVATE(this)->transitionlist.end()) {
722       hit = (*it)->search(attrname, attrvalue);
723       if (hit) {
724         return hit;
725       }
726       ++it;
727     }
728   }
729   if (PRIVATE(this)->initialptr.get()) {
730     hit = PRIVATE(this)->initialptr->search(attrname, attrvalue);
731     if (hit) {
732       return hit;
733     }
734   }
735   {
736     std::vector<ScXMLStateElt *>::const_iterator it = PRIVATE(this)->statelist.begin();
737     while (it != PRIVATE(this)->statelist.end()) {
738       hit = (*it)->search(attrname, attrvalue);
739       if (hit) {
740         return hit;
741       }
742       ++it;
743     }
744   }
745   {
746     std::vector<ScXMLParallelElt *>::const_iterator it = PRIVATE(this)->parallellist.begin();
747     while (it != PRIVATE(this)->parallellist.end()) {
748       hit = (*it)->search(attrname, attrvalue);
749       if (hit) {
750         return hit;
751       }
752       ++it;
753     }
754   }
755   {
756     std::vector<ScXMLFinalElt *>::const_iterator it = PRIVATE(this)->finallist.begin();
757     while (it != PRIVATE(this)->finallist.end()) {
758       hit = (*it)->search(attrname, attrvalue);
759       if (hit) {
760         return hit;
761       }
762       ++it;
763     }
764   }
765   {
766     std::vector<ScXMLHistoryElt *>::const_iterator it = PRIVATE(this)->historylist.begin();
767     while (it != PRIVATE(this)->historylist.end()) {
768       hit = (*it)->search(attrname, attrvalue);
769       if (hit) {
770         return hit;
771       }
772       ++it;
773     }
774   }
775   {
776     std::vector<ScXMLAnchorElt *>::const_iterator it = PRIVATE(this)->anchorlist.begin();
777     while (it != PRIVATE(this)->anchorlist.end()) {
778       hit = (*it)->search(attrname, attrvalue);
779       if (hit) {
780         return hit;
781       }
782       ++it;
783     }
784   }
785   if (PRIVATE(this)->datamodelptr.get()) {
786     hit = PRIVATE(this)->datamodelptr->search(attrname, attrvalue);
787     if (hit) {
788       return hit;
789     }
790   }
791   return NULL;
792 }
793 
794 SCXML_SINGLE_OBJECT_API_IMPL(ScXMLStateElt, ScXMLOnEntryElt,
795                              PRIVATE(this)->onentryptr, OnEntry);
796 
797 SCXML_SINGLE_OBJECT_API_IMPL(ScXMLStateElt, ScXMLOnExitElt,
798                              PRIVATE(this)->onexitptr, OnExit);
799 
800 SCXML_LIST_OBJECT_API_IMPL(ScXMLStateElt, ScXMLTransitionElt,
801                            PRIVATE(this)->transitionlist,
802                            Transition, Transitions);
803 
804 SCXML_SINGLE_OBJECT_API_IMPL(ScXMLStateElt, ScXMLInitialElt,
805                              PRIVATE(this)->initialptr, Initial);
806 
807 SCXML_LIST_OBJECT_API_IMPL(ScXMLStateElt, ScXMLStateElt,
808                            PRIVATE(this)->statelist, State, States);
809 
810 SCXML_LIST_OBJECT_API_IMPL(ScXMLStateElt, ScXMLParallelElt,
811                            PRIVATE(this)->parallellist, Parallel, Parallels);
812 
813 SCXML_LIST_OBJECT_API_IMPL(ScXMLStateElt, ScXMLFinalElt,
814                            PRIVATE(this)->finallist, Final, Finals);
815 
816 SCXML_LIST_OBJECT_API_IMPL(ScXMLStateElt, ScXMLHistoryElt,
817                            PRIVATE(this)->historylist, History, Histories);
818 
819 SCXML_LIST_OBJECT_API_IMPL(ScXMLStateElt, ScXMLAnchorElt,
820                            PRIVATE(this)->anchorlist, Anchor, Anchors);
821 
822 SCXML_SINGLE_OBJECT_API_IMPL(ScXMLStateElt, ScXMLDataModelElt,
823                              PRIVATE(this)->datamodelptr, DataModel);
824 
825 // SCXML_SINGLE_OBJECT_API_IMPL(ScXMLStateElt, ScXMLInvokeElt, PRIVATE(this)->invokeptr, Invoke);
826 
827 /*!
828   Returns TRUE if this is an "atomic state", which means that it has no
829   sub-states but contains executable content.
830 */
831 SbBool
isAtomicState(void) const832 ScXMLStateElt::isAtomicState(void) const
833 {
834   return ((PRIVATE(this)->statelist.size() == 0) &&
835           (PRIVATE(this)->parallellist.size() == 0) &&
836           (PRIVATE(this)->invokeptr.get() != NULL));
837 }
838 
839 #undef PRIVATE
840