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 .
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
;
94 class SfxFrameLoader_Impl
: public ::cppu::WeakImplHelper
< css::frame::XSynchronousFrameLoader
, css::lang::XServiceInfo
>
96 css::uno::Reference
< css::uno::XComponentContext
> m_aContext
;
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
;
114 virtual ~SfxFrameLoader_Impl() override
;
117 std::shared_ptr
<const SfxFilter
> impl_getFilterFromServiceName_nothrow(
118 const OUString
& i_rServiceName
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
132 static bool impl_createNewDocWithSlotParam(
133 const sal_uInt16 _nSlotID
,
134 const css::uno::Reference
< css::frame::XFrame
>& i_rxFrame
,
138 void impl_determineFilter(
139 ::comphelper::NamedValueCollection
& io_rDescriptor
142 bool impl_determineTemplateDocument(
143 ::comphelper::NamedValueCollection
& io_rDescriptor
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
198 if ( sURL
.isEmpty() )
201 Reference
< XTypeDetection
> xDetect(
202 m_aContext
->getServiceManager()->createInstanceWithContext(u
"com.sun.star.document.TypeDetection"_ustr
, m_aContext
),
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
);
219 sFilter
= pFilter
->GetName();
222 catch ( const RuntimeException
& )
226 catch( const Exception
& )
228 DBG_UNHANDLED_EXCEPTION("sfx.view");
232 std::shared_ptr
<const SfxFilter
> pFilter
;
233 if (!sFilter
.isEmpty())
234 pFilter
= rMatcher
.GetFilter4FilterName(sFilter
);
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
),
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() )
263 std::shared_ptr
<const SfxFilter
> pFilter
= rMatcher
.GetFilter4FilterName( sFilterName
);
267 SfxFilterFlags nFlags
= pFilter
->GetFilterFlags();
268 if ( ( ( nFlags
& nMust
) == nMust
)
269 && ( ( nFlags
& nDont
) == SfxFilterFlags::NONE
)
276 catch( const Exception
& )
278 DBG_UNHANDLED_EXCEPTION("sfx.view");
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");
305 bool lcl_getDispatchResult(const SfxPoolItemHolder
& rResult
)
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()));
318 bSuccess
= pItem
->GetValue();
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
) );
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
);
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() )
394 SAL_WARN( "sfx.view", "SfxFrameLoader_Impl::impl_findObjectShell: model is not based on SfxObjectShell - wrong frame loader usage!" );
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
);
417 if ( !sServiceName
.isEmpty() )
418 sTemplateURL
= SfxObjectFactory::GetStandardTemplate( sServiceName
);
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 );
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() );
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
) );
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() )
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
=
485 xHandler
.is() && xHandler
->handleInteractionRequest( pRequest
);
487 #if OSL_DEBUG_LEVEL > 0
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
);
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
);
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
544 // obtain the ViewID from the view data
545 Sequence
< PropertyValue
> aViewData
;
546 if ( !( xViewData
->getByIndex( 0 ) >>= aViewData
) )
549 OUString sViewId
= ::comphelper::NamedValueCollection::getOrDefault( aViewData
, u
"ViewId", OUString() );
550 if ( sViewId
.isEmpty() )
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
);
558 nViewId
= pViewFactory
->GetOrdinal();
562 catch( const Exception
& )
564 DBG_UNHANDLED_EXCEPTION("sfx.view");
567 if ( nViewId
== SFX_INTERFACE_NONE
)
568 nViewId
= i_rDocument
.GetFactory().GetViewFactory().GetOrdinal();
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(
580 i_rViewFactoryArgs
.getPropertyValues(),
584 // introduce model/view/controller to each other
585 utl::ConnectFrameControllerModel(i_rFrame
, xController
, i_rModel
);
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
);
603 // retry without PREFERED so we can find at least something for 0-byte *.ods
605 = rMatcher
.GetFilter4Extension(aExt
, SfxFilterFlags::IMPORT
| SfxFilterFlags::EXPORT
);
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())
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
);
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
655 bInitNewModel
= false;
659 const OUString sServiceName
= SfxObjectShell::GetServiceNameFromFactory( sFactory
);
660 aDescriptor
.put( u
"DocumentService"_ustr
, sServiceName
);
666 aDescriptor
.put( u
"FileName"_ustr
, aDescriptor
.get( u
"URL"_ustr
) );
668 if (!bIsFactoryURL
&& !bExternalModel
&& tools::isEmptyFileUrl(sURL
))
670 pEmptyURLFilter
= getEmptyURLFilter(sURL
);
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
);
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
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
);
718 xLoadable
->initNew();
720 impl_removeLoaderArguments( aDescriptor
);
721 xModel
->attachResource( OUString(), aDescriptor
.getPropertyValues() );
725 xLoadable
->load( aDescriptor
.getPropertyValues() );
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" );
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
);
769 uno::Sequence
<uno::Any
> aArgs
; // empty for now.
770 xInit
->initialize(aArgs
);
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 );
792 DBG_UNHANDLED_EXCEPTION("sfx.view");
799 void SfxFrameLoader_Impl::cancel()
804 OUString SAL_CALL
SfxFrameLoader_Impl::getImplementationName()
806 return u
"com.sun.star.comp.office.FrameLoader"_ustr
;
810 sal_Bool SAL_CALL
SfxFrameLoader_Impl::supportsService( const OUString
& sServiceName
)
812 return cppu::supportsService(this, sServiceName
);
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: */