Version 7.1.7.1, tag libreoffice-7.1.7.1
[LibreOffice.git] / sfx2 / source / bastyp / fltfnc.cxx
blobf1d3ac399f27c41b2d393d0dfe54967c60932a00
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 <com/sun/star/uno/Exception.hpp>
22 #include <com/sun/star/beans/PropertyValue.hpp>
23 #include <com/sun/star/beans/NamedValue.hpp>
24 #include <com/sun/star/container/XNameAccess.hpp>
25 #include <com/sun/star/container/XEnumeration.hpp>
26 #include <com/sun/star/document/XTypeDetection.hpp>
27 #include <com/sun/star/container/XContainerQuery.hpp>
28 #include <com/sun/star/io/XInputStream.hpp>
29 #include <com/sun/star/task/XInteractionHandler.hpp>
30 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
32 #include <comphelper/sequenceashashmap.hxx>
34 #include <sot/exchange.hxx>
35 #include <vcl/svapp.hxx>
36 #include <vcl/weld.hxx>
37 #include <rtl/ustring.hxx>
38 #include <rtl/ustrbuf.hxx>
39 #include <sal/log.hxx>
40 #include <svl/stritem.hxx>
42 #include <comphelper/processfactory.hxx>
44 #include <sal/types.h>
45 #include <com/sun/star/uno/Reference.hxx>
46 #include <unotools/moduleoptions.hxx>
47 #include <unotools/mediadescriptor.hxx>
48 #include <tools/urlobj.hxx>
50 #include <rtl/instance.hxx>
52 #include <unotools/syslocale.hxx>
53 #include <unotools/charclass.hxx>
55 #include <sfx2/docfilt.hxx>
56 #include <sfx2/fcontnr.hxx>
57 #include <sfxtypes.hxx>
58 #include <sfx2/docfile.hxx>
59 #include <sfx2/strings.hrc>
60 #include <sfx2/sfxresid.hxx>
61 #include <sfx2/objsh.hxx>
62 #include <sfx2/sfxsids.hrc>
63 #include "fltlst.hxx"
64 #include <arrdecl.hxx>
66 #include <vector>
67 #include <memory>
69 #if defined(DBG_UTIL)
70 unsigned SfxStack::nLevel = 0;
71 #endif
73 using namespace com::sun::star;
75 namespace
77 class theSfxFilterListener : public rtl::Static<SfxFilterListener, theSfxFilterListener> {};
78 class SfxFilterArray
80 SfxFilterList_Impl aList;
81 public:
83 SfxFilterList_Impl& getList()
85 return aList;
88 class theSfxFilterArray : public rtl::Static<SfxFilterArray, theSfxFilterArray > {};
91 static SfxFilterList_Impl* pFilterArr = nullptr;
92 static bool bFirstRead = true;
94 static void CreateFilterArr()
96 pFilterArr = &theSfxFilterArray::get().getList();
97 theSfxFilterListener::get();
100 static OUString ToUpper_Impl( const OUString &rStr )
102 return SvtSysLocale().GetCharClass().uppercase( rStr );
105 class SfxFilterContainer_Impl
107 public:
108 OUString aName;
110 explicit SfxFilterContainer_Impl( const OUString& rName )
111 : aName( rName )
116 std::shared_ptr<const SfxFilter> SfxFilterContainer::GetFilter4EA(const OUString& rEA, SfxFilterFlags nMust, SfxFilterFlags nDont) const
118 SfxFilterMatcher aMatch(pImpl->aName);
119 return aMatch.GetFilter4EA(rEA, nMust, nDont);
122 std::shared_ptr<const SfxFilter> SfxFilterContainer::GetFilter4Extension(const OUString& rExt, SfxFilterFlags nMust, SfxFilterFlags nDont) const
124 SfxFilterMatcher aMatch(pImpl->aName);
125 return aMatch.GetFilter4Extension(rExt, nMust, nDont);
128 std::shared_ptr<const SfxFilter> SfxFilterContainer::GetFilter4FilterName(const OUString& rName, SfxFilterFlags nMust, SfxFilterFlags nDont) const
130 SfxFilterMatcher aMatch(pImpl->aName);
131 return aMatch.GetFilter4FilterName(rName, nMust, nDont);
134 std::shared_ptr<const SfxFilter> SfxFilterContainer::GetAnyFilter( SfxFilterFlags nMust, SfxFilterFlags nDont ) const
136 SfxFilterMatcher aMatch( pImpl->aName );
137 return aMatch.GetAnyFilter( nMust, nDont );
141 SfxFilterContainer::SfxFilterContainer( const OUString& rName )
142 : pImpl( new SfxFilterContainer_Impl( rName ) )
147 SfxFilterContainer::~SfxFilterContainer()
152 OUString const & SfxFilterContainer::GetName() const
154 return pImpl->aName;
157 std::shared_ptr<const SfxFilter> SfxFilterContainer::GetDefaultFilter_Impl( const OUString& rName )
159 // Try to find out the type of factory.
160 // Interpret given name as Service- and ShortName!
161 SvtModuleOptions aOpt;
162 SvtModuleOptions::EFactory eFactory = SvtModuleOptions::ClassifyFactoryByServiceName(rName);
163 if (eFactory == SvtModuleOptions::EFactory::UNKNOWN_FACTORY)
164 eFactory = SvtModuleOptions::ClassifyFactoryByShortName(rName);
166 // could not classify factory by its service nor by its short name.
167 // Must be an unknown factory! => return NULL
168 if (eFactory == SvtModuleOptions::EFactory::UNKNOWN_FACTORY)
169 return nullptr;
171 // For the following code we need some additional information.
172 OUString sServiceName = aOpt.GetFactoryName(eFactory);
173 OUString sDefaultFilter = aOpt.GetFactoryDefaultFilter(eFactory);
175 // Try to get the default filter. Don't forget to verify it.
176 // May the set default filter does not exists any longer or
177 // does not fit the given factory.
178 const SfxFilterMatcher aMatcher;
179 std::shared_ptr<const SfxFilter> pFilter = aMatcher.GetFilter4FilterName(sDefaultFilter);
181 if (
182 pFilter &&
183 !pFilter->GetServiceName().equalsIgnoreAsciiCase(sServiceName)
186 pFilter = nullptr;
189 // If at least no default filter could be located - use any filter of this
190 // factory.
191 if (!pFilter)
193 if ( bFirstRead )
194 ReadFilters_Impl();
196 for (const std::shared_ptr<const SfxFilter>& pCheckFilter : *pFilterArr)
198 if ( pCheckFilter->GetServiceName().equalsIgnoreAsciiCase(sServiceName) )
200 pFilter = pCheckFilter;
201 break;
206 return pFilter;
210 // Impl-Data is shared between all FilterMatchers of the same factory
211 class SfxFilterMatcher_Impl
213 public:
214 OUString aName;
215 mutable SfxFilterList_Impl* pList; // is created on demand
217 void InitForIterating() const;
218 void Update() const;
219 explicit SfxFilterMatcher_Impl(const OUString &rName)
220 : aName(rName)
221 , pList(nullptr)
224 ~SfxFilterMatcher_Impl()
226 // SfxFilterMatcher_Impl::InitForIterating() will set pList to
227 // either the global filter array matcher pFilterArr, or to
228 // a new SfxFilterList_Impl.
229 if (pList != pFilterArr)
230 delete pList;
234 namespace
236 std::vector<std::unique_ptr<SfxFilterMatcher_Impl> > aImplArr;
237 int nSfxFilterMatcherCount;
239 SfxFilterMatcher_Impl & getSfxFilterMatcher_Impl(const OUString &rName)
241 OUString aName;
243 if (!rName.isEmpty())
244 aName = SfxObjectShell::GetServiceNameFromFactory(rName);
246 // find the impl-Data of any comparable FilterMatcher that was created
247 // previously
248 for (std::unique_ptr<SfxFilterMatcher_Impl>& aImpl : aImplArr)
249 if (aImpl->aName == aName)
250 return *aImpl;
252 // first Matcher created for this factory
253 aImplArr.push_back(std::make_unique<SfxFilterMatcher_Impl>(aName));
254 return *aImplArr.back();
258 SfxFilterMatcher::SfxFilterMatcher( const OUString& rName )
259 : m_rImpl( getSfxFilterMatcher_Impl(rName) )
261 ++nSfxFilterMatcherCount;
264 SfxFilterMatcher::SfxFilterMatcher()
265 : m_rImpl( getSfxFilterMatcher_Impl(OUString()) )
267 // global FilterMatcher always uses global filter array (also created on
268 // demand)
269 ++nSfxFilterMatcherCount;
272 SfxFilterMatcher::~SfxFilterMatcher()
274 --nSfxFilterMatcherCount;
275 if (nSfxFilterMatcherCount == 0)
276 aImplArr.clear();
279 void SfxFilterMatcher_Impl::Update() const
281 if ( pList )
283 // this List was already used
284 pList->clear();
285 for (const std::shared_ptr<const SfxFilter>& pFilter : *pFilterArr)
287 if ( pFilter->GetServiceName() == aName )
288 pList->push_back( pFilter );
293 void SfxFilterMatcher_Impl::InitForIterating() const
295 if ( pList )
296 return;
298 if ( bFirstRead )
299 // global filter array has not been created yet
300 SfxFilterContainer::ReadFilters_Impl();
302 if ( !aName.isEmpty() )
304 // matcher of factory: use only filters of that document type
305 pList = new SfxFilterList_Impl;
306 Update();
308 else
310 // global matcher: use global filter array
311 pList = pFilterArr;
315 std::shared_ptr<const SfxFilter> SfxFilterMatcher::GetAnyFilter( SfxFilterFlags nMust, SfxFilterFlags nDont ) const
317 m_rImpl.InitForIterating();
318 for (const std::shared_ptr<const SfxFilter>& pFilter : *m_rImpl.pList)
320 SfxFilterFlags nFlags = pFilter->GetFilterFlags();
321 if ( (nFlags & nMust) == nMust && !(nFlags & nDont ) )
322 return pFilter;
325 return nullptr;
329 ErrCode SfxFilterMatcher::GuessFilterIgnoringContent(
330 SfxMedium const & rMedium,
331 std::shared_ptr<const SfxFilter>& rpFilter ) const
333 uno::Reference<document::XTypeDetection> xDetection(
334 comphelper::getProcessServiceFactory()->createInstance("com.sun.star.document.TypeDetection"), uno::UNO_QUERY);
336 OUString sTypeName;
339 sTypeName = xDetection->queryTypeByURL( rMedium.GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
341 catch (uno::Exception&)
345 rpFilter = nullptr;
346 if ( !sTypeName.isEmpty() )
348 // make sure filter list is initialized
349 m_rImpl.InitForIterating();
350 rpFilter = GetFilter4EA( sTypeName );
353 return rpFilter ? ERRCODE_NONE : ERRCODE_ABORT;
357 ErrCode SfxFilterMatcher::GuessFilter( SfxMedium& rMedium, std::shared_ptr<const SfxFilter>& rpFilter, SfxFilterFlags nMust, SfxFilterFlags nDont ) const
359 return GuessFilterControlDefaultUI( rMedium, rpFilter, nMust, nDont );
363 ErrCode SfxFilterMatcher::GuessFilterControlDefaultUI( SfxMedium& rMedium, std::shared_ptr<const SfxFilter>& rpFilter, SfxFilterFlags nMust, SfxFilterFlags nDont ) const
365 std::shared_ptr<const SfxFilter> pOldFilter = rpFilter;
367 // no detection service -> nothing to do !
368 uno::Reference<document::XTypeDetection> xDetection(
369 comphelper::getProcessServiceFactory()->createInstance("com.sun.star.document.TypeDetection"), uno::UNO_QUERY);
371 if (!xDetection.is())
372 return ERRCODE_ABORT;
376 // open the stream one times only ...
377 // Otherwise it will be tried more than once and show the same interaction more than once ...
379 OUString sURL( rMedium.GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
380 uno::Reference< io::XInputStream > xInStream = rMedium.GetInputStream();
381 OUString aFilterName;
382 OUString sTypeName;
384 // stream exists => deep detection (with preselection ... if possible)
385 if (xInStream.is())
387 utl::MediaDescriptor aDescriptor;
389 aDescriptor[utl::MediaDescriptor::PROP_URL() ] <<= sURL;
390 aDescriptor[utl::MediaDescriptor::PROP_INPUTSTREAM() ] <<= xInStream;
391 aDescriptor[utl::MediaDescriptor::PROP_INTERACTIONHANDLER()] <<= rMedium.GetInteractionHandler();
392 SfxStringItem const * it = static_cast<SfxStringItem const *>(
393 rMedium.GetItemSet()->GetItem(SID_REFERER));
394 if (it != nullptr) {
395 aDescriptor[utl::MediaDescriptor::PROP_REFERRER()]
396 <<= it->GetValue();
399 if ( !m_rImpl.aName.isEmpty() )
400 aDescriptor[utl::MediaDescriptor::PROP_DOCUMENTSERVICE()] <<= m_rImpl.aName;
402 if ( pOldFilter )
404 aDescriptor[utl::MediaDescriptor::PROP_TYPENAME() ] <<= pOldFilter->GetTypeName();
405 aDescriptor[utl::MediaDescriptor::PROP_FILTERNAME()] <<= pOldFilter->GetFilterName();
408 uno::Sequence< beans::PropertyValue > lDescriptor = aDescriptor.getAsConstPropertyValueList();
409 sTypeName = xDetection->queryTypeByDescriptor(lDescriptor, true); // lDescriptor is used as In/Out param ... don't use aDescriptor.getAsConstPropertyValueList() directly!
411 for (const auto& rProp : std::as_const(lDescriptor))
413 if (rProp.Name == "FilterName")
414 // Type detection picked a preferred filter for this format.
415 aFilterName = rProp.Value.get<OUString>();
418 // no stream exists => try flat detection without preselection as fallback
419 else
420 sTypeName = xDetection->queryTypeByURL(sURL);
422 if (!sTypeName.isEmpty())
424 std::shared_ptr<const SfxFilter> pNewFilter;
425 if (!aFilterName.isEmpty())
426 // Type detection returned a suitable filter for this. Use it.
427 pNewFilter = SfxFilter::GetFilterByName(aFilterName);
429 // fdo#78742 respect requested document service if set
430 if (!pNewFilter || (!m_rImpl.aName.isEmpty()
431 && m_rImpl.aName != pNewFilter->GetServiceName()))
433 // detect filter by given type
434 // In case of this matcher is bound to a particular document type:
435 // If there is no acceptable type for this document at all, the type detection has possibly returned something else.
436 // The DocumentService property is only a preselection, and all preselections are considered as optional!
437 // This "wrong" type will be sorted out now because we match only allowed filters to the detected type
438 uno::Sequence< beans::NamedValue > lQuery { { "Name", css::uno::makeAny(sTypeName) } };
440 pNewFilter = GetFilterForProps(lQuery, nMust, nDont);
443 if (pNewFilter)
445 rpFilter = pNewFilter;
446 return ERRCODE_NONE;
450 catch (const uno::Exception&)
453 return ERRCODE_ABORT;
457 bool SfxFilterMatcher::IsFilterInstalled_Impl( const std::shared_ptr<const SfxFilter>& pFilter )
459 if ( pFilter->GetFilterFlags() & SfxFilterFlags::MUSTINSTALL )
461 // Here could a re-installation be offered
462 OUString aText( SfxResId(STR_FILTER_NOT_INSTALLED) );
463 aText = aText.replaceFirst( "$(FILTER)", pFilter->GetUIName() );
464 std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(nullptr,
465 VclMessageType::Question, VclButtonsType::YesNo,
466 aText));
467 xQueryBox->set_default_response(RET_YES);
469 short nRet = xQueryBox->run();
470 if ( nRet == RET_YES )
472 #ifdef DBG_UTIL
473 // Start Setup
474 std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(nullptr,
475 VclMessageType::Info, VclButtonsType::Ok,
476 "Here should the Setup now be starting!"));
477 xInfoBox->run();
478 #endif
479 // Installation must still give feedback if it worked or not,
480 // then the Filterflag be deleted
483 return ( !(pFilter->GetFilterFlags() & SfxFilterFlags::MUSTINSTALL) );
485 else if ( pFilter->GetFilterFlags() & SfxFilterFlags::CONSULTSERVICE )
487 OUString aText( SfxResId(STR_FILTER_CONSULT_SERVICE) );
488 aText = aText.replaceFirst( "$(FILTER)", pFilter->GetUIName() );
489 std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(nullptr,
490 VclMessageType::Info, VclButtonsType::Ok,
491 aText));
492 xInfoBox->run();
493 return false;
495 else
496 return true;
500 ErrCode SfxFilterMatcher::DetectFilter( SfxMedium& rMedium, std::shared_ptr<const SfxFilter>& rpFilter ) const
501 /* [Description]
503 Here the Filter selection box is pulled up. Otherwise GuessFilter
507 std::shared_ptr<const SfxFilter> pOldFilter = rMedium.GetFilter();
508 if ( pOldFilter )
510 if( !IsFilterInstalled_Impl( pOldFilter ) )
511 pOldFilter = nullptr;
512 else
514 const SfxStringItem* pSalvageItem = SfxItemSet::GetItem<SfxStringItem>(rMedium.GetItemSet(), SID_DOC_SALVAGE, false);
515 if ( ( pOldFilter->GetFilterFlags() & SfxFilterFlags::PACKED ) && pSalvageItem )
516 // Salvage is always done without packing
517 pOldFilter = nullptr;
521 std::shared_ptr<const SfxFilter> pFilter = pOldFilter;
523 bool bPreview = rMedium.IsPreview_Impl();
524 const SfxStringItem* pReferer = SfxItemSet::GetItem<SfxStringItem>(rMedium.GetItemSet(), SID_REFERER, false);
525 if ( bPreview && rMedium.IsRemote() && ( !pReferer || !pReferer->GetValue().match("private:searchfolder:") ) )
526 return ERRCODE_ABORT;
528 ErrCode nErr = GuessFilter( rMedium, pFilter );
529 if ( nErr == ERRCODE_ABORT )
530 return nErr;
532 if ( nErr == ERRCODE_IO_PENDING )
534 rpFilter = pFilter;
535 return nErr;
538 if ( !pFilter )
540 std::shared_ptr<const SfxFilter> pInstallFilter;
542 // Now test the filter which are not installed (ErrCode is irrelevant)
543 GuessFilter( rMedium, pInstallFilter, SfxFilterFlags::IMPORT, SfxFilterFlags::CONSULTSERVICE );
544 if ( pInstallFilter )
546 if ( IsFilterInstalled_Impl( pInstallFilter ) )
547 // Maybe the filter was installed afterwards.
548 pFilter = pInstallFilter;
550 else
552 // Now test the filter, which first must be obtained by Star
553 // (ErrCode is irrelevant)
554 GuessFilter( rMedium, pInstallFilter, SfxFilterFlags::IMPORT, SfxFilterFlags::NONE );
555 if ( pInstallFilter )
556 IsFilterInstalled_Impl( pInstallFilter );
560 bool bHidden = bPreview;
561 const SfxStringItem* pFlags = SfxItemSet::GetItem<SfxStringItem>(rMedium.GetItemSet(), SID_OPTIONS, false);
562 if ( !bHidden && pFlags )
564 OUString aFlags( pFlags->GetValue() );
565 aFlags = aFlags.toAsciiUpperCase();
566 if( -1 != aFlags.indexOf( 'H' ) )
567 bHidden = true;
569 rpFilter = pFilter;
571 if ( bHidden )
572 nErr = pFilter ? ERRCODE_NONE : ERRCODE_ABORT;
573 return nErr;
576 std::shared_ptr<const SfxFilter> SfxFilterMatcher::GetFilterForProps( const css::uno::Sequence < beans::NamedValue >& aSeq, SfxFilterFlags nMust, SfxFilterFlags nDont ) const
578 uno::Reference< lang::XMultiServiceFactory > xServiceManager = ::comphelper::getProcessServiceFactory();
579 uno::Reference< container::XContainerQuery > xTypeCFG;
580 if( xServiceManager.is() )
581 xTypeCFG.set( xServiceManager->createInstance( "com.sun.star.document.TypeDetection" ), uno::UNO_QUERY );
582 if ( xTypeCFG.is() )
584 // make query for all types matching the properties
585 uno::Reference < css::container::XEnumeration > xEnum = xTypeCFG->createSubSetEnumerationByProperties( aSeq );
586 while ( xEnum->hasMoreElements() )
588 ::comphelper::SequenceAsHashMap aProps( xEnum->nextElement() );
589 OUString aValue;
591 // try to get the preferred filter (works without loading all filters!)
592 if ( (aProps[OUString("PreferredFilter")] >>= aValue) && !aValue.isEmpty() )
594 std::shared_ptr<const SfxFilter> pFilter = SfxFilter::GetFilterByName( aValue );
595 if ( !pFilter || (pFilter->GetFilterFlags() & nMust) != nMust || (pFilter->GetFilterFlags() & nDont ) )
596 // check for filter flags
597 // pFilter == 0: if preferred filter is a Writer filter, but Writer module is not installed
598 continue;
600 if ( !m_rImpl.aName.isEmpty() )
602 // if this is not the global FilterMatcher: check if filter matches the document type
603 if ( pFilter->GetServiceName() != m_rImpl.aName )
605 // preferred filter belongs to another document type; now we must search the filter
606 m_rImpl.InitForIterating();
607 aProps[OUString("Name")] >>= aValue;
608 pFilter = GetFilter4EA( aValue, nMust, nDont );
609 if ( pFilter )
610 return pFilter;
612 else
613 return pFilter;
615 else
616 return pFilter;
621 return nullptr;
624 std::shared_ptr<const SfxFilter> SfxFilterMatcher::GetFilter4Mime( const OUString& rMediaType, SfxFilterFlags nMust, SfxFilterFlags nDont ) const
626 if ( m_rImpl.pList )
628 for (const std::shared_ptr<const SfxFilter>& pFilter : *m_rImpl.pList)
630 SfxFilterFlags nFlags = pFilter->GetFilterFlags();
631 if ( (nFlags & nMust) == nMust && !(nFlags & nDont ) && pFilter->GetMimeType() == rMediaType )
632 return pFilter;
635 return nullptr;
638 css::uno::Sequence < css::beans::NamedValue > aSeq { { "MediaType", css::uno::makeAny(rMediaType) } };
639 return GetFilterForProps( aSeq, nMust, nDont );
642 std::shared_ptr<const SfxFilter> SfxFilterMatcher::GetFilter4EA( const OUString& rType, SfxFilterFlags nMust, SfxFilterFlags nDont ) const
644 if ( m_rImpl.pList )
646 std::shared_ptr<const SfxFilter> pFirst;
647 for (const std::shared_ptr<const SfxFilter>& pFilter : *m_rImpl.pList)
649 SfxFilterFlags nFlags = pFilter->GetFilterFlags();
650 if ( (nFlags & nMust) == nMust && !(nFlags & nDont ) && pFilter->GetTypeName() == rType )
652 if (nFlags & SfxFilterFlags::PREFERED)
653 return pFilter;
654 if (!pFirst)
655 pFirst = pFilter;
658 if (pFirst)
659 return pFirst;
661 return nullptr;
664 css::uno::Sequence < css::beans::NamedValue > aSeq { { "Name", css::uno::makeAny(rType) } };
665 return GetFilterForProps( aSeq, nMust, nDont );
668 std::shared_ptr<const SfxFilter> SfxFilterMatcher::GetFilter4Extension( const OUString& rExt, SfxFilterFlags nMust, SfxFilterFlags nDont ) const
670 if ( m_rImpl.pList )
672 for (const std::shared_ptr<const SfxFilter>& pFilter : *m_rImpl.pList)
674 SfxFilterFlags nFlags = pFilter->GetFilterFlags();
675 if ( (nFlags & nMust) == nMust && !(nFlags & nDont ) )
677 OUString sWildCard = ToUpper_Impl( pFilter->GetWildcard().getGlob() );
678 OUString sExt = ToUpper_Impl( rExt );
680 if (sExt.isEmpty())
681 continue;
683 if (sExt[0] != '.')
684 sExt = "." + sExt;
686 WildCard aCheck(sWildCard, ';');
687 if (aCheck.Matches(sExt))
688 return pFilter;
692 return nullptr;
695 // Use extension without dot!
696 OUString sExt( rExt );
697 if ( sExt.startsWith(".") )
698 sExt = sExt.copy(1);
700 css::uno::Sequence < css::beans::NamedValue > aSeq
701 { { "Extensions", css::uno::makeAny(uno::Sequence < OUString > { sExt } ) } };
702 return GetFilterForProps( aSeq, nMust, nDont );
705 std::shared_ptr<const SfxFilter> SfxFilterMatcher::GetFilter4ClipBoardId( SotClipboardFormatId nId, SfxFilterFlags nMust, SfxFilterFlags nDont ) const
707 if (nId == SotClipboardFormatId::NONE)
708 return nullptr;
710 css::uno::Sequence < css::beans::NamedValue > aSeq
711 { { "ClipboardFormat", css::uno::makeAny(SotExchange::GetFormatName( nId )) } };
712 return GetFilterForProps( aSeq, nMust, nDont );
715 std::shared_ptr<const SfxFilter> SfxFilterMatcher::GetFilter4UIName( const OUString& rName, SfxFilterFlags nMust, SfxFilterFlags nDont ) const
717 m_rImpl.InitForIterating();
718 std::shared_ptr<const SfxFilter> pFirstFilter;
719 for (const std::shared_ptr<const SfxFilter>& pFilter : *m_rImpl.pList)
721 SfxFilterFlags nFlags = pFilter->GetFilterFlags();
722 if ( (nFlags & nMust) == nMust &&
723 !(nFlags & nDont ) && pFilter->GetUIName() == rName )
725 if ( pFilter->GetFilterFlags() & SfxFilterFlags::PREFERED )
726 return pFilter;
727 else if ( !pFirstFilter )
728 pFirstFilter = pFilter;
731 return pFirstFilter;
734 std::shared_ptr<const SfxFilter> SfxFilterMatcher::GetFilter4FilterName( const OUString& rName, SfxFilterFlags nMust, SfxFilterFlags nDont ) const
736 OUString aName( rName );
737 sal_Int32 nIndex = aName.indexOf(": ");
738 if ( nIndex != -1 )
740 SAL_WARN( "sfx.bastyp", "Old filter name used!");
741 aName = rName.copy( nIndex + 2 );
744 if ( bFirstRead )
746 uno::Reference< lang::XMultiServiceFactory > xServiceManager = ::comphelper::getProcessServiceFactory();
747 uno::Reference< container::XNameAccess > xFilterCFG ;
748 uno::Reference< container::XNameAccess > xTypeCFG ;
749 if( xServiceManager.is() )
751 xFilterCFG.set( xServiceManager->createInstance( "com.sun.star.document.FilterFactory" ), uno::UNO_QUERY );
752 xTypeCFG.set( xServiceManager->createInstance( "com.sun.star.document.TypeDetection" ), uno::UNO_QUERY );
755 if( xFilterCFG.is() && xTypeCFG.is() )
757 if ( !pFilterArr )
758 CreateFilterArr();
759 else
761 for (const std::shared_ptr<const SfxFilter>& pFilter : *pFilterArr)
763 SfxFilterFlags nFlags = pFilter->GetFilterFlags();
764 if ((nFlags & nMust) == nMust && !(nFlags & nDont) && pFilter->GetFilterName().equalsIgnoreAsciiCase(aName))
765 return pFilter;
769 SfxFilterContainer::ReadSingleFilter_Impl( rName, xTypeCFG, xFilterCFG, false );
773 SfxFilterList_Impl* pList = m_rImpl.pList;
774 if ( !pList )
775 pList = pFilterArr;
777 for (const std::shared_ptr<const SfxFilter>& pFilter : *pList)
779 SfxFilterFlags nFlags = pFilter->GetFilterFlags();
780 if ( (nFlags & nMust) == nMust && !(nFlags & nDont ) && pFilter->GetFilterName().equalsIgnoreAsciiCase(aName))
781 return pFilter;
784 return nullptr;
787 IMPL_LINK( SfxFilterMatcher, MaybeFileHdl_Impl, OUString*, pString, bool )
789 std::shared_ptr<const SfxFilter> pFilter = GetFilter4Extension( *pString );
790 return pFilter &&
791 !pFilter->GetWildcard().Matches("") &&
792 !pFilter->GetWildcard().Matches("*.*") &&
793 !pFilter->GetWildcard().Matches("*");
797 SfxFilterMatcherIter::SfxFilterMatcherIter(
798 const SfxFilterMatcher& rMatcher,
799 SfxFilterFlags nOrMaskP, SfxFilterFlags nAndMaskP )
800 : nOrMask( nOrMaskP ), nAndMask( nAndMaskP ),
801 nCurrent(0), m_rMatch(rMatcher.m_rImpl)
803 if( nOrMask == static_cast<SfxFilterFlags>(0xffff) ) //Due to faulty build on s
804 nOrMask = SfxFilterFlags::NONE;
805 m_rMatch.InitForIterating();
809 std::shared_ptr<const SfxFilter> SfxFilterMatcherIter::Find_Impl()
811 std::shared_ptr<const SfxFilter> pFilter;
812 while( nCurrent < m_rMatch.pList->size() )
814 pFilter = (*m_rMatch.pList)[nCurrent++];
815 SfxFilterFlags nFlags = pFilter->GetFilterFlags();
816 if( ((nFlags & nOrMask) == nOrMask ) && !(nFlags & nAndMask ) )
817 break;
818 pFilter = nullptr;
821 return pFilter;
824 std::shared_ptr<const SfxFilter> SfxFilterMatcherIter::First()
826 nCurrent = 0;
827 return Find_Impl();
831 std::shared_ptr<const SfxFilter> SfxFilterMatcherIter::Next()
833 return Find_Impl();
836 /*---------------------------------------------------------------
837 helper to build own formatted string from given stringlist by
838 using given separator
839 ---------------------------------------------------------------*/
840 static OUString implc_convertStringlistToString( const uno::Sequence< OUString >& lList ,
841 sal_Unicode cSeparator,
842 const OUString& sPrefix )
844 OUStringBuffer sString ( 1000 ) ;
845 sal_Int32 nCount = lList.getLength();
846 sal_Int32 nItem = 0 ;
847 for( nItem=0; nItem<nCount; ++nItem )
849 if( !sPrefix.isEmpty() )
851 sString.append( sPrefix );
853 sString.append( lList[nItem] );
854 if( nItem+1<nCount )
856 sString.append( cSeparator );
859 return sString.makeStringAndClear();
863 void SfxFilterContainer::ReadSingleFilter_Impl(
864 const OUString& rName,
865 const uno::Reference< container::XNameAccess >& xTypeCFG,
866 const uno::Reference< container::XNameAccess >& xFilterCFG,
867 bool bUpdate
870 OUString sFilterName( rName );
871 SfxFilterList_Impl& rList = *pFilterArr;
872 uno::Sequence< beans::PropertyValue > lFilterProperties;
873 uno::Any aResult;
876 aResult = xFilterCFG->getByName( sFilterName );
878 catch( container::NoSuchElementException& )
880 aResult = uno::Any();
883 if( !(aResult >>= lFilterProperties) )
884 return;
886 // collect information to add filter to container
887 // (attention: some information aren't available on filter directly ... you must search for corresponding type too!)
888 SfxFilterFlags nFlags = SfxFilterFlags::NONE;
889 SotClipboardFormatId nClipboardId = SotClipboardFormatId::NONE;
890 sal_Int32 nFormatVersion = 0 ;
891 OUString sMimeType ;
892 OUString sType ;
893 OUString sUIName ;
894 OUString sHumanName ;
895 OUString sDefaultTemplate ;
896 OUString sUserData ;
897 OUString sExtension ;
898 OUString sPattern ;
899 OUString sServiceName ;
900 bool bEnabled = true ;
902 // first get directly available properties
903 for( const auto& rFilterProperty : std::as_const(lFilterProperties) )
905 if ( rFilterProperty.Name == "FileFormatVersion" )
907 rFilterProperty.Value >>= nFormatVersion;
909 else if ( rFilterProperty.Name == "TemplateName" )
911 rFilterProperty.Value >>= sDefaultTemplate;
913 else if ( rFilterProperty.Name == "Flags" )
915 sal_Int32 nTmp(0);
916 rFilterProperty.Value >>= nTmp;
917 assert((nTmp & ~o3tl::typed_flags<SfxFilterFlags>::mask) == 0);
918 nFlags = static_cast<SfxFilterFlags>(nTmp);
920 else if ( rFilterProperty.Name == "UIName" )
922 rFilterProperty.Value >>= sUIName;
924 else if ( rFilterProperty.Name == "UserData" )
926 uno::Sequence< OUString > lUserData;
927 rFilterProperty.Value >>= lUserData;
928 sUserData = implc_convertStringlistToString( lUserData, ',', OUString() );
930 else if ( rFilterProperty.Name == "DocumentService" )
932 rFilterProperty.Value >>= sServiceName;
934 else if (rFilterProperty.Name == "ExportExtension")
936 // Extension preferred by the filter. This takes precedence
937 // over those that are given in the file format type.
938 rFilterProperty.Value >>= sExtension;
939 sExtension = "*." + sExtension;
941 else if ( rFilterProperty.Name == "Type" )
943 rFilterProperty.Value >>= sType;
944 // Try to get filter .. but look for any exceptions!
945 // May be filter was deleted by another thread ...
948 aResult = xTypeCFG->getByName( sType );
950 catch (const container::NoSuchElementException&)
952 aResult = uno::Any();
955 uno::Sequence< beans::PropertyValue > lTypeProperties;
956 if( aResult >>= lTypeProperties )
958 // get indirect available properties then (types)
959 for( const auto& rTypeProperty : std::as_const(lTypeProperties) )
961 if ( rTypeProperty.Name == "ClipboardFormat" )
963 rTypeProperty.Value >>= sHumanName;
965 else if ( rTypeProperty.Name == "MediaType" )
967 rTypeProperty.Value >>= sMimeType;
969 else if ( rTypeProperty.Name == "Extensions" )
971 if (sExtension.isEmpty())
973 uno::Sequence< OUString > lExtensions;
974 rTypeProperty.Value >>= lExtensions;
975 sExtension = implc_convertStringlistToString( lExtensions, ';', "*." );
978 else if ( rTypeProperty.Name == "URLPattern" )
980 uno::Sequence< OUString > lPattern;
981 rTypeProperty.Value >>= lPattern;
982 sPattern = implc_convertStringlistToString( lPattern, ';', OUString() );
987 else if ( rFilterProperty.Name == "Enabled" )
989 rFilterProperty.Value >>= bEnabled;
994 if ( sServiceName.isEmpty() )
995 return;
997 // old formats are found ... using HumanPresentableName!
998 if( !sHumanName.isEmpty() )
1000 nClipboardId = SotExchange::RegisterFormatName( sHumanName );
1002 // For external filters ignore clipboard IDs
1003 if(nFlags & SfxFilterFlags::STARONEFILTER)
1005 nClipboardId = SotClipboardFormatId::NONE;
1008 // register SfxFilter
1009 // first erase module name from old filter names!
1010 // e.g: "scalc: DIF" => "DIF"
1011 sal_Int32 nStartRealName = sFilterName.indexOf( ": " );
1012 if( nStartRealName != -1 )
1014 SAL_WARN( "sfx.bastyp", "Old format, not supported!");
1015 sFilterName = sFilterName.copy( nStartRealName+2 );
1018 std::shared_ptr<const SfxFilter> pFilter = bUpdate ? SfxFilter::GetFilterByName( sFilterName ) : nullptr;
1019 if (!pFilter)
1021 pFilter = std::make_shared<SfxFilter>( sFilterName ,
1022 sExtension ,
1023 nFlags ,
1024 nClipboardId ,
1025 sType ,
1026 sMimeType ,
1027 sUserData ,
1028 sServiceName ,
1029 bEnabled );
1030 rList.push_back( pFilter );
1032 else
1034 SfxFilter* pFilt = const_cast<SfxFilter*>(pFilter.get());
1035 pFilt->maFilterName = sFilterName;
1036 pFilt->aWildCard = WildCard(sExtension, ';');
1037 pFilt->nFormatType = nFlags;
1038 pFilt->lFormat = nClipboardId;
1039 pFilt->aTypeName = sType;
1040 pFilt->aMimeType = sMimeType;
1041 pFilt->aUserData = sUserData;
1042 pFilt->aServiceName = sServiceName;
1043 pFilt->mbEnabled = bEnabled;
1046 SfxFilter* pFilt = const_cast<SfxFilter*>(pFilter.get());
1048 // Don't forget to set right UIName!
1049 // Otherwise internal name is used as fallback ...
1050 pFilt->SetUIName( sUIName );
1051 pFilt->SetDefaultTemplate( sDefaultTemplate );
1052 if( nFormatVersion )
1054 pFilt->SetVersion( nFormatVersion );
1058 void SfxFilterContainer::ReadFilters_Impl( bool bUpdate )
1060 if ( !pFilterArr )
1061 CreateFilterArr();
1063 bFirstRead = false;
1064 SfxFilterList_Impl& rList = *pFilterArr;
1068 // get the FilterFactory service to access the registered filters ... and types!
1069 uno::Reference< lang::XMultiServiceFactory > xServiceManager = ::comphelper::getProcessServiceFactory();
1070 uno::Reference< container::XNameAccess > xFilterCFG ;
1071 uno::Reference< container::XNameAccess > xTypeCFG ;
1072 if( xServiceManager.is() )
1074 xFilterCFG.set( xServiceManager->createInstance( "com.sun.star.document.FilterFactory" ), uno::UNO_QUERY );
1075 xTypeCFG.set( xServiceManager->createInstance( "com.sun.star.document.TypeDetection" ), uno::UNO_QUERY );
1078 if( xFilterCFG.is() && xTypeCFG.is() )
1080 // select right query to get right set of filters for search module
1081 const uno::Sequence< OUString > lFilterNames = xFilterCFG->getElementNames();
1082 if ( lFilterNames.hasElements() )
1084 // If list of filters already exist ...
1085 // ReadExternalFilters must work in update mode.
1086 // Best way seems to mark all filters NOT_INSTALLED
1087 // and change it back for all valid filters afterwards.
1088 if( !rList.empty() )
1090 bUpdate = true;
1091 for (const std::shared_ptr<const SfxFilter>& pFilter : rList)
1093 SfxFilter* pNonConstFilter = const_cast<SfxFilter*>(pFilter.get());
1094 pNonConstFilter->nFormatType |= SFX_FILTER_NOTINSTALLED;
1098 // get all properties of filters ... put it into the filter container
1099 for( const OUString& sFilterName : lFilterNames )
1101 // Try to get filter .. but look for any exceptions!
1102 // May be filter was deleted by another thread ...
1103 ReadSingleFilter_Impl( sFilterName, xTypeCFG, xFilterCFG, bUpdate );
1108 catch(const uno::Exception&)
1110 SAL_WARN( "sfx.bastyp", "SfxFilterContainer::ReadFilter()\nException detected. Possible not all filters could be cached." );
1113 if ( bUpdate )
1115 // global filter array was modified, factory specific ones might need an
1116 // update too
1117 for (const auto& aImpl : aImplArr)
1118 aImpl->Update();
1122 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */