/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
usingnamespace com::sun::star; using ::com::sun::star::beans::PropertyValue; using ::com::sun::star::container::XContainerQuery; using ::com::sun::star::container::XEnumeration; using ::com::sun::star::document::XTypeDetection; using ::com::sun::star::frame::XFrame; using ::com::sun::star::frame::XLoadable; using ::com::sun::star::task::XInteractionHandler; using ::com::sun::star::task::XInteractionHandler2; using ::com::sun::star::uno::Any; using ::com::sun::star::uno::Exception; using ::com::sun::star::uno::Reference; using ::com::sun::star::uno::RuntimeException; using ::com::sun::star::uno::Sequence; using ::com::sun::star::uno::UNO_QUERY; using ::com::sun::star::uno::UNO_QUERY_THROW; using ::com::sun::star::uno::UNO_SET_THROW; using ::com::sun::star::util::XCloseable; using ::com::sun::star::document::XViewDataSupplier; using ::com::sun::star::container::XIndexAccess; using ::com::sun::star::frame::XController2; using ::com::sun::star::frame::XModel2;
namespace {
class SfxFrameLoader_Impl : public ::cppu::WeakImplHelper< css::frame::XSynchronousFrameLoader, css::lang::XServiceInfo >
{
css::uno::Reference < css::uno::XComponentContext > m_aContext;
bool lcl_getDispatchResult(const SfxPoolItemHolder& rResult)
{ if (!rResult) returnfalse;
// default must be set to true, because some return values // can't be checked, but nonetheless indicate "success"! bool bSuccess = true;
// On the other side some special slots return a boolean state, // which can be set to FALSE. const SfxBoolItem* pItem(dynamic_cast<const SfxBoolItem*>(rResult.getItem())); if ( pItem )
bSuccess = pItem->GetValue();
// get filter by its name directly ... if ( !sFilterName.isEmpty() )
pFilter = rMatcher.GetFilter4FilterName( sFilterName );
// or search the preferred filter for the detected type ... if ( !pFilter && !sTypeName.isEmpty() )
pFilter = rMatcher.GetFilter4EA( sTypeName );
// or use given document service for detection, too if ( !pFilter && !sServiceName.isEmpty() )
pFilter = impl_getFilterFromServiceName_nothrow( sServiceName );
// or use interaction to ask user for right filter. if ( !pFilter && xInteraction.is() && !sURL.isEmpty() )
{
OUString sSelectedFilter = impl_askForFilter_nothrow( xInteraction, sURL ); if ( !sSelectedFilter.isEmpty() )
pFilter = rMatcher.GetFilter4FilterName( sSelectedFilter );
}
// If detected filter indicates using of an own template format // add property "AsTemplate" to descriptor. But suppress this step // if such property already exists. if ( pFilter->IsOwnTemplateFormat() && !io_rDescriptor.has( u"AsTemplate"_ustr ) )
io_rDescriptor.put( u"AsTemplate"_ustr, true );
// The DocumentService property will finally be used to determine the document type to create, so // override it with the service name as indicated by the found filter.
io_rDescriptor.put( u"DocumentService"_ustr, pFilter->GetServiceName() );
}
SAL_WARN( "sfx.view", "SfxFrameLoader_Impl::impl_findObjectShell: model is not based on SfxObjectShell - wrong frame loader usage!" ); return nullptr;
}
// determine the full URL of the template to use, if any
OUString sTemplateURL; if ( !sTemplateRegioName.isEmpty() && !sTemplateName.isEmpty() )
{
SfxDocumentTemplates aTmpFac;
aTmpFac.GetFull( sTemplateRegioName, sTemplateName, sTemplateURL );
} else
{ if ( !sServiceName.isEmpty() )
sTemplateURL = SfxObjectFactory::GetStandardTemplate( sServiceName ); else
sTemplateURL = SfxObjectFactory::GetStandardTemplate( SfxObjectShell::GetServiceNameFromFactory( sURL ) ); // tdf#165851 expand trusted urls from configuration here
sTemplateURL = comphelper::getExpandedUri(m_aContext, sTemplateURL);
}
if ( !sTemplateURL.isEmpty() )
{ // detect the filter for the template. Might still be NULL (if the template is broken, or does not // exist, or some such), but this is handled by our caller the same way as if no template/URL was present.
std::shared_ptr<const SfxFilter> pTemplateFilter = impl_detectFilterForURL( sTemplateURL, io_rDescriptor, SfxGetpApp()->GetFilterMatcher() ); if ( pTemplateFilter )
{ // load the template document, but, well, "as template"
io_rDescriptor.put( u"FilterName"_ustr, pTemplateFilter->GetName() );
io_rDescriptor.put( u"FileName"_ustr, sTemplateURL );
io_rDescriptor.put( u"AsTemplate"_ustr, true );
// #i21583# // the DocumentService property will finally be used to create the document. Thus, override any possibly // present value with the document service of the template.
io_rDescriptor.put( u"DocumentService"_ustr, pTemplateFilter->GetServiceName() ); returntrue;
}
}
} catch (...)
{
} returnfalse;
}
sal_uInt16 SfxFrameLoader_Impl::impl_findSlotParam( std::u16string_view i_rFactoryURL )
{
std::u16string_view sSlotParam; const size_t nParamPos = i_rFactoryURL.find( '?' ); if ( nParamPos != std::u16string_view::npos )
{ // currently only the "slot" parameter is supported const size_t nSlotPos = i_rFactoryURL.find( u"slot=", nParamPos ); if ( nSlotPos > 0 && nSlotPos != std::u16string_view::npos )
sSlotParam = i_rFactoryURL.substr( nSlotPos + 5 );
}
if ( !sSlotParam.empty() ) return sal_uInt16( o3tl::toInt32(sSlotParam) );
#if OSL_DEBUG_LEVEL > 0 if ( !bHandled ) // the interaction handler couldn't deal with this error // => report it as assertion, at least (done in the DBG_UNHANDLED_EXCEPTION below)
::cppu::throwException( i_rCaughtError ); #endif
} catch( const Exception& )
{
DBG_UNHANDLED_EXCEPTION("sfx.view");
}
}
void SfxFrameLoader_Impl::impl_removeLoaderArguments( ::comphelper::NamedValueCollection& io_rDescriptor )
{ // remove the arguments which are for the loader only, and not for a call to attachResource
io_rDescriptor.remove( u"StatusIndicator"_ustr );
io_rDescriptor.remove( u"Model"_ustr );
}
// somewhat weird convention here ... in the view data, the ViewId is a string, effectively describing // a view name. In the document load descriptor, the ViewId is in fact the numeric ID.
// Requiring the export+preferred flags helps to find the relevant filter, e.g. .doc -> WW8 (and // not WW6 or Mac_Word).
std::shared_ptr<const SfxFilter> pFilter = rMatcher.GetFilter4Extension(
aExt, SfxFilterFlags::IMPORT | SfxFilterFlags::EXPORT | SfxFilterFlags::PREFERED); if (!pFilter)
{ // retry without PREFERED so we can find at least something for 0-byte *.ods
pFilter
= rMatcher.GetFilter4Extension(aExt, SfxFilterFlags::IMPORT | SfxFilterFlags::EXPORT);
} return pFilter;
}
// check for factory URLs to create a new doc, instead of loading one const OUString sURL = aDescriptor.getOrDefault( u"URL"_ustr, OUString() ); constbool bIsFactoryURL = sURL.startsWith( "private:factory/" );
if (bIsFactoryURL && officecfg::Office::Common::Misc::ViewerAppMode::get()) returnfalse;
std::shared_ptr<const SfxFilter> pEmptyURLFilter; bool bInitNewModel = bIsFactoryURL; constbool bIsDefault = bIsFactoryURL && !bExternalModel; if (!aDescriptor.has(u"Replaceable"_ustr))
aDescriptor.put(u"Replaceable"_ustr, bIsDefault); if (bIsDefault)
{ const OUString sFactory = sURL.copy( sizeof( "private:factory/" ) -1 ); // special handling for some weird factory URLs a la private:factory/swriter?slot=21053 const sal_uInt16 nSlotParam = impl_findSlotParam( sFactory ); if ( nSlotParam != 0 )
{ return impl_createNewDocWithSlotParam( nSlotParam, _rTargetFrame, aDescriptor.getOrDefault( u"Hidden"_ustr, false ) );
}
constbool bDescribesValidTemplate = impl_determineTemplateDocument( aDescriptor ); if ( bDescribesValidTemplate )
{ // if the media descriptor allowed us to determine a template document to create the new document // from, then do not init a new document model from scratch (below), but instead load the // template document
bInitNewModel = false;
} else
{ const OUString sServiceName = SfxObjectShell::GetServiceNameFromFactory( sFactory );
aDescriptor.put( u"DocumentService"_ustr, sServiceName );
}
} else
{ // compatibility
aDescriptor.put( u"FileName"_ustr, aDescriptor.get( u"URL"_ustr ) );
if (!bIsFactoryURL && !bExternalModel && tools::isEmptyFileUrl(sURL))
{
pEmptyURLFilter = getEmptyURLFilter(sURL); if (pEmptyURLFilter)
{
aDescriptor.put(u"DocumentService"_ustr, pEmptyURLFilter->GetServiceName()); if (impl_determineTemplateDocument(aDescriptor))
{ // if the media descriptor allowed us to determine a template document // to create the new document from, then do not init a new document model // from scratch (below), but instead load the template document
bInitNewModel = false; // Do not try to load from empty UCB content
aDescriptor.remove(u"UCBContent"_ustr);
} else
{
bInitNewModel = true;
}
}
}
}
// no model passed from outside? => create one from scratch if ( !bExternalModel )
{ bool bInternalFilter = aDescriptor.getOrDefault<OUString>(u"FilterProvider"_ustr, OUString()).isEmpty();
if (bInternalFilter && !bInitNewModel)
{ // Ensure that the current SfxFilter instance is loaded before // going further. We don't need to do this for external // filter providers.
impl_determineFilter(aDescriptor);
}
// create the new doc const OUString sServiceName = aDescriptor.getOrDefault( u"DocumentService"_ustr, OUString() );
xModel.set( m_aContext->getServiceManager()->createInstanceWithContext(sServiceName, m_aContext), UNO_QUERY_THROW );
// load resp. init it const Reference< XLoadable > xLoadable( xModel, UNO_QUERY_THROW ); if ( bInitNewModel )
{
xLoadable->initNew();
// get the SfxObjectShell (still needed at the moment) // SfxObjectShellRef is used here ( instead of ...Lock ) since the model is closed below if necessary // SfxObjectShellLock would be even dangerous here, since the lifetime control should be done outside in case of success const SfxObjectShellRef xDoc = impl_findObjectShell( xModel );
ENSURE_OR_THROW( xDoc.is(), "no SfxObjectShell for the given model" );
if (pEmptyURLFilter)
{ // Detach the medium from the template, and set proper document name and filter auto pMedium = xDoc->GetMedium(); auto& rItemSet = pMedium->GetItemSet();
rItemSet.ClearItem(SID_TEMPLATE);
rItemSet.Put(SfxStringItem(SID_FILTER_NAME, pEmptyURLFilter->GetFilterName()));
pMedium->SetName(sURL, true);
pMedium->SetFilter(pEmptyURLFilter);
pMedium->GetInitFileDate(true);
xDoc->SetLoading(SfxLoadedFlags::NONE);
xDoc->FinishedLoading();
}
// ensure the ID of the to-be-created view is in the descriptor, if possible const SfxInterfaceId nViewId = impl_determineEffectiveViewId_nothrow( *xDoc, aDescriptor ); const sal_Int16 nViewNo = xDoc->GetFactory().GetViewNo_Impl( nViewId, 0 ); const OUString sViewName( xDoc->GetFactory().GetViewFactory( nViewNo ).GetAPIViewName() );
// plug the document into the frame
Reference<XController2> xController =
impl_createDocumentView( xModel, _rTargetFrame, aViewCreationArgs, sViewName );
Reference<lang::XInitialization> xInit(xController, UNO_QUERY); if (xInit.is())
{
uno::Sequence<uno::Any> aArgs; // empty for now.
xInit->initialize(aArgs);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.