1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_basic.hxx" 30 #include <tools/stream.hxx> 31 #include <vcl/sound.hxx> 32 #include <basic/sbx.hxx> 33 #include <basic/sbxbase.hxx> 34 #include "sbxres.hxx" 35 #include <svl/brdcst.hxx> 36 37 TYPEINIT1(SbxMethod,SbxVariable) 38 TYPEINIT1(SbxProperty,SbxVariable) 39 TYPEINIT2(SbxObject,SbxVariable,SfxListener) 40 41 static const char* pNameProp; // Name-Property 42 static const char* pParentProp; // Parent-Property 43 44 static sal_uInt16 nNameHash = 0, nParentHash = 0; 45 46 ///////////////////////////////////////////////////////////////////////// 47 48 ///////////////////////////////////////////////////////////////////////// 49 50 SbxObject::SbxObject( const XubString& rClass ) 51 : SbxVariable( SbxOBJECT ), aClassName( rClass ) 52 { 53 aData.pObj = this; 54 if( !nNameHash ) 55 { 56 pNameProp = GetSbxRes( STRING_NAMEPROP ); 57 pParentProp = GetSbxRes( STRING_PARENTPROP ); 58 nNameHash = MakeHashCode( String::CreateFromAscii( pNameProp ) ); 59 nParentHash = MakeHashCode( String::CreateFromAscii( pParentProp ) ); 60 } 61 SbxObject::Clear(); 62 SbxObject::SetName( rClass ); 63 } 64 65 SbxObject::SbxObject( const SbxObject& rObj ) 66 : SvRefBase( rObj ), SbxVariable( rObj.GetType() ), 67 SfxListener( rObj ) 68 { 69 *this = rObj; 70 } 71 72 SbxObject& SbxObject::operator=( const SbxObject& r ) 73 { 74 if( &r != this ) 75 { 76 SbxVariable::operator=( r ); 77 aClassName = r.aClassName; 78 pMethods = new SbxArray; 79 pProps = new SbxArray; 80 pObjs = new SbxArray( SbxOBJECT ); 81 // Die Arrays werden kopiert, die Inhalte uebernommen 82 *pMethods = *r.pMethods; 83 *pProps = *r.pProps; 84 *pObjs = *r.pObjs; 85 // Da die Variablen uebernommen wurden, ist dies OK 86 pDfltProp = r.pDfltProp; 87 SetName( r.GetName() ); 88 SetFlags( r.GetFlags() ); 89 SetModified( sal_True ); 90 } 91 return *this; 92 } 93 94 static void CheckParentsOnDelete( SbxObject* pObj, SbxArray* p ) 95 { 96 for( sal_uInt16 i = 0; i < p->Count(); i++ ) 97 { 98 SbxVariableRef& rRef = p->GetRef( i ); 99 if( rRef->IsBroadcaster() ) 100 pObj->EndListening( rRef->GetBroadcaster(), sal_True ); 101 // Hat das Element mehr als eine Referenz und noch einen Listener? 102 if( rRef->GetRefCount() > 1 ) 103 { 104 rRef->SetParent( NULL ); 105 DBG_ASSERT( !rRef->IsBroadcaster() || rRef->GetBroadcaster().GetListenerCount(), "Object element with dangling parent" ); 106 } 107 } 108 } 109 110 SbxObject::~SbxObject() 111 { 112 CheckParentsOnDelete( this, pProps ); 113 CheckParentsOnDelete( this, pMethods ); 114 CheckParentsOnDelete( this, pObjs ); 115 116 // avoid handling in ~SbxVariable as SBX_DIM_AS_NEW == SBX_GBLSEARCH 117 ResetFlag( SBX_DIM_AS_NEW ); 118 } 119 120 SbxDataType SbxObject::GetType() const 121 { 122 return SbxOBJECT; 123 } 124 125 SbxClassType SbxObject::GetClass() const 126 { 127 return SbxCLASS_OBJECT; 128 } 129 130 void SbxObject::Clear() 131 { 132 pMethods = new SbxArray; 133 pProps = new SbxArray; 134 pObjs = new SbxArray( SbxOBJECT ); 135 SbxVariable* p; 136 p = Make( String::CreateFromAscii( pNameProp ), SbxCLASS_PROPERTY, SbxSTRING ); 137 p->SetFlag( SBX_DONTSTORE ); 138 p = Make( String::CreateFromAscii( pParentProp ), SbxCLASS_PROPERTY, SbxOBJECT ); 139 p->ResetFlag( SBX_WRITE ); 140 p->SetFlag( SBX_DONTSTORE ); 141 pDfltProp = NULL; 142 SetModified( sal_False ); 143 } 144 145 void SbxObject::SFX_NOTIFY( SfxBroadcaster&, const TypeId&, 146 const SfxHint& rHint, const TypeId& ) 147 { 148 const SbxHint* p = PTR_CAST(SbxHint,&rHint); 149 if( p ) 150 { 151 sal_uIntPtr nId = p->GetId(); 152 sal_Bool bRead = sal_Bool( nId == SBX_HINT_DATAWANTED ); 153 sal_Bool bWrite = sal_Bool( nId == SBX_HINT_DATACHANGED ); 154 SbxVariable* pVar = p->GetVar(); 155 if( bRead || bWrite ) 156 { 157 XubString aVarName( pVar->GetName() ); 158 sal_uInt16 nHash_ = MakeHashCode( aVarName ); 159 if( nHash_ == nNameHash 160 && aVarName.EqualsIgnoreCaseAscii( pNameProp ) ) 161 { 162 if( bRead ) 163 pVar->PutString( GetName() ); 164 else 165 SetName( pVar->GetString() ); 166 } 167 else if( nHash_ == nParentHash 168 && aVarName.EqualsIgnoreCaseAscii( pParentProp ) ) 169 { 170 SbxObject* p_ = GetParent(); 171 if( !p_ ) 172 p_ = this; 173 pVar->PutObject( p_ ); 174 } 175 } 176 } 177 } 178 179 sal_Bool SbxObject::IsClass( const XubString& rName ) const 180 { 181 return sal_Bool( aClassName.EqualsIgnoreCaseAscii( rName ) ); 182 } 183 184 SbxVariable* SbxObject::FindUserData( sal_uInt32 nData ) 185 { 186 if( !GetAll( SbxCLASS_DONTCARE ) ) 187 return NULL; 188 189 SbxVariable* pRes = pMethods->FindUserData( nData ); 190 if( !pRes ) 191 pRes = pProps->FindUserData( nData ); 192 if( !pRes ) 193 pRes = pObjs->FindUserData( nData ); 194 // Search in den Parents? 195 if( !pRes && IsSet( SBX_GBLSEARCH ) ) 196 { 197 SbxObject* pCur = this; 198 while( !pRes && pCur->pParent ) 199 { 200 // Ich selbst bin schon durchsucht worden! 201 sal_uInt16 nOwn = pCur->GetFlags(); 202 pCur->ResetFlag( SBX_EXTSEARCH ); 203 // Ich suche bereits global! 204 sal_uInt16 nPar = pCur->pParent->GetFlags(); 205 pCur->pParent->ResetFlag( SBX_GBLSEARCH ); 206 pRes = pCur->pParent->FindUserData( nData ); 207 pCur->SetFlags( nOwn ); 208 pCur->pParent->SetFlags( nPar ); 209 pCur = pCur->pParent; 210 } 211 } 212 return pRes; 213 } 214 215 SbxVariable* SbxObject::Find( const XubString& rName, SbxClassType t ) 216 { 217 #ifdef DBG_UTIL 218 static sal_uInt16 nLvl = 0; 219 static const char* pCls[] = 220 { "DontCare","Array","Value","Variable","Method","Property","Object" }; 221 ByteString aNameStr1( (const UniString&)rName, RTL_TEXTENCODING_ASCII_US ); 222 ByteString aNameStr2( (const UniString&)SbxVariable::GetName(), RTL_TEXTENCODING_ASCII_US ); 223 DbgOutf( "SBX: Search %.*s %s %s in %s", 224 nLvl++, " ", 225 ( t >= SbxCLASS_DONTCARE && t <= SbxCLASS_OBJECT ) 226 ? pCls[ t-1 ] : "Unknown class", aNameStr1.GetBuffer(), aNameStr1.GetBuffer() ); 227 #endif 228 229 if( !GetAll( t ) ) 230 return NULL; 231 SbxVariable* pRes = NULL; 232 pObjs->SetFlag( SBX_EXTSEARCH ); 233 if( t == SbxCLASS_DONTCARE ) 234 { 235 pRes = pMethods->Find( rName, SbxCLASS_METHOD ); 236 if( !pRes ) 237 pRes = pProps->Find( rName, SbxCLASS_PROPERTY ); 238 if( !pRes ) 239 pRes = pObjs->Find( rName, t ); 240 } 241 else 242 { 243 SbxArray* pArray = NULL; 244 switch( t ) 245 { 246 case SbxCLASS_VARIABLE: 247 case SbxCLASS_PROPERTY: pArray = pProps; break; 248 case SbxCLASS_METHOD: pArray = pMethods; break; 249 case SbxCLASS_OBJECT: pArray = pObjs; break; 250 default: 251 DBG_ASSERT( !this, "Ungueltige SBX-Klasse" ); 252 } 253 if( pArray ) 254 pRes = pArray->Find( rName, t ); 255 } 256 // Extended Search im Objekt-Array? 257 // Fuer Objekte und DontCare ist das Objektarray bereits 258 // durchsucht worden 259 if( !pRes && ( t == SbxCLASS_METHOD || t == SbxCLASS_PROPERTY ) ) 260 pRes = pObjs->Find( rName, t ); 261 // Search in den Parents? 262 if( !pRes && IsSet( SBX_GBLSEARCH ) ) 263 { 264 SbxObject* pCur = this; 265 while( !pRes && pCur->pParent ) 266 { 267 // Ich selbst bin schon durchsucht worden! 268 sal_uInt16 nOwn = pCur->GetFlags(); 269 pCur->ResetFlag( SBX_EXTSEARCH ); 270 // Ich suche bereits global! 271 sal_uInt16 nPar = pCur->pParent->GetFlags(); 272 pCur->pParent->ResetFlag( SBX_GBLSEARCH ); 273 pRes = pCur->pParent->Find( rName, t ); 274 pCur->SetFlags( nOwn ); 275 pCur->pParent->SetFlags( nPar ); 276 pCur = pCur->pParent; 277 } 278 } 279 #ifdef DBG_UTIL 280 nLvl--; 281 if( pRes ) 282 { 283 ByteString aNameStr3( (const UniString&)rName, RTL_TEXTENCODING_ASCII_US ); 284 ByteString aNameStr4( (const UniString&)SbxVariable::GetName(), RTL_TEXTENCODING_ASCII_US ); 285 DbgOutf( "SBX: Found %.*s %s in %s", 286 nLvl, " ", aNameStr3.GetBuffer(), aNameStr4.GetBuffer() ); 287 } 288 #endif 289 return pRes; 290 } 291 292 // Kurzform: Die Parent-Kette wird durchsucht 293 // Das ganze rekursiv, da Call() ueberladen sein kann 294 // Qualified Names sind zugelassen 295 296 sal_Bool SbxObject::Call( const XubString& rName, SbxArray* pParam ) 297 { 298 SbxVariable* pMeth = FindQualified( rName, SbxCLASS_DONTCARE); 299 if( pMeth && pMeth->ISA(SbxMethod) ) 300 { 301 // FindQualified() koennte schon zugeschlagen haben! 302 if( pParam ) 303 pMeth->SetParameters( pParam ); 304 pMeth->Broadcast( SBX_HINT_DATAWANTED ); 305 pMeth->SetParameters( NULL ); 306 return sal_True; 307 } 308 SetError( SbxERR_NO_METHOD ); 309 return sal_False; 310 } 311 312 SbxProperty* SbxObject::GetDfltProperty() 313 { 314 if ( !pDfltProp && aDfltPropName.Len() ) 315 { 316 pDfltProp = (SbxProperty*) Find( aDfltPropName, SbxCLASS_PROPERTY ); 317 if( !pDfltProp ) 318 pDfltProp = (SbxProperty*) Make( aDfltPropName, SbxCLASS_PROPERTY, SbxVARIANT ); 319 } 320 return pDfltProp; 321 } 322 void SbxObject::SetDfltProperty( const XubString& rName ) 323 { 324 if ( rName != aDfltPropName ) 325 pDfltProp = NULL; 326 aDfltPropName = rName; 327 SetModified( sal_True ); 328 } 329 330 void SbxObject::SetDfltProperty( SbxProperty* p ) 331 { 332 if( p ) 333 { 334 sal_uInt16 n; 335 SbxArray* pArray = FindVar( p, n ); 336 pArray->Put( p, n ); 337 if( p->GetParent() != this ) 338 p->SetParent( this ); 339 Broadcast( SBX_HINT_OBJECTCHANGED ); 340 } 341 pDfltProp = p; 342 SetModified( sal_True ); 343 } 344 345 // Suchen einer bereits vorhandenen Variablen. Falls sie gefunden wurde, 346 // wird der Index gesetzt, sonst wird der Count des Arrays geliefert. 347 // In jedem Fall wird das korrekte Array geliefert. 348 349 SbxArray* SbxObject::FindVar( SbxVariable* pVar, sal_uInt16& nArrayIdx ) 350 { 351 SbxArray* pArray = NULL; 352 if( pVar ) switch( pVar->GetClass() ) 353 { 354 case SbxCLASS_VARIABLE: 355 case SbxCLASS_PROPERTY: pArray = pProps; break; 356 case SbxCLASS_METHOD: pArray = pMethods; break; 357 case SbxCLASS_OBJECT: pArray = pObjs; break; 358 default: 359 DBG_ASSERT( !this, "Ungueltige SBX-Klasse" ); 360 } 361 if( pArray ) 362 { 363 nArrayIdx = pArray->Count(); 364 // ist die Variable per Name vorhanden? 365 pArray->ResetFlag( SBX_EXTSEARCH ); 366 SbxVariable* pOld = pArray->Find( pVar->GetName(), pVar->GetClass() ); 367 if( pOld ) 368 for( sal_uInt16 i = 0; i < pArray->Count(); i++ ) 369 { 370 SbxVariableRef& rRef = pArray->GetRef( i ); 371 if( (SbxVariable*) rRef == pOld ) 372 { 373 nArrayIdx = i; break; 374 } 375 } 376 } 377 return pArray; 378 } 379 380 // Falls ein neues Objekt eingerichtet wird, wird es, falls es bereits 381 // eines mit diesem Namen gibt, indiziert. 382 383 SbxVariable* SbxObject::Make( const XubString& rName, SbxClassType ct, SbxDataType dt ) 384 { 385 // Ist das Objekt bereits vorhanden? 386 SbxArray* pArray = NULL; 387 switch( ct ) 388 { 389 case SbxCLASS_VARIABLE: 390 case SbxCLASS_PROPERTY: pArray = pProps; break; 391 case SbxCLASS_METHOD: pArray = pMethods; break; 392 case SbxCLASS_OBJECT: pArray = pObjs; break; 393 default: 394 DBG_ASSERT( !this, "Ungueltige SBX-Klasse" ); 395 } 396 if( !pArray ) 397 return NULL; 398 // Collections duerfen gleichnamige Objekte enthalten 399 if( !( ct == SbxCLASS_OBJECT && ISA(SbxCollection) ) ) 400 { 401 SbxVariable* pRes = pArray->Find( rName, ct ); 402 if( pRes ) 403 { 404 /* Wegen haeufiger Probleme (z.B. #67000) erstmal ganz raus 405 #ifdef DBG_UTIL 406 if( pRes->GetHashCode() != nNameHash 407 && pRes->GetHashCode() != nParentHash ) 408 { 409 XubString aMsg( "SBX-Element \"" ); 410 aMsg += pRes->GetName(); 411 aMsg += "\"\n in Objekt \""; 412 aMsg += GetName(); 413 aMsg += "\" bereits vorhanden"; 414 DbgError( (const char*)aMsg.GetStr() ); 415 } 416 #endif 417 */ 418 return pRes; 419 } 420 } 421 SbxVariable* pVar = NULL; 422 switch( ct ) 423 { 424 case SbxCLASS_VARIABLE: 425 case SbxCLASS_PROPERTY: 426 pVar = new SbxProperty( rName, dt ); 427 break; 428 case SbxCLASS_METHOD: 429 pVar = new SbxMethod( rName, dt ); 430 break; 431 case SbxCLASS_OBJECT: 432 pVar = CreateObject( rName ); 433 break; 434 default: break; 435 } 436 pVar->SetParent( this ); 437 pArray->Put( pVar, pArray->Count() ); 438 SetModified( sal_True ); 439 // Das Objekt lauscht immer 440 StartListening( pVar->GetBroadcaster(), sal_True ); 441 Broadcast( SBX_HINT_OBJECTCHANGED ); 442 return pVar; 443 } 444 445 SbxObject* SbxObject::MakeObject( const XubString& rName, const XubString& rClass ) 446 { 447 // Ist das Objekt bereits vorhanden? 448 if( !ISA(SbxCollection) ) 449 { 450 SbxVariable* pRes = pObjs->Find( rName, SbxCLASS_OBJECT ); 451 if( pRes ) 452 { 453 /* Wegen haeufiger Probleme (z.B. #67000) erstmal ganz raus 454 #ifdef DBG_UTIL 455 if( pRes->GetHashCode() != nNameHash 456 && pRes->GetHashCode() != nParentHash ) 457 { 458 XubString aMsg( "SBX-Objekt \"" ); 459 aMsg += pRes->GetName(); 460 aMsg += "\"\n in Objekt \""; 461 aMsg += GetName(); 462 aMsg += "\" bereits vorhanden"; 463 DbgError( (const char*)aMsg.GetStr() ); 464 } 465 #endif 466 */ 467 return PTR_CAST(SbxObject,pRes); 468 } 469 } 470 SbxObject* pVar = CreateObject( rClass ); 471 if( pVar ) 472 { 473 pVar->SetName( rName ); 474 pVar->SetParent( this ); 475 pObjs->Put( pVar, pObjs->Count() ); 476 SetModified( sal_True ); 477 // Das Objekt lauscht immer 478 StartListening( pVar->GetBroadcaster(), sal_True ); 479 Broadcast( SBX_HINT_OBJECTCHANGED ); 480 } 481 return pVar; 482 } 483 484 void SbxObject::Insert( SbxVariable* pVar ) 485 { 486 sal_uInt16 nIdx; 487 SbxArray* pArray = FindVar( pVar, nIdx ); 488 if( pArray ) 489 { 490 // Hinein damit. Man sollte allerdings auf die Pointer aufpassen! 491 if( nIdx < pArray->Count() ) 492 { 493 // dann gibt es dieses Element bereits 494 // Bei Collections duerfen gleichnamige Objekte hinein 495 if( pArray == pObjs && ISA(SbxCollection) ) 496 nIdx = pArray->Count(); 497 else 498 { 499 SbxVariable* pOld = pArray->Get( nIdx ); 500 // schon drin: ueberschreiben 501 if( pOld == pVar ) 502 return; 503 504 /* Wegen haeufiger Probleme (z.B. #67000) erstmal ganz raus 505 #ifdef DBG_UTIL 506 if( pOld->GetHashCode() != nNameHash 507 && pOld->GetHashCode() != nParentHash ) 508 { 509 XubString aMsg( "SBX-Element \"" ); 510 aMsg += pVar->GetName(); 511 aMsg += "\"\n in Objekt \""; 512 aMsg += GetName(); 513 aMsg += "\" bereits vorhanden"; 514 DbgError( (const char*)aMsg.GetStr() ); 515 } 516 #endif 517 */ 518 EndListening( pOld->GetBroadcaster(), sal_True ); 519 if( pVar->GetClass() == SbxCLASS_PROPERTY ) 520 { 521 if( pOld == pDfltProp ) 522 pDfltProp = (SbxProperty*) pVar; 523 } 524 } 525 } 526 StartListening( pVar->GetBroadcaster(), sal_True ); 527 pArray->Put( pVar, nIdx ); 528 if( pVar->GetParent() != this ) 529 pVar->SetParent( this ); 530 SetModified( sal_True ); 531 Broadcast( SBX_HINT_OBJECTCHANGED ); 532 #ifdef DBG_UTIL 533 static const char* pCls[] = 534 { "DontCare","Array","Value","Variable","Method","Property","Object" }; 535 XubString aVarName( pVar->GetName() ); 536 if ( !aVarName.Len() && pVar->ISA(SbxObject) ) 537 aVarName = PTR_CAST(SbxObject,pVar)->GetClassName(); 538 ByteString aNameStr1( (const UniString&)aVarName, RTL_TEXTENCODING_ASCII_US ); 539 ByteString aNameStr2( (const UniString&)SbxVariable::GetName(), RTL_TEXTENCODING_ASCII_US ); 540 DbgOutf( "SBX: Insert %s %s in %s", 541 ( pVar->GetClass() >= SbxCLASS_DONTCARE && 542 pVar->GetClass() <= SbxCLASS_OBJECT ) 543 ? pCls[ pVar->GetClass()-1 ] : "Unknown class", aNameStr1.GetBuffer(), aNameStr1.GetBuffer() ); 544 #endif 545 } 546 } 547 548 // AB 23.4.1997, Optimierung, Einfuegen ohne Ueberpruefung auf doppelte 549 // Eintraege und ohne Broadcasts, wird nur in SO2/auto.cxx genutzt 550 void SbxObject::QuickInsert( SbxVariable* pVar ) 551 { 552 SbxArray* pArray = NULL; 553 if( pVar ) 554 { 555 switch( pVar->GetClass() ) 556 { 557 case SbxCLASS_VARIABLE: 558 case SbxCLASS_PROPERTY: pArray = pProps; break; 559 case SbxCLASS_METHOD: pArray = pMethods; break; 560 case SbxCLASS_OBJECT: pArray = pObjs; break; 561 default: 562 DBG_ASSERT( !this, "Ungueltige SBX-Klasse" ); 563 } 564 } 565 if( pArray ) 566 { 567 StartListening( pVar->GetBroadcaster(), sal_True ); 568 pArray->Put( pVar, pArray->Count() ); 569 if( pVar->GetParent() != this ) 570 pVar->SetParent( this ); 571 SetModified( sal_True ); 572 #ifdef DBG_UTIL 573 static const char* pCls[] = 574 { "DontCare","Array","Value","Variable","Method","Property","Object" }; 575 XubString aVarName( pVar->GetName() ); 576 if ( !aVarName.Len() && pVar->ISA(SbxObject) ) 577 aVarName = PTR_CAST(SbxObject,pVar)->GetClassName(); 578 ByteString aNameStr1( (const UniString&)aVarName, RTL_TEXTENCODING_ASCII_US ); 579 ByteString aNameStr2( (const UniString&)SbxVariable::GetName(), RTL_TEXTENCODING_ASCII_US ); 580 DbgOutf( "SBX: Insert %s %s in %s", 581 ( pVar->GetClass() >= SbxCLASS_DONTCARE && 582 pVar->GetClass() <= SbxCLASS_OBJECT ) 583 ? pCls[ pVar->GetClass()-1 ] : "Unknown class", aNameStr1.GetBuffer(), aNameStr1.GetBuffer() ); 584 #endif 585 } 586 } 587 588 // AB 23.3.1997, Spezial-Methode, gleichnamige Controls zulassen 589 void SbxObject::VCPtrInsert( SbxVariable* pVar ) 590 { 591 SbxArray* pArray = NULL; 592 if( pVar ) 593 { 594 switch( pVar->GetClass() ) 595 { 596 case SbxCLASS_VARIABLE: 597 case SbxCLASS_PROPERTY: pArray = pProps; break; 598 case SbxCLASS_METHOD: pArray = pMethods; break; 599 case SbxCLASS_OBJECT: pArray = pObjs; break; 600 default: 601 DBG_ASSERT( !this, "Ungueltige SBX-Klasse" ); 602 } 603 } 604 if( pArray ) 605 { 606 StartListening( pVar->GetBroadcaster(), sal_True ); 607 pArray->Put( pVar, pArray->Count() ); 608 if( pVar->GetParent() != this ) 609 pVar->SetParent( this ); 610 SetModified( sal_True ); 611 Broadcast( SBX_HINT_OBJECTCHANGED ); 612 } 613 } 614 615 void SbxObject::Remove( const XubString& rName, SbxClassType t ) 616 { 617 Remove( SbxObject::Find( rName, t ) ); 618 } 619 620 void SbxObject::Remove( SbxVariable* pVar ) 621 { 622 sal_uInt16 nIdx; 623 SbxArray* pArray = FindVar( pVar, nIdx ); 624 if( pArray && nIdx < pArray->Count() ) 625 { 626 #ifdef DBG_UTIL 627 XubString aVarName( pVar->GetName() ); 628 if ( !aVarName.Len() && pVar->ISA(SbxObject) ) 629 aVarName = PTR_CAST(SbxObject,pVar)->GetClassName(); 630 ByteString aNameStr1( (const UniString&)aVarName, RTL_TEXTENCODING_ASCII_US ); 631 ByteString aNameStr2( (const UniString&)SbxVariable::GetName(), RTL_TEXTENCODING_ASCII_US ); 632 #endif 633 SbxVariableRef pVar_ = pArray->Get( nIdx ); 634 if( pVar_->IsBroadcaster() ) 635 EndListening( pVar_->GetBroadcaster(), sal_True ); 636 if( (SbxVariable*) pVar_ == pDfltProp ) 637 pDfltProp = NULL; 638 pArray->Remove( nIdx ); 639 if( pVar_->GetParent() == this ) 640 pVar_->SetParent( NULL ); 641 SetModified( sal_True ); 642 Broadcast( SBX_HINT_OBJECTCHANGED ); 643 } 644 } 645 646 // AB 23.3.1997, Loeschen per Pointer fuer Controls (doppelte Namen!) 647 void SbxObject::VCPtrRemove( SbxVariable* pVar ) 648 { 649 sal_uInt16 nIdx; 650 // Neu FindVar-Methode, sonst identisch mit normaler Methode 651 SbxArray* pArray = VCPtrFindVar( pVar, nIdx ); 652 if( pArray && nIdx < pArray->Count() ) 653 { 654 SbxVariableRef xVar = pArray->Get( nIdx ); 655 if( xVar->IsBroadcaster() ) 656 EndListening( xVar->GetBroadcaster(), sal_True ); 657 if( (SbxVariable*) xVar == pDfltProp ) 658 pDfltProp = NULL; 659 pArray->Remove( nIdx ); 660 if( xVar->GetParent() == this ) 661 xVar->SetParent( NULL ); 662 SetModified( sal_True ); 663 Broadcast( SBX_HINT_OBJECTCHANGED ); 664 } 665 } 666 667 // AB 23.3.1997, Zugehoerige Spezial-Methode, nur ueber Pointer suchen 668 SbxArray* SbxObject::VCPtrFindVar( SbxVariable* pVar, sal_uInt16& nArrayIdx ) 669 { 670 SbxArray* pArray = NULL; 671 if( pVar ) switch( pVar->GetClass() ) 672 { 673 case SbxCLASS_VARIABLE: 674 case SbxCLASS_PROPERTY: pArray = pProps; break; 675 case SbxCLASS_METHOD: pArray = pMethods; break; 676 case SbxCLASS_OBJECT: pArray = pObjs; break; 677 default: 678 DBG_ASSERT( !this, "Ungueltige SBX-Klasse" ); 679 } 680 if( pArray ) 681 { 682 nArrayIdx = pArray->Count(); 683 for( sal_uInt16 i = 0; i < pArray->Count(); i++ ) 684 { 685 SbxVariableRef& rRef = pArray->GetRef( i ); 686 if( (SbxVariable*) rRef == pVar ) 687 { 688 nArrayIdx = i; break; 689 } 690 } 691 } 692 return pArray; 693 } 694 695 696 697 void SbxObject::SetPos( SbxVariable* pVar, sal_uInt16 nPos ) 698 { 699 sal_uInt16 nIdx; 700 SbxArray* pArray = FindVar( pVar, nIdx ); 701 if( pArray ) 702 { 703 if( nPos >= pArray->Count() ) 704 nPos = pArray->Count() - 1; 705 if( nIdx < ( pArray->Count() - 1 ) ) 706 { 707 SbxVariableRef refVar = pArray->Get( nIdx ); 708 pArray->Remove( nIdx ); 709 pArray->Insert( refVar, nPos ); 710 } 711 } 712 // SetModified( sal_True ); 713 // Broadcast( SBX_HINT_OBJECTCHANGED ); 714 } 715 716 static sal_Bool LoadArray( SvStream& rStrm, SbxObject* pThis, SbxArray* pArray ) 717 { 718 SbxArrayRef p = (SbxArray*) SbxBase::Load( rStrm ); 719 if( !p.Is() ) 720 return sal_False; 721 for( sal_uInt16 i = 0; i < p->Count(); i++ ) 722 { 723 SbxVariableRef& r = p->GetRef( i ); 724 SbxVariable* pVar = r; 725 if( pVar ) 726 { 727 pVar->SetParent( pThis ); 728 pThis->StartListening( pVar->GetBroadcaster(), sal_True ); 729 } 730 } 731 pArray->Merge( p ); 732 return sal_True; 733 } 734 735 // Der Load eines Objekts ist additiv! 736 737 sal_Bool SbxObject::LoadData( SvStream& rStrm, sal_uInt16 nVer ) 738 { 739 // Hilfe fuer das Einlesen alter Objekte: einfach sal_True zurueck, 740 // LoadPrivateData() muss Default-Zustand herstellen 741 if( !nVer ) 742 return sal_True; 743 744 pDfltProp = NULL; 745 if( !SbxVariable::LoadData( rStrm, nVer ) ) 746 return sal_False; 747 // Wenn kein fremdes Objekt enthalten ist, uns selbst eintragen 748 if( aData.eType == SbxOBJECT && !aData.pObj ) 749 aData.pObj = this; 750 sal_uInt32 nSize; 751 XubString aDfltProp; 752 rStrm.ReadByteString( aClassName, RTL_TEXTENCODING_ASCII_US ); 753 rStrm.ReadByteString( aDfltProp, RTL_TEXTENCODING_ASCII_US ); 754 sal_uIntPtr nPos = rStrm.Tell(); 755 rStrm >> nSize; 756 if( !LoadPrivateData( rStrm, nVer ) ) 757 return sal_False; 758 sal_uIntPtr nNewPos = rStrm.Tell(); 759 nPos += nSize; 760 DBG_ASSERT( nPos >= nNewPos, "SBX: Zu viele Daten eingelesen" ); 761 if( nPos != nNewPos ) 762 rStrm.Seek( nPos ); 763 if( !LoadArray( rStrm, this, pMethods ) 764 || !LoadArray( rStrm, this, pProps ) 765 || !LoadArray( rStrm, this, pObjs ) ) 766 return sal_False; 767 // Properties setzen 768 if( aDfltProp.Len() ) 769 pDfltProp = (SbxProperty*) pProps->Find( aDfltProp, SbxCLASS_PROPERTY ); 770 SetModified( sal_False ); 771 return sal_True; 772 } 773 774 sal_Bool SbxObject::StoreData( SvStream& rStrm ) const 775 { 776 if( !SbxVariable::StoreData( rStrm ) ) 777 return sal_False; 778 XubString aDfltProp; 779 if( pDfltProp ) 780 aDfltProp = pDfltProp->GetName(); 781 rStrm.WriteByteString( aClassName, RTL_TEXTENCODING_ASCII_US ); 782 rStrm.WriteByteString( aDfltProp, RTL_TEXTENCODING_ASCII_US ); 783 sal_uIntPtr nPos = rStrm.Tell(); 784 rStrm << (sal_uInt32) 0L; 785 if( !StorePrivateData( rStrm ) ) 786 return sal_False; 787 sal_uIntPtr nNew = rStrm.Tell(); 788 rStrm.Seek( nPos ); 789 rStrm << (sal_uInt32) ( nNew - nPos ); 790 rStrm.Seek( nNew ); 791 if( !pMethods->Store( rStrm ) ) 792 return sal_False; 793 if( !pProps->Store( rStrm ) ) 794 return sal_False; 795 if( !pObjs->Store( rStrm ) ) 796 return sal_False; 797 ((SbxObject*) this)->SetModified( sal_False ); 798 return sal_True; 799 } 800 801 XubString SbxObject::GenerateSource( const XubString &rLinePrefix, 802 const SbxObject* ) 803 { 804 // Properties in einem String einsammeln 805 XubString aSource; 806 SbxArrayRef xProps( GetProperties() ); 807 bool bLineFeed = false; 808 for ( sal_uInt16 nProp = 0; nProp < xProps->Count(); ++nProp ) 809 { 810 SbxPropertyRef xProp = (SbxProperty*) xProps->Get(nProp); 811 XubString aPropName( xProp->GetName() ); 812 if ( xProp->CanWrite() 813 && !( xProp->GetHashCode() == nNameHash 814 && aPropName.EqualsIgnoreCaseAscii( pNameProp ) ) ) 815 { 816 // ausser vor dem ersten Property immer einen Umbruch einfuegen 817 if ( bLineFeed ) 818 aSource.AppendAscii( "\n" ); 819 else 820 bLineFeed = true; 821 822 aSource += rLinePrefix; 823 aSource += '.'; 824 aSource += aPropName; 825 aSource.AppendAscii( " = " ); 826 827 // den Property-Wert textuell darstellen 828 switch ( xProp->GetType() ) 829 { 830 case SbxEMPTY: 831 case SbxNULL: 832 // kein Wert 833 break; 834 835 case SbxSTRING: 836 { 837 // Strings in Anf"uhrungszeichen 838 aSource.AppendAscii( "\"" ); 839 aSource += xProp->GetString(); 840 aSource.AppendAscii( "\"" ); 841 break; 842 } 843 844 default: 845 { 846 // sonstiges wie z.B. Zahlen direkt 847 aSource += xProp->GetString(); 848 break; 849 } 850 } 851 } 852 } 853 return aSource; 854 } 855 856 static sal_Bool CollectAttrs( const SbxBase* p, XubString& rRes ) 857 { 858 XubString aAttrs; 859 if( p->IsHidden() ) 860 aAttrs.AssignAscii( "Hidden" ); 861 if( p->IsSet( SBX_EXTSEARCH ) ) 862 { 863 if( aAttrs.Len() ) 864 aAttrs += ','; 865 aAttrs.AppendAscii( "ExtSearch" ); 866 } 867 if( !p->IsVisible() ) 868 { 869 if( aAttrs.Len() ) 870 aAttrs += ','; 871 aAttrs.AppendAscii( "Invisible" ); 872 } 873 if( p->IsSet( SBX_DONTSTORE ) ) 874 { 875 if( aAttrs.Len() ) 876 aAttrs += ','; 877 aAttrs.AppendAscii( "DontStore" ); 878 } 879 if( aAttrs.Len() ) 880 { 881 rRes.AssignAscii( " (" ); 882 rRes += aAttrs; 883 rRes += ')'; 884 return sal_True; 885 } 886 else 887 { 888 rRes.Erase(); 889 return sal_False; 890 } 891 } 892 893 void SbxObject::Dump( SvStream& rStrm, sal_Bool bFill ) 894 { 895 // Einr"uckung 896 static sal_uInt16 nLevel = 0; 897 if ( nLevel > 10 ) 898 { 899 rStrm << "<too deep>" << endl; 900 return; 901 } 902 ++nLevel; 903 String aIndent; 904 for ( sal_uInt16 n = 1; n < nLevel; ++n ) 905 aIndent.AppendAscii( " " ); 906 907 // ggf. Objekt vervollst"andigen 908 if ( bFill ) 909 GetAll( SbxCLASS_DONTCARE ); 910 911 // Daten des Objekts selbst ausgeben 912 ByteString aNameStr( (const UniString&)GetName(), RTL_TEXTENCODING_ASCII_US ); 913 ByteString aClassNameStr( (const UniString&)aClassName, RTL_TEXTENCODING_ASCII_US ); 914 rStrm << "Object( " 915 << ByteString::CreateFromInt64( (sal_uIntPtr) this ).GetBuffer() << "=='" 916 << ( aNameStr.Len() ? aNameStr.GetBuffer() : "<unnamed>" ) << "', " 917 << "of class '" << aClassNameStr.GetBuffer() << "', " 918 << "counts " 919 << ByteString::CreateFromInt64( GetRefCount() ).GetBuffer() 920 << " refs, "; 921 if ( GetParent() ) 922 { 923 ByteString aParentNameStr( (const UniString&)GetName(), RTL_TEXTENCODING_ASCII_US ); 924 rStrm << "in parent " 925 << ByteString::CreateFromInt64( (sal_uIntPtr) GetParent() ).GetBuffer() 926 << "=='" << ( aParentNameStr.Len() ? aParentNameStr.GetBuffer() : "<unnamed>" ) << "'"; 927 } 928 else 929 rStrm << "no parent "; 930 rStrm << " )" << endl; 931 ByteString aIndentNameStr( (const UniString&)aIndent, RTL_TEXTENCODING_ASCII_US ); 932 rStrm << aIndentNameStr.GetBuffer() << "{" << endl; 933 934 // Flags 935 XubString aAttrs; 936 if( CollectAttrs( this, aAttrs ) ) 937 { 938 ByteString aAttrStr( (const UniString&)aAttrs, RTL_TEXTENCODING_ASCII_US ); 939 rStrm << aIndentNameStr.GetBuffer() << "- Flags: " << aAttrStr.GetBuffer() << endl; 940 } 941 942 // Methods 943 rStrm << aIndentNameStr.GetBuffer() << "- Methods:" << endl; 944 for( sal_uInt16 i = 0; i < pMethods->Count(); i++ ) 945 { 946 SbxVariableRef& r = pMethods->GetRef( i ); 947 SbxVariable* pVar = r; 948 if( pVar ) 949 { 950 XubString aLine( aIndent ); 951 aLine.AppendAscii( " - " ); 952 aLine += pVar->GetName( SbxNAME_SHORT_TYPES ); 953 XubString aAttrs2; 954 if( CollectAttrs( pVar, aAttrs2 ) ) 955 aLine += aAttrs2; 956 if( !pVar->IsA( TYPE(SbxMethod) ) ) 957 aLine.AppendAscii( " !! Not a Method !!" ); 958 rStrm.WriteByteString( aLine, RTL_TEXTENCODING_ASCII_US ); 959 960 // bei Object-Methods auch das Object ausgeben 961 if ( pVar->GetValues_Impl().eType == SbxOBJECT && 962 pVar->GetValues_Impl().pObj && 963 pVar->GetValues_Impl().pObj != this && 964 pVar->GetValues_Impl().pObj != GetParent() ) 965 { 966 rStrm << " contains "; 967 ((SbxObject*) pVar->GetValues_Impl().pObj)->Dump( rStrm, bFill ); 968 } 969 else 970 rStrm << endl; 971 } 972 } 973 974 // Properties 975 rStrm << aIndentNameStr.GetBuffer() << "- Properties:" << endl; 976 { 977 for( sal_uInt16 i = 0; i < pProps->Count(); i++ ) 978 { 979 SbxVariableRef& r = pProps->GetRef( i ); 980 SbxVariable* pVar = r; 981 if( pVar ) 982 { 983 XubString aLine( aIndent ); 984 aLine.AppendAscii( " - " ); 985 aLine += pVar->GetName( SbxNAME_SHORT_TYPES ); 986 XubString aAttrs3; 987 if( CollectAttrs( pVar, aAttrs3 ) ) 988 aLine += aAttrs3; 989 if( !pVar->IsA( TYPE(SbxProperty) ) ) 990 aLine.AppendAscii( " !! Not a Property !!" ); 991 rStrm.WriteByteString( aLine, RTL_TEXTENCODING_ASCII_US ); 992 993 // bei Object-Properties auch das Object ausgeben 994 if ( pVar->GetValues_Impl().eType == SbxOBJECT && 995 pVar->GetValues_Impl().pObj && 996 pVar->GetValues_Impl().pObj != this && 997 pVar->GetValues_Impl().pObj != GetParent() ) 998 { 999 rStrm << " contains "; 1000 ((SbxObject*) pVar->GetValues_Impl().pObj)->Dump( rStrm, bFill ); 1001 } 1002 else 1003 rStrm << endl; 1004 } 1005 } 1006 } 1007 1008 // Objects 1009 rStrm << aIndentNameStr.GetBuffer() << "- Objects:" << endl; 1010 { 1011 for( sal_uInt16 i = 0; i < pObjs->Count(); i++ ) 1012 { 1013 SbxVariableRef& r = pObjs->GetRef( i ); 1014 SbxVariable* pVar = r; 1015 if ( pVar ) 1016 { 1017 rStrm << aIndentNameStr.GetBuffer() << " - Sub"; 1018 if ( pVar->ISA(SbxObject) ) 1019 ((SbxObject*) pVar)->Dump( rStrm, bFill ); 1020 else if ( pVar->ISA(SbxVariable) ) 1021 ((SbxVariable*) pVar)->Dump( rStrm, bFill ); 1022 } 1023 } 1024 } 1025 1026 rStrm << aIndentNameStr.GetBuffer() << "}" << endl << endl; 1027 --nLevel; 1028 } 1029 1030 SvDispatch* SbxObject::GetSvDispatch() 1031 { 1032 return NULL; 1033 } 1034 1035 sal_Bool SbxMethod::Run( SbxValues* pValues ) 1036 { 1037 SbxValues aRes; 1038 if( !pValues ) 1039 pValues = &aRes; 1040 pValues->eType = SbxVARIANT; 1041 return Get( *pValues ); 1042 } 1043 1044 SbxClassType SbxMethod::GetClass() const 1045 { 1046 return SbxCLASS_METHOD; 1047 } 1048 1049 SbxClassType SbxProperty::GetClass() const 1050 { 1051 return SbxCLASS_PROPERTY; 1052 } 1053 1054 void SbxObject::GarbageCollection( sal_uIntPtr nObjects ) 1055 1056 /* [Beschreibung] 1057 1058 Diese statische Methode durchsucht die n"achsten 'nObjects' der zur Zeit 1059 existierenden <SbxObject>-Instanzen nach zyklischen Referenzen, die sich 1060 nur noch selbst am Leben erhalten. Ist 'nObjects==0', dann werden 1061 alle existierenden durchsucht. 1062 1063 zur Zeit nur implementiert: Object -> Parent-Property -> Parent -> Object 1064 */ 1065 1066 { 1067 (void)nObjects; 1068 1069 static sal_Bool bInGarbageCollection = sal_False; 1070 if ( bInGarbageCollection ) 1071 return; 1072 bInGarbageCollection = sal_True; 1073 1074 #if 0 1075 // erstes Object dieser Runde anspringen 1076 sal_Bool bAll = !nObjects; 1077 if ( bAll ) 1078 rObjects.First(); 1079 SbxObject *pObj = rObjects.GetCurObject(); 1080 if ( !pObj ) 1081 pObj = rObjects.First(); 1082 1083 while ( pObj && 0 != nObjects-- ) 1084 { 1085 // hat der Parent nur noch 1 Ref-Count? 1086 SbxObject *pParent = PTR_CAST( SbxObject, pObj->GetParent() ); 1087 if ( pParent && 1 == pParent->GetRefCount() ) 1088 { 1089 // dann alle Properies des Objects durchsuchen 1090 SbxArray *pProps = pObj->GetProperties(); 1091 for ( sal_uInt16 n = 0; n < pProps->Count(); ++n ) 1092 { 1093 // verweist die Property auf den Parent des Object? 1094 SbxVariable *pProp = pProps->Get(n); 1095 const SbxValues &rValues = pProp->GetValues_Impl(); 1096 if ( SbxOBJECT == rValues.eType && 1097 pParent == rValues.pObj ) 1098 { 1099 #ifdef DBG_UTIL 1100 DbgOutf( "SBX: %s.%s with Object %s was garbage", 1101 pObj->GetName().GetStr(), 1102 pProp->GetName().GetStr(), 1103 pParent->GetName().GetStr() ); 1104 #endif 1105 // dann freigeben 1106 pProp->SbxValue::Clear(); 1107 Sound::Beep(); 1108 break; 1109 } 1110 } 1111 } 1112 1113 // zum n"achsten 1114 pObj = rObjects.Next(); 1115 if ( !bAll && !pObj ) 1116 pObj = rObjects.First(); 1117 } 1118 #endif 1119 1120 // AB 28.10. Zur 507a vorerst raus, da SfxBroadcaster::Enable() wegfaellt 1121 #if 0 1122 #ifdef DBG_UTIL 1123 SbxVarList_Impl &rVars = GetSbxData_Impl()->aVars; 1124 DbgOutf( "SBX: garbage collector done, %lu objects remainding", 1125 rVars.Count() ); 1126 if ( rVars.Count() > 200 && rVars.Count() < 210 ) 1127 { 1128 SvFileStream aStream( "d:\\tmp\\dump.sbx", STREAM_STD_WRITE ); 1129 SfxBroadcaster::Enable(sal_False); 1130 for ( sal_uIntPtr n = 0; n < rVars.Count(); ++n ) 1131 { 1132 SbxVariable *pVar = rVars.GetObject(n); 1133 SbxObject *pObj = PTR_CAST(SbxObject, pVar); 1134 sal_uInt16 nFlags = pVar->GetFlags(); 1135 pVar->SetFlag(SBX_NO_BROADCAST); 1136 if ( pObj ) 1137 pObj->Dump(aStream); 1138 else if ( !pVar->GetParent() || !pVar->GetParent()->ISA(SbxObject) ) 1139 pVar->Dump(aStream); 1140 pVar->SetFlags(nFlags); 1141 } 1142 SfxBroadcaster::Enable(sal_True); 1143 } 1144 #endif 1145 #endif 1146 bInGarbageCollection = sal_False; 1147 } 1148 1149