1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* 3 * This file is part of the LibreOffice project. 4 * 5 * This Source Code Form is subject to the terms of the Mozilla Public 6 * License, v. 2.0. If a copy of the MPL was not distributed with this 7 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 * 9 * This file incorporates work covered by the following license notice: 10 * 11 * Licensed to the Apache Software Foundation (ASF) under one or more 12 * contributor license agreements. See the NOTICE file distributed 13 * with this work for additional information regarding copyright 14 * ownership. The ASF licenses this file to you under the Apache 15 * License, Version 2.0 (the "License"); you may not use this file 16 * except in compliance with the License. You may obtain a copy of 17 * the License at http://www.apache.org/licenses/LICENSE-2.0 . 18 */ 19 20 #include <sal/config.h> 21 #include <sal/log.hxx> 22 23 #include <iomanip> 24 25 #include <tools/debug.hxx> 26 #include <tools/stream.hxx> 27 #include <basic/sbx.hxx> 28 #include <basic/sberrors.hxx> 29 #include <basic/sbxmeth.hxx> 30 #include <basic/sbxprop.hxx> 31 #include <svl/SfxBroadcaster.hxx> 32 #include "sbxres.hxx" 33 34 35 static OUString pNameProp; // Name-Property 36 static OUString pParentProp; // Parent-Property 37 38 static sal_uInt16 nNameHash = 0, nParentHash = 0; 39 40 41 SbxObject::SbxObject( const OUString& rClass ) 42 : SbxVariable( SbxOBJECT ), aClassName( rClass ) 43 { 44 aData.pObj = this; 45 if( !nNameHash ) 46 { 47 pNameProp = GetSbxRes( StringId::NameProp ); 48 pParentProp = GetSbxRes( StringId::ParentProp ); 49 nNameHash = MakeHashCode( pNameProp ); 50 nParentHash = MakeHashCode( pParentProp ); 51 } 52 SbxObject::Clear(); 53 SbxObject::SetName( rClass ); 54 } 55 56 SbxObject::SbxObject( const SbxObject& rObj ) 57 : SvRefBase( rObj ), SbxVariable( rObj.GetType() ), 58 SfxListener( rObj ) 59 { 60 *this = rObj; 61 } 62 63 SbxObject& SbxObject::operator=( const SbxObject& r ) 64 { 65 if( &r != this ) 66 { 67 SbxVariable::operator=( r ); 68 aClassName = r.aClassName; 69 pMethods = new SbxArray; 70 pProps = new SbxArray; 71 pObjs = new SbxArray( SbxOBJECT ); 72 // The arrays were copied, the content taken over 73 *pMethods = *r.pMethods; 74 *pProps = *r.pProps; 75 *pObjs = *r.pObjs; 76 // Because the variables were taken over, this is OK 77 pDfltProp = r.pDfltProp; 78 SetName( r.GetName() ); 79 SetFlags( r.GetFlags() ); 80 SetModified( true ); 81 } 82 return *this; 83 } 84 85 static void CheckParentsOnDelete( SbxObject* pObj, SbxArray* p ) 86 { 87 for( sal_uInt16 i = 0; i < p->Count(); i++ ) 88 { 89 SbxVariableRef& rRef = p->GetRef( i ); 90 if( rRef->IsBroadcaster() ) 91 { 92 pObj->EndListening( rRef->GetBroadcaster(), true ); 93 } 94 // does the element have more than one reference and still a Listener? 95 if( rRef->GetRefCount() > 1 ) 96 { 97 rRef->SetParent( nullptr ); 98 SAL_INFO_IF(rRef->IsBroadcaster() && rRef->GetBroadcaster().GetListenerCount(), "basic.sbx", "Object element with dangling parent"); 99 } 100 } 101 } 102 103 SbxObject::~SbxObject() 104 { 105 CheckParentsOnDelete( this, pProps.get() ); 106 CheckParentsOnDelete( this, pMethods.get() ); 107 CheckParentsOnDelete( this, pObjs.get() ); 108 109 // avoid handling in ~SbxVariable as SbxFlagBits::DimAsNew == SbxFlagBits::GlobalSearch 110 ResetFlag( SbxFlagBits::DimAsNew ); 111 } 112 113 SbxDataType SbxObject::GetType() const 114 { 115 return SbxOBJECT; 116 } 117 118 SbxClassType SbxObject::GetClass() const 119 { 120 return SbxClassType::Object; 121 } 122 123 void SbxObject::Clear() 124 { 125 pMethods = new SbxArray; 126 pProps = new SbxArray; 127 pObjs = new SbxArray( SbxOBJECT ); 128 SbxVariable* p; 129 p = Make( pNameProp, SbxClassType::Property, SbxSTRING ); 130 p->SetFlag( SbxFlagBits::DontStore ); 131 p = Make( pParentProp, SbxClassType::Property, SbxOBJECT ); 132 p->ResetFlag( SbxFlagBits::Write ); 133 p->SetFlag( SbxFlagBits::DontStore ); 134 pDfltProp = nullptr; 135 SetModified( false ); 136 } 137 138 void SbxObject::Notify( SfxBroadcaster&, const SfxHint& rHint ) 139 { 140 const SbxHint* p = dynamic_cast<const SbxHint*>(&rHint); 141 if( p ) 142 { 143 const SfxHintId nId = p->GetId(); 144 bool bRead = ( nId == SfxHintId::BasicDataWanted ); 145 bool bWrite = ( nId == SfxHintId::BasicDataChanged ); 146 SbxVariable* pVar = p->GetVar(); 147 if( bRead || bWrite ) 148 { 149 OUString aVarName( pVar->GetName() ); 150 sal_uInt16 nHash_ = MakeHashCode( aVarName ); 151 if( nHash_ == nNameHash && aVarName.equalsIgnoreAsciiCase( pNameProp ) ) 152 { 153 if( bRead ) 154 { 155 pVar->PutString( GetName() ); 156 } 157 else 158 { 159 SetName( pVar->GetOUString() ); 160 } 161 } 162 else if( nHash_ == nParentHash && aVarName.equalsIgnoreAsciiCase( pParentProp ) ) 163 { 164 SbxObject* p_ = GetParent(); 165 if( !p_ ) 166 { 167 p_ = this; 168 } 169 pVar->PutObject( p_ ); 170 } 171 } 172 } 173 } 174 175 bool SbxObject::IsClass( const OUString& rName ) const 176 { 177 return aClassName.equalsIgnoreAsciiCase( rName ); 178 } 179 180 SbxVariable* SbxObject::Find( const OUString& rName, SbxClassType t ) 181 { 182 #ifdef DBG_UTIL 183 static int nLvl = 1; 184 static const char* pCls[] = { "DontCare","Array","Value","Variable","Method","Property","Object" }; 185 SAL_INFO( 186 "basic.sbx", 187 "search" << std::setw(nLvl) << " " 188 << (t >= SbxClassType::DontCare && t <= SbxClassType::Object 189 ? pCls[static_cast<int>(t) - 1] : "Unknown class") 190 << " " << rName << " in " << SbxVariable::GetName()); 191 ++nLvl; 192 #endif 193 194 SbxVariable* pRes = nullptr; 195 pObjs->SetFlag( SbxFlagBits::ExtSearch ); 196 if( t == SbxClassType::DontCare ) 197 { 198 pRes = pMethods->Find( rName, SbxClassType::Method ); 199 if( !pRes ) 200 { 201 pRes = pProps->Find( rName, SbxClassType::Property ); 202 } 203 if( !pRes ) 204 { 205 pRes = pObjs->Find( rName, t ); 206 } 207 } 208 else 209 { 210 SbxArray* pArray = nullptr; 211 switch( t ) 212 { 213 case SbxClassType::Variable: 214 case SbxClassType::Property: pArray = pProps.get(); break; 215 case SbxClassType::Method: pArray = pMethods.get(); break; 216 case SbxClassType::Object: pArray = pObjs.get(); break; 217 default: SAL_WARN( "basic.sbx", "Invalid SBX-Class" ); break; 218 } 219 if( pArray ) 220 { 221 pRes = pArray->Find( rName, t ); 222 } 223 } 224 // Extended Search in the Object-Array? 225 // For objects and DontCare the array of objects has already been searched 226 if( !pRes && ( t == SbxClassType::Method || t == SbxClassType::Property ) ) 227 pRes = pObjs->Find( rName, t ); 228 // Search in the parents? 229 if( !pRes && IsSet( SbxFlagBits::GlobalSearch ) ) 230 { 231 SbxObject* pCur = this; 232 while( !pRes && pCur->pParent ) 233 { 234 // I myself was already searched! 235 SbxFlagBits nOwn = pCur->GetFlags(); 236 pCur->ResetFlag( SbxFlagBits::ExtSearch ); 237 // I search already global! 238 SbxFlagBits nPar = pCur->pParent->GetFlags(); 239 pCur->pParent->ResetFlag( SbxFlagBits::GlobalSearch ); 240 pRes = pCur->pParent->Find( rName, t ); 241 pCur->SetFlags( nOwn ); 242 pCur->pParent->SetFlags( nPar ); 243 pCur = pCur->pParent; 244 } 245 } 246 #ifdef DBG_UTIL 247 --nLvl; 248 SAL_INFO_IF( 249 pRes, "basic.sbx", 250 "found" << std::setw(nLvl) << " " << rName << " in " 251 << SbxVariable::GetName()); 252 #endif 253 return pRes; 254 } 255 256 // Abbreviated version: The parent-string will be searched 257 // The whole thing recursive, because Call() might be overridden 258 // Qualified names are allowed 259 260 bool SbxObject::Call( const OUString& rName, SbxArray* pParam ) 261 { 262 SbxVariable* pMeth = FindQualified( rName, SbxClassType::DontCare); 263 if( dynamic_cast<const SbxMethod*>( pMeth) ) 264 { 265 // FindQualified() might have struck already! 266 if( pParam ) 267 { 268 pMeth->SetParameters( pParam ); 269 } 270 pMeth->Broadcast( SfxHintId::BasicDataWanted ); 271 pMeth->SetParameters( nullptr ); 272 return true; 273 } 274 SetError( ERRCODE_BASIC_NO_METHOD ); 275 return false; 276 } 277 278 SbxProperty* SbxObject::GetDfltProperty() 279 { 280 if ( !pDfltProp && !aDfltPropName.isEmpty() ) 281 { 282 pDfltProp = static_cast<SbxProperty*>( Find( aDfltPropName, SbxClassType::Property ) ); 283 if( !pDfltProp ) 284 { 285 pDfltProp = static_cast<SbxProperty*>( Make( aDfltPropName, SbxClassType::Property, SbxVARIANT ) ); 286 } 287 } 288 return pDfltProp; 289 } 290 void SbxObject::SetDfltProperty( const OUString& rName ) 291 { 292 if ( rName != aDfltPropName ) 293 { 294 pDfltProp = nullptr; 295 } 296 aDfltPropName = rName; 297 SetModified( true ); 298 } 299 300 // Search of an already available variable. If it was located, 301 // the index will be set, otherwise the Count of the Array will be returned. 302 // In any case the correct Array will be returned. 303 304 SbxArray* SbxObject::FindVar( SbxVariable const * pVar, sal_uInt16& nArrayIdx ) 305 { 306 SbxArray* pArray = nullptr; 307 if( pVar ) 308 { 309 switch( pVar->GetClass() ) 310 { 311 case SbxClassType::Variable: 312 case SbxClassType::Property: pArray = pProps.get(); break; 313 case SbxClassType::Method: pArray = pMethods.get(); break; 314 case SbxClassType::Object: pArray = pObjs.get(); break; 315 default: SAL_WARN( "basic.sbx", "Invalid SBX-Class" ); break; 316 } 317 } 318 if( pArray ) 319 { 320 nArrayIdx = pArray->Count(); 321 // Is the variable per name available? 322 pArray->ResetFlag( SbxFlagBits::ExtSearch ); 323 SbxVariable* pOld = pArray->Find( pVar->GetName(), pVar->GetClass() ); 324 if( pOld ) 325 { 326 for( sal_uInt16 i = 0; i < pArray->Count(); i++ ) 327 { 328 SbxVariableRef& rRef = pArray->GetRef( i ); 329 if( rRef.get() == pOld ) 330 { 331 nArrayIdx = i; break; 332 } 333 } 334 } 335 } 336 return pArray; 337 } 338 339 // If a new object will be established, this object will be indexed, 340 // if an object of this name exists already. 341 342 SbxVariable* SbxObject::Make( const OUString& rName, SbxClassType ct, SbxDataType dt, bool bIsRuntimeFunction ) 343 { 344 // Is the object already available? 345 SbxArray* pArray = nullptr; 346 switch( ct ) 347 { 348 case SbxClassType::Variable: 349 case SbxClassType::Property: pArray = pProps.get(); break; 350 case SbxClassType::Method: pArray = pMethods.get(); break; 351 case SbxClassType::Object: pArray = pObjs.get(); break; 352 default: SAL_WARN( "basic.sbx", "Invalid SBX-Class" ); break; 353 } 354 if( !pArray ) 355 { 356 return nullptr; 357 } 358 // Collections may contain objects of the same name 359 if( !( ct == SbxClassType::Object && dynamic_cast<const SbxCollection*>( this ) != nullptr ) ) 360 { 361 SbxVariable* pRes = pArray->Find( rName, ct ); 362 if( pRes ) 363 { 364 return pRes; 365 } 366 } 367 SbxVariable* pVar = nullptr; 368 switch( ct ) 369 { 370 case SbxClassType::Variable: 371 case SbxClassType::Property: 372 pVar = new SbxProperty( rName, dt ); 373 break; 374 case SbxClassType::Method: 375 pVar = new SbxMethod( rName, dt, bIsRuntimeFunction ); 376 break; 377 case SbxClassType::Object: 378 pVar = CreateObject( rName ); 379 break; 380 default: 381 break; 382 } 383 pVar->SetParent( this ); 384 pArray->Put( pVar, pArray->Count() ); 385 SetModified( true ); 386 // The object listen always 387 StartListening(pVar->GetBroadcaster(), DuplicateHandling::Prevent); 388 return pVar; 389 } 390 391 void SbxObject::Insert( SbxVariable* pVar ) 392 { 393 sal_uInt16 nIdx; 394 SbxArray* pArray = FindVar( pVar, nIdx ); 395 if( pArray ) 396 { 397 // Into with it. But you should pay attention at the Pointer! 398 if( nIdx < pArray->Count() ) 399 { 400 // Then this element exists already 401 // There are objects of the same name allowed at collections 402 if( pArray == pObjs.get() && dynamic_cast<const SbxCollection*>( this ) != nullptr ) 403 { 404 nIdx = pArray->Count(); 405 } 406 else 407 { 408 SbxVariable* pOld = pArray->Get( nIdx ); 409 // already inside: overwrite 410 if( pOld == pVar ) 411 { 412 return; 413 } 414 EndListening( pOld->GetBroadcaster(), true ); 415 if( pVar->GetClass() == SbxClassType::Property ) 416 { 417 if( pOld == pDfltProp ) 418 { 419 pDfltProp = static_cast<SbxProperty*>(pVar); 420 } 421 } 422 } 423 } 424 StartListening(pVar->GetBroadcaster(), DuplicateHandling::Prevent); 425 pArray->Put( pVar, nIdx ); 426 if( pVar->GetParent() != this ) 427 { 428 pVar->SetParent( this ); 429 } 430 SetModified( true ); 431 #ifdef DBG_UTIL 432 static const char* pCls[] = 433 { "DontCare","Array","Value","Variable","Method","Property","Object" }; 434 OUString aVarName( pVar->GetName() ); 435 if (const SbxObject *pSbxObj = aVarName.isEmpty() ? dynamic_cast<const SbxObject*>(pVar) : nullptr) 436 { 437 aVarName = pSbxObj->GetClassName(); 438 } 439 SAL_INFO( 440 "basic.sbx", 441 "insert " 442 << ((pVar->GetClass() >= SbxClassType::DontCare 443 && pVar->GetClass() <= SbxClassType::Object) 444 ? pCls[static_cast<int>(pVar->GetClass()) - 1] : "Unknown class") 445 << " " << aVarName << " in " << SbxVariable::GetName()); 446 #endif 447 } 448 } 449 450 // Optimisation, Insertion without checking about 451 // double entry and without broadcasts, will only be used in SO2/auto.cxx 452 void SbxObject::QuickInsert( SbxVariable* pVar ) 453 { 454 SbxArray* pArray = nullptr; 455 if( pVar ) 456 { 457 switch( pVar->GetClass() ) 458 { 459 case SbxClassType::Variable: 460 case SbxClassType::Property: pArray = pProps.get(); break; 461 case SbxClassType::Method: pArray = pMethods.get(); break; 462 case SbxClassType::Object: pArray = pObjs.get(); break; 463 default: SAL_WARN( "basic.sbx", "Invalid SBX-Class" ); break; 464 } 465 } 466 if( pArray ) 467 { 468 StartListening(pVar->GetBroadcaster(), DuplicateHandling::Prevent); 469 pArray->Put( pVar, pArray->Count() ); 470 if( pVar->GetParent() != this ) 471 { 472 pVar->SetParent( this ); 473 } 474 SetModified( true ); 475 #ifdef DBG_UTIL 476 static const char* pCls[] = 477 { "DontCare","Array","Value","Variable","Method","Property","Object" }; 478 OUString aVarName( pVar->GetName() ); 479 if (const SbxObject *pSbxObj = aVarName.isEmpty() ? dynamic_cast<const SbxObject*>(pVar) : nullptr) 480 { 481 aVarName = pSbxObj->GetClassName(); 482 } 483 SAL_INFO( 484 "basic.sbx", 485 "insert " 486 << ((pVar->GetClass() >= SbxClassType::DontCare 487 && pVar->GetClass() <= SbxClassType::Object) 488 ? pCls[static_cast<int>(pVar->GetClass()) - 1] : "Unknown class") 489 << " " << aVarName << " in " << SbxVariable::GetName()); 490 #endif 491 } 492 } 493 494 void SbxObject::Remove( const OUString& rName, SbxClassType t ) 495 { 496 Remove( SbxObject::Find( rName, t ) ); 497 } 498 499 void SbxObject::Remove( SbxVariable* pVar ) 500 { 501 sal_uInt16 nIdx; 502 SbxArray* pArray = FindVar( pVar, nIdx ); 503 if( pArray && nIdx < pArray->Count() ) 504 { 505 #ifdef DBG_UTIL 506 OUString aVarName( pVar->GetName() ); 507 if (const SbxObject *pSbxObj = aVarName.isEmpty() ? dynamic_cast<const SbxObject*>(pVar) : nullptr) 508 { 509 aVarName = pSbxObj->GetClassName(); 510 } 511 SAL_INFO( 512 "basic.sbx", 513 "remove " << aVarName << " in " << SbxVariable::GetName()); 514 #endif 515 SbxVariableRef pVar_ = pArray->Get( nIdx ); 516 if( pVar_->IsBroadcaster() ) 517 { 518 EndListening( pVar_->GetBroadcaster(), true ); 519 } 520 if( pVar_.get() == pDfltProp ) 521 { 522 pDfltProp = nullptr; 523 } 524 pArray->Remove( nIdx ); 525 if( pVar_->GetParent() == this ) 526 { 527 pVar_->SetParent( nullptr ); 528 } 529 SetModified( true ); 530 } 531 } 532 533 static bool LoadArray( SvStream& rStrm, SbxObject* pThis, SbxArray* pArray ) 534 { 535 SbxArrayRef p = static_cast<SbxArray*>( SbxBase::Load( rStrm ) ); 536 if( !p.is() ) 537 { 538 return false; 539 } 540 for( sal_uInt16 i = 0; i < p->Count(); i++ ) 541 { 542 SbxVariableRef& r = p->GetRef( i ); 543 SbxVariable* pVar = r.get(); 544 if( pVar ) 545 { 546 pVar->SetParent( pThis ); 547 pThis->StartListening(pVar->GetBroadcaster(), DuplicateHandling::Prevent); 548 } 549 } 550 pArray->Merge( p.get() ); 551 return true; 552 } 553 554 // The load of an object is additive! 555 556 bool SbxObject::LoadData( SvStream& rStrm, sal_uInt16 nVer ) 557 { 558 // Help for the read in of old objects: just return TRUE, 559 // LoadPrivateData() has to set the default status up 560 if( !nVer ) 561 { 562 return true; 563 } 564 pDfltProp = nullptr; 565 if( !SbxVariable::LoadData( rStrm, nVer ) ) 566 { 567 return false; 568 } 569 // If it contains no alien object, insert ourselves 570 if( aData.eType == SbxOBJECT && !aData.pObj ) 571 { 572 aData.pObj = this; 573 } 574 sal_uInt32 nSize; 575 OUString aDfltProp; 576 aClassName = read_uInt16_lenPrefixed_uInt8s_ToOUString(rStrm, RTL_TEXTENCODING_ASCII_US); 577 aDfltProp = read_uInt16_lenPrefixed_uInt8s_ToOUString(rStrm, RTL_TEXTENCODING_ASCII_US); 578 sal_uInt64 nPos = rStrm.Tell(); 579 rStrm.ReadUInt32( nSize ); 580 sal_uInt64 const nNewPos = rStrm.Tell(); 581 nPos += nSize; 582 DBG_ASSERT( nPos >= nNewPos, "SBX: Loaded too much data" ); 583 if( nPos != nNewPos ) 584 { 585 rStrm.Seek( nPos ); 586 } 587 if( !LoadArray( rStrm, this, pMethods.get() ) || 588 !LoadArray( rStrm, this, pProps.get() ) || 589 !LoadArray( rStrm, this, pObjs.get() ) ) 590 { 591 return false; 592 } 593 // Set properties 594 if( !aDfltProp.isEmpty() ) 595 { 596 pDfltProp = static_cast<SbxProperty*>( pProps->Find( aDfltProp, SbxClassType::Property ) ); 597 } 598 SetModified( false ); 599 return true; 600 } 601 602 bool SbxObject::StoreData( SvStream& rStrm ) const 603 { 604 if( !SbxVariable::StoreData( rStrm ) ) 605 { 606 return false; 607 } 608 OUString aDfltProp; 609 if( pDfltProp ) 610 { 611 aDfltProp = pDfltProp->GetName(); 612 } 613 write_uInt16_lenPrefixed_uInt8s_FromOUString(rStrm, aClassName, RTL_TEXTENCODING_ASCII_US); 614 write_uInt16_lenPrefixed_uInt8s_FromOUString(rStrm, aDfltProp, RTL_TEXTENCODING_ASCII_US); 615 sal_uInt64 const nPos = rStrm.Tell(); 616 rStrm.WriteUInt32( 0 ); 617 sal_uInt64 const nNew = rStrm.Tell(); 618 rStrm.Seek( nPos ); 619 rStrm.WriteUInt32( nNew - nPos ); 620 rStrm.Seek( nNew ); 621 if( !pMethods->Store( rStrm ) ) 622 { 623 return false; 624 } 625 if( !pProps->Store( rStrm ) ) 626 { 627 return false; 628 } 629 if( !pObjs->Store( rStrm ) ) 630 { 631 return false; 632 } 633 const_cast<SbxObject*>(this)->SetModified( false ); 634 return true; 635 } 636 637 static bool CollectAttrs( const SbxBase* p, OUString& rRes ) 638 { 639 OUString aAttrs; 640 if( p->IsHidden() ) 641 { 642 aAttrs = "Hidden"; 643 } 644 if( p->IsSet( SbxFlagBits::ExtSearch ) ) 645 { 646 if( !aAttrs.isEmpty() ) 647 { 648 aAttrs += ","; 649 } 650 aAttrs += "ExtSearch"; 651 } 652 if( !p->IsVisible() ) 653 { 654 if( !aAttrs.isEmpty() ) 655 { 656 aAttrs += ","; 657 } 658 aAttrs += "Invisible"; 659 } 660 if( p->IsSet( SbxFlagBits::DontStore ) ) 661 { 662 if( !aAttrs.isEmpty() ) 663 { 664 aAttrs += ","; 665 } 666 aAttrs += "DontStore"; 667 } 668 if( !aAttrs.isEmpty() ) 669 { 670 rRes = " (" + aAttrs + ")"; 671 return true; 672 } 673 else 674 { 675 rRes.clear(); 676 return false; 677 } 678 } 679 680 void SbxObject::Dump( SvStream& rStrm, bool bFill ) 681 { 682 // Shifting 683 static sal_uInt16 nLevel = 0; 684 if ( nLevel > 10 ) 685 { 686 rStrm.WriteCharPtr( "<too deep>" ) << endl; 687 return; 688 } 689 ++nLevel; 690 OUString aIndent(""); 691 for ( sal_uInt16 n = 1; n < nLevel; ++n ) 692 { 693 aIndent += " "; 694 } 695 // Output the data of the object itself 696 OString aNameStr(OUStringToOString(GetName(), RTL_TEXTENCODING_ASCII_US)); 697 OString aClassNameStr(OUStringToOString(aClassName, RTL_TEXTENCODING_ASCII_US)); 698 rStrm.WriteCharPtr( "Object( " ) 699 .WriteCharPtr( OString::number(reinterpret_cast<sal_Int64>(this)).getStr() ).WriteCharPtr( "=='" ) 700 .WriteCharPtr( aNameStr.isEmpty() ? "<unnamed>" : aNameStr.getStr() ).WriteCharPtr( "', " ) 701 .WriteCharPtr( "of class '" ).WriteCharPtr( aClassNameStr.getStr() ).WriteCharPtr( "', " ) 702 .WriteCharPtr( "counts " ) 703 .WriteCharPtr( OString::number(GetRefCount()).getStr() ) 704 .WriteCharPtr( " refs, " ); 705 if ( GetParent() ) 706 { 707 OString aParentNameStr(OUStringToOString(GetName(), RTL_TEXTENCODING_ASCII_US)); 708 rStrm.WriteCharPtr( "in parent " ) 709 .WriteCharPtr( OString::number(reinterpret_cast<sal_Int64>(GetParent())).getStr() ) 710 .WriteCharPtr( "=='" ).WriteCharPtr( aParentNameStr.isEmpty() ? "<unnamed>" : aParentNameStr.getStr() ).WriteCharPtr( "'" ); 711 } 712 else 713 { 714 rStrm.WriteCharPtr( "no parent " ); 715 } 716 rStrm.WriteCharPtr( " )" ) << endl; 717 OString aIndentNameStr(OUStringToOString(aIndent, RTL_TEXTENCODING_ASCII_US)); 718 rStrm.WriteCharPtr( aIndentNameStr.getStr() ).WriteCharPtr( "{" ) << endl; 719 720 // Flags 721 OUString aAttrs; 722 if( CollectAttrs( this, aAttrs ) ) 723 { 724 OString aAttrStr(OUStringToOString(aAttrs, RTL_TEXTENCODING_ASCII_US)); 725 rStrm.WriteCharPtr( aIndentNameStr.getStr() ).WriteCharPtr( "- Flags: " ).WriteCharPtr( aAttrStr.getStr() ) << endl; 726 } 727 728 // Methods 729 rStrm.WriteCharPtr( aIndentNameStr.getStr() ).WriteCharPtr( "- Methods:" ) << endl; 730 for( sal_uInt16 i = 0; i < pMethods->Count(); i++ ) 731 { 732 SbxVariableRef& r = pMethods->GetRef( i ); 733 SbxVariable* pVar = r.get(); 734 if( pVar ) 735 { 736 OUString aLine = aIndent + " - " + pVar->GetName( SbxNameType::ShortTypes ); 737 OUString aAttrs2; 738 if( CollectAttrs( pVar, aAttrs2 ) ) 739 { 740 aLine += aAttrs2; 741 } 742 if( dynamic_cast<const SbxMethod *>(pVar) == nullptr ) 743 { 744 aLine += " !! Not a Method !!"; 745 } 746 write_uInt16_lenPrefixed_uInt8s_FromOUString(rStrm, aLine, RTL_TEXTENCODING_ASCII_US); 747 748 // Output also the object at object-methods 749 if ( pVar->GetValues_Impl().eType == SbxOBJECT && 750 pVar->GetValues_Impl().pObj && 751 pVar->GetValues_Impl().pObj != this && 752 pVar->GetValues_Impl().pObj != GetParent() ) 753 { 754 rStrm.WriteCharPtr( " contains " ); 755 static_cast<SbxObject*>(pVar->GetValues_Impl().pObj)->Dump( rStrm, bFill ); 756 } 757 else 758 { 759 rStrm << endl; 760 } 761 } 762 } 763 764 // Properties 765 rStrm.WriteCharPtr( aIndentNameStr.getStr() ).WriteCharPtr( "- Properties:" ) << endl; 766 { 767 for( sal_uInt16 i = 0; i < pProps->Count(); i++ ) 768 { 769 SbxVariableRef& r = pProps->GetRef( i ); 770 SbxVariable* pVar = r.get(); 771 if( pVar ) 772 { 773 OUString aLine = aIndent + " - " + pVar->GetName( SbxNameType::ShortTypes ); 774 OUString aAttrs3; 775 if( CollectAttrs( pVar, aAttrs3 ) ) 776 { 777 aLine += aAttrs3; 778 } 779 if( dynamic_cast<const SbxProperty *>(pVar) == nullptr ) 780 { 781 aLine += " !! Not a Property !!"; 782 } 783 write_uInt16_lenPrefixed_uInt8s_FromOUString(rStrm, aLine, RTL_TEXTENCODING_ASCII_US); 784 785 // output also the object at object properties 786 if ( pVar->GetValues_Impl().eType == SbxOBJECT && 787 pVar->GetValues_Impl().pObj && 788 pVar->GetValues_Impl().pObj != this && 789 pVar->GetValues_Impl().pObj != GetParent() ) 790 { 791 rStrm.WriteCharPtr( " contains " ); 792 static_cast<SbxObject*>(pVar->GetValues_Impl().pObj)->Dump( rStrm, bFill ); 793 } 794 else 795 { 796 rStrm << endl; 797 } 798 } 799 } 800 } 801 802 // Objects 803 rStrm.WriteCharPtr( aIndentNameStr.getStr() ).WriteCharPtr( "- Objects:" ) << endl; 804 { 805 for( sal_uInt16 i = 0; i < pObjs->Count(); i++ ) 806 { 807 SbxVariableRef& r = pObjs->GetRef( i ); 808 SbxVariable* pVar = r.get(); 809 if ( pVar ) 810 { 811 rStrm.WriteCharPtr( aIndentNameStr.getStr() ).WriteCharPtr( " - Sub" ); 812 if (SbxObject *pSbxObj = dynamic_cast<SbxObject*>(pVar)) 813 { 814 pSbxObj->Dump(rStrm, bFill); 815 } 816 else 817 { 818 pVar->Dump(rStrm, bFill); 819 } 820 } 821 } 822 } 823 824 rStrm.WriteCharPtr( aIndentNameStr.getStr() ).WriteCharPtr( "}" ) << endl << endl; 825 --nLevel; 826 } 827 828 SbxMethod::SbxMethod( const OUString& r, SbxDataType t, bool bIsRuntimeFunction ) 829 : SbxVariable(t) 830 , mbIsRuntimeFunction(bIsRuntimeFunction) 831 , mbRuntimeFunctionReturnType(t) 832 { 833 SetName(r); 834 } 835 836 SbxMethod::SbxMethod( const SbxMethod& r ) 837 : SvRefBase(r) 838 , SbxVariable(r) 839 , mbIsRuntimeFunction(r.IsRuntimeFunction()) 840 , mbRuntimeFunctionReturnType(r.GetRuntimeFunctionReturnType()) 841 { 842 } 843 844 SbxMethod::~SbxMethod() 845 { 846 } 847 848 SbxClassType SbxMethod::GetClass() const 849 { 850 return SbxClassType::Method; 851 } 852 853 SbxProperty::SbxProperty( const OUString& r, SbxDataType t ) 854 : SbxVariable( t ) 855 { 856 SetName( r ); 857 } 858 859 SbxProperty::~SbxProperty() 860 { 861 } 862 863 SbxClassType SbxProperty::GetClass() const 864 { 865 return SbxClassType::Property; 866 } 867 868 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 869
