Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include <macroloader.hxx>
21 :
22 : #include <com/sun/star/document/UpdateDocMode.hpp>
23 : #include <com/sun/star/document/MacroExecMode.hpp>
24 : #include <com/sun/star/frame/DispatchResultState.hpp>
25 : #include <basic/basmgr.hxx>
26 : #include <basic/sbuno.hxx>
27 : #include <cppuhelper/implbase5.hxx>
28 : #include <cppuhelper/supportsservice.hxx>
29 : #include <framework/documentundoguard.hxx>
30 : #include <rtl/ref.hxx>
31 : #include <sfx2/app.hxx>
32 : #include <sfx2/docfile.hxx>
33 : #include <sfx2/frame.hxx>
34 : #include <sfx2/objsh.hxx>
35 : #include <sfx2/request.hxx>
36 : #include <sfx2/sfxsids.hrc>
37 : #include <svl/intitem.hxx>
38 : #include <tools/urlobj.hxx>
39 : #include <vcl/svapp.hxx>
40 :
41 : #include <boost/scoped_ptr.hpp>
42 :
43 : using namespace ::com::sun::star;
44 : using namespace ::com::sun::star::frame;
45 : using namespace ::com::sun::star::lang;
46 : using namespace ::com::sun::star::uno;
47 : using namespace ::com::sun::star::util;
48 :
49 0 : SfxMacroLoader::SfxMacroLoader(const css::uno::Sequence< css::uno::Any >& aArguments)
50 0 : throw (css::uno::Exception, css::uno::RuntimeException)
51 : {
52 0 : Reference < XFrame > xFrame;
53 0 : if ( aArguments.getLength() )
54 : {
55 0 : aArguments[0] >>= xFrame;
56 0 : m_xFrame = xFrame;
57 0 : }
58 0 : }
59 :
60 0 : OUString SAL_CALL SfxMacroLoader::getImplementationName()
61 : throw (css::uno::RuntimeException, std::exception)
62 : {
63 0 : return OUString("com.sun.star.comp.sfx2.SfxMacroLoader");
64 : }
65 :
66 0 : sal_Bool SAL_CALL SfxMacroLoader::supportsService(OUString const & ServiceName)
67 : throw (css::uno::RuntimeException, std::exception)
68 : {
69 0 : return cppu::supportsService(this, ServiceName);
70 : }
71 :
72 0 : css::uno::Sequence<OUString> SAL_CALL SfxMacroLoader::getSupportedServiceNames()
73 : throw (css::uno::RuntimeException, std::exception)
74 : {
75 0 : css::uno::Sequence< OUString > aSeq(1);
76 0 : aSeq[0] = OUString("com.sun.star.frame.ProtocolHandler");
77 0 : return aSeq;
78 : }
79 :
80 0 : SfxObjectShell* SfxMacroLoader::GetObjectShell_Impl()
81 : {
82 0 : SfxObjectShell* pDocShell = NULL;
83 0 : Reference < XFrame > xFrame( m_xFrame.get(), UNO_QUERY );
84 0 : if ( xFrame.is() )
85 : {
86 0 : SfxFrame* pFrame=0;
87 0 : for ( pFrame = SfxFrame::GetFirst(); pFrame; pFrame = SfxFrame::GetNext( *pFrame ) )
88 : {
89 0 : if ( pFrame->GetFrameInterface() == xFrame )
90 0 : break;
91 : }
92 :
93 0 : if ( pFrame )
94 0 : pDocShell = pFrame->GetCurrentDocument();
95 : }
96 :
97 0 : return pDocShell;
98 : }
99 :
100 :
101 0 : uno::Reference<frame::XDispatch> SAL_CALL SfxMacroLoader::queryDispatch(
102 : const util::URL& aURL ,
103 : const OUString& /*sTargetFrameName*/,
104 : sal_Int32 /*nSearchFlags*/ ) throw( uno::RuntimeException, std::exception )
105 : {
106 0 : uno::Reference<frame::XDispatch> xDispatcher;
107 0 : if(aURL.Complete.startsWith("macro:"))
108 0 : xDispatcher = this;
109 0 : return xDispatcher;
110 : }
111 :
112 :
113 : uno::Sequence< uno::Reference<frame::XDispatch> > SAL_CALL
114 0 : SfxMacroLoader::queryDispatches( const uno::Sequence < frame::DispatchDescriptor >& seqDescriptor )
115 : throw( uno::RuntimeException, std::exception )
116 : {
117 0 : sal_Int32 nCount = seqDescriptor.getLength();
118 0 : uno::Sequence< uno::Reference<frame::XDispatch> > lDispatcher(nCount);
119 0 : for( sal_Int32 i=0; i<nCount; ++i )
120 0 : lDispatcher[i] = this->queryDispatch( seqDescriptor[i].FeatureURL,
121 0 : seqDescriptor[i].FrameName,
122 0 : seqDescriptor[i].SearchFlags );
123 0 : return lDispatcher;
124 : }
125 :
126 :
127 0 : void SAL_CALL SfxMacroLoader::dispatchWithNotification(
128 : const util::URL& aURL, const uno::Sequence<beans::PropertyValue>& /*lArgs*/,
129 : const uno::Reference<frame::XDispatchResultListener>& xListener )
130 : throw (uno::RuntimeException, std::exception)
131 : {
132 0 : SolarMutexGuard aGuard;
133 :
134 0 : uno::Any aAny;
135 0 : ErrCode nErr = loadMacro( aURL.Complete, aAny, GetObjectShell_Impl() );
136 0 : if( xListener.is() )
137 : {
138 : // always call dispatchFinished(), because we didn't load a document but
139 : // executed a macro instead!
140 0 : frame::DispatchResultEvent aEvent;
141 :
142 0 : aEvent.Source = static_cast< ::cppu::OWeakObject* >(this);
143 0 : if( nErr == ERRCODE_NONE )
144 0 : aEvent.State = frame::DispatchResultState::SUCCESS;
145 : else
146 0 : aEvent.State = frame::DispatchResultState::FAILURE;
147 :
148 0 : xListener->dispatchFinished( aEvent ) ;
149 0 : }
150 0 : }
151 :
152 0 : uno::Any SAL_CALL SfxMacroLoader::dispatchWithReturnValue(
153 : const util::URL& aURL, const uno::Sequence<beans::PropertyValue>& )
154 : throw (uno::RuntimeException, std::exception)
155 : {
156 0 : uno::Any aRet;
157 0 : loadMacro( aURL.Complete, aRet, GetObjectShell_Impl() );
158 0 : return aRet;
159 : }
160 :
161 0 : void SAL_CALL SfxMacroLoader::dispatch(
162 : const util::URL& aURL, const uno::Sequence<beans::PropertyValue>& /*lArgs*/ )
163 : throw (uno::RuntimeException, std::exception)
164 : {
165 0 : SolarMutexGuard aGuard;
166 :
167 0 : uno::Any aAny;
168 0 : loadMacro( aURL.Complete, aAny, GetObjectShell_Impl() );
169 0 : }
170 :
171 0 : void SAL_CALL SfxMacroLoader::addStatusListener(
172 : const uno::Reference< frame::XStatusListener >& ,
173 : const util::URL& )
174 : throw (uno::RuntimeException, std::exception)
175 : {
176 : /* TODO
177 : How we can handle different listener for further coming or currently running dispatch() jobs
178 : without any inconsistency!
179 : */
180 0 : }
181 :
182 :
183 0 : void SAL_CALL SfxMacroLoader::removeStatusListener(
184 : const uno::Reference< frame::XStatusListener >&,
185 : const util::URL& )
186 : throw (uno::RuntimeException, std::exception)
187 : {
188 0 : }
189 :
190 0 : ErrCode SfxMacroLoader::loadMacro( const OUString& rURL, com::sun::star::uno::Any& rRetval, SfxObjectShell* pSh )
191 : throw ( uno::RuntimeException )
192 : {
193 : #ifdef DISABLE_SCRIPTING
194 : (void) rURL;
195 : (void) rRetval;
196 : (void) pSh;
197 : return ERRCODE_BASIC_PROC_UNDEFINED;
198 : #else
199 0 : SfxObjectShell* pCurrent = pSh;
200 0 : if ( !pCurrent )
201 : // all not full qualified names use the BASIC of the given or current document
202 0 : pCurrent = SfxObjectShell::Current();
203 :
204 : // 'macro:///lib.mod.proc(args)' => macro of App-BASIC
205 : // 'macro://[docname|.]/lib.mod.proc(args)' => macro of current or qualified document
206 : // 'macro://obj.method(args)' => direct API call, execute it via App-BASIC
207 0 : OUString aMacro( rURL );
208 0 : sal_Int32 nHashPos = aMacro.indexOf( '/', 8 );
209 0 : sal_Int32 nArgsPos = aMacro.indexOf( '(' );
210 0 : BasicManager *pAppMgr = SFX_APP()->GetBasicManager();
211 0 : BasicManager *pBasMgr = 0;
212 0 : ErrCode nErr = ERRCODE_NONE;
213 :
214 : // should a macro function be executed ( no direct API call)?
215 0 : if ( -1 != nHashPos && ( -1 == nArgsPos || nHashPos < nArgsPos ) )
216 : {
217 : // find BasicManager
218 0 : SfxObjectShell* pDoc = NULL;
219 0 : OUString aBasMgrName( INetURLObject::decode(aMacro.copy( 8, nHashPos-8 ), '%', INetURLObject::DECODE_WITH_CHARSET) );
220 0 : if ( aBasMgrName.isEmpty() )
221 0 : pBasMgr = pAppMgr;
222 0 : else if ( aBasMgrName == "." )
223 : {
224 : // current/actual document
225 0 : pDoc = pCurrent;
226 0 : if (pDoc)
227 0 : pBasMgr = pDoc->GetBasicManager();
228 : }
229 : else
230 : {
231 : // full qualified name, find document by name
232 0 : for ( SfxObjectShell *pObjSh = SfxObjectShell::GetFirst();
233 0 : pObjSh && !pBasMgr;
234 : pObjSh = SfxObjectShell::GetNext(*pObjSh) )
235 0 : if ( aBasMgrName == pObjSh->GetTitle(SFX_TITLE_APINAME) )
236 : {
237 0 : pDoc = pObjSh;
238 0 : pBasMgr = pDoc->GetBasicManager();
239 : }
240 : }
241 :
242 0 : if ( pBasMgr )
243 : {
244 0 : const bool bIsAppBasic = ( pBasMgr == pAppMgr );
245 0 : const bool bIsDocBasic = ( pBasMgr != pAppMgr );
246 :
247 0 : if ( pDoc )
248 : {
249 : // security check for macros from document basic if an SFX doc is given
250 0 : if ( !pDoc->AdjustMacroMode( OUString() ) )
251 : // check forbids execution
252 0 : return ERRCODE_IO_ACCESSDENIED;
253 : }
254 :
255 : // find BASIC method
256 0 : OUString aQualifiedMethod( INetURLObject::decode(aMacro.copy( nHashPos+1 ), '%', INetURLObject::DECODE_WITH_CHARSET) );
257 0 : OUString aArgs;
258 0 : if ( -1 != nArgsPos )
259 : {
260 : // remove arguments from macro name
261 0 : aArgs = aQualifiedMethod.copy( nArgsPos - nHashPos - 1 );
262 0 : aQualifiedMethod = aQualifiedMethod.copy( 0, nArgsPos - nHashPos - 1 );
263 : }
264 :
265 0 : if ( pBasMgr->HasMacro( aQualifiedMethod ) )
266 : {
267 0 : Any aOldThisComponent;
268 0 : const bool bSetDocMacroMode = ( pDoc != NULL ) && bIsDocBasic;
269 0 : const bool bSetGlobalThisComponent = ( pDoc != NULL ) && bIsAppBasic;
270 0 : if ( bSetDocMacroMode )
271 : {
272 : // mark document: it executes an own macro, so it's in a modal mode
273 0 : pDoc->SetMacroMode_Impl( true );
274 : }
275 :
276 0 : if ( bSetGlobalThisComponent )
277 : {
278 : // document is executed via AppBASIC, adjust ThisComponent variable
279 0 : aOldThisComponent = pAppMgr->SetGlobalUNOConstant( "ThisComponent", makeAny( pDoc->GetModel() ) );
280 : }
281 :
282 : // just to let the shell be alive
283 0 : SfxObjectShellRef xKeepDocAlive = pDoc;
284 :
285 : {
286 : // attempt to protect the document against the script tampering with its Undo Context
287 0 : boost::scoped_ptr< ::framework::DocumentUndoGuard > pUndoGuard;
288 0 : if ( bIsDocBasic )
289 0 : pUndoGuard.reset( new ::framework::DocumentUndoGuard( pDoc->GetModel() ) );
290 :
291 : // execute the method
292 0 : SbxVariableRef retValRef = new SbxVariable;
293 0 : nErr = pBasMgr->ExecuteMacro( aQualifiedMethod, aArgs, retValRef );
294 0 : if ( nErr == ERRCODE_NONE )
295 0 : rRetval = sbxToUnoValue( retValRef );
296 : }
297 :
298 0 : if ( bSetGlobalThisComponent )
299 : {
300 0 : pAppMgr->SetGlobalUNOConstant( "ThisComponent", aOldThisComponent );
301 : }
302 :
303 0 : if ( bSetDocMacroMode )
304 : {
305 : // remove flag for modal mode
306 0 : pDoc->SetMacroMode_Impl( false );
307 0 : }
308 : }
309 : else
310 0 : nErr = ERRCODE_BASIC_PROC_UNDEFINED;
311 : }
312 : else
313 0 : nErr = ERRCODE_IO_NOTEXISTS;
314 : }
315 : else
316 : {
317 : // direct API call on a specified object
318 0 : OUStringBuffer aCall;
319 0 : aCall.append('[').append(INetURLObject::decode(aMacro.copy(6), '%',
320 0 : INetURLObject::DECODE_WITH_CHARSET));
321 0 : aCall.append(']');
322 0 : pAppMgr->GetLib(0)->Execute(aCall.makeStringAndClear());
323 0 : nErr = SbxBase::GetError();
324 : }
325 :
326 0 : SbxBase::ResetError();
327 0 : return nErr;
328 : #endif
329 : }
330 :
331 : extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * SAL_CALL
332 0 : com_sun_star_comp_sfx2_SfxMacroLoader_get_implementation(
333 : css::uno::XComponentContext *,
334 : css::uno::Sequence<css::uno::Any> const &arguments)
335 : {
336 0 : return cppu::acquire(new SfxMacroLoader(arguments));
337 : }
338 :
339 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|