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