1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <config_features.h>
22 #include <tools/stream.hxx>
23 #include <svl/SfxBroadcaster.hxx>
25 #include <basic/sbx.hxx>
26 #include <runtime.hxx>
28 #include "sbxconv.hxx"
29 #include <sbunoobj.hxx>
30 #include <rtl/character.hxx>
31 #include <sal/log.hxx>
33 #include <com/sun/star/uno/XInterface.hpp>
34 using namespace com::sun::star::uno
;
43 friend class SbxVariable
;
44 OUString m_aDeclareClassName
;
45 Reference
< XInterface
> m_xComListener
;
46 StarBASIC
* m_pComListenerParentBasic
;
49 : m_pComListenerParentBasic( nullptr )
56 SbxVariable::SbxVariable() : SbxValue()
63 SbxVariable::SbxVariable( const SbxVariable
& r
)
69 if( r
.mpImpl
!= nullptr )
71 mpImpl
.reset( new SbxVariableImpl( *r
.mpImpl
) );
72 #if HAVE_FEATURE_SCRIPTING
73 if( mpImpl
->m_xComListener
.is() )
75 registerComListenerVariableForBasic( this, mpImpl
->m_pComListenerParentBasic
);
82 nUserData
= r
.nUserData
;
94 SbxEnsureParentVariable::SbxEnsureParentVariable(const SbxVariable
& r
)
96 , xParent(const_cast<SbxVariable
&>(r
).GetParent())
98 assert(GetParent() == xParent
.get());
101 void SbxEnsureParentVariable::SetParent(SbxObject
* p
)
103 assert(GetParent() == xParent
.get());
104 SbxVariable::SetParent(p
);
105 xParent
= SbxObjectRef(p
);
106 assert(GetParent() == xParent
.get());
109 SbxVariable::SbxVariable( SbxDataType t
) : SbxValue( t
)
116 SbxVariable::~SbxVariable()
118 #if HAVE_FEATURE_SCRIPTING
119 if( IsSet( SbxFlagBits::DimAsNew
))
121 removeDimAsNewRecoverItem( this );
124 mpBroadcaster
.reset();
129 SfxBroadcaster
& SbxVariable::GetBroadcaster()
133 mpBroadcaster
.reset( new SfxBroadcaster
);
135 return *mpBroadcaster
;
138 SbxArray
* SbxVariable::GetParameters() const
144 // Perhaps some day one could cut the parameter 0.
145 // Then the copying will be dropped...
147 void SbxVariable::Broadcast( SfxHintId nHintId
)
149 if( mpBroadcaster
&& !IsSet( SbxFlagBits::NoBroadcast
) )
151 // Because the method could be called from outside, check the
153 if( nHintId
== SfxHintId::BasicDataWanted
)
160 if( nHintId
== SfxHintId::BasicDataChanged
)
168 //fdo#86843 Add a ref during the following block to guard against
169 //getting deleted before completing this method
170 SbxVariableRef
aBroadcastGuard(this);
172 // Avoid further broadcasting
173 std::unique_ptr
<SfxBroadcaster
> pSave
= std::move(mpBroadcaster
);
174 SbxFlagBits nSaveFlags
= GetFlags();
175 SetFlag( SbxFlagBits::ReadWrite
);
178 // Register this as element 0, but don't change over the parent!
179 mpPar
->GetRef( 0 ) = this;
181 pSave
->Broadcast( SbxHint( nHintId
, this ) );
182 mpBroadcaster
= std::move(pSave
);
183 SetFlags( nSaveFlags
);
187 SbxInfo
* SbxVariable::GetInfo()
191 Broadcast( SfxHintId::BasicInfoWanted
);
200 void SbxVariable::SetInfo( SbxInfo
* p
)
205 void SbxVariable::SetParameters( SbxArray
* p
)
211 // Name of the variables
213 void SbxVariable::SetName( const OUString
& rName
)
216 nHash
= MakeHashCode( rName
);
219 const OUString
& SbxVariable::GetName( SbxNameType t
) const
221 static const OUString cSuffixes
{ " %&!#@ $" };
222 if( t
== SbxNameType::NONE
)
226 // Request parameter-information (not for objects)
227 const_cast<SbxVariable
*>(this)->GetInfo();
228 // Append nothing, if it is a simple property (no empty brackets)
229 if (!pInfo
.is() || (pInfo
->m_Params
.empty() && GetClass() == SbxClassType::Property
))
233 sal_Unicode cType
= ' ';
234 OUStringBuffer
aTmp( maName
);
235 // short type? Then fetch it, possible this is 0.
236 SbxDataType et
= GetType();
237 if( t
== SbxNameType::ShortTypes
)
239 if( et
<= SbxSTRING
)
241 cType
= cSuffixes
[ et
];
250 for (SbxParams::const_iterator iter
= pInfo
->m_Params
.begin(); iter
!= pInfo
->m_Params
.end(); ++iter
)
252 auto const& i
= *iter
;
253 int nt
= i
->eType
& 0x0FFF;
254 if (iter
!= pInfo
->m_Params
.begin())
258 if( i
->nFlags
& SbxFlagBits::Optional
)
260 aTmp
.append( GetSbxRes( StringId::Optional
) );
262 if( i
->eType
& SbxBYREF
)
264 aTmp
.append( GetSbxRes( StringId::ByRef
) );
266 aTmp
.append( i
->aName
);
268 // short type? Then fetch it, possible this is 0.
269 if( t
== SbxNameType::ShortTypes
)
271 if( nt
<= SbxSTRING
)
273 cType
= cSuffixes
[ nt
];
279 if( i
->eType
& SbxARRAY
)
286 if( i
->eType
& SbxARRAY
)
291 aTmp
.append(GetSbxRes( StringId::As
));
294 aTmp
.append(GetSbxRes( static_cast<StringId
>( static_cast<int>( StringId::Types
) + nt
) ));
298 aTmp
.append(GetSbxRes( StringId::Any
));
303 const_cast<SbxVariable
*>(this)->aToolString
= aTmp
.makeStringAndClear();
307 // Create a simple hashcode: the first six characters are evaluated.
309 sal_uInt16
SbxVariable::MakeHashCode( const OUString
& rName
)
312 sal_Int32 nLen
= rName
.getLength();
317 for( sal_Int32 i
=0; i
<nLen
; ++i
)
319 sal_uInt8 c
= static_cast<sal_uInt8
>(rName
[i
]);
320 // If we have a comment sign break!!
325 n
= sal::static_int_cast
< sal_uInt16
>( ( n
<< 3 ) + rtl::toAsciiUpperCase( c
) );
332 SbxVariable
& SbxVariable::operator=( const SbxVariable
& r
)
336 SbxValue::operator=( r
);
338 if( r
.mpImpl
!= nullptr )
340 mpImpl
.reset( new SbxVariableImpl( *r
.mpImpl
) );
341 #if HAVE_FEATURE_SCRIPTING
342 if( mpImpl
->m_xComListener
.is() )
344 registerComListenerVariableForBasic( this, mpImpl
->m_pComListenerParentBasic
);
354 SbxDataType
SbxVariable::GetType() const
356 if( aData
.eType
== SbxOBJECT
)
358 return aData
.pObj
? aData
.pObj
->GetType() : SbxOBJECT
;
360 else if( aData
.eType
== SbxVARIANT
)
362 return aData
.pObj
? aData
.pObj
->GetType() : SbxVARIANT
;
370 SbxClassType
SbxVariable::GetClass() const
372 return SbxClassType::Variable
;
375 void SbxVariable::SetModified( bool b
)
377 if( IsSet( SbxFlagBits::NoModify
) )
381 SbxBase::SetModified( b
);
382 if( pParent
&& pParent
!= this ) //??? HotFix: Recursion out here MM
384 pParent
->SetModified( b
);
388 void SbxVariable::SetParent( SbxObject
* p
)
391 // Will the parent of a SbxObject be set?
392 if (p
&& dynamic_cast<SbxObject
*>(this))
394 // then this had to be a child of the new parent
396 SbxArray
*pChildren
= p
->GetObjects();
399 for ( sal_uInt16 nIdx
= 0; !bFound
&& nIdx
< pChildren
->Count(); ++nIdx
)
401 bFound
= ( this == pChildren
->Get(nIdx
) );
405 !bFound
, "basic.sbx",
406 "dangling: [" << GetName() << "].SetParent([" << p
->GetName()
414 SbxVariableImpl
* SbxVariable::getImpl()
418 mpImpl
.reset(new SbxVariableImpl
);
423 const OUString
& SbxVariable::GetDeclareClassName()
425 SbxVariableImpl
* pImpl
= getImpl();
426 return pImpl
->m_aDeclareClassName
;
429 void SbxVariable::SetDeclareClassName( const OUString
& rDeclareClassName
)
431 SbxVariableImpl
* pImpl
= getImpl();
432 pImpl
->m_aDeclareClassName
= rDeclareClassName
;
435 void SbxVariable::SetComListener( const css::uno::Reference
< css::uno::XInterface
>& xComListener
,
436 StarBASIC
* pParentBasic
)
438 SbxVariableImpl
* pImpl
= getImpl();
439 pImpl
->m_xComListener
= xComListener
;
440 pImpl
->m_pComListenerParentBasic
= pParentBasic
;
441 #if HAVE_FEATURE_SCRIPTING
442 registerComListenerVariableForBasic( this, pParentBasic
);
446 void SbxVariable::ClearComListener()
448 SbxVariableImpl
* pImpl
= getImpl();
449 pImpl
->m_xComListener
.clear();
455 bool SbxVariable::LoadData( SvStream
& rStrm
, sal_uInt16 nVer
)
458 rStrm
.ReadUChar( cMark
);
461 if( !SbxValue::LoadData( rStrm
, nVer
) )
465 maName
= read_uInt16_lenPrefixed_uInt8s_ToOUString(rStrm
,
466 RTL_TEXTENCODING_ASCII_US
);
468 rStrm
.ReadUInt32( nTemp
);
475 rStrm
.ReadUInt16( nType
);
476 maName
= read_uInt16_lenPrefixed_uInt8s_ToOUString(rStrm
,
477 RTL_TEXTENCODING_ASCII_US
);
479 rStrm
.ReadUInt32( nTemp
);
481 // correction: old methods have instead of SbxNULL now SbxEMPTY
482 if( nType
== SbxNULL
&& GetClass() == SbxClassType::Method
)
489 aTmp
.eType
= aData
.eType
= static_cast<SbxDataType
>(nType
);
490 aTmp
.pOUString
= &aVal
;
496 rStrm
.ReadInt16( aTmp
.nInteger
); break;
498 rStrm
.ReadInt32( aTmp
.nLong
); break;
502 aTmpString
= read_uInt16_lenPrefixed_uInt8s_ToOUString(
503 rStrm
, RTL_TEXTENCODING_ASCII_US
);
506 if( ImpScan( aTmpString
, d
, t
, nullptr, false ) != ERRCODE_NONE
|| t
== SbxDOUBLE
)
511 aTmp
.nSingle
= static_cast<float>(d
);
518 aTmpString
= read_uInt16_lenPrefixed_uInt8s_ToOUString(rStrm
,
519 RTL_TEXTENCODING_ASCII_US
);
521 if( ImpScan( aTmpString
, aTmp
.nDouble
, t
, nullptr, false ) != ERRCODE_NONE
)
529 aVal
= read_uInt16_lenPrefixed_uInt8s_ToOUString(rStrm
,
530 RTL_TEXTENCODING_ASCII_US
);
536 aData
.eType
= SbxNULL
;
537 SAL_WARN( "basic.sbx", "Loaded a non-supported data type" );
541 if( nType
!= SbxNULL
&& nType
!= SbxEMPTY
&& !Put( aTmp
) )
546 rStrm
.ReadUChar( cMark
);
547 // cMark is also a version number!
548 // 1: initial version
557 pInfo
->LoadData( rStrm
, static_cast<sal_uInt16
>(cMark
) );
559 Broadcast( SfxHintId::BasicDataChanged
);
560 nHash
= MakeHashCode( maName
);
565 bool SbxVariable::StoreData( SvStream
& rStrm
) const
567 rStrm
.WriteUChar( 0xFF ); // Marker
569 if( dynamic_cast<const SbxMethod
*>(this) != nullptr )
571 // #50200 Avoid that objects , which during the runtime
572 // as return-value are saved in the method as a value were saved
573 SbxVariable
* pThis
= const_cast<SbxVariable
*>(this);
574 SbxFlagBits nSaveFlags
= GetFlags();
575 pThis
->SetFlag( SbxFlagBits::Write
);
576 pThis
->SbxValue::Clear();
577 pThis
->SetFlags( nSaveFlags
);
579 // So that the method will not be executed in any case!
580 // CAST, to avoid const!
581 pThis
->SetFlag( SbxFlagBits::NoBroadcast
);
582 bValStore
= SbxValue::StoreData( rStrm
);
583 pThis
->ResetFlag( SbxFlagBits::NoBroadcast
);
587 bValStore
= SbxValue::StoreData( rStrm
);
593 write_uInt16_lenPrefixed_uInt8s_FromOUString(rStrm
, maName
,
594 RTL_TEXTENCODING_ASCII_US
);
595 rStrm
.WriteUInt32( nUserData
);
598 rStrm
.WriteUChar( 2 ); // Version 2: with UserData!
599 pInfo
->StoreData( rStrm
);
603 rStrm
.WriteUChar( 0 );
611 : aHelpFile(), nHelpId(0)
614 SbxInfo::SbxInfo( const OUString
& r
, sal_uInt32 n
)
615 : aHelpFile( r
), nHelpId( n
)
618 void SbxVariable::Dump( SvStream
& rStrm
, bool bFill
)
620 OString
aBNameStr(OUStringToOString(GetName( SbxNameType::ShortTypes
), RTL_TEXTENCODING_ASCII_US
));
621 rStrm
.WriteCharPtr( "Variable( " )
622 .WriteOString( OString::number(reinterpret_cast<sal_Int64
>(this)) ).WriteCharPtr( "==" )
623 .WriteOString( aBNameStr
);
624 OString
aBParentNameStr(OUStringToOString(GetParent()->GetName(), RTL_TEXTENCODING_ASCII_US
));
627 rStrm
.WriteCharPtr( " in parent '" ).WriteOString( aBParentNameStr
).WriteCharPtr( "'" );
631 rStrm
.WriteCharPtr( " no parent" );
633 rStrm
.WriteCharPtr( " ) " );
635 // output also the object at object-vars
636 if ( GetValues_Impl().eType
== SbxOBJECT
&&
637 GetValues_Impl().pObj
&&
638 GetValues_Impl().pObj
!= this &&
639 GetValues_Impl().pObj
!= GetParent() )
641 rStrm
.WriteCharPtr( " contains " );
642 static_cast<SbxObject
*>(GetValues_Impl().pObj
)->Dump( rStrm
, bFill
);
650 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */