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/debug.hxx>
23 #include <tools/stream.hxx>
24 #include <svl/SfxBroadcaster.hxx>
26 #include <basic/sbx.hxx>
27 #include "runtime.hxx"
29 #include "sbxconv.hxx"
30 #include "sbunoobj.hxx"
32 #include <rtl/character.hxx>
34 #include <com/sun/star/uno/XInterface.hpp>
35 using namespace com::sun::star::uno
;
44 friend class SbxVariable
;
45 OUString m_aDeclareClassName
;
46 Reference
< XInterface
> m_xComListener
;
47 StarBASIC
* m_pComListenerParentBasic
;
50 : m_pComListenerParentBasic( nullptr )
52 SbxVariableImpl( const SbxVariableImpl
& r
)
53 : m_aDeclareClassName( r
.m_aDeclareClassName
)
54 , m_xComListener( r
.m_xComListener
)
55 , m_pComListenerParentBasic( r
.m_pComListenerParentBasic
)
63 SbxVariable::SbxVariable() : SbxValue()
71 SbxVariable::SbxVariable( const SbxVariable
& r
)
77 if( r
.mpImpl
!= nullptr )
79 mpImpl
.reset( new SbxVariableImpl( *r
.mpImpl
) );
80 #if HAVE_FEATURE_SCRIPTING
81 if( mpImpl
->m_xComListener
.is() )
83 registerComListenerVariableForBasic( this, mpImpl
->m_pComListenerParentBasic
);
91 nUserData
= r
.nUserData
;
103 SbxEnsureParentVariable::SbxEnsureParentVariable(const SbxVariable
& r
)
105 , xParent(const_cast<SbxVariable
&>(r
).GetParent())
107 assert(GetParent() == xParent
.get());
110 void SbxEnsureParentVariable::SetParent(SbxObject
* p
)
112 assert(GetParent() == xParent
.get());
113 SbxVariable::SetParent(p
);
114 xParent
= SbxObjectRef(p
);
115 assert(GetParent() == xParent
.get());
118 SbxVariable::SbxVariable( SbxDataType t
) : SbxValue( t
)
126 SbxVariable::~SbxVariable()
128 #if HAVE_FEATURE_SCRIPTING
129 if( IsSet( SbxFlagBits::DimAsNew
))
131 removeDimAsNewRecoverItem( this );
139 SfxBroadcaster
& SbxVariable::GetBroadcaster()
143 pCst
= new SfxBroadcaster
;
148 SbxArray
* SbxVariable::GetParameters() const
154 // Perhaps some day one could cut the parameter 0.
155 // Then the copying will be dropped...
157 void SbxVariable::Broadcast( SfxHintId nHintId
)
159 if( pCst
&& !IsSet( SbxFlagBits::NoBroadcast
) )
161 // Because the method could be called from outside, check the
163 if( nHintId
== SfxHintId::BasicDataWanted
)
170 if( nHintId
== SfxHintId::BasicDataChanged
)
178 //fdo#86843 Add a ref during the following block to guard against
179 //getting deleted before completing this method
180 SbxVariableRef
aBroadcastGuard(this);
182 // Avoid further broadcasting
183 SfxBroadcaster
* pSave
= pCst
;
185 SbxFlagBits nSaveFlags
= GetFlags();
186 SetFlag( SbxFlagBits::ReadWrite
);
189 // Register this as element 0, but don't change over the parent!
190 mpPar
->GetRef( 0 ) = this;
192 pSave
->Broadcast( SbxHint( nHintId
, this ) );
193 delete pCst
; // who knows already, onto which thoughts someone comes?
195 SetFlags( nSaveFlags
);
199 SbxInfo
* SbxVariable::GetInfo()
203 Broadcast( SfxHintId::BasicInfoWanted
);
212 void SbxVariable::SetInfo( SbxInfo
* p
)
217 void SbxVariable::SetParameters( SbxArray
* p
)
223 // Name of the variables
225 void SbxVariable::SetName( const OUString
& rName
)
228 nHash
= MakeHashCode( rName
);
231 const OUString
& SbxVariable::GetName( SbxNameType t
) const
233 static const char cSuffixes
[] = " %&!#@ $";
234 if( t
== SbxNameType::NONE
)
238 // Request parameter-information (not for objects)
239 const_cast<SbxVariable
*>(this)->GetInfo();
240 // Append nothing, if it is a simple property (no empty brackets)
241 if (!pInfo
.is() || (pInfo
->m_Params
.empty() && GetClass() == SbxClassType::Property
))
245 sal_Unicode cType
= ' ';
246 OUString
aTmp( maName
);
247 // short type? Then fetch it, possible this is 0.
248 SbxDataType et
= GetType();
249 if( t
== SbxNameType::ShortTypes
)
251 if( et
<= SbxSTRING
)
253 cType
= cSuffixes
[ et
];
257 aTmp
+= OUStringLiteral1(cType
);
262 for (SbxParams::const_iterator iter
= pInfo
->m_Params
.begin(); iter
!= pInfo
->m_Params
.end(); ++iter
)
264 auto const& i
= *iter
;
265 int nt
= i
->eType
& 0x0FFF;
266 if (iter
!= pInfo
->m_Params
.begin())
270 if( i
->nFlags
& SbxFlagBits::Optional
)
272 aTmp
+= GetSbxRes( StringId::Optional
);
274 if( i
->eType
& SbxBYREF
)
276 aTmp
+= GetSbxRes( StringId::ByRef
);
280 // short type? Then fetch it, possible this is 0.
281 if( t
== SbxNameType::ShortTypes
)
283 if( nt
<= SbxSTRING
)
285 cType
= cSuffixes
[ nt
];
290 aTmp
+= OUStringLiteral1(cType
);
291 if( i
->eType
& SbxARRAY
)
298 if( i
->eType
& SbxARRAY
)
303 aTmp
+= GetSbxRes( StringId::As
);
306 aTmp
+= GetSbxRes( static_cast<StringId
>( static_cast<int>( StringId::Types
) + nt
) );
310 aTmp
+= GetSbxRes( StringId::Any
);
315 const_cast<SbxVariable
*>(this)->aToolString
= aTmp
;
319 // Create a simple hashcode: the first six characters are evaluated.
321 sal_uInt16
SbxVariable::MakeHashCode( const OUString
& rName
)
324 sal_Int32 nLen
= rName
.getLength();
329 for( sal_Int32 i
=0; i
<nLen
; ++i
)
331 sal_uInt8 c
= static_cast<sal_uInt8
>(rName
[i
]);
332 // If we have a comment sign break!!
337 n
= sal::static_int_cast
< sal_uInt16
>( ( n
<< 3 ) + rtl::toAsciiUpperCase( c
) );
344 SbxVariable
& SbxVariable::operator=( const SbxVariable
& r
)
346 SbxValue::operator=( r
);
348 if( r
.mpImpl
!= nullptr )
350 mpImpl
.reset( new SbxVariableImpl( *r
.mpImpl
) );
351 #if HAVE_FEATURE_SCRIPTING
352 if( mpImpl
->m_xComListener
.is() )
354 registerComListenerVariableForBasic( this, mpImpl
->m_pComListenerParentBasic
);
363 SbxDataType
SbxVariable::GetType() const
365 if( aData
.eType
== SbxOBJECT
)
367 return aData
.pObj
? aData
.pObj
->GetType() : SbxOBJECT
;
369 else if( aData
.eType
== SbxVARIANT
)
371 return aData
.pObj
? aData
.pObj
->GetType() : SbxVARIANT
;
379 SbxClassType
SbxVariable::GetClass() const
381 return SbxClassType::Variable
;
384 void SbxVariable::SetModified( bool b
)
386 if( IsSet( SbxFlagBits::NoModify
) )
390 SbxBase::SetModified( b
);
391 if( pParent
&& pParent
!= this ) //??? HotFix: Recursion out here MM
393 pParent
->SetModified( b
);
397 void SbxVariable::SetParent( SbxObject
* p
)
400 // Will the parent of a SbxObject be set?
401 if (p
&& dynamic_cast<SbxObject
*>(this))
403 // then this had to be a child of the new parent
405 SbxArray
*pChildren
= p
->GetObjects();
408 for ( sal_uInt16 nIdx
= 0; !bFound
&& nIdx
< pChildren
->Count(); ++nIdx
)
410 bFound
= ( this == pChildren
->Get(nIdx
) );
414 !bFound
, "basic.sbx",
415 "dangling: [" << GetName() << "].SetParent([" << p
->GetName()
423 SbxVariableImpl
* SbxVariable::getImpl()
427 mpImpl
.reset(new SbxVariableImpl
);
432 const OUString
& SbxVariable::GetDeclareClassName()
434 SbxVariableImpl
* pImpl
= getImpl();
435 return pImpl
->m_aDeclareClassName
;
438 void SbxVariable::SetDeclareClassName( const OUString
& rDeclareClassName
)
440 SbxVariableImpl
* pImpl
= getImpl();
441 pImpl
->m_aDeclareClassName
= rDeclareClassName
;
444 void SbxVariable::SetComListener( const css::uno::Reference
< css::uno::XInterface
>& xComListener
,
445 StarBASIC
* pParentBasic
)
447 SbxVariableImpl
* pImpl
= getImpl();
448 pImpl
->m_xComListener
= xComListener
;
449 pImpl
->m_pComListenerParentBasic
= pParentBasic
;
450 #if HAVE_FEATURE_SCRIPTING
451 registerComListenerVariableForBasic( this, pParentBasic
);
455 void SbxVariable::ClearComListener()
457 SbxVariableImpl
* pImpl
= getImpl();
458 pImpl
->m_xComListener
.clear();
464 bool SbxVariable::LoadData( SvStream
& rStrm
, sal_uInt16 nVer
)
468 rStrm
.ReadUChar( cMark
);
471 if( !SbxValue::LoadData( rStrm
, nVer
) )
475 maName
= read_uInt16_lenPrefixed_uInt8s_ToOUString(rStrm
,
476 RTL_TEXTENCODING_ASCII_US
);
478 rStrm
.ReadUInt32( nTemp
);
484 rStrm
.ReadUInt16( nType
);
485 maName
= read_uInt16_lenPrefixed_uInt8s_ToOUString(rStrm
,
486 RTL_TEXTENCODING_ASCII_US
);
488 rStrm
.ReadUInt32( nTemp
);
490 // correction: old methods have instead of SbxNULL now SbxEMPTY
491 if( nType
== SbxNULL
&& GetClass() == SbxClassType::Method
)
498 aTmp
.eType
= aData
.eType
= (SbxDataType
) nType
;
499 aTmp
.pOUString
= &aVal
;
505 rStrm
.ReadInt16( aTmp
.nInteger
); break;
507 rStrm
.ReadInt32( aTmp
.nLong
); break;
511 aTmpString
= read_uInt16_lenPrefixed_uInt8s_ToOUString(
512 rStrm
, RTL_TEXTENCODING_ASCII_US
);
515 if( ImpScan( aTmpString
, d
, t
, nullptr ) != ERRCODE_SBX_OK
|| t
== SbxDOUBLE
)
520 aTmp
.nSingle
= (float) d
;
527 aTmpString
= read_uInt16_lenPrefixed_uInt8s_ToOUString(rStrm
,
528 RTL_TEXTENCODING_ASCII_US
);
530 if( ImpScan( aTmpString
, aTmp
.nDouble
, t
, nullptr ) != ERRCODE_SBX_OK
)
538 aVal
= read_uInt16_lenPrefixed_uInt8s_ToOUString(rStrm
,
539 RTL_TEXTENCODING_ASCII_US
);
545 aData
.eType
= SbxNULL
;
546 SAL_WARN( "basic.sbx", "Loaded a non-supported data type" );
550 if( nType
!= SbxNULL
&& nType
!= SbxEMPTY
&& !Put( aTmp
) )
555 rStrm
.ReadUChar( cMark
);
556 // cMark is also a version number!
557 // 1: initial version
566 pInfo
->LoadData( rStrm
, (sal_uInt16
) cMark
);
568 Broadcast( SfxHintId::BasicDataChanged
);
569 nHash
= MakeHashCode( maName
);
574 bool SbxVariable::StoreData( SvStream
& rStrm
) const
576 rStrm
.WriteUChar( 0xFF ); // Marker
578 if( dynamic_cast<const SbxMethod
*>(this) != nullptr )
580 // #50200 Avoid that objects , which during the runtime
581 // as return-value are saved in the method as a value were saved
582 SbxVariable
* pThis
= const_cast<SbxVariable
*>(this);
583 SbxFlagBits nSaveFlags
= GetFlags();
584 pThis
->SetFlag( SbxFlagBits::Write
);
585 pThis
->SbxValue::Clear();
586 pThis
->SetFlags( nSaveFlags
);
588 // So that the method will not be executed in any case!
589 // CAST, to avoid const!
590 pThis
->SetFlag( SbxFlagBits::NoBroadcast
);
591 bValStore
= SbxValue::StoreData( rStrm
);
592 pThis
->ResetFlag( SbxFlagBits::NoBroadcast
);
596 bValStore
= SbxValue::StoreData( rStrm
);
602 write_uInt16_lenPrefixed_uInt8s_FromOUString(rStrm
, maName
,
603 RTL_TEXTENCODING_ASCII_US
);
604 rStrm
.WriteUInt32( nUserData
);
607 rStrm
.WriteUChar( 2 ); // Version 2: with UserData!
608 pInfo
->StoreData( rStrm
);
612 rStrm
.WriteUChar( 0 );
620 : aHelpFile(), nHelpId(0)
623 SbxInfo::SbxInfo( const OUString
& r
, sal_uInt32 n
)
624 : aHelpFile( r
), nHelpId( n
)
629 SbxAlias::SbxAlias( const SbxAlias
& r
)
630 : SvRefBase( r
), SbxVariable( r
),
631 SfxListener( r
), xAlias( r
.xAlias
)
634 SbxAlias
& SbxAlias::operator=( const SbxAlias
& r
)
640 SbxAlias::~SbxAlias()
644 EndListening( xAlias
->GetBroadcaster() );
648 void SbxAlias::Broadcast( SfxHintId nHt
)
652 xAlias
->SetParameters( GetParameters() );
653 if( nHt
== SfxHintId::BasicDataWanted
)
655 SbxVariable::operator=( *xAlias
);
657 else if( nHt
== SfxHintId::BasicDataChanged
|| nHt
== SfxHintId::BasicConverted
)
661 else if( nHt
== SfxHintId::BasicInfoWanted
)
663 xAlias
->Broadcast( nHt
);
664 pInfo
= xAlias
->GetInfo();
669 void SbxAlias::Notify( SfxBroadcaster
&, const SfxHint
& rHint
)
671 const SbxHint
* p
= dynamic_cast<const SbxHint
*>(&rHint
);
672 if( p
&& p
->GetId() == SfxHintId::BasicDying
)
678 pParent
->Remove( this );
683 void SbxVariable::Dump( SvStream
& rStrm
, bool bFill
)
685 OString
aBNameStr(OUStringToOString(GetName( SbxNameType::ShortTypes
), RTL_TEXTENCODING_ASCII_US
));
686 rStrm
.WriteCharPtr( "Variable( " )
687 .WriteCharPtr( OString::number(reinterpret_cast<sal_Int64
>(this)).getStr() ).WriteCharPtr( "==" )
688 .WriteCharPtr( aBNameStr
.getStr() );
689 OString
aBParentNameStr(OUStringToOString(GetParent()->GetName(), RTL_TEXTENCODING_ASCII_US
));
692 rStrm
.WriteCharPtr( " in parent '" ).WriteCharPtr( aBParentNameStr
.getStr() ).WriteCharPtr( "'" );
696 rStrm
.WriteCharPtr( " no parent" );
698 rStrm
.WriteCharPtr( " ) " );
700 // output also the object at object-vars
701 if ( GetValues_Impl().eType
== SbxOBJECT
&&
702 GetValues_Impl().pObj
&&
703 GetValues_Impl().pObj
!= this &&
704 GetValues_Impl().pObj
!= GetParent() )
706 rStrm
.WriteCharPtr( " contains " );
707 static_cast<SbxObject
*>(GetValues_Impl().pObj
)->Dump( rStrm
, bFill
);
715 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */