]> git.saurik.com Git - wxWidgets.git/blame - src/common/xtistrm.cpp
added more specializations for bcc32
[wxWidgets.git] / src / common / xtistrm.cpp
CommitLineData
70e88103
SC
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/common/xtistrm.cpp
3// Purpose: streaming runtime metadata information
4// Author: Stefan Csomor
5// Modified by:
6// Created: 27/07/03
7// RCS-ID: $Id$
8// Copyright: (c) 2003 Stefan Csomor
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12#ifdef __GNUG__
13#pragma implementation "xtistrm.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 #include "wx/object.h"
26#endif
27
28#include "wx/xml/xml.h"
29#include "wx/tokenzr.h"
30#include "wx/xtistrm.h"
31#include "wx/txtstrm.h"
32
33#if wxUSE_EXTENDED_RTTI
34#include <map>
35#include <vector>
36#include <string>
37
38using namespace std ;
39
40// ----------------------------------------------------------------------------
41// streaming xml out
42// ----------------------------------------------------------------------------
43
45212047 44void WriteComponent(wxObject *Object, const wxClassInfo *classInfo, wxXmlNode *parent, const wxString& nodeName , int &nextId, bool embeddedObject, map< wxObject* , int > &writtenObjects ) ;
70e88103
SC
45
46void WriteComponentProperties( wxObject* obj , const wxClassInfo* ci , wxXmlNode *onode , int &nextId, map< wxObject* , int > &writtenObjects, map< string , int > &writtenProperties)
47{
48 const wxPropertyInfo *pi = ci->GetFirstProperty() ;
49 while( pi )
50 {
51 if ( writtenProperties.find( pi->GetName() ) == writtenProperties.end() )
52 {
53 writtenProperties[ pi->GetName() ] = 1 ;
54 const wxClassTypeInfo* cti = dynamic_cast< const wxClassTypeInfo* > ( pi->GetTypeInfo() ) ;
55 if ( cti )
56 {
57 const wxClassInfo* pci = cti->GetClassInfo() ;
45212047
SC
58 wxxVariant value = pi->GetAccessor()->GetProperty(obj) ;
59 WriteComponent( pci->VariantToInstance( value ) , pci , onode , pi->GetName() , nextId ,
60 ( cti->GetKind() == wxT_OBJECT ) , writtenObjects ) ;
70e88103
SC
61 }
62 else
63 {
64 const wxDelegateTypeInfo* dti = dynamic_cast< const wxDelegateTypeInfo* > ( pi->GetTypeInfo() ) ;
65 if ( dti )
66 {
67 // in which form should we stream out these ?
68 }
69 else
70 {
71 wxXmlNode *pnode;
72 pnode = new wxXmlNode(wxXML_ELEMENT_NODE, pi->GetName() );
73 pi->GetAccessor()->WriteValue(pnode, obj ) ;
74 onode->AddChild(pnode);
75 }
76 }
77 }
78 pi = pi->GetNext() ;
79 }
80 const wxClassInfo** parents = ci->GetParents() ;
81 for ( int i = 0 ; parents[i] ; ++ i )
82 {
83 WriteComponentProperties( obj , parents[i] , onode , nextId , writtenObjects , writtenProperties ) ;
84 }
85}
86
87/*
88 Writing Components does have to take inheritance into account, that's why we are iterating
89 over our parents as well
90 */
91
92void WriteComponent(wxObject *obj, const wxClassInfo *classInfo, wxXmlNode *parent, const wxString &nodeName)
93{
94 int nextid = 0 ; // 0 is the root element
95 map< wxObject* , int > writtenobjects ;
45212047 96 WriteComponent( obj , classInfo, parent, nodeName , nextid , false , writtenobjects ) ;
70e88103
SC
97}
98
45212047 99void WriteComponent(wxObject *obj, const wxClassInfo *classInfo, wxXmlNode *parent, const wxString& nodeName , int &nextId, bool embeddedObject, map< wxObject* , int > &writtenObjects )
70e88103
SC
100{
101 map< string , int > writtenProperties ;
102 wxXmlNode *onode;
103
104 onode = new wxXmlNode(wxXML_ELEMENT_NODE, nodeName);
105
106 onode->AddProperty(wxString("class"), wxString(classInfo->GetClassName()));
107 if ( obj == NULL )
108 {
109 wxXmlNode* nullnode = new wxXmlNode(wxXML_TEXT_NODE, wxEmptyString, "null");
110 onode->AddChild(nullnode);
111 }
112 else
113 {
114 // if we have already written this object, just insert an id
45212047
SC
115 // embedded objects have to be written out fully always, their address will be reused and is not a valid key
116 if ( !embeddedObject && (writtenObjects.find( obj ) != writtenObjects.end()) )
70e88103
SC
117 {
118 onode->AddProperty(wxString("id"), wxString::Format( "%d" , writtenObjects[obj] ) );
119 }
120 else
121 {
122 int id = nextId++ ;
45212047
SC
123 if ( !embeddedObject )
124 writtenObjects[obj] = id ;
70e88103
SC
125 onode->AddProperty(wxString("id"), wxString::Format( "%d" , id ) );
126 WriteComponentProperties( obj , classInfo , onode , nextId , writtenObjects, writtenProperties) ;
127 }
128 }
129
130 parent->AddChild(onode);
131}
132
133// ----------------------------------------------------------------------------
45212047 134// reading objects in
70e88103
SC
135// ----------------------------------------------------------------------------
136
70e88103
SC
137struct wxReader::wxReaderInternal
138{
45212047 139 map<int,wxClassInfo*> m_classInfos;
70e88103
SC
140};
141
45212047 142wxReader::wxReader()
70e88103 143{
45212047 144 m_data = new wxReaderInternal;
70e88103
SC
145}
146
147wxReader::~wxReader()
148{
45212047 149 delete m_data;
70e88103
SC
150}
151
45212047 152wxClassInfo* wxReader::GetObjectClassInfo(int objectID)
70e88103 153{
45212047
SC
154 assert( m_data->m_classInfos.find(objectID) != m_data->m_classInfos.end() );
155 return m_data->m_classInfos[objectID] ;
70e88103
SC
156}
157
45212047 158void wxReader::SetObjectClassInfo(int objectID, wxClassInfo *classInfo )
70e88103 159{
45212047
SC
160 assert( m_data->m_classInfos.find(objectID) == m_data->m_classInfos.end() ) ;
161 m_data->m_classInfos[objectID] = classInfo ;
70e88103
SC
162}
163
45212047 164bool wxReader::HasObjectClassInfo( int objectID )
70e88103 165{
45212047 166 return m_data->m_classInfos.find(objectID) != m_data->m_classInfos.end() ;
70e88103
SC
167}
168
70e88103 169
45212047
SC
170// ----------------------------------------------------------------------------
171// reading xml in
172// ----------------------------------------------------------------------------
70e88103
SC
173
174/*
175 Reading components has not to be extended for components
176 as properties are always sought by typeinfo over all levels
177 and create params are always toplevel class only
178*/
179
45212047 180int wxXmlReader::ReadComponent(wxXmlNode *node, wxDepersister *callbacks)
70e88103 181{
45212047
SC
182 wxString className;
183 wxClassInfo *classInfo;
70e88103 184
45212047
SC
185 wxxVariant *createParams ;
186 int *createParamOids ;
187 const wxClassInfo** createClassInfos ;
188 wxXmlNode *children;
189 int objectID;
70e88103 190
45212047
SC
191 children = node->GetChildren();
192 if (!node->GetPropVal("class", &className))
70e88103
SC
193 {
194 // No class name. Eek. FIXME: error handling
45212047 195 return wxInvalidObjectID;
70e88103 196 }
45212047
SC
197 classInfo = wxClassInfo::FindClass(className);
198 if (children && children->GetType() == wxXML_TEXT_NODE)
70e88103 199 {
45212047 200 assert( wxXmlGetContentFromNode(node) == "null" ) ;
70e88103 201 // this must be a NULL component reference. We just bail out
45212047 202 return wxNullObjectID;
70e88103
SC
203 }
204
205 wxString ObjectIdString ;
45212047 206 if (!node->GetPropVal("id", &ObjectIdString))
70e88103
SC
207 {
208 // No object id. Eek. FIXME: error handling
45212047 209 return wxInvalidObjectID;
70e88103
SC
210 }
211
45212047 212 objectID = atoi( ObjectIdString.c_str() ) ;
70e88103 213 // is this object already has been streamed in, return it here
45212047
SC
214 if ( HasObjectClassInfo( objectID ) )
215 return objectID ;
70e88103
SC
216
217 // new object, start with allocation
45212047
SC
218 // first make the object know to our internal registry
219 SetObjectClassInfo( objectID , classInfo ) ;
220
221 callbacks->AllocateObject(objectID, classInfo);
70e88103
SC
222
223 //
224 // stream back the Create parameters first
45212047
SC
225 createParams = new wxxVariant[ classInfo->GetCreateParamCount() ] ;
226 createParamOids = new int[classInfo->GetCreateParamCount() ] ;
227 createClassInfos = new const wxClassInfo*[classInfo->GetCreateParamCount() ] ;
70e88103
SC
228
229 typedef map<string, wxXmlNode *> PropertyNodes ;
230 typedef vector<string> PropertyNames ;
231
232 PropertyNodes propertyNodes ;
233 PropertyNames propertyNames ;
234
45212047 235 while( children )
70e88103 236 {
45212047
SC
237 propertyNames.push_back( children->GetName().c_str() ) ;
238 propertyNodes[children->GetName().c_str()] = children ;
239 children = children->GetNext() ;
70e88103
SC
240 }
241
45212047 242 for ( int i = 0 ; i <classInfo->GetCreateParamCount() ; ++i )
70e88103 243 {
45212047 244 const wxChar* paramName = classInfo->GetCreateParamName(i) ;
70e88103 245 PropertyNodes::iterator propiter = propertyNodes.find( paramName ) ;
45212047 246 const wxPropertyInfo* pi = classInfo->FindPropertyInfo( paramName ) ;
70e88103
SC
247 // if we don't have the value of a create param set in the xml
248 // we use the default value
249 if ( propiter != propertyNodes.end() )
250 {
251 wxXmlNode* prop = propiter->second ;
45212047
SC
252 if ( pi->GetTypeInfo()->IsObjectType() )
253 {
254 createParamOids[i] = ReadComponent( prop , callbacks ) ;
255 createClassInfos[i] = dynamic_cast<const wxClassTypeInfo*>(pi->GetTypeInfo())->GetClassInfo() ;
256 }
257 else
258 {
259 createParamOids[i] = wxInvalidObjectID ;
260 createParams[i] = ReadValue( prop , pi->GetAccessor() ) ;
261 createClassInfos[i] = NULL ;
262 }
263
70e88103
SC
264 for ( size_t j = 0 ; j < propertyNames.size() ; ++j )
265 {
266 if ( propertyNames[j] == paramName )
267 {
268 propertyNames[j] = "" ;
269 break ;
270 }
271 }
272 }
273 else
274 {
45212047 275 createParams[i] = pi->GetDefaultValue() ;
70e88103
SC
276 }
277 }
278
279 // got the parameters. Call the Create method
45212047
SC
280 callbacks->CreateObject(objectID, classInfo,
281 classInfo->GetCreateParamCount(),
282 createParams, createParamOids, createClassInfos);
70e88103
SC
283
284 // now stream in the rest of the properties, in the sequence their properties were written in the xml
285 for ( size_t j = 0 ; j < propertyNames.size() ; ++j )
286 {
287 if ( propertyNames[j].length() )
288 {
289 PropertyNodes::iterator propiter = propertyNodes.find( propertyNames[j] ) ;
290 if ( propiter != propertyNodes.end() )
291 {
292 wxXmlNode* prop = propiter->second ;
45212047
SC
293 const wxPropertyInfo* pi = classInfo->FindPropertyInfo( propertyNames[j].c_str() ) ;
294 if ( pi->GetTypeInfo()->IsObjectType() )
295 {
296 int valueId = ReadComponent( prop , callbacks ) ;
297 if ( callbacks )
298 {
299 if ( valueId != wxInvalidObjectID )
300 {
301 callbacks->SetPropertyAsObject( objectID , classInfo , pi , valueId ) ;
302 if ( pi->GetTypeInfo()->GetKind() == wxT_OBJECT && valueId != wxNullObjectID )
303 callbacks->DestroyObject( valueId , GetObjectClassInfo( valueId ) ) ;
304 }
305 }
306 }
307 else if ( pi->GetTypeInfo()->IsDelegateType() )
308 {
309 wxString resstring = wxXmlGetContentFromNode(prop) ;
310 wxInt32 pos = resstring.Find('.') ;
311 assert( pos != wxNOT_FOUND ) ;
312 int sinkOid = atol(resstring.Left(pos)) ;
313 wxString handlerName = resstring.Mid(pos+1) ;
314 wxClassInfo* sinkClassInfo = GetObjectClassInfo( sinkOid ) ;
315
316 if (callbacks)
317 callbacks->SetConnect( objectID , classInfo , dynamic_cast<const wxDelegateTypeInfo*>(pi->GetTypeInfo()) , sinkClassInfo ,
318 sinkClassInfo->FindHandlerInfo(handlerName) , sinkOid ) ;
319
320 }
321 else
322 {
323 if ( callbacks )
324 callbacks->SetProperty( objectID, classInfo ,pi , ReadValue( prop , pi->GetAccessor() ) ) ;
325 }
70e88103
SC
326 }
327 }
328 }
70e88103 329
45212047
SC
330 delete[] createParams ;
331 delete[] createParamOids ;
332 delete[] createClassInfos ;
70e88103 333
45212047
SC
334 return objectID;
335}
70e88103 336
45212047
SC
337wxxVariant wxXmlReader::ReadValue(wxXmlNode *node,
338 wxPropertyAccessor *accessor )
339{
340 return accessor->ReadValue(node) ;
341}
342
343int wxXmlReader::ReadObject(wxDepersister *callbacks)
344{
345 return ReadComponent( m_parent , callbacks ) ;
70e88103
SC
346}
347
348// ----------------------------------------------------------------------------
349// depersisting to memory
350// ----------------------------------------------------------------------------
351
45212047 352struct wxRuntimeDepersister::wxRuntimeDepersisterInternal
70e88103 353{
45212047
SC
354 map<int,wxObject *> m_objects;
355
356 void SetObject(int objectID, wxObject *obj )
357 {
358 assert( m_objects.find(objectID) == m_objects.end() ) ;
359 m_objects[objectID] = obj ;
360 }
361 wxObject* GetObject( int objectID )
362 {
363 if ( objectID == wxNullObjectID )
364 return NULL ;
365
366 assert( m_objects.find(objectID) != m_objects.end() ) ;
367 return m_objects[objectID] ;
368 }
369} ;
370
371wxRuntimeDepersister::wxRuntimeDepersister()
372{
373 m_data = new wxRuntimeDepersisterInternal() ;
70e88103
SC
374}
375
45212047 376wxRuntimeDepersister::~wxRuntimeDepersister()
70e88103 377{
45212047 378 delete m_data ;
70e88103
SC
379}
380
45212047 381void wxRuntimeDepersister::AllocateObject(int objectID, wxClassInfo *classInfo)
70e88103
SC
382{
383 wxObject *O;
45212047
SC
384 O = classInfo->CreateObject();
385 m_data->SetObject(objectID, O);
386}
387
388void wxRuntimeDepersister::CreateObject(int objectID,
389 const wxClassInfo *classInfo,
390 int paramCount,
391 wxxVariant *params,
392 int *objectIdValues,
393 const wxClassInfo **objectClassInfos)
394{
395 wxObject *o;
396 o = m_data->GetObject(objectID);
397 for ( int i = 0 ; i < paramCount ; ++i )
398 {
399 if ( objectIdValues[i] != wxInvalidObjectID )
400 {
401 wxObject *o;
402 o = m_data->GetObject(objectIdValues[i]);
403 params[i] = objectClassInfos[i]->InstanceToVariant(o) ;
404 }
405 }
406 classInfo->Create(o, paramCount, params);
407}
408
409void wxRuntimeDepersister::DestroyObject(int objectID, wxClassInfo *WXUNUSED(classInfo))
410{
411 wxObject *o;
412 o = m_data->GetObject(objectID);
413 delete o ;
70e88103
SC
414}
415
45212047
SC
416void wxRuntimeDepersister::SetProperty(int objectID,
417 const wxClassInfo *WXUNUSED(classInfo),
418 const wxPropertyInfo* propertyInfo,
419 const wxxVariant &value)
70e88103 420{
45212047
SC
421 wxObject *o;
422 o = m_data->GetObject(objectID);
423 propertyInfo->GetAccessor()->SetProperty( o , value ) ;
424}
425
426void wxRuntimeDepersister::SetPropertyAsObject(int objectID,
427 const wxClassInfo *WXUNUSED(classInfo),
428 const wxPropertyInfo* propertyInfo,
429 int valueObjectId)
430{
431 wxObject *o, *valo;
432 o = m_data->GetObject(objectID);
433 valo = m_data->GetObject(valueObjectId);
434 propertyInfo->GetAccessor()->SetProperty( o ,
435 (dynamic_cast<const wxClassTypeInfo*>(propertyInfo->GetTypeInfo()))->GetClassInfo()->InstanceToVariant(valo) ) ;
436}
437
438void wxRuntimeDepersister::SetConnect(int eventSourceObjectID,
439 const wxClassInfo *WXUNUSED(eventSourceClassInfo),
440 const wxDelegateTypeInfo *delegateInfo ,
441 const wxClassInfo *WXUNUSED(eventSinkClassInfo) ,
442 const wxHandlerInfo* handlerInfo ,
443 int eventSinkObjectID )
444{
445 wxWindow *ehsource = dynamic_cast< wxWindow* >( m_data->GetObject( eventSourceObjectID ) ) ;
446 wxEvtHandler *ehsink = dynamic_cast< wxEvtHandler *>(m_data->GetObject(eventSinkObjectID) ) ;
70e88103
SC
447
448 if ( ehsource && ehsink )
449 {
45212047
SC
450 ehsource->Connect( ehsource->GetId() , delegateInfo->GetEventType() ,
451 handlerInfo->GetEventFunction() , NULL /*user data*/ ,
70e88103
SC
452 ehsink ) ;
453 }
454}
455
45212047
SC
456wxObject *wxRuntimeDepersister::GetObject(int objectID)
457{
458 return m_data->GetObject( objectID ) ;
459}
460
461
70e88103
SC
462// ----------------------------------------------------------------------------
463// depersisting to code
464// ----------------------------------------------------------------------------
465
45212047
SC
466struct wxCodeDepersister::wxCodeDepersisterInternal
467{
468 map<int,string> m_objectNames ;
469
470 void SetObjectName(int objectID, const wxString &name )
471 {
472 assert( m_objectNames.find(objectID) == m_objectNames.end() ) ;
473 m_objectNames[objectID] = (const char *)name;
474 }
475 wxString GetObjectName( int objectID )
476 {
477 if ( objectID == wxNullObjectID )
478 return "NULL" ;
479
480 assert( m_objectNames.find(objectID) != m_objectNames.end() ) ;
481 return wxString( m_objectNames[objectID].c_str() ) ;
482 }
483} ;
70e88103 484
45212047
SC
485wxCodeDepersister::wxCodeDepersister(wxTextOutputStream *out)
486 : m_fp(out)
70e88103 487{
45212047
SC
488 m_data = new wxCodeDepersisterInternal ;
489}
490
491wxCodeDepersister::~wxCodeDepersister()
492{
493 delete m_data ;
494}
495
496void wxCodeDepersister::AllocateObject(int objectID, wxClassInfo *classInfo)
497{
498 wxString objectName = wxString::Format( "LocalObject_%d" , objectID ) ;
499 m_fp->WriteString( wxString::Format( "\t%s *%s = new %s;\n",
500 classInfo->GetClassName(),
70e88103 501 objectName,
45212047
SC
502 classInfo->GetClassName()) );
503 m_data->SetObjectName( objectID , objectName ) ;
504}
505
506void wxCodeDepersister::DestroyObject(int objectID, wxClassInfo *WXUNUSED(classInfo))
507{
508 m_fp->WriteString( wxString::Format( "\tdelete %s;\n",
509 m_data->GetObjectName( objectID) ) );
510}
511
512wxString wxCodeDepersister::ValueAsCode( const wxxVariant &param )
513{
514 wxString value ;
515 const wxTypeInfo* type = param.GetTypeInfo() ;
516 if ( type->GetKind() == wxT_CUSTOM )
517 {
518 const wxCustomTypeInfo* cti = dynamic_cast<const wxCustomTypeInfo*>(type) ;
519 wxASSERT_MSG( cti , wxT("Internal error, illegal wxCustomTypeInfo") ) ;
520 value.Printf( "%s(%s)",cti->GetTypeName(),param.GetAsString() );
521 }
522 else if ( type->GetKind() == wxT_STRING )
523 {
524 value.Printf( "\"%s\"",param.GetAsString() );
525 }
526 else
527 {
528 value.Printf( "%s", param.GetAsString() );
529 }
530 return value ;
70e88103
SC
531}
532
45212047
SC
533void wxCodeDepersister::CreateObject(int objectID,
534 const wxClassInfo *WXUNUSED(classInfo),
535 int paramCount,
536 wxxVariant *params,
537 int *objectIDValues,
538 const wxClassInfo **WXUNUSED(objectClassInfos)
539 )
70e88103
SC
540{
541 int i;
45212047
SC
542 m_fp->WriteString( wxString::Format( "\t%s->Create(", m_data->GetObjectName(objectID) ) );
543 for (i = 0; i < paramCount; i++)
70e88103 544 {
45212047
SC
545 if ( objectIDValues[i] != wxInvalidObjectID )
546 m_fp->WriteString( wxString::Format( "%s", m_data->GetObjectName( objectIDValues[i] ) ) );
547 else
548 {
549 m_fp->WriteString( wxString::Format( "%s", ValueAsCode(params[i]) ) );
550 }
551 if (i < paramCount - 1)
552 m_fp->WriteString( ", ");
70e88103 553 }
45212047 554 m_fp->WriteString( ");\n");
70e88103
SC
555}
556
45212047
SC
557void wxCodeDepersister::SetProperty(int objectID,
558 const wxClassInfo *WXUNUSED(classInfo),
559 const wxPropertyInfo* propertyInfo,
560 const wxxVariant &value)
70e88103 561{
45212047
SC
562 m_fp->WriteString( wxString::Format( "\t%s->%s(%s);\n",
563 m_data->GetObjectName(objectID),
564 propertyInfo->GetAccessor()->GetSetterName(),
565 ValueAsCode(value)) );
566}
567
568void wxCodeDepersister::SetPropertyAsObject(int objectID,
569 const wxClassInfo *WXUNUSED(classInfo),
570 const wxPropertyInfo* propertyInfo,
571 int valueObjectId)
572{
573 if ( propertyInfo->GetTypeInfo()->GetKind() == wxT_OBJECT )
574 m_fp->WriteString( wxString::Format( "\t%s->%s(*%s);\n",
575 m_data->GetObjectName(objectID),
576 propertyInfo->GetAccessor()->GetSetterName(),
577 m_data->GetObjectName( valueObjectId) ) );
578 else
579 m_fp->WriteString( wxString::Format( "\t%s->%s(%s);\n",
580 m_data->GetObjectName(objectID),
581 propertyInfo->GetAccessor()->GetSetterName(),
582 m_data->GetObjectName( valueObjectId) ) );
70e88103
SC
583}
584
45212047
SC
585void wxCodeDepersister::SetConnect(int eventSourceObjectID,
586 const wxClassInfo *WXUNUSED(eventSourceClassInfo),
587 const wxDelegateTypeInfo *delegateInfo ,
588 const wxClassInfo *eventSinkClassInfo ,
589 const wxHandlerInfo* handlerInfo ,
590 int eventSinkObjectID )
70e88103 591{
45212047
SC
592 wxString ehsource = m_data->GetObjectName( eventSourceObjectID ) ;
593 wxString ehsink = m_data->GetObjectName(eventSinkObjectID) ;
594 wxString ehsinkClass = eventSinkClassInfo->GetClassName() ;
595 int eventType = delegateInfo->GetEventType() ;
596 wxString handlerName = handlerInfo->GetName() ;
70e88103 597
45212047 598 m_fp->WriteString( wxString::Format( "\t%s->Connect( %s->GetId() , %d , (wxObjectEventFunction)(wxEventFunction) & %s::%s , NULL , %s ) ;" ,
70e88103
SC
599 ehsource , ehsource , eventType , ehsinkClass , handlerName , ehsink ) );
600}
601
602#endif