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 <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 
SbxObject(const OUString & rClass)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 
SbxObject(const SbxObject & rObj)56 SbxObject::SbxObject( const SbxObject& rObj )
57     : SvRefBase( rObj ), SbxVariable( rObj.GetType() ),
58       SfxListener( rObj )
59 {
60     *this = rObj;
61 }
62 
operator =(const SbxObject & r)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 
CheckParentsOnDelete(SbxObject * pObj,SbxArray * p)85 static void CheckParentsOnDelete( SbxObject* pObj, SbxArray* p )
86 {
87     for (sal_uInt32 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 
~SbxObject()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 
GetType() const113 SbxDataType SbxObject::GetType() const
114 {
115     return SbxOBJECT;
116 }
117 
GetClass() const118 SbxClassType SbxObject::GetClass() const
119 {
120     return SbxClassType::Object;
121 }
122 
Clear()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 
Notify(SfxBroadcaster &,const SfxHint & rHint)138 void SbxObject::Notify( SfxBroadcaster&, const SfxHint& rHint )
139 {
140     const SbxHint* p = dynamic_cast<const SbxHint*>(&rHint);
141     if( !p )
142         return;
143 
144     const SfxHintId nId = p->GetId();
145     bool bRead  = ( nId == SfxHintId::BasicDataWanted );
146     bool bWrite = ( nId == SfxHintId::BasicDataChanged );
147     SbxVariable* pVar = p->GetVar();
148     if( !(bRead || bWrite) )
149         return;
150 
151     OUString aVarName( pVar->GetName() );
152     sal_uInt16 nHash_ = MakeHashCode( aVarName );
153     if( nHash_ == nNameHash && aVarName.equalsIgnoreAsciiCase( pNameProp ) )
154     {
155         if( bRead )
156         {
157             pVar->PutString( GetName() );
158         }
159         else
160         {
161             SetName( pVar->GetOUString() );
162         }
163     }
164     else if( nHash_ == nParentHash && aVarName.equalsIgnoreAsciiCase( pParentProp ) )
165     {
166         SbxObject* p_ = GetParent();
167         if( !p_ )
168         {
169             p_ = this;
170         }
171         pVar->PutObject( p_ );
172     }
173 }
174 
IsClass(const OUString & rName) const175 bool SbxObject::IsClass( const OUString& rName ) const
176 {
177     return aClassName.equalsIgnoreAsciiCase( rName );
178 }
179 
Find(const OUString & rName,SbxClassType t)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 
Call(const OUString & rName,SbxArray * pParam)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 
GetDfltProperty()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 }
SetDfltProperty(const OUString & rName)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 
FindVar(SbxVariable const * pVar,sal_uInt32 & nArrayIdx)304 SbxArray* SbxObject::FindVar( SbxVariable const * pVar, sal_uInt32& 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_uInt32 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 
Make(const OUString & rName,SbxClassType ct,SbxDataType dt,bool bIsRuntimeFunction)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     SbxVariableRef pVar;
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 ).get();
379         break;
380     default:
381         break;
382     }
383     pVar->SetParent( this );
384     pArray->Put(pVar.get(), pArray->Count());
385     SetModified( true );
386     // The object listen always
387     StartListening(pVar->GetBroadcaster(), DuplicateHandling::Prevent);
388     return pVar.get();
389 }
390 
Insert(SbxVariable * pVar)391 void SbxObject::Insert( SbxVariable* pVar )
392 {
393     sal_uInt32 nIdx;
394     SbxArray* pArray = FindVar( pVar, nIdx );
395     if( !pArray )
396         return;
397 
398     // Into with it. But you should pay attention at the Pointer!
399     if (nIdx < pArray->Count())
400     {
401         // Then this element exists already
402         // There are objects of the same name allowed at collections
403         if( pArray == pObjs.get() && dynamic_cast<const SbxCollection*>( this ) != nullptr )
404         {
405             nIdx = pArray->Count();
406         }
407         else
408         {
409             SbxVariable* pOld = pArray->Get(nIdx);
410             // already inside: overwrite
411             if( pOld == pVar )
412             {
413                 return;
414             }
415             EndListening( pOld->GetBroadcaster(), true );
416             if( pVar->GetClass() == SbxClassType::Property )
417             {
418                 if( pOld == pDfltProp )
419                 {
420                     pDfltProp = static_cast<SbxProperty*>(pVar);
421                 }
422             }
423         }
424     }
425     StartListening(pVar->GetBroadcaster(), DuplicateHandling::Prevent);
426     pArray->Put(pVar, nIdx);
427     if( pVar->GetParent() != this )
428     {
429         pVar->SetParent( this );
430     }
431     SetModified( true );
432 #ifdef DBG_UTIL
433     static const char* pCls[] =
434         { "DontCare","Array","Value","Variable","Method","Property","Object" };
435     OUString aVarName( pVar->GetName() );
436     if (const SbxObject *pSbxObj = aVarName.isEmpty() ? dynamic_cast<const SbxObject*>(pVar) : nullptr)
437     {
438         aVarName = pSbxObj->GetClassName();
439     }
440     SAL_INFO(
441         "basic.sbx",
442         "insert "
443             << ((pVar->GetClass() >= SbxClassType::DontCare
444                  && pVar->GetClass() <= SbxClassType::Object)
445                 ? pCls[static_cast<int>(pVar->GetClass()) - 1] : "Unknown class")
446             << " " << aVarName << " in " << SbxVariable::GetName());
447 #endif
448 }
449 
450 // Optimisation, Insertion without checking about
451 // double entry and without broadcasts, will only be used in SO2/auto.cxx
QuickInsert(SbxVariable * pVar)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         return;
468 
469     StartListening(pVar->GetBroadcaster(), DuplicateHandling::Prevent);
470     pArray->Put(pVar, pArray->Count());
471     if( pVar->GetParent() != this )
472     {
473         pVar->SetParent( this );
474     }
475     SetModified( true );
476 #ifdef DBG_UTIL
477     static const char* pCls[] =
478         { "DontCare","Array","Value","Variable","Method","Property","Object" };
479     OUString aVarName( pVar->GetName() );
480     if (const SbxObject *pSbxObj = aVarName.isEmpty() ? dynamic_cast<const SbxObject*>(pVar) : nullptr)
481     {
482         aVarName = pSbxObj->GetClassName();
483     }
484     SAL_INFO(
485         "basic.sbx",
486         "insert "
487             << ((pVar->GetClass() >= SbxClassType::DontCare
488                  && pVar->GetClass() <= SbxClassType::Object)
489                 ? pCls[static_cast<int>(pVar->GetClass()) - 1] : "Unknown class")
490             << " " << aVarName << " in " << SbxVariable::GetName());
491 #endif
492 }
493 
Remove(const OUString & rName,SbxClassType t)494 void SbxObject::Remove( const OUString& rName, SbxClassType t )
495 {
496     Remove( SbxObject::Find( rName, t ) );
497 }
498 
Remove(SbxVariable * pVar)499 void SbxObject::Remove( SbxVariable* pVar )
500 {
501     sal_uInt32 nIdx;
502     SbxArray* pArray = FindVar( pVar, nIdx );
503     if (!(pArray && nIdx < pArray->Count()))
504         return;
505 
506 #ifdef DBG_UTIL
507     OUString aVarName( pVar->GetName() );
508     if (const SbxObject *pSbxObj = aVarName.isEmpty() ? dynamic_cast<const SbxObject*>(pVar) : nullptr)
509     {
510         aVarName = pSbxObj->GetClassName();
511     }
512     SAL_INFO(
513         "basic.sbx",
514         "remove " << aVarName << " in " << SbxVariable::GetName());
515 #endif
516     SbxVariableRef pVar_ = pArray->Get(nIdx);
517     if( pVar_->IsBroadcaster() )
518     {
519         EndListening( pVar_->GetBroadcaster(), true );
520     }
521     if( pVar_.get() == pDfltProp )
522     {
523         pDfltProp = nullptr;
524     }
525     pArray->Remove( nIdx );
526     if( pVar_->GetParent() == this )
527     {
528         pVar_->SetParent( nullptr );
529     }
530     SetModified( true );
531 }
532 
LoadArray(SvStream & rStrm,SbxObject * pThis,SbxArray * pArray)533 static bool LoadArray( SvStream& rStrm, SbxObject* pThis, SbxArray* pArray )
534 {
535     SbxArrayRef p = static_cast<SbxArray*>( SbxBase::Load( rStrm ).get() );
536     if( !p.is() )
537     {
538         return false;
539     }
540     for (sal_uInt32 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 
LoadData(SvStream & rStrm,sal_uInt16 nVer)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 
StoreData(SvStream & rStrm) const602 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 
CollectAttrs(const SbxBase * p,OUString & rRes)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 
Dump(SvStream & rStrm,bool bFill)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          .WriteOString( OString::number(reinterpret_cast<sal_Int64>(this)) ).WriteCharPtr( "=='" )
700          .WriteCharPtr( aNameStr.isEmpty() ?  "<unnamed>" : aNameStr.getStr()  ).WriteCharPtr( "', " )
701          .WriteCharPtr( "of class '" ).WriteOString( aClassNameStr ).WriteCharPtr( "', " )
702          .WriteCharPtr( "counts " )
703          .WriteOString( OString::number(GetRefCount()) )
704          .WriteCharPtr( " refs, " );
705     if ( GetParent() )
706     {
707         OString aParentNameStr(OUStringToOString(GetName(), RTL_TEXTENCODING_ASCII_US));
708         rStrm.WriteCharPtr( "in parent " )
709              .WriteOString( OString::number(reinterpret_cast<sal_Int64>(GetParent())) )
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.WriteOString( aIndentNameStr ).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.WriteOString( aIndentNameStr ).WriteCharPtr( "- Flags: " ).WriteOString( aAttrStr ) << endl;
726     }
727 
728     // Methods
729     rStrm.WriteOString( aIndentNameStr ).WriteCharPtr( "- Methods:" ) << endl;
730     for (sal_uInt32 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.WriteOString( aIndentNameStr ).WriteCharPtr( "- Properties:" ) << endl;
766     {
767         for (sal_uInt32 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.WriteOString( aIndentNameStr ).WriteCharPtr( "- Objects:" ) << endl;
804     {
805         for (sal_uInt32 i = 0; i < pObjs->Count(); i++)
806         {
807             SbxVariableRef& r = pObjs->GetRef(i);
808             SbxVariable* pVar = r.get();
809             if ( pVar )
810             {
811                 rStrm.WriteOString( aIndentNameStr ).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.WriteOString( aIndentNameStr ).WriteCharPtr( "}" ) << endl << endl;
825     --nLevel;
826 }
827 
SbxMethod(const OUString & r,SbxDataType t,bool bIsRuntimeFunction)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 
SbxMethod(const SbxMethod & r)836 SbxMethod::SbxMethod( const SbxMethod& r )
837     : SvRefBase(r)
838     , SbxVariable(r)
839     , mbIsRuntimeFunction(r.IsRuntimeFunction())
840     , mbRuntimeFunctionReturnType(r.GetRuntimeFunctionReturnType())
841 {
842 }
843 
~SbxMethod()844 SbxMethod::~SbxMethod()
845 {
846 }
847 
GetClass() const848 SbxClassType SbxMethod::GetClass() const
849 {
850     return SbxClassType::Method;
851 }
852 
SbxProperty(const OUString & r,SbxDataType t)853 SbxProperty::SbxProperty( const OUString& r, SbxDataType t )
854     : SbxVariable( t )
855 {
856     SetName( r );
857 }
858 
~SbxProperty()859 SbxProperty::~SbxProperty()
860 {
861 }
862 
GetClass() const863 SbxClassType SbxProperty::GetClass() const
864 {
865     return SbxClassType::Property;
866 }
867 
868 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
869