\input windowdc.tex
\input destroyevt.tex
\input weakref.tex
+\input weakrefdynamic.tex
\input wnddisbl.tex
\input wizard.tex
\input wizevt.tex
-
-\section{\class{wxTrackableBase}}\label{wxtrackablebase}
+\section{\class{wxTrackable}}\label{wxtrackable}
Add-on base class for a trackable object. This class maintains
an internal linked list of classes of type wxTrackerNode and
make it trackable.
\begin{verbatim}
-class MyClass: public Foo, public TrackableBase
+class MyClass: public Foo, public wxTrackable
{
// whatever
}
\section{\class{wxTrackable}}\label{wxtrackable}
-The only difference to \helpref{wxTrackableBase}{wxtrackablebase} is
-that this class adds a virtual table to enable dynamic\_cast query for
-wxTrackable.
-
-\wxheading{Derived from}
-
-\helpref{wxTrackableBase}{wxtrackablebase}
-
\wxheading{Include files}
<tracker.h>
-\wxheading{Data structures}
-
-
pointer, but when the object pointed is destroyed, the weak reference is
automatically reset to a NULL pointer.
-wxWeakref<T> can be used whenever one must keep a pointer to an object
-that does not directly own, and that may be destroyed before the object
+wxWeakRef<T> can be used whenever one must keep a pointer to an object
+that one does not directly own, and that may be destroyed before the object
holding the reference.
-wxWeakref<T> is a small object and the mechanism behind it is fast
+wxWeakRef<T> is a small object and the mechanism behind it is fast
(\textbf{O(1)}). So the overall cost of using it is small.
wxASSERT( wr==NULL );
\end{verbatim}
-wxWeakref<T> works for any objects that are derived from
-\helpref{wxTrackableBase}{wxtrackablebase} or \helpref{wxTrackable}{wxtrackable}.
-By default, wxEvtHandler and wxWindow derive from wxTrackableBase. However,
+wxWeakRef<T> works for any objects that are derived from \helpref{wxTrackable}{wxtrackable}.
+By default, wxEvtHandler and wxWindow derive from wxTrackable. However,
wxObject does not, so types like \helpref{wxFont}{wxfont} and
\helpref{wxColour}{wxcolour} are not trackable. The example below shows how to
create a wxObject derived class that is trackable:
};
\end{verbatim}
-\textbf{Note:} Custom trackable objects should derive from wxTrackable
-if one wants to reference them from a \texttt{wxWeakRef<wxObject>}. The
-difference between the two base classes is that wxTrackableBase
-has no virtual member functions (no VTable), and thus cannot be detected
-through \texttt{dynamic\_cast<>}.
-
\wxheading{Predefined types}
The following types of weak references are predefined:
\begin{verbatim}
-typedef wxWeakRef<wxObject> wxObjectRef;
typedef wxWeakRef<wxEvtHandler> wxEvtHandlerRef;
typedef wxWeakRef<wxWindow> wxWindowRef;
\end{verbatim}
\membersection{wxWeakRef<T>::operator=}\label{wxweakrefoperatorassign}
-\func{T* operator}{operator=}{\param{T* }{pobj}}
+\func{T*}{operator=}{\param{T* }{pobj}}
Releases the currently tracked object and starts tracking {\it pobj}.
A weak reference may be reset by passing {\it NULL} as {\it pobj}.
\membersection{wxWeakRef<T>::operator =}\label{wxweakrefoperatorassign2}
-\func{T* operator}{operator =}{\param{wxWeakRef<T>\& }{wr}}
+\func{T*}{operator =}{\param{wxWeakRef<T>\& }{wr}}
Release currently tracked object and start tracking the same object as
the wxWeakRef {\it wr}.
+\membersection{wxWeakRef<T>::Release}\label{wxweakrefrelease}
+
+\func{void}{Release}{\void}
+
+Release currently tracked object and rests object reference.
+
+
\membersection{wxWeakRef<T>::OnObjectDestroy}\label{wxweakrefonobjectdestroy}
\func{virtual void}{OnObjectDestroy}{\void}
--- /dev/null
+\section{\class{wxWeakRefDynamic<T>}}\label{wxweakrefdynamic}
+
+wxWeakRefDynamic<T> is a template class for weak references that is used in
+the same way as wxWeakRef<T>. The only difference is that wxWeakRefDynamic
+defaults to using \texttt{dynamic\_cast<>} for establishing the object
+reference (while wxWeakRef defaults to \texttt{static\_cast<>}).
+
+So, wxWeakRef will detect a type mismatch during compile time and will
+have a little better run-time performance. The role of wxWeakRefDynamic
+is to handle objects which derived type one does not know.
+
+\textbf{Note:} wxWeakRef<T> selects an implementation based on the static type
+of T. If T does not have wxTrackable statically, it defaults to to a mixed-
+mode operation, where it uses \texttt{dynamic\_cast<>} as the last measure (if
+available from the compiler and enabled when building wxWidgets).
+
+For general cases, wxWeakRef<T> is the better choice.
+
+For API documentation, see: \helpref{wxWeakRef}{wxweakref}
+
#endif
#endif /* HAVE_WOSTREAM */
+// ----------------------------------------------------------------------------
+// other C++ features
+// ----------------------------------------------------------------------------
+
+#ifndef HAVE_PARTIAL_SPECIALIZATION
+ // be optimistic by default
+ #define HAVE_PARTIAL_SPECIALIZATION
+#endif
+
+#ifdef __VISUALC__
+ #if __VISUALC__ < 1310
+ #undef HAVE_PARTIAL_SPECIALIZATION
+ #endif
+#endif // __VISUALC__
+
/* ---------------------------------------------------------------------------- */
/* portable calling conventions macros */
/* ---------------------------------------------------------------------------- */
#endif // wxUSE_GUI
class WXDLLIMPEXP_FWD_BASE wxEvtHandler;
+class wxEventConnectionRef;
// ----------------------------------------------------------------------------
// Event types
DECLARE_NO_COPY_CLASS(wxEventHashTable)
};
-// ----------------------------------------------------------------------------
-// wxEventConnectionRef: A class that represents all connections between two event
-// handlers and enables automatic disconnect when an event handler sink goes
-// out of scope. Each connection/disconnect increases/decreases ref count, and
-// when zero the node goes out of scope.
-// ----------------------------------------------------------------------------
-
-struct wxEventConnectionRef : public wxTrackerNode {
-
- wxEventConnectionRef() : m_src(0), m_sink(0), m_refCount(0) { }
- wxEventConnectionRef( wxEvtHandler *src, wxEvtHandler *sink );
- virtual ~wxEventConnectionRef();
-
- // The sink is being destroyed
- virtual void OnObjectDestroy( );
- virtual wxTrackerNodeType GetType( ){ return EventConnectionRef; }
-
- void IncRef( ) { m_refCount++; }
- void DecRef( );
-
-protected:
- wxEvtHandler *m_src, *m_sink;
- int m_refCount;
-
- friend class wxEvtHandler;
-
-private:
- // It makes no sense to copy objects of this class
- wxEventConnectionRef& operator = (const wxEventConnectionRef& WXUNUSED(other)) { wxFAIL; return *this; }
-};
-
-
-
// ----------------------------------------------------------------------------
// wxEvtHandler: the base class for all objects handling wxWidgets events
// ----------------------------------------------------------------------------
-class WXDLLIMPEXP_BASE wxEvtHandler : public wxObject, public wxTrackableBase
+class WXDLLIMPEXP_BASE wxEvtHandler : public wxObject, public wxTrackable
{
public:
wxEvtHandler();
virtual void *DoGetClientData() const;
// Search tracker objects for event connection with this sink
- wxEventConnectionRef *FindRefInTrackerList( wxEvtHandler *eventSink );
+ wxEventConnectionRef *FindRefInTrackerList(wxEvtHandler *eventSink);
private:
DECLARE_DYNAMIC_CLASS_NO_COPY(wxEvtHandler)
};
+// ----------------------------------------------------------------------------
+// wxEventConnectionRef represents all connections between two event handlers
+// and enables automatic disconnect when an event handler sink goes out of
+// scope. Each connection/disconnect increases/decreases ref count, and
+// when it reaches zero the node goes out of scope.
+// ----------------------------------------------------------------------------
+
+class wxEventConnectionRef : public wxTrackerNode
+{
+public:
+ wxEventConnectionRef() : m_src(NULL), m_sink(NULL), m_refCount(0) { }
+ wxEventConnectionRef(wxEvtHandler *src, wxEvtHandler *sink)
+ : m_src(src), m_sink(sink), m_refCount(1)
+ {
+ m_sink->AddNode(this);
+ }
+
+ // The sink is being destroyed
+ virtual void OnObjectDestroy( )
+ {
+ if ( m_src )
+ m_src->OnSinkDestroyed( m_sink );
+ delete this;
+ }
+
+ virtual wxEventConnectionRef *ToEventConnection() { return this; }
+
+ void IncRef() { m_refCount++; }
+ void DecRef()
+ {
+ if ( !--m_refCount )
+ {
+ // The sink holds the only external pointer to this object
+ if ( m_sink )
+ m_sink->RemoveNode(this);
+ delete this;
+ }
+ }
+
+private:
+ wxEvtHandler *m_src,
+ *m_sink;
+ int m_refCount;
+
+ friend class wxEvtHandler;
+
+ DECLARE_NO_ASSIGN_CLASS(wxEventConnectionRef)
+};
+
// Post a message to the given eventhandler which will be processed during the
// next event loop iteration
inline void wxPostEvent(wxEvtHandler *dest, const wxEvent& event)
// Name: wx/tracker.h
// Purpose: Support class for object lifetime tracking (wxWeakRef<T>)
// Author: Arne Steinarson
-// Created: 2007-12-28
+// Created: 28 Dec 07
// RCS-ID: $Id$
// Copyright: (c) 2007 Arne Steinarson
// Licence: wxWindows licence
#ifndef _WX_TRACKER_H_
#define _WX_TRACKER_H_
+#include "wx/defs.h"
-// This structure represents an object tracker and is stored in a linked list
+class wxEventConnectionRef;
+
+// This class represents an object tracker and is stored in a linked list
// in the tracked object. It is only used in one of its derived forms.
-struct wxTrackerNode {
- wxTrackerNode( ) : m_nxt(0) { }
+class WXDLLIMPEXP_BASE wxTrackerNode
+{
+public:
+ wxTrackerNode() : m_nxt(NULL) { }
virtual ~wxTrackerNode() { }
-
- virtual void OnObjectDestroy( ) = 0;
-
- // This is to tell the difference between different tracker node types.
- // It's a replacement of dynamic_cast<> for this class since dynamic_cast
- // may be disabled (and we don't have wxDynamicCast since wxTrackerNode
- // is not derived wxObject).
- enum wxTrackerNodeType { WeakRef, EventConnectionRef };
-
- virtual wxTrackerNodeType GetType() = 0;
-
-protected:
+
+ virtual void OnObjectDestroy() = 0;
+
+ virtual wxEventConnectionRef *ToEventConnection() { return NULL; }
+
+private:
wxTrackerNode *m_nxt;
- friend class wxTrackableBase; // For list access
+
+ friend class wxTrackable; // For list access
friend class wxEvtHandler; // For list access
};
-
// Add-on base class for a trackable object.
-struct wxTrackableBase {
- wxTrackableBase() : m_first(0) { }
- ~wxTrackableBase()
- {
+class wxTrackable
+{
+public:
+ wxTrackable() : m_first(NULL) { }
+
+ ~wxTrackable()
+ {
// Notify all registered refs
-
- wxTrackerNode *first;
- while( m_first )
+ while ( m_first )
{
- first = m_first;
- first->OnObjectDestroy( );
- RemoveNode(first);
+ wxTrackerNode * const first = m_first;
+ m_first = first->m_nxt;
+ first->OnObjectDestroy();
}
}
-
- void AddNode( wxTrackerNode *prn )
+
+ void AddNode(wxTrackerNode *prn)
{
prn->m_nxt = m_first;
m_first = prn;
}
- void RemoveNode( wxTrackerNode *prn )
+
+ void RemoveNode(wxTrackerNode *prn)
{
- for( wxTrackerNode **pprn=&m_first; *pprn; pprn=&(*pprn)->m_nxt )
+ for ( wxTrackerNode **pprn = &m_first; *pprn; pprn = &(*pprn)->m_nxt )
{
- if( *pprn==prn )
+ if ( *pprn == prn )
{
*pprn = prn->m_nxt;
return;
}
}
- // Not found, an error.
- wxASSERT( false );
- }
-
- wxTrackerNode* GetFirst( ){ return m_first; }
- // If trying to copy this object, then do not copy its ref list.
- wxTrackableBase& operator = (const wxTrackableBase& WXUNUSED(other)) { return *this; }
-
-protected:
- wxTrackerNode *m_first;
-};
+ wxFAIL_MSG( "removing invalid tracker node" );
+ }
+ wxTrackerNode *GetFirst() const { return m_first; }
-// The difference to wxTrackableBase is that this class adds
-// a VTable to enable dynamic_cast query for wxTrackable.
-struct wxTrackable : public wxTrackableBase
-{
- virtual ~wxTrackable(){ }
-};
-
+protected:
+ wxTrackerNode *m_first;
-// Helper to decide if an object has a base class or not
-// (strictly speaking, this test succeeds if a type is convertible
-// to another type in some way.)
-template<class T, class B>
-struct wxHasBase{
- static char Match( B* pb );
- static int Match( ... );
- enum { value = (sizeof(Match((T*)NULL))==sizeof(char)) };
+ DECLARE_NO_COPY_CLASS(wxTrackable)
};
-// VC++ before 7.1 does not have partial template specialization
-#ifdef __VISUALC__
- #if __VISUALC__ < 1310
- #define HAVE_NO_PARTIAL_SPECIALIZATION
- #endif
-#endif
-
-#if defined(HAVE_DYNAMIC_CAST) && !defined(HAVE_NO_PARTIAL_SPECIALIZATION)
- // A structure to cast to wxTrackableBase, using either static_cast<> or dynamic_cast<>.
- template<class T,bool is_static>
- struct wxTrackableCaster;
-
- template <class T>
- struct wxTrackableCaster<T,true> {
- static wxTrackableBase* Cast(T* pt){ return static_cast<wxTrackableBase*>(pt); }
- };
-
- template <class T>
- struct wxTrackableCaster<T,false> {
- static wxTrackableBase* Cast(T* pt){ return dynamic_cast<wxTrackableBase*>(pt); }
- };
-#else
- #if defined(HAVE_DYNAMIC_CAST)
- // If we have dynamic_cast, default to that. For gcc, dynamic_cast<> does the job
- // of both the dynamic and the static case. It could be that all compilers do it
- // that way, rendering the specialization code above rednundant.
- template <class T,bool is_static>
- struct wxTrackableCaster {
- static wxTrackableBase* Cast(T* pt){ return dynamic_cast<wxTrackableBase*>(pt); }
- };
- #else
- // No dynamic_cast<> is available.
- // We use static_cast<>, that gives support for wxEvtHandler and wxWindow references.
- // We don't get weak refs to other wxObject derived types.
- template <class T,bool is_static>
- struct wxTrackableCaster {
- static wxTrackableBase* Cast(T* pt){ return static_cast<wxTrackableBase*>(pt); }
- };
- #endif
-#endif
-
#endif // _WX_TRACKER_H_
// Name: wx/weakref.h
// Purpose: wxWeakRef - Generic weak references for wxWidgets
// Author: Arne Steinarson
-// Created: 2007-12-27
+// Created: 27 Dec 07
// RCS-ID: $Id$
// Copyright: (c) 2007 Arne Steinarson
// Licence: wxWindows licence
#ifndef _WX_WEAKREF_H_
#define _WX_WEAKREF_H_
-#include <wx/tracker.h>
+#include "wx/tracker.h"
-// A weak reference to an object of type T, where T has type wxTrackable
-// as one of its base classes (in a static or dynamic sense).
+#include "wx/meta/convertible.h"
+#include "wx/meta/int2type.h"
+
+template <class T>
+struct wxIsStaticTrackable
+{
+ enum { value = wxConvertibleTo<T, wxTrackable>::value };
+};
+
+// Weak ref implementation when T has wxTrackable as a known base class
+template <class T>
+class wxWeakRefStatic : public wxTrackerNode
+{
+public:
+ wxWeakRefStatic() : m_pobj(NULL) { }
+
+ void Release()
+ {
+ // Release old object if any
+ if ( m_pobj )
+ {
+ // Remove ourselves from object tracker list
+ wxTrackable *pt = static_cast<wxTrackable*>(m_pobj);
+ pt->RemoveNode(this);
+ m_pobj = NULL;
+ }
+ }
+
+protected:
+ void Assign(T* pobj)
+ {
+ if ( m_pobj == pobj )
+ return;
+
+ Release();
+
+ // Now set new trackable object
+ if ( pobj )
+ {
+ // Add ourselves to object tracker list
+ wxTrackable *pt = static_cast<wxTrackable*>(pobj);
+ pt->AddNode(this);
+ m_pobj = pobj;
+ }
+ }
+
+ void AssignCopy( const wxWeakRefStatic& wr )
+ {
+ Assign( wr.m_pobj );
+ }
+
+ virtual void OnObjectDestroy()
+ {
+ // Tracked object itself removes us from list of trackers
+ wxASSERT( m_pobj!=NULL );
+ m_pobj = NULL;
+ }
+
+ T *m_pobj;
+};
+
+#ifdef HAVE_PARTIAL_SPECIALIZATION
+
+template<class T,bool use_static>
+struct wxWeakRefImpl;
+
+// Intermediate class, to select the static case above.
+template <class T>
+struct wxWeakRefImpl<T, true> : public wxWeakRefStatic<T>
+{
+ enum { value = 1 };
+};
+
+// Weak ref implementation when T does not have wxTrackable as known base class
template<class T>
-class wxWeakRef : public wxTrackerNode
+struct wxWeakRefImpl<T, false> : public wxTrackerNode
+{
+ void Release()
+ {
+ // Release old object if any
+ if ( m_pobj )
+ {
+ // Remove ourselves from object tracker list
+ m_ptbase->RemoveNode(this);
+ m_pobj = NULL;
+ m_ptbase = NULL;
+ }
+ }
+
+protected:
+ wxWeakRefImpl() : m_pobj(NULL), m_ptbase(NULL) { }
+
+ // Assign receives most derived class here and can use that
+ template <class TDerived>
+ void Assign( TDerived* pobj )
+ {
+ AssignHelper( pobj, wxInt2Type<wxIsStaticTrackable<TDerived>::value>() );
+ }
+
+ template <class TDerived>
+ void AssignHelper(TDerived* pobj, wxInt2Type<true>)
+ {
+ wxTrackable *ptbase = static_cast<wxTrackable*>(pobj);
+ DoAssign( pobj, ptbase );
+ }
+
+#ifdef HAVE_DYNAMIC_CAST
+ void AssignHelper(T* pobj, wxInt2Type<false>)
+ {
+ // A last way to get a trackable pointer
+ wxTrackable *ptbase = dynamic_cast<wxTrackable*>(pobj);
+ if ( ptbase )
+ {
+ DoAssign( pobj, ptbase );
+ }
+ else
+ {
+ wxFAIL_MSG( "Tracked class should inherit from wxTrackable" );
+
+ Release();
+ }
+ }
+#endif // HAVE_DYNAMIC_CAST
+
+ void AssignCopy(const wxWeakRefImpl& wr)
+ {
+ DoAssign( wr.m_pobj, wr.m_ptbase );
+ }
+
+ void DoAssign( T* pobj, wxTrackable *ptbase ) {
+ if( m_pobj==pobj ) return;
+ Release();
+
+ // Now set new trackable object
+ if( pobj )
+ {
+ // Add ourselves to object tracker list
+ wxASSERT( ptbase );
+ ptbase->AddNode( this );
+ m_pobj = pobj;
+ m_ptbase = ptbase;
+ }
+ }
+
+ virtual void OnObjectDestroy()
+ {
+ // Tracked object itself removes us from list of trackers
+ wxASSERT( m_pobj!=NULL );
+ m_pobj = NULL;
+ m_ptbase = NULL;
+ }
+
+ T *m_pobj;
+ wxTrackable *m_ptbase;
+};
+
+#endif // HAVE_PARTIAL_SPECIALIZATION
+
+
+// A weak reference to an object of type T, where T has type wxTrackable
+// (usually statically but if not dynamic_cast<> is tried).
+template <class T>
+class wxWeakRef : public
+#ifdef HAVE_PARTIAL_SPECIALIZATION
+ wxWeakRefImpl<T, wxIsStaticTrackable<T>::value>
+#else
+ wxWeakRefStatic<T>
+#endif
{
public:
- typedef T element_type;
-
- wxWeakRef(T *pobj = NULL) : m_pobj(NULL) { Assign(pobj); }
+ // Default ctor
+ wxWeakRef() { }
+
+ // When we have the full type here, static_cast<> will always work
+ // (or give a straight compiler error).
+ template <class TDerived>
+ wxWeakRef(TDerived* pobj)
+ {
+ Assign(pobj);
+ }
+
+ template <class TDerived>
+ wxWeakRef<T>& operator=(TDerived* pobj)
+ {
+ Assign(pobj);
+ return *this;
+ }
+
+ wxWeakRef<T>& operator=(const wxWeakRef<T>& wr)
+ {
+ AssignCopy(wr);
+ return *this;
+ }
- virtual ~wxWeakRef() { Assign(NULL); }
+ virtual ~wxWeakRef() { Release(); }
+
+ // Smart pointer functions
+ T& operator*() const { return *m_pobj; }
+ T* operator->() const { return m_pobj; }
+
+ T* get() const { return m_pobj; }
// test for pointer validity: defining conversion to unspecified_bool_type
// and not more obvious bool to avoid implicit conversions to integer types
typedef T *(wxWeakRef<T>::*unspecified_bool_type)() const;
operator unspecified_bool_type() const
{
- return m_pobj ? &wxWeakRef<T>::get : NULL;
+ return this->m_pobj ? &wxWeakRef<T>::get : NULL;
}
+};
+
+
+// Weak ref implementation assign objects are queried for wxTrackable
+// using dynamic_cast<>
+template<class T>
+class wxWeakRefDynamic : public wxTrackerNode
+{
+public:
+ wxWeakRefDynamic() : m_pobj(NULL) { }
- T * get() const
- {
- return m_pobj;
- }
-
- T* operator->()
- {
- wxASSERT(m_pobj != NULL);
- return m_pobj;
- }
-
- T& operator*() const
- {
- wxASSERT(m_pobj != NULL);
- return *m_pobj;
- }
-
- T* operator=(T *pobj)
+ wxWeakRefDynamic(T* pobj) : m_pobj(pobj)
{
Assign(pobj);
- return m_pobj;
}
- // Assign from another weak ref, point to same object
- T* operator = (const wxWeakRef<T> &wr)
- {
- Assign(wr);
- return m_pobj;
- }
-
- virtual void OnObjectDestroy()
+ virtual ~wxWeakRefDynamic() { Release(); }
+
+ // Smart pointer functions
+ T& operator * (){ wxASSERT(this->m_pobj); return *m_pobj; }
+ T* operator -> (){ wxASSERT(this->m_pobj); return m_pobj; }
+ T* operator = (T* pobj) { Assign(pobj); return m_pobj; }
+
+ T* get(){ return this->m_pobj; }
+
+ // operator T* (){ return this->m_pobj; }
+
+ // test for pointer validity: defining conversion to unspecified_bool_type
+ // and not more obvious bool to avoid implicit conversions to integer types
+ typedef T *(wxWeakRef<T>::*unspecified_bool_type)() const;
+ operator unspecified_bool_type() const
{
- // Tracked object itself removes us from list of trackers
- wxASSERT( m_pobj );
- m_pobj = NULL;
+ return m_pobj ? &wxWeakRef<T>::get : NULL;
}
-protected:
- friend class wxTrackableBase;
- friend class wxEvtHandler;
+ // Assign from another weak ref, point to same object
+ T* operator = (const wxWeakRef<T> &wr) { Assign( wr.get() ); return this->m_pobj; }
- virtual wxTrackerNodeType GetType() { return WeakRef; }
-
- void Assign(T* pobj)
+ void Release()
{
- if ( m_pobj == pobj )
- return;
-
- // First release old object if any
- if ( m_pobj )
+ // Release old object if any
+ if( m_pobj )
{
// Remove ourselves from object tracker list
- // This does static_cast if available, otherwise it tries dynamic cast
- wxTrackableBase *pt = wxTrackableCaster<T,wxHasBase<T,wxTrackableBase>::value >::Cast(m_pobj);
+ wxTrackable *pt = dynamic_cast<wxTrackable*>(m_pobj);
wxASSERT(pt);
pt->RemoveNode(this);
m_pobj = NULL;
}
+ }
+
+protected:
+ void Assign(T *pobj)
+ {
+ if ( m_pobj == pobj )
+ return;
+
+ Release();
// Now set new trackable object
if ( pobj )
{
- wxTrackableBase *pt = wxTrackableCaster<T,wxHasBase<T,wxTrackableBase>::value >::Cast(pobj);
- if( pt )
+ // Add ourselves to object tracker list
+ wxTrackable *pt = dynamic_cast<wxTrackable*>(pobj);
+ if ( pt )
{
- pt->AddNode( this );
+ pt->AddNode(this);
m_pobj = pobj;
}
else
{
- // If the tracked we want to track does not support wxTackableBase, then
- // log a message and keep the NULL object pointer.
- wxLogWarning( _T("wxWeakRef::Assign - Type does not provide wxTrackableBase - resetting tracked object") );
+ // If the object we want to track does not support wxTackable, then
+ // log a message and keep the NULL object pointer.
+ wxFAIL_MSG( "Tracked class should inherit from wxTrackable" );
}
}
}
+ void AssignCopy(const wxWeakRefDynamic& wr)
+ {
+ Assign(wr.m_pobj);
+ }
+
+ virtual void OnObjectDestroy()
+ {
+ wxASSERT_MSG( m_pobj, "tracked object should have removed us itself" );
+
+ m_pobj = NULL;
+ }
+
T *m_pobj;
};
// Provide some basic types of weak references
-class WXDLLIMPEXP_FWD_BASE wxObject;
class WXDLLIMPEXP_FWD_BASE wxEvtHandler;
-class WXDLLIMPEXP_FWD_CORE wxWindow;
+class WXDLLIMPEXP_FWD_BASE wxWindow;
-typedef wxWeakRef<wxObject> wxObjectRef;
typedef wxWeakRef<wxEvtHandler> wxEvtHandlerRef;
typedef wxWeakRef<wxWindow> wxWindowRef;
wxString wxCommandEvent::GetString() const
{
- if(m_eventType != wxEVT_COMMAND_TEXT_UPDATED || !m_eventObject)
+ if (m_eventType != wxEVT_COMMAND_TEXT_UPDATED || !m_eventObject)
+ {
return m_cmdString;
+ }
else
{
#if wxUSE_TEXTCTRL
wxTextCtrl *txt = wxDynamicCast(m_eventObject, wxTextCtrl);
- if(txt)
+ if ( txt )
return txt->GetValue();
else
#endif // wxUSE_TEXTCTRL
delete[] oldEventTypeTable;
}
-
-// ----------------------------------------------------------------------------
-// wxEventConnectionRef
-// ----------------------------------------------------------------------------
-
-// Below functions are mostly short but kept in cpp file to simplify setting
-// breakpoints (GDB)
-wxEventConnectionRef::wxEventConnectionRef(wxEvtHandler *src, wxEvtHandler *sink)
- : m_src(src), m_sink(sink), m_refCount(1)
-{
- wxASSERT( m_sink );
- m_sink->AddNode( this );
-}
-
-wxEventConnectionRef::~wxEventConnectionRef()
-{
-}
-
-void wxEventConnectionRef::OnObjectDestroy( )
-{
- if( m_src )
- m_src->OnSinkDestroyed( m_sink );
- // It is safe to delete this tracker object here
- delete this;
-}
-
-void wxEventConnectionRef::DecRef( )
-{
- if( !--m_refCount )
- {
- // The sink holds the only external pointer to this object
- if( m_sink )
- m_sink->RemoveNode(this);
- delete this;
- }
-}
-
-
// ----------------------------------------------------------------------------
// wxEvtHandler
// ----------------------------------------------------------------------------
{
wxDynamicEventTableEntry *entry = (wxDynamicEventTableEntry*)*it;
- // Remove ourselves from sink destructor notifications
+ // Remove ourselves from sink destructor notifications
// (this has usually been been done, in wxTrackable destructor)
wxEvtHandler *eventSink = entry->m_eventSink;
- if( eventSink )
+ if ( eventSink )
{
- wxEventConnectionRef *pecr = FindRefInTrackerList( eventSink );
- if( pecr )
- {
- eventSink->RemoveNode( pecr );
- delete pecr;
- }
+ wxEventConnectionRef * const
+ evtConnRef = FindRefInTrackerList(eventSink);
+ if ( evtConnRef )
+ {
+ eventSink->RemoveNode(evtConnRef);
+ delete evtConnRef;
+ }
}
-
+
if (entry->m_callbackUserData)
delete entry->m_callbackUserData;
delete entry;
if ( wxPendingEvents )
{
#if wxUSE_THREADS
- if(wxPendingEventsLocker)
+ if (wxPendingEventsLocker)
wxENTER_CRIT_SECT(*wxPendingEventsLocker);
#endif
//else: we weren't in this list at all, it's ok
#if wxUSE_THREADS
- if(wxPendingEventsLocker)
+ if (wxPendingEventsLocker)
wxLEAVE_CRIT_SECT(*wxPendingEventsLocker);
#endif
}
// Insert at the front of the list so most recent additions are found first
m_dynamicEvents->Insert( (wxObject*) entry );
-
- // Make sure we get to know when a sink is destroyed
- if( eventSink )
+
+ // Make sure we get to know when a sink is destroyed
+ if ( eventSink )
{
- wxEventConnectionRef *pecr = FindRefInTrackerList( eventSink );
- if( pecr )
- pecr->IncRef( );
+ wxEventConnectionRef *evtConnRef = FindRefInTrackerList(eventSink);
+ if ( evtConnRef )
+ evtConnRef->IncRef( );
else
- pecr = new wxEventConnectionRef(this,eventSink);
+ evtConnRef = new wxEventConnectionRef(this, eventSink);
}
}
return false;
// Remove connection from tracker node (wxEventConnectionRef)
- if( eventSink )
+ if ( eventSink )
{
- wxEventConnectionRef *pecr = FindRefInTrackerList( eventSink );
- if( pecr )
- pecr->DecRef( );
+ wxEventConnectionRef *evtConnRef = FindRefInTrackerList(eventSink);
+ if ( evtConnRef )
+ evtConnRef->DecRef();
}
wxList::compatibility_iterator node = m_dynamicEvents->GetFirst();
return m_clientData;
}
-// A helper func to find an wxEventConnectionRef object
-wxEventConnectionRef* wxEvtHandler::FindRefInTrackerList( wxEvtHandler *eventSink )
+// A helper to find an wxEventConnectionRef object
+wxEventConnectionRef *
+wxEvtHandler::FindRefInTrackerList(wxEvtHandler *eventSink)
{
- wxASSERT(eventSink);
- for( wxTrackerNode *ptn=eventSink->GetFirst(); ptn; ptn=ptn->m_nxt )
+ for ( wxTrackerNode *node = eventSink->GetFirst(); node; node = node->m_nxt )
{
- // Only want wxEventConnectionRef nodes here
- if( ptn->GetType()!=wxTrackerNode::EventConnectionRef )
- continue;
- wxEventConnectionRef *pecr = static_cast<wxEventConnectionRef*>(ptn);
- if( pecr && pecr->m_src==this )
+ // we only want wxEventConnectionRef nodes here
+ wxEventConnectionRef *evtConnRef = node->ToEventConnection();
+ if ( evtConnRef && evtConnRef->m_src == this )
{
- wxASSERT( pecr->m_sink==eventSink );
- return pecr;
+ wxASSERT( evtConnRef->m_sink==eventSink );
+ return evtConnRef;
}
}
+
return NULL;
}
void wxEvtHandler::OnSinkDestroyed( wxEvtHandler *sink )
{
wxASSERT(m_dynamicEvents);
-
+
// remove all connections with this sink
wxList::compatibility_iterator node = m_dynamicEvents->GetFirst(), node_nxt;
while (node)
{
wxDynamicEventTableEntry *entry = (wxDynamicEventTableEntry*)node->GetData();
node_nxt = node->GetNext();
-
- if( entry->m_eventSink==sink )
+
+ if ( entry->m_eventSink==sink )
{
if (entry->m_callbackUserData)
delete entry->m_callbackUserData;
thread/queue.cpp
uris/uris.cpp
vectors/vectors.cpp
+ weakref/evtconnection.cpp
+ weakref/weakref.cpp
</sources>
<wx-lib>net</wx-lib>
<wx-lib>base</wx-lib>
--- /dev/null
+///////////////////////////////////////////////////////////////////////////////
+// Name: tests/weakref/evtconnection.cpp
+// Purpose: wxWeakRef<T> unit test
+// Author: Arne Steinarson
+// Created: 2008-01-10
+// RCS-ID: $Id$
+// Copyright: (c) 2007 Arne Steinarson
+///////////////////////////////////////////////////////////////////////////////
+
+// ----------------------------------------------------------------------------
+// headers
+// ----------------------------------------------------------------------------
+
+#include "testprec.h"
+
+#ifdef __BORLANDC__
+ #pragma hdrstop
+#endif
+
+#ifndef WX_PRECOMP
+ #include "wx/wx.h"
+#endif // WX_PRECOMP
+
+#include "wx/event.h"
+#include "wx/weakref.h"
+
+static int gs_value = 0; // Increased by 1 by first object and 0x10000 by 2nd object
+
+static wxObject *gs_psrc1;
+static wxObject *gs_psrc2;
+
+// We need some event types
+const wxEventType wxEVT_TEST = wxNewEventType(),
+ wxEVT_TEST1 = wxNewEventType(),
+ wxEVT_TEST2 = wxNewEventType();
+
+class wxTestEvent : public wxEvent
+{
+public:
+ wxTestEvent(wxEventType type = wxEVT_TEST) : wxEvent(0, type) { }
+ virtual wxEvent *Clone() const { return new wxTestEvent(GetEventType()); }
+};
+
+class wxTestSink : public wxEvtHandler
+{
+public:
+ void OnTestEvent(wxEvent& evt)
+ {
+ if ( evt.GetEventObject() == gs_psrc1 )
+ gs_value += 1;
+ else if ( evt.GetEventObject() == gs_psrc2 )
+ gs_value += 0x10000;
+ }
+
+ void OnTestEvent1(wxEvent& )
+ {
+ gs_value += 0x00100;
+ }
+
+ void OnTestEvent2(wxEvent&)
+ {
+ gs_value += 0x01000000;
+ }
+};
+
+
+
+// --------------------------------------------------------------------------
+// test class
+// --------------------------------------------------------------------------
+
+class EvtConnectionTestCase : public CppUnit::TestCase
+{
+public:
+ EvtConnectionTestCase() {}
+
+private:
+ CPPUNIT_TEST_SUITE( EvtConnectionTestCase );
+ CPPUNIT_TEST( SinkTest );
+ CPPUNIT_TEST( SourceDestroyTest );
+ CPPUNIT_TEST( MultiConnectionTest );
+ CPPUNIT_TEST_SUITE_END();
+
+ void SinkTest();
+ void SourceDestroyTest();
+ void MultiConnectionTest();
+
+ DECLARE_NO_COPY_CLASS(EvtConnectionTestCase)
+};
+
+// register in the unnamed registry so that these tests are run by default
+CPPUNIT_TEST_SUITE_REGISTRATION( EvtConnectionTestCase );
+
+// also include in it's own registry so that these tests can be run alone
+CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( EvtConnectionTestCase, "EvtConnectionTestCase" );
+
+
+// Helpers
+void DoConnect( wxEvtHandler& eh1, wxEvtHandler& eh2, wxTestSink& ts ){
+ eh1.Connect(wxEVT_TEST, (wxObjectEventFunction)&wxTestSink::OnTestEvent,
+ NULL, &ts);
+ eh2.Connect(wxEVT_TEST, (wxObjectEventFunction) &wxTestSink::OnTestEvent,
+ NULL, &ts);
+}
+
+void DoDisconnect( wxEvtHandler& eh1, wxEvtHandler& eh2, wxTestSink& ts ){
+ eh1.Disconnect(wxEVT_TEST, (wxObjectEventFunction) &wxTestSink::OnTestEvent,
+ NULL, &ts);
+ eh2.Disconnect(wxEVT_TEST, (wxObjectEventFunction) &wxTestSink::OnTestEvent,
+ NULL, &ts);
+}
+
+
+void EvtConnectionTestCase::SinkTest()
+{
+ // Let the sink be destroyed before the sources
+
+ // An event used below
+ wxTestEvent evt;
+
+ // Connect two event handlers to one sink
+ wxEvtHandler eh1, eh2;
+ gs_psrc1 = &eh1;
+ gs_psrc2 = &eh2;
+
+ {
+ wxTestSink ts;
+ CPPUNIT_ASSERT( !ts.GetFirst() );
+ DoConnect(eh1, eh2, ts);
+
+ DoDisconnect(eh1, eh2, ts);
+
+ DoConnect(eh1, eh2, ts);
+
+ // Fire events
+ evt.SetEventObject(&eh1);
+ eh1.ProcessEvent(evt);
+ evt.SetEventObject(&eh2);
+ eh2.ProcessEvent(evt);
+
+ // Make sure they were processed correctly
+ CPPUNIT_ASSERT_EQUAL( 0x00010001, gs_value );
+ }
+
+ // Fire events again, should be no sink connected now
+ gs_value = 0;
+ evt.SetEventObject(&eh1);
+ eh1.ProcessEvent( evt );
+ evt.SetEventObject(&eh2);
+ eh2.ProcessEvent( evt );
+
+ // Make sure no processing happened
+ CPPUNIT_ASSERT_EQUAL( 0, gs_value );
+}
+
+void EvtConnectionTestCase::SourceDestroyTest()
+{
+ // Let the sources be destroyed before the sink
+ wxTestSink ts;
+ wxTestEvent evt;
+ {
+ wxEvtHandler eh1;
+ {
+ CPPUNIT_ASSERT( !ts.GetFirst() );
+
+ // Connect two event handlers to one sink
+ wxEvtHandler eh2;
+ gs_psrc1 = &eh1;
+ gs_psrc2 = &eh2;
+ DoConnect( eh1, eh2, ts );
+
+ // Fire events
+ gs_value = 0;
+ evt.SetEventObject(&eh1);
+ eh1.ProcessEvent( evt );
+ evt.SetEventObject(&eh2);
+ eh2.ProcessEvent( evt );
+
+ // Make sure they were processed correctly
+ CPPUNIT_ASSERT_EQUAL( 0x00010001, gs_value );
+ }
+
+ gs_value = 0;
+ evt.SetEventObject(&eh1);
+ eh1.ProcessEvent( evt );
+
+ // Make sure still connected
+ CPPUNIT_ASSERT_EQUAL( 0x00000001, gs_value );
+ }
+ CPPUNIT_ASSERT( !ts.GetFirst() );
+}
+
+void EvtConnectionTestCase::MultiConnectionTest()
+{
+ // events used below
+ wxTestEvent evt;
+ wxTestEvent evt1(wxEVT_TEST1);
+ wxTestEvent evt2(wxEVT_TEST2);
+
+ // One source
+ wxEvtHandler eh1;
+ evt.SetEventObject(&eh1);
+ gs_psrc1 = NULL;
+ gs_psrc2 = &eh1;
+
+ {
+ // ...and one sink
+ wxTestSink ts;
+
+ eh1.Connect(wxEVT_TEST, (wxObjectEventFunction)&wxTestSink::OnTestEvent,
+ NULL, &ts);
+ eh1.Connect(wxEVT_TEST1, (wxObjectEventFunction)&wxTestSink::OnTestEvent1,
+ NULL, &ts);
+ eh1.Connect(wxEVT_TEST2, (wxObjectEventFunction)&wxTestSink::OnTestEvent2,
+ NULL, &ts);
+
+ // Generate events
+ gs_value = 0;
+ eh1.ProcessEvent(evt);
+ eh1.ProcessEvent(evt1);
+ eh1.ProcessEvent(evt2);
+ CPPUNIT_ASSERT( gs_value==0x01010100 );
+
+ {
+ // Declare weak references to the objects (using same list)
+ wxEvtHandlerRef re(&eh1), rs(&ts);
+ }
+ // And now destroyed
+
+ eh1.Disconnect(wxEVT_TEST, (wxObjectEventFunction)&wxTestSink::OnTestEvent,
+ NULL, &ts);
+ eh1.ProcessEvent(evt);
+ eh1.ProcessEvent(evt1);
+ eh1.ProcessEvent(evt2);
+ CPPUNIT_ASSERT_EQUAL( 0x02010200, gs_value );
+ }
+
+ // No connection should be left now
+ gs_value = 0;
+ eh1.ProcessEvent(evt);
+ eh1.ProcessEvent(evt1);
+ eh1.ProcessEvent(evt2);
+
+ // Nothing should have been done
+ CPPUNIT_ASSERT_EQUAL( 0, gs_value );
+}
+
--- /dev/null
+///////////////////////////////////////////////////////////////////////////////
+// Name: tests/weakref/weakref.cpp
+// Purpose: wxWeakRef<T> unit test
+// Author: Arne Steinarson
+// Created: 2008-01-10
+// RCS-ID: $Id$
+// Copyright: (c) 2007 Arne Steinarson
+///////////////////////////////////////////////////////////////////////////////
+
+// ----------------------------------------------------------------------------
+// headers
+// ----------------------------------------------------------------------------
+
+#include "testprec.h"
+
+#ifdef __BORLANDC__
+ #pragma hdrstop
+#endif
+
+#ifndef WX_PRECOMP
+ #include "wx/wx.h"
+#endif // WX_PRECOMP
+
+#include "wx/event.h"
+#include "wx/weakref.h"
+
+// A statically trackable derived wxObject
+class wxObjectTrackable : public wxObject, public wxTrackable
+{
+public:
+ // Test member access
+ void TestFunc(){ }
+
+ // Make sure this does not clash with wxTrackableBase method
+ int GetFirst() { return 0; }
+};
+
+// --------------------------------------------------------------------------
+// test class
+// --------------------------------------------------------------------------
+
+class WeakRefTestCase : public CppUnit::TestCase
+{
+public:
+ WeakRefTestCase() {}
+
+private:
+ CPPUNIT_TEST_SUITE( WeakRefTestCase );
+ CPPUNIT_TEST( DeclareTest );
+ CPPUNIT_TEST( AssignTest );
+ CPPUNIT_TEST( AssignWeakRefTest );
+ CPPUNIT_TEST( MultiAssignTest );
+ CPPUNIT_TEST( CleanupTest );
+ CPPUNIT_TEST( DeleteTest );
+#ifdef HAVE_DYNAMIC_CAST
+ CPPUNIT_TEST( DynamicRefTest );
+#endif
+ CPPUNIT_TEST_SUITE_END();
+
+ void DeclareTest();
+ void AssignTest();
+ void AssignWeakRefTest();
+ void MultiAssignTest();
+ void CleanupTest();
+ void DeleteTest();
+#ifdef HAVE_DYNAMIC_CAST
+ void DynamicRefTest();
+#endif
+
+ DECLARE_NO_COPY_CLASS(WeakRefTestCase)
+};
+
+// register in the unnamed registry so that these tests are run by default
+CPPUNIT_TEST_SUITE_REGISTRATION( WeakRefTestCase );
+
+// also include in it's own registry so that these tests can be run alone
+CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( WeakRefTestCase, "WeakRefTestCase" );
+
+void WeakRefTestCase::DeclareTest()
+{
+ {
+ wxObject o; // Should not work
+ wxEvtHandler eh;
+ wxObjectTrackable ot;
+
+ // Test declare when T is wxObject
+ // wxWeakRef<wxObject> wro1(&o); // Gives compile time failure
+ wxWeakRef<wxEvtHandler> wro2(&eh);
+ wxWeakRef<wxObjectTrackable> wro3(&ot);
+
+ CPPUNIT_ASSERT( wro2.get() == &eh );
+ CPPUNIT_ASSERT( wro3.get() == &ot );
+
+ // Test accessing wxObject members
+ CPPUNIT_ASSERT( !wro2->GetRefData() );
+ CPPUNIT_ASSERT( !wro3->GetRefData() );
+
+
+ wxWeakRef<wxEvtHandler> wreh(&eh);
+ wxWeakRef<wxObjectTrackable> wrot(&ot);
+
+ CPPUNIT_ASSERT( wreh.get() == &eh );
+ CPPUNIT_ASSERT( wrot.get() == &ot );
+ }
+}
+
+void WeakRefTestCase::AssignTest()
+{
+ wxWeakRef<wxEvtHandler> wro1;
+ wxWeakRef<wxObjectTrackable> wro2;
+
+ { // Scope for object destruction
+ wxEvtHandler eh;
+ wxObjectTrackable ot;
+
+ wro1 = &eh;
+ wro2 = &ot;
+
+ CPPUNIT_ASSERT( wro1.get() == &eh );
+ CPPUNIT_ASSERT( wro2.get() == &ot );
+ }
+
+ // Should be reset now
+ CPPUNIT_ASSERT( !wro1 );
+ CPPUNIT_ASSERT( !wro2 );
+}
+
+void WeakRefTestCase::AssignWeakRefTest()
+{
+ // Test declare when T is wxObject
+ wxWeakRef<wxEvtHandler> wro1;
+ wxWeakRef<wxObjectTrackable> wro2;
+
+ { // Scope for object destruction
+ wxEvtHandler eh;
+ wxObjectTrackable ot;
+ wxWeakRef<wxEvtHandler> wro3;
+ wxWeakRef<wxObjectTrackable> wro4;
+
+ wro1 = &eh;
+ wro2 = &ot;
+ wro3 = wro1;
+ wro4 = wro2;
+
+ CPPUNIT_ASSERT( wro1.get() == &eh );
+ CPPUNIT_ASSERT( wro2.get() == &ot );
+ CPPUNIT_ASSERT( wro3.get() == &eh );
+ CPPUNIT_ASSERT( wro4.get() == &ot );
+
+ wro4.Release();
+ CPPUNIT_ASSERT( !wro4.get() );
+ }
+
+ // Should be reset now
+ CPPUNIT_ASSERT( !wro1 );
+ CPPUNIT_ASSERT( !wro2 );
+}
+
+void WeakRefTestCase::MultiAssignTest()
+{
+ // Object is tracked by several refs
+ wxEvtHandler *peh = new wxEvtHandler;
+
+ // Test declare when T is wxObject
+ wxWeakRef<wxEvtHandler> wro1(peh);
+ wxWeakRef<wxEvtHandler> wro2(peh);
+
+ wxObjectTrackable *pot = new wxObjectTrackable;
+ wxWeakRef<wxObjectTrackable> wro3 = pot;
+ wxWeakRef<wxObjectTrackable> wro4 = pot;
+
+ CPPUNIT_ASSERT( wro1.get() == peh );
+ CPPUNIT_ASSERT( wro2.get() == peh );
+ CPPUNIT_ASSERT( wro3.get() == pot );
+ CPPUNIT_ASSERT( wro4.get() == pot );
+
+ delete peh;
+ delete pot;
+
+ // Should be reset now
+ CPPUNIT_ASSERT( !wro1 );
+ CPPUNIT_ASSERT( !wro2 );
+ CPPUNIT_ASSERT( !wro3 );
+ CPPUNIT_ASSERT( !wro4 );
+}
+
+void WeakRefTestCase::CleanupTest()
+{
+ // Make sure that trackable objects have no left over tracker nodes after use.
+ // This time the references goes out of scope before the objects.
+ wxEvtHandler eh;
+ wxObjectTrackable ots;
+ wxObjectTrackable otd;
+
+ { // Scope for object destruction
+ wxWeakRef<wxEvtHandler> wro1;
+ wxWeakRef<wxEvtHandler> wro2;
+ wxWeakRef<wxObjectTrackable> wro3;
+ wxWeakRef<wxObjectTrackable> wro4;
+
+ wro1 = &eh;
+ wro2 = &eh; // Has two tracker nodes now
+ wro3 = &ots;
+ wro4 = &otd;
+
+ // Access members of reffed object
+ wro3->TestFunc();
+
+ CPPUNIT_ASSERT( eh.GetFirst()==&wro2 );
+ CPPUNIT_ASSERT( ots.wxTrackable::GetFirst()==&wro3 );
+ CPPUNIT_ASSERT( otd.wxTrackable::GetFirst()==&wro4 );
+ }
+
+ // Should be reset now
+ CPPUNIT_ASSERT( !eh.GetFirst() );
+ CPPUNIT_ASSERT( !ots.wxTrackable::GetFirst() );
+ CPPUNIT_ASSERT( !otd.wxTrackable::GetFirst() );
+}
+
+void WeakRefTestCase::DeleteTest()
+{
+ // Object is tracked by several refs
+ wxEvtHandler *peh = new wxEvtHandler;
+
+ // Declared derived type of object and test deleting it
+ wxEvtHandlerRef wre(peh);
+ wxWeakRef<wxEvtHandler> wro(peh);
+
+ // test size of references (see that it has selected right base class)
+#ifdef HAVE_PARTIAL_SPECIALIZATION
+ CPPUNIT_ASSERT_EQUAL( sizeof(void*)*3, sizeof(wre) );
+ CPPUNIT_ASSERT_EQUAL( sizeof(void*)*4, sizeof(wro) );
+#else
+ CPPUNIT_ASSERT_EQUAL( sizeof(void*)*3, sizeof(wre) );
+ CPPUNIT_ASSERT_EQUAL( sizeof(void*)*3, sizeof(wro) );
+#endif
+
+ CPPUNIT_ASSERT( wre.get() == peh );
+ CPPUNIT_ASSERT( wro.get() == peh );
+
+ delete wre.get();
+
+ CPPUNIT_ASSERT( !wre );
+ CPPUNIT_ASSERT( !wro );
+}
+
+#ifdef HAVE_DYNAMIC_CAST
+
+void WeakRefTestCase::DynamicRefTest()
+{
+ wxWeakRefDynamic<wxEvtHandler> wro1;
+ wxWeakRefDynamic<wxObjectTrackable> wro2;
+ wxWeakRefDynamic<wxObjectTrackable> wro3;
+
+ { // Scope for object destruction
+ {
+ wxEvtHandler eh;
+ wro1 = &eh;
+ }
+
+ CPPUNIT_ASSERT( !wro1 );
+
+ wxObjectTrackable otd1;
+ wxObjectTrackable otd2;
+ wro2 = &otd1;
+ wro3 = &otd2;
+
+ CPPUNIT_ASSERT( wro2.get() == &otd1 );
+ CPPUNIT_ASSERT( wro3.get() == &otd2 );
+
+ wro3 = wro2;
+ CPPUNIT_ASSERT( wro2.get() == &otd1 );
+ CPPUNIT_ASSERT( wro3.get() == &otd1 );
+ }
+
+ // Should be reset now
+ CPPUNIT_ASSERT( !wro2 );
+ CPPUNIT_ASSERT( !wro3 );
+}
+
+#endif // HAVE_DYNAMIC_CAST