]>
Commit | Line | Data |
---|---|---|
db7035e4 VZ |
1 | ///////////////////////////////////////////////////////////////////////////// |
2 | // Name: wx/weakref.h | |
3 | // Purpose: wxWeakRef - Generic weak references for wxWidgets | |
4 | // Author: Arne Steinarson | |
cc6ceca7 | 5 | // Created: 27 Dec 07 |
9dd5ff5b | 6 | // RCS-ID: $Id$ |
db7035e4 VZ |
7 | // Copyright: (c) 2007 Arne Steinarson |
8 | // Licence: wxWindows licence | |
9 | ///////////////////////////////////////////////////////////////////////////// | |
10 | ||
11 | #ifndef _WX_WEAKREF_H_ | |
12 | #define _WX_WEAKREF_H_ | |
13 | ||
cc6ceca7 | 14 | #include "wx/tracker.h" |
db7035e4 | 15 | |
cc6ceca7 VZ |
16 | #include "wx/meta/convertible.h" |
17 | #include "wx/meta/int2type.h" | |
18 | ||
19 | template <class T> | |
20 | struct wxIsStaticTrackable | |
21 | { | |
22 | enum { value = wxConvertibleTo<T, wxTrackable>::value }; | |
23 | }; | |
24 | ||
25 | // Weak ref implementation when T has wxTrackable as a known base class | |
26 | template <class T> | |
27 | class wxWeakRefStatic : public wxTrackerNode | |
28 | { | |
29 | public: | |
30 | wxWeakRefStatic() : m_pobj(NULL) { } | |
31 | ||
32 | void Release() | |
33 | { | |
34 | // Release old object if any | |
35 | if ( m_pobj ) | |
36 | { | |
37 | // Remove ourselves from object tracker list | |
38 | wxTrackable *pt = static_cast<wxTrackable*>(m_pobj); | |
39 | pt->RemoveNode(this); | |
40 | m_pobj = NULL; | |
41 | } | |
42 | } | |
43 | ||
44 | protected: | |
45 | void Assign(T* pobj) | |
46 | { | |
47 | if ( m_pobj == pobj ) | |
48 | return; | |
49 | ||
50 | Release(); | |
51 | ||
52 | // Now set new trackable object | |
53 | if ( pobj ) | |
54 | { | |
55 | // Add ourselves to object tracker list | |
56 | wxTrackable *pt = static_cast<wxTrackable*>(pobj); | |
57 | pt->AddNode(this); | |
58 | m_pobj = pobj; | |
59 | } | |
60 | } | |
61 | ||
42d9ad79 | 62 | void AssignCopy(const wxWeakRefStatic& wr) |
cc6ceca7 VZ |
63 | { |
64 | Assign( wr.m_pobj ); | |
65 | } | |
66 | ||
67 | virtual void OnObjectDestroy() | |
68 | { | |
69 | // Tracked object itself removes us from list of trackers | |
70 | wxASSERT( m_pobj!=NULL ); | |
71 | m_pobj = NULL; | |
72 | } | |
73 | ||
74 | T *m_pobj; | |
75 | }; | |
76 | ||
cc6ceca7 | 77 | |
7005cf44 VZ |
78 | #if !defined(HAVE_PARTIAL_SPECIALIZATION) || !defined(HAVE_TEMPLATE_OVERLOAD_RESOLUTION) |
79 | #define USE_STATIC_WEAKREF | |
80 | #endif | |
81 | ||
82 | ||
83 | #ifndef USE_STATIC_WEAKREF | |
cc6ceca7 VZ |
84 | template<class T,bool use_static> |
85 | struct wxWeakRefImpl; | |
86 | ||
87 | // Intermediate class, to select the static case above. | |
88 | template <class T> | |
89 | struct wxWeakRefImpl<T, true> : public wxWeakRefStatic<T> | |
90 | { | |
91 | enum { value = 1 }; | |
92 | }; | |
93 | ||
94 | // Weak ref implementation when T does not have wxTrackable as known base class | |
db7035e4 | 95 | template<class T> |
cc6ceca7 VZ |
96 | struct wxWeakRefImpl<T, false> : public wxTrackerNode |
97 | { | |
98 | void Release() | |
99 | { | |
100 | // Release old object if any | |
101 | if ( m_pobj ) | |
102 | { | |
103 | // Remove ourselves from object tracker list | |
104 | m_ptbase->RemoveNode(this); | |
105 | m_pobj = NULL; | |
106 | m_ptbase = NULL; | |
107 | } | |
108 | } | |
109 | ||
110 | protected: | |
111 | wxWeakRefImpl() : m_pobj(NULL), m_ptbase(NULL) { } | |
112 | ||
113 | // Assign receives most derived class here and can use that | |
114 | template <class TDerived> | |
115 | void Assign( TDerived* pobj ) | |
116 | { | |
117 | AssignHelper( pobj, wxInt2Type<wxIsStaticTrackable<TDerived>::value>() ); | |
118 | } | |
119 | ||
120 | template <class TDerived> | |
121 | void AssignHelper(TDerived* pobj, wxInt2Type<true>) | |
122 | { | |
123 | wxTrackable *ptbase = static_cast<wxTrackable*>(pobj); | |
124 | DoAssign( pobj, ptbase ); | |
125 | } | |
126 | ||
127 | #ifdef HAVE_DYNAMIC_CAST | |
128 | void AssignHelper(T* pobj, wxInt2Type<false>) | |
129 | { | |
130 | // A last way to get a trackable pointer | |
131 | wxTrackable *ptbase = dynamic_cast<wxTrackable*>(pobj); | |
132 | if ( ptbase ) | |
133 | { | |
134 | DoAssign( pobj, ptbase ); | |
135 | } | |
136 | else | |
137 | { | |
138 | wxFAIL_MSG( "Tracked class should inherit from wxTrackable" ); | |
139 | ||
140 | Release(); | |
141 | } | |
142 | } | |
143 | #endif // HAVE_DYNAMIC_CAST | |
144 | ||
145 | void AssignCopy(const wxWeakRefImpl& wr) | |
146 | { | |
42d9ad79 | 147 | DoAssign(wr.m_pobj, wr.m_ptbase); |
cc6ceca7 VZ |
148 | } |
149 | ||
150 | void DoAssign( T* pobj, wxTrackable *ptbase ) { | |
151 | if( m_pobj==pobj ) return; | |
152 | Release(); | |
153 | ||
154 | // Now set new trackable object | |
155 | if( pobj ) | |
156 | { | |
157 | // Add ourselves to object tracker list | |
158 | wxASSERT( ptbase ); | |
159 | ptbase->AddNode( this ); | |
160 | m_pobj = pobj; | |
161 | m_ptbase = ptbase; | |
162 | } | |
163 | } | |
164 | ||
165 | virtual void OnObjectDestroy() | |
166 | { | |
167 | // Tracked object itself removes us from list of trackers | |
168 | wxASSERT( m_pobj!=NULL ); | |
169 | m_pobj = NULL; | |
170 | m_ptbase = NULL; | |
171 | } | |
172 | ||
173 | T *m_pobj; | |
174 | wxTrackable *m_ptbase; | |
175 | }; | |
176 | ||
7005cf44 VZ |
177 | #endif // #ifndef USE_STATIC_WEAKREF |
178 | ||
cc6ceca7 VZ |
179 | |
180 | ||
181 | // A weak reference to an object of type T, where T has type wxTrackable | |
182 | // (usually statically but if not dynamic_cast<> is tried). | |
183 | template <class T> | |
184 | class wxWeakRef : public | |
7005cf44 | 185 | #ifdef USE_STATIC_WEAKREF |
cc6ceca7 | 186 | wxWeakRefStatic<T> |
7005cf44 VZ |
187 | #else |
188 | wxWeakRefImpl<T, wxIsStaticTrackable<T>::value> | |
cc6ceca7 | 189 | #endif |
db7035e4 VZ |
190 | { |
191 | public: | |
cc6ceca7 VZ |
192 | // Default ctor |
193 | wxWeakRef() { } | |
194 | ||
195 | // When we have the full type here, static_cast<> will always work | |
196 | // (or give a straight compiler error). | |
197 | template <class TDerived> | |
198 | wxWeakRef(TDerived* pobj) | |
199 | { | |
200 | Assign(pobj); | |
201 | } | |
202 | ||
203 | template <class TDerived> | |
204 | wxWeakRef<T>& operator=(TDerived* pobj) | |
205 | { | |
206 | Assign(pobj); | |
207 | return *this; | |
208 | } | |
209 | ||
210 | wxWeakRef<T>& operator=(const wxWeakRef<T>& wr) | |
211 | { | |
212 | AssignCopy(wr); | |
213 | return *this; | |
214 | } | |
db7035e4 | 215 | |
34bfda8a | 216 | virtual ~wxWeakRef() { this->Release(); } |
cc6ceca7 VZ |
217 | |
218 | // Smart pointer functions | |
34bfda8a VZ |
219 | T& operator*() const { return *this->m_pobj; } |
220 | T* operator->() const { return this->m_pobj; } | |
cc6ceca7 | 221 | |
34bfda8a VZ |
222 | T* get() const { return this->m_pobj; } |
223 | operator T*() const { return get(); } | |
cc6ceca7 VZ |
224 | }; |
225 | ||
226 | ||
227 | // Weak ref implementation assign objects are queried for wxTrackable | |
228 | // using dynamic_cast<> | |
42d9ad79 | 229 | template <class T> |
cc6ceca7 VZ |
230 | class wxWeakRefDynamic : public wxTrackerNode |
231 | { | |
232 | public: | |
233 | wxWeakRefDynamic() : m_pobj(NULL) { } | |
1e9192d0 | 234 | |
cc6ceca7 | 235 | wxWeakRefDynamic(T* pobj) : m_pobj(pobj) |
db7035e4 VZ |
236 | { |
237 | Assign(pobj); | |
db7035e4 VZ |
238 | } |
239 | ||
cc6ceca7 VZ |
240 | virtual ~wxWeakRefDynamic() { Release(); } |
241 | ||
242 | // Smart pointer functions | |
243 | T& operator * (){ wxASSERT(this->m_pobj); return *m_pobj; } | |
244 | T* operator -> (){ wxASSERT(this->m_pobj); return m_pobj; } | |
245 | T* operator = (T* pobj) { Assign(pobj); return m_pobj; } | |
246 | ||
247 | T* get(){ return this->m_pobj; } | |
248 | ||
249 | // operator T* (){ return this->m_pobj; } | |
250 | ||
251 | // test for pointer validity: defining conversion to unspecified_bool_type | |
252 | // and not more obvious bool to avoid implicit conversions to integer types | |
253 | typedef T *(wxWeakRef<T>::*unspecified_bool_type)() const; | |
254 | operator unspecified_bool_type() const | |
db7035e4 | 255 | { |
cc6ceca7 | 256 | return m_pobj ? &wxWeakRef<T>::get : NULL; |
db7035e4 VZ |
257 | } |
258 | ||
cc6ceca7 VZ |
259 | // Assign from another weak ref, point to same object |
260 | T* operator = (const wxWeakRef<T> &wr) { Assign( wr.get() ); return this->m_pobj; } | |
db7035e4 | 261 | |
cc6ceca7 | 262 | void Release() |
db7035e4 | 263 | { |
cc6ceca7 VZ |
264 | // Release old object if any |
265 | if( m_pobj ) | |
db7035e4 VZ |
266 | { |
267 | // Remove ourselves from object tracker list | |
cc6ceca7 | 268 | wxTrackable *pt = dynamic_cast<wxTrackable*>(m_pobj); |
9dd5ff5b RR |
269 | wxASSERT(pt); |
270 | pt->RemoveNode(this); | |
db7035e4 VZ |
271 | m_pobj = NULL; |
272 | } | |
cc6ceca7 VZ |
273 | } |
274 | ||
275 | protected: | |
276 | void Assign(T *pobj) | |
277 | { | |
278 | if ( m_pobj == pobj ) | |
279 | return; | |
280 | ||
281 | Release(); | |
db7035e4 VZ |
282 | |
283 | // Now set new trackable object | |
284 | if ( pobj ) | |
285 | { | |
cc6ceca7 VZ |
286 | // Add ourselves to object tracker list |
287 | wxTrackable *pt = dynamic_cast<wxTrackable*>(pobj); | |
288 | if ( pt ) | |
9dd5ff5b | 289 | { |
cc6ceca7 | 290 | pt->AddNode(this); |
9dd5ff5b RR |
291 | m_pobj = pobj; |
292 | } | |
293 | else | |
294 | { | |
cc6ceca7 VZ |
295 | // If the object we want to track does not support wxTackable, then |
296 | // log a message and keep the NULL object pointer. | |
297 | wxFAIL_MSG( "Tracked class should inherit from wxTrackable" ); | |
9dd5ff5b | 298 | } |
db7035e4 VZ |
299 | } |
300 | } | |
301 | ||
cc6ceca7 VZ |
302 | virtual void OnObjectDestroy() |
303 | { | |
304 | wxASSERT_MSG( m_pobj, "tracked object should have removed us itself" ); | |
305 | ||
306 | m_pobj = NULL; | |
307 | } | |
308 | ||
db7035e4 VZ |
309 | T *m_pobj; |
310 | }; | |
311 | ||
312 | // Provide some basic types of weak references | |
db7035e4 | 313 | class WXDLLIMPEXP_FWD_BASE wxEvtHandler; |
5a0c7d66 | 314 | class WXDLLIMPEXP_FWD_CORE wxWindow; |
db7035e4 | 315 | |
db7035e4 VZ |
316 | typedef wxWeakRef<wxEvtHandler> wxEvtHandlerRef; |
317 | typedef wxWeakRef<wxWindow> wxWindowRef; | |
318 | ||
319 | #endif // _WX_WEAKREF_H_ | |
320 |