1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_basic.hxx" 26 27 28 #include <tools/stream.hxx> 29 #include "svl/brdcst.hxx" 30 31 #include <basic/sbx.hxx> 32 #include <basic/sbxbase.hxx> 33 #include "sbxres.hxx" 34 #include "sbxconv.hxx" 35 #include <math.h> 36 #include <ctype.h> 37 38 #include "com/sun/star/uno/XInterface.hpp" 39 using namespace com::sun::star::uno; 40 41 ///////////////////////////// SbxVariable ////////////////////////////// 42 43 TYPEINIT1(SbxVariable,SbxValue) 44 TYPEINIT1(SbxHint,SfxSimpleHint) 45 46 extern sal_uInt32 nVarCreator; // in SBXBASE.CXX, fuer LoadData() 47 #ifdef DBG_UTIL 48 static sal_uIntPtr nVar = 0; 49 #endif 50 51 ///////////////////////////// SbxVariableImpl //////////////////////////// 52 53 class SbxVariableImpl 54 { 55 friend class SbxVariable; 56 String m_aDeclareClassName; 57 Reference< XInterface > m_xComListener; 58 StarBASIC* m_pComListenerParentBasic; 59 60 SbxVariableImpl( void ) 61 : m_pComListenerParentBasic( NULL ) 62 {} 63 SbxVariableImpl( const SbxVariableImpl& r ) 64 : m_aDeclareClassName( r.m_aDeclareClassName ) 65 , m_xComListener( r.m_xComListener ) 66 , m_pComListenerParentBasic( r.m_pComListenerParentBasic ) 67 { 68 } 69 }; 70 71 72 ///////////////////////////// Konstruktoren ////////////////////////////// 73 74 SbxVariable::SbxVariable() : SbxValue() 75 { 76 mpSbxVariableImpl = NULL; 77 pCst = NULL; 78 pParent = NULL; 79 nUserData = 0; 80 nHash = 0; 81 #ifdef DBG_UTIL 82 DbgOutf( "SbxVariable::Ctor %lx=%ld", (void*)this, ++nVar ); 83 GetSbxData_Impl()->aVars.Insert( this, LIST_APPEND ); 84 #endif 85 } 86 87 void registerComListenerVariableForBasic( SbxVariable* pVar, StarBASIC* pBasic ); 88 89 SbxVariable::SbxVariable( const SbxVariable& r ) 90 : SvRefBase( r ), SbxValue( r ), mpPar( r.mpPar ), pInfo( r.pInfo ) 91 { 92 mpSbxVariableImpl = NULL; 93 if( r.mpSbxVariableImpl != NULL ) 94 { 95 mpSbxVariableImpl = new SbxVariableImpl( *r.mpSbxVariableImpl ); 96 if( mpSbxVariableImpl->m_xComListener.is() ) 97 registerComListenerVariableForBasic( this, mpSbxVariableImpl->m_pComListenerParentBasic ); 98 } 99 pCst = NULL; 100 if( r.CanRead() ) 101 { 102 pParent = r.pParent; 103 nUserData = r.nUserData; 104 maName = r.maName; 105 nHash = r.nHash; 106 } 107 else 108 { 109 pParent = NULL; 110 nUserData = 0; 111 nHash = 0; 112 } 113 #ifdef DBG_UTIL 114 static sal_Char const aCellsStr[] = "Cells"; 115 if ( maName.EqualsAscii( aCellsStr ) ) 116 maName.AssignAscii( aCellsStr, sizeof( aCellsStr )-1 ); 117 DbgOutf( "SbxVariable::Ctor %lx=%ld", (void*)this, ++nVar ); 118 GetSbxData_Impl()->aVars.Insert( this, LIST_APPEND ); 119 #endif 120 } 121 122 SbxVariable::SbxVariable( SbxDataType t, void* p ) : SbxValue( t, p ) 123 { 124 mpSbxVariableImpl = NULL; 125 pCst = NULL; 126 pParent = NULL; 127 nUserData = 0; 128 nHash = 0; 129 #ifdef DBG_UTIL 130 DbgOutf( "SbxVariable::Ctor %lx=%ld", (void*)this, ++nVar ); 131 GetSbxData_Impl()->aVars.Insert( this, LIST_APPEND ); 132 #endif 133 } 134 135 void removeDimAsNewRecoverItem( SbxVariable* pVar ); 136 137 SbxVariable::~SbxVariable() 138 { 139 #ifdef DBG_UTIL 140 ByteString aBStr( (const UniString&)maName, RTL_TEXTENCODING_ASCII_US ); 141 DbgOutf( "SbxVariable::Dtor %lx (%s)", (void*)this, aBStr.GetBuffer() ); 142 static sal_Char const aCellsStr[] = "Cells"; 143 if ( maName.EqualsAscii( aCellsStr ) ) 144 maName.AssignAscii( aCellsStr, sizeof( aCellsStr )-1 ); 145 GetSbxData_Impl()->aVars.Remove( this ); 146 #endif 147 if( IsSet( SBX_DIM_AS_NEW )) 148 removeDimAsNewRecoverItem( this ); 149 delete mpSbxVariableImpl; 150 delete pCst; 151 } 152 153 ////////////////////////////// Broadcasting ////////////////////////////// 154 155 SfxBroadcaster& SbxVariable::GetBroadcaster() 156 { 157 if( !pCst ) 158 pCst = new SfxBroadcaster; 159 return *pCst; 160 } 161 162 // Eines Tages kann man vielleicht den Parameter 0 schleifen, 163 // dann entfaellt die Kopiererei... 164 165 void SbxVariable::Broadcast( sal_uIntPtr nHintId ) 166 { 167 if( pCst && !IsSet( SBX_NO_BROADCAST ) && StaticIsEnabledBroadcasting() ) 168 { 169 // Da die Methode von aussen aufrufbar ist, hier noch einmal 170 // die Berechtigung testen 171 if( nHintId & SBX_HINT_DATAWANTED ) 172 if( !CanRead() ) 173 return; 174 if( nHintId & SBX_HINT_DATACHANGED ) 175 if( !CanWrite() ) 176 return; 177 // Weitere Broadcasts verhindern 178 SfxBroadcaster* pSave = pCst; 179 pCst = NULL; 180 sal_uInt16 nSaveFlags = GetFlags(); 181 SetFlag( SBX_READWRITE ); 182 if( mpPar.Is() ) 183 // this, als Element 0 eintragen, aber den Parent nicht umsetzen! 184 mpPar->GetRef( 0 ) = this; 185 pSave->Broadcast( SbxHint( nHintId, this ) ); 186 delete pCst; // wer weiss schon, auf welche Gedanken mancher kommt? 187 pCst = pSave; 188 SetFlags( nSaveFlags ); 189 } 190 } 191 192 SbxInfo* SbxVariable::GetInfo() 193 { 194 if( !pInfo ) 195 { 196 Broadcast( SBX_HINT_INFOWANTED ); 197 if( pInfo.Is() ) 198 SetModified( sal_True ); 199 } 200 return pInfo; 201 } 202 203 void SbxVariable::SetInfo( SbxInfo* p ) 204 { 205 pInfo = p; 206 } 207 208 void SbxVariable::SetParameters( SbxArray* p ) 209 { 210 mpPar = p; 211 } 212 213 214 /////////////////////////// Name der Variablen /////////////////////////// 215 216 void SbxVariable::SetName( const XubString& rName ) 217 { 218 maName = rName; 219 nHash = MakeHashCode( rName ); 220 } 221 222 const XubString& SbxVariable::GetName( SbxNameType t ) const 223 { 224 static char cSuffixes[] = " %&!#@ $"; 225 if( t == SbxNAME_NONE ) 226 return maName; 227 // Parameter-Infos anfordern (nicht fuer Objekte) 228 ((SbxVariable*)this)->GetInfo(); 229 // Nix anfuegen, wenn einfache Property (keine leeren Klammern) 230 if( !pInfo 231 || ( !pInfo->aParams.Count() && GetClass() == SbxCLASS_PROPERTY ) ) 232 return maName; 233 xub_Unicode cType = ' '; 234 XubString aTmp( maName ); 235 // Kurzer Typ? Dann holen, evtl. ist dieser 0. 236 SbxDataType et = GetType(); 237 if( t == SbxNAME_SHORT_TYPES ) 238 { 239 if( et <= SbxSTRING ) 240 cType = cSuffixes[ et ]; 241 if( cType != ' ' ) 242 aTmp += cType; 243 } 244 aTmp += '('; 245 for( sal_uInt16 i = 0; i < pInfo->aParams.Count(); i++ ) 246 { 247 const SbxParamInfo* q = pInfo->aParams.GetObject( i ); 248 int nt = q->eType & 0x0FFF; 249 if( i ) 250 aTmp += ','; 251 if( q->nFlags & SBX_OPTIONAL ) 252 aTmp += String( SbxRes( STRING_OPTIONAL ) ); 253 if( q->eType & SbxBYREF ) 254 aTmp += String( SbxRes( STRING_BYREF ) ); 255 aTmp += q->aName; 256 cType = ' '; 257 // Kurzer Typ? Dann holen, evtl. ist dieser 0. 258 if( t == SbxNAME_SHORT_TYPES ) 259 { 260 if( nt <= SbxSTRING ) 261 cType = cSuffixes[ nt ]; 262 } 263 if( cType != ' ' ) 264 { 265 aTmp += cType; 266 if( q->eType & SbxARRAY ) 267 aTmp.AppendAscii( "()" ); 268 } 269 else 270 { 271 if( q->eType & SbxARRAY ) 272 aTmp.AppendAscii( "()" ); 273 // langer Typ? 274 if( t != SbxNAME_SHORT ) 275 { 276 aTmp += String( SbxRes( STRING_AS ) ); 277 if( nt < 32 ) 278 aTmp += String( SbxRes( 279 sal::static_int_cast< sal_uInt16 >( STRING_TYPES + nt ) ) ); 280 else 281 aTmp += String( SbxRes( STRING_ANY ) ); 282 } 283 } 284 } 285 aTmp += ')'; 286 // Langer Typ? Dann holen 287 if( t == SbxNAME_LONG_TYPES && et != SbxEMPTY ) 288 { 289 aTmp += String( SbxRes( STRING_AS ) ); 290 if( et < 32 ) 291 aTmp += String( SbxRes( 292 sal::static_int_cast< sal_uInt16 >( STRING_TYPES + et ) ) ); 293 else 294 aTmp += String( SbxRes( STRING_ANY ) ); 295 } 296 ((SbxVariable*) this)->aToolString = aTmp; 297 return aToolString; 298 } 299 300 // Einen simplen Hashcode erzeugen: Es werden die ersten 6 Zeichen gewertet. 301 302 sal_uInt16 SbxVariable::MakeHashCode( const XubString& rName ) 303 { 304 sal_uInt16 n = 0; 305 sal_uInt16 nLen = rName.Len(); 306 if( nLen > 6 ) 307 nLen = 6; 308 const xub_Unicode* p = rName.GetBuffer(); 309 while( nLen-- ) 310 { 311 sal_uInt8 c = (sal_uInt8)*p; 312 p++; 313 // Falls wir ein Schweinezeichen haben, abbrechen!! 314 if( c >= 0x80 ) 315 return 0; 316 n = sal::static_int_cast< sal_uInt16 >( ( n << 3 ) + toupper( c ) ); 317 } 318 return n; 319 } 320 321 ////////////////////////////// Operatoren //////////////////////////////// 322 323 SbxVariable& SbxVariable::operator=( const SbxVariable& r ) 324 { 325 SbxValue::operator=( r ); 326 delete mpSbxVariableImpl; 327 if( r.mpSbxVariableImpl != NULL ) 328 { 329 mpSbxVariableImpl = new SbxVariableImpl( *r.mpSbxVariableImpl ); 330 if( mpSbxVariableImpl->m_xComListener.is() ) 331 registerComListenerVariableForBasic( this, mpSbxVariableImpl->m_pComListenerParentBasic ); 332 } 333 else 334 mpSbxVariableImpl = NULL; 335 return *this; 336 } 337 338 //////////////////////////////// Konversion //////////////////////////////// 339 340 SbxDataType SbxVariable::GetType() const 341 { 342 if( aData.eType == SbxOBJECT ) 343 return aData.pObj ? aData.pObj->GetType() : SbxOBJECT; 344 else if( aData.eType == SbxVARIANT ) 345 return aData.pObj ? aData.pObj->GetType() : SbxVARIANT; 346 else 347 return aData.eType; 348 } 349 350 SbxClassType SbxVariable::GetClass() const 351 { 352 return SbxCLASS_VARIABLE; 353 } 354 355 void SbxVariable::SetModified( sal_Bool b ) 356 { 357 if( IsSet( SBX_NO_MODIFY ) ) 358 return; 359 SbxBase::SetModified( b ); 360 if( pParent && pParent != this ) //??? HotFix: Rekursion raus MM 361 pParent->SetModified( b ); 362 } 363 364 void SbxVariable::SetParent( SbxObject* p ) 365 { 366 #ifdef DBG_UTIL 367 // wird der Parent eines SbxObjects gesetzt? 368 if ( p && ISA(SbxObject) ) 369 { 370 // dann mu\s dieses auch Child vom neuen Parent sein 371 sal_Bool bFound = sal_False; 372 SbxArray *pChilds = p->GetObjects(); 373 if ( pChilds ) 374 { 375 for ( sal_uInt16 nIdx = 0; !bFound && nIdx < pChilds->Count(); ++nIdx ) 376 bFound = ( this == pChilds->Get(nIdx) ); 377 } 378 if ( !bFound ) 379 { 380 String aMsg = String::CreateFromAscii( "dangling: [" ); 381 aMsg += GetName(); 382 aMsg.AppendAscii( "].SetParent([" ); 383 aMsg += p->GetName(); 384 aMsg.AppendAscii( "])" ); 385 ByteString aBStr( (const UniString&)aMsg, RTL_TEXTENCODING_ASCII_US ); 386 DbgOut( aBStr.GetBuffer(), DBG_OUT_WARNING, __FILE__, __LINE__); 387 } 388 } 389 #endif 390 391 pParent = p; 392 } 393 394 SbxVariableImpl* SbxVariable::getImpl( void ) 395 { 396 if( mpSbxVariableImpl == NULL ) 397 mpSbxVariableImpl = new SbxVariableImpl(); 398 return mpSbxVariableImpl; 399 } 400 401 const String& SbxVariable::GetDeclareClassName( void ) 402 { 403 SbxVariableImpl* pImpl = getImpl(); 404 return pImpl->m_aDeclareClassName; 405 } 406 407 void SbxVariable::SetDeclareClassName( const String& rDeclareClassName ) 408 { 409 SbxVariableImpl* pImpl = getImpl(); 410 pImpl->m_aDeclareClassName = rDeclareClassName; 411 } 412 413 void SbxVariable::SetComListener( ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > xComListener, 414 StarBASIC* pParentBasic ) 415 { 416 SbxVariableImpl* pImpl = getImpl(); 417 pImpl->m_xComListener = xComListener; 418 pImpl->m_pComListenerParentBasic = pParentBasic; 419 registerComListenerVariableForBasic( this, pParentBasic ); 420 } 421 422 void SbxVariable::ClearComListener( void ) 423 { 424 SbxVariableImpl* pImpl = getImpl(); 425 pImpl->m_xComListener.clear(); 426 } 427 428 429 ////////////////////////////// Laden/Speichern ///////////////////////////// 430 431 sal_Bool SbxVariable::LoadData( SvStream& rStrm, sal_uInt16 nVer ) 432 { 433 sal_uInt16 nType; 434 sal_uInt8 cMark; 435 rStrm >> cMark; 436 if( cMark == 0xFF ) 437 { 438 if( !SbxValue::LoadData( rStrm, nVer ) ) 439 return sal_False; 440 rStrm.ReadByteString( maName, RTL_TEXTENCODING_ASCII_US ); 441 sal_uInt32 nTemp; 442 rStrm >> nTemp; 443 nUserData = nTemp; 444 } 445 else 446 { 447 rStrm.SeekRel( -1L ); 448 rStrm >> nType; 449 rStrm.ReadByteString( maName, RTL_TEXTENCODING_ASCII_US ); 450 sal_uInt32 nTemp; 451 rStrm >> nTemp; 452 nUserData = nTemp; 453 // Korrektur: Alte Methoden haben statt SbxNULL jetzt SbxEMPTY 454 if( nType == SbxNULL && GetClass() == SbxCLASS_METHOD ) 455 nType = SbxEMPTY; 456 SbxValues aTmp; 457 String aTmpString; 458 ::rtl::OUString aVal; 459 aTmp.eType = aData.eType = (SbxDataType) nType; 460 aTmp.pOUString = &aVal; 461 switch( nType ) 462 { 463 case SbxBOOL: 464 case SbxERROR: 465 case SbxINTEGER: 466 rStrm >> aTmp.nInteger; break; 467 case SbxLONG: 468 rStrm >> aTmp.nLong; break; 469 case SbxSINGLE: 470 { 471 // Floats als ASCII 472 rStrm.ReadByteString( aTmpString, RTL_TEXTENCODING_ASCII_US ); 473 double d; 474 SbxDataType t; 475 if( ImpScan( aTmpString, d, t, NULL ) != SbxERR_OK || t == SbxDOUBLE ) 476 { 477 aTmp.nSingle = 0; 478 return sal_False; 479 } 480 aTmp.nSingle = (float) d; 481 break; 482 } 483 case SbxDATE: 484 case SbxDOUBLE: 485 { 486 // Floats als ASCII 487 rStrm.ReadByteString( aTmpString, RTL_TEXTENCODING_ASCII_US ); 488 SbxDataType t; 489 if( ImpScan( aTmpString, aTmp.nDouble, t, NULL ) != SbxERR_OK ) 490 { 491 aTmp.nDouble = 0; 492 return sal_False; 493 } 494 break; 495 } 496 case SbxSTRING: 497 rStrm.ReadByteString( aTmpString, RTL_TEXTENCODING_ASCII_US ); 498 aVal = aTmpString; 499 break; 500 case SbxEMPTY: 501 case SbxNULL: 502 break; 503 default: 504 aData.eType = SbxNULL; 505 DBG_ASSERT( !this, "Nicht unterstuetzer Datentyp geladen" ); 506 return sal_False; 507 } 508 // Wert putten 509 if( nType != SbxNULL && nType != SbxEMPTY && !Put( aTmp ) ) 510 return sal_False; 511 } 512 rStrm >> cMark; 513 // cMark ist auch eine Versionsnummer! 514 // 1: initial version 515 // 2: mit nUserData 516 if( cMark ) 517 { 518 if( cMark > 2 ) 519 return sal_False; 520 pInfo = new SbxInfo; 521 pInfo->LoadData( rStrm, (sal_uInt16) cMark ); 522 } 523 // Privatdaten nur laden, wenn es eine SbxVariable ist 524 if( GetClass() == SbxCLASS_VARIABLE && !LoadPrivateData( rStrm, nVer ) ) 525 return sal_False; 526 ((SbxVariable*) this)->Broadcast( SBX_HINT_DATACHANGED ); 527 nHash = MakeHashCode( maName ); 528 SetModified( sal_True ); 529 return sal_True; 530 } 531 532 sal_Bool SbxVariable::StoreData( SvStream& rStrm ) const 533 { 534 rStrm << (sal_uInt8) 0xFF; // Marker 535 sal_Bool bValStore; 536 if( this->IsA( TYPE(SbxMethod) ) ) 537 { 538 // #50200 Verhindern, dass Objekte, die zur Laufzeit als Return-Wert 539 // in der Methode als Value gespeichert sind, mit gespeichert werden 540 SbxVariable* pThis = (SbxVariable*)this; 541 sal_uInt16 nSaveFlags = GetFlags(); 542 pThis->SetFlag( SBX_WRITE ); 543 pThis->SbxValue::Clear(); 544 pThis->SetFlags( nSaveFlags ); 545 546 // Damit die Methode in keinem Fall ausgefuehrt wird! 547 // CAST, um const zu umgehen! 548 pThis->SetFlag( SBX_NO_BROADCAST ); 549 bValStore = SbxValue::StoreData( rStrm ); 550 pThis->ResetFlag( SBX_NO_BROADCAST ); 551 } 552 else 553 bValStore = SbxValue::StoreData( rStrm ); 554 if( !bValStore ) 555 return sal_False; 556 // if( !SbxValue::StoreData( rStrm ) ) 557 // return sal_False; 558 rStrm.WriteByteString( maName, RTL_TEXTENCODING_ASCII_US ); 559 rStrm << (sal_uInt32)nUserData; 560 if( pInfo.Is() ) 561 { 562 rStrm << (sal_uInt8) 2; // Version 2: mit UserData! 563 pInfo->StoreData( rStrm ); 564 } 565 else 566 rStrm << (sal_uInt8) 0; 567 // Privatdaten nur speichern, wenn es eine SbxVariable ist 568 if( GetClass() == SbxCLASS_VARIABLE ) 569 return StorePrivateData( rStrm ); 570 else 571 return sal_True; 572 } 573 574 ////////////////////////////// SbxInfo /////////////////////////////////// 575 576 SbxInfo::SbxInfo() : aHelpFile(), nHelpId( 0 ), aParams() 577 {} 578 579 SbxInfo::SbxInfo( const String& r, sal_uInt32 n ) 580 : aHelpFile( r ), nHelpId( n ), aParams() 581 {} 582 583 ////////////////////////////// SbxAlias ////////////////////////////////// 584 585 SbxAlias::SbxAlias( const XubString& rName, SbxVariable* p ) 586 : SbxVariable(), xAlias( p ) 587 { 588 SetName( rName ); 589 SetFlags( p->GetFlags() ); 590 SetFlag( SBX_DONTSTORE ); 591 aData.eType = p->GetType(); 592 StartListening( p->GetBroadcaster() ); 593 } 594 595 SbxAlias::SbxAlias( const SbxAlias& r ) 596 : SvRefBase( r ), SbxVariable( r ), 597 SfxListener( r ), xAlias( r.xAlias ) 598 {} 599 600 SbxAlias& SbxAlias::operator=( const SbxAlias& r ) 601 { 602 xAlias = r.xAlias; 603 return *this; 604 } 605 606 SbxAlias::~SbxAlias() 607 { 608 if( xAlias.Is() ) 609 EndListening( xAlias->GetBroadcaster() ); 610 } 611 612 void SbxAlias::Broadcast( sal_uIntPtr nHt ) 613 { 614 if( xAlias.Is() && StaticIsEnabledBroadcasting() ) 615 { 616 xAlias->SetParameters( GetParameters() ); 617 if( nHt == SBX_HINT_DATAWANTED ) 618 SbxVariable::operator=( *xAlias ); 619 else if( nHt == SBX_HINT_DATACHANGED || nHt == SBX_HINT_CONVERTED ) 620 *xAlias = *this; 621 else if( nHt == SBX_HINT_INFOWANTED ) 622 { 623 xAlias->Broadcast( nHt ); 624 pInfo = xAlias->GetInfo(); 625 } 626 } 627 } 628 629 void SbxAlias::SFX_NOTIFY( SfxBroadcaster&, const TypeId&, 630 const SfxHint& rHint, const TypeId& ) 631 { 632 const SbxHint* p = PTR_CAST(SbxHint,&rHint); 633 if( p && p->GetId() == SBX_HINT_DYING ) 634 { 635 xAlias.Clear(); 636 // Alias loeschen? 637 if( pParent ) 638 pParent->Remove( this ); 639 } 640 } 641 642 void SbxVariable::Dump( SvStream& rStrm, sal_Bool bFill ) 643 { 644 ByteString aBNameStr( (const UniString&)GetName( SbxNAME_SHORT_TYPES ), RTL_TEXTENCODING_ASCII_US ); 645 rStrm << "Variable( " 646 << ByteString::CreateFromInt64( (sal_uIntPtr) this ).GetBuffer() << "==" 647 << aBNameStr.GetBuffer(); 648 ByteString aBParentNameStr( (const UniString&)GetParent()->GetName(), RTL_TEXTENCODING_ASCII_US ); 649 if ( GetParent() ) 650 rStrm << " in parent '" << aBParentNameStr.GetBuffer() << "'"; 651 else 652 rStrm << " no parent"; 653 rStrm << " ) "; 654 655 // bei Object-Vars auch das Object ausgeben 656 if ( GetValues_Impl().eType == SbxOBJECT && 657 GetValues_Impl().pObj && 658 GetValues_Impl().pObj != this && 659 GetValues_Impl().pObj != GetParent() ) 660 { 661 rStrm << " contains "; 662 ((SbxObject*) GetValues_Impl().pObj)->Dump( rStrm, bFill ); 663 } 664 else 665 rStrm << endl; 666 } 667 668