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