]>
Commit | Line | Data |
---|---|---|
bd9396d5 HH |
1 | ///////////////////////////////////////////////////////////////////////////// |
2 | // Name: No names yet. | |
3 | // Purpose: Contrib. demo | |
4 | // Author: Aleksandras Gluchovas | |
5 | // Modified by: | |
6 | // Created: 26/10/98 | |
7 | // RCS-ID: $Id$ | |
8 | // Copyright: (c) Aleksandras Gluchovas | |
9 | // Licence: wxWindows license | |
10 | ///////////////////////////////////////////////////////////////////////////// | |
11 | ||
12 | #ifdef __GNUG__ | |
13 | #pragma implementation "objstore.h" | |
14 | // #pragma interface | |
15 | #endif | |
16 | ||
17 | // For compilers that support precompilation, includes "wx.h". | |
18 | #include "wx/wxprec.h" | |
19 | ||
20 | #ifdef __BORLANDC__ | |
21 | #pragma hdrstop | |
22 | #endif | |
23 | ||
24 | #ifndef WX_PRECOMP | |
25 | #include "wx/wx.h" | |
26 | #endif | |
27 | ||
28 | #include <fstream.h> | |
29 | #include "objstore.h" | |
30 | #include <string.h> | |
31 | ||
32 | // FIXME:: | |
33 | // BUG?:: somehow assertion statements with oritinal wxASSERT do not get compiled in | |
34 | ||
35 | //#undef wxASSERT | |
36 | //#define wxASSERT(x) if ( !(x) ) throw; | |
37 | ||
38 | /***** Implementation for class wxSerializerInfo *****/ | |
39 | ||
40 | bool wxSerializerInfo::alreadyInitialized = FALSE; | |
41 | wxSerializerInfo *wxSerializerInfo::first = NULL; | |
42 | wxHashTable wxSerializerInfo::serInfoHash; | |
43 | ||
44 | wxSerializerInfo::wxSerializerInfo( char* theClassName, | |
45 | wxObjectSerializationFn serializationFun, | |
46 | wxObjectInitializationFn initializationFun, | |
47 | char* classVersionName | |
48 | ) | |
49 | : classInfo ( NULL ), | |
50 | next ( NULL ), | |
51 | nextByVersion( NULL ), | |
52 | className ( theClassName ), | |
53 | serFn ( serializationFun ), | |
54 | initFn ( initializationFun ), | |
55 | classVersion ( classVersionName ) | |
56 | { | |
57 | next = first; | |
58 | ||
59 | first = this; | |
60 | } | |
61 | ||
62 | int serializer_ver_cmp_fun( const void* arg1, const void* arg2 ) | |
63 | { | |
64 | // "no-version" is considered being the highest version | |
65 | ||
66 | if ( ((wxSerializerInfo*)arg1)->classVersion == NO_CLASS_VER ) | |
67 | { | |
68 | // DBG:: two serializers for the same version of the class should not be present! | |
69 | wxASSERT( ((wxSerializerInfo*)arg1)->classVersion != NO_CLASS_VER ); | |
70 | ||
71 | return -1; // (inverted already) | |
72 | } | |
73 | ||
74 | if ( ((wxSerializerInfo*)arg2)->classVersion == NO_CLASS_VER ) | |
75 | { | |
76 | // DBG:: two serializers for the same version of the class should not be present! | |
77 | wxASSERT( ((wxSerializerInfo*)arg1)->classVersion != NO_CLASS_VER ); | |
78 | ||
79 | return 1; // (inverted already) | |
80 | } | |
81 | ||
82 | // versions are compared lexicographically ignoring the char-case | |
83 | ||
84 | wxString v1( ((wxSerializerInfo*)arg1)->classVersion ); | |
85 | wxString v2( ((wxSerializerInfo*)arg2)->classVersion ); | |
86 | ||
87 | bool result = v1.CompareTo( v2, wxString::ignoreCase ); | |
88 | ||
89 | // DBG:: two serializers for the same version of the class should not be present! | |
90 | wxASSERT( result == FALSE ); | |
91 | ||
92 | // invert the sense of "greater than" for storting in decreasing order | |
93 | ||
94 | return ( result > 0 ) ? -1 : 1; | |
95 | } | |
96 | ||
97 | void wxSerializerInfo::InitializeSerializers(void) | |
98 | { | |
99 | if ( alreadyInitialized ) return; | |
100 | ||
101 | alreadyInitialized = TRUE; | |
102 | ||
103 | wxSerializerInfo* pCur = first; | |
104 | ||
105 | // first resolve references to class information structures | |
106 | ||
107 | while( pCur ) | |
108 | { | |
109 | pCur->classInfo = wxClassInfo::FindClass( pCur->className ); | |
110 | ||
111 | wxASSERT( pCur->classInfo ); // DBG:: class info should already be present somewhere! | |
112 | ||
113 | // check if serializer for the class is already present, | |
114 | ||
115 | wxSerializerInfo* pFound = (wxSerializerInfo*)serInfoHash.Get( (long)pCur->classInfo ); | |
116 | ||
117 | if ( pFound ) | |
118 | { | |
119 | // if present, then it must be serializer for the certain version of that class, | |
120 | // put it at the end of the chain of versioned serializers for that class | |
121 | ||
122 | // go to the end of chain | |
123 | ||
124 | while( pFound->nextByVersion ) pFound = pFound->nextByVersion; | |
125 | ||
126 | // append it | |
127 | ||
128 | pFound->nextByVersion = pCur; | |
129 | ||
130 | pCur->next = (wxSerializerInfo*)(-1); // label it as member of local chain | |
131 | // of "versioned" serializers | |
132 | ||
133 | pCur->nextByVersion = NULL; | |
134 | } | |
135 | else | |
136 | { | |
137 | // otherwise, serializer for the class found for the first time - | |
138 | // hash it | |
139 | ||
140 | serInfoHash.Put( (long)pCur->classInfo, (wxObject*)pCur ); | |
141 | ||
142 | // and include it to the list of serializers for the highest-versions | |
143 | pCur = pCur->next; | |
144 | } | |
145 | } | |
146 | ||
147 | // sort chains of "versioned" serializers in the order of decreasing version | |
148 | // | |
149 | // (since, when loading, the newest version of an object | |
150 | // is expected first, rather then the older one) | |
151 | ||
152 | wxSerializerInfo* pPrev = NULL; | |
153 | pCur = first; | |
154 | ||
155 | while ( pCur ) | |
156 | { | |
157 | // chain present? | |
158 | ||
159 | if ( pCur->nextByVersion ) | |
160 | { | |
161 | // sort it | |
162 | ||
163 | wxSerializerInfo* pStart = pCur; | |
164 | wxSerializerInfo* pNext = pCur->next; | |
165 | ||
166 | // let wxList do the sorting, we're too lazy :) | |
167 | ||
168 | wxList sorted; | |
169 | ||
170 | while( pCur ) | |
171 | { | |
172 | sorted.Append( (wxObject*) pCur ); | |
173 | ||
174 | pCur = pCur->nextByVersion; | |
175 | } | |
176 | ||
177 | sorted.Sort( serializer_ver_cmp_fun ); | |
178 | ||
179 | wxNode* pNode = sorted.First(); | |
180 | ||
181 | while( pNode ) | |
182 | { | |
183 | wxSerializerInfo* pInfo = (wxSerializerInfo*)pNode->Data(); | |
184 | ||
185 | if ( pNode == sorted.First() ) | |
186 | { | |
187 | // make node with the highest version, a member of the global | |
188 | // list of serializers | |
189 | ||
190 | if ( pPrev ) pPrev->next = pInfo; | |
191 | else first = pInfo; | |
192 | ||
193 | pInfo->next = pNext; | |
194 | } | |
195 | else | |
196 | pInfo->next = (wxSerializerInfo*)(-1); // otherwise label it as a member of local | |
197 | // chain of "versioned" serializers | |
198 | ||
199 | if ( pNode->Next() ) | |
200 | { | |
201 | pInfo->nextByVersion = (wxSerializerInfo*)( pNode->Next()->Data() ); | |
202 | } | |
203 | else | |
204 | pInfo->nextByVersion = 0; | |
205 | ||
206 | pNode = pNode->Next(); | |
207 | } | |
208 | ||
209 | } // end of if ( nextByVersion ) | |
210 | ||
211 | pPrev = pCur; | |
212 | pCur = pCur->next; | |
213 | ||
214 | } // end of while(...) | |
215 | } | |
216 | ||
217 | wxSerializerInfo* wxSerializerInfo::FindSerializer( char* className ) | |
218 | { | |
219 | wxSerializerInfo::InitializeSerializers(); | |
220 | ||
221 | wxSerializerInfo* pInfo = (wxSerializerInfo*) | |
222 | ||
223 | serInfoHash.Get( (long)wxClassInfo::FindClass( className ) ); | |
224 | ||
225 | return pInfo; | |
226 | } | |
227 | ||
228 | static void invoke_for_inherited( wxObject* pObj, wxClassInfo* pCInfo, wxObjectStorage* pStore, bool invokeSerFn ) | |
229 | { | |
230 | wxSerializerInfo* pSrzInfo = (wxSerializerInfo*) | |
231 | ||
232 | wxSerializerInfo::serInfoHash.Get( (long)wxClassInfo::FindClass( pCInfo->GetClassName() ) ); | |
233 | ||
234 | if ( pSrzInfo ) | |
235 | { | |
236 | // if found, serialize/initialize and don't go "any higher" | |
237 | ||
238 | if ( invokeSerFn ) | |
239 | ||
240 | (*pSrzInfo->serFn) ( pObj, *pStore ); | |
241 | else | |
242 | (*pSrzInfo->initFn)( pObj ); | |
243 | ||
244 | } | |
245 | else | |
246 | { | |
247 | // go up the hierarchy, if no serializer present for the current class | |
248 | ||
249 | if ( pCInfo->GetBaseClass1() ) | |
250 | ||
251 | invoke_for_inherited( pObj, pCInfo->GetBaseClass1(), pStore, invokeSerFn ); | |
252 | ||
253 | if ( pCInfo->GetBaseClass2() ) | |
254 | ||
255 | invoke_for_inherited( pObj, pCInfo->GetBaseClass2(), pStore, invokeSerFn ); | |
256 | } | |
257 | } | |
258 | ||
259 | void wxSerializerInfo::SerializeInherited( wxObject* pObj, wxObjectStorage& store ) | |
260 | { | |
261 | // search recursivelly up the hierarchy for serializers of base | |
262 | // classes, and invoke serialization function for the given object | |
263 | ||
264 | if ( classInfo->GetBaseClass1() ) | |
265 | ||
266 | invoke_for_inherited( pObj, classInfo->GetBaseClass1(), &store, TRUE ); | |
267 | ||
268 | if ( classInfo->GetBaseClass2() ) | |
269 | ||
270 | invoke_for_inherited( pObj, classInfo->GetBaseClass2(), &store, TRUE ); | |
271 | } | |
272 | ||
273 | void wxSerializerInfo::InitializeInherited( wxObject* pObj ) | |
274 | { | |
275 | // search recursivelly up the hierarchy for serializers of base | |
276 | // classes, and invoke initialization function for the given object | |
277 | ||
278 | if ( classInfo->GetBaseClass1() ) | |
279 | ||
280 | invoke_for_inherited( pObj, classInfo->GetBaseClass1(), NULL, FALSE ); | |
281 | ||
282 | if ( classInfo->GetBaseClass2() ) | |
283 | ||
284 | invoke_for_inherited( pObj, classInfo->GetBaseClass2(), NULL, FALSE ); | |
285 | } | |
286 | ||
287 | /***** Implementation for class wxDataStreamBase *****/ | |
288 | ||
289 | IMPLEMENT_ABSTRACT_CLASS( wxDataStreamBase, wxObject ) | |
290 | ||
291 | /***** Implementation for class wxObjectStorage *****/ | |
292 | ||
293 | // codes, used as tokens written/read from the stream | |
294 | ||
295 | enum STORED_OBJ_TYPES | |
296 | { | |
297 | SOT_NULL_POINTER = 'N', | |
298 | SOT_POINTER_TO_OBJ = 'P', | |
299 | SOT_INITIAL_REF = 'I', | |
300 | SOT_OBJ_DATA = 'D' | |
301 | }; | |
302 | ||
303 | // veraion-encoding in object-name string fromat defaults: | |
304 | ||
305 | char wxObjectStorage::mVerSepartorCh = '#'; | |
306 | char wxObjectStorage::mMinorMajorSepartorCh = '-'; | |
307 | ||
308 | IMPLEMENT_DYNAMIC_CLASS( wxObjectStorage, wxObject ) | |
309 | ||
310 | wxObjectStorage::wxObjectStorage() | |
311 | : mpStm ( 0 ), | |
312 | mIsLoading ( TRUE ), | |
313 | mInitialRefsCnt ( 0 ), | |
314 | mFinalizePending( FALSE ) | |
315 | {} | |
316 | ||
317 | wxObjectStorage::wxObjectStorage( wxDataStreamBase& stm ) | |
318 | : mpStm ( &stm ), | |
319 | mIsLoading ( stm.IsForInput() ), | |
320 | mInitialRefsCnt ( 0 ), | |
321 | mFinalizePending( FALSE ) | |
322 | { | |
323 | wxSerializerInfo::InitializeSerializers(); | |
324 | ||
325 | mFinalizePending = TRUE; // stream object was given - store/load is | |
326 | // started | |
327 | } | |
328 | ||
329 | wxObjectStorage::~wxObjectStorage() | |
330 | { | |
331 | if ( mFinalizePending ) | |
332 | ||
333 | Finalize(); // <- do it now, if "user" forgot about it | |
334 | } | |
335 | ||
336 | /*** protected members ***/ | |
337 | ||
338 | void wxObjectStorage::ClearHashesAndLists() | |
339 | { | |
340 | mNewObjs.Clear(); | |
341 | mSerializersForNewObjs.Clear(); | |
342 | mRefHash.Clear(); | |
343 | } | |
344 | ||
345 | /*** public members ***/ | |
346 | ||
347 | void wxObjectStorage::SetDataStream( wxDataStreamBase& stm ) | |
348 | { | |
349 | if ( mFinalizePending ) | |
350 | ||
351 | Finalize(); | |
352 | ||
353 | wxSerializerInfo::InitializeSerializers(); | |
354 | ||
355 | ClearHashesAndLists(); | |
356 | ||
357 | mpStm = &stm; | |
358 | ||
359 | mIsLoading = stm.IsForInput(); | |
360 | ||
361 | mFinalizePending = TRUE; | |
362 | } | |
363 | ||
364 | void wxObjectStorage::Finalize() | |
365 | { | |
366 | wxASSERT( mpStm ); // DBG:: finalize should called be after loading/storing has proceeded | |
367 | ||
368 | mFinalizePending = FALSE; | |
369 | ||
370 | if ( mIsLoading ) | |
371 | { | |
372 | // initializaiton is performed after all objects successfully | |
373 | // loaded, and references among them are established | |
374 | ||
375 | wxNode* pObjNode = mNewObjs.First(); | |
376 | wxNode* pSrzNode = mSerializersForNewObjs.First(); | |
377 | ||
378 | while( pObjNode ) | |
379 | { | |
380 | wxSerializerInfo* pSrzInfo = (wxSerializerInfo*)(pSrzNode->Data()); | |
381 | ||
382 | if ( pSrzInfo->HasInitializer() ) | |
383 | ||
384 | (*pSrzInfo->initFn)( pObjNode->Data() ); | |
385 | ||
386 | pObjNode = pObjNode->Next(); | |
387 | pSrzNode = pSrzNode->Next(); | |
388 | } | |
389 | } | |
390 | else | |
391 | // otherwise, nothing's need to be done after storing of objects is proceeded | |
392 | mpStm->Flush(); | |
393 | } | |
394 | ||
395 | // storage methods for basic types | |
396 | ||
397 | void wxObjectStorage::XchgChar( char& chObj ) | |
398 | { | |
399 | if ( mIsLoading ) mpStm->LoadChar( &chObj ); | |
400 | else mpStm->StoreChar( chObj ); | |
401 | } | |
402 | ||
403 | void wxObjectStorage::XchgInt( int& intObj ) | |
404 | { | |
405 | if ( mIsLoading ) mpStm->LoadInt( &intObj ); | |
406 | else mpStm->StoreInt( intObj ); | |
407 | } | |
408 | ||
409 | void wxObjectStorage::XchgSizeType( size_t& szObj ) | |
410 | { | |
411 | int i = int(szObj); | |
412 | ||
413 | if ( mIsLoading ) | |
414 | { | |
415 | mpStm->LoadInt( &i ); | |
416 | szObj = (size_t)i; | |
417 | } | |
418 | else | |
419 | mpStm->StoreInt( i ); | |
420 | } | |
421 | ||
422 | void wxObjectStorage::XchgLong( long& longObj ) | |
423 | { | |
424 | if ( mIsLoading ) mpStm->LoadLong( &longObj ); | |
425 | else mpStm->StoreLong( longObj ); | |
426 | } | |
427 | ||
428 | void wxObjectStorage::XchgBool( bool& boolObj ) | |
429 | { | |
430 | // bools are stored as ints | |
431 | ||
432 | if ( mIsLoading ) | |
433 | { | |
434 | int bVal = (int)boolObj; | |
435 | mpStm->LoadInt( &bVal ); | |
436 | boolObj = bVal; | |
437 | } | |
438 | else | |
439 | mpStm->StoreInt( (int)boolObj ); | |
440 | } | |
441 | ||
442 | void wxObjectStorage::XchgUInt ( unsigned int& uI ) | |
443 | { | |
444 | if ( mIsLoading ) | |
445 | { | |
446 | int uiVal = (int)uI; | |
447 | mpStm->LoadInt( &uiVal ); | |
448 | uI = (unsigned int)uiVal; | |
449 | } | |
450 | else | |
451 | mpStm->StoreInt( (int)uI ); | |
452 | } | |
453 | ||
454 | void wxObjectStorage::XchgObjList( wxList& objList ) | |
455 | { | |
456 | int count = 0; | |
457 | ||
458 | if ( mIsLoading ) | |
459 | { | |
460 | XchgInt( count ); | |
461 | ||
462 | if ( count == 0 ) return; | |
463 | ||
464 | objList.Clear(); | |
465 | } | |
466 | else | |
467 | { | |
468 | count = objList.GetCount(); | |
469 | ||
470 | XchgInt( count ); | |
471 | } | |
472 | ||
473 | // work-around for assessing operator[] which is protected in wxArrayBase | |
474 | ||
475 | if ( mIsLoading ) | |
476 | ||
477 | for( int i = 0; i != count; ++i ) | |
478 | { | |
479 | wxObject* pObj = NULL; | |
480 | ||
481 | XchgObjPtr( &pObj ); | |
482 | ||
483 | objList.Append( pObj ); | |
484 | } | |
485 | else | |
486 | { | |
487 | wxNode* pNode = objList.First(); | |
488 | ||
489 | while( pNode ) | |
490 | { | |
491 | wxObject* pObj = pNode->Data(); | |
492 | ||
493 | XchgObjPtr( &pObj ); | |
494 | ||
495 | pNode = pNode->Next(); | |
496 | } | |
497 | } | |
498 | } | |
499 | ||
500 | void wxObjectStorage::XchgObjArray ( wxBaseArray& objArr ) | |
501 | { | |
502 | int count = 0; | |
503 | ||
504 | if ( mIsLoading ) | |
505 | { | |
506 | XchgInt( count ); | |
507 | ||
508 | if ( count == 0 ) return; | |
509 | ||
510 | objArr.Clear(); | |
511 | objArr.Alloc( count ); | |
512 | } | |
513 | else | |
514 | { | |
515 | count = objArr.GetCount(); | |
516 | ||
517 | XchgInt( count ); | |
518 | } | |
519 | ||
520 | // work-around for assessing operator[] which is protected in wxArrayBase | |
521 | ||
522 | wxArrayLong& longArr = *( (wxArrayLong*) (&objArr) ); | |
523 | ||
524 | if ( mIsLoading ) | |
525 | ||
526 | for( int i = 0; i != count; ++i ) | |
527 | { | |
528 | wxObject* pObj = NULL; | |
529 | ||
530 | XchgObjPtr( &pObj ); | |
531 | ||
532 | longArr.Add( (long) pObj ); | |
533 | } | |
534 | else | |
535 | for( int i = 0; i != count; ++i ) | |
536 | { | |
537 | wxObject* pObj = (wxObject*)longArr[i]; | |
538 | ||
539 | XchgObjPtr( &pObj ); | |
540 | } | |
541 | } | |
542 | ||
543 | void wxObjectStorage::XchgLongArray( wxBaseArray& longArr ) | |
544 | { | |
545 | int count = 0; | |
546 | ||
547 | if ( mIsLoading ) | |
548 | { | |
549 | XchgInt( count ); | |
550 | ||
551 | if ( count == 0 ) return; | |
552 | ||
553 | longArr.Clear(); | |
554 | longArr.Alloc( count ); | |
555 | } | |
556 | else | |
557 | { | |
558 | count = longArr.GetCount(); | |
559 | ||
560 | XchgInt( count ); | |
561 | } | |
562 | ||
563 | // work-around for assessing operator[] which is protected in wxArrayBase | |
564 | ||
565 | wxArrayLong& realLongArr = *( (wxArrayLong*) (&longArr) ); | |
566 | ||
567 | if ( mIsLoading ) | |
568 | ||
569 | for( int i = 0; i != count; ++i ) | |
570 | { | |
571 | long l = 0; | |
572 | XchgLong( l ); | |
573 | ||
574 | realLongArr.Add( l ); | |
575 | } | |
576 | else | |
577 | for( int i = 0; i != count; ++i ) | |
578 | ||
579 | XchgLong( realLongArr[i] ); | |
580 | } | |
581 | ||
582 | void wxObjectStorage::XchgDouble( double& doubleObj ) | |
583 | { | |
584 | if ( mIsLoading ) mpStm->LoadDouble( &doubleObj ); | |
585 | else mpStm->StoreDouble( doubleObj ); | |
586 | } | |
587 | ||
588 | void wxObjectStorage::XchgCStr( char* pCStrObj ) | |
589 | { | |
590 | if ( mIsLoading ) | |
591 | { | |
592 | int len; | |
593 | mpStm->LoadInt( &len ); | |
594 | mpStm->LoadBytes( pCStrObj, len ); | |
595 | } | |
596 | else | |
597 | { | |
598 | int len = strlen( pCStrObj ) + 1; // include terminating zero | |
599 | mpStm->StoreInt( len ); | |
600 | mpStm->StoreBytes( pCStrObj, len ); | |
601 | } | |
602 | } | |
603 | ||
604 | wxSerializerInfo* wxObjectStorage::FindSrzInfoForClass( wxClassInfo* pInfo ) | |
605 | { | |
606 | wxSerializerInfo* pSrz = (wxSerializerInfo*) | |
607 | ||
608 | wxSerializerInfo::serInfoHash.Get( (long)pInfo ); | |
609 | ||
610 | if ( !pSrz ) | |
611 | { | |
612 | // look up recursivelly for serializers for of the base classes | |
613 | ||
614 | if ( pInfo->GetBaseClass1() ) | |
615 | ||
616 | return FindSrzInfoForClass( pInfo->GetBaseClass1() ); | |
617 | else | |
618 | if ( pInfo->GetBaseClass2() ) | |
619 | ||
620 | return FindSrzInfoForClass( pInfo->GetBaseClass2() ); | |
621 | else | |
622 | { | |
623 | wxASSERT(0); // DBG:: no serializers present for the given class, | |
624 | // serialization cannot proceed | |
625 | return 0; | |
626 | } | |
627 | } | |
628 | else | |
629 | return pSrz; | |
630 | } | |
631 | ||
632 | bool wxObjectStorage::VersionsMatch( char* v1, char* v2 ) | |
633 | { | |
634 | while( *v1 && *v2 ) | |
635 | { | |
636 | if ( *v1 == mMinorMajorSepartorCh || | |
637 | *v2 == mMinorMajorSepartorCh ) | |
638 | ||
639 | // minor versions are ignored | |
640 | ||
641 | return TRUE; | |
642 | ||
643 | if ( wxToUpper(*v1) != wxToUpper(*v2) ) | |
644 | ||
645 | return FALSE; | |
646 | ||
647 | ++v1; ++v2; | |
648 | } | |
649 | ||
650 | return ( *v1 == '\0' && *v2 == '\0' ); | |
651 | } | |
652 | ||
653 | bool wxObjectStorage::ExchangeObjectInfo( wxClassInfo** ppCInfo, wxSerializerInfo** ppSrz ) | |
654 | { | |
655 | char objInfoStr[512]; // FOR NOW:: fixed? | |
656 | ||
657 | if ( mIsLoading == FALSE ) | |
658 | { | |
659 | strcpy( objInfoStr, (*ppCInfo)->GetClassName() ); | |
660 | ||
661 | if ( (*ppSrz)->HasVersion() ) | |
662 | { | |
663 | char separator[2]; | |
664 | separator[2] = mVerSepartorCh; | |
665 | separator[1] = '\0'; | |
666 | ||
667 | strcat( objInfoStr, separator ); | |
668 | ||
669 | strcat( objInfoStr, (*ppSrz)->classVersion ); | |
670 | } | |
671 | ||
672 | XchgCStr( objInfoStr ); | |
673 | ||
674 | return TRUE; | |
675 | } | |
676 | ||
677 | // otherwise if loading... | |
678 | ||
679 | XchgCStr( objInfoStr ); // read string | |
680 | ||
681 | (*ppCInfo) = NULL; | |
682 | (*ppSrz) = NULL; | |
683 | ||
684 | // formal description of objInfoStr format is following (if '#' and '-' are set | |
685 | // as version and minor/major separators): | |
686 | // | |
687 | // object objInfoStr = { class_name_str , [version] } | |
688 | // | |
689 | // version = { '#', simple_version_str | major_and_minor_version_str } | |
690 | // | |
691 | // simple_version_str = any_literal | |
692 | // | |
693 | // major_and_minro_version_str = { major_version_str, '-', minro_version_str } | |
694 | // | |
695 | // major_version_str = any_literal | |
696 | // | |
697 | // inor_version_str = any_literal | |
698 | // | |
699 | // any_literal = "any string not containing '#' and '-' characters" | |
700 | // | |
701 | ||
702 | char* cur = objInfoStr; | |
703 | ||
704 | while( *cur && *cur != mVerSepartorCh ) ++cur; | |
705 | ||
706 | char last = *cur; | |
707 | ||
708 | if ( last == mVerSepartorCh ) | |
709 | ||
710 | *cur = '\0'; | |
711 | ||
712 | (*ppCInfo) = wxClassInfo::FindClass( objInfoStr ); | |
713 | ||
714 | if ( !(*ppCInfo) ) return FALSE; | |
715 | ||
716 | // get the bigining of the chain of serializers for (*ppCInfo) | |
717 | ||
718 | wxSerializerInfo* pSrz = FindSrzInfoForClass( (*ppCInfo ) ); | |
719 | ||
720 | if ( last == mVerSepartorCh ) *cur = last; // restore from temprary "termination" | |
721 | ||
722 | // find serializer which matches the version, or the serializer | |
723 | // with no version, if version is not attached to the objInfoStr | |
724 | ||
725 | if ( *cur == '\0' ) | |
726 | { | |
727 | // there's no version trailing, the "not-versioned" | |
728 | // serializer can be present only at the begining of | |
729 | // the chain | |
730 | ||
731 | if ( pSrz->HasVersion() == FALSE ) | |
732 | { | |
733 | (*ppSrz) = pSrz; | |
734 | ||
735 | return TRUE; | |
736 | } | |
737 | else | |
738 | return FALSE; | |
739 | } | |
740 | ||
741 | ++cur; // skip className<->version separator | |
742 | ||
743 | // version present, search for matching serializer down the chain | |
744 | ||
745 | if ( pSrz->HasVersion() == FALSE ) pSrz = pSrz->nextByVersion; | |
746 | ||
747 | while( pSrz ) | |
748 | { | |
749 | if ( VersionsMatch( pSrz->classVersion, cur ) ) | |
750 | { | |
751 | (*ppSrz) = pSrz; | |
752 | ||
753 | return TRUE; | |
754 | } | |
755 | ||
756 | pSrz = pSrz->nextByVersion; | |
757 | } | |
758 | ||
759 | return FALSE; // no serializers matching given version found | |
760 | } | |
761 | ||
762 | wxSerializerInfo* wxObjectStorage::GetLatestSrzForObj( wxObject* pWxObj ) | |
763 | { | |
764 | wxClassInfo* pCInfo = pWxObj->GetClassInfo(); | |
765 | ||
766 | wxASSERT( pCInfo ); // DBG:: object's class should be dynamic | |
767 | ||
768 | // find first serializer for (*pCInfo) in the chain | |
769 | ||
770 | wxSerializerInfo* pSrz = FindSrzInfoForClass( pCInfo ); | |
771 | ||
772 | wxASSERT( pSrz ); // DBG:: there should be at least one serializer of | |
773 | // the object's class, at least for it's base classes | |
774 | ||
775 | // skip not-versioned serializer at the beginng of the chain if present | |
776 | ||
777 | if ( !pSrz->HasVersion() && pSrz->nextByVersion ) | |
778 | ||
779 | pSrz = pSrz->nextByVersion; // the reminding ones are "vesioned", | |
780 | // starting from the highest version | |
781 | ||
782 | return pSrz; | |
783 | } | |
784 | ||
785 | void wxObjectStorage::DoExchangeObject( wxObject* pInstance, wxSerializerInfo& srzInfo ) | |
786 | { | |
787 | if ( mIsLoading ) | |
788 | ||
789 | // put info about already (partially) loaded object (stream-offset <=> object-ptr ) | |
790 | ||
791 | mRefHash.Put( (long)mpStm->GetStreamPos(), (wxObject*)pInstance ); | |
792 | else | |
793 | // put info about already (partially) stored object (object-ptr <=> stream-offset) | |
794 | ||
795 | mRefHash.Put( (long)(pInstance), (wxObject*)mpStm->GetStreamPos() ); | |
796 | ||
797 | if ( mIsLoading ) | |
798 | { | |
799 | mNewObjs.Append( pInstance ); | |
800 | mSerializersForNewObjs.Append( (wxObject*)&srzInfo ); | |
801 | } | |
802 | ||
803 | // now, perform actual serialization of the object | |
804 | ||
805 | (srzInfo.serFn)( pInstance, *this ); | |
806 | } | |
807 | ||
808 | // storage methods for objects and object-references | |
809 | ||
810 | void wxObjectStorage::XchgObj( wxObject* pWxObj ) | |
811 | { | |
812 | wxClassInfo* pCInfo = pWxObj->GetClassInfo(); | |
813 | ||
814 | wxASSERT( pCInfo ); // DBG:: if this fails, the object which is passed to | |
815 | // XchgObj(..) has not it's class information | |
816 | // i.e. is not a wxWindows dynamic class | |
817 | ||
818 | wxSerializerInfo* pSrz = ( mIsLoading == FALSE ) ? GetLatestSrzForObj( pWxObj ) | |
819 | : NULL; | |
820 | ||
821 | bool success = ExchangeObjectInfo( &pCInfo, &pSrz ); | |
822 | ||
823 | wxASSERT( success ); // DBG:: all info about object should be present i.e. class | |
824 | // info, serializer which matches the object's version | |
825 | // (see source of ExchangeObjectInfo() for more info) | |
826 | ||
827 | DoExchangeObject( pWxObj, *pSrz ); | |
828 | } | |
829 | ||
830 | void wxObjectStorage::XchgObjPtr( wxObject** ppWxObj ) | |
831 | { | |
832 | if ( mIsLoading ) | |
833 | { | |
834 | char token; | |
835 | mpStm->LoadChar( &token ); | |
836 | ||
837 | if ( token == (char)SOT_NULL_POINTER ) | |
838 | ||
839 | (*ppWxObj) = NULL; | |
840 | else | |
841 | if ( token == (char)SOT_POINTER_TO_OBJ ) | |
842 | { | |
843 | long ofs; // stream-offset | |
844 | ||
845 | mpStm->LoadLong( &ofs ); | |
846 | ||
847 | wxObject* pObj = (wxObject*) mRefHash.Get( ofs ); | |
848 | ||
849 | wxASSERT( pObj ); // DBG:: object (at the given stream-offset) | |
850 | // must be already loaded | |
851 | ||
852 | (*ppWxObj) = pObj; | |
853 | } | |
854 | else | |
855 | if ( token == (char)SOT_INITIAL_REF ) | |
856 | { | |
857 | long refNo; | |
858 | ||
859 | mpStm->LoadLong( &refNo ); | |
860 | ||
861 | wxASSERT( mInitialRefsCnt >= refNo ); // DBG:: inital refernce should be already added | |
862 | ||
863 | // refNo is 1-based | |
864 | (*ppWxObj) = mInitialRefs.Nth( refNo-1 )->Data(); | |
865 | } | |
866 | else | |
867 | { | |
868 | wxASSERT( token == (char)SOT_OBJ_DATA );// DBG:: other types of tokens are | |
869 | // bogous! If this happens you're | |
870 | // probably trying to load the data | |
871 | // which was stored by defferent. | |
872 | // perhaps out-dated serializers | |
873 | // | |
874 | // Use versioning mechanizm to | |
875 | // privide backwards compatiblity | |
876 | // option, among different versions | |
877 | // stored data-format | |
878 | ||
879 | ||
880 | int stmPos = mpStm->GetStreamPos(); | |
881 | ||
882 | wxClassInfo* pCInfo = 0; | |
883 | wxSerializerInfo* pSrz = 0; | |
884 | ||
885 | bool success = ExchangeObjectInfo( &pCInfo, &pSrz ); | |
886 | ||
887 | wxASSERT( success ); // DBG:: all info about object should be present | |
888 | // i.e. class info, serializer which matches the object's | |
889 | // version (see source of ExchangeObjectInfo() for more info) | |
890 | ||
891 | (*ppWxObj) = pCInfo->CreateObject(); | |
892 | ||
893 | DoExchangeObject( (*ppWxObj), *pSrz ); | |
894 | } | |
895 | } | |
896 | else | |
897 | { | |
898 | // otherwise if storing the pointer to an object | |
899 | ||
900 | // first, check if it's an initial reference | |
901 | ||
902 | long refNo = (long)mInitialRefsHash.Get( (long)(*ppWxObj) ); | |
903 | ||
904 | if ( refNo != 0 ) | |
905 | { | |
906 | mpStm->StoreChar( (char)SOT_INITIAL_REF ); | |
907 | mpStm->StoreLong( refNo ); | |
908 | ||
909 | return; | |
910 | } | |
911 | ||
912 | long streamPos = (long) mRefHash.Get( (long)(*ppWxObj) ); | |
913 | ||
914 | // check if object is already stored | |
915 | if ( streamPos != 0 ) | |
916 | { | |
917 | // store only reference to the object (in the form of stream-offset) | |
918 | ||
919 | mpStm->StoreChar( (char)SOT_POINTER_TO_OBJ ); | |
920 | mpStm->StoreLong( streamPos ); | |
921 | } | |
922 | else | |
923 | { | |
924 | // otherwise store the entire referenced object | |
925 | ||
926 | if ( (*ppWxObj) == NULL ) | |
927 | { | |
928 | mpStm->StoreChar( (char)SOT_NULL_POINTER ); // token | |
929 | return; | |
930 | } | |
931 | ||
932 | mpStm->StoreChar( (char)SOT_OBJ_DATA ); // token | |
933 | ||
934 | // store object's info and data | |
935 | XchgObj( *ppWxObj ); | |
936 | } | |
937 | } | |
938 | } | |
939 | ||
940 | // storage methods for common wxWindows objects | |
941 | ||
942 | void wxObjectStorage::XchgWxStr( wxString& str ) | |
943 | { | |
944 | if ( mIsLoading ) | |
945 | { | |
946 | long len = 0; | |
947 | mpStm->LoadLong( &len ); | |
948 | ||
949 | str = ""; | |
950 | str.Append( (char)1, len ); | |
951 | ||
952 | mpStm->LoadBytes( (char*)str.c_str(), len ); | |
953 | } | |
954 | else | |
955 | XchgCStr( (char*)str.c_str() ); | |
956 | } | |
957 | ||
958 | void wxObjectStorage::XchgWxSize( wxSize& size ) | |
959 | { | |
960 | XchgLong( size.x ); | |
961 | XchgLong( size.y ); | |
962 | } | |
963 | ||
964 | void wxObjectStorage::XchgWxPoint( wxPoint& point ) | |
965 | { | |
966 | XchgLong( point.x ); | |
967 | XchgLong( point.y ); | |
968 | } | |
969 | ||
970 | void wxObjectStorage::XchgWxRect( wxRect& rect ) | |
971 | { | |
972 | XchgLong( rect.x ); | |
973 | XchgLong( rect.y ); | |
974 | XchgLong( rect.width ); | |
975 | XchgLong( rect.height ); | |
976 | } | |
977 | ||
978 | void wxObjectStorage::AddInitialRef( wxObject* pObjRef ) | |
979 | { | |
980 | // duplicates are not accepted | |
981 | ||
982 | if ( mInitialRefsHash.Get( (long)pObjRef ) != NULL ) | |
983 | ||
984 | return; | |
985 | ||
986 | ++mInitialRefsCnt; | |
987 | ||
988 | // NOTE:: reference number is 1-based (zero is "reserved" by wxHashTable) | |
989 | ||
990 | mInitialRefs.Append( pObjRef ); | |
991 | mInitialRefsHash.Put( (long)pObjRef, (wxObject*)mInitialRefsCnt ); | |
992 | } | |
993 | ||
994 | void wxObjectStorage::ClearInitalRefs() | |
995 | { | |
996 | mInitialRefsCnt = 0; | |
997 | ||
998 | mInitialRefsHash.Clear(); | |
999 | mInitialRefsHash.Clear(); | |
1000 | } | |
1001 | ||
1002 | /***** Implementation for class wxColourSerializer *****/ | |
1003 | ||
1004 | IMPLEMENT_SERIALIZER_CLASS( wxColour, | |
1005 | wxColourSerializer, | |
1006 | wxColourSerializer::Serialize, | |
1007 | NO_CLASS_INIT ) | |
1008 | ||
1009 | void wxColourSerializer::Serialize( wxObject* pObj, wxObjectStorage& store ) | |
1010 | { | |
1011 | wxColour* pCol = (wxColour*)pObj; | |
1012 | ||
1013 | // slightly optimized | |
1014 | ||
1015 | if ( store.IsLoading() ) | |
1016 | { | |
1017 | long rgb; | |
1018 | store.XchgLong( rgb ); | |
1019 | ||
1020 | *pCol = wxColour( rgb & 0xFF, | |
1021 | ( rgb >> 8 ) & 0xFF, | |
1022 | ( rgb >> 16 ) & 0xFF ); | |
1023 | ||
1024 | } | |
1025 | else | |
1026 | { | |
1027 | long rgb = 0; | |
1028 | ||
1029 | unsigned char r = pCol->Red(),g = pCol->Green(), b = pCol->Blue(); | |
1030 | ||
1031 | rgb = ( long(r) & 0x0000FF ) | | |
1032 | ( ( long(g) << 8 ) & 0x00FF00 ) | | |
1033 | ( ( long(b) << 16 ) & 0xFF0000 ); | |
1034 | ||
1035 | store.XchgLong( rgb ); | |
1036 | } | |
1037 | } | |
1038 | ||
1039 | /***** Implementation for class wxPenSerializer *****/ | |
1040 | ||
1041 | IMPLEMENT_SERIALIZER_CLASS( wxPen, | |
1042 | wxPenSerializer, | |
1043 | wxPenSerializer::Serialize, | |
1044 | NO_CLASS_INIT ) | |
1045 | ||
1046 | void wxPenSerializer::Serialize( wxObject* pObj, wxObjectStorage& store ) | |
1047 | { | |
1048 | wxPen* pPen = (wxPen*)pObj; | |
1049 | ||
1050 | int cap; | |
1051 | wxColour col; | |
1052 | int join; | |
1053 | int style; | |
1054 | int width; | |
1055 | ||
1056 | if ( store.IsLoading() == FALSE ) | |
1057 | { | |
1058 | cap = pPen->GetCap(); | |
1059 | col = pPen->GetColour(); | |
1060 | join = pPen->GetJoin(); | |
1061 | style = pPen->GetStyle(); | |
1062 | width = pPen->GetWidth(); | |
1063 | } | |
1064 | ||
1065 | store.XchgInt( cap ); | |
1066 | store.XchgObj( (wxObject*) &col ); | |
1067 | store.XchgInt( join ); | |
1068 | store.XchgInt( style ); | |
1069 | store.XchgInt( width ); | |
1070 | ||
1071 | if ( store.IsLoading() ) | |
1072 | { | |
1073 | pPen->SetCap ( cap ); | |
1074 | pPen->SetColour( col ); | |
1075 | pPen->SetJoin ( join ); | |
1076 | pPen->SetStyle ( style ); | |
1077 | pPen->SetWidth ( width ); | |
1078 | } | |
1079 | } | |
1080 | ||
1081 | /***** Implementation for class wxBrushSerializer *****/ | |
1082 | ||
1083 | IMPLEMENT_SERIALIZER_CLASS( wxBrush, | |
1084 | wxBrushSerializer, | |
1085 | wxBrushSerializer::Serialize, | |
1086 | NO_CLASS_INIT ) | |
1087 | ||
1088 | void wxBrushSerializer::Serialize( wxObject* pObj, wxObjectStorage& store ) | |
1089 | { | |
1090 | wxBrush* pBrush = (wxBrush*)pObj; | |
1091 | ||
1092 | wxColour col; | |
1093 | int style; | |
1094 | ||
1095 | if ( store.IsLoading() == FALSE ) | |
1096 | { | |
1097 | col = pBrush->GetColour(); | |
1098 | style = pBrush->GetStyle(); | |
1099 | } | |
1100 | ||
1101 | store.XchgObj( (wxObject*) &col ); | |
1102 | store.XchgInt( style ); | |
1103 | ||
1104 | if ( store.IsLoading() ) | |
1105 | { | |
1106 | pBrush->SetColour( col ); | |
1107 | pBrush->SetStyle ( style ); | |
1108 | } | |
1109 | } | |
1110 | ||
1111 | /***** Implementation for class wxEvtHandlerSerializer *****/ | |
1112 | ||
1113 | IMPLEMENT_SERIALIZER_CLASS( wxEvtHandler, | |
1114 | wxEvtHandlerSerializer, | |
1115 | wxEvtHandlerSerializer::Serialize, | |
1116 | wxEvtHandlerSerializer::Initialize ) | |
1117 | ||
1118 | void wxEvtHandlerSerializer::Serialize( wxObject* pObj, wxObjectStorage& store ) | |
1119 | { | |
1120 | wxEvtHandler* pHnd = ( wxEvtHandler*) pObj; | |
1121 | ||
1122 | wxEvtHandler* pPrevHnd; | |
1123 | wxEvtHandler* pNextHnd; | |
1124 | ||
1125 | if ( store.IsLoading() == FALSE ) | |
1126 | { | |
1127 | // extract properties when storing | |
1128 | ||
1129 | pPrevHnd = pHnd->GetPreviousHandler(); | |
1130 | pNextHnd = pHnd->GetNextHandler(); | |
1131 | } | |
1132 | ||
1133 | // serialize properties | |
1134 | ||
1135 | store.XchgObjPtr( (wxObject**) &pPrevHnd ); | |
1136 | store.XchgObjPtr( (wxObject**) &pNextHnd ); | |
1137 | ||
1138 | if ( store.IsLoading() ) | |
1139 | { | |
1140 | // set properties when loading | |
1141 | ||
1142 | pHnd->SetPreviousHandler( pPrevHnd ); | |
1143 | pHnd->SetNextHandler ( pNextHnd ); | |
1144 | } | |
1145 | } | |
1146 | ||
1147 | void wxEvtHandlerSerializer::Initialize( wxObject* pObj ) | |
1148 | { | |
1149 | wxEvtHandler* pHnd = ( wxEvtHandler*) pObj; | |
1150 | ||
1151 | // if we're on top | |
1152 | if ( pHnd->GetPreviousHandler() == NULL ) | |
1153 | { | |
1154 | // then check if we're in the chain which is | |
1155 | // attached to wxWindow object | |
1156 | ||
1157 | wxEvtHandler* pCur = pHnd->GetNextHandler(); | |
1158 | ||
1159 | while( pCur ) | |
1160 | { | |
1161 | if ( pCur->IsKindOf( CLASSINFO(wxWindow) ) ) | |
1162 | { | |
1163 | // since we are the the right-most event handler | |
1164 | // in the chain, then we must be the first | |
1165 | // receiver of events sent to the window obj. - | |
1166 | // therefore "make it happen": | |
1167 | ||
1168 | ((wxWindow*)pCur)->SetEventHandler( pHnd ); | |
1169 | ||
1170 | // but if wxWindow is persistant, then why | |
1171 | // we're setting "manually" the property | |
1172 | // which is serialized anyway? | |
1173 | // | |
1174 | // The *PROBLEM* is that, it's not always good idea | |
1175 | // to serialize a window (e.g. main frame), instead | |
1176 | // they could be referred by "inital-refernces". To | |
1177 | // handle the later case, we additionally make sure | |
1178 | // that serialized evt. handlers are "glued" to the | |
1179 | // window correctly,even if the window is transient | |
1180 | // itself | |
1181 | ||
1182 | return; | |
1183 | } | |
1184 | ||
1185 | // keep on searching for wxWindows down the chain | |
1186 | ||
1187 | pCur = pCur->GetNextHandler(); | |
1188 | } | |
1189 | } | |
1190 | } | |
1191 | ||
1192 | /***** Implementation for class wxWindowSerializer *****/ | |
1193 | ||
1194 | IMPLEMENT_SERIALIZER_CLASS( wxWindow, | |
1195 | wxWindowSerializer, | |
1196 | wxWindowSerializer::Serialize, | |
1197 | NO_CLASS_INIT ) | |
1198 | ||
1199 | void wxWindowSerializer::Serialize( wxObject* pObj, wxObjectStorage& store ) | |
1200 | { | |
1201 | DoSerialize( pObj, store, (wndCreationFn)wxWindowSerializer::CreateWindowFn ); | |
1202 | } | |
1203 | ||
1204 | void wxWindowSerializer::DoSerialize( wxObject* pObj, wxObjectStorage& store, | |
1205 | wndCreationFn creationFn, bool refreshNow ) | |
1206 | { | |
1207 | // wxWindow is a kind of wxEvtHandler - peform serialization of | |
1208 | // the base class first | |
1209 | ||
1210 | info.SerializeInherited( pObj, store ); | |
1211 | ||
1212 | wxWindow* pWnd = (wxWindow*)pObj; | |
1213 | ||
1214 | long id; | |
1215 | long style; | |
1216 | wxString name; | |
1217 | wxPoint pos; | |
1218 | wxSize size; | |
1219 | wxColour bkCol; | |
1220 | wxWindow* pParent; | |
1221 | wxList* pCldLst; | |
1222 | wxEvtHandler* pEvtHandler; | |
1223 | ||
1224 | wxList tmpCldLst; | |
1225 | ||
1226 | if ( store.IsLoading() == FALSE ) | |
1227 | { | |
1228 | // extract properties from window object | |
1229 | ||
1230 | name = pWnd->GetName(); | |
1231 | id = pWnd->GetId(); | |
1232 | style = pWnd->GetWindowStyleFlag(); | |
1233 | ||
1234 | // workaround for long/int inconsitency of wxWin2.0a | |
1235 | int x,y,w,h; | |
1236 | pWnd->GetPosition( &x, &y ); | |
1237 | pWnd->GetSize ( &w, &h ); | |
1238 | bkCol = pWnd->GetBackgroundColour(); | |
1239 | ||
1240 | pos.x = x; pos.y = y; | |
1241 | size.x = w; size.y = h; | |
1242 | ||
1243 | pEvtHandler = pWnd->GetEventHandler(); | |
1244 | pParent = pWnd->GetParent(); | |
1245 | ||
1246 | #ifdef __HACK_MY_MSDEV40__ | |
1247 | pCldLst = pWnd->GetChildren(); | |
1248 | #else | |
1249 | pCldLst = &pWnd->GetChildren(); | |
1250 | #endif | |
1251 | ||
1252 | } | |
1253 | ||
1254 | // serialize properties | |
1255 | ||
1256 | store.XchgWxStr ( name ); | |
1257 | store.XchgLong ( id ); | |
1258 | store.XchgLong ( style ); | |
1259 | store.XchgLong ( pos.x ); | |
1260 | store.XchgLong ( pos.y ); | |
1261 | store.XchgLong ( size.x ); | |
1262 | store.XchgLong ( size.y ); | |
1263 | store.XchgObj ( (wxObject* ) &bkCol ); | |
1264 | store.XchgObjPtr( (wxObject**) &pParent ); | |
1265 | store.XchgObjPtr( (wxObject**) &pEvtHandler ); | |
1266 | ||
1267 | if ( store.IsLoading() ) | |
1268 | { | |
1269 | ||
1270 | // serialize to on-stack list object, since children will | |
1271 | // automatically add themselves to parent's list | |
1272 | ||
1273 | pCldLst = &tmpCldLst; | |
1274 | ||
1275 | // first create window (when loading), then serialize it's children | |
1276 | ||
1277 | (*creationFn)( pWnd, pParent, id, pos, size, style, name ); | |
1278 | ||
1279 | //pWnd->SetBackgroundColour( bkCol ); | |
1280 | ||
1281 | //pWnd->SetBackgroundColour( bkCol ); | |
1282 | ||
1283 | if ( refreshNow && 0 ) pWnd->Refresh(); | |
1284 | } | |
1285 | ||
1286 | store.XchgObjList( *pCldLst ); | |
1287 | } | |
1288 | ||
1289 | void wxWindowSerializer::CreateWindowFn( wxWindow* wnd, wxWindow* parent, const wxWindowID id, | |
1290 | const wxPoint& pos, const wxSize& size, long style , | |
1291 | const wxString& name ) | |
1292 | { | |
1293 | wnd->Create( parent, id, pos, size, style, name ); | |
1294 | } | |
1295 | ||
1296 | /***** Implementation for class wxTextCtrlSerializer *****/ | |
1297 | ||
1298 | IMPLEMENT_SERIALIZER_CLASS( wxTextCtrl, | |
1299 | wxTextCtrlSerializer, | |
1300 | wxTextCtrlSerializer::Serialize, | |
1301 | NO_CLASS_INIT ) | |
1302 | ||
1303 | void wxTextCtrlSerializer::Serialize( wxObject* pObj, wxObjectStorage& store ) | |
1304 | { | |
1305 | wxTextCtrl* pCtrl = (wxTextCtrl*)pObj; | |
1306 | ||
1307 | wxWindowSerializer::DoSerialize( pObj, store, | |
1308 | (wndCreationFn)wxTextCtrlSerializer::CreateTextCtrlWindowFn ); | |
1309 | ||
1310 | wxString text; | |
1311 | ||
1312 | if ( store.IsLoading() == FALSE ) | |
1313 | ||
1314 | text = pCtrl->GetValue(); | |
1315 | ||
1316 | store.XchgWxStr( text ); | |
1317 | ||
1318 | if ( store.IsLoading() ) | |
1319 | ||
1320 | pCtrl->SetValue( text ); | |
1321 | } | |
1322 | ||
1323 | void wxTextCtrlSerializer::CreateTextCtrlWindowFn( wxTextCtrl* wnd, wxWindow* parent, const wxWindowID id, | |
1324 | const wxPoint& pos, const wxSize& size, long style , | |
1325 | const wxString& name ) | |
1326 | { | |
1327 | wnd->Create( parent, id, "", pos, size, style ); | |
1328 | ||
1329 | // FIXME:: quick-hack | |
1330 | wnd->SetBackgroundColour( wxColour(255,255,255) ); | |
1331 | } | |
1332 | ||
1333 | /***** Implementation for class wxButtonSerializer *****/ | |
1334 | ||
1335 | IMPLEMENT_SERIALIZER_CLASS( wxButton, | |
1336 | wxButtonSerializer, | |
1337 | wxButtonSerializer::Serialize, | |
1338 | NO_CLASS_INIT ) | |
1339 | ||
1340 | void wxButtonSerializer::Serialize( wxObject* pObj, wxObjectStorage& store ) | |
1341 | { | |
1342 | wxButton* pBtn = (wxButton*)pObj; | |
1343 | ||
1344 | wxWindowSerializer::DoSerialize( pObj, store, | |
1345 | (wndCreationFn)wxButtonSerializer::CreateButtonWindowFn ); | |
1346 | ||
1347 | wxString label; | |
1348 | ||
1349 | if ( store.IsLoading() == FALSE ) | |
1350 | ||
1351 | label = pBtn->GetLabel(); | |
1352 | ||
1353 | store.XchgWxStr( label ); | |
1354 | ||
1355 | if ( store.IsLoading() ) | |
1356 | ||
1357 | pBtn->SetLabel( label ); | |
1358 | } | |
1359 | ||
1360 | void wxButtonSerializer::CreateButtonWindowFn( wxButton* btn, wxWindow* parent, const wxWindowID id, | |
1361 | const wxPoint& pos, const wxSize& size, long style , | |
1362 | const wxString& name ) | |
1363 | { | |
1364 | btn->Create( parent, id, "", pos, size, style ); | |
1365 | } | |
1366 | ||
1367 | /***** Implementation for class wxStaticTextSerializer *****/ | |
1368 | ||
1369 | IMPLEMENT_SERIALIZER_CLASS( wxStaticText, | |
1370 | wxStaticTextSerializer, | |
1371 | wxStaticTextSerializer::Serialize, | |
1372 | NO_CLASS_INIT ) | |
1373 | ||
1374 | void wxStaticTextSerializer::Serialize( wxObject* pObj, wxObjectStorage& store ) | |
1375 | { | |
1376 | wxStaticText* pSTxt = (wxStaticText*)pObj; | |
1377 | ||
1378 | wxWindowSerializer::DoSerialize( pObj, store, | |
1379 | (wndCreationFn)wxStaticTextSerializer::CreateSTextWindowFn ); | |
1380 | ||
1381 | wxString label; | |
1382 | ||
1383 | if ( store.IsLoading() == FALSE ) | |
1384 | ||
1385 | label = pSTxt->GetLabel(); | |
1386 | ||
1387 | store.XchgWxStr( label ); | |
1388 | ||
1389 | if ( store.IsLoading() ) | |
1390 | ||
1391 | pSTxt->SetLabel( label ); | |
1392 | } | |
1393 | ||
1394 | void wxStaticTextSerializer::CreateSTextWindowFn( wxStaticText* pSTxt, wxWindow* parent, const wxWindowID id, | |
1395 | const wxPoint& pos, const wxSize& size, long style , | |
1396 | const wxString& name ) | |
1397 | { | |
1398 | pSTxt->Create( parent, id, "", pos, size, style ); | |
1399 | } | |
1400 | ||
1401 | /***** Implementation for class wxScrollBarSerializer *****/ | |
1402 | ||
1403 | IMPLEMENT_SERIALIZER_CLASS( wxScrollBar, | |
1404 | wxScrollBarSerializer, | |
1405 | wxScrollBarSerializer::Serialize, | |
1406 | NO_CLASS_INIT ) | |
1407 | ||
1408 | void wxScrollBarSerializer::Serialize( wxObject* pObj, wxObjectStorage& store ) | |
1409 | { | |
1410 | wxWindowSerializer::DoSerialize( pObj, store, | |
1411 | (wndCreationFn)wxScrollBarSerializer::CreateScollBarWindowFn ); | |
1412 | } | |
1413 | ||
1414 | void wxScrollBarSerializer::CreateScollBarWindowFn( wxScrollBar* sbar, wxWindow* parent, const wxWindowID id, | |
1415 | const wxPoint& pos, const wxSize& size, long style , | |
1416 | const wxString& name ) | |
1417 | { | |
1418 | sbar->Create( parent, id, pos, size, style ); | |
1419 | } | |
1420 | ||
1421 | // FIXME:: serialization of tree control causes bunch of assertions on wxGtk | |
1422 | ||
1423 | #if 0 | |
1424 | ||
1425 | /***** Implementation for class wxTreeCtrlSerializer *****/ | |
1426 | ||
1427 | IMPLEMENT_SERIALIZER_CLASS( wxTreeCtrl, | |
1428 | wxTreeCtrlSerializer, | |
1429 | wxTreeCtrlSerializer::Serialize, | |
1430 | NO_CLASS_INIT ) | |
1431 | ||
1432 | static bool get_child_count( wxTreeItemId itemId, wxTreeCtrl* pTree ) | |
1433 | { | |
1434 | long cookie; | |
1435 | ||
1436 | if ( !pTree->ItemHasChildren( itemId ) ) return 0; | |
1437 | ||
1438 | wxTreeItemId curId = pTree->GetFirstChild( itemId, cookie ); | |
1439 | ||
1440 | int cnt = 0; | |
1441 | ||
1442 | do | |
1443 | { | |
1444 | ++cnt; | |
1445 | ||
1446 | curId = pTree->GetNextChild( itemId, cookie ); | |
1447 | ||
1448 | } while( curId ); | |
1449 | ||
1450 | return cnt; | |
1451 | } | |
1452 | ||
1453 | void wxTreeCtrlSerializer::SerializeBranch( wxTreeItemId parentId, wxTreeCtrl* pTree, | |
1454 | wxObjectStorage& store, wxTreeItemId nextVisId, | |
1455 | int depth ) | |
1456 | { | |
1457 | wxString text; | |
1458 | int childCnt; | |
1459 | int img; | |
1460 | bool isExpanded; | |
1461 | bool isVisible; | |
1462 | ||
1463 | if ( store.IsLoading() ) | |
1464 | { | |
1465 | store.XchgWxStr( text ); | |
1466 | store.XchgInt ( childCnt ); | |
1467 | store.XchgInt ( img ); | |
1468 | store.XchgBool ( isExpanded ); | |
1469 | store.XchgBool ( isVisible ); | |
1470 | ||
1471 | wxTreeItemId subBranchId = | |
1472 | ( depth == 0 ) | |
1473 | ? pTree->AddRoot( text, img ) | |
1474 | : pTree->AppendItem( parentId, text, img); | |
1475 | ||
1476 | // check if the item was labeled as first-visible | |
1477 | ||
1478 | if ( isVisible ) | |
1479 | ||
1480 | nextVisId = subBranchId; | |
1481 | ||
1482 | while ( childCnt-- ) | |
1483 | ||
1484 | SerializeBranch( subBranchId, pTree, store, nextVisId, depth+1 ); | |
1485 | ||
1486 | if ( isExpanded ) pTree->Expand( subBranchId ); | |
1487 | else pTree->Collapse( subBranchId ); | |
1488 | ||
1489 | } | |
1490 | else | |
1491 | { | |
1492 | // otherwise storing children of the branch | |
1493 | ||
1494 | text = pTree->GetItemText( parentId ); | |
1495 | childCnt = get_child_count( parentId, pTree ); | |
1496 | img = pTree->GetItemImage( parentId ); | |
1497 | isExpanded = pTree->IsExpanded( parentId ); | |
1498 | ||
1499 | if ( parentId == nextVisId ) | |
1500 | ||
1501 | isVisible = TRUE; | |
1502 | else | |
1503 | isVisible = FALSE; | |
1504 | ||
1505 | store.XchgWxStr( text ); | |
1506 | store.XchgInt ( childCnt ); | |
1507 | store.XchgInt ( img ); | |
1508 | store.XchgBool ( isExpanded ); | |
1509 | store.XchgBool ( isVisible ); | |
1510 | ||
1511 | long cookie; | |
1512 | ||
1513 | wxTreeItemId curId = pTree->GetFirstChild( parentId, cookie ); | |
1514 | ||
1515 | while ( childCnt-- ) | |
1516 | { | |
1517 | SerializeBranch( curId, pTree, store, nextVisId, -1 ); | |
1518 | ||
1519 | curId = pTree->GetNextChild( parentId, cookie ); | |
1520 | } | |
1521 | } | |
1522 | } | |
1523 | ||
1524 | void wxTreeCtrlSerializer::Serialize( wxObject* pObj, wxObjectStorage& store ) | |
1525 | { | |
1526 | // FOR NOW::image id's and image list are not serialized! | |
1527 | // it should be provided as a initial reference (IR) | |
1528 | // if it presents. Currently only normal image list | |
1529 | // for normal items-states is set up | |
1530 | ||
1531 | wxTreeCtrl* pTree = (wxTreeCtrl*)pObj; | |
1532 | ||
1533 | wxWindowSerializer::DoSerialize( pObj, store, | |
1534 | (wndCreationFn)wxTreeCtrlSerializer::CreateTreeCtrlWindowFn ); | |
1535 | ||
1536 | wxTreeItemId nextVisId = (long)0; | |
1537 | int indent = 0; | |
1538 | int childCnt; | |
1539 | wxImageList* pILst; | |
1540 | ||
1541 | if ( store.IsLoading() ) | |
1542 | { | |
1543 | store.XchgInt( indent ); | |
1544 | ||
1545 | store.XchgObjPtr( (wxObject**) &(pILst) ); | |
1546 | ||
1547 | if ( pILst ) | |
1548 | ||
1549 | pTree->SetImageList( pILst ); | |
1550 | ||
1551 | store.XchgInt( childCnt ); | |
1552 | ||
1553 | while ( childCnt-- ) | |
1554 | ||
1555 | SerializeBranch( pTree->GetRootItem() , pTree, store, nextVisId, 0 ); | |
1556 | ||
1557 | // FIXME:: somehow this is no longer inmplemented in latest wxWin-2.0 | |
1558 | // pTree->ScrollTo( nextVisId ); | |
1559 | ||
1560 | pTree->SetIndent( indent ); | |
1561 | } | |
1562 | else | |
1563 | { | |
1564 | indent = pTree->GetIndent(); | |
1565 | ||
1566 | // FIXME:: somehow this is no longer inmplemented in latest wxWin-2.0 | |
1567 | // nextVisId = pTree->GetFirstVisibleItem(); | |
1568 | ||
1569 | nextVisId = pTree->GetRootItem(); | |
1570 | ||
1571 | pILst = pTree->GetImageList(); | |
1572 | ||
1573 | store.XchgInt( indent ); | |
1574 | ||
1575 | store.XchgObjPtr( (wxObject**) &(pILst) ); | |
1576 | ||
1577 | // otherwise storing children of the branch | |
1578 | ||
1579 | childCnt = get_child_count( pTree->GetRootItem(), pTree ); | |
1580 | ||
1581 | store.XchgInt( childCnt ); | |
1582 | ||
1583 | long cookie; | |
1584 | wxTreeItemId parent = pTree->GetRootItem(); | |
1585 | wxTreeItemId curId = pTree->GetFirstChild( parent, cookie ); | |
1586 | ||
1587 | while ( childCnt-- ) | |
1588 | { | |
1589 | SerializeBranch( curId, pTree, store, nextVisId, -1 ); | |
1590 | ||
1591 | curId = pTree->GetNextChild( parent, cookie ); | |
1592 | } | |
1593 | } | |
1594 | } | |
1595 | ||
1596 | void wxTreeCtrlSerializer::CreateTreeCtrlWindowFn( wxTreeCtrl* tree, wxWindow* parent, const wxWindowID id, | |
1597 | const wxPoint& pos, const wxSize& size, long style , | |
1598 | const wxString& name ) | |
1599 | { | |
1600 | tree->Create( parent, id, pos, size, style ); | |
1601 | } | |
1602 | ||
1603 | #endif | |
1604 | ||
1605 | /***** Implementation for class wxIOStreamWrapper *****/ | |
1606 | ||
1607 | IMPLEMENT_DYNAMIC_CLASS( wxIOStreamWrapper, wxDataStreamBase ) | |
1608 | ||
1609 | void wxIOStreamWrapper::Close() | |
1610 | { | |
1611 | // close previous stream if any | |
1612 | if ( mpStm ) | |
1613 | { | |
1614 | mpStm->flush(); | |
1615 | ||
1616 | if ( mOwnsStmObject ) | |
1617 | ||
1618 | delete mpStm; | |
1619 | ||
1620 | mOwnsStmObject = FALSE; | |
1621 | ||
1622 | mpStm = NULL; | |
1623 | } | |
1624 | ||
1625 | mStreamPos = 0; | |
1626 | } | |
1627 | ||
1628 | wxIOStreamWrapper::wxIOStreamWrapper() | |
1629 | : mpStm( NULL ), | |
1630 | mOwnsStmObject( FALSE ), | |
1631 | mStreamPos(0) | |
1632 | { | |
1633 | mIsForInput = TRUE; // just a defaul | |
1634 | } | |
1635 | ||
1636 | bool wxIOStreamWrapper::Create( const char* fileName, bool forInput ) | |
1637 | { | |
1638 | Close(); | |
1639 | ||
1640 | // FIXME:: if using default value of the last arg, linking breaks complaining | |
1641 | // about duplicated symbols | |
1642 | ||
1643 | #ifdef __WXMSW__ | |
1644 | mpStm = new fstream( fileName, | |
1645 | ( ( forInput == FALSE ) ? ios::out : ios::in ) | ios::binary, | |
1646 | 0 | |
1647 | ); | |
1648 | #else | |
1649 | mpStm = new fstream( fileName, | |
1650 | ( ( forInput == FALSE ) ? ios::out : ios::in ) | ios::binary | |
1651 | ); | |
1652 | #endif | |
1653 | ||
1654 | //((fstream*)mpStm)->close(); | |
1655 | ||
1656 | //delete ((fstream*)mpStm); | |
1657 | ||
1658 | mOwnsStmObject = TRUE; | |
1659 | ||
1660 | if ( !Good() ) | |
1661 | { | |
1662 | Close(); | |
1663 | return FALSE; | |
1664 | } | |
1665 | ||
1666 | mIsForInput = forInput; | |
1667 | ||
1668 | return TRUE; | |
1669 | } | |
1670 | ||
1671 | wxIOStreamWrapper::wxIOStreamWrapper( iostream& stm, bool forInput ) | |
1672 | : mOwnsStmObject( FALSE ) | |
1673 | { | |
1674 | mpStm = &stm; | |
1675 | ||
1676 | // FIXME:: what about actual stream postion of attached stream? | |
1677 | mStreamPos = 0; | |
1678 | ||
1679 | mIsForInput = forInput; | |
1680 | } | |
1681 | ||
1682 | void wxIOStreamWrapper::Attach( iostream& stm, bool forInput ) | |
1683 | { | |
1684 | Close(); | |
1685 | ||
1686 | mOwnsStmObject = FALSE; | |
1687 | ||
1688 | mpStm = &stm; | |
1689 | ||
1690 | // FIXME:: what about actual stream postion of attached stream? | |
1691 | mStreamPos = 0; | |
1692 | ||
1693 | mIsForInput = forInput; | |
1694 | } | |
1695 | ||
1696 | wxIOStreamWrapper::~wxIOStreamWrapper() | |
1697 | { | |
1698 | Close(); | |
1699 | } | |
1700 | ||
1701 | bool wxIOStreamWrapper::StoreChar( char ch ) | |
1702 | { | |
1703 | mpStm->write( &ch, sizeof(char) ); | |
1704 | ||
1705 | mStreamPos += sizeof(char); | |
1706 | ||
1707 | return Good(); | |
1708 | } | |
1709 | ||
1710 | bool wxIOStreamWrapper::StoreInt( int i ) | |
1711 | { | |
1712 | mpStm->write( (char*)&i, sizeof(int) ); | |
1713 | ||
1714 | mStreamPos += sizeof(int); | |
1715 | ||
1716 | return Good(); | |
1717 | } | |
1718 | ||
1719 | bool wxIOStreamWrapper::StoreLong( long l ) | |
1720 | { | |
1721 | mpStm->write( (char*)&l, sizeof(long) ); | |
1722 | ||
1723 | mStreamPos += sizeof(long); | |
1724 | ||
1725 | return Good(); | |
1726 | } | |
1727 | ||
1728 | bool wxIOStreamWrapper::StoreDouble( double d ) | |
1729 | { | |
1730 | mpStm->write( (char*)&d, sizeof(double) ); | |
1731 | ||
1732 | mStreamPos += sizeof(double); | |
1733 | ||
1734 | return Good(); | |
1735 | } | |
1736 | ||
1737 | bool wxIOStreamWrapper::StoreBytes( void* bytes, int count ) | |
1738 | { | |
1739 | mpStm->write( (char*)bytes, count ); | |
1740 | ||
1741 | mStreamPos += count; | |
1742 | ||
1743 | return Good(); | |
1744 | } | |
1745 | ||
1746 | bool wxIOStreamWrapper::LoadChar( char* pCh ) | |
1747 | { | |
1748 | mpStm->read( pCh, sizeof(char) ); | |
1749 | ||
1750 | mStreamPos += sizeof(char); | |
1751 | ||
1752 | return Good(); | |
1753 | } | |
1754 | ||
1755 | bool wxIOStreamWrapper::LoadInt( int* pI ) | |
1756 | { | |
1757 | mpStm->read( (char*)pI, sizeof(int) ); | |
1758 | ||
1759 | mStreamPos += sizeof(int); | |
1760 | ||
1761 | return Good(); | |
1762 | } | |
1763 | ||
1764 | bool wxIOStreamWrapper::LoadLong( long* pL ) | |
1765 | { | |
1766 | mpStm->read( (char*)pL, sizeof(long) ); | |
1767 | ||
1768 | mStreamPos += sizeof(long); | |
1769 | ||
1770 | return Good(); | |
1771 | } | |
1772 | ||
1773 | bool wxIOStreamWrapper::LoadDouble( double* pD ) | |
1774 | { | |
1775 | mpStm->read( (char*)pD, sizeof(double) ); | |
1776 | ||
1777 | mStreamPos += sizeof(double); | |
1778 | ||
1779 | return Good(); | |
1780 | } | |
1781 | ||
1782 | bool wxIOStreamWrapper::LoadBytes ( void* pBytes, int count ) | |
1783 | { | |
1784 | mpStm->read( (char*)pBytes, count ); | |
1785 | ||
1786 | mStreamPos += count; | |
1787 | ||
1788 | return Good(); | |
1789 | } | |
1790 | ||
1791 | bool wxIOStreamWrapper::Flush() | |
1792 | { | |
1793 | mpStm->flush(); | |
1794 | ||
1795 | return Good(); | |
1796 | } | |
1797 | ||
1798 | long wxIOStreamWrapper::GetStreamPos() | |
1799 | { | |
1800 | return mStreamPos; | |
1801 | } | |
1802 | ||
1803 | bool wxIOStreamWrapper::Good() | |
1804 | { | |
1805 | // FIXME FIXME:: somehow, when using ios::good/ios::bad, linking breaks complaining | |
1806 | // about "ios::bad" already defined in this object file... | |
1807 | ||
1808 | return TRUE; | |
1809 | } |