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 <macroloader.hxx>
24 #include <com/sun/star/document/UpdateDocMode.hpp>
25 #include <com/sun/star/document/MacroExecMode.hpp>
26 #include <com/sun/star/frame/DispatchResultState.hpp>
27 #include <basic/basmgr.hxx>
28 #include <basic/sbuno.hxx>
29 #include <cppuhelper/implbase5.hxx>
30 #include <cppuhelper/supportsservice.hxx>
31 #include <framework/documentundoguard.hxx>
32 #include <rtl/ref.hxx>
33 #include <sfx2/app.hxx>
34 #include <sfx2/docfile.hxx>
35 #include <sfx2/frame.hxx>
36 #include <sfx2/objsh.hxx>
37 #include <sfx2/request.hxx>
38 #include <sfx2/sfxsids.hrc>
39 #include <svl/intitem.hxx>
40 #include <tools/urlobj.hxx>
41 #include <vcl/svapp.hxx>
43 #include <boost/scoped_ptr.hpp>
45 using namespace ::com::sun::star
;
46 using namespace ::com::sun::star::frame
;
47 using namespace ::com::sun::star::lang
;
48 using namespace ::com::sun::star::uno
;
49 using namespace ::com::sun::star::util
;
51 SfxMacroLoader::SfxMacroLoader(const css::uno::Sequence
< css::uno::Any
>& aArguments
)
52 throw (css::uno::Exception
, css::uno::RuntimeException
)
54 Reference
< XFrame
> xFrame
;
55 if ( aArguments
.getLength() )
57 aArguments
[0] >>= xFrame
;
62 OUString SAL_CALL
SfxMacroLoader::getImplementationName()
63 throw (css::uno::RuntimeException
, std::exception
)
65 return OUString("com.sun.star.comp.sfx2.SfxMacroLoader");
68 sal_Bool SAL_CALL
SfxMacroLoader::supportsService(OUString
const & ServiceName
)
69 throw (css::uno::RuntimeException
, std::exception
)
71 return cppu::supportsService(this, ServiceName
);
74 css::uno::Sequence
<OUString
> SAL_CALL
SfxMacroLoader::getSupportedServiceNames()
75 throw (css::uno::RuntimeException
, std::exception
)
77 css::uno::Sequence
< OUString
> aSeq(1);
78 aSeq
[0] = "com.sun.star.frame.ProtocolHandler";
82 SfxObjectShell
* SfxMacroLoader::GetObjectShell_Impl()
84 SfxObjectShell
* pDocShell
= NULL
;
85 Reference
< XFrame
> xFrame( m_xFrame
.get(), UNO_QUERY
);
89 for ( pFrame
= SfxFrame::GetFirst(); pFrame
; pFrame
= SfxFrame::GetNext( *pFrame
) )
91 if ( pFrame
->GetFrameInterface() == xFrame
)
96 pDocShell
= pFrame
->GetCurrentDocument();
103 uno::Reference
<frame::XDispatch
> SAL_CALL
SfxMacroLoader::queryDispatch(
104 const util::URL
& aURL
,
105 const OUString
& /*sTargetFrameName*/,
106 sal_Int32
/*nSearchFlags*/ ) throw( uno::RuntimeException
, std::exception
)
108 uno::Reference
<frame::XDispatch
> xDispatcher
;
109 if(aURL
.Complete
.startsWith("macro:"))
115 uno::Sequence
< uno::Reference
<frame::XDispatch
> > SAL_CALL
116 SfxMacroLoader::queryDispatches( const uno::Sequence
< frame::DispatchDescriptor
>& seqDescriptor
)
117 throw( uno::RuntimeException
, std::exception
)
119 sal_Int32 nCount
= seqDescriptor
.getLength();
120 uno::Sequence
< uno::Reference
<frame::XDispatch
> > lDispatcher(nCount
);
121 for( sal_Int32 i
=0; i
<nCount
; ++i
)
122 lDispatcher
[i
] = this->queryDispatch( seqDescriptor
[i
].FeatureURL
,
123 seqDescriptor
[i
].FrameName
,
124 seqDescriptor
[i
].SearchFlags
);
129 void SAL_CALL
SfxMacroLoader::dispatchWithNotification(
130 const util::URL
& aURL
, const uno::Sequence
<beans::PropertyValue
>& /*lArgs*/,
131 const uno::Reference
<frame::XDispatchResultListener
>& xListener
)
132 throw (uno::RuntimeException
, std::exception
)
134 SolarMutexGuard aGuard
;
137 ErrCode nErr
= loadMacro( aURL
.Complete
, aAny
, GetObjectShell_Impl() );
140 // always call dispatchFinished(), because we didn't load a document but
141 // executed a macro instead!
142 frame::DispatchResultEvent aEvent
;
144 aEvent
.Source
= static_cast< ::cppu::OWeakObject
* >(this);
145 if( nErr
== ERRCODE_NONE
)
146 aEvent
.State
= frame::DispatchResultState::SUCCESS
;
148 aEvent
.State
= frame::DispatchResultState::FAILURE
;
150 xListener
->dispatchFinished( aEvent
) ;
154 uno::Any SAL_CALL
SfxMacroLoader::dispatchWithReturnValue(
155 const util::URL
& aURL
, const uno::Sequence
<beans::PropertyValue
>& )
156 throw (uno::RuntimeException
, std::exception
)
159 loadMacro( aURL
.Complete
, aRet
, GetObjectShell_Impl() );
163 void SAL_CALL
SfxMacroLoader::dispatch(
164 const util::URL
& aURL
, const uno::Sequence
<beans::PropertyValue
>& /*lArgs*/ )
165 throw (uno::RuntimeException
, std::exception
)
167 SolarMutexGuard aGuard
;
170 loadMacro( aURL
.Complete
, aAny
, GetObjectShell_Impl() );
173 void SAL_CALL
SfxMacroLoader::addStatusListener(
174 const uno::Reference
< frame::XStatusListener
>& ,
176 throw (uno::RuntimeException
, std::exception
)
179 How we can handle different listener for further coming or currently running dispatch() jobs
180 without any inconsistency!
185 void SAL_CALL
SfxMacroLoader::removeStatusListener(
186 const uno::Reference
< frame::XStatusListener
>&,
188 throw (uno::RuntimeException
, std::exception
)
192 ErrCode
SfxMacroLoader::loadMacro( const OUString
& rURL
, com::sun::star::uno::Any
& rRetval
, SfxObjectShell
* pSh
)
193 throw ( ucb::ContentCreationException
, uno::RuntimeException
)
195 #if !HAVE_FEATURE_SCRIPTING
199 return ERRCODE_BASIC_PROC_UNDEFINED
;
201 SfxObjectShell
* pCurrent
= pSh
;
203 // all not full qualified names use the BASIC of the given or current document
204 pCurrent
= SfxObjectShell::Current();
206 // 'macro:///lib.mod.proc(args)' => macro of App-BASIC
207 // 'macro://[docname|.]/lib.mod.proc(args)' => macro of current or qualified document
208 // 'macro://obj.method(args)' => direct API call, execute it via App-BASIC
209 OUString
aMacro( rURL
);
210 sal_Int32 nHashPos
= aMacro
.indexOf( '/', 8 );
211 sal_Int32 nArgsPos
= aMacro
.indexOf( '(' );
212 BasicManager
*pAppMgr
= SfxApplication::GetBasicManager();
213 BasicManager
*pBasMgr
= 0;
214 ErrCode nErr
= ERRCODE_NONE
;
216 // should a macro function be executed ( no direct API call)?
217 if ( -1 != nHashPos
&& ( -1 == nArgsPos
|| nHashPos
< nArgsPos
) )
220 SfxObjectShell
* pDoc
= NULL
;
221 OUString
aBasMgrName( INetURLObject::decode(aMacro
.copy( 8, nHashPos
-8 ), INetURLObject::DECODE_WITH_CHARSET
) );
222 if ( aBasMgrName
.isEmpty() )
224 else if ( aBasMgrName
== "." )
226 // current/actual document
229 pBasMgr
= pDoc
->GetBasicManager();
233 // full qualified name, find document by name
234 for ( SfxObjectShell
*pObjSh
= SfxObjectShell::GetFirst();
236 pObjSh
= SfxObjectShell::GetNext(*pObjSh
) )
237 if ( aBasMgrName
== pObjSh
->GetTitle(SFX_TITLE_APINAME
) )
240 pBasMgr
= pDoc
->GetBasicManager();
246 const bool bIsAppBasic
= ( pBasMgr
== pAppMgr
);
247 const bool bIsDocBasic
= ( pBasMgr
!= pAppMgr
);
251 // security check for macros from document basic if an SFX doc is given
252 if ( !pDoc
->AdjustMacroMode( OUString() ) )
253 // check forbids execution
254 return ERRCODE_IO_ACCESSDENIED
;
258 OUString
aQualifiedMethod( INetURLObject::decode(aMacro
.copy( nHashPos
+1 ), INetURLObject::DECODE_WITH_CHARSET
) );
260 if ( -1 != nArgsPos
)
262 // remove arguments from macro name
263 aArgs
= aQualifiedMethod
.copy( nArgsPos
- nHashPos
- 1 );
264 aQualifiedMethod
= aQualifiedMethod
.copy( 0, nArgsPos
- nHashPos
- 1 );
267 if ( pBasMgr
->HasMacro( aQualifiedMethod
) )
269 Any aOldThisComponent
;
270 const bool bSetDocMacroMode
= ( pDoc
!= NULL
) && bIsDocBasic
;
271 const bool bSetGlobalThisComponent
= ( pDoc
!= NULL
) && bIsAppBasic
;
272 if ( bSetDocMacroMode
)
274 // mark document: it executes an own macro, so it's in a modal mode
275 pDoc
->SetMacroMode_Impl( true );
278 if ( bSetGlobalThisComponent
)
280 // document is executed via AppBASIC, adjust ThisComponent variable
281 aOldThisComponent
= pAppMgr
->SetGlobalUNOConstant( "ThisComponent", makeAny( pDoc
->GetModel() ) );
284 // just to let the shell be alive
285 SfxObjectShellRef xKeepDocAlive
= pDoc
;
288 // attempt to protect the document against the script tampering with its Undo Context
289 boost::scoped_ptr
< ::framework::DocumentUndoGuard
> pUndoGuard
;
291 pUndoGuard
.reset( new ::framework::DocumentUndoGuard( pDoc
->GetModel() ) );
293 // execute the method
294 SbxVariableRef retValRef
= new SbxVariable
;
295 nErr
= pBasMgr
->ExecuteMacro( aQualifiedMethod
, aArgs
, retValRef
);
296 if ( nErr
== ERRCODE_NONE
)
297 rRetval
= sbxToUnoValue( retValRef
);
300 if ( bSetGlobalThisComponent
)
302 pAppMgr
->SetGlobalUNOConstant( "ThisComponent", aOldThisComponent
);
305 if ( bSetDocMacroMode
)
307 // remove flag for modal mode
308 pDoc
->SetMacroMode_Impl( false );
312 nErr
= ERRCODE_BASIC_PROC_UNDEFINED
;
315 nErr
= ERRCODE_IO_NOTEXISTS
;
319 // direct API call on a specified object
320 OUStringBuffer aCall
;
321 aCall
.append('[').append(INetURLObject::decode(aMacro
.copy(6),
322 INetURLObject::DECODE_WITH_CHARSET
));
324 pAppMgr
->GetLib(0)->Execute(aCall
.makeStringAndClear());
325 nErr
= SbxBase::GetError();
328 SbxBase::ResetError();
333 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
* SAL_CALL
334 com_sun_star_comp_sfx2_SfxMacroLoader_get_implementation(
335 css::uno::XComponentContext
*,
336 css::uno::Sequence
<css::uno::Any
> const &arguments
)
338 return cppu::acquire(new SfxMacroLoader(arguments
));
341 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */