bump product version to 5.0.4.1
[LibreOffice.git] / basic / source / classes / sbxmod.cxx
blobd025cf00f06af21b9ffaa7d6a568511aa4b4a507
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
21 #include <list>
23 #include <boost/noncopyable.hpp>
24 #include <boost/scoped_ptr.hpp>
25 #include <vcl/svapp.hxx>
26 #include <tools/stream.hxx>
27 #include <svl/SfxBroadcaster.hxx>
28 #include <basic/sbx.hxx>
29 #include <basic/sbuno.hxx>
30 #include "sb.hxx"
31 #include <sbjsmeth.hxx>
32 #include "sbjsmod.hxx"
33 #include "sbintern.hxx"
34 #include "image.hxx"
35 #include "opcodes.hxx"
36 #include "runtime.hxx"
37 #include "token.hxx"
38 #include "sbunoobj.hxx"
40 #include <sal/log.hxx>
42 #include <basic/basrdll.hxx>
43 #include <osl/mutex.hxx>
44 #include "sbobjmod.hxx"
45 #include <basic/vbahelper.hxx>
46 #include <cppuhelper/implbase3.hxx>
47 #include <unotools/eventcfg.hxx>
48 #include <com/sun/star/frame/Desktop.hpp>
49 #include <com/sun/star/lang/XServiceInfo.hpp>
50 #include <com/sun/star/script/ModuleType.hpp>
51 #include <com/sun/star/script/vba/XVBACompatibility.hpp>
52 #include <com/sun/star/script/vba/VBAScriptEventId.hpp>
53 #include <com/sun/star/beans/XPropertySet.hpp>
54 #include <com/sun/star/document/XDocumentEventBroadcaster.hpp>
55 #include <com/sun/star/document/XDocumentEventListener.hpp>
57 #ifdef UNX
58 #include <sys/resource.h>
59 #endif
61 #include <com/sun/star/frame/XDesktop.hpp>
62 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
63 #include <comphelper/processfactory.hxx>
64 #include <map>
65 #include <com/sun/star/reflection/ProxyFactory.hpp>
66 #include <cppuhelper/implbase1.hxx>
67 #include <com/sun/star/uno/XAggregation.hpp>
68 #include <com/sun/star/script/XInvocation.hpp>
70 #include <com/sun/star/script/XLibraryContainer.hpp>
71 #include <com/sun/star/awt/DialogProvider.hpp>
72 #include <com/sun/star/awt/XTopWindow.hpp>
73 #include <com/sun/star/awt/XWindow.hpp>
74 #include <com/sun/star/awt/XControl.hpp>
75 #include <comphelper/anytostring.hxx>
76 #include <ooo/vba/VbQueryClose.hpp>
77 #include "sbxmod.hxx"
78 #include "parser.hxx"
80 #include <limits>
82 using namespace com::sun::star;
83 using namespace com::sun::star::lang;
84 using namespace com::sun::star::reflection;
85 using namespace com::sun::star::beans;
86 using namespace com::sun::star::script;
87 using namespace com::sun::star::uno;
89 typedef ::cppu::WeakImplHelper1< XInvocation > DocObjectWrapper_BASE;
90 typedef ::std::map< sal_Int16, Any, ::std::less< sal_Int16 > > OutParamMap;
92 class DocObjectWrapper : public DocObjectWrapper_BASE
94 Reference< XAggregation > m_xAggProxy;
95 Reference< XInvocation > m_xAggInv;
96 Reference< XTypeProvider > m_xAggregateTypeProv;
97 Sequence< Type > m_Types;
98 SbModule* m_pMod;
99 SbMethodRef getMethod( const OUString& aName ) throw (RuntimeException);
100 SbPropertyRef getProperty( const OUString& aName ) throw (RuntimeException);
101 OUString mName; // for debugging
103 public:
104 DocObjectWrapper( SbModule* pMod );
105 virtual ~DocObjectWrapper();
107 virtual void SAL_CALL acquire() throw() SAL_OVERRIDE;
108 virtual void SAL_CALL release() throw() SAL_OVERRIDE;
110 virtual Sequence< sal_Int8 > SAL_CALL getImplementationId() throw (RuntimeException, std::exception) SAL_OVERRIDE
112 return css::uno::Sequence<sal_Int8>();
115 virtual Reference< XIntrospectionAccess > SAL_CALL getIntrospection( ) throw (RuntimeException, std::exception) SAL_OVERRIDE;
117 virtual Any SAL_CALL invoke( const OUString& aFunctionName, const Sequence< Any >& aParams, Sequence< ::sal_Int16 >& aOutParamIndex, Sequence< Any >& aOutParam ) throw (IllegalArgumentException, CannotConvertException, InvocationTargetException, RuntimeException, std::exception) SAL_OVERRIDE;
118 virtual void SAL_CALL setValue( const OUString& aPropertyName, const Any& aValue ) throw (UnknownPropertyException, CannotConvertException, InvocationTargetException, RuntimeException, std::exception) SAL_OVERRIDE;
119 virtual Any SAL_CALL getValue( const OUString& aPropertyName ) throw (UnknownPropertyException, RuntimeException, std::exception) SAL_OVERRIDE;
120 virtual sal_Bool SAL_CALL hasMethod( const OUString& aName ) throw (RuntimeException, std::exception) SAL_OVERRIDE;
121 virtual sal_Bool SAL_CALL hasProperty( const OUString& aName ) throw (RuntimeException, std::exception) SAL_OVERRIDE;
122 virtual Any SAL_CALL queryInterface( const Type& aType ) throw ( RuntimeException, std::exception ) SAL_OVERRIDE;
124 virtual Sequence< Type > SAL_CALL getTypes() throw ( RuntimeException, std::exception ) SAL_OVERRIDE;
127 DocObjectWrapper::DocObjectWrapper( SbModule* pVar ) : m_pMod( pVar ), mName( pVar->GetName() )
129 SbObjModule* pMod = PTR_CAST(SbObjModule,pVar);
130 if ( pMod )
132 if ( pMod->GetModuleType() == ModuleType::DOCUMENT )
134 // Use proxy factory service to create aggregatable proxy.
135 SbUnoObject* pUnoObj = PTR_CAST(SbUnoObject,pMod->GetObject() );
136 Reference< XInterface > xIf;
137 if ( pUnoObj )
139 Any aObj = pUnoObj->getUnoAny();
140 aObj >>= xIf;
141 if ( xIf.is() )
143 m_xAggregateTypeProv.set( xIf, UNO_QUERY );
144 m_xAggInv.set( xIf, UNO_QUERY );
147 if ( xIf.is() )
151 Reference< XProxyFactory > xProxyFac = ProxyFactory::create( comphelper::getProcessComponentContext() );
152 m_xAggProxy = xProxyFac->createProxy( xIf );
154 catch(const Exception& )
156 SAL_WARN( "basic", "DocObjectWrapper::DocObjectWrapper: Caught exception!" );
160 if ( m_xAggProxy.is() )
162 osl_atomic_increment( &m_refCount );
164 /* i35609 - Fix crash on Solaris. The setDelegator call needs
165 to be in its own block to ensure that all temporary Reference
166 instances that are acquired during the call are released
167 before m_refCount is decremented again */
169 m_xAggProxy->setDelegator( static_cast< cppu::OWeakObject * >( this ) );
172 osl_atomic_decrement( &m_refCount );
178 void SAL_CALL
179 DocObjectWrapper::acquire() throw ()
181 osl_atomic_increment( &m_refCount );
182 SAL_INFO("basic","DocObjectWrapper::acquire("<< OUStringToOString( mName, RTL_TEXTENCODING_UTF8 ).getStr() << ") 0x" << this << " refcount is now " << m_refCount );
184 void SAL_CALL
185 DocObjectWrapper::release() throw ()
187 if ( osl_atomic_decrement( &m_refCount ) == 0 )
189 SAL_INFO("basic","DocObjectWrapper::release("<< OUStringToOString( mName, RTL_TEXTENCODING_UTF8 ).getStr() << ") 0x" << this << " refcount is now " << m_refCount );
190 delete this;
192 else
194 SAL_INFO("basic","DocObjectWrapper::release("<< OUStringToOString( mName, RTL_TEXTENCODING_UTF8 ).getStr() << ") 0x" << this << " refcount is now " << m_refCount );
198 DocObjectWrapper::~DocObjectWrapper()
202 Sequence< Type > SAL_CALL DocObjectWrapper::getTypes()
203 throw ( RuntimeException, std::exception )
205 if ( m_Types.getLength() == 0 )
207 Sequence< Type > sTypes;
208 if ( m_xAggregateTypeProv.is() )
210 sTypes = m_xAggregateTypeProv->getTypes();
212 m_Types.realloc( sTypes.getLength() + 1 );
213 Type* pPtr = m_Types.getArray();
214 for ( int i=0; i<m_Types.getLength(); ++i, ++pPtr )
216 if ( i == 0 )
218 *pPtr = cppu::UnoType<XInvocation>::get();
220 else
222 *pPtr = sTypes[ i - 1 ];
226 return m_Types;
229 Reference< XIntrospectionAccess > SAL_CALL
230 DocObjectWrapper::getIntrospection( ) throw (RuntimeException, std::exception)
232 return NULL;
235 Any SAL_CALL
236 DocObjectWrapper::invoke( const OUString& aFunctionName, const Sequence< Any >& aParams, Sequence< ::sal_Int16 >& aOutParamIndex, Sequence< Any >& aOutParam ) throw (IllegalArgumentException, CannotConvertException, InvocationTargetException, RuntimeException, std::exception)
238 if ( m_xAggInv.is() && m_xAggInv->hasMethod( aFunctionName ) )
239 return m_xAggInv->invoke( aFunctionName, aParams, aOutParamIndex, aOutParam );
240 SbMethodRef pMethod = getMethod( aFunctionName );
241 if ( !pMethod )
242 throw RuntimeException();
243 // check number of parameters
244 sal_Int32 nParamsCount = aParams.getLength();
245 SbxInfo* pInfo = pMethod->GetInfo();
246 if ( pInfo )
248 sal_Int32 nSbxOptional = 0;
249 sal_uInt16 n = 1;
250 for ( const SbxParamInfo* pParamInfo = pInfo->GetParam( n ); pParamInfo; pParamInfo = pInfo->GetParam( ++n ) )
252 if ( ( pParamInfo->nFlags & SBX_OPTIONAL ) != SBX_NONE )
253 ++nSbxOptional;
254 else
255 nSbxOptional = 0;
257 sal_Int32 nSbxCount = n - 1;
258 if ( nParamsCount < nSbxCount - nSbxOptional )
260 throw RuntimeException( "wrong number of parameters!" );
263 // set parameters
264 SbxArrayRef xSbxParams;
265 if ( nParamsCount > 0 )
267 xSbxParams = new SbxArray;
268 const Any* pParams = aParams.getConstArray();
269 for ( sal_Int32 i = 0; i < nParamsCount; ++i )
271 SbxVariableRef xSbxVar = new SbxVariable( SbxVARIANT );
272 unoToSbxValue( static_cast< SbxVariable* >( xSbxVar ), pParams[i] );
273 xSbxParams->Put( xSbxVar, static_cast< sal_uInt16 >( i ) + 1 );
275 // Enable passing by ref
276 if ( xSbxVar->GetType() != SbxVARIANT )
277 xSbxVar->SetFlag( SBX_FIXED );
280 if ( xSbxParams.Is() )
281 pMethod->SetParameters( xSbxParams );
283 // call method
284 SbxVariableRef xReturn = new SbxVariable;
286 pMethod->Call( xReturn );
287 Any aReturn;
288 // get output parameters
289 if ( xSbxParams.Is() )
291 SbxInfo* pInfo_ = pMethod->GetInfo();
292 if ( pInfo_ )
294 OutParamMap aOutParamMap;
295 for ( sal_uInt16 n = 1, nCount = xSbxParams->Count(); n < nCount; ++n )
297 const SbxParamInfo* pParamInfo = pInfo_->GetParam( n );
298 if ( pParamInfo && ( pParamInfo->eType & SbxBYREF ) != 0 )
300 SbxVariable* pVar = xSbxParams->Get( n );
301 if ( pVar )
303 SbxVariableRef xVar = pVar;
304 aOutParamMap.insert( OutParamMap::value_type( n - 1, sbxToUnoValue( xVar ) ) );
308 sal_Int32 nOutParamCount = aOutParamMap.size();
309 aOutParamIndex.realloc( nOutParamCount );
310 aOutParam.realloc( nOutParamCount );
311 sal_Int16* pOutParamIndex = aOutParamIndex.getArray();
312 Any* pOutParam = aOutParam.getArray();
313 for ( OutParamMap::iterator aIt = aOutParamMap.begin(); aIt != aOutParamMap.end(); ++aIt, ++pOutParamIndex, ++pOutParam )
315 *pOutParamIndex = aIt->first;
316 *pOutParam = aIt->second;
321 // get return value
322 aReturn = sbxToUnoValue( xReturn );
324 pMethod->SetParameters( NULL );
326 return aReturn;
329 void SAL_CALL
330 DocObjectWrapper::setValue( const OUString& aPropertyName, const Any& aValue ) throw (UnknownPropertyException, CannotConvertException, InvocationTargetException, RuntimeException, std::exception)
332 if ( m_xAggInv.is() && m_xAggInv->hasProperty( aPropertyName ) )
333 return m_xAggInv->setValue( aPropertyName, aValue );
335 SbPropertyRef pProperty = getProperty( aPropertyName );
336 if ( !pProperty.Is() )
337 throw UnknownPropertyException();
338 unoToSbxValue( (SbxVariable*) pProperty, aValue );
341 Any SAL_CALL
342 DocObjectWrapper::getValue( const OUString& aPropertyName ) throw (UnknownPropertyException, RuntimeException, std::exception)
344 if ( m_xAggInv.is() && m_xAggInv->hasProperty( aPropertyName ) )
345 return m_xAggInv->getValue( aPropertyName );
347 SbPropertyRef pProperty = getProperty( aPropertyName );
348 if ( !pProperty.Is() )
349 throw UnknownPropertyException();
351 SbxVariable* pProp = ( SbxVariable* ) pProperty;
352 if ( pProp->GetType() == SbxEMPTY )
353 pProperty->Broadcast( SBX_HINT_DATAWANTED );
355 Any aRet = sbxToUnoValue( pProp );
356 return aRet;
359 sal_Bool SAL_CALL
360 DocObjectWrapper::hasMethod( const OUString& aName ) throw (RuntimeException, std::exception)
362 if ( m_xAggInv.is() && m_xAggInv->hasMethod( aName ) )
363 return sal_True;
364 return getMethod( aName ).Is();
367 sal_Bool SAL_CALL
368 DocObjectWrapper::hasProperty( const OUString& aName ) throw (RuntimeException, std::exception)
370 bool bRes = false;
371 if ( m_xAggInv.is() && m_xAggInv->hasProperty( aName ) )
372 bRes = true;
373 else bRes = getProperty( aName ).Is();
374 return bRes;
377 Any SAL_CALL DocObjectWrapper::queryInterface( const Type& aType )
378 throw ( RuntimeException, std::exception )
380 Any aRet = DocObjectWrapper_BASE::queryInterface( aType );
381 if ( aRet.hasValue() )
382 return aRet;
383 else if ( m_xAggProxy.is() )
384 aRet = m_xAggProxy->queryAggregation( aType );
385 return aRet;
388 SbMethodRef DocObjectWrapper::getMethod( const OUString& aName ) throw (RuntimeException)
390 SbMethodRef pMethod = NULL;
391 if ( m_pMod )
393 SbxFlagBits nSaveFlgs = m_pMod->GetFlags();
394 // Limit search to this module
395 m_pMod->ResetFlag( SBX_GBLSEARCH );
396 pMethod = dynamic_cast<SbMethod*>(m_pMod->SbModule::Find(aName, SbxCLASS_METHOD));
397 m_pMod->SetFlags( nSaveFlgs );
400 return pMethod;
403 SbPropertyRef DocObjectWrapper::getProperty( const OUString& aName ) throw (RuntimeException)
405 SbPropertyRef pProperty = NULL;
406 if ( m_pMod )
408 SbxFlagBits nSaveFlgs = m_pMod->GetFlags();
409 // Limit search to this module.
410 m_pMod->ResetFlag( SBX_GBLSEARCH );
411 pProperty = dynamic_cast<SbProperty*>(m_pMod->SbModule::Find(aName, SbxCLASS_PROPERTY));
412 m_pMod->SetFlag( nSaveFlgs );
415 return pProperty;
418 TYPEINIT1(SbModule,SbxObject)
419 TYPEINIT1(SbMethod,SbxMethod)
420 TYPEINIT1(SbProperty,SbxProperty)
421 TYPEINIT1(SbProcedureProperty,SbxProperty)
422 TYPEINIT1(SbJScriptModule,SbModule)
423 TYPEINIT1(SbJScriptMethod,SbMethod)
424 TYPEINIT1(SbObjModule,SbModule)
425 TYPEINIT1(SbUserFormModule,SbObjModule)
427 uno::Reference< frame::XModel > getDocumentModel( StarBASIC* pb )
429 uno::Reference< frame::XModel > xModel;
430 if( pb && pb->IsDocBasic() )
432 uno::Any aDoc;
433 if( pb->GetUNOConstant( "ThisComponent", aDoc ) )
434 xModel.set( aDoc, uno::UNO_QUERY );
436 return xModel;
439 uno::Reference< vba::XVBACompatibility > getVBACompatibility( const uno::Reference< frame::XModel >& rxModel )
441 uno::Reference< vba::XVBACompatibility > xVBACompat;
444 uno::Reference< beans::XPropertySet > xModelProps( rxModel, uno::UNO_QUERY_THROW );
445 xVBACompat.set( xModelProps->getPropertyValue( "BasicLibraries" ), uno::UNO_QUERY );
447 catch(const uno::Exception& )
450 return xVBACompat;
453 bool getDefaultVBAMode( StarBASIC* pb )
455 uno::Reference< vba::XVBACompatibility > xVBACompat = getVBACompatibility( getDocumentModel( pb ) );
456 return xVBACompat.is() && xVBACompat->getVBACompatibilityMode();
459 class AsyncQuitHandler: private boost::noncopyable
461 AsyncQuitHandler() {}
463 public:
464 static AsyncQuitHandler& instance()
466 static AsyncQuitHandler dInst;
467 return dInst;
470 static void QuitApplication()
472 uno::Reference< frame::XDesktop2 > xDeskTop = frame::Desktop::create( comphelper::getProcessComponentContext() );
473 xDeskTop->terminate();
475 DECL_STATIC_LINK( AsyncQuitHandler, OnAsyncQuit, void* );
478 IMPL_STATIC_LINK_NOARG( AsyncQuitHandler, OnAsyncQuit )
480 QuitApplication();
481 return 0L;
484 // A Basic module has set EXTSEARCH, so that the elements, that the modul contains,
485 // could be found from other module.
487 SbModule::SbModule( const OUString& rName, bool bVBACompat )
488 : SbxObject( "StarBASICModule" ),
489 pImage( NULL ), pBreaks( NULL ), pClassData( NULL ), mbVBACompat( bVBACompat ), pDocObject( NULL ), bIsProxyModule( false )
491 SetName( rName );
492 SetFlag( SBX_EXTSEARCH | SBX_GBLSEARCH );
493 SetModuleType( script::ModuleType::NORMAL );
495 // #i92642: Set name property to intitial name
496 SbxVariable* pNameProp = pProps->Find( "Name", SbxCLASS_PROPERTY );
497 if( pNameProp != NULL )
499 pNameProp->PutString( GetName() );
503 SbModule::~SbModule()
505 SAL_INFO("basic","Module named " << OUStringToOString( GetName(), RTL_TEXTENCODING_UTF8 ).getStr() << " is destructing");
506 delete pImage;
507 delete pBreaks;
508 delete pClassData;
509 mxWrapper = NULL;
512 uno::Reference< script::XInvocation >
513 SbModule::GetUnoModule()
515 if ( !mxWrapper.is() )
516 mxWrapper = new DocObjectWrapper( this );
518 SAL_INFO("basic","Module named " << OUStringToOString( GetName(), RTL_TEXTENCODING_UTF8 ).getStr() << " returning wrapper mxWrapper (0x" << mxWrapper.get() <<")" );
519 return mxWrapper;
522 bool SbModule::IsCompiled() const
524 return pImage != 0;
527 const SbxObject* SbModule::FindType( const OUString& aTypeName ) const
529 return pImage ? pImage->FindType( aTypeName ) : NULL;
533 // From the code generator: deletion of images and the opposite of validation for entries
535 void SbModule::StartDefinitions()
537 delete pImage; pImage = NULL;
538 if( pClassData )
539 pClassData->clear();
541 // methods and properties persist, but they are invalid;
542 // at least are the information under certain conditions clogged
543 sal_uInt16 i;
544 for( i = 0; i < pMethods->Count(); i++ )
546 SbMethod* p = PTR_CAST(SbMethod,pMethods->Get( i ) );
547 if( p )
548 p->bInvalid = true;
550 for( i = 0; i < pProps->Count(); )
552 SbProperty* p = PTR_CAST(SbProperty,pProps->Get( i ) );
553 if( p )
554 pProps->Remove( i );
555 else
556 i++;
560 // request/create method
562 SbMethod* SbModule::GetMethod( const OUString& rName, SbxDataType t )
564 SbxVariable* p = pMethods->Find( rName, SbxCLASS_METHOD );
565 SbMethod* pMeth = p ? PTR_CAST(SbMethod,p) : NULL;
566 if( p && !pMeth )
568 pMethods->Remove( p );
570 if( !pMeth )
572 pMeth = new SbMethod( rName, t, this );
573 pMeth->SetParent( this );
574 pMeth->SetFlags( SBX_READ );
575 pMethods->Put( pMeth, pMethods->Count() );
576 StartListening( pMeth->GetBroadcaster(), true );
578 // The method is per default valid, because it could be
579 // created from the compiler (code generator) as well.
580 pMeth->bInvalid = false;
581 pMeth->ResetFlag( SBX_FIXED );
582 pMeth->SetFlag( SBX_WRITE );
583 pMeth->SetType( t );
584 pMeth->ResetFlag( SBX_WRITE );
585 if( t != SbxVARIANT )
587 pMeth->SetFlag( SBX_FIXED );
589 return pMeth;
592 // request/create property
594 SbProperty* SbModule::GetProperty( const OUString& rName, SbxDataType t )
596 SbxVariable* p = pProps->Find( rName, SbxCLASS_PROPERTY );
597 SbProperty* pProp = p ? PTR_CAST(SbProperty,p) : NULL;
598 if( p && !pProp )
600 pProps->Remove( p );
602 if( !pProp )
604 pProp = new SbProperty( rName, t, this );
605 pProp->SetFlag( SBX_READWRITE );
606 pProp->SetParent( this );
607 pProps->Put( pProp, pProps->Count() );
608 StartListening( pProp->GetBroadcaster(), true );
610 return pProp;
613 SbProcedureProperty* SbModule::GetProcedureProperty( const OUString& rName, SbxDataType t )
615 SbxVariable* p = pProps->Find( rName, SbxCLASS_PROPERTY );
616 SbProcedureProperty* pProp = p ? PTR_CAST(SbProcedureProperty,p) : NULL;
617 if( p && !pProp )
619 pProps->Remove( p );
621 if( !pProp )
623 pProp = new SbProcedureProperty( rName, t );
624 pProp->SetFlag( SBX_READWRITE );
625 pProp->SetParent( this );
626 pProps->Put( pProp, pProps->Count() );
627 StartListening( pProp->GetBroadcaster(), true );
629 return pProp;
632 SbIfaceMapperMethod* SbModule::GetIfaceMapperMethod( const OUString& rName, SbMethod* pImplMeth )
634 SbxVariable* p = pMethods->Find( rName, SbxCLASS_METHOD );
635 SbIfaceMapperMethod* pMapperMethod = p ? PTR_CAST(SbIfaceMapperMethod,p) : NULL;
636 if( p && !pMapperMethod )
638 pMethods->Remove( p );
640 if( !pMapperMethod )
642 pMapperMethod = new SbIfaceMapperMethod( rName, pImplMeth );
643 pMapperMethod->SetParent( this );
644 pMapperMethod->SetFlags( SBX_READ );
645 pMethods->Put( pMapperMethod, pMethods->Count() );
647 pMapperMethod->bInvalid = false;
648 return pMapperMethod;
651 SbIfaceMapperMethod::~SbIfaceMapperMethod()
655 TYPEINIT1(SbIfaceMapperMethod,SbMethod)
658 // From the code generator: remove invalid entries
660 void SbModule::EndDefinitions( bool bNewState )
662 for( sal_uInt16 i = 0; i < pMethods->Count(); )
664 SbMethod* p = PTR_CAST(SbMethod,pMethods->Get( i ) );
665 if( p )
667 if( p->bInvalid )
669 pMethods->Remove( p );
671 else
673 p->bInvalid = bNewState;
674 i++;
677 else
678 i++;
680 SetModified( true );
683 void SbModule::Clear()
685 delete pImage; pImage = NULL;
686 if( pClassData )
687 pClassData->clear();
688 SbxObject::Clear();
692 SbxVariable* SbModule::Find( const OUString& rName, SbxClassType t )
694 // make sure a search in an uninstatiated class module will fail
695 SbxVariable* pRes = SbxObject::Find( rName, t );
696 if ( bIsProxyModule && !GetSbData()->bRunInit )
698 return NULL;
700 if( !pRes && pImage )
702 SbiInstance* pInst = GetSbData()->pInst;
703 if( pInst && pInst->IsCompatibility() )
705 // Put enum types as objects into module,
706 // allows MyEnum.First notation
707 SbxArrayRef xArray = pImage->GetEnums();
708 if( xArray.Is() )
710 SbxVariable* pEnumVar = xArray->Find( rName, SbxCLASS_DONTCARE );
711 SbxObject* pEnumObject = PTR_CAST( SbxObject, pEnumVar );
712 if( pEnumObject )
714 bool bPrivate = pEnumObject->IsSet( SBX_PRIVATE );
715 OUString aEnumName = pEnumObject->GetName();
717 pRes = new SbxVariable( SbxOBJECT );
718 pRes->SetName( aEnumName );
719 pRes->SetParent( this );
720 pRes->SetFlag( SBX_READ );
721 if( bPrivate )
723 pRes->SetFlag( SBX_PRIVATE );
725 pRes->PutObject( pEnumObject );
730 return pRes;
734 const OUString& SbModule::GetSource() const
736 return aOUSource;
739 // Parent and BASIC are one!
741 void SbModule::SetParent( SbxObject* p )
743 pParent = p;
746 void SbModule::SFX_NOTIFY( SfxBroadcaster& rBC, const TypeId& rBCType,
747 const SfxHint& rHint, const TypeId& rHintType )
749 const SbxHint* pHint = dynamic_cast<const SbxHint*>(&rHint);
750 if( pHint )
752 SbxVariable* pVar = pHint->GetVar();
753 SbProperty* pProp = PTR_CAST(SbProperty,pVar);
754 SbMethod* pMeth = PTR_CAST(SbMethod,pVar);
755 SbProcedureProperty* pProcProperty = PTR_CAST( SbProcedureProperty, pVar );
756 if( pProcProperty )
759 if( pHint->GetId() == SBX_HINT_DATAWANTED )
761 OUString aProcName("Property Get ");
762 aProcName += pProcProperty->GetName();
764 SbxVariable* pMethVar = Find( aProcName, SbxCLASS_METHOD );
765 if( pMethVar )
767 SbxValues aVals;
768 aVals.eType = SbxVARIANT;
770 SbxArray* pArg = pVar->GetParameters();
771 sal_uInt16 nVarParCount = (pArg != NULL) ? pArg->Count() : 0;
772 if( nVarParCount > 1 )
774 SbxArrayRef xMethParameters = new SbxArray;
775 xMethParameters->Put( pMethVar, 0 ); // Method as parameter 0
776 for( sal_uInt16 i = 1 ; i < nVarParCount ; ++i )
778 SbxVariable* pPar = pArg->Get( i );
779 xMethParameters->Put( pPar, i );
782 pMethVar->SetParameters( xMethParameters );
783 pMethVar->Get( aVals );
784 pMethVar->SetParameters( NULL );
786 else
788 pMethVar->Get( aVals );
791 pVar->Put( aVals );
794 else if( pHint->GetId() == SBX_HINT_DATACHANGED )
796 SbxVariable* pMethVar = NULL;
798 bool bSet = pProcProperty->isSet();
799 if( bSet )
801 pProcProperty->setSet( false );
803 OUString aProcName("Property Set ");
804 aProcName += pProcProperty->GetName();
805 pMethVar = Find( aProcName, SbxCLASS_METHOD );
807 if( !pMethVar ) // Let
809 OUString aProcName("Property Let " );
810 aProcName += pProcProperty->GetName();
811 pMethVar = Find( aProcName, SbxCLASS_METHOD );
814 if( pMethVar )
816 // Setup parameters
817 SbxArrayRef xArray = new SbxArray;
818 xArray->Put( pMethVar, 0 ); // Method as parameter 0
819 xArray->Put( pVar, 1 );
820 pMethVar->SetParameters( xArray );
822 SbxValues aVals;
823 pMethVar->Get( aVals );
824 pMethVar->SetParameters( NULL );
828 if( pProp )
830 if( pProp->GetModule() != this )
831 SetError( SbxERR_BAD_ACTION );
833 else if( pMeth )
835 if( pHint->GetId() == SBX_HINT_DATAWANTED )
837 if( pMeth->bInvalid && !Compile() )
839 // auto compile has not worked!
840 StarBASIC::Error( SbERR_BAD_PROP_VALUE );
842 else
844 // Call of a subprogram
845 SbModule* pOld = GetSbData()->pMod;
846 GetSbData()->pMod = this;
847 Run( static_cast<SbMethod*>(pVar) );
848 GetSbData()->pMod = pOld;
852 else
854 // #i92642: Special handling for name property to avoid
855 // side effects when using name as variable implicitly
856 bool bForwardToSbxObject = true;
858 sal_uIntPtr nId = pHint->GetId();
859 if( (nId == SBX_HINT_DATAWANTED || nId == SBX_HINT_DATACHANGED) &&
860 pVar->GetName().equalsIgnoreAsciiCase( "name" ) )
862 bForwardToSbxObject = false;
864 if( bForwardToSbxObject )
866 SbxObject::SFX_NOTIFY( rBC, rBCType, rHint, rHintType );
872 // The setting of the source makes the image invalid
873 // and scans the method definitions newly in
875 void SbModule::SetSource32( const OUString& r )
877 // Default basic mode to library container mode, but.. allow Option VBASupport 0/1 override
878 SetVBACompat( getDefaultVBAMode( static_cast< StarBASIC*>( GetParent() ) ) );
879 aOUSource = r;
880 StartDefinitions();
881 SbiTokenizer aTok( r );
882 aTok.SetCompatible( IsVBACompat() );
884 while( !aTok.IsEof() )
886 SbiToken eEndTok = NIL;
888 // Searching for SUB or FUNCTION
889 SbiToken eLastTok = NIL;
890 while( !aTok.IsEof() )
892 // #32385: not by declare
893 SbiToken eCurTok = aTok.Next();
894 if( eLastTok != DECLARE )
896 if( eCurTok == SUB )
898 eEndTok = ENDSUB; break;
900 if( eCurTok == FUNCTION )
902 eEndTok = ENDFUNC; break;
904 if( eCurTok == PROPERTY )
906 eEndTok = ENDPROPERTY; break;
908 if( eCurTok == OPTION )
910 eCurTok = aTok.Next();
911 if( eCurTok == COMPATIBLE )
913 aTok.SetCompatible( true );
915 else if ( ( eCurTok == VBASUPPORT ) && ( aTok.Next() == NUMBER ) )
917 bool bIsVBA = ( aTok.GetDbl()== 1 );
918 SetVBACompat( bIsVBA );
919 aTok.SetCompatible( bIsVBA );
923 eLastTok = eCurTok;
925 // Definition of the method
926 SbMethod* pMeth = NULL;
927 if( eEndTok != NIL )
929 sal_uInt16 nLine1 = aTok.GetLine();
930 if( aTok.Next() == SYMBOL )
932 OUString aName_( aTok.GetSym() );
933 SbxDataType t = aTok.GetType();
934 if( t == SbxVARIANT && eEndTok == ENDSUB )
936 t = SbxVOID;
938 pMeth = GetMethod( aName_, t );
939 pMeth->nLine1 = pMeth->nLine2 = nLine1;
940 // The method is for a start VALID
941 pMeth->bInvalid = false;
943 else
945 eEndTok = NIL;
948 // Skip up to END SUB/END FUNCTION
949 if( eEndTok != NIL )
951 while( !aTok.IsEof() )
953 if( aTok.Next() == eEndTok )
955 pMeth->nLine2 = aTok.GetLine();
956 break;
959 if( aTok.IsEof() )
961 pMeth->nLine2 = aTok.GetLine();
965 EndDefinitions( true );
968 // Broadcast of a hint to all Basics
970 static void _SendHint( SbxObject* pObj, sal_uIntPtr nId, SbMethod* p )
972 // Self a BASIC?
973 if( pObj->IsA( TYPE(StarBASIC) ) && pObj->IsBroadcaster() )
974 pObj->GetBroadcaster().Broadcast( SbxHint( nId, p ) );
975 // Then ask for the subobjects
976 SbxArray* pObjs = pObj->GetObjects();
977 for( sal_uInt16 i = 0; i < pObjs->Count(); i++ )
979 SbxVariable* pVar = pObjs->Get( i );
980 if( pVar->IsA( TYPE(SbxObject) ) )
981 _SendHint( PTR_CAST(SbxObject,pVar), nId, p );
985 static void SendHint( SbxObject* pObj, sal_uIntPtr nId, SbMethod* p )
987 while( pObj->GetParent() )
988 pObj = pObj->GetParent();
989 _SendHint( pObj, nId, p );
992 // #57841 Clear Uno-Objects, which were helt in RTL functions,
993 // at the end of the program, so that nothing were helt.
994 void ClearUnoObjectsInRTL_Impl_Rek( StarBASIC* pBasic )
996 // delete the return value of CreateUnoService
997 SbxVariable* pVar = pBasic->GetRtl()->Find( OUString("CreateUnoService"), SbxCLASS_METHOD );
998 if( pVar )
1000 pVar->SbxValue::Clear();
1002 // delete the return value of CreateUnoDialog
1003 pVar = pBasic->GetRtl()->Find( OUString("CreateUnoDialog"), SbxCLASS_METHOD );
1004 if( pVar )
1006 pVar->SbxValue::Clear();
1008 // delete the return value of CDec
1009 pVar = pBasic->GetRtl()->Find( OUString("CDec"), SbxCLASS_METHOD );
1010 if( pVar )
1012 pVar->SbxValue::Clear();
1014 // delete return value of CreateObject
1015 pVar = pBasic->GetRtl()->Find( OUString("CreateObject"), SbxCLASS_METHOD );
1016 if( pVar )
1018 pVar->SbxValue::Clear();
1020 // Go over all Sub-Basics
1021 SbxArray* pObjs = pBasic->GetObjects();
1022 sal_uInt16 nCount = pObjs->Count();
1023 for( sal_uInt16 i = 0 ; i < nCount ; i++ )
1025 SbxVariable* pObjVar = pObjs->Get( i );
1026 StarBASIC* pSubBasic = PTR_CAST( StarBASIC, pObjVar );
1027 if( pSubBasic )
1029 ClearUnoObjectsInRTL_Impl_Rek( pSubBasic );
1034 void ClearUnoObjectsInRTL_Impl( StarBASIC* pBasic )
1036 // #67781 Delete return values of the Uno-methods
1037 clearUnoMethods();
1038 clearUnoServiceCtors();
1040 ClearUnoObjectsInRTL_Impl_Rek( pBasic );
1042 // Search for the topmost Basic
1043 SbxObject* p = pBasic;
1044 while( p->GetParent() )
1045 p = p->GetParent();
1046 if( static_cast<StarBASIC*>(p) != pBasic )
1047 ClearUnoObjectsInRTL_Impl_Rek( static_cast<StarBASIC*>(p) );
1051 void SbModule::SetVBACompat( bool bCompat )
1053 if( mbVBACompat != bCompat )
1055 mbVBACompat = bCompat;
1056 // initialize VBA document API
1057 if( mbVBACompat ) try
1059 StarBASIC* pBasic = static_cast< StarBASIC* >( GetParent() );
1060 uno::Reference< lang::XMultiServiceFactory > xFactory( getDocumentModel( pBasic ), uno::UNO_QUERY_THROW );
1061 xFactory->createInstance( "ooo.vba.VBAGlobals" );
1063 catch( Exception& )
1069 // Run a Basic-subprogram
1070 void SbModule::Run( SbMethod* pMeth )
1072 SAL_INFO("basic","About to run " << OUStringToOString( pMeth->GetName(), RTL_TEXTENCODING_UTF8 ).getStr() << ", vba compatmode is " << mbVBACompat );
1074 static sal_uInt16 nMaxCallLevel = 0;
1076 bool bDelInst = ( GetSbData()->pInst == NULL );
1077 bool bQuit = false;
1078 StarBASICRef xBasic;
1079 uno::Reference< frame::XModel > xModel;
1080 uno::Reference< script::vba::XVBACompatibility > xVBACompat;
1081 if( bDelInst )
1083 // #32779: Hold Basic during the execution
1084 xBasic = static_cast<StarBASIC*>( GetParent() );
1086 GetSbData()->pInst = new SbiInstance( static_cast<StarBASIC*>(GetParent()) );
1088 /* If a VBA script in a document is started, get the VBA compatibility
1089 interface from the document Basic library container, and notify all
1090 VBA script listeners about the started script. */
1091 if( mbVBACompat )
1093 StarBASIC* pBasic = static_cast< StarBASIC* >( GetParent() );
1094 if( pBasic && pBasic->IsDocBasic() ) try
1096 xModel.set( getDocumentModel( pBasic ), uno::UNO_SET_THROW );
1097 xVBACompat.set( getVBACompatibility( xModel ), uno::UNO_SET_THROW );
1098 xVBACompat->broadcastVBAScriptEvent( script::vba::VBAScriptEventId::SCRIPT_STARTED, GetName() );
1100 catch(const uno::Exception& )
1105 // Launcher problem
1106 // i80726 The Find below will genarate an error in Testtool so we reset it unless there was one before already
1107 bool bWasError = SbxBase::GetError() != 0;
1108 SbxVariable* pMSOMacroRuntimeLibVar = Find( "Launcher", SbxCLASS_OBJECT );
1109 if ( !bWasError && (SbxBase::GetError() == SbxERR_PROC_UNDEFINED) )
1110 SbxBase::ResetError();
1111 if( pMSOMacroRuntimeLibVar )
1113 StarBASIC* pMSOMacroRuntimeLib = PTR_CAST(StarBASIC,pMSOMacroRuntimeLibVar);
1114 if( pMSOMacroRuntimeLib )
1116 SbxFlagBits nGblFlag = pMSOMacroRuntimeLib->GetFlags() & SBX_GBLSEARCH;
1117 pMSOMacroRuntimeLib->ResetFlag( SBX_GBLSEARCH );
1118 SbxVariable* pAppSymbol = pMSOMacroRuntimeLib->Find( "Application", SbxCLASS_METHOD );
1119 pMSOMacroRuntimeLib->SetFlag( nGblFlag );
1120 if( pAppSymbol )
1122 pMSOMacroRuntimeLib->SetFlag( SBX_EXTSEARCH ); // Could have been disabled before
1123 GetSbData()->pMSOMacroRuntimLib = pMSOMacroRuntimeLib;
1128 if( nMaxCallLevel == 0 )
1130 #ifdef UNX
1131 struct rlimit rl;
1132 getrlimit ( RLIMIT_STACK, &rl );
1133 #endif
1134 #if defined LINUX
1135 // Empiric value, 900 = needed bytes/Basic call level
1136 // for Linux including 10% safety margin
1137 nMaxCallLevel = rl.rlim_cur / 900;
1138 #elif defined SOLARIS
1139 // Empiric value, 1650 = needed bytes/Basic call level
1140 // for Solaris including 10% safety margin
1141 nMaxCallLevel = rl.rlim_cur / 1650;
1142 #elif defined WIN32
1143 nMaxCallLevel = 5800;
1144 #else
1145 nMaxCallLevel = MAXRECURSION;
1146 #endif
1150 // Recursion to deep?
1151 if( ++GetSbData()->pInst->nCallLvl <= nMaxCallLevel )
1153 // Define a globale variable in all Mods
1154 GlobalRunInit( /* bBasicStart = */ bDelInst );
1156 // Appeared a compiler error? Then we don't launch
1157 if( !GetSbData()->bGlobalInitErr )
1159 if( bDelInst )
1161 SendHint( GetParent(), SBX_HINT_BASICSTART, pMeth );
1163 // 1996-10-16: #31460 New concept for StepInto/Over/Out
1164 // For an explanation see runtime.cxx at SbiInstance::CalcBreakCallLevel()
1165 // Identify the BreakCallLevel
1166 GetSbData()->pInst->CalcBreakCallLevel( pMeth->GetDebugFlags() );
1169 SbModule* pOldMod = GetSbData()->pMod;
1170 GetSbData()->pMod = this;
1171 SbiRuntime* pRt = new SbiRuntime( this, pMeth, pMeth->nStart );
1173 pRt->pNext = GetSbData()->pInst->pRun;
1174 if( pRt->pNext )
1175 pRt->pNext->block();
1176 GetSbData()->pInst->pRun = pRt;
1177 if ( mbVBACompat )
1179 GetSbData()->pInst->EnableCompatibility( true );
1182 while( pRt->Step() ) {}
1184 if( pRt->pNext )
1185 pRt->pNext->unblock();
1187 // #63710 It can happen by an another thread handling at events,
1188 // that the show call returns to an dialog (by closing the
1189 // dialog per UI), before a by an event triggered further call returned,
1190 // which stands in Basic more top in the stack and that had been run on
1191 // a Basic-Breakpoint. Then would the instance below destroyed. And if the Basic,
1192 // that stand still in the call, further runs, there is a GPF.
1193 // Thus here had to be wait until the other call comes back.
1194 if( bDelInst )
1196 // Compare here with 1 instead of 0, because before nCallLvl--
1197 while( GetSbData()->pInst->nCallLvl != 1 )
1198 Application::Yield();
1201 GetSbData()->pInst->pRun = pRt->pNext;
1202 GetSbData()->pInst->nCallLvl--; // Call-Level down again
1204 // Exist an higher-ranking runtime instance?
1205 // Then take over SbDEBUG_BREAK, if set
1206 SbiRuntime* pRtNext = pRt->pNext;
1207 if( pRtNext && (pRt->GetDebugFlags() & SbDEBUG_BREAK) )
1208 pRtNext->SetDebugFlags( SbDEBUG_BREAK );
1210 delete pRt;
1211 GetSbData()->pMod = pOldMod;
1212 if( bDelInst )
1214 // #57841 Clear Uno-Objects, which were helt in RTL functions,
1215 // at the end of the program, so that nothing were helt.
1216 ClearUnoObjectsInRTL_Impl( xBasic );
1218 clearNativeObjectWrapperVector();
1220 SAL_WARN_IF(GetSbData()->pInst->nCallLvl != 0,"basic","BASIC-Call-Level > 0");
1221 delete GetSbData()->pInst, GetSbData()->pInst = NULL, bDelInst = false;
1223 // #i30690
1224 SolarMutexGuard aSolarGuard;
1225 SendHint( GetParent(), SBX_HINT_BASICSTOP, pMeth );
1227 GlobalRunDeInit();
1229 if( xVBACompat.is() )
1231 // notify all VBA script listeners about the stopped script
1234 xVBACompat->broadcastVBAScriptEvent( script::vba::VBAScriptEventId::SCRIPT_STOPPED, GetName() );
1236 catch(const uno::Exception& )
1239 // VBA always ensures screenupdating is enabled after completing
1240 ::basic::vba::lockControllersOfAllDocuments( xModel, false );
1241 ::basic::vba::enableContainerWindowsOfAllDocuments( xModel, true );
1244 #ifdef DBG_TRACE_BASIC
1245 dbg_DeInitTrace();
1246 #endif
1249 else
1250 GetSbData()->pInst->nCallLvl--; // Call-Level down again
1252 else
1254 GetSbData()->pInst->nCallLvl--; // Call-Level down again
1255 StarBASIC::FatalError( SbERR_STACK_OVERFLOW );
1258 StarBASIC* pBasic = PTR_CAST(StarBASIC,GetParent());
1259 if( bDelInst )
1261 // #57841 Clear Uno-Objects, which were helt in RTL functions,
1262 // the end of the program, so that nothing were helt.
1263 ClearUnoObjectsInRTL_Impl( xBasic );
1265 delete GetSbData()->pInst;
1266 GetSbData()->pInst = NULL;
1268 if ( pBasic && pBasic->IsDocBasic() && pBasic->IsQuitApplication() && !GetSbData()->pInst )
1269 bQuit = true;
1270 if ( bQuit )
1272 Application::PostUserEvent( LINK( &AsyncQuitHandler::instance(), AsyncQuitHandler, OnAsyncQuit ), NULL );
1276 // Execute of the init method of a module after the loading
1277 // or the compilation
1279 void SbModule::RunInit()
1281 if( pImage
1282 && !pImage->bInit
1283 && pImage->IsFlag( SbiImageFlags::INITCODE ) )
1285 // Set flag, so that RunInit get activ (Testtool)
1286 GetSbData()->bRunInit = true;
1288 SbModule* pOldMod = GetSbData()->pMod;
1289 GetSbData()->pMod = this;
1290 // The init code starts always here
1291 SbiRuntime* pRt = new SbiRuntime( this, NULL, 0 );
1293 pRt->pNext = GetSbData()->pInst->pRun;
1294 GetSbData()->pInst->pRun = pRt;
1295 while( pRt->Step() ) {}
1297 GetSbData()->pInst->pRun = pRt->pNext;
1298 delete pRt;
1299 GetSbData()->pMod = pOldMod;
1300 pImage->bInit = true;
1301 pImage->bFirstInit = false;
1303 // RunInit is not activ anymore
1304 GetSbData()->bRunInit = false;
1308 // Delete with private/dim declared variables
1310 void SbModule::AddVarName( const OUString& aName )
1312 // see if the name is added already
1313 std::vector< OUString >::iterator it_end = mModuleVariableNames.end();
1314 for ( std::vector< OUString >::iterator it = mModuleVariableNames.begin(); it != it_end; ++it )
1316 if ( aName == *it )
1317 return;
1319 mModuleVariableNames.push_back( aName );
1322 void SbModule::RemoveVars()
1324 std::vector< OUString >::iterator it_end = mModuleVariableNames.end();
1325 for ( std::vector< OUString >::iterator it = mModuleVariableNames.begin(); it != it_end; ++it )
1327 // We don't want a Find being called in a derived class ( e.g.
1328 // SbUserform because it could trigger say an initialise event
1329 // which would cause basic to be re-run in the middle of the init ( and remember RemoveVars is called from compile and we don't want code to run as part of the compile )
1330 SbxVariableRef p = SbModule::Find( *it, SbxCLASS_PROPERTY );
1331 if( p.Is() )
1332 Remove (p);
1336 void SbModule::ClearPrivateVars()
1338 for( sal_uInt16 i = 0 ; i < pProps->Count() ; i++ )
1340 SbProperty* p = PTR_CAST(SbProperty,pProps->Get( i ) );
1341 if( p )
1343 // Delete not the arrays, only their content
1344 if( p->GetType() & SbxARRAY )
1346 SbxArray* pArray = PTR_CAST(SbxArray,p->GetObject());
1347 if( pArray )
1349 for( sal_uInt16 j = 0 ; j < pArray->Count() ; j++ )
1351 SbxVariable* pj = PTR_CAST(SbxVariable,pArray->Get( j ));
1352 pj->SbxValue::Clear();
1356 else
1358 p->SbxValue::Clear();
1364 void SbModule::implClearIfVarDependsOnDeletedBasic( SbxVariable* pVar, StarBASIC* pDeletedBasic )
1366 if( pVar->SbxValue::GetType() != SbxOBJECT || pVar->ISA( SbProcedureProperty ) )
1367 return;
1369 SbxObject* pObj = PTR_CAST(SbxObject,pVar->GetObject());
1370 if( pObj != NULL )
1372 SbxObject* p = pObj;
1374 SbModule* pMod = PTR_CAST( SbModule, p );
1375 if( pMod != NULL )
1376 pMod->ClearVarsDependingOnDeletedBasic( pDeletedBasic );
1378 while( (p = p->GetParent()) != NULL )
1380 StarBASIC* pBasic = PTR_CAST( StarBASIC, p );
1381 if( pBasic != NULL && pBasic == pDeletedBasic )
1383 pVar->SbxValue::Clear();
1384 break;
1390 void SbModule::ClearVarsDependingOnDeletedBasic( StarBASIC* pDeletedBasic )
1392 (void)pDeletedBasic;
1394 for( sal_uInt16 i = 0 ; i < pProps->Count() ; i++ )
1396 SbProperty* p = PTR_CAST(SbProperty,pProps->Get( i ) );
1397 if( p )
1399 if( p->GetType() & SbxARRAY )
1401 SbxArray* pArray = PTR_CAST(SbxArray,p->GetObject());
1402 if( pArray )
1404 for( sal_uInt16 j = 0 ; j < pArray->Count() ; j++ )
1406 SbxVariable* pVar = PTR_CAST(SbxVariable,pArray->Get( j ));
1407 implClearIfVarDependsOnDeletedBasic( pVar, pDeletedBasic );
1411 else
1413 implClearIfVarDependsOnDeletedBasic( p, pDeletedBasic );
1419 void StarBASIC::ClearAllModuleVars()
1421 // Initialise the own module
1422 for ( sal_uInt16 nMod = 0; nMod < pModules->Count(); nMod++ )
1424 SbModule* pModule = static_cast<SbModule*>(pModules->Get( nMod ));
1425 // Initialise only, if the startcode was already executed
1426 if( pModule->pImage && pModule->pImage->bInit && !pModule->isProxyModule() && !pModule->ISA(SbObjModule) )
1427 pModule->ClearPrivateVars();
1432 // Execution of the init-code of all module
1433 void SbModule::GlobalRunInit( bool bBasicStart )
1435 // If no Basic-Start, only initialise, if the module is not initialised
1436 if( !bBasicStart )
1437 if( !(pImage && !pImage->bInit) )
1438 return;
1440 // Initialise GlobalInitErr-Flag for Compiler-Error
1441 // With the help of this flags could be located in SbModule::Run() after the call of
1442 // GlobalRunInit, if at the intialising of the module
1443 // an error occurred. Then it will not be launched.
1444 GetSbData()->bGlobalInitErr = false;
1446 // Parent of the module is a Basic
1447 StarBASIC *pBasic = PTR_CAST(StarBASIC,GetParent());
1448 if( pBasic )
1450 pBasic->InitAllModules();
1452 SbxObject* pParent_ = pBasic->GetParent();
1453 if( pParent_ )
1455 StarBASIC * pParentBasic = PTR_CAST(StarBASIC,pParent_);
1456 if( pParentBasic )
1458 pParentBasic->InitAllModules( pBasic );
1460 // #109018 Parent can also have a parent (library in doc)
1461 SbxObject* pParentParent = pParentBasic->GetParent();
1462 if( pParentParent )
1464 StarBASIC * pParentParentBasic = PTR_CAST(StarBASIC,pParentParent);
1465 if( pParentParentBasic )
1466 pParentParentBasic->InitAllModules( pParentBasic );
1473 void SbModule::GlobalRunDeInit()
1475 StarBASIC *pBasic = PTR_CAST(StarBASIC,GetParent());
1476 if( pBasic )
1478 pBasic->DeInitAllModules();
1480 SbxObject* pParent_ = pBasic->GetParent();
1481 if( pParent_ )
1482 pBasic = PTR_CAST(StarBASIC,pParent_);
1483 if( pBasic )
1484 pBasic->DeInitAllModules();
1488 // Search for the next STMNT-Command in the code. This was used from the STMNT-
1489 // Opcode to set the endcolumn.
1491 const sal_uInt8* SbModule::FindNextStmnt( const sal_uInt8* p, sal_uInt16& nLine, sal_uInt16& nCol ) const
1493 return FindNextStmnt( p, nLine, nCol, false );
1496 const sal_uInt8* SbModule::FindNextStmnt( const sal_uInt8* p, sal_uInt16& nLine, sal_uInt16& nCol,
1497 bool bFollowJumps, const SbiImage* pImg ) const
1499 sal_uInt32 nPC = (sal_uInt32) ( p - reinterpret_cast<const sal_uInt8*>(pImage->GetCode()) );
1500 while( nPC < pImage->GetCodeSize() )
1502 SbiOpcode eOp = (SbiOpcode ) ( *p++ );
1503 nPC++;
1504 if( bFollowJumps && eOp == _JUMP && pImg )
1506 SAL_WARN_IF( !pImg, "basic", "FindNextStmnt: pImg==NULL with FollowJumps option" );
1507 sal_uInt32 nOp1 = *p++; nOp1 |= *p++ << 8;
1508 nOp1 |= *p++ << 16; nOp1 |= *p++ << 24;
1509 p = reinterpret_cast<const sal_uInt8*>(pImg->GetCode()) + nOp1;
1511 else if( eOp >= SbOP1_START && eOp <= SbOP1_END )
1512 p += 4, nPC += 4;
1513 else if( eOp == _STMNT )
1515 sal_uInt32 nl, nc;
1516 nl = *p++; nl |= *p++ << 8;
1517 nl |= *p++ << 16 ; nl |= *p++ << 24;
1518 nc = *p++; nc |= *p++ << 8;
1519 nc |= *p++ << 16 ; nc |= *p++ << 24;
1520 nLine = (sal_uInt16)nl; nCol = (sal_uInt16)nc;
1521 return p;
1523 else if( eOp >= SbOP2_START && eOp <= SbOP2_END )
1524 p += 8, nPC += 8;
1525 else if( !( eOp >= SbOP0_START && eOp <= SbOP0_END ) )
1527 StarBASIC::FatalError( SbERR_INTERNAL_ERROR );
1528 break;
1531 return NULL;
1534 // Test, if a line contains STMNT-Opcodes
1536 bool SbModule::IsBreakable( sal_uInt16 nLine ) const
1538 if( !pImage )
1539 return false;
1540 const sal_uInt8* p = reinterpret_cast<const sal_uInt8*>(pImage->GetCode());
1541 sal_uInt16 nl, nc;
1542 while( ( p = FindNextStmnt( p, nl, nc ) ) != NULL )
1543 if( nl == nLine )
1544 return true;
1545 return false;
1548 bool SbModule::IsBP( sal_uInt16 nLine ) const
1550 if( pBreaks )
1552 for( size_t i = 0; i < pBreaks->size(); i++ )
1554 sal_uInt16 b = pBreaks->operator[]( i );
1555 if( b == nLine )
1556 return true;
1557 if( b < nLine )
1558 break;
1561 return false;
1564 bool SbModule::SetBP( sal_uInt16 nLine )
1566 if( !IsBreakable( nLine ) )
1567 return false;
1568 if( !pBreaks )
1569 pBreaks = new SbiBreakpoints;
1570 size_t i;
1571 for( i = 0; i < pBreaks->size(); i++ )
1573 sal_uInt16 b = pBreaks->operator[]( i );
1574 if( b == nLine )
1575 return true;
1576 if( b < nLine )
1577 break;
1579 pBreaks->insert( pBreaks->begin() + i, nLine );
1581 // #38568: Set during runtime as well here SbDEBUG_BREAK
1582 if( GetSbData()->pInst && GetSbData()->pInst->pRun )
1583 GetSbData()->pInst->pRun->SetDebugFlags( SbDEBUG_BREAK );
1585 return IsBreakable( nLine );
1588 bool SbModule::ClearBP( sal_uInt16 nLine )
1590 bool bRes = false;
1591 if( pBreaks )
1593 for( size_t i = 0; i < pBreaks->size(); i++ )
1595 sal_uInt16 b = pBreaks->operator[]( i );
1596 if( b == nLine )
1598 pBreaks->erase( pBreaks->begin() + i );
1599 bRes = true;
1600 break;
1602 if( b < nLine )
1603 break;
1605 if( pBreaks->empty() )
1606 delete pBreaks, pBreaks = NULL;
1608 return bRes;
1611 void SbModule::ClearAllBP()
1613 delete pBreaks;
1614 pBreaks = NULL;
1617 void
1618 SbModule::fixUpMethodStart( bool bCvtToLegacy, SbiImage* pImg ) const
1620 if ( !pImg )
1621 pImg = pImage;
1622 for( sal_uInt32 i = 0; i < pMethods->Count(); i++ )
1624 SbMethod* pMeth = PTR_CAST(SbMethod,pMethods->Get( (sal_uInt16)i ) );
1625 if( pMeth )
1627 //fixup method start positions
1628 if ( bCvtToLegacy )
1629 pMeth->nStart = pImg->CalcLegacyOffset( pMeth->nStart );
1630 else
1631 pMeth->nStart = pImg->CalcNewOffset( (sal_uInt16)pMeth->nStart );
1637 bool SbModule::LoadData( SvStream& rStrm, sal_uInt16 nVer )
1639 Clear();
1640 if( !SbxObject::LoadData( rStrm, 1 ) )
1641 return false;
1642 // As a precaution...
1643 SetFlag( SBX_EXTSEARCH | SBX_GBLSEARCH );
1644 sal_uInt8 bImage;
1645 rStrm.ReadUChar( bImage );
1646 if( bImage )
1648 SbiImage* p = new SbiImage;
1649 sal_uInt32 nImgVer = 0;
1651 if( !p->Load( rStrm, nImgVer ) )
1653 delete p;
1654 return false;
1656 // If the image is in old format, we fix up the method start offsets
1657 if ( nImgVer < B_EXT_IMG_VERSION )
1659 fixUpMethodStart( false, p );
1660 p->ReleaseLegacyBuffer();
1662 aComment = p->aComment;
1663 SetName( p->aName );
1664 if( p->GetCodeSize() )
1666 aOUSource = p->aOUSource;
1667 // Old version: image away
1668 if( nVer == 1 )
1670 SetSource32( p->aOUSource );
1671 delete p;
1673 else
1674 pImage = p;
1676 else
1678 SetSource32( p->aOUSource );
1679 delete p;
1682 return true;
1685 bool SbModule::StoreData( SvStream& rStrm ) const
1687 bool bFixup = ( pImage && !pImage->ExceedsLegacyLimits() );
1688 if ( bFixup )
1689 fixUpMethodStart( true );
1690 bool bRet = SbxObject::StoreData( rStrm );
1691 if ( !bRet )
1692 return false;
1694 if( pImage )
1696 pImage->aOUSource = aOUSource;
1697 pImage->aComment = aComment;
1698 pImage->aName = GetName();
1699 rStrm.WriteUChar( 1 );
1700 // # PCode is saved only for legacy formats only
1701 // It should be noted that it probably isn't necessary
1702 // It would be better not to store the image ( more flexible with
1703 // formats )
1704 bool bRes = pImage->Save( rStrm, B_LEGACYVERSION );
1705 if ( bFixup )
1706 fixUpMethodStart( false ); // restore method starts
1707 return bRes;
1710 else
1712 SbiImage aImg;
1713 aImg.aOUSource = aOUSource;
1714 aImg.aComment = aComment;
1715 aImg.aName = GetName();
1716 rStrm.WriteUChar( 1 );
1717 return aImg.Save( rStrm );
1721 bool SbModule::ExceedsLegacyModuleSize()
1723 if ( !IsCompiled() )
1724 Compile();
1725 if ( pImage && pImage->ExceedsLegacyLimits() )
1726 return true;
1727 return false;
1730 class ErrorHdlResetter
1732 Link<StarBASIC*,bool> mErrHandler;
1733 bool mbError;
1734 public:
1735 ErrorHdlResetter() : mbError( false )
1737 // save error handler
1738 mErrHandler = StarBASIC::GetGlobalErrorHdl();
1739 // set new error handler
1740 StarBASIC::SetGlobalErrorHdl( LINK( this, ErrorHdlResetter, BasicErrorHdl ) );
1742 ~ErrorHdlResetter()
1744 // restore error handler
1745 StarBASIC::SetGlobalErrorHdl(mErrHandler);
1747 DECL_LINK_TYPED( BasicErrorHdl, StarBASIC *, bool );
1748 bool HasError() { return mbError; }
1751 IMPL_LINK_TYPED( ErrorHdlResetter, BasicErrorHdl, StarBASIC *, /*pBasic*/, bool)
1753 mbError = true;
1754 return false;
1757 void SbModule::GetCodeCompleteDataFromParse(CodeCompleteDataCache& aCache)
1759 ErrorHdlResetter aErrHdl;
1760 SbxBase::ResetError();
1762 boost::scoped_ptr<SbiParser> pParser(new SbiParser( static_cast<StarBASIC*>(GetParent()), this ));
1763 pParser->SetCodeCompleting(true);
1765 while( pParser->Parse() ) {}
1766 SbiSymPool* pPool = pParser->pPool;
1767 aCache.Clear();
1768 for( sal_uInt16 i = 0; i < pPool->GetSize(); ++i )
1770 SbiSymDef* pSymDef = pPool->Get(i);
1771 //std::cerr << "i: " << i << ", type: " << pSymDef->GetType() << "; name:" << pSymDef->GetName() << std::endl;
1772 if( (pSymDef->GetType() != SbxEMPTY) && (pSymDef->GetType() != SbxNULL) )
1773 aCache.InsertGlobalVar( pSymDef->GetName(), pParser->aGblStrings.Find(pSymDef->GetTypeId()) );
1775 SbiSymPool& pChildPool = pSymDef->GetPool();
1776 for(sal_uInt16 j = 0; j < pChildPool.GetSize(); ++j )
1778 SbiSymDef* pChildSymDef = pChildPool.Get(j);
1779 //std::cerr << "j: " << j << ", type: " << pChildSymDef->GetType() << "; name:" << pChildSymDef->GetName() << std::endl;
1780 if( (pChildSymDef->GetType() != SbxEMPTY) && (pChildSymDef->GetType() != SbxNULL) )
1781 aCache.InsertLocalVar( pSymDef->GetName(), pChildSymDef->GetName(), pParser->aGblStrings.Find(pChildSymDef->GetTypeId()) );
1787 OUString SbModule::GetKeywordCase( const OUString& sKeyword )
1789 return SbiParser::GetKeywordCase( sKeyword );
1792 bool SbModule::HasExeCode()
1794 // And empty Image always has the Global Chain set up
1795 static const unsigned char pEmptyImage[] = { 0x45, 0x0 , 0x0, 0x0, 0x0 };
1796 // lets be stricter for the moment than VBA
1798 if (!IsCompiled())
1800 ErrorHdlResetter aGblErrHdl;
1801 Compile();
1802 if (aGblErrHdl.HasError()) //assume unsafe on compile error
1803 return true;
1806 bool bRes = false;
1807 if (pImage && !(pImage->GetCodeSize() == 5 && (memcmp(pImage->GetCode(), pEmptyImage, pImage->GetCodeSize()) == 0 )))
1808 bRes = true;
1810 return bRes;
1813 // Store only image, no source
1814 bool SbModule::StoreBinaryData( SvStream& rStrm, sal_uInt16 nVer )
1816 bool bRet = Compile();
1817 if( bRet )
1819 bool bFixup = ( !nVer && !pImage->ExceedsLegacyLimits() );// save in old image format, fix up method starts
1821 if ( bFixup ) // save in old image format, fix up method starts
1822 fixUpMethodStart( true );
1823 bRet = SbxObject::StoreData( rStrm );
1824 if( bRet )
1826 (pImage->aOUSource).clear();
1827 pImage->aComment = aComment;
1828 pImage->aName = GetName();
1830 rStrm.WriteUChar( 1 );
1831 if ( nVer )
1832 bRet = pImage->Save( rStrm, B_EXT_IMG_VERSION );
1833 else
1834 bRet = pImage->Save( rStrm, B_LEGACYVERSION );
1835 if ( bFixup )
1836 fixUpMethodStart( false ); // restore method starts
1838 pImage->aOUSource = aOUSource;
1841 return bRet;
1844 // Called for >= OO 1.0 passwd protected libraries only
1846 bool SbModule::LoadBinaryData( SvStream& rStrm )
1848 OUString aKeepSource = aOUSource;
1849 bool bRet = LoadData( rStrm, 2 );
1850 LoadCompleted();
1851 aOUSource = aKeepSource;
1852 return bRet;
1855 bool SbModule::LoadCompleted()
1857 SbxArray* p = GetMethods();
1858 sal_uInt16 i;
1859 for( i = 0; i < p->Count(); i++ )
1861 SbMethod* q = PTR_CAST(SbMethod,p->Get( i ) );
1862 if( q )
1863 q->pMod = this;
1865 p = GetProperties();
1866 for( i = 0; i < p->Count(); i++ )
1868 SbProperty* q = PTR_CAST(SbProperty,p->Get( i ) );
1869 if( q )
1870 q->pMod = this;
1872 return true;
1875 void SbModule::handleProcedureProperties( SfxBroadcaster& rBC, const SfxHint& rHint )
1877 bool bDone = false;
1879 const SbxHint* pHint = dynamic_cast<const SbxHint*>(&rHint);
1880 if( pHint )
1882 SbxVariable* pVar = pHint->GetVar();
1883 SbProcedureProperty* pProcProperty = PTR_CAST( SbProcedureProperty, pVar );
1884 if( pProcProperty )
1886 bDone = true;
1888 if( pHint->GetId() == SBX_HINT_DATAWANTED )
1890 OUString aProcName("Property Get ");
1891 aProcName += pProcProperty->GetName();
1893 SbxVariable* pMeth = Find( aProcName, SbxCLASS_METHOD );
1894 if( pMeth )
1896 SbxValues aVals;
1897 aVals.eType = SbxVARIANT;
1899 SbxArray* pArg = pVar->GetParameters();
1900 sal_uInt16 nVarParCount = (pArg != NULL) ? pArg->Count() : 0;
1901 if( nVarParCount > 1 )
1903 SbxArrayRef xMethParameters = new SbxArray;
1904 xMethParameters->Put( pMeth, 0 ); // Method as parameter 0
1905 for( sal_uInt16 i = 1 ; i < nVarParCount ; ++i )
1907 SbxVariable* pPar = pArg->Get( i );
1908 xMethParameters->Put( pPar, i );
1911 pMeth->SetParameters( xMethParameters );
1912 pMeth->Get( aVals );
1913 pMeth->SetParameters( NULL );
1915 else
1917 pMeth->Get( aVals );
1920 pVar->Put( aVals );
1923 else if( pHint->GetId() == SBX_HINT_DATACHANGED )
1925 SbxVariable* pMeth = NULL;
1927 bool bSet = pProcProperty->isSet();
1928 if( bSet )
1930 pProcProperty->setSet( false );
1932 OUString aProcName("Property Set " );
1933 aProcName += pProcProperty->GetName();
1934 pMeth = Find( aProcName, SbxCLASS_METHOD );
1936 if( !pMeth ) // Let
1938 OUString aProcName("Property Let " );
1939 aProcName += pProcProperty->GetName();
1940 pMeth = Find( aProcName, SbxCLASS_METHOD );
1943 if( pMeth )
1945 // Setup parameters
1946 SbxArrayRef xArray = new SbxArray;
1947 xArray->Put( pMeth, 0 ); // Method as parameter 0
1948 xArray->Put( pVar, 1 );
1949 pMeth->SetParameters( xArray );
1951 SbxValues aVals;
1952 pMeth->Get( aVals );
1953 pMeth->SetParameters( NULL );
1959 if( !bDone )
1960 SbModule::Notify( rBC, rHint );
1964 // Implementation SbJScriptModule (Basic module for JavaScript source code)
1965 SbJScriptModule::SbJScriptModule( const OUString& rName )
1966 :SbModule( rName )
1970 bool SbJScriptModule::LoadData( SvStream& rStrm, sal_uInt16 nVer )
1972 (void)nVer;
1974 Clear();
1975 if( !SbxObject::LoadData( rStrm, 1 ) )
1976 return false;
1978 // Get the source string
1979 aOUSource = rStrm.ReadUniOrByteString( osl_getThreadTextEncoding() );
1980 return true;
1983 bool SbJScriptModule::StoreData( SvStream& rStrm ) const
1985 if( !SbxObject::StoreData( rStrm ) )
1986 return false;
1988 // Write the source string
1989 OUString aTmp = aOUSource;
1990 rStrm.WriteUniOrByteString( aTmp, osl_getThreadTextEncoding() );
1991 return true;
1997 SbMethod::SbMethod( const OUString& r, SbxDataType t, SbModule* p )
1998 : SbxMethod( r, t ), pMod( p )
2000 bInvalid = true;
2001 nStart =
2002 nDebugFlags =
2003 nLine1 =
2004 nLine2 = 0;
2005 refStatics = new SbxArray;
2006 mCaller = 0;
2007 // HACK due to 'Referenz could not be saved'
2008 SetFlag( SBX_NO_MODIFY );
2011 SbMethod::SbMethod( const SbMethod& r )
2012 : SvRefBase( r ), SbxMethod( r )
2014 pMod = r.pMod;
2015 bInvalid = r.bInvalid;
2016 nStart = r.nStart;
2017 nDebugFlags = r.nDebugFlags;
2018 nLine1 = r.nLine1;
2019 nLine2 = r.nLine2;
2020 refStatics = r.refStatics;
2021 mCaller = r.mCaller;
2022 SetFlag( SBX_NO_MODIFY );
2025 SbMethod::~SbMethod()
2029 void SbMethod::ClearStatics()
2031 refStatics = new SbxArray;
2034 SbxArray* SbMethod::GetStatics()
2036 return refStatics;
2039 bool SbMethod::LoadData( SvStream& rStrm, sal_uInt16 nVer )
2041 if( !SbxMethod::LoadData( rStrm, 1 ) )
2042 return false;
2044 sal_uInt16 nFlag;
2045 rStrm.ReadUInt16( nFlag );
2047 sal_Int16 nTempStart = (sal_Int16)nStart;
2049 if( nVer == 2 )
2051 rStrm.ReadUInt16( nLine1 ).ReadUInt16( nLine2 ).ReadInt16( nTempStart ).ReadCharAsBool( bInvalid );
2052 //tdf#94617
2053 if (nFlag & 0x8000)
2055 sal_uInt16 nMult = nFlag & 0x7FFF;
2056 sal_Int16 nMax = std::numeric_limits<sal_Int16>::max();
2057 nStart = nMult * nMax + nTempStart;
2059 else
2061 nStart = nTempStart;
2064 else
2066 nStart = nTempStart;
2069 // HACK ue to 'Referenz could not be saved'
2070 SetFlag( SBX_NO_MODIFY );
2072 return true;
2075 bool SbMethod::StoreData( SvStream& rStrm ) const
2077 if( !SbxMethod::StoreData( rStrm ) )
2078 return false;
2080 //tdf#94617
2081 sal_Int16 nMax = std::numeric_limits<sal_Int16>::max();
2082 sal_Int16 nStartTemp = nStart % nMax;
2083 sal_uInt16 nDebugFlagsTemp = nStart / nMax;
2084 nDebugFlagsTemp |= 0x8000;
2086 rStrm.WriteUInt16( nDebugFlagsTemp )
2087 .WriteInt16( nLine1 )
2088 .WriteInt16( nLine2 )
2089 .WriteInt16( nStartTemp )
2090 .WriteBool( bInvalid );
2092 return true;
2095 void SbMethod::GetLineRange( sal_uInt16& l1, sal_uInt16& l2 )
2097 l1 = nLine1; l2 = nLine2;
2100 // Could later be deleted
2102 SbxInfo* SbMethod::GetInfo()
2104 return pInfo;
2107 // Interface to execute a method of the applications
2108 // With special RefCounting, so that the Basic was not fired of by CloseDocument()
2109 // The return value will be delivered as string.
2110 ErrCode SbMethod::Call( SbxValue* pRet, SbxVariable* pCaller )
2112 if ( pCaller )
2114 SAL_INFO("basic", "SbMethod::Call Have been passed a caller 0x" << pCaller );
2115 mCaller = pCaller;
2117 // RefCount vom Modul hochzaehlen
2118 SbModule* pMod_ = static_cast<SbModule*>(GetParent());
2119 pMod_->AddFirstRef();
2121 // Increment the RefCount of the Basic
2122 StarBASIC* pBasic = static_cast<StarBASIC*>(pMod_->GetParent());
2123 pBasic->AddFirstRef();
2125 // Establish the values to get the return value
2126 SbxValues aVals;
2127 aVals.eType = SbxVARIANT;
2129 // #104083: Compile BEFORE get
2130 if( bInvalid && !pMod_->Compile() )
2131 StarBASIC::Error( SbERR_BAD_PROP_VALUE );
2133 Get( aVals );
2134 if ( pRet )
2135 pRet->Put( aVals );
2137 // Was there an error
2138 ErrCode nErr = SbxBase::GetError();
2139 SbxBase::ResetError();
2141 // Release objects
2142 pMod_->ReleaseRef();
2143 pBasic->ReleaseRef();
2144 mCaller = 0;
2145 return nErr;
2149 // #100883 Own Broadcast for SbMethod
2150 void SbMethod::Broadcast( sal_uIntPtr nHintId )
2152 if( pCst && !IsSet( SBX_NO_BROADCAST ) )
2154 // Because the method could be called from outside, test here once again
2155 // the authorisation
2156 if( nHintId & SBX_HINT_DATAWANTED )
2157 if( !CanRead() )
2158 return;
2159 if( nHintId & SBX_HINT_DATACHANGED )
2160 if( !CanWrite() )
2161 return;
2163 if( pMod && !pMod->IsCompiled() )
2164 pMod->Compile();
2166 // Block broadcasts while creating new method
2167 SfxBroadcaster* pSave = pCst;
2168 pCst = NULL;
2169 SbMethod* pThisCopy = new SbMethod( *this );
2170 SbMethodRef xHolder = pThisCopy;
2171 if( mpPar.Is() )
2173 // Enregister this as element 0, but don't reset the parent!
2174 if( GetType() != SbxVOID ) {
2175 mpPar->PutDirect( pThisCopy, 0 );
2177 SetParameters( NULL );
2180 pCst = pSave;
2181 pSave->Broadcast( SbxHint( nHintId, pThisCopy ) );
2183 SbxFlagBits nSaveFlags = GetFlags();
2184 SetFlag( SBX_READWRITE );
2185 pCst = NULL;
2186 Put( pThisCopy->GetValues_Impl() );
2187 pCst = pSave;
2188 SetFlags( nSaveFlags );
2193 // Implementation of SbJScriptMethod (method class as a wrapper for JavaScript-functions)
2195 SbJScriptMethod::SbJScriptMethod( const OUString& r, SbxDataType t, SbModule* p )
2196 : SbMethod( r, t, p )
2200 SbJScriptMethod::~SbJScriptMethod()
2204 SbObjModule::SbObjModule( const OUString& rName, const com::sun::star::script::ModuleInfo& mInfo, bool bIsVbaCompatible )
2205 : SbModule( rName, bIsVbaCompatible )
2207 SetModuleType( mInfo.ModuleType );
2208 if ( mInfo.ModuleType == script::ModuleType::FORM )
2210 SetClassName( "Form" );
2212 else if ( mInfo.ModuleObject.is() )
2214 SetUnoObject( uno::makeAny( mInfo.ModuleObject ) );
2218 SbObjModule::~SbObjModule()
2222 void
2223 SbObjModule::SetUnoObject( const uno::Any& aObj ) throw ( uno::RuntimeException )
2225 SbUnoObject* pUnoObj = PTR_CAST(SbUnoObject,(SbxVariable*)pDocObject);
2226 if ( pUnoObj && pUnoObj->getUnoAny() == aObj ) // object is equal, nothing to do
2227 return;
2228 pDocObject = new SbUnoObject( GetName(), aObj );
2230 com::sun::star::uno::Reference< com::sun::star::lang::XServiceInfo > xServiceInfo( aObj, com::sun::star::uno::UNO_QUERY_THROW );
2231 if( xServiceInfo->supportsService( "ooo.vba.excel.Worksheet" ) )
2233 SetClassName( "Worksheet" );
2235 else if( xServiceInfo->supportsService( "ooo.vba.excel.Workbook" ) )
2237 SetClassName( "Workbook" );
2241 SbxVariable*
2242 SbObjModule::GetObject()
2244 return pDocObject;
2246 SbxVariable*
2247 SbObjModule::Find( const OUString& rName, SbxClassType t )
2249 SbxVariable* pVar = NULL;
2250 if ( pDocObject)
2251 pVar = pDocObject->Find( rName, t );
2252 if ( !pVar )
2253 pVar = SbModule::Find( rName, t );
2254 return pVar;
2257 void SbObjModule::SFX_NOTIFY( SfxBroadcaster& rBC, const TypeId& rBCType,
2258 const SfxHint& rHint, const TypeId& rHintType )
2260 SbModule::handleProcedureProperties( rBC, rHint );
2264 typedef ::cppu::WeakImplHelper3<
2265 awt::XTopWindowListener,
2266 awt::XWindowListener,
2267 document::XDocumentEventListener > FormObjEventListener_BASE;
2269 class FormObjEventListenerImpl:
2270 public FormObjEventListener_BASE, private boost::noncopyable
2272 SbUserFormModule* mpUserForm;
2273 uno::Reference< lang::XComponent > mxComponent;
2274 uno::Reference< frame::XModel > mxModel;
2275 bool mbDisposed;
2276 bool mbOpened;
2277 bool mbActivated;
2278 bool mbShowing;
2280 public:
2281 FormObjEventListenerImpl( SbUserFormModule* pUserForm, const uno::Reference< lang::XComponent >& xComponent, const uno::Reference< frame::XModel >& xModel ) :
2282 mpUserForm( pUserForm ), mxComponent( xComponent), mxModel( xModel ),
2283 mbDisposed( false ), mbOpened( false ), mbActivated( false ), mbShowing( false )
2285 if ( mxComponent.is() )
2287 SAL_INFO("basic", "*********** Registering the listeners");
2290 uno::Reference< awt::XTopWindow >( mxComponent, uno::UNO_QUERY_THROW )->addTopWindowListener( this );
2292 catch(const uno::Exception& ) {}
2295 uno::Reference< awt::XWindow >( mxComponent, uno::UNO_QUERY_THROW )->addWindowListener( this );
2297 catch(const uno::Exception& ) {}
2300 if ( mxModel.is() )
2304 uno::Reference< document::XDocumentEventBroadcaster >( mxModel, uno::UNO_QUERY_THROW )->addDocumentEventListener( this );
2306 catch(const uno::Exception& ) {}
2310 virtual ~FormObjEventListenerImpl()
2312 removeListener();
2315 bool isShowing() const { return mbShowing; }
2317 void removeListener()
2319 if ( mxComponent.is() && !mbDisposed )
2321 SAL_INFO("basic", "*********** Removing the listeners");
2324 uno::Reference< awt::XTopWindow >( mxComponent, uno::UNO_QUERY_THROW )->removeTopWindowListener( this );
2326 catch(const uno::Exception& ) {}
2329 uno::Reference< awt::XWindow >( mxComponent, uno::UNO_QUERY_THROW )->removeWindowListener( this );
2331 catch(const uno::Exception& ) {}
2333 mxComponent.clear();
2335 if ( mxModel.is() && !mbDisposed )
2339 uno::Reference< document::XDocumentEventBroadcaster >( mxModel, uno::UNO_QUERY_THROW )->removeDocumentEventListener( this );
2341 catch(const uno::Exception& ) {}
2343 mxModel.clear();
2346 virtual void SAL_CALL windowOpened( const lang::EventObject& /*e*/ ) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE
2348 if ( mpUserForm )
2350 mbOpened = true;
2351 mbShowing = true;
2352 if ( mbActivated )
2354 mbOpened = mbActivated = false;
2355 mpUserForm->triggerActivateEvent();
2361 virtual void SAL_CALL windowClosing( const lang::EventObject& /*e*/ ) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE
2363 #ifdef IN_THE_FUTURE
2364 uno::Reference< awt::XDialog > xDialog( e.Source, uno::UNO_QUERY );
2365 if ( xDialog.is() )
2367 uno::Reference< awt::XControl > xControl( xDialog, uno::UNO_QUERY );
2368 if ( xControl->getPeer().is() )
2370 uno::Reference< document::XVbaMethodParameter > xVbaMethodParameter( xControl->getPeer(), uno::UNO_QUERY );
2371 if ( xVbaMethodParameter.is() )
2373 sal_Int8 nCancel = 0;
2374 sal_Int8 nCloseMode = ::ooo::vba::VbQueryClose::vbFormControlMenu;
2376 Sequence< Any > aParams;
2377 aParams.realloc(2);
2378 aParams[0] <<= nCancel;
2379 aParams[1] <<= nCloseMode;
2381 mpUserForm->triggerMethod( "Userform_QueryClose", aParams);
2382 return;
2388 mpUserForm->triggerMethod( "Userform_QueryClose" );
2389 #endif
2393 virtual void SAL_CALL windowClosed( const lang::EventObject& /*e*/ ) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE
2395 mbOpened = false;
2396 mbShowing = false;
2399 virtual void SAL_CALL windowMinimized( const lang::EventObject& /*e*/ ) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE
2403 virtual void SAL_CALL windowNormalized( const lang::EventObject& /*e*/ ) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE
2407 virtual void SAL_CALL windowActivated( const lang::EventObject& /*e*/ ) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE
2409 if ( mpUserForm )
2411 mbActivated = true;
2412 if ( mbOpened )
2414 mbOpened = mbActivated = false;
2415 mpUserForm->triggerActivateEvent();
2420 virtual void SAL_CALL windowDeactivated( const lang::EventObject& /*e*/ ) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE
2422 if ( mpUserForm )
2423 mpUserForm->triggerDeactivateEvent();
2426 virtual void SAL_CALL windowResized( const awt::WindowEvent& /*e*/ ) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE
2428 if ( mpUserForm )
2430 mpUserForm->triggerResizeEvent();
2431 mpUserForm->triggerLayoutEvent();
2435 virtual void SAL_CALL windowMoved( const awt::WindowEvent& /*e*/ ) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE
2437 if ( mpUserForm )
2438 mpUserForm->triggerLayoutEvent();
2441 virtual void SAL_CALL windowShown( const lang::EventObject& /*e*/ ) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE
2445 virtual void SAL_CALL windowHidden( const lang::EventObject& /*e*/ ) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE
2449 virtual void SAL_CALL documentEventOccured( const document::DocumentEvent& rEvent ) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE
2451 // early dosposing on document event "OnUnload", to be sure Basic still exists when calling VBA "UserForm_Terminate"
2452 if( rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::CLOSEDOC ) )
2454 removeListener();
2455 mbDisposed = true;
2456 if ( mpUserForm )
2457 mpUserForm->ResetApiObj(); // will trigger "UserForm_Terminate"
2461 virtual void SAL_CALL disposing( const lang::EventObject& /*Source*/ ) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE
2463 SAL_INFO("basic", "** Userform/Dialog disposing");
2464 removeListener();
2465 mbDisposed = true;
2466 if ( mpUserForm )
2467 mpUserForm->ResetApiObj( false ); // pass false (too late to trigger VBA events here)
2471 SbUserFormModule::SbUserFormModule( const OUString& rName, const com::sun::star::script::ModuleInfo& mInfo, bool bIsCompat )
2472 : SbObjModule( rName, mInfo, bIsCompat )
2473 , m_mInfo( mInfo )
2474 , mbInit( false )
2476 m_xModel.set( mInfo.ModuleObject, uno::UNO_QUERY_THROW );
2479 SbUserFormModule::~SbUserFormModule()
2483 void SbUserFormModule::ResetApiObj( bool bTriggerTerminateEvent )
2485 SAL_INFO("basic", " SbUserFormModule::ResetApiObj( " << (bTriggerTerminateEvent ? "true )" : "false )") );
2486 if ( bTriggerTerminateEvent && m_xDialog.is() ) // probably someone close the dialog window
2488 triggerTerminateEvent();
2490 pDocObject = NULL;
2491 m_xDialog = NULL;
2494 void SbUserFormModule::triggerMethod( const OUString& aMethodToRun )
2496 Sequence< Any > aArguments;
2497 triggerMethod( aMethodToRun, aArguments );
2500 void SbUserFormModule::triggerMethod( const OUString& aMethodToRun, Sequence< Any >& aArguments )
2502 SAL_INFO("basic", "*** trigger " << OUStringToOString( aMethodToRun, RTL_TEXTENCODING_UTF8 ).getStr() << " ***");
2503 // Search method
2504 SbxVariable* pMeth = SbObjModule::Find( aMethodToRun, SbxCLASS_METHOD );
2505 if( pMeth )
2507 if ( aArguments.getLength() > 0 ) // Setup parameters
2509 SbxArrayRef xArray = new SbxArray;
2510 xArray->Put( pMeth, 0 ); // Method as parameter 0
2512 for ( sal_Int32 i = 0; i < aArguments.getLength(); ++i )
2514 SbxVariableRef xSbxVar = new SbxVariable( SbxVARIANT );
2515 unoToSbxValue( static_cast< SbxVariable* >( xSbxVar ), aArguments[i] );
2516 xArray->Put( xSbxVar, static_cast< sal_uInt16 >( i ) + 1 );
2518 // Enable passing by ref
2519 if ( xSbxVar->GetType() != SbxVARIANT )
2520 xSbxVar->SetFlag( SBX_FIXED );
2522 pMeth->SetParameters( xArray );
2524 SbxValues aVals;
2525 pMeth->Get( aVals );
2527 for ( sal_Int32 i = 0; i < aArguments.getLength(); ++i )
2529 aArguments[i] = sbxToUnoValue( xArray->Get( static_cast< sal_uInt16 >(i) + 1) );
2531 pMeth->SetParameters( NULL );
2533 else
2535 SbxValues aVals;
2536 pMeth->Get( aVals );
2541 void SbUserFormModule::triggerActivateEvent()
2543 SAL_INFO("basic", "**** entering SbUserFormModule::triggerActivate");
2544 triggerMethod( "UserForm_Activate" );
2545 SAL_INFO("basic", "**** leaving SbUserFormModule::triggerActivate");
2548 void SbUserFormModule::triggerDeactivateEvent()
2550 SAL_INFO("basic", "**** SbUserFormModule::triggerDeactivate");
2551 triggerMethod( "Userform_Deactivate" );
2554 void SbUserFormModule::triggerInitializeEvent()
2556 if ( mbInit )
2557 return;
2558 SAL_INFO("basic", "**** SbUserFormModule::triggerInitializeEvent");
2559 triggerMethod(OUString("Userform_Initialize"));
2560 mbInit = true;
2563 void SbUserFormModule::triggerTerminateEvent()
2565 SAL_INFO("basic", "**** SbUserFormModule::triggerTerminateEvent");
2566 triggerMethod(OUString( "Userform_Terminate" ));
2567 mbInit=false;
2570 void SbUserFormModule::triggerLayoutEvent()
2572 triggerMethod(OUString( "Userform_Layout" ));
2575 void SbUserFormModule::triggerResizeEvent()
2577 triggerMethod(OUString("Userform_Resize"));
2580 SbUserFormModuleInstance* SbUserFormModule::CreateInstance()
2582 SbUserFormModuleInstance* pInstance = new SbUserFormModuleInstance( this, GetName(), m_mInfo, IsVBACompat() );
2583 return pInstance;
2586 SbUserFormModuleInstance::SbUserFormModuleInstance( SbUserFormModule* pParentModule,
2587 const OUString& rName, const com::sun::star::script::ModuleInfo& mInfo, bool bIsVBACompat )
2588 : SbUserFormModule( rName, mInfo, bIsVBACompat )
2589 , m_pParentModule( pParentModule )
2593 bool SbUserFormModuleInstance::IsClass( const OUString& rName ) const
2595 bool bParentNameMatches = m_pParentModule->GetName().equalsIgnoreAsciiCase( rName );
2596 bool bRet = bParentNameMatches || SbxObject::IsClass( rName );
2597 return bRet;
2600 SbxVariable* SbUserFormModuleInstance::Find( const OUString& rName, SbxClassType t )
2602 SbxVariable* pVar = m_pParentModule->Find( rName, t );
2603 return pVar;
2607 void SbUserFormModule::Load()
2609 SAL_INFO("basic", "** load() ");
2610 // forces a load
2611 if ( !pDocObject )
2612 InitObject();
2616 void SbUserFormModule::Unload()
2618 SAL_INFO("basic", "** Unload() ");
2620 sal_Int8 nCancel = 0;
2621 sal_Int8 nCloseMode = ::ooo::vba::VbQueryClose::vbFormCode;
2623 Sequence< Any > aParams;
2624 aParams.realloc(2);
2625 aParams[0] <<= nCancel;
2626 aParams[1] <<= nCloseMode;
2628 triggerMethod( "Userform_QueryClose", aParams);
2630 aParams[0] >>= nCancel;
2631 // basic boolean ( and what the user might use ) can be ambiguous ( e.g. basic true = -1 )
2632 // test against 0 ( false ) and assume anything else is true
2633 // ( Note: ) this used to work ( something changes somewhere )
2634 if (nCancel != 0)
2636 return;
2639 if ( m_xDialog.is() )
2641 triggerTerminateEvent();
2643 // Search method
2644 SbxVariable* pMeth = SbObjModule::Find( "UnloadObject", SbxCLASS_METHOD );
2645 if( pMeth )
2647 SAL_INFO("basic", "Attempting too run the UnloadObjectMethod");
2648 m_xDialog.clear(); //release ref to the uno object
2649 SbxValues aVals;
2650 bool bWaitForDispose = true; // assume dialog is showing
2651 if ( m_DialogListener.get() )
2653 bWaitForDispose = m_DialogListener->isShowing();
2654 SAL_INFO("basic", "Showing " << bWaitForDispose );
2656 pMeth->Get( aVals);
2657 if ( !bWaitForDispose )
2659 // we've either already got a dispose or we'er never going to get one
2660 ResetApiObj();
2661 } // else wait for dispose
2662 SAL_INFO("basic", "UnloadObject completed ( we hope )");
2667 void SbUserFormModule::InitObject()
2671 OUString aHook("VBAGlobals");
2672 SbUnoObject* pGlobs = static_cast<SbUnoObject*>(GetParent()->Find( aHook, SbxCLASS_DONTCARE ));
2673 if ( m_xModel.is() && pGlobs )
2675 // broadcast INITIALIZE_USERFORM script event before the dialog is created
2676 Reference< script::vba::XVBACompatibility > xVBACompat( getVBACompatibility( m_xModel ), uno::UNO_SET_THROW );
2677 xVBACompat->broadcastVBAScriptEvent( script::vba::VBAScriptEventId::INITIALIZE_USERFORM, GetName() );
2678 uno::Reference< lang::XMultiServiceFactory > xVBAFactory( pGlobs->getUnoAny(), uno::UNO_QUERY_THROW );
2679 uno::Reference< uno::XComponentContext > xContext = comphelper::getProcessComponentContext();
2680 OUString sDialogUrl( "vnd.sun.star.script:" );
2681 OUString sProjectName( "Standard" );
2685 Reference< beans::XPropertySet > xProps( m_xModel, UNO_QUERY_THROW );
2686 uno::Reference< script::vba::XVBACompatibility > xVBAMode( xProps->getPropertyValue( "BasicLibraries" ), uno::UNO_QUERY_THROW );
2687 sProjectName = xVBAMode->getProjectName();
2689 catch(const Exception& ) {}
2691 sDialogUrl = sDialogUrl + sProjectName + "." + GetName() + "?location=document";
2693 uno::Reference< awt::XDialogProvider > xProvider = awt::DialogProvider::createWithModel( xContext, m_xModel );
2694 m_xDialog = xProvider->createDialog( sDialogUrl );
2696 // create vba api object
2697 uno::Sequence< uno::Any > aArgs(4);
2698 aArgs[ 0 ] = uno::Any();
2699 aArgs[ 1 ] <<= m_xDialog;
2700 aArgs[ 2 ] <<= m_xModel;
2701 aArgs[ 3 ] <<= OUString( GetParent()->GetName() );
2702 pDocObject = new SbUnoObject( GetName(), uno::makeAny( xVBAFactory->createInstanceWithArguments( "ooo.vba.msforms.UserForm", aArgs ) ) );
2704 uno::Reference< lang::XComponent > xComponent( m_xDialog, uno::UNO_QUERY_THROW );
2706 // the dialog must be disposed at the end!
2707 StarBASIC* pParentBasic = NULL;
2708 SbxObject* pCurObject = this;
2711 SbxObject* pObjParent = pCurObject->GetParent();
2712 pParentBasic = PTR_CAST( StarBASIC, pObjParent );
2713 pCurObject = pObjParent;
2715 while( pParentBasic == NULL && pCurObject != NULL );
2717 SAL_WARN_IF( pParentBasic == NULL, "basic", "pParentBasic == NULL" );
2718 registerComponentToBeDisposedForBasic( xComponent, pParentBasic );
2720 // if old listener object exists, remove it from dialog and document model
2721 if( m_DialogListener.is() )
2722 m_DialogListener->removeListener();
2723 m_DialogListener.set( new FormObjEventListenerImpl( this, xComponent, m_xModel ) );
2725 triggerInitializeEvent();
2728 catch(const uno::Exception& )
2734 SbxVariable*
2735 SbUserFormModule::Find( const OUString& rName, SbxClassType t )
2737 if ( !pDocObject && !GetSbData()->bRunInit && GetSbData()->pInst )
2738 InitObject();
2739 return SbObjModule::Find( rName, t );
2742 SbProperty::SbProperty( const OUString& r, SbxDataType t, SbModule* p )
2743 : SbxProperty( r, t ), pMod( p )
2745 bInvalid = false;
2748 SbProperty::~SbProperty()
2752 SbProcedureProperty::~SbProcedureProperty()
2755 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */