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 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif // HAVE_CONFIG_H
36 
37 #ifdef HAVE_NODEKITS
38 
39 /*!
40   \class SoNodeKitPath SoNodeKitPath.h Inventor/SoNodeKitPath.h
41   \brief The SoNodeKitPath class is a path that contains only nodekit nodes.
42 
43   \ingroup nodekits
44 
45   All other nodes are hidden from the user.
46 */
47 
48 // FIXME: We now need a "friend class SoNodeKitPath;" in the SoPath
49 // definition -- could we do without it? That would clean up the
50 // implementation a bit. 20020119 mortene.
51 
52 #include <Inventor/SoNodeKitPath.h>
53 
54 #include <cstdlib>
55 
56 #include <Inventor/nodekits/SoBaseKit.h>
57 #include <Inventor/actions/SoSearchAction.h>
58 
59 #include "tidbitsp.h"
60 
61 #if COIN_DEBUG
62 #include <Inventor/errors/SoDebugError.h>
63 #endif // COIN_DEBUG
64 
65 SoSearchAction * SoNodeKitPath::searchAction;
66 
67 /*!
68   A constructor.
69 */
SoNodeKitPath(const int approxLength)70 SoNodeKitPath::SoNodeKitPath(const int approxLength)
71   : SoPath(approxLength)
72 {
73 #if COIN_DEBUG
74   int n = this->nodes.getLength();
75   for (int i = 0; i < n; i++) {
76     if (this->nodes[i]->isOfType(SoBaseKit::getClassTypeId()))
77       return;
78   }
79   SoDebugError::postInfo("SoNodeKitPath::SoNodeKitPath",
80                          "no nodekits in path");
81 #endif // COIN_DEBUG
82 }
83 
84 /*!
85   The destructor.
86 */
~SoNodeKitPath()87 SoNodeKitPath::~SoNodeKitPath()
88 {
89 }
90 
91 /*!
92   Returns the length of the path (the number of nodekit nodes).
93 */
94 int
getLength(void) const95 SoNodeKitPath::getLength(void) const
96 {
97   int n = this->nodes.getLength();
98   int cnt = 0;
99   for (int i = 0; i < n; i++) {
100     if (this->nodes[i]->isOfType(SoBaseKit::getClassTypeId())) cnt++;
101   }
102   return cnt;
103 }
104 
105 /*!
106   Returns the tail of the path (the last nodekit in the path).
107 */
108 SoNode *
getTail(void) const109 SoNodeKitPath::getTail(void) const
110 {
111   for (int i = this->nodes.getLength()-1; i >= 0; i--) {
112     if (this->nodes[i]->isOfType(SoBaseKit::getClassTypeId()))
113       return this->nodes[i];
114   }
115 #if COIN_DEBUG && 1 // debug
116   SoDebugError::postInfo("SoNodeKitPath::getTail",
117                          "no nodekit in path");
118 #endif // debug
119   return NULL;
120 }
121 
122 /*!
123   Returns nodekit number \a idx in path.
124 */
125 SoNode *
getNode(const int idx) const126 SoNodeKitPath::getNode(const int idx) const
127 {
128   int n = this->nodes.getLength();
129   int cnt = 0;
130   for (int i = 0; i < n; i++) {
131     if (this->nodes[i]->isOfType(SoBaseKit::getClassTypeId())) {
132       if (cnt++ == idx) return this->nodes[i];
133     }
134   }
135 #if COIN_DEBUG
136   SoDebugError::postInfo("SoNodeKitPath::getNode",
137                          "index %d out of bounds", idx);
138 #endif // COIN_DEBUG
139 
140   return NULL;
141 }
142 
143 /*!
144   Returns nodekit number \a idx in the path, from the tail.
145 */
146 SoNode *
getNodeFromTail(const int idx) const147 SoNodeKitPath::getNodeFromTail(const int idx) const
148 {
149   int cnt = 0;
150   for (int i = this->nodes.getLength()-1; i >=0; i--) {
151     if (this->nodes[i]->isOfType(SoBaseKit::getClassTypeId())) {
152       if (cnt++ == idx) return this->nodes[i];
153     }
154   }
155 #if COIN_DEBUG
156   SoDebugError::postInfo("SoNodeKitPath::getNodeFromTail",
157                          "index %d out of bounds", idx);
158 #endif // COIN_DEBUG
159   return NULL;
160 }
161 
162 /*!
163   Truncates the path at nodekit number \a length.
164 */
165 void
truncate(const int length)166 SoNodeKitPath::truncate(const int length)
167 {
168   int i, n = this->nodes.getLength();
169   int cnt = 0;
170   for (i = 0; i < n; i++) {
171     if (this->nodes[i]->isOfType(SoBaseKit::getClassTypeId())) {
172       if (cnt++ == length) break;
173     }
174   }
175   if (i < n) SoPath::truncate(i);
176 #if COIN_DEBUG
177   else {
178     SoDebugError::postInfo("SoNodeKitPath::truncate",
179                            "illegal length: %d", length);
180   }
181 #endif // COIN_DEBUG
182 }
183 
184 /*!
185   Pops off the last nodekit (truncates at last tail).
186 */
187 void
pop(void)188 SoNodeKitPath::pop(void)
189 {
190   int i = this->nodes.getLength() - 1;
191   for (; i >= 0; i--) {
192     if (this->nodes[i]->isOfType(SoBaseKit::getClassTypeId())) break;
193   }
194   if (i < 0) {
195 #if COIN_DEBUG
196     SoDebugError::postInfo("SoNodeKitPath::pop",
197                            "no nodekits in path");
198 #endif // COIN_DEBUG
199     return;
200   }
201   SoPath::truncate(i);
202 }
203 
204 /*!
205   Appends \a childKit to the path. childKit should be a part in the
206   tail nodekit of this path. In effect, the path from the tail to first
207   occurrance of \a childKit will be appended to the path.
208 */
209 void
append(SoBaseKit * childKit)210 SoNodeKitPath::append(SoBaseKit * childKit)
211 {
212   if (this->getLength() == 0) this->setHead(childKit);
213   else {
214     SoBaseKit * tail = (SoBaseKit *) this->getTail();
215     assert(tail != NULL);
216     SoSearchAction * sa = this->getSearchAction();
217     sa->setNode(childKit);
218     SbBool oldSearch = tail->isSearchingChildren();
219     tail->setSearchingChildren(TRUE);
220     sa->apply(tail);
221     tail->setSearchingChildren(oldSearch);
222     SoPath * path = sa->getPath();
223     if (path) SoPath::append(path);
224     else {
225 #if COIN_DEBUG
226       SoDebugError::postInfo("SoNodeKitPath::append",
227                              "childKit not found as part of tail");
228 #endif // COIN_DEBUG
229     }
230   }
231 }
232 
233 /*!
234   Appends the nodekit path to this path. Head of \a fromPath must
235   be a part in the current tail.
236 */
237 void
append(const SoNodeKitPath * fromPath)238 SoNodeKitPath::append(const SoNodeKitPath * fromPath)
239 {
240   int n = fromPath->getLength();
241   for (int i = 0; i < n; i++) {
242     this->append((SoBaseKit *)fromPath->getNode(i));
243   }
244 }
245 
246 /*!
247   Returns \c TRUE if \a node is in this path.
248 */
249 SbBool
containsNode(SoBaseKit * node) const250 SoNodeKitPath::containsNode(SoBaseKit * node) const
251 {
252   return SoPath::containsNode((SoNode *)node);
253 }
254 
255 /*!
256   Returns the index of last common nodekit, or -1 if head
257   node differs.
258 */
259 int
findFork(const SoNodeKitPath * path) const260 SoNodeKitPath::findFork(const SoNodeKitPath * path) const
261 {
262   int i, n = SbMin(this->getLength(), path->getLength());
263   for (i = 0; i < n; i++) {
264     if (this->getNode(i) != path->getNode(i)) break;
265   }
266   return i-1;
267 }
268 
269 /*!
270   Returns \c TRUE if paths are equal, \c FALSE otherwise.
271 */
272 int
operator ==(const SoNodeKitPath & p1,const SoNodeKitPath & p2)273 operator==(const SoNodeKitPath & p1, const SoNodeKitPath & p2)
274 {
275   if (&p1 == &p2) return TRUE;
276   int n = p1.getLength();
277   if (n != p2.getLength()) return FALSE;
278 
279   for (int i = 0; i < n; i++) {
280     if (p1.getNode(i) != p2.getNode(i)) return FALSE;
281   }
282   return TRUE;
283 }
284 
285 
286 //
287 // atexit() method
288 //
289 void
clean(void)290 SoNodeKitPath::clean(void)
291 {
292   delete SoNodeKitPath::searchAction;
293   SoNodeKitPath::searchAction = NULL;
294 }
295 
296 //
297 // returns a search action to be used while serching for nodes
298 //
299 SoSearchAction *
getSearchAction(void)300 SoNodeKitPath::getSearchAction(void)
301 {
302   if (SoNodeKitPath::searchAction == NULL) {
303     SoNodeKitPath::searchAction = new SoSearchAction();
304     searchAction->setInterest(SoSearchAction::FIRST);
305     searchAction->setSearchingAll(FALSE);
306     coin_atexit((coin_atexit_f *)SoNodeKitPath::clean, CC_ATEXIT_NORMAL);
307   }
308   return SoNodeKitPath::searchAction;
309 }
310 
311 //
312 // private methods, just to keep the user from making mistakes
313 //
314 
315 void
append(const int)316 SoNodeKitPath::append(const int)
317 {
318 
319 }
320 
321 void
append(SoNode *)322 SoNodeKitPath::append(SoNode *)
323 {
324 }
325 
326 void
append(const SoPath *)327 SoNodeKitPath::append(const SoPath *)
328 {
329 }
330 
331 void
push(const int)332 SoNodeKitPath::push(const int)
333 {
334 }
335 
336 int
getIndex(const int) const337 SoNodeKitPath::getIndex(const int) const
338 {
339   return 0;
340 }
341 
342 int
getIndexFromTail(const int) const343 SoNodeKitPath::getIndexFromTail(const int) const
344 {
345   return 0;
346 }
347 
348 void
insertIndex(SoNode *,const int)349 SoNodeKitPath::insertIndex(SoNode *, const int)
350 {
351 }
352 
353 void
removeIndex(SoNode *,const int)354 SoNodeKitPath::removeIndex(SoNode *,const int)
355 {
356 }
357 
358 void
replaceIndex(SoNode *,const int,SoNode *)359 SoNodeKitPath::replaceIndex(SoNode *, const int, SoNode *)
360 {
361 }
362 
363 #endif // HAVE_NODEKITS
364