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