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 SoFieldSensor SoFieldSensor.h Inventor/sensors/SoFieldSensor.h
35   \brief The SoFieldSensor class detects changes to a field.
36 
37   \ingroup sensors
38 
39   Attach a field to a sensor of this type to put it under
40   surveillance, so you can act upon changes to the field.
41 
42   An SoFieldSensor can also act for delete-callback purposes alone and
43   does not need a regular notification-based callback.
44 */
45 
46 #include <Inventor/sensors/SoFieldSensor.h>
47 #include <Inventor/fields/SoField.h>
48 
49 
50 /*!
51   Constructor.
52  */
SoFieldSensor(void)53 SoFieldSensor::SoFieldSensor(void)
54 {
55   this->convict = NULL;
56 }
57 
58 /*!
59   Constructor taking as parameters the sensor callback function and
60   the userdata which will be passed the callback.
61 
62   \sa setFunction(), setData()
63  */
SoFieldSensor(SoSensorCB * func,void * data)64 SoFieldSensor::SoFieldSensor(SoSensorCB * func, void * data)
65   : inherited(func, data)
66 {
67   this->convict = NULL;
68 }
69 
70 /*!
71   Destructor.
72 */
~SoFieldSensor(void)73 SoFieldSensor::~SoFieldSensor(void)
74 {
75   if (this->convict) this->detach();
76 }
77 
78 /*!
79   Attach sensor to a field. Whenever the field's value changes, the
80   sensor will be triggered and call the callback function.
81 
82   A field sensor can be attached to only a single field at a
83   time. When this method is invoked multiple times, each subsequent
84   call will replace the field the sensor is monitoring with the new \a
85   field.
86 
87   When the given field is deleted, the sensor will automatically be
88   detached.
89 
90   \sa detach()
91  */
92 void
attach(SoField * field)93 SoFieldSensor::attach(SoField * field)
94 {
95   if (this->convict) this->detach();
96   this->convict = field;
97   field->addAuditor(this, SoNotRec::SENSOR);
98   field->evaluate();
99 }
100 
101 /*!
102   Detach sensor from field. As long as an SoFieldSensor is detached,
103   it will never call its callback function.
104 
105   \sa attach()
106  */
107 void
detach(void)108 SoFieldSensor::detach(void)
109 {
110   if (this->convict) {
111     this->convict->removeAuditor(this, SoNotRec::SENSOR);
112     this->convict = NULL;
113     if (this->isScheduled()) this->unschedule();
114   }
115 }
116 
117 /*!
118   Returns a pointer to the field connected to the sensor.
119 
120   \sa attach(), detach()
121  */
122 SoField *
getAttachedField(void) const123 SoFieldSensor::getAttachedField(void) const
124 {
125   return this->convict;
126 }
127 
128 // Doc from superclass.
129 void
trigger(void)130 SoFieldSensor::trigger(void)
131 {
132   this->convict->evaluate();
133   inherited::trigger();
134 }
135 
136 // Doc from superclass.
137 void
notify(SoNotList * l)138 SoFieldSensor::notify(SoNotList * l)
139 {
140   // Overridden to only propagate if the field that caused the
141   // notification is the one this sensor is attached to.
142   if (l->getLastField() == this->convict) {
143     inherited::notify(l);
144   }
145 }
146 
147 // Doc from superclass.
148 void
dyingReference(void)149 SoFieldSensor::dyingReference(void)
150 {
151   SoFieldContainer * dyingcontainer = this->getAttachedField()->getContainer();
152 
153   this->invokeDeleteCallback();
154 
155   if (this->getAttachedField() != NULL &&
156       this->getAttachedField()->getContainer() == dyingcontainer) {
157     // sensor is attached, and to the same field-container
158     this->detach();
159     // FIXME: we could maybe do an exception for the globalfield-container,
160     // and for loose fields I assume have NULL for getContainer() - those cases
161     // should be checked at the field-pointer level instead.
162   }
163 }
164