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 <state> 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 <state> 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 <state> element.
593 */
594
595 /*!
596 Sets the XML 'initial' attribute for the SCXML <state> element.
597 If this value is set, the state should not contain an <initial>
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 <state> 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