]> git.saurik.com Git - wxWidgets.git/blob - src/common/object.cpp
1. small fix in wxDirDialog: SHBrowseForFolder() doesn't like '/'s
[wxWidgets.git] / src / common / object.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: object.cpp
3 // Purpose: wxObject implementation
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "object.h"
14 #endif
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22
23 #ifndef WX_PRECOMP
24 #include "wx/hash.h"
25 #if wxUSE_SERIAL
26 #include "wx/objstrm.h"
27 #include "wx/serbase.h"
28
29 // for error messages
30 #include "wx/log.h"
31 #include "wx/intl.h"
32 #endif // wxUSE_SERIAL
33 #endif // WX_PRECOMP
34
35 #include <string.h>
36 #include <assert.h>
37
38 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
39 #include "wx/memory.h"
40 #endif
41
42 #if defined(__WXDEBUG__) || wxUSE_DEBUG_CONTEXT
43 // for wxObject::Dump
44 #include "wx/ioswrap.h"
45 #endif
46
47 wxClassInfo wxObject::sm_classwxObject((wxChar *) wxT("wxObject"), (wxChar *) NULL, (wxChar *) NULL, (int ) sizeof(wxObject), (wxObjectConstructorFn) NULL);
48 wxClassInfo* wxClassInfo::sm_first = (wxClassInfo *) NULL;
49 wxHashTable* wxClassInfo::sm_classTable = (wxHashTable*) NULL;
50
51 /*
52 * wxWindows root object.
53 */
54
55 wxObject::wxObject()
56 {
57 m_refData = (wxObjectRefData *) NULL;
58 #if wxUSE_SERIAL
59 m_serialObj = (wxObject_Serialize *)NULL;
60 #endif
61 }
62
63 wxObject::~wxObject()
64 {
65 UnRef();
66 #if wxUSE_SERIAL
67 if (m_serialObj)
68 delete m_serialObj;
69 #endif
70 }
71
72 /*
73 * Is this object a kind of (a subclass of) 'info'?
74 * E.g. is wxWindow a kind of wxObject?
75 * Go from this class to superclass, taking into account
76 * two possible base classes.
77 */
78
79 bool wxObject::IsKindOf(wxClassInfo *info) const
80 {
81 wxClassInfo *thisInfo = GetClassInfo();
82 if (thisInfo)
83 return thisInfo->IsKindOf(info);
84 else
85 return FALSE;
86 }
87
88 wxObject *wxObject::Clone() const
89 {
90 wxObject *object = GetClassInfo()->CreateObject();
91 CopyObject(*object);
92 return object;
93 }
94
95 #ifdef __WXDEBUG__
96 void wxObject::CopyObject(wxObject& object_dest) const
97 #else // !Debug
98 void wxObject::CopyObject(wxObject& WXUNUSED(object_dest)) const
99 #endif // Debug/!Debug
100 {
101 wxASSERT(object_dest.GetClassInfo()->IsKindOf(GetClassInfo()));
102 }
103
104 #if wxUSE_STD_IOSTREAM && (defined(__WXDEBUG__) || wxUSE_DEBUG_CONTEXT)
105 void wxObject::Dump(ostream& str)
106 {
107 if (GetClassInfo() && GetClassInfo()->GetClassName())
108 str << GetClassInfo()->GetClassName();
109 else
110 str << "unknown object class";
111 }
112 #endif
113
114 #if defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING
115
116 #ifdef new
117 #undef new
118 #endif
119
120 void *wxObject::operator new (size_t size, wxChar * fileName, int lineNum)
121 {
122 return wxDebugAlloc(size, fileName, lineNum, TRUE);
123 }
124
125 void wxObject::operator delete (void * buf)
126 {
127 wxDebugFree(buf);
128 }
129
130 // VC++ 6.0
131 #if defined(__VISUALC__) && (__VISUALC__ >= 1200)
132 void wxObject::operator delete(void* pData, char* /* fileName */, int /* lineNum */)
133 {
134 ::operator delete(pData);
135 }
136 #endif
137
138 // Cause problems for VC++ - crashes
139 #if (!defined(__VISUALC__) && wxUSE_ARRAY_MEMORY_OPERATORS ) || defined(__MWERKS__)
140 void * wxObject::operator new[] (size_t size, wxChar * fileName, int lineNum)
141 {
142 return wxDebugAlloc(size, fileName, lineNum, TRUE, TRUE);
143 }
144
145 void wxObject::operator delete[] (void * buf)
146 {
147 wxDebugFree(buf, TRUE);
148 }
149 #endif
150
151 #endif
152
153 /*
154 * Class info: provides run-time class type information.
155 */
156
157 wxClassInfo::wxClassInfo(wxChar *cName, wxChar *baseName1, wxChar *baseName2, int sz, wxObjectConstructorFn constr)
158 {
159 m_className = cName;
160 m_baseClassName1 = baseName1;
161 m_baseClassName2 = baseName2;
162
163 m_objectSize = sz;
164 m_objectConstructor = constr;
165
166 m_next = sm_first;
167 sm_first = this;
168
169 m_baseInfo1 = (wxClassInfo *) NULL;
170 m_baseInfo2 = (wxClassInfo *) NULL;
171 }
172
173 wxObject *wxClassInfo::CreateObject()
174 {
175 if (m_objectConstructor)
176 return (wxObject *)(*m_objectConstructor)();
177 else
178 return (wxObject *) NULL;
179 }
180
181 wxClassInfo *wxClassInfo::FindClass(wxChar *c)
182 {
183 wxClassInfo *p = sm_first;
184 while (p)
185 {
186 if (p && p->GetClassName() && wxStrcmp(p->GetClassName(), c) == 0)
187 return p;
188 p = p->m_next;
189 }
190 return (wxClassInfo *) NULL;
191 }
192
193 // Climb upwards through inheritance hierarchy.
194 // Dual inheritance is catered for.
195 bool wxClassInfo::IsKindOf(wxClassInfo *info) const
196 {
197 if (info == NULL)
198 return FALSE;
199
200 // For some reason, when making/using a DLL, static data has to be included
201 // in both the DLL and the application. This can lead to duplicate
202 // wxClassInfo objects, so we have to test the name instead of the pointers.
203 // PROBABLY NO LONGER TRUE now I've done DLL creation right.
204 /*
205 #if WXMAKINGDLL
206 if (GetClassName() && info->GetClassName() && (wxStrcmp(GetClassName(), info->GetClassName()) == 0))
207 return TRUE;
208 #else
209 */
210 if (this == info)
211 return TRUE;
212
213 if (m_baseInfo1)
214 if (m_baseInfo1->IsKindOf(info))
215 return TRUE;
216
217 if (m_baseInfo2)
218 return m_baseInfo2->IsKindOf(info);
219
220 return FALSE;
221 }
222
223 // Set pointers to base class(es) to speed up IsKindOf
224 void wxClassInfo::InitializeClasses()
225 {
226 // using IMPLEMENT_DYNAMIC_CLASS() macro twice (which may happen if you
227 // link any object module twice mistakenly) will break this function
228 // because it will enter an infinite loop and eventually die with "out of
229 // memory" - as this is quite hard to detect if you're unaware of this,
230 // try to do some checks here
231 #ifdef __WXDEBUG__
232 // more classes than we'll ever have
233 static const size_t nMaxClasses = 10000;
234 size_t nClass = 0;
235 #endif // Debug
236
237 wxClassInfo::sm_classTable = new wxHashTable(wxKEY_STRING);
238
239 // Index all class infos by their class name
240 wxClassInfo *info = sm_first;
241 while (info)
242 {
243 if (info->m_className)
244 {
245 wxASSERT_MSG( ++nClass < nMaxClasses,
246 _T("an infinite loop detected - have you used "
247 "IMPLEMENT_DYNAMIC_CLASS() twice (may be by "
248 "linking some object module(s) twice)?") );
249
250 sm_classTable->Put(info->m_className, (wxObject *)info);
251 }
252
253 info = info->m_next;
254 }
255
256 // Set base pointers for each wxClassInfo
257 info = sm_first;
258 while (info)
259 {
260 if (info->GetBaseClassName1())
261 info->m_baseInfo1 = (wxClassInfo *)sm_classTable->Get(info->GetBaseClassName1());
262 if (info->GetBaseClassName2())
263 info->m_baseInfo2 = (wxClassInfo *)sm_classTable->Get(info->GetBaseClassName2());
264 info = info->m_next;
265 }
266 }
267
268 void wxClassInfo::CleanUpClasses()
269 {
270 delete wxClassInfo::sm_classTable;
271 wxClassInfo::sm_classTable = NULL;
272 }
273
274 wxObject *wxCreateDynamicObject(const wxChar *name)
275 {
276 if (wxClassInfo::sm_classTable)
277 {
278 wxClassInfo *info = (wxClassInfo *)wxClassInfo::sm_classTable->Get(name);
279 if (!info)
280 return (wxObject *)NULL;
281
282 return info->CreateObject();
283 }
284 else
285 {
286 wxClassInfo *info = wxClassInfo::sm_first;
287 while (info)
288 {
289 if (info->m_className && wxStrcmp(info->m_className, name) == 0)
290 return info->CreateObject();
291 info = info->m_next;
292 }
293 return (wxObject*) NULL;
294 }
295 }
296
297 #if wxUSE_SERIAL
298
299 #include "wx/serbase.h"
300 #include "wx/dynlib.h"
301
302 wxObject* wxCreateStoredObject( wxInputStream &stream )
303 {
304 wxObjectInputStream obj_s(stream);
305 return obj_s.LoadObject();
306 };
307
308 void wxObject::StoreObject( wxObjectOutputStream& stream )
309 {
310 wxString obj_name = wxString(GetClassInfo()->GetClassName()) + "_Serialize";
311 wxLibrary *lib = wxTheLibraries.LoadLibrary("wxserial");
312
313 if (!lib) {
314 wxLogError(_("Can't load wxSerial dynamic library."));
315 return;
316 }
317 if (!m_serialObj) {
318 m_serialObj = (WXSERIAL(wxObject) *)lib->CreateObject( obj_name );
319
320 if (!m_serialObj) {
321 wxLogError(_("Can't find the serialization object '%s' "
322 "for the object '%s'."),
323 obj_name.c_str(),
324 GetClassInfo()->GetClassName());
325 return;
326 }
327 m_serialObj->SetObject(this);
328 }
329
330 m_serialObj->StoreObject(stream);
331 }
332
333 void wxObject::LoadObject( wxObjectInputStream& stream )
334 {
335 wxString obj_name = wxString(GetClassInfo()->GetClassName()) + "_Serialize";
336 wxLibrary *lib = wxTheLibraries.LoadLibrary("wxserial");
337
338 if (!m_serialObj) {
339 m_serialObj = (WXSERIAL(wxObject) *)lib->CreateObject( obj_name );
340
341 if (!m_serialObj) {
342 wxLogError(_("Can't find the serialization object '%s' "
343 "for the object '%s'."),
344 obj_name.c_str(),
345 GetClassInfo()->GetClassName());
346 return;
347 }
348 m_serialObj->SetObject(this);
349 }
350
351 m_serialObj->LoadObject(stream);
352 }
353
354 #endif // wxUSE_SERIAL
355
356 /*
357 * wxObject: cloning of objects
358 */
359
360 void wxObject::Ref(const wxObject& clone)
361 {
362 // delete reference to old data
363 UnRef();
364 // reference new data
365 if (clone.m_refData) {
366 m_refData = clone.m_refData;
367 ++(m_refData->m_count);
368 }
369 }
370
371 void wxObject::UnRef()
372 {
373 if ( m_refData )
374 {
375 wxASSERT_MSG( m_refData->m_count > 0, _T("invalid ref data count") );
376
377 if ( !--m_refData->m_count )
378 delete m_refData;
379
380 m_refData = (wxObjectRefData *) NULL;
381 }
382 }
383
384 /*
385 * wxObjectData
386 */
387
388 wxObjectRefData::wxObjectRefData(void) : m_count(1)
389 {
390 }
391
392 wxObjectRefData::~wxObjectRefData()
393 {
394 }
395
396 // These are here so we can avoid 'always true/false' warnings
397 // by referring to these instead of TRUE/FALSE
398 const bool wxTrue = TRUE;
399 const bool wxFalse = FALSE;