/* -*- 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 .
*/
std::shared_ptr<const SfxFilter> SfxFilterContainer::GetDefaultFilter_Impl( std::u16string_view rName )
{ // Try to find out the type of factory. // Interpret given name as Service- and ShortName!
SvtModuleOptions aOpt;
SvtModuleOptions::EFactory eFactory = SvtModuleOptions::ClassifyFactoryByServiceName(rName); if (eFactory == SvtModuleOptions::EFactory::UNKNOWN_FACTORY)
eFactory = SvtModuleOptions::ClassifyFactoryByShortName(rName);
// could not classify factory by its service nor by its short name. // Must be an unknown factory! => return NULL if (eFactory == SvtModuleOptions::EFactory::UNKNOWN_FACTORY) return nullptr;
// For the following code we need some additional information. const OUString& sServiceName = aOpt.GetFactoryName(eFactory);
OUString sDefaultFilter = aOpt.GetFactoryDefaultFilter(eFactory);
// Try to get the default filter. Don't forget to verify it. // May the set default filter does not exists any longer or // does not fit the given factory. const SfxFilterMatcher aMatcher;
std::shared_ptr<const SfxFilter> pFilter = aMatcher.GetFilter4FilterName(sDefaultFilter);
// If at least no default filter could be located - use any filter of this // factory. if (!pFilter)
{ if ( bFirstRead )
ReadFilters_Impl();
for (const std::shared_ptr<const SfxFilter>& pCheckFilter : *pFilterArr)
{ if ( pCheckFilter->GetServiceName().equalsIgnoreAsciiCase(sServiceName) )
{
pFilter = pCheckFilter; break;
}
}
}
return pFilter;
}
// Impl-Data is shared between all FilterMatchers of the same factory class SfxFilterMatcher_Impl
{ public:
OUString aName; mutable SfxFilterList_Impl* pList; // is created on demand
void InitForIterating() const; void Update() const; explicit SfxFilterMatcher_Impl(OUString _aName)
: aName(std::move(_aName))
, pList(nullptr)
{
}
~SfxFilterMatcher_Impl()
{ // SfxFilterMatcher_Impl::InitForIterating() will set pList to // either the global filter array matcher pFilterArr, or to // a new SfxFilterList_Impl. if (pList != pFilterArr) delete pList;
}
};
namespace
{
std::vector<std::unique_ptr<SfxFilterMatcher_Impl> > aImplArr; int nSfxFilterMatcherCount;
if (!rName.isEmpty())
aName = SfxObjectShell::GetServiceNameFromFactory(rName);
// find the impl-Data of any comparable FilterMatcher that was created // previously for (std::unique_ptr<SfxFilterMatcher_Impl>& aImpl : aImplArr) if (aImpl->aName == aName) return *aImpl;
// first Matcher created for this factory
aImplArr.push_back(std::make_unique<SfxFilterMatcher_Impl>(aName)); return *aImplArr.back();
}
}
SfxFilterMatcher::SfxFilterMatcher()
: m_rImpl( getSfxFilterMatcher_Impl(OUString()) )
{ // global FilterMatcher always uses global filter array (also created on // demand)
++nSfxFilterMatcherCount;
}
SfxFilterMatcher::~SfxFilterMatcher()
{
--nSfxFilterMatcherCount; if (nSfxFilterMatcherCount == 0)
aImplArr.clear();
}
void SfxFilterMatcher_Impl::Update() const
{ if ( pList )
{ // this List was already used
pList->clear(); for (const std::shared_ptr<const SfxFilter>& pFilter : *pFilterArr)
{ if ( pFilter->GetServiceName() == aName )
pList->push_back( pFilter );
}
}
}
void SfxFilterMatcher_Impl::InitForIterating() const
{ if ( pList ) return;
if ( bFirstRead ) // global filter array has not been created yet
SfxFilterContainer::ReadFilters_Impl();
if ( !aName.isEmpty() )
{ // matcher of factory: use only filters of that document type
pList = new SfxFilterList_Impl;
Update();
} else
{ // global matcher: use global filter array
pList = pFilterArr;
}
}
// no detection service -> nothing to do !
uno::Reference<document::XTypeDetection> xDetection(
comphelper::getProcessServiceFactory()->createInstance(u"com.sun.star.document.TypeDetection"_ustr), uno::UNO_QUERY);
if (!xDetection.is()) return ERRCODE_ABORT;
try
{ // open the stream one times only ... // Otherwise it will be tried more than once and show the same interaction more than once ...
uno::Sequence< beans::PropertyValue > lDescriptor = aDescriptor.getAsConstPropertyValueList();
sTypeName = xDetection->queryTypeByDescriptor(lDescriptor, true); // lDescriptor is used as In/Out param ... don't use aDescriptor.getAsConstPropertyValueList() directly!
for (constauto& rProp : lDescriptor)
{ if (rProp.Name == "FilterName") // Type detection picked a preferred filter for this format.
aFilterName = rProp.Value.get<OUString>();
}
} // no stream exists => try flat detection without preselection as fallback else
sTypeName = xDetection->queryTypeByURL(sURL);
if (!sTypeName.isEmpty())
{
std::shared_ptr<const SfxFilter> xNewFilter; if (!aFilterName.isEmpty()) // Type detection returned a suitable filter for this. Use it.
xNewFilter = SfxFilter::GetFilterByName(aFilterName);
// fdo#78742 respect requested document service if set if (!xNewFilter || (!m_rImpl.aName.isEmpty()
&& m_rImpl.aName != xNewFilter->GetServiceName()))
{ // detect filter by given type // In case of this matcher is bound to a particular document type: // If there is no acceptable type for this document at all, the type detection has possibly returned something else. // The DocumentService property is only a preselection, and all preselections are considered as optional! // This "wrong" type will be sorted out now because we match only allowed filters to the detected type
uno::Sequence< beans::NamedValue > lQuery { { u"Name"_ustr, css::uno::Any(sTypeName) } };
xNewFilter = GetFilterForProps(lQuery, nMust, nDont); if (xNewFilter && xNewFilter->GetFilterName().endsWith("_pdf_addstream_import")
&& aFilterName.endsWith("_pdf_import")
&& sTypeName == "pdf_Portable_Document_Format")
{ // pdf_Portable_Document_Format covers two sets of import filters: normal PDF // (like draw_pdf_import), and hybrid (like calc_pdf_addstream_import). // Type detection didn't detect hybrid PDF; this new filter can't match
xNewFilter.reset();
}
}
bool SfxFilterMatcher::IsFilterInstalled_Impl( const std::shared_ptr<const SfxFilter>& pFilter )
{ if ( pFilter->GetFilterFlags() & SfxFilterFlags::MUSTINSTALL )
{ // Here could a re-installation be offered
OUString aText( SfxResId(STR_FILTER_NOT_INSTALLED) );
aText = aText.replaceFirst( "$(FILTER)", pFilter->GetUIName() );
std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(nullptr,
VclMessageType::Question, VclButtonsType::YesNo,
aText));
xQueryBox->set_default_response(RET_YES);
short nRet = xQueryBox->run(); if ( nRet == RET_YES )
{ #ifdef DBG_UTIL // Start Setup
std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(nullptr,
VclMessageType::Info, VclButtonsType::Ok,
u"Here should the Setup now be starting!"_ustr));
xInfoBox->run(); #endif // Installation must still give feedback if it worked or not, // then the Filterflag be deleted
}
if ( !pFilter )
{
std::shared_ptr<const SfxFilter> pInstallFilter;
// Now test the filter which are not installed (ErrCode is irrelevant)
GuessFilter( rMedium, pInstallFilter, SfxFilterFlags::IMPORT, SfxFilterFlags::CONSULTSERVICE ); if ( pInstallFilter )
{ if ( IsFilterInstalled_Impl( pInstallFilter ) )
{ // Maybe the filter was installed afterwards.
pFilter = std::move(pInstallFilter);
}
} else
{ // Now test the filter, which first must be obtained by Star // (ErrCode is irrelevant)
GuessFilter( rMedium, pInstallFilter, SfxFilterFlags::IMPORT, SfxFilterFlags::NONE ); if ( pInstallFilter )
IsFilterInstalled_Impl( pInstallFilter );
}
}
// try to get the preferred filter (works without loading all filters!) if ( !aValue.isEmpty() )
{
std::shared_ptr<const SfxFilter> pFilter = SfxFilter::GetFilterByName( aValue ); if ( !pFilter || (pFilter->GetFilterFlags() & nMust) != nMust || (pFilter->GetFilterFlags() & nDont ) ) // check for filter flags // pFilter == 0: if preferred filter is a Writer filter, but Writer module is not installed continue;
if ( !m_rImpl.aName.isEmpty() )
{ // if this is not the global FilterMatcher: check if filter matches the document type if ( pFilter->GetServiceName() != m_rImpl.aName )
{ // preferred filter belongs to another document type; now we must search the filter
m_rImpl.InitForIterating();
pFilter = GetFilter4EA( aName, nMust, nDont ); if ( pFilter ) return pFilter;
} else return pFilter;
} else return pFilter;
}
}
// Don't forget to set right UIName! // Otherwise internal name is used as fallback ...
pFilt->SetUIName( sUIName );
pFilt->SetDefaultTemplate( sDefaultTemplate ); if( nFormatVersion )
{
pFilt->SetVersion( nFormatVersion );
}
}
try
{ // get the FilterFactory service to access the registered filters ... and types!
uno::Reference< lang::XMultiServiceFactory > xServiceManager = ::comphelper::getProcessServiceFactory();
uno::Reference< container::XNameAccess > xFilterCFG ;
uno::Reference< container::XNameAccess > xTypeCFG ; if( xServiceManager.is() )
{
xFilterCFG.set( xServiceManager->createInstance( u"com.sun.star.document.FilterFactory"_ustr ), uno::UNO_QUERY );
xTypeCFG.set( xServiceManager->createInstance( u"com.sun.star.document.TypeDetection"_ustr ), uno::UNO_QUERY );
}
if( xFilterCFG.is() && xTypeCFG.is() )
{ // select right query to get right set of filters for search module const uno::Sequence< OUString > lFilterNames = xFilterCFG->getElementNames(); if ( lFilterNames.hasElements() )
{ // If list of filters already exist ... // ReadExternalFilters must work in update mode. // Best way seems to mark all filters NOT_INSTALLED // and change it back for all valid filters afterwards. if( !rList.empty() )
{
bUpdate = true; for (const std::shared_ptr<const SfxFilter>& pFilter : rList)
{
SfxFilter* pNonConstFilter = const_cast<SfxFilter*>(pFilter.get());
pNonConstFilter->nFormatType |= SFX_FILTER_NOTINSTALLED;
}
}
// get all properties of filters ... put it into the filter container for( const OUString& sFilterName : lFilterNames )
{ // Try to get filter .. but look for any exceptions! // May be filter was deleted by another thread ...
ReadSingleFilter_Impl( sFilterName, xTypeCFG, xFilterCFG, bUpdate );
}
}
}
} catch(const uno::Exception&)
{
SAL_WARN( "sfx.bastyp", "SfxFilterContainer::ReadFilter()\nException detected. Possible not all filters could be cached." );
}
if ( bUpdate )
{ // global filter array was modified, factory specific ones might need an // update too for (constauto& aImpl : aImplArr)
aImpl->Update();
}
}
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.