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 /*!
34   \class SoEnabledElementsList SoEnabledElementsList.h Inventor/lists/SoEnabledElementsList.h
35   \brief The SoEnabledElementsList class is a container for type info for element types that are enabled in actions.
36 
37   \ingroup actions
38 
39   This class is probably not interesting for the application
40   programmer.
41 */
42 
43 // FIXME: doesn't handle post-initialization changes very well (fixing
44 // this also needs some tempering to be done with SoAction, I think.)
45 // 20000305 mortene.
46 
47 #include <Inventor/lists/SoEnabledElementsList.h>
48 #include <cassert>
49 
50 #ifdef HAVE_CONFIG_H
51 #include <config.h>
52 #endif // HAVE_CONFIG_H
53 
54 #ifdef COIN_THREADSAFE
55 #include <Inventor/threads/SbMutex.h>
56 #endif // COIN_THREADSAFE
57 
58 #ifndef DOXYGEN_SKIP_THIS
59 
60 class SoEnabledElementsListP {
61 public:
62   int prevmerge;
63   SoTypeList elements;
64   SoEnabledElementsList * parent;
65 #ifdef COIN_THREADSAFE
66   SbMutex mutex;
67 #endif // COIN_THREADSAFE
lock(void)68   void lock(void) {
69 #ifdef COIN_THREADSAFE
70     this->mutex.lock();
71 #endif
72   }
unlock(void)73   void unlock(void) {
74 #ifdef COIN_THREADSAFE
75     this->mutex.unlock();
76 #endif
77   }
78 };
79 
80 static int enable_counter = 0;
81 
82 #endif // DOXYGEN_SKIP_THIS
83 
84 #define PRIVATE(obj) ((obj)->pimpl)
85 
86 /*!
87   Constructor.
88 */
SoEnabledElementsList(SoEnabledElementsList * const parentlist)89 SoEnabledElementsList::SoEnabledElementsList(SoEnabledElementsList * const parentlist)
90 {
91   PRIVATE(this) = new SoEnabledElementsListP;
92 
93   PRIVATE(this)->prevmerge = 0;
94   PRIVATE(this)->parent = parentlist;
95 }
96 
97 /*!
98   Destructor.
99 */
~SoEnabledElementsList()100 SoEnabledElementsList::~SoEnabledElementsList()
101 {
102   delete PRIVATE(this);
103 }
104 
105 /*!
106   Return the list of enabled elements.
107 */
108 const SoTypeList &
getElements(void) const109 SoEnabledElementsList::getElements(void) const
110 {
111   PRIVATE(this)->lock();
112   // check if we need a new merge
113   if (PRIVATE(this)->prevmerge != enable_counter) {
114     int storedcounter = enable_counter;
115     SoEnabledElementsList * plist = (SoEnabledElementsList*) PRIVATE(this)->parent;
116     while (plist) {
117       ((SoEnabledElementsList*)this)->merge(*plist);
118       plist = plist->pimpl->parent;
119     }
120     // use and restore old counter since it might change during merge
121     ((SoEnabledElementsList*)this)->pimpl->prevmerge =
122       enable_counter = storedcounter;
123   }
124   PRIVATE(this)->unlock();
125   return PRIVATE(this)->elements;
126 }
127 
128 /*!
129   Add an \a elementtype to the list of enabled elements if it's not
130   enabled already.
131 */
132 void
enable(const SoType elementtype,const int stackindex)133 SoEnabledElementsList::enable(const SoType elementtype, const int stackindex)
134 {
135   while (stackindex >= PRIVATE(this)->elements.getLength())
136     PRIVATE(this)->elements.append(SoType::badType());
137 
138   SoType currtype = PRIVATE(this)->elements[stackindex];
139   if (currtype.isBad() ||
140       (elementtype != currtype && elementtype.isDerivedFrom(currtype))) {
141     PRIVATE(this)->elements.set(stackindex, elementtype);
142     // increment to detect when a new merge is needed
143     enable_counter++;
144   }
145 }
146 
147 /*!
148   Enables all the elements from the \a eel list that is enabled in
149   this instance.
150 */
151 void
merge(const SoEnabledElementsList & eel)152 SoEnabledElementsList::merge(const SoEnabledElementsList & eel)
153 {
154   SoType bad = SoType::badType();
155   const int num = eel.pimpl->elements.getLength();
156   for (int i = 0; i < num; i++) {
157     if (eel.pimpl->elements[i] != bad) this->enable(eel.pimpl->elements[i], i);
158   }
159 }
160 
161 /*!
162   Return the current setting of the global counter used to determine
163   when lists are out of date.  It is incremented whenever a new
164   element is added to a list.
165 */
166 int
getCounter(void)167 SoEnabledElementsList::getCounter(void)
168 {
169   return enable_counter;
170 }
171 
172 #undef PRIVATE
173