xref: /trunk/main/scripting/source/basprov/basscript.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_scripting.hxx"
26 #include "basscript.hxx"
27 #include <vos/mutex.hxx>
28 #include <vcl/svapp.hxx>
29 #include <basic/sbx.hxx>
30 #include <basic/sbstar.hxx>
31 #include <basic/sbmod.hxx>
32 #include <basic/sbmeth.hxx>
33 #include <basic/basmgr.hxx>
34 #include <com/sun/star/script/provider/ScriptFrameworkErrorType.hpp>
35 
36 #include <map>
37 
38 
39 using namespace ::com::sun::star;
40 using namespace ::com::sun::star::lang;
41 using namespace ::com::sun::star::uno;
42 using namespace ::com::sun::star::script;
43 using namespace ::com::sun::star::document;
44 
45 extern ::com::sun::star::uno::Any sbxToUnoValue( SbxVariable* pVar );
46 extern void unoToSbxValue( SbxVariable* pVar, const ::com::sun::star::uno::Any& aValue );
47 
48 
49 //.........................................................................
50 namespace basprov
51 {
52 //.........................................................................
53 
54     typedef ::std::map< sal_Int16, Any, ::std::less< sal_Int16 > > OutParamMap;
55 
56     // =============================================================================
57     // BasicScriptImpl
58     // =============================================================================
59 
60     // -----------------------------------------------------------------------------
61 
BasicScriptImpl(const::rtl::OUString & funcName,SbMethodRef xMethod)62     BasicScriptImpl::BasicScriptImpl( const ::rtl::OUString& funcName, SbMethodRef xMethod )
63         :m_xMethod( xMethod )
64         ,m_funcName( funcName )
65         ,m_documentBasicManager( NULL )
66         ,m_xDocumentScriptContext()
67     {
68     }
69 
70     // -----------------------------------------------------------------------------
71 
BasicScriptImpl(const::rtl::OUString & funcName,SbMethodRef xMethod,BasicManager & documentBasicManager,const Reference<XScriptInvocationContext> & documentScriptContext)72     BasicScriptImpl::BasicScriptImpl( const ::rtl::OUString& funcName, SbMethodRef xMethod,
73         BasicManager& documentBasicManager, const Reference< XScriptInvocationContext >& documentScriptContext )
74         :m_xMethod( xMethod )
75         ,m_funcName( funcName )
76         ,m_documentBasicManager( &documentBasicManager )
77         ,m_xDocumentScriptContext( documentScriptContext )
78     {
79         StartListening( *m_documentBasicManager );
80     }
81 
82     // -----------------------------------------------------------------------------
~BasicScriptImpl()83     BasicScriptImpl::~BasicScriptImpl()
84     {
85         if ( m_documentBasicManager )
86             EndListening( *m_documentBasicManager );
87     }
88 
89     // -----------------------------------------------------------------------------
90     // SfxListener
91     // -----------------------------------------------------------------------------
Notify(SfxBroadcaster & rBC,const SfxHint & rHint)92     void BasicScriptImpl::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
93     {
94         if ( &rBC != m_documentBasicManager )
95         {
96             OSL_ENSURE( false, "BasicScriptImpl::Notify: where does this come from?" );
97             // not interested in
98             return;
99         }
100         const SfxSimpleHint* pSimpleHint = PTR_CAST( SfxSimpleHint, &rHint );
101         if ( pSimpleHint && ( pSimpleHint->GetId() == SFX_HINT_DYING ) )
102         {
103             m_documentBasicManager = NULL;
104             EndListening( rBC );    // prevent multiple notifications
105         }
106     }
107 
108     // -----------------------------------------------------------------------------
109     // XScript
110     // -----------------------------------------------------------------------------
111 
invoke(const Sequence<Any> & aParams,Sequence<sal_Int16> & aOutParamIndex,Sequence<Any> & aOutParam)112     Any BasicScriptImpl::invoke( const Sequence< Any >& aParams, Sequence< sal_Int16 >& aOutParamIndex, Sequence< Any >& aOutParam )
113     {
114         // TODO: throw CannotConvertException
115         // TODO: check length of aOutParamIndex, aOutParam
116 
117         ::vos::OGuard aGuard( Application::GetSolarMutex() );
118 
119         Any aReturn;
120 
121         if ( m_xMethod )
122         {
123             // check if compiled
124             SbModule* pModule = static_cast< SbModule* >( m_xMethod->GetParent() );
125             if ( pModule && !pModule->IsCompiled() )
126                 pModule->Compile();
127 
128             // check number of parameters
129             sal_Int32 nParamsCount = aParams.getLength();
130             SbxInfo* pInfo = m_xMethod->GetInfo();
131             if ( pInfo )
132             {
133                 sal_Int32 nSbxOptional = 0;
134                 sal_uInt16 n = 1;
135                 for ( const SbxParamInfo* pParamInfo = pInfo->GetParam( n ); pParamInfo; pParamInfo = pInfo->GetParam( ++n ) )
136                 {
137                     if ( ( pParamInfo->nFlags & SBX_OPTIONAL ) != 0 )
138                         ++nSbxOptional;
139                     else
140                         nSbxOptional = 0;
141                 }
142                 sal_Int32 nSbxCount = n - 1;
143                 if ( nParamsCount < nSbxCount - nSbxOptional )
144                 {
145                     throw provider::ScriptFrameworkErrorException(
146                         ::rtl::OUString(
147                             RTL_CONSTASCII_USTRINGPARAM(
148                                 "wrong number of parameters!" ) ),
149                          Reference< XInterface >(),
150                          m_funcName,
151                          ::rtl::OUString(
152                              RTL_CONSTASCII_USTRINGPARAM( "Basic" ) ),
153                         provider::ScriptFrameworkErrorType::NO_SUCH_SCRIPT  );
154                 }
155             }
156 
157             // set parameters
158             SbxArrayRef xSbxParams;
159             if ( nParamsCount > 0 )
160             {
161                 xSbxParams = new SbxArray;
162                 const Any* pParams = aParams.getConstArray();
163                 for ( sal_Int32 i = 0; i < nParamsCount; ++i )
164                 {
165                     SbxVariableRef xSbxVar = new SbxVariable( SbxVARIANT );
166                     unoToSbxValue( static_cast< SbxVariable* >( xSbxVar ), pParams[i] );
167                     xSbxParams->Put( xSbxVar, static_cast< sal_uInt16 >( i ) + 1 );
168 
169                     // Enable passing by ref
170                     if ( xSbxVar->GetType() != SbxVARIANT )
171                         xSbxVar->SetFlag( SBX_FIXED );
172                  }
173             }
174             if ( xSbxParams.Is() )
175                 m_xMethod->SetParameters( xSbxParams );
176 
177             // call method
178             SbxVariableRef xReturn = new SbxVariable;
179             ErrCode nErr = SbxERR_OK;
180             {
181                 // if it's a document-based script, temporarily reset ThisComponent to the script invocation context
182                 Any aOldThisComponent;
183                 if ( m_documentBasicManager && m_xDocumentScriptContext.is() )
184                     aOldThisComponent = m_documentBasicManager->SetGlobalUNOConstant( "ThisComponent", makeAny( m_xDocumentScriptContext ) );
185 
186                 nErr = m_xMethod->Call( xReturn );
187 
188                 if ( m_documentBasicManager && m_xDocumentScriptContext.is() )
189                     m_documentBasicManager->SetGlobalUNOConstant( "ThisComponent", aOldThisComponent );
190             }
191             if ( nErr != SbxERR_OK )
192             {
193                 // TODO: throw InvocationTargetException ?
194             }
195 
196             // get output parameters
197             if ( xSbxParams.Is() )
198             {
199                 SbxInfo* pInfo_ = m_xMethod->GetInfo();
200                 if ( pInfo_ )
201                 {
202                     OutParamMap aOutParamMap;
203                     for ( sal_uInt16 n = 1, nCount = xSbxParams->Count(); n < nCount; ++n )
204                     {
205                         const SbxParamInfo* pParamInfo = pInfo_->GetParam( n );
206                         if ( pParamInfo && ( pParamInfo->eType & SbxBYREF ) != 0 )
207                         {
208                             SbxVariable* pVar = xSbxParams->Get( n );
209                             if ( pVar )
210                             {
211                                 SbxVariableRef xVar = pVar;
212                                 aOutParamMap.insert( OutParamMap::value_type( n - 1, sbxToUnoValue( xVar ) ) );
213                             }
214                         }
215                     }
216                     sal_Int32 nOutParamCount = aOutParamMap.size();
217                     aOutParamIndex.realloc( nOutParamCount );
218                     aOutParam.realloc( nOutParamCount );
219                     sal_Int16* pOutParamIndex = aOutParamIndex.getArray();
220                     Any* pOutParam = aOutParam.getArray();
221                     for ( OutParamMap::iterator aIt = aOutParamMap.begin(); aIt != aOutParamMap.end(); ++aIt, ++pOutParamIndex, ++pOutParam )
222                     {
223                         *pOutParamIndex = aIt->first;
224                         *pOutParam = aIt->second;
225                     }
226                 }
227             }
228 
229             // get return value
230             aReturn = sbxToUnoValue( xReturn );
231 
232             // reset parameters
233             m_xMethod->SetParameters( NULL );
234         }
235 
236         return aReturn;
237     }
238 
239     // -----------------------------------------------------------------------------
240 
241 //.........................................................................
242 }   // namespace basprov
243 //.........................................................................
244