1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: TestSmartPointer.cxx
5
6 Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7 All rights reserved.
8 See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9
10 This software is distributed WITHOUT ANY WARRANTY; without even
11 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12 PURPOSE. See the above copyright notice for more information.
13
14 =========================================================================*/
15 // .NAME Test of Observers.
16 // .SECTION Description
17 // Tests vtkObject::AddObserver templated API
18
19 #include "vtkObjectFactory.h"
20 #include "vtkSmartPointer.h"
21 #include <map>
22
23 class vtkHandler : public vtkObject
24 {
25 public:
26 static std::map<int, int> EventCounts;
27 static int VoidEventCounts;
28
29 static vtkHandler* New();
30 vtkTypeMacro(vtkHandler, vtkObject);
31
VoidCallback()32 void VoidCallback() { vtkHandler::VoidEventCounts++; }
CallbackWithArguments(vtkObject *,unsigned long event,void *)33 void CallbackWithArguments(vtkObject*, unsigned long event, void*)
34 {
35 vtkHandler::EventCounts[event]++;
36 }
37 };
38 vtkStandardNewMacro(vtkHandler);
39
40 int vtkHandler::VoidEventCounts = 0;
41 std::map<int, int> vtkHandler::EventCounts;
42
43 class OtherHandler
44 {
45 public:
46 static std::map<int, int> EventCounts;
47 static int VoidEventCounts;
48
VoidCallback()49 void VoidCallback() { OtherHandler::VoidEventCounts++; }
CallbackWithArguments(vtkObject *,unsigned long event,void *)50 void CallbackWithArguments(vtkObject*, unsigned long event, void*)
51 {
52 OtherHandler::EventCounts[event]++;
53 }
54 };
55
56 int OtherHandler::VoidEventCounts = 0;
57 std::map<int, int> OtherHandler::EventCounts;
58
TestObservers(int,char * [])59 int TestObservers(int, char*[])
60 {
61 unsigned long event0 = 0;
62 unsigned long event1 = 0;
63 unsigned long event2 = 0;
64
65 vtkObject* volcano = vtkObject::New();
66
67 // First the base test, with a vtkObject pointer
68 vtkHandler* handler = vtkHandler::New();
69
70 event0 = volcano->AddObserver(1000, handler, &vtkHandler::VoidCallback);
71 event1 = volcano->AddObserver(1001, handler, &vtkHandler::CallbackWithArguments);
72 event2 = volcano->AddObserver(1002, handler, &vtkHandler::CallbackWithArguments);
73
74 volcano->InvokeEvent(1000);
75 volcano->InvokeEvent(1001);
76 volcano->InvokeEvent(1002);
77
78 // let's see if removing an observer works
79 volcano->RemoveObserver(event2);
80 volcano->InvokeEvent(1000);
81 volcano->InvokeEvent(1001);
82 volcano->InvokeEvent(1002);
83
84 // now delete the observer, we shouldn't have any dangling pointers.
85 handler->Delete();
86
87 volcano->InvokeEvent(1000);
88 volcano->InvokeEvent(1001);
89 volcano->InvokeEvent(1002);
90
91 // remove an observer after the handler has been deleted, should work.
92 volcano->RemoveObserver(event1);
93 volcano->InvokeEvent(1000);
94 volcano->InvokeEvent(1001);
95 volcano->InvokeEvent(1002);
96
97 // remove the final observer
98 volcano->RemoveObserver(event0);
99
100 if (vtkHandler::VoidEventCounts == 2 && vtkHandler::EventCounts[1000] == 0 &&
101 vtkHandler::EventCounts[1001] == 2 && vtkHandler::EventCounts[1002] == 1)
102 {
103 cout << "All vtkObject callback counts as expected." << endl;
104 }
105 else
106 {
107 cerr << "Mismatched callback counts for VTK observer." << endl;
108 volcano->Delete();
109 return 1;
110 }
111
112 // ---------------------------------
113 // Test again, with smart pointers
114 vtkHandler::VoidEventCounts = 0;
115
116 // Make a scope for the smart pointer
117 {
118 vtkSmartPointer<vtkHandler> handler2 = vtkSmartPointer<vtkHandler>::New();
119
120 event0 = volcano->AddObserver(1003, handler2, &vtkHandler::VoidCallback);
121 event1 = volcano->AddObserver(1004, handler2, &vtkHandler::CallbackWithArguments);
122 event2 = volcano->AddObserver(1005, handler2, &vtkHandler::CallbackWithArguments);
123
124 volcano->InvokeEvent(1003);
125 volcano->InvokeEvent(1004);
126 volcano->InvokeEvent(1005);
127
128 // let's see if removing an observer works
129 volcano->RemoveObserver(event2);
130 volcano->InvokeEvent(1003);
131 volcano->InvokeEvent(1004);
132 volcano->InvokeEvent(1005);
133
134 // end the scope, which deletes the observer
135 }
136
137 // continue invoking, to make sure that
138 // no events to to the deleted observer
139 volcano->InvokeEvent(1003);
140 volcano->InvokeEvent(1004);
141 volcano->InvokeEvent(1005);
142
143 // remove an observer after the handler2 has been deleted, should work.
144 volcano->RemoveObserver(event1);
145 volcano->InvokeEvent(1003);
146 volcano->InvokeEvent(1004);
147 volcano->InvokeEvent(1005);
148
149 // remove the final observer
150 volcano->RemoveObserver(event0);
151
152 if (vtkHandler::VoidEventCounts == 2 && vtkHandler::EventCounts[1003] == 0 &&
153 vtkHandler::EventCounts[1004] == 2 && vtkHandler::EventCounts[1005] == 1)
154 {
155 cout << "All smart pointer callback counts as expected." << endl;
156 }
157 else
158 {
159 cerr << "Mismatched callback counts for smart pointer observer." << endl;
160 volcano->Delete();
161 return 1;
162 }
163
164 // ---------------------------------
165 // Test yet again, this time with a non-VTK object
166 // (this _can_ leave dangling pointers!!!)
167
168 OtherHandler* handler3 = new OtherHandler();
169
170 event0 = volcano->AddObserver(1006, handler3, &OtherHandler::VoidCallback);
171 event1 = volcano->AddObserver(1007, handler3, &OtherHandler::CallbackWithArguments);
172 event2 = volcano->AddObserver(1008, handler3, &OtherHandler::CallbackWithArguments);
173
174 volcano->InvokeEvent(1006);
175 volcano->InvokeEvent(1007);
176 volcano->InvokeEvent(1008);
177
178 // let's see if removing an observer works
179 volcano->RemoveObserver(event2);
180 volcano->InvokeEvent(1006);
181 volcano->InvokeEvent(1007);
182 volcano->InvokeEvent(1008);
183
184 // if we delete this non-vtkObject observer, we will
185 // have dangling pointers and will see a crash...
186 // so let's not do that until the events are removed
187
188 volcano->RemoveObserver(event0);
189 volcano->RemoveObserver(event1);
190 delete handler3;
191
192 // delete the observed object
193 volcano->Delete();
194
195 if (OtherHandler::VoidEventCounts == 2 && OtherHandler::EventCounts[1006] == 0 &&
196 OtherHandler::EventCounts[1007] == 2 && OtherHandler::EventCounts[1008] == 1)
197 {
198 cout << "All non-VTK observer callback counts as expected." << endl;
199 return 0;
200 }
201
202 cerr << "Mismatched callback counts for non-VTK observer." << endl;
203 return 1;
204 }
205