Work on streams of all sorts. More to come.
[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 #if !USE_SHARED_LIBRARY
48 wxClassInfo wxObject::sm_classwxObject((wxChar *) _T("wxObject"), (wxChar *) NULL, (wxChar *) NULL, (int ) sizeof(wxObject), (wxObjectConstructorFn) NULL);
49 wxClassInfo* wxClassInfo::sm_first = (wxClassInfo *) NULL;
50 wxHashTable* wxClassInfo::sm_classTable = (wxHashTable*) NULL;
51 #endif
52
53 /*
54 * wxWindows root object.
55 */
56
57 wxObject::wxObject()
58 {
59 m_refData = (wxObjectRefData *) NULL;
60 #if wxUSE_SERIAL
61 m_serialObj = (wxObject_Serialize *)NULL;
62 #endif
63 }
64
65 wxObject::~wxObject()
66 {
67 UnRef();
68 #if wxUSE_SERIAL
69 if (m_serialObj)
70 delete m_serialObj;
71 #endif
72 }
73
74 /*
75 * Is this object a kind of (a subclass of) 'info'?
76 * E.g. is wxWindow a kind of wxObject?
77 * Go from this class to superclass, taking into account
78 * two possible base classes.
79 */
80
81 bool wxObject::IsKindOf(wxClassInfo *info) const
82 {
83 wxClassInfo *thisInfo = GetClassInfo();
84 if (thisInfo)
85 return thisInfo->IsKindOf(info);
86 else
87 return FALSE;
88 }
89
90 wxObject *wxObject::Clone() const
91 {
92 wxObject *object = GetClassInfo()->CreateObject();
93 CopyObject(*object);
94 return object;
95 }
96
97 void wxObject::CopyObject(wxObject& object_dest) const
98 {
99 wxASSERT(object_dest.GetClassInfo()->IsKindOf(GetClassInfo()));
100 }
101
102 #if wxUSE_STD_IOSTREAM && (defined(__WXDEBUG__) || wxUSE_DEBUG_CONTEXT)
103 void wxObject::Dump(ostream& str)
104 {
105 if (GetClassInfo() && GetClassInfo()->GetClassName())
106 str << GetClassInfo()->GetClassName();
107 else
108 str << "unknown object class";
109 }
110 #endif
111
112 #if defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING
113
114 #ifdef new
115 #undef new
116 #endif
117
118 void *wxObject::operator new (size_t size, wxChar * fileName, int lineNum)
119 {
120 return wxDebugAlloc(size, fileName, lineNum, TRUE);
121 }
122
123 void wxObject::operator delete (void * buf)
124 {
125 wxDebugFree(buf);
126 }
127
128 // VC++ 6.0
129 #if defined(__VISUALC__) && (__VISUALC__ >= 1200)
130 void wxObject::operator delete(void* pData, char* /* fileName */, int /* lineNum */)
131 {
132 ::operator delete(pData);
133 }
134 #endif
135
136 // Cause problems for VC++ - crashes
137 #if !defined(__VISUALC__) && wxUSE_ARRAY_MEMORY_OPERATORS
138 void * wxObject::operator new[] (size_t size, wxChar * fileName, int lineNum)
139 {
140 return wxDebugAlloc(size, fileName, lineNum, TRUE, TRUE);
141 }
142
143 void wxObject::operator delete[] (void * buf)
144 {
145 wxDebugFree(buf, TRUE);
146 }
147 #endif
148
149 #endif
150
151 /*
152 * Class info: provides run-time class type information.
153 */
154
155 wxClassInfo::wxClassInfo(wxChar *cName, wxChar *baseName1, wxChar *baseName2, int sz, wxObjectConstructorFn constr)
156 {
157 m_className = cName;
158 m_baseClassName1 = baseName1;
159 m_baseClassName2 = baseName2;
160
161 m_objectSize = sz;
162 m_objectConstructor = constr;
163
164 m_next = sm_first;
165 sm_first = this;
166
167 m_baseInfo1 = (wxClassInfo *) NULL;
168 m_baseInfo2 = (wxClassInfo *) NULL;
169 }
170
171 wxObject *wxClassInfo::CreateObject()
172 {
173 if (m_objectConstructor)
174 return (wxObject *)(*m_objectConstructor)();
175 else
176 return (wxObject *) NULL;
177 }
178
179 wxClassInfo *wxClassInfo::FindClass(wxChar *c)
180 {
181 wxClassInfo *p = sm_first;
182 while (p)
183 {
184 if (p && p->GetClassName() && wxStrcmp(p->GetClassName(), c) == 0)
185 return p;
186 p = p->m_next;
187 }
188 return (wxClassInfo *) NULL;
189 }
190
191 // Climb upwards through inheritance hierarchy.
192 // Dual inheritance is catered for.
193 bool wxClassInfo::IsKindOf(wxClassInfo *info) const
194 {
195 if (info == NULL)
196 return FALSE;
197
198 // For some reason, when making/using a DLL, static data has to be included
199 // in both the DLL and the application. This can lead to duplicate
200 // wxClassInfo objects, so we have to test the name instead of the pointers.
201 // PROBABLY NO LONGER TRUE now I've done DLL creation right.
202 /*
203 #if WXMAKINGDLL
204 if (GetClassName() && info->GetClassName() && (strcmp(GetClassName(), info->GetClassName()) == 0))
205 return TRUE;
206 #else
207 */
208 if (this == info)
209 return TRUE;
210
211 if (m_baseInfo1)
212 if (m_baseInfo1->IsKindOf(info))
213 return TRUE;
214
215 if (m_baseInfo2)
216 return m_baseInfo2->IsKindOf(info);
217
218 return FALSE;
219 }
220
221 // Set pointers to base class(es) to speed up IsKindOf
222 void wxClassInfo::InitializeClasses()
223 {
224 wxClassInfo::sm_classTable = new wxHashTable(wxKEY_STRING);
225
226 // Index all class infos by their class name
227 wxClassInfo *info = sm_first;
228 while (info)
229 {
230 if (info->m_className)
231 sm_classTable->Put(info->m_className, (wxObject *)info);
232 info = info->m_next;
233 }
234
235 // Set base pointers for each wxClassInfo
236 info = sm_first;
237 while (info)
238 {
239 if (info->GetBaseClassName1())
240 info->m_baseInfo1 = (wxClassInfo *)sm_classTable->Get(info->GetBaseClassName1());
241 if (info->GetBaseClassName2())
242 info->m_baseInfo2 = (wxClassInfo *)sm_classTable->Get(info->GetBaseClassName2());
243 info = info->m_next;
244 }
245 }
246
247 void wxClassInfo::CleanUpClasses()
248 {
249 delete wxClassInfo::sm_classTable;
250 wxClassInfo::sm_classTable = NULL;
251 }
252
253 wxObject *wxCreateDynamicObject(const wxChar *name)
254 {
255 if (wxClassInfo::sm_classTable)
256 {
257 wxClassInfo *info = (wxClassInfo *)wxClassInfo::sm_classTable->Get(name);
258 if (!info)
259 return (wxObject *)NULL;
260
261 return info->CreateObject();
262 }
263 else
264 {
265 wxClassInfo *info = wxClassInfo::sm_first;
266 while (info)
267 {
268 if (info->m_className && wxStrcmp(info->m_className, name) == 0)
269 return info->CreateObject();
270 info = info->m_next;
271 }
272 return (wxObject*) NULL;
273 }
274 return (wxObject*) NULL;
275 }
276
277 #if wxUSE_SERIAL
278
279 #include "wx/serbase.h"
280 #include "wx/dynlib.h"
281 #include "wx/msgdlg.h"
282
283 wxObject* wxCreateStoredObject( wxInputStream &stream )
284 {
285 wxObjectInputStream obj_s(stream);
286 return obj_s.LoadObject();
287 };
288
289 void wxObject::StoreObject( wxObjectOutputStream& stream )
290 {
291 wxString obj_name = wxString(GetClassInfo()->GetClassName()) + "_Serialize";
292 wxLibrary *lib = wxTheLibraries.LoadLibrary("wxserial");
293
294 if (!lib) {
295 wxLogError(_("Can't load wxSerial dynamic library."));
296 return;
297 }
298 if (!m_serialObj) {
299 m_serialObj = (WXSERIAL(wxObject) *)lib->CreateObject( obj_name );
300
301 if (!m_serialObj) {
302 wxLogError(_("Can't find the serialization object '%s' "
303 "for the object '%s'."),
304 obj_name.c_str(),
305 GetClassInfo()->GetClassName());
306 return;
307 }
308 m_serialObj->SetObject(this);
309 }
310
311 m_serialObj->StoreObject(stream);
312 }
313
314 void wxObject::LoadObject( wxObjectInputStream& stream )
315 {
316 wxString obj_name = wxString(GetClassInfo()->GetClassName()) + "_Serialize";
317 wxLibrary *lib = wxTheLibraries.LoadLibrary("wxserial");
318
319 if (!m_serialObj) {
320 m_serialObj = (WXSERIAL(wxObject) *)lib->CreateObject( obj_name );
321
322 if (!m_serialObj) {
323 wxLogError(_("Can't find the serialization object '%s' "
324 "for the object '%s'."),
325 obj_name.c_str(),
326 GetClassInfo()->GetClassName());
327 return;
328 }
329 m_serialObj->SetObject(this);
330 }
331
332 m_serialObj->LoadObject(stream);
333 }
334
335 #endif // wxUSE_SERIAL
336
337 /*
338 * wxObject: cloning of objects
339 */
340
341 void wxObject::Ref(const wxObject& clone)
342 {
343 // delete reference to old data
344 UnRef();
345 // reference new data
346 if (clone.m_refData) {
347 m_refData = clone.m_refData;
348 ++(m_refData->m_count);
349 }
350 }
351
352 void wxObject::UnRef()
353 {
354 if (m_refData) {
355 assert(m_refData->m_count > 0);
356 --(m_refData->m_count);
357 if (m_refData->m_count == 0)
358 delete m_refData;
359 }
360 m_refData = (wxObjectRefData *) NULL;
361 }
362
363 /*
364 * wxObjectData
365 */
366
367 wxObjectRefData::wxObjectRefData(void) : m_count(1)
368 {
369 }
370
371 wxObjectRefData::~wxObjectRefData()
372 {
373 }
374
375 // These are here so we can avoid 'always true/false' warnings
376 // by referring to these instead of TRUE/FALSE
377 const bool wxTrue = TRUE;
378 const bool wxFalse = FALSE;