Use correct object
[LibreOffice.git] / sfx2 / source / view / frmload.cxx
blob7ef7c19d2f63c9e54633daf803b013e0e9213ceb
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 .
21 #include <sfx2/app.hxx>
22 #include <sfx2/bindings.hxx>
23 #include <sfx2/docfac.hxx>
24 #include <sfx2/docfile.hxx>
25 #include <sfx2/docfilt.hxx>
26 #include <sfx2/doctempl.hxx>
27 #include <sfx2/fcontnr.hxx>
28 #include <sfx2/frame.hxx>
29 #include <sfx2/objsh.hxx>
30 #include <sfx2/request.hxx>
31 #include <sfx2/sfxsids.hrc>
32 #include <sfx2/viewfac.hxx>
34 #include <com/sun/star/container/XContainerQuery.hpp>
35 #include <com/sun/star/document/XTypeDetection.hpp>
36 #include <com/sun/star/frame/XFrame.hpp>
37 #include <com/sun/star/frame/XLoadable.hpp>
38 #include <com/sun/star/task/XInteractionHandler.hpp>
39 #include <com/sun/star/task/XInteractionHandler2.hpp>
40 #include <com/sun/star/document/XViewDataSupplier.hpp>
41 #include <com/sun/star/container/XIndexAccess.hpp>
42 #include <com/sun/star/frame/XSynchronousFrameLoader.hpp>
43 #include <com/sun/star/frame/XController2.hpp>
44 #include <com/sun/star/frame/XModel2.hpp>
45 #include <com/sun/star/lang/XServiceInfo.hpp>
46 #include <com/sun/star/lang/XInitialization.hpp>
47 #include <com/sun/star/uno/XComponentContext.hpp>
48 #include <com/sun/star/util/XCloseable.hpp>
50 #include <comphelper/interaction.hxx>
51 #include <comphelper/namedvaluecollection.hxx>
52 #include <cppuhelper/exc_hlp.hxx>
53 #include <cppuhelper/implbase.hxx>
54 #include <cppuhelper/supportsservice.hxx>
55 #include <framework/interaction.hxx>
56 #include <officecfg/Office/Common.hxx>
57 #include <rtl/ref.hxx>
58 #include <sal/log.hxx>
59 #include <svl/eitem.hxx>
60 #include <svl/stritem.hxx>
61 #include <unotools/fcm.hxx>
62 #include <unotools/moduleoptions.hxx>
63 #include <comphelper/diagnose_ex.hxx>
64 #include <tools/stream.hxx>
65 #include <tools/urlobj.hxx>
66 #include <vcl/svapp.hxx>
67 #include <o3tl/string_view.hxx>
69 using namespace com::sun::star;
70 using ::com::sun::star::beans::PropertyValue;
71 using ::com::sun::star::container::XContainerQuery;
72 using ::com::sun::star::container::XEnumeration;
73 using ::com::sun::star::document::XTypeDetection;
74 using ::com::sun::star::frame::XFrame;
75 using ::com::sun::star::frame::XLoadable;
76 using ::com::sun::star::task::XInteractionHandler;
77 using ::com::sun::star::task::XInteractionHandler2;
78 using ::com::sun::star::uno::Any;
79 using ::com::sun::star::uno::Exception;
80 using ::com::sun::star::uno::Reference;
81 using ::com::sun::star::uno::RuntimeException;
82 using ::com::sun::star::uno::Sequence;
83 using ::com::sun::star::uno::UNO_QUERY;
84 using ::com::sun::star::uno::UNO_QUERY_THROW;
85 using ::com::sun::star::uno::UNO_SET_THROW;
86 using ::com::sun::star::util::XCloseable;
87 using ::com::sun::star::document::XViewDataSupplier;
88 using ::com::sun::star::container::XIndexAccess;
89 using ::com::sun::star::frame::XController2;
90 using ::com::sun::star::frame::XModel2;
92 namespace {
94 class SfxFrameLoader_Impl : public ::cppu::WeakImplHelper< css::frame::XSynchronousFrameLoader, css::lang::XServiceInfo >
96 css::uno::Reference < css::uno::XComponentContext > m_aContext;
98 public:
99 explicit SfxFrameLoader_Impl( const css::uno::Reference < css::uno::XComponentContext >& _rxContext );
101 virtual OUString SAL_CALL getImplementationName() override;
103 virtual sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override;
105 virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
108 // XSynchronousFrameLoader
110 virtual sal_Bool SAL_CALL load( const css::uno::Sequence< css::beans::PropertyValue >& _rArgs, const css::uno::Reference< css::frame::XFrame >& _rxFrame ) override;
111 virtual void SAL_CALL cancel() override;
113 protected:
114 virtual ~SfxFrameLoader_Impl() override;
116 private:
117 std::shared_ptr<const SfxFilter> impl_getFilterFromServiceName_nothrow(
118 const OUString& i_rServiceName
119 ) const;
121 static OUString impl_askForFilter_nothrow(
122 const css::uno::Reference< css::task::XInteractionHandler >& i_rxHandler,
123 const OUString& i_rDocumentURL
126 std::shared_ptr<const SfxFilter> impl_detectFilterForURL(
127 const OUString& _rURL,
128 const ::comphelper::NamedValueCollection& i_rDescriptor,
129 const SfxFilterMatcher& rMatcher
130 ) const;
132 static bool impl_createNewDocWithSlotParam(
133 const sal_uInt16 _nSlotID,
134 const css::uno::Reference< css::frame::XFrame >& i_rxFrame,
135 const bool i_bHidden
138 void impl_determineFilter(
139 ::comphelper::NamedValueCollection& io_rDescriptor
140 ) const;
142 bool impl_determineTemplateDocument(
143 ::comphelper::NamedValueCollection& io_rDescriptor
144 ) const;
146 static sal_uInt16 impl_findSlotParam(
147 std::u16string_view i_rFactoryURL
150 static SfxObjectShellRef impl_findObjectShell(
151 const css::uno::Reference< css::frame::XModel2 >& i_rxDocument
154 static void impl_handleCaughtError_nothrow(
155 const css::uno::Any& i_rCaughtError,
156 const ::comphelper::NamedValueCollection& i_rDescriptor
159 static void impl_removeLoaderArguments(
160 ::comphelper::NamedValueCollection& io_rDescriptor
163 static SfxInterfaceId impl_determineEffectiveViewId_nothrow(
164 const SfxObjectShell& i_rDocument,
165 const ::comphelper::NamedValueCollection& i_rDescriptor
168 static ::comphelper::NamedValueCollection
169 impl_extractViewCreationArgs(
170 ::comphelper::NamedValueCollection& io_rDescriptor
173 static css::uno::Reference< css::frame::XController2 >
174 impl_createDocumentView(
175 const css::uno::Reference< css::frame::XModel2 >& i_rModel,
176 const css::uno::Reference< css::frame::XFrame >& i_rFrame,
177 const ::comphelper::NamedValueCollection& i_rViewFactoryArgs,
178 const OUString& i_rViewName
182 SfxFrameLoader_Impl::SfxFrameLoader_Impl( const Reference< css::uno::XComponentContext >& _rxContext )
183 :m_aContext( _rxContext )
187 SfxFrameLoader_Impl::~SfxFrameLoader_Impl()
192 std::shared_ptr<const SfxFilter> SfxFrameLoader_Impl::impl_detectFilterForURL( const OUString& sURL,
193 const ::comphelper::NamedValueCollection& i_rDescriptor, const SfxFilterMatcher& rMatcher ) const
195 OUString sFilter;
198 if ( sURL.isEmpty() )
199 return nullptr;
201 Reference< XTypeDetection > xDetect(
202 m_aContext->getServiceManager()->createInstanceWithContext(u"com.sun.star.document.TypeDetection"_ustr, m_aContext),
203 UNO_QUERY_THROW);
205 ::comphelper::NamedValueCollection aNewArgs;
206 aNewArgs.put( u"URL"_ustr, sURL );
208 if ( i_rDescriptor.has( u"InteractionHandler"_ustr ) )
209 aNewArgs.put( u"InteractionHandler"_ustr, i_rDescriptor.get( u"InteractionHandler"_ustr ) );
210 if ( i_rDescriptor.has( u"StatusIndicator"_ustr ) )
211 aNewArgs.put( u"StatusIndicator"_ustr, i_rDescriptor.get( u"StatusIndicator"_ustr ) );
213 Sequence< PropertyValue > aQueryArgs( aNewArgs.getPropertyValues() );
214 OUString sType = xDetect->queryTypeByDescriptor( aQueryArgs, true );
215 if ( !sType.isEmpty() )
217 std::shared_ptr<const SfxFilter> pFilter = rMatcher.GetFilter4EA( sType );
218 if ( pFilter )
219 sFilter = pFilter->GetName();
222 catch ( const RuntimeException& )
224 throw;
226 catch( const Exception& )
228 DBG_UNHANDLED_EXCEPTION("sfx.view");
229 sFilter.clear();
232 std::shared_ptr<const SfxFilter> pFilter;
233 if (!sFilter.isEmpty())
234 pFilter = rMatcher.GetFilter4FilterName(sFilter);
235 return pFilter;
239 std::shared_ptr<const SfxFilter> SfxFrameLoader_Impl::impl_getFilterFromServiceName_nothrow( const OUString& i_rServiceName ) const
243 ::comphelper::NamedValueCollection aQuery;
244 aQuery.put( u"DocumentService"_ustr, i_rServiceName );
246 const Reference< XContainerQuery > xQuery(
247 m_aContext->getServiceManager()->createInstanceWithContext(u"com.sun.star.document.FilterFactory"_ustr, m_aContext),
248 UNO_QUERY_THROW );
250 const SfxFilterMatcher& rMatcher = SfxGetpApp()->GetFilterMatcher();
251 const SfxFilterFlags nMust = SfxFilterFlags::IMPORT;
252 const SfxFilterFlags nDont = SFX_FILTER_NOTINSTALLED;
254 Reference < XEnumeration > xEnum( xQuery->createSubSetEnumerationByProperties(
255 aQuery.getNamedValues() ), UNO_SET_THROW );
256 while ( xEnum->hasMoreElements() )
258 ::comphelper::NamedValueCollection aType( xEnum->nextElement() );
259 OUString sFilterName = aType.getOrDefault( u"Name"_ustr, OUString() );
260 if ( sFilterName.isEmpty() )
261 continue;
263 std::shared_ptr<const SfxFilter> pFilter = rMatcher.GetFilter4FilterName( sFilterName );
264 if ( !pFilter )
265 continue;
267 SfxFilterFlags nFlags = pFilter->GetFilterFlags();
268 if ( ( ( nFlags & nMust ) == nMust )
269 && ( ( nFlags & nDont ) == SfxFilterFlags::NONE )
272 return pFilter;
276 catch( const Exception& )
278 DBG_UNHANDLED_EXCEPTION("sfx.view");
280 return nullptr;
284 OUString SfxFrameLoader_Impl::impl_askForFilter_nothrow( const Reference< XInteractionHandler >& i_rxHandler,
285 const OUString& i_rDocumentURL )
287 ENSURE_OR_THROW( i_rxHandler.is(), "invalid interaction handler" );
289 OUString sFilterName;
292 ::framework::RequestFilterSelect aRequest( i_rDocumentURL );
293 i_rxHandler->handle( aRequest.GetRequest() );
294 if( !aRequest.isAbort() )
295 sFilterName = aRequest.getFilter();
297 catch( const Exception& )
299 DBG_UNHANDLED_EXCEPTION("sfx.view");
302 return sFilterName;
305 bool lcl_getDispatchResult(const SfxPoolItemHolder& rResult)
307 if (!rResult)
308 return false;
310 // default must be set to true, because some return values
311 // can't be checked, but nonetheless indicate "success"!
312 bool bSuccess = true;
314 // On the other side some special slots return a boolean state,
315 // which can be set to FALSE.
316 const SfxBoolItem* pItem(dynamic_cast<const SfxBoolItem*>(rResult.getItem()));
317 if ( pItem )
318 bSuccess = pItem->GetValue();
320 return bSuccess;
323 bool SfxFrameLoader_Impl::impl_createNewDocWithSlotParam( const sal_uInt16 _nSlotID, const Reference< XFrame >& i_rxFrame,
324 const bool i_bHidden )
326 SfxRequest aRequest( _nSlotID, SfxCallMode::SYNCHRON, SfxGetpApp()->GetPool() );
327 aRequest.AppendItem( SfxUnoFrameItem( SID_FILLFRAME, i_rxFrame ) );
328 if ( i_bHidden )
329 aRequest.AppendItem( SfxBoolItem( SID_HIDDEN, true ) );
330 return lcl_getDispatchResult(SfxGetpApp()->ExecuteSlot(aRequest));
334 void SfxFrameLoader_Impl::impl_determineFilter( ::comphelper::NamedValueCollection& io_rDescriptor ) const
336 const OUString sURL = io_rDescriptor.getOrDefault( u"URL"_ustr, OUString() );
337 const OUString sTypeName = io_rDescriptor.getOrDefault( u"TypeName"_ustr, OUString() );
338 const OUString sFilterName = io_rDescriptor.getOrDefault( u"FilterName"_ustr, OUString() );
339 const OUString sServiceName = io_rDescriptor.getOrDefault( u"DocumentService"_ustr, OUString() );
340 const Reference< XInteractionHandler >
341 xInteraction = io_rDescriptor.getOrDefault( u"InteractionHandler"_ustr, Reference< XInteractionHandler >() );
343 const SfxFilterMatcher& rMatcher = SfxGetpApp()->GetFilterMatcher();
344 std::shared_ptr<const SfxFilter> pFilter;
346 // get filter by its name directly ...
347 if ( !sFilterName.isEmpty() )
348 pFilter = rMatcher.GetFilter4FilterName( sFilterName );
350 // or search the preferred filter for the detected type ...
351 if ( !pFilter && !sTypeName.isEmpty() )
352 pFilter = rMatcher.GetFilter4EA( sTypeName );
354 // or use given document service for detection, too
355 if ( !pFilter && !sServiceName.isEmpty() )
356 pFilter = impl_getFilterFromServiceName_nothrow( sServiceName );
358 // or use interaction to ask user for right filter.
359 if ( !pFilter && xInteraction.is() && !sURL.isEmpty() )
361 OUString sSelectedFilter = impl_askForFilter_nothrow( xInteraction, sURL );
362 if ( !sSelectedFilter.isEmpty() )
363 pFilter = rMatcher.GetFilter4FilterName( sSelectedFilter );
366 if ( !pFilter )
367 return;
369 io_rDescriptor.put( u"FilterName"_ustr, pFilter->GetFilterName() );
371 // If detected filter indicates using of an own template format
372 // add property "AsTemplate" to descriptor. But suppress this step
373 // if such property already exists.
374 if ( pFilter->IsOwnTemplateFormat() && !io_rDescriptor.has( u"AsTemplate"_ustr ) )
375 io_rDescriptor.put( u"AsTemplate"_ustr, true );
377 // The DocumentService property will finally be used to determine the document type to create, so
378 // override it with the service name as indicated by the found filter.
379 io_rDescriptor.put( u"DocumentService"_ustr, pFilter->GetServiceName() );
383 SfxObjectShellRef SfxFrameLoader_Impl::impl_findObjectShell( const Reference< XModel2 >& i_rxDocument )
385 for ( SfxObjectShell* pDoc = SfxObjectShell::GetFirst( nullptr, false ); pDoc;
386 pDoc = SfxObjectShell::GetNext( *pDoc, nullptr, false ) )
388 if ( i_rxDocument == pDoc->GetModel() )
390 return pDoc;
394 SAL_WARN( "sfx.view", "SfxFrameLoader_Impl::impl_findObjectShell: model is not based on SfxObjectShell - wrong frame loader usage!" );
395 return nullptr;
399 bool SfxFrameLoader_Impl::impl_determineTemplateDocument( ::comphelper::NamedValueCollection& io_rDescriptor ) const
403 const OUString sTemplateRegioName = io_rDescriptor.getOrDefault( u"TemplateRegionName"_ustr, OUString() );
404 const OUString sTemplateName = io_rDescriptor.getOrDefault( u"TemplateName"_ustr, OUString() );
405 const OUString sServiceName = io_rDescriptor.getOrDefault( u"DocumentService"_ustr, OUString() );
406 const OUString sURL = io_rDescriptor.getOrDefault( u"URL"_ustr, OUString() );
408 // determine the full URL of the template to use, if any
409 OUString sTemplateURL;
410 if ( !sTemplateRegioName.isEmpty() && !sTemplateName.isEmpty() )
412 SfxDocumentTemplates aTmpFac;
413 aTmpFac.GetFull( sTemplateRegioName, sTemplateName, sTemplateURL );
415 else
417 if ( !sServiceName.isEmpty() )
418 sTemplateURL = SfxObjectFactory::GetStandardTemplate( sServiceName );
419 else
420 sTemplateURL = SfxObjectFactory::GetStandardTemplate( SfxObjectShell::GetServiceNameFromFactory( sURL ) );
423 if ( !sTemplateURL.isEmpty() )
425 // detect the filter for the template. Might still be NULL (if the template is broken, or does not
426 // exist, or some such), but this is handled by our caller the same way as if no template/URL was present.
427 std::shared_ptr<const SfxFilter> pTemplateFilter = impl_detectFilterForURL( sTemplateURL, io_rDescriptor, SfxGetpApp()->GetFilterMatcher() );
428 if ( pTemplateFilter )
430 // load the template document, but, well, "as template"
431 io_rDescriptor.put( u"FilterName"_ustr, pTemplateFilter->GetName() );
432 io_rDescriptor.put( u"FileName"_ustr, sTemplateURL );
433 io_rDescriptor.put( u"AsTemplate"_ustr, true );
435 // #i21583#
436 // the DocumentService property will finally be used to create the document. Thus, override any possibly
437 // present value with the document service of the template.
438 io_rDescriptor.put( u"DocumentService"_ustr, pTemplateFilter->GetServiceName() );
439 return true;
443 catch (...)
446 return false;
450 sal_uInt16 SfxFrameLoader_Impl::impl_findSlotParam( std::u16string_view i_rFactoryURL )
452 std::u16string_view sSlotParam;
453 const size_t nParamPos = i_rFactoryURL.find( '?' );
454 if ( nParamPos != std::u16string_view::npos )
456 // currently only the "slot" parameter is supported
457 const size_t nSlotPos = i_rFactoryURL.find( u"slot=", nParamPos );
458 if ( nSlotPos > 0 && nSlotPos != std::u16string_view::npos )
459 sSlotParam = i_rFactoryURL.substr( nSlotPos + 5 );
462 if ( !sSlotParam.empty() )
463 return sal_uInt16( o3tl::toInt32(sSlotParam) );
465 return 0;
469 void SfxFrameLoader_Impl::impl_handleCaughtError_nothrow( const Any& i_rCaughtError, const ::comphelper::NamedValueCollection& i_rDescriptor )
473 const Reference< XInteractionHandler > xInteraction =
474 i_rDescriptor.getOrDefault( u"InteractionHandler"_ustr, Reference< XInteractionHandler >() );
475 if ( !xInteraction.is() )
476 return;
477 ::rtl::Reference< ::comphelper::OInteractionRequest > pRequest( new ::comphelper::OInteractionRequest( i_rCaughtError ) );
478 ::rtl::Reference< ::comphelper::OInteractionApprove > pApprove( new ::comphelper::OInteractionApprove );
479 pRequest->addContinuation( pApprove );
481 const Reference< XInteractionHandler2 > xHandler( xInteraction, UNO_QUERY );
482 #if OSL_DEBUG_LEVEL > 0
483 const bool bHandled =
484 #endif
485 xHandler.is() && xHandler->handleInteractionRequest( pRequest );
487 #if OSL_DEBUG_LEVEL > 0
488 if ( !bHandled )
489 // the interaction handler couldn't deal with this error
490 // => report it as assertion, at least (done in the DBG_UNHANDLED_EXCEPTION below)
491 ::cppu::throwException( i_rCaughtError );
492 #endif
494 catch( const Exception& )
496 DBG_UNHANDLED_EXCEPTION("sfx.view");
501 void SfxFrameLoader_Impl::impl_removeLoaderArguments( ::comphelper::NamedValueCollection& io_rDescriptor )
503 // remove the arguments which are for the loader only, and not for a call to attachResource
504 io_rDescriptor.remove( u"StatusIndicator"_ustr );
505 io_rDescriptor.remove( u"Model"_ustr );
509 ::comphelper::NamedValueCollection SfxFrameLoader_Impl::impl_extractViewCreationArgs( ::comphelper::NamedValueCollection& io_rDescriptor )
511 static const std::u16string_view sKnownViewArgs[] = { u"JumpMark", u"PickListEntry" };
513 ::comphelper::NamedValueCollection aViewArgs;
514 for (const auto& rKnownViewArg : sKnownViewArgs)
516 const OUString sKnownViewArg(rKnownViewArg);
517 if ( io_rDescriptor.has( sKnownViewArg ) )
519 aViewArgs.put( sKnownViewArg, io_rDescriptor.get( sKnownViewArg ) );
520 io_rDescriptor.remove( sKnownViewArg );
523 return aViewArgs;
527 SfxInterfaceId SfxFrameLoader_Impl::impl_determineEffectiveViewId_nothrow( const SfxObjectShell& i_rDocument, const ::comphelper::NamedValueCollection& i_rDescriptor )
529 SfxInterfaceId nViewId(i_rDescriptor.getOrDefault( u"ViewId"_ustr, sal_Int16( 0 ) ));
532 if ( nViewId == SFX_INTERFACE_NONE )
535 Reference< XViewDataSupplier > xViewDataSupplier( i_rDocument.GetModel(), UNO_QUERY );
536 Reference< XIndexAccess > xViewData;
537 if ( xViewDataSupplier.is() )
538 xViewData.set( xViewDataSupplier->getViewData() );
540 if ( !xViewData.is() || ( xViewData->getCount() == 0 ) )
541 // no view data stored together with the model
542 break;
544 // obtain the ViewID from the view data
545 Sequence< PropertyValue > aViewData;
546 if ( !( xViewData->getByIndex( 0 ) >>= aViewData ) )
547 break;
549 OUString sViewId = ::comphelper::NamedValueCollection::getOrDefault( aViewData, u"ViewId", OUString() );
550 if ( sViewId.isEmpty() )
551 break;
553 // somewhat weird convention here ... in the view data, the ViewId is a string, effectively describing
554 // a view name. In the document load descriptor, the ViewId is in fact the numeric ID.
556 SfxViewFactory* pViewFactory = i_rDocument.GetFactory().GetViewFactoryByViewName( sViewId );
557 if ( pViewFactory )
558 nViewId = pViewFactory->GetOrdinal();
560 while ( false );
562 catch( const Exception& )
564 DBG_UNHANDLED_EXCEPTION("sfx.view");
567 if ( nViewId == SFX_INTERFACE_NONE )
568 nViewId = i_rDocument.GetFactory().GetViewFactory().GetOrdinal();
569 return nViewId;
573 Reference< XController2 > SfxFrameLoader_Impl::impl_createDocumentView( const Reference< XModel2 >& i_rModel,
574 const Reference< XFrame >& i_rFrame, const ::comphelper::NamedValueCollection& i_rViewFactoryArgs,
575 const OUString& i_rViewName )
577 // let the model create a new controller
578 const Reference< XController2 > xController( i_rModel->createViewController(
579 i_rViewName,
580 i_rViewFactoryArgs.getPropertyValues(),
581 i_rFrame
582 ), UNO_SET_THROW );
584 // introduce model/view/controller to each other
585 utl::ConnectFrameControllerModel(i_rFrame, xController, i_rModel);
587 return xController;
590 std::shared_ptr<const SfxFilter> getEmptyURLFilter(std::u16string_view sURL)
592 INetURLObject aParser(sURL);
593 const OUString aExt = aParser.getExtension(INetURLObject::LAST_SEGMENT, true,
594 INetURLObject::DecodeMechanism::WithCharset);
595 const SfxFilterMatcher& rMatcher = SfxGetpApp()->GetFilterMatcher();
597 // Requiring the export+preferred flags helps to find the relevant filter, e.g. .doc -> WW8 (and
598 // not WW6 or Mac_Word).
599 std::shared_ptr<const SfxFilter> pFilter = rMatcher.GetFilter4Extension(
600 aExt, SfxFilterFlags::IMPORT | SfxFilterFlags::EXPORT | SfxFilterFlags::PREFERED);
601 if (!pFilter)
603 // retry without PREFERED so we can find at least something for 0-byte *.ods
604 pFilter
605 = rMatcher.GetFilter4Extension(aExt, SfxFilterFlags::IMPORT | SfxFilterFlags::EXPORT);
607 return pFilter;
610 sal_Bool SAL_CALL SfxFrameLoader_Impl::load( const Sequence< PropertyValue >& rArgs,
611 const Reference< XFrame >& _rTargetFrame )
613 ENSURE_OR_THROW( _rTargetFrame.is(), "illegal NULL frame" );
615 SAL_INFO( "sfx.view", "SfxFrameLoader::load" );
617 ::comphelper::NamedValueCollection aDescriptor( rArgs );
619 // ensure the descriptor contains a referrer
620 if ( !aDescriptor.has( u"Referer"_ustr ) )
621 aDescriptor.put( u"Referer"_ustr, OUString() );
623 // did the caller already pass a model?
624 Reference< XModel2 > xModel = aDescriptor.getOrDefault( u"Model"_ustr, Reference< XModel2 >() );
625 const bool bExternalModel = xModel.is();
627 // check for factory URLs to create a new doc, instead of loading one
628 const OUString sURL = aDescriptor.getOrDefault( u"URL"_ustr, OUString() );
629 const bool bIsFactoryURL = sURL.startsWith( "private:factory/" );
631 if (bIsFactoryURL && officecfg::Office::Common::Misc::ViewerAppMode::get())
632 return false;
634 std::shared_ptr<const SfxFilter> pEmptyURLFilter;
635 bool bInitNewModel = bIsFactoryURL;
636 const bool bIsDefault = bIsFactoryURL && !bExternalModel;
637 if (!aDescriptor.has(u"Replaceable"_ustr))
638 aDescriptor.put(u"Replaceable"_ustr, bIsDefault);
639 if (bIsDefault)
641 const OUString sFactory = sURL.copy( sizeof( "private:factory/" ) -1 );
642 // special handling for some weird factory URLs a la private:factory/swriter?slot=21053
643 const sal_uInt16 nSlotParam = impl_findSlotParam( sFactory );
644 if ( nSlotParam != 0 )
646 return impl_createNewDocWithSlotParam( nSlotParam, _rTargetFrame, aDescriptor.getOrDefault( u"Hidden"_ustr, false ) );
649 const bool bDescribesValidTemplate = impl_determineTemplateDocument( aDescriptor );
650 if ( bDescribesValidTemplate )
652 // if the media descriptor allowed us to determine a template document to create the new document
653 // from, then do not init a new document model from scratch (below), but instead load the
654 // template document
655 bInitNewModel = false;
657 else
659 const OUString sServiceName = SfxObjectShell::GetServiceNameFromFactory( sFactory );
660 aDescriptor.put( u"DocumentService"_ustr, sServiceName );
663 else
665 // compatibility
666 aDescriptor.put( u"FileName"_ustr, aDescriptor.get( u"URL"_ustr ) );
668 if (!bIsFactoryURL && !bExternalModel && tools::isEmptyFileUrl(sURL))
670 pEmptyURLFilter = getEmptyURLFilter(sURL);
671 if (pEmptyURLFilter)
673 aDescriptor.put(u"DocumentService"_ustr, pEmptyURLFilter->GetServiceName());
674 if (impl_determineTemplateDocument(aDescriptor))
676 // if the media descriptor allowed us to determine a template document
677 // to create the new document from, then do not init a new document model
678 // from scratch (below), but instead load the template document
679 bInitNewModel = false;
680 // Do not try to load from empty UCB content
681 aDescriptor.remove(u"UCBContent"_ustr);
683 else
685 bInitNewModel = true;
691 bool bLoadSuccess = false;
694 // extract view relevant arguments from the loader args
695 ::comphelper::NamedValueCollection aViewCreationArgs( impl_extractViewCreationArgs( aDescriptor ) );
697 // no model passed from outside? => create one from scratch
698 if ( !bExternalModel )
700 bool bInternalFilter = aDescriptor.getOrDefault<OUString>(u"FilterProvider"_ustr, OUString()).isEmpty();
702 if (bInternalFilter && !bInitNewModel)
704 // Ensure that the current SfxFilter instance is loaded before
705 // going further. We don't need to do this for external
706 // filter providers.
707 impl_determineFilter(aDescriptor);
710 // create the new doc
711 const OUString sServiceName = aDescriptor.getOrDefault( u"DocumentService"_ustr, OUString() );
712 xModel.set( m_aContext->getServiceManager()->createInstanceWithContext(sServiceName, m_aContext), UNO_QUERY_THROW );
714 // load resp. init it
715 const Reference< XLoadable > xLoadable( xModel, UNO_QUERY_THROW );
716 if ( bInitNewModel )
718 xLoadable->initNew();
720 impl_removeLoaderArguments( aDescriptor );
721 xModel->attachResource( OUString(), aDescriptor.getPropertyValues() );
723 else
725 xLoadable->load( aDescriptor.getPropertyValues() );
728 else
730 // tell the doc its (current) load args.
731 impl_removeLoaderArguments( aDescriptor );
732 xModel->attachResource( xModel->getURL(), aDescriptor.getPropertyValues() );
735 SolarMutexGuard aGuard;
737 // get the SfxObjectShell (still needed at the moment)
738 // SfxObjectShellRef is used here ( instead of ...Lock ) since the model is closed below if necessary
739 // SfxObjectShellLock would be even dangerous here, since the lifetime control should be done outside in case of success
740 const SfxObjectShellRef xDoc = impl_findObjectShell( xModel );
741 ENSURE_OR_THROW( xDoc.is(), "no SfxObjectShell for the given model" );
743 if (pEmptyURLFilter)
745 // Detach the medium from the template, and set proper document name and filter
746 auto pMedium = xDoc->GetMedium();
747 auto& rItemSet = pMedium->GetItemSet();
748 rItemSet.ClearItem(SID_TEMPLATE);
749 rItemSet.Put(SfxStringItem(SID_FILTER_NAME, pEmptyURLFilter->GetFilterName()));
750 pMedium->SetName(sURL, true);
751 pMedium->SetFilter(pEmptyURLFilter);
752 pMedium->GetInitFileDate(true);
753 xDoc->SetLoading(SfxLoadedFlags::NONE);
754 xDoc->FinishedLoading();
757 // ensure the ID of the to-be-created view is in the descriptor, if possible
758 const SfxInterfaceId nViewId = impl_determineEffectiveViewId_nothrow( *xDoc, aDescriptor );
759 const sal_Int16 nViewNo = xDoc->GetFactory().GetViewNo_Impl( nViewId, 0 );
760 const OUString sViewName( xDoc->GetFactory().GetViewFactory( nViewNo ).GetAPIViewName() );
762 // plug the document into the frame
763 Reference<XController2> xController =
764 impl_createDocumentView( xModel, _rTargetFrame, aViewCreationArgs, sViewName );
766 Reference<lang::XInitialization> xInit(xController, UNO_QUERY);
767 if (xInit.is())
769 uno::Sequence<uno::Any> aArgs; // empty for now.
770 xInit->initialize(aArgs);
773 bLoadSuccess = true;
775 catch ( Exception& )
777 const Any aError( ::cppu::getCaughtException() );
778 if ( !aDescriptor.getOrDefault( u"Silent"_ustr, false ) )
779 impl_handleCaughtError_nothrow( aError, aDescriptor );
782 // if loading was not successful, close the document
783 if ( !bLoadSuccess && !bExternalModel )
787 const Reference< XCloseable > xCloseable( xModel, UNO_QUERY_THROW );
788 xCloseable->close( true );
790 catch ( Exception& )
792 DBG_UNHANDLED_EXCEPTION("sfx.view");
796 return bLoadSuccess;
799 void SfxFrameLoader_Impl::cancel()
803 /* XServiceInfo */
804 OUString SAL_CALL SfxFrameLoader_Impl::getImplementationName()
806 return u"com.sun.star.comp.office.FrameLoader"_ustr;
809 /* XServiceInfo */
810 sal_Bool SAL_CALL SfxFrameLoader_Impl::supportsService( const OUString& sServiceName )
812 return cppu::supportsService(this, sServiceName);
815 /* XServiceInfo */
816 Sequence< OUString > SAL_CALL SfxFrameLoader_Impl::getSupportedServiceNames()
818 return { u"com.sun.star.frame.SynchronousFrameLoader"_ustr, u"com.sun.star.frame.OfficeFrameLoader"_ustr };
823 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
824 com_sun_star_comp_office_FrameLoader_get_implementation(
825 css::uno::XComponentContext *context,
826 css::uno::Sequence<css::uno::Any> const &)
828 return cppu::acquire(new SfxFrameLoader_Impl(context));
831 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */