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 <rtlproto.hxx>
30 #include <sbunoobj.hxx>
31 #include <rtl/ustrbuf.hxx>
32 #include <sal/log.hxx>
34 #include <com/sun/star/uno/XInterface.hpp>
35 using namespace com::sun::star::uno
;
39 SbxVariable::SbxVariable()
43 SbxVariable::SbxVariable( const SbxVariable
& r
)
46 m_aDeclareClassName( r
.m_aDeclareClassName
),
47 m_xComListener( r
.m_xComListener
),
51 #if HAVE_FEATURE_SCRIPTING
52 if( r
.m_xComListener
.is() )
54 registerComListenerVariableForBasic( this, r
.m_pComListenerParentBasic
);
60 nUserData
= r
.nUserData
;
66 SbxEnsureParentVariable::SbxEnsureParentVariable(const SbxVariable
& r
)
68 , xParent(const_cast<SbxVariable
&>(r
).GetParent())
70 assert(GetParent() == xParent
.get());
73 void SbxEnsureParentVariable::SetParent(SbxObject
* p
)
75 assert(GetParent() == xParent
.get());
76 SbxVariable::SetParent(p
);
77 xParent
= SbxObjectRef(p
);
78 assert(GetParent() == xParent
.get());
81 SbxVariable::SbxVariable( SbxDataType t
) : SbxValue( t
)
85 SbxVariable::~SbxVariable()
87 #if HAVE_FEATURE_SCRIPTING
88 if( IsSet( SbxFlagBits::DimAsNew
))
90 removeDimAsNewRecoverItem( this );
93 mpBroadcaster
.reset();
98 SfxBroadcaster
& SbxVariable::GetBroadcaster()
102 mpBroadcaster
.reset( new SfxBroadcaster
);
104 return *mpBroadcaster
;
107 SbxArray
* SbxVariable::GetParameters() const
113 // Perhaps some day one could cut the parameter 0.
114 // Then the copying will be dropped...
116 void SbxVariable::Broadcast( SfxHintId nHintId
)
118 if( !mpBroadcaster
|| IsSet( SbxFlagBits::NoBroadcast
) )
121 // Because the method could be called from outside, check the
123 if( nHintId
== SfxHintId::BasicDataWanted
)
130 if( nHintId
== SfxHintId::BasicDataChanged
)
138 //fdo#86843 Add a ref during the following block to guard against
139 //getting deleted before completing this method
140 SbxVariableRef
aBroadcastGuard(this);
142 // Avoid further broadcasting
143 std::unique_ptr
<SfxBroadcaster
> pSave
= std::move(mpBroadcaster
);
144 SbxFlagBits nSaveFlags
= GetFlags();
145 SetFlag( SbxFlagBits::ReadWrite
);
148 // Register this as element 0, but don't change over the parent!
149 mpPar
->GetRef(0) = this;
151 pSave
->Broadcast( SbxHint( nHintId
, this ) );
152 mpBroadcaster
= std::move(pSave
);
153 SetFlags( nSaveFlags
);
156 SbxInfo
* SbxVariable::GetInfo()
160 Broadcast( SfxHintId::BasicInfoWanted
);
169 void SbxVariable::SetInfo( SbxInfo
* p
)
174 void SbxVariable::SetParameters( SbxArray
* p
)
180 // Name of the variables
182 void SbxVariable::SetName( const OUString
& rName
)
185 nHash
= MakeHashCode( rName
);
188 const OUString
& SbxVariable::GetName( SbxNameType t
) const
190 static const char cSuffixes
[] = " %&!#@ $";
191 if( t
== SbxNameType::NONE
)
195 // Request parameter-information (not for objects)
196 const_cast<SbxVariable
*>(this)->GetInfo();
197 // Append nothing, if it is a simple property (no empty brackets)
198 if (!pInfo
.is() || (pInfo
->m_Params
.empty() && GetClass() == SbxClassType::Property
))
202 sal_Unicode cType
= ' ';
203 OUStringBuffer
aTmp( maName
);
204 // short type? Then fetch it, possible this is 0.
205 SbxDataType et
= GetType();
206 if( t
== SbxNameType::ShortTypes
)
208 if( et
<= SbxSTRING
)
210 cType
= cSuffixes
[ et
];
219 for (SbxParams::const_iterator iter
= pInfo
->m_Params
.begin(); iter
!= pInfo
->m_Params
.end(); ++iter
)
221 auto const& i
= *iter
;
222 int nt
= i
->eType
& 0x0FFF;
223 if (iter
!= pInfo
->m_Params
.begin())
227 if( i
->nFlags
& SbxFlagBits::Optional
)
229 aTmp
.append( GetSbxRes( StringId::Optional
) );
231 if( i
->eType
& SbxBYREF
)
233 aTmp
.append( GetSbxRes( StringId::ByRef
) );
235 aTmp
.append( i
->aName
);
237 // short type? Then fetch it, possible this is 0.
238 if( t
== SbxNameType::ShortTypes
)
240 if( nt
<= SbxSTRING
)
242 cType
= cSuffixes
[ nt
];
248 if( i
->eType
& SbxARRAY
)
255 if( i
->eType
& SbxARRAY
)
260 aTmp
.append(GetSbxRes( StringId::As
));
263 aTmp
.append(GetSbxRes( static_cast<StringId
>( static_cast<int>( StringId::Types
) + nt
) ));
267 aTmp
.append(GetSbxRes( StringId::Any
));
272 const_cast<SbxVariable
*>(this)->aToolString
= aTmp
.makeStringAndClear();
278 SbxVariable
& SbxVariable::operator=( const SbxVariable
& r
)
282 SbxValue::operator=( r
);
283 // tdf#144353 - copy information about a missing parameter. See SbiRuntime::SetIsMissing.
284 // We cannot unconditionally assign the data about a variable because we would overwrite
285 // the information about parameters (name, type, flags, and ids). For instance, in the case
286 // where a method will be initialized with a literal.
289 m_aDeclareClassName
= r
.m_aDeclareClassName
;
290 m_xComListener
= r
.m_xComListener
;
291 m_pComListenerParentBasic
= r
.m_pComListenerParentBasic
;
292 #if HAVE_FEATURE_SCRIPTING
293 if( m_xComListener
.is() )
295 registerComListenerVariableForBasic( this, m_pComListenerParentBasic
);
304 SbxDataType
SbxVariable::GetType() const
306 if( aData
.eType
== SbxOBJECT
)
308 return aData
.pObj
? aData
.pObj
->GetType() : SbxOBJECT
;
310 else if( aData
.eType
== SbxVARIANT
)
312 return aData
.pObj
? aData
.pObj
->GetType() : SbxVARIANT
;
320 SbxClassType
SbxVariable::GetClass() const
322 return SbxClassType::Variable
;
325 void SbxVariable::SetModified( bool b
)
327 if( IsSet( SbxFlagBits::NoModify
) )
331 SbxBase::SetModified( b
);
332 if( pParent
&& pParent
!= this ) //??? HotFix: Recursion out here MM
334 pParent
->SetModified( b
);
338 void SbxVariable::SetParent( SbxObject
* p
)
341 // Will the parent of a SbxObject be set?
342 if (p
&& dynamic_cast<SbxObject
*>(this))
344 // then this had to be a child of the new parent
346 SbxArray
*pChildren
= p
->GetObjects();
349 for (sal_uInt32 nIdx
= 0; !bFound
&& nIdx
< pChildren
->Count(); ++nIdx
)
351 bFound
= (this == pChildren
->Get(nIdx
));
355 !bFound
, "basic.sbx",
356 "dangling: [" << GetName() << "].SetParent([" << p
->GetName()
364 const OUString
& SbxVariable::GetDeclareClassName() const
366 return m_aDeclareClassName
;
369 void SbxVariable::SetDeclareClassName( const OUString
& rDeclareClassName
)
371 m_aDeclareClassName
= rDeclareClassName
;
374 void SbxVariable::SetComListener( const css::uno::Reference
< css::uno::XInterface
>& xComListener
,
375 StarBASIC
* pParentBasic
)
377 m_xComListener
= xComListener
;
378 m_pComListenerParentBasic
= pParentBasic
;
379 #if HAVE_FEATURE_SCRIPTING
380 registerComListenerVariableForBasic( this, pParentBasic
);
384 void SbxVariable::ClearComListener()
386 m_xComListener
.clear();
392 bool SbxVariable::LoadData( SvStream
& rStrm
, sal_uInt16 nVer
)
395 rStrm
.ReadUChar( cMark
);
398 if( !SbxValue::LoadData( rStrm
, nVer
) )
402 maName
= read_uInt16_lenPrefixed_uInt8s_ToOUString(rStrm
,
403 RTL_TEXTENCODING_ASCII_US
);
405 rStrm
.ReadUInt32( nTemp
);
412 rStrm
.ReadUInt16( nType
);
413 maName
= read_uInt16_lenPrefixed_uInt8s_ToOUString(rStrm
,
414 RTL_TEXTENCODING_ASCII_US
);
416 rStrm
.ReadUInt32( nTemp
);
418 // correction: old methods have instead of SbxNULL now SbxEMPTY
419 if( nType
== SbxNULL
&& GetClass() == SbxClassType::Method
)
426 aTmp
.eType
= aData
.eType
= static_cast<SbxDataType
>(nType
);
427 aTmp
.pOUString
= &aVal
;
433 rStrm
.ReadInt16( aTmp
.nInteger
); break;
435 rStrm
.ReadInt32( aTmp
.nLong
); break;
439 aTmpString
= read_uInt16_lenPrefixed_uInt8s_ToOUString(
440 rStrm
, RTL_TEXTENCODING_ASCII_US
);
443 if( ImpScan( aTmpString
, d
, t
, nullptr, !LibreOffice6FloatingPointMode() ) != ERRCODE_NONE
|| t
== SbxDOUBLE
)
448 aTmp
.nSingle
= static_cast<float>(d
);
455 aTmpString
= read_uInt16_lenPrefixed_uInt8s_ToOUString(rStrm
,
456 RTL_TEXTENCODING_ASCII_US
);
458 if( ImpScan( aTmpString
, aTmp
.nDouble
, t
, nullptr, !LibreOffice6FloatingPointMode() ) != ERRCODE_NONE
)
466 aVal
= read_uInt16_lenPrefixed_uInt8s_ToOUString(rStrm
,
467 RTL_TEXTENCODING_ASCII_US
);
473 aData
.eType
= SbxNULL
;
474 SAL_WARN( "basic.sbx", "Loaded a non-supported data type" );
478 if( nType
!= SbxNULL
&& nType
!= SbxEMPTY
&& !Put( aTmp
) )
483 rStrm
.ReadUChar( cMark
);
484 // cMark is also a version number!
485 // 1: initial version
494 pInfo
->LoadData( rStrm
, static_cast<sal_uInt16
>(cMark
) );
496 Broadcast( SfxHintId::BasicDataChanged
);
497 nHash
= MakeHashCode( maName
);
502 bool SbxVariable::StoreData( SvStream
& rStrm
) const
504 rStrm
.WriteUChar( 0xFF ); // Marker
506 if( dynamic_cast<const SbxMethod
*>(this) != nullptr )
508 // #50200 Avoid that objects , which during the runtime
509 // as return-value are saved in the method as a value were saved
510 SbxVariable
* pThis
= const_cast<SbxVariable
*>(this);
511 SbxFlagBits nSaveFlags
= GetFlags();
512 pThis
->SetFlag( SbxFlagBits::Write
);
513 pThis
->SbxValue::Clear();
514 pThis
->SetFlags( nSaveFlags
);
516 // So that the method will not be executed in any case!
517 // CAST, to avoid const!
518 pThis
->SetFlag( SbxFlagBits::NoBroadcast
);
519 bValStore
= SbxValue::StoreData( rStrm
);
520 pThis
->ResetFlag( SbxFlagBits::NoBroadcast
);
524 bValStore
= SbxValue::StoreData( rStrm
);
530 write_uInt16_lenPrefixed_uInt8s_FromOUString(rStrm
, maName
,
531 RTL_TEXTENCODING_ASCII_US
);
532 rStrm
.WriteUInt32( nUserData
);
535 rStrm
.WriteUChar( 2 ); // Version 2: with UserData!
536 pInfo
->StoreData( rStrm
);
540 rStrm
.WriteUChar( 0 );
551 SbxInfo::SbxInfo( const OUString
& r
, sal_uInt32 n
)
552 : aHelpFile( r
), nHelpId( n
)
555 void SbxVariable::Dump( SvStream
& rStrm
, bool bFill
)
557 OString
aBNameStr(OUStringToOString(GetName( SbxNameType::ShortTypes
), RTL_TEXTENCODING_ASCII_US
));
558 rStrm
.WriteCharPtr( "Variable( " )
559 .WriteOString( OString::number(reinterpret_cast<sal_Int64
>(this)) ).WriteCharPtr( "==" )
560 .WriteOString( aBNameStr
);
561 OString
aBParentNameStr(OUStringToOString(GetParent()->GetName(), RTL_TEXTENCODING_ASCII_US
));
564 rStrm
.WriteCharPtr( " in parent '" ).WriteOString( aBParentNameStr
).WriteCharPtr( "'" );
568 rStrm
.WriteCharPtr( " no parent" );
570 rStrm
.WriteCharPtr( " ) " );
572 // output also the object at object-vars
573 if ( GetValues_Impl().eType
== SbxOBJECT
&&
574 GetValues_Impl().pObj
&&
575 GetValues_Impl().pObj
!= this &&
576 GetValues_Impl().pObj
!= GetParent() )
578 rStrm
.WriteCharPtr( " contains " );
579 static_cast<SbxObject
*>(GetValues_Impl().pObj
)->Dump( rStrm
, bFill
);
587 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */