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 // Important note: nearly all of this sourcefile was generated by the
34 // Coin/scripts/templant script from the code in SFNodeEnginePath.tpl.
35 //
36 // Only the notify() function at the bottom of the file deviates from
37 // the templatized code of SoSF[Node|Engine|Path].
38 
39 ///////////////////////////////////////////////////////////////////////////
40 
41 //$ BEGIN TEMPLATE SFNodeEnginePath(PATH, Path, path)
42 
43 /*!
44   \class SoSFPath SoSFPath.h Inventor/fields/SoSFPath.h
45   \brief The SoSFPath class is a container for a single path.
46 
47   \ingroup fields
48 
49   This field container stores a pointer to a Coin path. It takes care
50   of the necessary functionality for handling copy, import and export
51   operations.
52 
53   Note that the path pointer stored in a field instance of this type
54   may be a \c NULL pointer.
55 
56   \sa SoPath, SoMFPath
57 
58 */
59 
60 // Type-specific define to be able to do #ifdef tests on type.  (Note:
61 // used to check the header file wrapper define, but that doesn't work
62 // with --enable-compact build.)
63 #define COIN_INTERNAL_SOSFPATH
64 
65 #include <Inventor/fields/SoSFPath.h>
66 
67 #include "coindefs.h"
68 #include "SbBasicP.h"
69 
70 #include <Inventor/SoInput.h>
71 #include <Inventor/SoOutput.h>
72 #include <Inventor/actions/SoWriteAction.h>
73 #include <Inventor/errors/SoReadError.h>
74 #include <Inventor/nodes/SoNode.h>
75 #include <Inventor/engines/SoEngine.h>
76 #include <Inventor/SoOutput.h>
77 #if COIN_DEBUG
78 #include <Inventor/errors/SoDebugError.h>
79 #endif // COIN_DEBUG
80 
81 #include "fields/SoSubFieldP.h"
82 
83 // Can't use SO_SFIELD_SOURCE() because we need to modify setValue()
84 // to ref and unref the passed path.
85 SO_SFIELD_REQUIRED_SOURCE(SoSFPath);
86 
87 
88 // Override from parent class.
89 void
initClass(void)90 SoSFPath::initClass(void)
91 {
92   SO_SFIELD_INTERNAL_INIT_CLASS(SoSFPath);
93 }
94 
95 // (Declarations hidden in SO_[S|M]FIELD_HEADER macro in header file,
96 // so don't use Doxygen commenting.)
97 #ifndef DOXYGEN_SKIP_THIS
98 
99 /* Constructor, sets initial path pointer to a \c NULL pointer. */
SoSFPath(void)100 SoSFPath::SoSFPath(void)
101 {
102   this->value = NULL;
103 #ifdef COIN_INTERNAL_SOSFPATH
104   this->head = NULL;
105 #endif // COIN_INTERNAL_SOSFPATH
106 }
107 
108 /* Destructor, dereferences the current path pointer if necessary. */
~SoSFPath(void)109 SoSFPath::~SoSFPath(void)
110 {
111   this->enableNotify(FALSE);
112   this->setValue(NULL);
113 }
114 
115 #endif // DOXYGEN_SKIP_THIS
116 
117 
118 // No need to document readValue() and writeValue() here, as the
119 // necessary information is provided by the documentation of the
120 // parent classes.
121 #ifndef DOXYGEN_SKIP_THIS
122 
123 // Store the \a newval path pointer in this field. If \a newval is not
124 // \c NULL, will add 1 to the reference count of the path.
125 void
setValue(SoPath * newval)126 SoSFPath::setValue(SoPath * newval)
127 {
128   // Don't use getValue() to find oldptr, since this might trigger a
129   // recursive evaluation call if the field is connected.
130   SoPath * oldptr = this->value;
131   if (oldptr == newval) return;
132 
133   if (oldptr) {
134 #ifdef COIN_INTERNAL_SOSFPATH
135     SoNode * h = oldptr->getHead();
136     // The path should be audited by us at all times. So don't use
137     // SoSFPath to wrap SoTempPath or SoLightPath, for instance.
138     assert(h==this->head && "Path head changed without notification!");
139     if (h) {
140       h->removeAuditor(this, SoNotRec::FIELD);
141       h->unref();
142     }
143 #endif // COIN_INTERNAL_SOSFPATH
144     oldptr->removeAuditor(this, SoNotRec::FIELD);
145     oldptr->unref();
146   }
147 
148   if (newval) {
149     newval->addAuditor(this, SoNotRec::FIELD);
150     newval->ref();
151 #ifdef COIN_INTERNAL_SOSFPATH
152     this->head = newval->getHead();
153     if (this->head) {
154       this->head->addAuditor(this, SoNotRec::FIELD);
155       this->head->ref();
156     }
157 #endif // COIN_INTERNAL_SOSFPATH
158   }
159 
160   this->value = newval;
161   this->valueChanged();
162 }
163 
164 // Compares to see if the \a field points to the same path as this
165 // field does, and returns \c TRUE if this is the case.
166 //
167 // Be aware that this method does \e not check for path/subgraph
168 // equality if the pointers are not the same, so \c FALSE is returned
169 // even though the contents of the path/subgraph are equal.
170 SbBool
operator ==(const SoSFPath & field) const171 SoSFPath::operator==(const SoSFPath & field) const
172 {
173   return (this->getValue() == field.getValue());
174 }
175 
176 // Import path.
177 SbBool
readValue(SoInput * in)178 SoSFPath::readValue(SoInput * in)
179 {
180   SoBase * baseptr;
181 
182   //Handle when the path is set to NULL
183   SbName keyword;
184   if (in)
185     if (!in->read(keyword)) return FALSE;
186 
187   if(keyword=="NULL") {
188     this->setValue(NULL);
189     return TRUE;
190   }
191   else
192   in->putBack(keyword.getString());
193 
194   if (!SoBase::read(in, baseptr, SoPath::getClassTypeId())) return FALSE;
195 
196   if (in->eof()) {
197     SoReadError::post(in, "Premature end of file");
198     return FALSE;
199   }
200   if (!baseptr) {
201     SoReadError::post(in, "Unable to read value for SoSFPath");
202     return FALSE;
203   }
204 
205   this->setValue(coin_assert_cast<SoPath *>(baseptr));
206   return TRUE;
207 }
208 
209 // Export path.
210 void
writeValue(SoOutput * out) const211 SoSFPath::writeValue(SoOutput * out) const
212 {
213   // NB: This code is common for SoSFNode, SoSFPath and SoSFEngine.
214   // That's why we check the base type before writing.
215   SoBase * base = this->getValue();
216   if (base) {
217     if (base->isOfType(SoNode::getClassTypeId())) {
218       coin_assert_cast<SoNode *>(base)->writeInstance(out);
219     }
220     else if (base->isOfType(SoPath::getClassTypeId())) {
221       SoWriteAction wa(out);
222       wa.continueToApply(coin_assert_cast<SoPath *>(base));
223     }
224     else if (base->isOfType(SoEngine::getClassTypeId())) {
225       coin_assert_cast<SoEngine *>(base)->writeInstance(out);
226     }
227     else {
228       assert(0 && "strange internal error");
229     }
230   }
231   else {
232     // This actually works for both ASCII and binary formats.
233     out->write("NULL");
234   }
235 }
236 
237 #endif // DOXYGEN_SKIP_THIS
238 
239 
240 // Overridden from parent to propagate write reference counting to
241 // path.
242 void
countWriteRefs(SoOutput * out) const243 SoSFPath::countWriteRefs(SoOutput * out) const
244 {
245   inherited::countWriteRefs(out);
246 
247   SoBase * base = this->getValue();
248   if (base == NULL) return;
249 
250   // NB: This code is common for SoSFNode, SoSFPath and SoSFEngine.
251   // That's why we check the base type before writing/counting
252 
253   if (base->isOfType(SoNode::getClassTypeId())) {
254     coin_assert_cast<SoNode *>(base)->writeInstance(out);
255   }
256   else if (base->isOfType(SoEngine::getClassTypeId())) {
257     coin_assert_cast<SoEngine *>(base)->addWriteReference(out);
258   }
259   else if (base->isOfType(SoPath::getClassTypeId())) {
260     SoWriteAction wa(out);
261     wa.continueToApply(coin_assert_cast<SoPath *>(base));
262   }
263 }
264 
265 // Override from parent to update our path pointer
266 // reference. This is necessary so we do the Right Thing with regard
267 // to the copyconnections flag.
268 //
269 // Note that we have to unplug auditing and the reference counter
270 // addition we made during the copy process.
271 //
272 // For reference for future debugging sessions, copying of this field
273 // goes like this:
274 //
275 //    - copyFrom() is called (typically from SoFieldData::overlay())
276 //    - copyFrom() calls operator=()
277 //    - operator=() calls setValue()
278 //    - we have a local copy (ie not from SoSubField.h) of setValue()
279 //      that sets up auditing and references the item
280 //
281 // <mortene@sim.no>
282 void
fixCopy(SbBool COIN_UNUSED_ARG (copyconnections))283 SoSFPath::fixCopy(SbBool COIN_UNUSED_ARG(copyconnections))
284 {
285   SoPath * n = this->getValue();
286   if (!n) return;
287 
288 #if COIN_DEBUG
289   n->assertAlive();
290 #endif // COIN_DEBUG
291 
292   // The setValue() call below will automatically de-audit and un-ref
293   // the old pointer-value reference we have, *before* re-inserting a
294   // copy.
295 
296 #if defined(COIN_INTERNAL_SOSFNODE) || defined(COIN_INTERNAL_SOSFENGINE)
297   SoFieldContainer * fc = SoFieldContainer::findCopy(n, copyconnections);
298 #if COIN_DEBUG
299   fc->assertAlive();
300 #endif // COIN_DEBUG
301   this->setValue((SoPath *)fc);
302 #endif // COIN_INTERNAL_SOSFNODE || COIN_INTERNAL_SOSFENGINE
303 
304 #ifdef COIN_INTERNAL_SOSFPATH
305   this->setValue(n->copy());
306 #endif // COIN_INTERNAL_SOSFPATH
307 }
308 
309 // Override from SoField to check path pointer.
310 SbBool
referencesCopy(void) const311 SoSFPath::referencesCopy(void) const
312 {
313   if (inherited::referencesCopy()) return TRUE;
314 
315   SoBase * n = this->getValue();
316   if (!n) return FALSE;
317 
318   if (n->isOfType(SoNode::getClassTypeId()) ||
319       n->isOfType(SoEngine::getClassTypeId())) {
320     if (SoFieldContainer::checkCopy(coin_assert_cast<SoFieldContainer *>(n))) return TRUE;
321   }
322   else if (n->isOfType(SoPath::getClassTypeId())) {
323     SoPath * p = coin_assert_cast<SoPath *>(n);
324     if (p->getHead() == NULL) return FALSE;
325     if (SoFieldContainer::checkCopy(p->getHead())) return TRUE;
326   }
327   else {
328     assert(0 && "strange internal error");
329   }
330 
331   return FALSE;
332 }
333 
334 // Kill the type-specific define.
335 #undef COIN_INTERNAL_SOSFPATH
336 //$ END TEMPLATE SFNodeEnginePath
337 
338 
339 void
notify(SoNotList * l)340 SoSFPath::notify(SoNotList * l)
341 {
342   // Detect if our path has gotten a new head :^), and if so do the
343   // necessary audit setup magic.
344   if (this->getValue() && this->getValue()->getHead() != this->head) {
345     if (this->head) {
346       this->head->removeAuditor(this, SoNotRec::FIELD);
347       this->head->unref();
348     }
349     this->head = this->getValue()->getHead();
350     if (this->head) {
351       this->head->addAuditor(this, SoNotRec::FIELD);
352       this->head->ref();
353     }
354   }
355 
356   inherited::notify(l);
357 }
358 
359 
360 #ifdef COIN_TEST_SUITE
361 
BOOST_AUTO_TEST_CASE(initialized)362 BOOST_AUTO_TEST_CASE(initialized)
363 {
364   SoSFPath field;
365   BOOST_CHECK_MESSAGE(SoSFPath::getClassTypeId() != SoType::badType(),
366                       "SoSFPath class not initialized");
367   BOOST_CHECK_MESSAGE(field.getTypeId() != SoType::badType(),
368                       "missing class initialization");
369 }
370 
371 #endif // COIN_TEST_SUITE
372