Branch libreoffice-5-0-4
[LibreOffice.git] / sfx2 / source / appl / macroloader.cxx
blob226f2faeb9e06031060c4c4fbb883e68ca0c71c7
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 .
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;
58 m_xFrame = 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";
79 return aSeq;
82 SfxObjectShell* SfxMacroLoader::GetObjectShell_Impl()
84 SfxObjectShell* pDocShell = NULL;
85 Reference < XFrame > xFrame( m_xFrame.get(), UNO_QUERY );
86 if ( xFrame.is() )
88 SfxFrame* pFrame=0;
89 for ( pFrame = SfxFrame::GetFirst(); pFrame; pFrame = SfxFrame::GetNext( *pFrame ) )
91 if ( pFrame->GetFrameInterface() == xFrame )
92 break;
95 if ( pFrame )
96 pDocShell = pFrame->GetCurrentDocument();
99 return pDocShell;
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:"))
110 xDispatcher = this;
111 return xDispatcher;
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 );
125 return lDispatcher;
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;
136 uno::Any aAny;
137 ErrCode nErr = loadMacro( aURL.Complete, aAny, GetObjectShell_Impl() );
138 if( xListener.is() )
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;
147 else
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)
158 uno::Any aRet;
159 loadMacro( aURL.Complete, aRet, GetObjectShell_Impl() );
160 return aRet;
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;
169 uno::Any aAny;
170 loadMacro( aURL.Complete, aAny, GetObjectShell_Impl() );
173 void SAL_CALL SfxMacroLoader::addStatusListener(
174 const uno::Reference< frame::XStatusListener >& ,
175 const util::URL& )
176 throw (uno::RuntimeException, std::exception)
178 /* TODO
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 >&,
187 const util::URL& )
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
196 (void) rURL;
197 (void) rRetval;
198 (void) pSh;
199 return ERRCODE_BASIC_PROC_UNDEFINED;
200 #else
201 SfxObjectShell* pCurrent = pSh;
202 if ( !pCurrent )
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 ) )
219 // find BasicManager
220 SfxObjectShell* pDoc = NULL;
221 OUString aBasMgrName( INetURLObject::decode(aMacro.copy( 8, nHashPos-8 ), INetURLObject::DECODE_WITH_CHARSET) );
222 if ( aBasMgrName.isEmpty() )
223 pBasMgr = pAppMgr;
224 else if ( aBasMgrName == "." )
226 // current/actual document
227 pDoc = pCurrent;
228 if (pDoc)
229 pBasMgr = pDoc->GetBasicManager();
231 else
233 // full qualified name, find document by name
234 for ( SfxObjectShell *pObjSh = SfxObjectShell::GetFirst();
235 pObjSh && !pBasMgr;
236 pObjSh = SfxObjectShell::GetNext(*pObjSh) )
237 if ( aBasMgrName == pObjSh->GetTitle(SFX_TITLE_APINAME) )
239 pDoc = pObjSh;
240 pBasMgr = pDoc->GetBasicManager();
244 if ( pBasMgr )
246 const bool bIsAppBasic = ( pBasMgr == pAppMgr );
247 const bool bIsDocBasic = ( pBasMgr != pAppMgr );
249 if ( pDoc )
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;
257 // find BASIC method
258 OUString aQualifiedMethod( INetURLObject::decode(aMacro.copy( nHashPos+1 ), INetURLObject::DECODE_WITH_CHARSET) );
259 OUString aArgs;
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;
290 if ( bIsDocBasic )
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 );
311 else
312 nErr = ERRCODE_BASIC_PROC_UNDEFINED;
314 else
315 nErr = ERRCODE_IO_NOTEXISTS;
317 else
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));
323 aCall.append(']');
324 pAppMgr->GetLib(0)->Execute(aCall.makeStringAndClear());
325 nErr = SbxBase::GetError();
328 SbxBase::ResetError();
329 return nErr;
330 #endif
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: */