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 :
21 : #include <sal/macros.h>
22 : #include "objshimp.hxx"
23 : #include <sfx2/app.hxx>
24 : #include <sfx2/dispatch.hxx>
25 : #include <sfx2/docfac.hxx>
26 : #include <sfx2/docfile.hxx>
27 : #include <sfx2/docfilt.hxx>
28 : #include <sfx2/doctempl.hxx>
29 : #include <sfx2/fcontnr.hxx>
30 : #include <sfx2/frame.hxx>
31 : #include <sfx2/objsh.hxx>
32 : #include <sfx2/request.hxx>
33 : #include <sfx2/sfx.hrc>
34 : #include <sfx2/sfxsids.hrc>
35 : #include <sfx2/sfxuno.hxx>
36 : #include <sfx2/viewfrm.hxx>
37 : #include <sfx2/viewsh.hxx>
38 : #include <sfx2/viewfac.hxx>
39 :
40 : #include <com/sun/star/container/XContainerQuery.hpp>
41 : #include <com/sun/star/document/XTypeDetection.hpp>
42 : #include <com/sun/star/frame/XFrame.hpp>
43 : #include <com/sun/star/frame/XLoadable.hpp>
44 : #include <com/sun/star/frame/XModel.hpp>
45 : #include <com/sun/star/task/XInteractionHandler.hpp>
46 : #include <com/sun/star/task/XInteractionHandler2.hpp>
47 : #include <com/sun/star/document/XViewDataSupplier.hpp>
48 : #include <com/sun/star/container/XIndexAccess.hpp>
49 : #include <com/sun/star/frame/XSynchronousFrameLoader.hpp>
50 : #include <com/sun/star/frame/XController2.hpp>
51 : #include <com/sun/star/frame/XModel2.hpp>
52 : #include <com/sun/star/lang/XServiceInfo.hpp>
53 :
54 : #include <comphelper/interaction.hxx>
55 : #include <comphelper/namedvaluecollection.hxx>
56 : #include <cppuhelper/exc_hlp.hxx>
57 : #include <cppuhelper/implbase2.hxx>
58 : #include <cppuhelper/supportsservice.hxx>
59 : #include <framework/interaction.hxx>
60 : #include <rtl/ref.hxx>
61 : #include <rtl/ustring.h>
62 : #include <sot/storinfo.hxx>
63 : #include <svtools/ehdl.hxx>
64 : #include <svl/eitem.hxx>
65 : #include <svl/itemset.hxx>
66 : #include <unotools/moduleoptions.hxx>
67 : #include <svtools/sfxecode.hxx>
68 : #include <svl/stritem.hxx>
69 : #include <toolkit/helper/vclunohelper.hxx>
70 : #include <tools/diagnose_ex.h>
71 : #include <ucbhelper/simpleinteractionrequest.hxx>
72 : #include <osl/mutex.hxx>
73 :
74 : using ::com::sun::star::beans::PropertyValue;
75 : using ::com::sun::star::container::XContainerQuery;
76 : using ::com::sun::star::container::XEnumeration;
77 : using ::com::sun::star::document::XTypeDetection;
78 : using ::com::sun::star::frame::XFrame;
79 : using ::com::sun::star::frame::XLoadable;
80 : using ::com::sun::star::frame::XModel;
81 : using ::com::sun::star::lang::XMultiServiceFactory;
82 : using ::com::sun::star::task::XInteractionHandler;
83 : using ::com::sun::star::task::XInteractionHandler2;
84 : using ::com::sun::star::task::XInteractionRequest;
85 : using ::com::sun::star::task::XStatusIndicator;
86 : using ::com::sun::star::uno::Any;
87 : using ::com::sun::star::uno::Exception;
88 : using ::com::sun::star::uno::Reference;
89 : using ::com::sun::star::uno::RuntimeException;
90 : using ::com::sun::star::uno::Sequence;
91 : using ::com::sun::star::uno::UNO_QUERY;
92 : using ::com::sun::star::uno::UNO_QUERY_THROW;
93 : using ::com::sun::star::uno::UNO_SET_THROW;
94 : using ::com::sun::star::uno::makeAny;
95 : using ::com::sun::star::util::XCloseable;
96 : using ::com::sun::star::document::XViewDataSupplier;
97 : using ::com::sun::star::container::XIndexAccess;
98 : using ::com::sun::star::frame::XController2;
99 : using ::com::sun::star::frame::XController;
100 : using ::com::sun::star::frame::XModel2;
101 :
102 : namespace {
103 :
104 : class SfxFrameLoader_Impl : public ::cppu::WeakImplHelper2< css::frame::XSynchronousFrameLoader, css::lang::XServiceInfo >
105 : {
106 : css::uno::Reference < css::uno::XComponentContext > m_aContext;
107 :
108 : public:
109 : SfxFrameLoader_Impl( const css::uno::Reference < css::uno::XComponentContext >& _rxContext );
110 :
111 : virtual OUString SAL_CALL getImplementationName()
112 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
113 :
114 : virtual sal_Bool SAL_CALL supportsService(OUString const & ServiceName)
115 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
116 :
117 : virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames()
118 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
119 :
120 :
121 : // XSynchronousFrameLoader
122 :
123 : virtual sal_Bool SAL_CALL load( const css::uno::Sequence< css::beans::PropertyValue >& _rArgs, const css::uno::Reference< css::frame::XFrame >& _rxFrame ) throw( css::uno::RuntimeException, std::exception ) SAL_OVERRIDE;
124 : virtual void SAL_CALL cancel() throw( css::uno::RuntimeException, std::exception ) SAL_OVERRIDE;
125 :
126 : protected:
127 : virtual ~SfxFrameLoader_Impl();
128 :
129 : private:
130 : const SfxFilter* impl_getFilterFromServiceName_nothrow(
131 : const OUString& i_rServiceName
132 : ) const;
133 :
134 : OUString impl_askForFilter_nothrow(
135 : const css::uno::Reference< css::task::XInteractionHandler >& i_rxHandler,
136 : const OUString& i_rDocumentURL
137 : ) const;
138 :
139 : const SfxFilter* impl_detectFilterForURL(
140 : const OUString& _rURL,
141 : const ::comphelper::NamedValueCollection& i_rDescriptor,
142 : const SfxFilterMatcher& rMatcher
143 : ) const;
144 :
145 : bool impl_createNewDocWithSlotParam(
146 : const sal_uInt16 _nSlotID,
147 : const css::uno::Reference< css::frame::XFrame >& i_rxFrame,
148 : const bool i_bHidden
149 : );
150 :
151 : void impl_determineFilter(
152 : ::comphelper::NamedValueCollection& io_rDescriptor
153 : ) const;
154 :
155 : bool impl_determineTemplateDocument(
156 : ::comphelper::NamedValueCollection& io_rDescriptor
157 : ) const;
158 :
159 : sal_uInt16 impl_findSlotParam(
160 : const OUString& i_rFactoryURL
161 : ) const;
162 :
163 : SfxObjectShellRef impl_findObjectShell(
164 : const css::uno::Reference< css::frame::XModel2 >& i_rxDocument
165 : ) const;
166 :
167 : void impl_handleCaughtError_nothrow(
168 : const css::uno::Any& i_rCaughtError,
169 : const ::comphelper::NamedValueCollection& i_rDescriptor
170 : ) const;
171 :
172 : void impl_removeLoaderArguments(
173 : ::comphelper::NamedValueCollection& io_rDescriptor
174 : );
175 :
176 : sal_Int16 impl_determineEffectiveViewId_nothrow(
177 : const SfxObjectShell& i_rDocument,
178 : const ::comphelper::NamedValueCollection& i_rDescriptor
179 : );
180 :
181 : ::comphelper::NamedValueCollection
182 : impl_extractViewCreationArgs(
183 : ::comphelper::NamedValueCollection& io_rDescriptor
184 : );
185 :
186 : css::uno::Reference< css::frame::XController2 >
187 : impl_createDocumentView(
188 : const css::uno::Reference< css::frame::XModel2 >& i_rModel,
189 : const css::uno::Reference< css::frame::XFrame >& i_rFrame,
190 : const ::comphelper::NamedValueCollection& i_rViewFactoryArgs,
191 : const OUString& i_rViewName
192 : );
193 : };
194 :
195 0 : SfxFrameLoader_Impl::SfxFrameLoader_Impl( const Reference< css::uno::XComponentContext >& _rxContext )
196 0 : :m_aContext( _rxContext )
197 : {
198 0 : }
199 :
200 0 : SfxFrameLoader_Impl::~SfxFrameLoader_Impl()
201 : {
202 0 : }
203 :
204 :
205 0 : const SfxFilter* SfxFrameLoader_Impl::impl_detectFilterForURL( const OUString& sURL,
206 : const ::comphelper::NamedValueCollection& i_rDescriptor, const SfxFilterMatcher& rMatcher ) const
207 : {
208 0 : OUString sFilter;
209 : try
210 : {
211 0 : if ( sURL.isEmpty() )
212 0 : return 0;
213 :
214 : Reference< XTypeDetection > xDetect(
215 0 : m_aContext->getServiceManager()->createInstanceWithContext("com.sun.star.document.TypeDetection", m_aContext),
216 0 : UNO_QUERY_THROW);
217 :
218 0 : ::comphelper::NamedValueCollection aNewArgs;
219 0 : aNewArgs.put( "URL", sURL );
220 :
221 0 : if ( i_rDescriptor.has( "InteractionHandler" ) )
222 0 : aNewArgs.put( "InteractionHandler", i_rDescriptor.get( "InteractionHandler" ) );
223 0 : if ( i_rDescriptor.has( "StatusIndicator" ) )
224 0 : aNewArgs.put( "StatusIndicator", i_rDescriptor.get( "StatusIndicator" ) );
225 :
226 0 : Sequence< PropertyValue > aQueryArgs( aNewArgs.getPropertyValues() );
227 0 : OUString sType = xDetect->queryTypeByDescriptor( aQueryArgs, sal_True );
228 0 : if ( !sType.isEmpty() )
229 : {
230 0 : const SfxFilter* pFilter = rMatcher.GetFilter4EA( sType );
231 0 : if ( pFilter )
232 0 : sFilter = pFilter->GetName();
233 0 : }
234 : }
235 0 : catch ( const RuntimeException& )
236 : {
237 0 : throw;
238 : }
239 0 : catch( const Exception& )
240 : {
241 : DBG_UNHANDLED_EXCEPTION();
242 0 : sFilter = OUString();
243 : }
244 :
245 0 : const SfxFilter* pFilter = 0;
246 0 : if (!sFilter.isEmpty())
247 0 : pFilter = rMatcher.GetFilter4FilterName(sFilter);
248 0 : return pFilter;
249 : }
250 :
251 :
252 0 : const SfxFilter* SfxFrameLoader_Impl::impl_getFilterFromServiceName_nothrow( const OUString& i_rServiceName ) const
253 : {
254 : try
255 : {
256 0 : ::comphelper::NamedValueCollection aQuery;
257 0 : aQuery.put( "DocumentService", i_rServiceName );
258 :
259 : const Reference< XContainerQuery > xQuery(
260 0 : m_aContext->getServiceManager()->createInstanceWithContext("com.sun.star.document.FilterFactory", m_aContext),
261 0 : UNO_QUERY_THROW );
262 :
263 0 : const SfxFilterMatcher& rMatcher = SFX_APP()->GetFilterMatcher();
264 0 : const SfxFilterFlags nMust = SFX_FILTER_IMPORT;
265 0 : const SfxFilterFlags nDont = SFX_FILTER_NOTINSTALLED;
266 :
267 0 : Reference < XEnumeration > xEnum( xQuery->createSubSetEnumerationByProperties(
268 0 : aQuery.getNamedValues() ), UNO_SET_THROW );
269 0 : while ( xEnum->hasMoreElements() )
270 : {
271 0 : ::comphelper::NamedValueCollection aType( xEnum->nextElement() );
272 0 : OUString sFilterName = aType.getOrDefault( "Name", OUString() );
273 0 : if ( sFilterName.isEmpty() )
274 0 : continue;
275 :
276 0 : const SfxFilter* pFilter = rMatcher.GetFilter4FilterName( sFilterName );
277 0 : if ( !pFilter )
278 0 : continue;
279 :
280 0 : SfxFilterFlags nFlags = pFilter->GetFilterFlags();
281 0 : if ( ( ( nFlags & nMust ) == nMust )
282 0 : && ( ( nFlags & nDont ) == 0 )
283 : )
284 : {
285 0 : return pFilter;
286 : }
287 0 : }
288 : }
289 0 : catch( const Exception& )
290 : {
291 : DBG_UNHANDLED_EXCEPTION();
292 : }
293 0 : return NULL;
294 : }
295 :
296 :
297 0 : OUString SfxFrameLoader_Impl::impl_askForFilter_nothrow( const Reference< XInteractionHandler >& i_rxHandler,
298 : const OUString& i_rDocumentURL ) const
299 : {
300 0 : ENSURE_OR_THROW( i_rxHandler.is(), "invalid interaction handler" );
301 :
302 0 : OUString sFilterName;
303 : try
304 : {
305 0 : ::framework::RequestFilterSelect aRequest( i_rDocumentURL );
306 0 : i_rxHandler->handle( aRequest.GetRequest() );
307 0 : if( !aRequest.isAbort() )
308 0 : sFilterName = aRequest.getFilter();
309 : }
310 0 : catch( const Exception& )
311 : {
312 : DBG_UNHANDLED_EXCEPTION();
313 : }
314 :
315 0 : return sFilterName;
316 : }
317 :
318 :
319 : namespace
320 : {
321 0 : bool lcl_getDispatchResult( const SfxPoolItem* _pResult )
322 : {
323 0 : if ( !_pResult )
324 0 : return false;
325 :
326 : // default must be set to true, because some return values
327 : // cant be checked, but nonetheless indicate "success"!
328 0 : bool bSuccess = true;
329 :
330 : // On the other side some special slots return a boolean state,
331 : // which can be set to FALSE.
332 0 : SfxBoolItem *pItem = PTR_CAST( SfxBoolItem, _pResult );
333 0 : if ( pItem )
334 0 : bSuccess = pItem->GetValue();
335 :
336 0 : return bSuccess;
337 : }
338 : }
339 :
340 :
341 0 : bool SfxFrameLoader_Impl::impl_createNewDocWithSlotParam( const sal_uInt16 _nSlotID, const Reference< XFrame >& i_rxFrame,
342 : const bool i_bHidden )
343 : {
344 0 : SfxRequest aRequest( _nSlotID, SFX_CALLMODE_SYNCHRON, SFX_APP()->GetPool() );
345 0 : aRequest.AppendItem( SfxUnoFrameItem( SID_FILLFRAME, i_rxFrame ) );
346 0 : if ( i_bHidden )
347 0 : aRequest.AppendItem( SfxBoolItem( SID_HIDDEN, true ) );
348 0 : return lcl_getDispatchResult( SFX_APP()->ExecuteSlot( aRequest ) );
349 : }
350 :
351 :
352 0 : void SfxFrameLoader_Impl::impl_determineFilter( ::comphelper::NamedValueCollection& io_rDescriptor ) const
353 : {
354 0 : const OUString sURL = io_rDescriptor.getOrDefault( "URL", OUString() );
355 0 : const OUString sTypeName = io_rDescriptor.getOrDefault( "TypeName", OUString() );
356 0 : const OUString sFilterName = io_rDescriptor.getOrDefault( "FilterName", OUString() );
357 0 : const OUString sServiceName = io_rDescriptor.getOrDefault( "DocumentService", OUString() );
358 : const Reference< XInteractionHandler >
359 0 : xInteraction = io_rDescriptor.getOrDefault( "InteractionHandler", Reference< XInteractionHandler >() );
360 :
361 0 : const SfxFilterMatcher& rMatcher = SFX_APP()->GetFilterMatcher();
362 0 : const SfxFilter* pFilter = NULL;
363 :
364 : // get filter by its name directly ...
365 0 : if ( !sFilterName.isEmpty() )
366 0 : pFilter = rMatcher.GetFilter4FilterName( sFilterName );
367 :
368 : // or search the preferred filter for the detected type ...
369 0 : if ( !pFilter && !sTypeName.isEmpty() )
370 0 : pFilter = rMatcher.GetFilter4EA( sTypeName );
371 :
372 : // or use given document service for detection, too
373 0 : if ( !pFilter && !sServiceName.isEmpty() )
374 0 : pFilter = impl_getFilterFromServiceName_nothrow( sServiceName );
375 :
376 : // or use interaction to ask user for right filter.
377 0 : if ( !pFilter && xInteraction.is() && !sURL.isEmpty() )
378 : {
379 0 : OUString sSelectedFilter = impl_askForFilter_nothrow( xInteraction, sURL );
380 0 : if ( !sSelectedFilter.isEmpty() )
381 0 : pFilter = rMatcher.GetFilter4FilterName( sSelectedFilter );
382 : }
383 :
384 0 : if ( pFilter )
385 : {
386 0 : io_rDescriptor.put( "FilterName", OUString( pFilter->GetFilterName() ) );
387 :
388 : // If detected filter indicates using of an own template format
389 : // add property "AsTemplate" to descriptor. But suppress this step
390 : // if such property already exists.
391 0 : if ( pFilter->IsOwnTemplateFormat() && !io_rDescriptor.has( "AsTemplate" ) )
392 0 : io_rDescriptor.put( "AsTemplate", true );
393 :
394 : // The DocumentService property will finally be used to determine the document type to create, so
395 : // override it with the service name as indicated by the found filter.
396 0 : io_rDescriptor.put( "DocumentService", OUString( pFilter->GetServiceName() ) );
397 0 : }
398 0 : }
399 :
400 :
401 0 : SfxObjectShellRef SfxFrameLoader_Impl::impl_findObjectShell( const Reference< XModel2 >& i_rxDocument ) const
402 : {
403 0 : for ( SfxObjectShell* pDoc = SfxObjectShell::GetFirst( NULL, false ); pDoc; pDoc = SfxObjectShell::GetNext( *pDoc, NULL, false ) )
404 : {
405 0 : if ( i_rxDocument == pDoc->GetModel() )
406 : {
407 0 : return pDoc;
408 : }
409 : }
410 :
411 : SAL_WARN( "sfx.view", "SfxFrameLoader_Impl::impl_findObjectShell: model is not based on SfxObjectShell - wrong frame loader usage!" );
412 0 : return NULL;
413 : }
414 :
415 :
416 0 : bool SfxFrameLoader_Impl::impl_determineTemplateDocument( ::comphelper::NamedValueCollection& io_rDescriptor ) const
417 : {
418 : try
419 : {
420 0 : const OUString sTemplateRegioName = io_rDescriptor.getOrDefault( "TemplateRegionName", OUString() );
421 0 : const OUString sTemplateName = io_rDescriptor.getOrDefault( "TemplateName", OUString() );
422 0 : const OUString sServiceName = io_rDescriptor.getOrDefault( "DocumentService", OUString() );
423 0 : const OUString sURL = io_rDescriptor.getOrDefault( "URL", OUString() );
424 :
425 : // determine the full URL of the template to use, if any
426 0 : OUString sTemplateURL;
427 0 : if ( !sTemplateRegioName.isEmpty() && !sTemplateName.isEmpty() )
428 : {
429 0 : SfxDocumentTemplates aTmpFac;
430 0 : aTmpFac.GetFull( sTemplateRegioName, sTemplateName, sTemplateURL );
431 : }
432 : else
433 : {
434 0 : if ( !sServiceName.isEmpty() )
435 0 : sTemplateURL = SfxObjectFactory::GetStandardTemplate( sServiceName );
436 : else
437 0 : sTemplateURL = SfxObjectFactory::GetStandardTemplate( SfxObjectShell::GetServiceNameFromFactory( sURL ) );
438 : }
439 :
440 0 : if ( !sTemplateURL.isEmpty() )
441 : {
442 : // detect the filter for the template. Might still be NULL (if the template is broken, or does not
443 : // exist, or some such), but this is handled by our caller the same way as if no template/URL was present.
444 0 : const SfxFilter* pTemplateFilter = impl_detectFilterForURL( sTemplateURL, io_rDescriptor, SFX_APP()->GetFilterMatcher() );
445 0 : if ( pTemplateFilter )
446 : {
447 : // load the template document, but, well, "as template"
448 0 : io_rDescriptor.put( "FilterName", OUString( pTemplateFilter->GetName() ) );
449 0 : io_rDescriptor.put( "FileName", OUString( sTemplateURL ) );
450 0 : io_rDescriptor.put( "AsTemplate", sal_True );
451 :
452 : // #i21583#
453 : // the DocumentService property will finally be used to create the document. Thus, override any possibly
454 : // present value with the document service of the template.
455 0 : io_rDescriptor.put( "DocumentService", OUString( pTemplateFilter->GetServiceName() ) );
456 0 : return true;
457 : }
458 0 : }
459 : }
460 0 : catch (...)
461 : {
462 : }
463 0 : return false;
464 : }
465 :
466 :
467 0 : sal_uInt16 SfxFrameLoader_Impl::impl_findSlotParam( const OUString& i_rFactoryURL ) const
468 : {
469 0 : OUString sSlotParam;
470 0 : const sal_Int32 nParamPos = i_rFactoryURL.indexOf( '?' );
471 0 : if ( nParamPos >= 0 )
472 : {
473 : // currently only the "slot" parameter is supported
474 0 : const sal_Int32 nSlotPos = i_rFactoryURL.indexOf( "slot=", nParamPos );
475 0 : if ( nSlotPos > 0 )
476 0 : sSlotParam = i_rFactoryURL.copy( nSlotPos + 5 );
477 : }
478 :
479 0 : if ( !sSlotParam.isEmpty() )
480 0 : return sal_uInt16( sSlotParam.toInt32() );
481 :
482 0 : return 0;
483 : }
484 :
485 :
486 0 : void SfxFrameLoader_Impl::impl_handleCaughtError_nothrow( const Any& i_rCaughtError, const ::comphelper::NamedValueCollection& i_rDescriptor ) const
487 : {
488 : try
489 : {
490 : const Reference< XInteractionHandler > xInteraction =
491 0 : i_rDescriptor.getOrDefault( "InteractionHandler", Reference< XInteractionHandler >() );
492 0 : if ( !xInteraction.is() )
493 0 : return;
494 0 : ::rtl::Reference< ::comphelper::OInteractionRequest > pRequest( new ::comphelper::OInteractionRequest( i_rCaughtError ) );
495 0 : ::rtl::Reference< ::comphelper::OInteractionApprove > pApprove( new ::comphelper::OInteractionApprove );
496 0 : pRequest->addContinuation( pApprove.get() );
497 :
498 0 : const Reference< XInteractionHandler2 > xHandler( xInteraction, UNO_QUERY );
499 : #if OSL_DEBUG_LEVEL > 0
500 : const bool bHandled =
501 : #endif
502 0 : xHandler.is() && xHandler->handleInteractionRequest( pRequest.get() );
503 :
504 : #if OSL_DEBUG_LEVEL > 0
505 : if ( !bHandled )
506 : // the interaction handler couldn't deal with this error
507 : // => report it as assertion, at least (done in the DBG_UNHANDLED_EXCEPTION below)
508 : ::cppu::throwException( i_rCaughtError );
509 : #endif
510 : }
511 0 : catch( const Exception& )
512 : {
513 : DBG_UNHANDLED_EXCEPTION();
514 : }
515 : }
516 :
517 :
518 0 : void SfxFrameLoader_Impl::impl_removeLoaderArguments( ::comphelper::NamedValueCollection& io_rDescriptor )
519 : {
520 : // remove the arguments which are for the loader only, and not for a call to attachResource
521 0 : io_rDescriptor.remove( "StatusIndicator" );
522 0 : io_rDescriptor.remove( "Model" );
523 0 : }
524 :
525 :
526 0 : ::comphelper::NamedValueCollection SfxFrameLoader_Impl::impl_extractViewCreationArgs( ::comphelper::NamedValueCollection& io_rDescriptor )
527 : {
528 : const sal_Char* pKnownViewArgs[] = {
529 : "JumpMark"
530 0 : };
531 :
532 0 : ::comphelper::NamedValueCollection aViewArgs;
533 0 : for ( size_t i=0; i < sizeof( pKnownViewArgs ) / sizeof( pKnownViewArgs[0] ); ++i )
534 : {
535 0 : if ( io_rDescriptor.has( pKnownViewArgs[i] ) )
536 : {
537 0 : aViewArgs.put( pKnownViewArgs[i], io_rDescriptor.get( pKnownViewArgs[i] ) );
538 0 : io_rDescriptor.remove( pKnownViewArgs[i] );
539 : }
540 : }
541 0 : return aViewArgs;
542 : }
543 :
544 :
545 0 : sal_Int16 SfxFrameLoader_Impl::impl_determineEffectiveViewId_nothrow( const SfxObjectShell& i_rDocument, const ::comphelper::NamedValueCollection& i_rDescriptor )
546 : {
547 0 : sal_Int16 nViewId = i_rDescriptor.getOrDefault( "ViewId", sal_Int16( 0 ) );
548 : try
549 : {
550 0 : if ( nViewId == 0 ) do
551 : {
552 0 : Reference< XViewDataSupplier > xViewDataSupplier( i_rDocument.GetModel(), UNO_QUERY );
553 0 : Reference< XIndexAccess > xViewData;
554 0 : if ( xViewDataSupplier.is() )
555 0 : xViewData.set( xViewDataSupplier->getViewData() );
556 :
557 0 : if ( !xViewData.is() || ( xViewData->getCount() == 0 ) )
558 : // no view data stored together with the model
559 0 : break;
560 :
561 : // obtain the ViewID from the view data
562 0 : Sequence< PropertyValue > aViewData;
563 0 : if ( !( xViewData->getByIndex( 0 ) >>= aViewData ) )
564 0 : break;
565 :
566 0 : ::comphelper::NamedValueCollection aNamedViewData( aViewData );
567 0 : OUString sViewId = aNamedViewData.getOrDefault( "ViewId", OUString() );
568 0 : if ( sViewId.isEmpty() )
569 0 : break;
570 :
571 : // somewhat weird convention here ... in the view data, the ViewId is a string, effectively describing
572 : // a view name. In the document load descriptor, the ViewId is in fact the numeric ID.
573 :
574 0 : SfxViewFactory* pViewFactory = i_rDocument.GetFactory().GetViewFactoryByViewName( sViewId );
575 0 : if ( pViewFactory )
576 0 : nViewId = sal_Int16( pViewFactory->GetOrdinal() );
577 : }
578 : while ( false );
579 : }
580 0 : catch( const Exception& )
581 : {
582 : DBG_UNHANDLED_EXCEPTION();
583 : }
584 :
585 0 : if ( nViewId == 0 )
586 0 : nViewId = i_rDocument.GetFactory().GetViewFactory( 0 ).GetOrdinal();
587 0 : return nViewId;
588 : }
589 :
590 :
591 0 : Reference< XController2 > SfxFrameLoader_Impl::impl_createDocumentView( const Reference< XModel2 >& i_rModel,
592 : const Reference< XFrame >& i_rFrame, const ::comphelper::NamedValueCollection& i_rViewFactoryArgs,
593 : const OUString& i_rViewName )
594 : {
595 : // let the model create a new controller
596 0 : const Reference< XController2 > xController( i_rModel->createViewController(
597 : i_rViewName,
598 : i_rViewFactoryArgs.getPropertyValues(),
599 : i_rFrame
600 0 : ), UNO_SET_THROW );
601 :
602 : // introduce model/view/controller to each other
603 0 : xController->attachModel( i_rModel.get() );
604 0 : i_rModel->connectController( xController.get() );
605 0 : i_rFrame->setComponent( xController->getComponentWindow(), xController.get() );
606 0 : xController->attachFrame( i_rFrame );
607 0 : i_rModel->setCurrentController( xController.get() );
608 :
609 0 : return xController;
610 : }
611 :
612 :
613 0 : sal_Bool SAL_CALL SfxFrameLoader_Impl::load( const Sequence< PropertyValue >& rArgs,
614 : const Reference< XFrame >& _rTargetFrame )
615 : throw( RuntimeException, std::exception )
616 : {
617 0 : ENSURE_OR_THROW( _rTargetFrame.is(), "illegal NULL frame" );
618 :
619 0 : SolarMutexGuard aGuard;
620 :
621 : SAL_INFO( "sfx.view", "SfxFrameLoader::load" );
622 :
623 0 : ::comphelper::NamedValueCollection aDescriptor( rArgs );
624 :
625 : // ensure the descriptor contains a referrer
626 0 : if ( !aDescriptor.has( "Referer" ) )
627 0 : aDescriptor.put( "Referer", OUString() );
628 :
629 : // did the caller already pass a model?
630 0 : Reference< XModel2 > xModel = aDescriptor.getOrDefault( "Model", Reference< XModel2 >() );
631 0 : const bool bExternalModel = xModel.is();
632 :
633 : // check for factory URLs to create a new doc, instead of loading one
634 0 : const OUString sURL = aDescriptor.getOrDefault( "URL", OUString() );
635 0 : const bool bIsFactoryURL = sURL.startsWith( "private:factory/" );
636 0 : bool bInitNewModel = bIsFactoryURL;
637 0 : if ( bIsFactoryURL && !bExternalModel )
638 : {
639 0 : const OUString sFactory = sURL.copy( sizeof( "private:factory/" ) -1 );
640 : // special handling for some weird factory URLs a la private:factory/swriter?slot=21053
641 0 : const sal_uInt16 nSlotParam = impl_findSlotParam( sFactory );
642 0 : if ( nSlotParam != 0 )
643 : {
644 0 : return impl_createNewDocWithSlotParam( nSlotParam, _rTargetFrame, aDescriptor.getOrDefault( "Hidden", false ) );
645 : }
646 :
647 0 : const bool bDescribesValidTemplate = impl_determineTemplateDocument( aDescriptor );
648 0 : if ( bDescribesValidTemplate )
649 : {
650 : // if the media descriptor allowed us to determine a template document to create the new document
651 : // from, then do not init a new document model from scratch (below), but instead load the
652 : // template document
653 0 : bInitNewModel = false;
654 : }
655 : else
656 : {
657 0 : const OUString sServiceName = SfxObjectShell::GetServiceNameFromFactory( sFactory );
658 0 : aDescriptor.put( "DocumentService", sServiceName );
659 0 : }
660 : }
661 : else
662 : {
663 : // compatibility
664 0 : aDescriptor.put( "FileName", aDescriptor.get( "URL" ) );
665 : }
666 :
667 0 : bool bLoadSuccess = false;
668 : try
669 : {
670 : // extract view releant arguments from the loader args
671 0 : ::comphelper::NamedValueCollection aViewCreationArgs( impl_extractViewCreationArgs( aDescriptor ) );
672 :
673 : // no model passed from outside? => create one from scratch
674 0 : if ( !xModel.is() )
675 : {
676 0 : bool bInternalFilter = aDescriptor.getOrDefault<OUString>("FilterProvider", OUString()).isEmpty();
677 :
678 0 : if (bInternalFilter && !bInitNewModel)
679 : {
680 : // Ensure that the current SfxFilter instance is loaded before
681 : // going further. We don't need to do this for external
682 : // filter providers.
683 0 : impl_determineFilter(aDescriptor);
684 : }
685 :
686 : // create the new doc
687 0 : const OUString sServiceName = aDescriptor.getOrDefault( "DocumentService", OUString() );
688 0 : xModel.set( m_aContext->getServiceManager()->createInstanceWithContext(sServiceName, m_aContext), UNO_QUERY_THROW );
689 :
690 : // load resp. init it
691 0 : const Reference< XLoadable > xLoadable( xModel, UNO_QUERY_THROW );
692 0 : if ( bInitNewModel )
693 : {
694 0 : xLoadable->initNew();
695 :
696 0 : impl_removeLoaderArguments( aDescriptor );
697 0 : xModel->attachResource( OUString(), aDescriptor.getPropertyValues() );
698 : }
699 : else
700 : {
701 0 : xLoadable->load( aDescriptor.getPropertyValues() );
702 0 : }
703 : }
704 : else
705 : {
706 : // tell the doc its (current) load args.
707 0 : impl_removeLoaderArguments( aDescriptor );
708 0 : xModel->attachResource( xModel->getURL(), aDescriptor.getPropertyValues() );
709 : }
710 :
711 : // get the SfxObjectShell (still needed at the moment)
712 : // SfxObjectShellRef is used here ( instead of ...Lock ) since the model is closed below if necessary
713 : // SfxObjectShellLock would be even dangerous here, since the lifetime control should be done outside in case of success
714 0 : const SfxObjectShellRef xDoc = impl_findObjectShell( xModel );
715 0 : ENSURE_OR_THROW( xDoc.Is(), "no SfxObjectShell for the given model" );
716 :
717 : // ensure the ID of the to-be-created view is in the descriptor, if possible
718 0 : const sal_Int16 nViewId = impl_determineEffectiveViewId_nothrow( *xDoc, aDescriptor );
719 0 : const sal_Int16 nViewNo = xDoc->GetFactory().GetViewNo_Impl( nViewId, 0 );
720 0 : const OUString sViewName( xDoc->GetFactory().GetViewFactory( nViewNo ).GetAPIViewName() );
721 :
722 : // plug the document into the frame
723 0 : impl_createDocumentView( xModel, _rTargetFrame, aViewCreationArgs, sViewName );
724 0 : bLoadSuccess = true;
725 : }
726 0 : catch ( Exception& )
727 : {
728 0 : const Any aError( ::cppu::getCaughtException() );
729 0 : if ( !aDescriptor.getOrDefault( "Silent", sal_False ) )
730 0 : impl_handleCaughtError_nothrow( aError, aDescriptor );
731 : }
732 :
733 : // if loading was not successful, close the document
734 0 : if ( !bLoadSuccess && !bExternalModel )
735 : {
736 : try
737 : {
738 0 : const Reference< XCloseable > xCloseable( xModel, UNO_QUERY_THROW );
739 0 : xCloseable->close( sal_True );
740 : }
741 0 : catch ( Exception& )
742 : {
743 : DBG_UNHANDLED_EXCEPTION();
744 : }
745 : }
746 :
747 0 : return bLoadSuccess;
748 : }
749 :
750 0 : void SfxFrameLoader_Impl::cancel() throw( RuntimeException, std::exception )
751 : {
752 0 : }
753 :
754 : /* XServiceInfo */
755 0 : OUString SAL_CALL SfxFrameLoader_Impl::getImplementationName() throw( RuntimeException, std::exception )
756 : {
757 0 : return OUString("com.sun.star.comp.office.FrameLoader");
758 : }
759 : \
760 : /* XServiceInfo */
761 0 : sal_Bool SAL_CALL SfxFrameLoader_Impl::supportsService( const OUString& sServiceName ) throw( RuntimeException, std::exception )
762 : {
763 0 : return cppu::supportsService(this, sServiceName);
764 : }
765 :
766 : /* XServiceInfo */
767 0 : Sequence< OUString > SAL_CALL SfxFrameLoader_Impl::getSupportedServiceNames() throw( RuntimeException, std::exception )
768 : {
769 0 : Sequence< OUString > seqServiceNames( 2 );
770 0 : seqServiceNames.getArray() [0] = "com.sun.star.frame.SynchronousFrameLoader";
771 0 : seqServiceNames.getArray() [1] = "com.sun.star.frame.OfficeFrameLoader";
772 0 : return seqServiceNames ;
773 : }
774 :
775 : }
776 :
777 : extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * SAL_CALL
778 0 : com_sun_star_comp_office_FrameLoader_get_implementation(
779 : css::uno::XComponentContext *context,
780 : css::uno::Sequence<css::uno::Any> const &)
781 : {
782 0 : return cppu::acquire(new SfxFrameLoader_Impl(context));
783 : }
784 :
785 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|