]>
Commit | Line | Data |
---|---|---|
1 | ///////////////////////////////////////////////////////////////////////////// | |
2 | // Name: wx/weakref.h | |
3 | // Purpose: wxWeakRef - Generic weak references for wxWidgets | |
4 | // Author: Arne Steinarson | |
5 | // Created: 27 Dec 07 | |
6 | // RCS-ID: $Id$ | |
7 | // Copyright: (c) 2007 Arne Steinarson | |
8 | // Licence: wxWindows licence | |
9 | ///////////////////////////////////////////////////////////////////////////// | |
10 | ||
11 | #ifndef _WX_WEAKREF_H_ | |
12 | #define _WX_WEAKREF_H_ | |
13 | ||
14 | #include "wx/tracker.h" | |
15 | ||
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 | ||
62 | void AssignCopy(const wxWeakRefStatic& wr) | |
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 | ||
77 | ||
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 | |
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 | |
95 | template<class T> | |
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 | { | |
147 | DoAssign(wr.m_pobj, wr.m_ptbase); | |
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 | ||
177 | #endif // #ifndef USE_STATIC_WEAKREF | |
178 | ||
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 | |
185 | #ifdef USE_STATIC_WEAKREF | |
186 | wxWeakRefStatic<T> | |
187 | #else | |
188 | wxWeakRefImpl<T, wxIsStaticTrackable<T>::value> | |
189 | #endif | |
190 | { | |
191 | public: | |
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 | } | |
215 | ||
216 | virtual ~wxWeakRef() { this->Release(); } | |
217 | ||
218 | // Smart pointer functions | |
219 | T& operator*() const { return *this->m_pobj; } | |
220 | T* operator->() const { return this->m_pobj; } | |
221 | ||
222 | T* get() const { return this->m_pobj; } | |
223 | operator T*() const { return get(); } | |
224 | }; | |
225 | ||
226 | ||
227 | // Weak ref implementation assign objects are queried for wxTrackable | |
228 | // using dynamic_cast<> | |
229 | template <class T> | |
230 | class wxWeakRefDynamic : public wxTrackerNode | |
231 | { | |
232 | public: | |
233 | wxWeakRefDynamic() : m_pobj(NULL) { } | |
234 | ||
235 | wxWeakRefDynamic(T* pobj) : m_pobj(pobj) | |
236 | { | |
237 | Assign(pobj); | |
238 | } | |
239 | ||
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 | |
255 | { | |
256 | return m_pobj ? &wxWeakRef<T>::get : NULL; | |
257 | } | |
258 | ||
259 | // Assign from another weak ref, point to same object | |
260 | T* operator = (const wxWeakRef<T> &wr) { Assign( wr.get() ); return this->m_pobj; } | |
261 | ||
262 | void Release() | |
263 | { | |
264 | // Release old object if any | |
265 | if( m_pobj ) | |
266 | { | |
267 | // Remove ourselves from object tracker list | |
268 | wxTrackable *pt = dynamic_cast<wxTrackable*>(m_pobj); | |
269 | wxASSERT(pt); | |
270 | pt->RemoveNode(this); | |
271 | m_pobj = NULL; | |
272 | } | |
273 | } | |
274 | ||
275 | protected: | |
276 | void Assign(T *pobj) | |
277 | { | |
278 | if ( m_pobj == pobj ) | |
279 | return; | |
280 | ||
281 | Release(); | |
282 | ||
283 | // Now set new trackable object | |
284 | if ( pobj ) | |
285 | { | |
286 | // Add ourselves to object tracker list | |
287 | wxTrackable *pt = dynamic_cast<wxTrackable*>(pobj); | |
288 | if ( pt ) | |
289 | { | |
290 | pt->AddNode(this); | |
291 | m_pobj = pobj; | |
292 | } | |
293 | else | |
294 | { | |
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" ); | |
298 | } | |
299 | } | |
300 | } | |
301 | ||
302 | virtual void OnObjectDestroy() | |
303 | { | |
304 | wxASSERT_MSG( m_pobj, "tracked object should have removed us itself" ); | |
305 | ||
306 | m_pobj = NULL; | |
307 | } | |
308 | ||
309 | T *m_pobj; | |
310 | }; | |
311 | ||
312 | // Provide some basic types of weak references | |
313 | class WXDLLIMPEXP_FWD_BASE wxEvtHandler; | |
314 | class WXDLLIMPEXP_FWD_CORE wxWindow; | |
315 | ||
316 | typedef wxWeakRef<wxEvtHandler> wxEvtHandlerRef; | |
317 | typedef wxWeakRef<wxWindow> wxWindowRef; | |
318 | ||
319 | #endif // _WX_WEAKREF_H_ | |
320 |