LanguageTool: don't crash if REST protocol isn't set
[LibreOffice.git] / sfx2 / source / bastyp / fltfnc.cxx
blobfd2e7c2df31dcb26aff2c7983bc9599b03bee054
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 <unotools/syslocale.hxx>
51 #include <unotools/charclass.hxx>
53 #include <sfx2/docfilt.hxx>
54 #include <sfx2/fcontnr.hxx>
55 #include <sfxtypes.hxx>
56 #include <sfx2/docfile.hxx>
57 #include <sfx2/strings.hrc>
58 #include <sfx2/sfxresid.hxx>
59 #include <sfx2/objsh.hxx>
60 #include <sfx2/sfxsids.hrc>
61 #include "fltlst.hxx"
62 #include <arrdecl.hxx>
64 #include <vector>
65 #include <memory>
67 #if defined(DBG_UTIL)
68 unsigned SfxStack::nLevel = 0;
69 #endif
71 using namespace com::sun::star;
73 static SfxFilterList_Impl* pFilterArr = nullptr;
74 static bool bFirstRead = true;
76 static void CreateFilterArr()
78 static SfxFilterList_Impl theSfxFilterArray;
79 pFilterArr = &theSfxFilterArray;
80 static SfxFilterListener theSfxFilterListener;
83 static OUString ToUpper_Impl( const OUString &rStr )
85 return SvtSysLocale().GetCharClass().uppercase( rStr );
88 class SfxFilterContainer_Impl
90 public:
91 OUString aName;
93 explicit SfxFilterContainer_Impl( const OUString& rName )
94 : aName( rName )
99 std::shared_ptr<const SfxFilter> SfxFilterContainer::GetFilter4EA(const OUString& rEA, SfxFilterFlags nMust, SfxFilterFlags nDont) const
101 SfxFilterMatcher aMatch(pImpl->aName);
102 return aMatch.GetFilter4EA(rEA, nMust, nDont);
105 std::shared_ptr<const SfxFilter> SfxFilterContainer::GetFilter4Extension(const OUString& rExt, SfxFilterFlags nMust, SfxFilterFlags nDont) const
107 SfxFilterMatcher aMatch(pImpl->aName);
108 return aMatch.GetFilter4Extension(rExt, nMust, nDont);
111 std::shared_ptr<const SfxFilter> SfxFilterContainer::GetFilter4FilterName(const OUString& rName, SfxFilterFlags nMust, SfxFilterFlags nDont) const
113 SfxFilterMatcher aMatch(pImpl->aName);
114 return aMatch.GetFilter4FilterName(rName, nMust, nDont);
117 std::shared_ptr<const SfxFilter> SfxFilterContainer::GetAnyFilter( SfxFilterFlags nMust, SfxFilterFlags nDont ) const
119 SfxFilterMatcher aMatch( pImpl->aName );
120 return aMatch.GetAnyFilter( nMust, nDont );
124 SfxFilterContainer::SfxFilterContainer( const OUString& rName )
125 : pImpl( new SfxFilterContainer_Impl( rName ) )
130 SfxFilterContainer::~SfxFilterContainer()
135 OUString const & SfxFilterContainer::GetName() const
137 return pImpl->aName;
140 std::shared_ptr<const SfxFilter> SfxFilterContainer::GetDefaultFilter_Impl( const OUString& rName )
142 // Try to find out the type of factory.
143 // Interpret given name as Service- and ShortName!
144 SvtModuleOptions aOpt;
145 SvtModuleOptions::EFactory eFactory = SvtModuleOptions::ClassifyFactoryByServiceName(rName);
146 if (eFactory == SvtModuleOptions::EFactory::UNKNOWN_FACTORY)
147 eFactory = SvtModuleOptions::ClassifyFactoryByShortName(rName);
149 // could not classify factory by its service nor by its short name.
150 // Must be an unknown factory! => return NULL
151 if (eFactory == SvtModuleOptions::EFactory::UNKNOWN_FACTORY)
152 return nullptr;
154 // For the following code we need some additional information.
155 OUString sServiceName = aOpt.GetFactoryName(eFactory);
156 OUString sDefaultFilter = aOpt.GetFactoryDefaultFilter(eFactory);
158 // Try to get the default filter. Don't forget to verify it.
159 // May the set default filter does not exists any longer or
160 // does not fit the given factory.
161 const SfxFilterMatcher aMatcher;
162 std::shared_ptr<const SfxFilter> pFilter = aMatcher.GetFilter4FilterName(sDefaultFilter);
164 if (
165 pFilter &&
166 !pFilter->GetServiceName().equalsIgnoreAsciiCase(sServiceName)
169 pFilter = nullptr;
172 // If at least no default filter could be located - use any filter of this
173 // factory.
174 if (!pFilter)
176 if ( bFirstRead )
177 ReadFilters_Impl();
179 for (const std::shared_ptr<const SfxFilter>& pCheckFilter : *pFilterArr)
181 if ( pCheckFilter->GetServiceName().equalsIgnoreAsciiCase(sServiceName) )
183 pFilter = pCheckFilter;
184 break;
189 return pFilter;
193 // Impl-Data is shared between all FilterMatchers of the same factory
194 class SfxFilterMatcher_Impl
196 public:
197 OUString aName;
198 mutable SfxFilterList_Impl* pList; // is created on demand
200 void InitForIterating() const;
201 void Update() const;
202 explicit SfxFilterMatcher_Impl(const OUString &rName)
203 : aName(rName)
204 , pList(nullptr)
207 ~SfxFilterMatcher_Impl()
209 // SfxFilterMatcher_Impl::InitForIterating() will set pList to
210 // either the global filter array matcher pFilterArr, or to
211 // a new SfxFilterList_Impl.
212 if (pList != pFilterArr)
213 delete pList;
217 namespace
219 std::vector<std::unique_ptr<SfxFilterMatcher_Impl> > aImplArr;
220 int nSfxFilterMatcherCount;
222 SfxFilterMatcher_Impl & getSfxFilterMatcher_Impl(const OUString &rName)
224 OUString aName;
226 if (!rName.isEmpty())
227 aName = SfxObjectShell::GetServiceNameFromFactory(rName);
229 // find the impl-Data of any comparable FilterMatcher that was created
230 // previously
231 for (std::unique_ptr<SfxFilterMatcher_Impl>& aImpl : aImplArr)
232 if (aImpl->aName == aName)
233 return *aImpl;
235 // first Matcher created for this factory
236 aImplArr.push_back(std::make_unique<SfxFilterMatcher_Impl>(aName));
237 return *aImplArr.back();
241 SfxFilterMatcher::SfxFilterMatcher( const OUString& rName )
242 : m_rImpl( getSfxFilterMatcher_Impl(rName) )
244 ++nSfxFilterMatcherCount;
247 SfxFilterMatcher::SfxFilterMatcher()
248 : m_rImpl( getSfxFilterMatcher_Impl(OUString()) )
250 // global FilterMatcher always uses global filter array (also created on
251 // demand)
252 ++nSfxFilterMatcherCount;
255 SfxFilterMatcher::~SfxFilterMatcher()
257 --nSfxFilterMatcherCount;
258 if (nSfxFilterMatcherCount == 0)
259 aImplArr.clear();
262 void SfxFilterMatcher_Impl::Update() const
264 if ( pList )
266 // this List was already used
267 pList->clear();
268 for (const std::shared_ptr<const SfxFilter>& pFilter : *pFilterArr)
270 if ( pFilter->GetServiceName() == aName )
271 pList->push_back( pFilter );
276 void SfxFilterMatcher_Impl::InitForIterating() const
278 if ( pList )
279 return;
281 if ( bFirstRead )
282 // global filter array has not been created yet
283 SfxFilterContainer::ReadFilters_Impl();
285 if ( !aName.isEmpty() )
287 // matcher of factory: use only filters of that document type
288 pList = new SfxFilterList_Impl;
289 Update();
291 else
293 // global matcher: use global filter array
294 pList = pFilterArr;
298 std::shared_ptr<const SfxFilter> SfxFilterMatcher::GetAnyFilter( SfxFilterFlags nMust, SfxFilterFlags nDont ) const
300 m_rImpl.InitForIterating();
301 for (const std::shared_ptr<const SfxFilter>& pFilter : *m_rImpl.pList)
303 SfxFilterFlags nFlags = pFilter->GetFilterFlags();
304 if ( (nFlags & nMust) == nMust && !(nFlags & nDont ) )
305 return pFilter;
308 return nullptr;
312 ErrCode SfxFilterMatcher::GuessFilterIgnoringContent(
313 SfxMedium const & rMedium,
314 std::shared_ptr<const SfxFilter>& rpFilter ) const
316 uno::Reference<document::XTypeDetection> xDetection(
317 comphelper::getProcessServiceFactory()->createInstance("com.sun.star.document.TypeDetection"), uno::UNO_QUERY);
319 OUString sTypeName;
322 sTypeName = xDetection->queryTypeByURL( rMedium.GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
324 catch (uno::Exception&)
328 rpFilter = nullptr;
329 if ( !sTypeName.isEmpty() )
331 // make sure filter list is initialized
332 m_rImpl.InitForIterating();
333 rpFilter = GetFilter4EA( sTypeName );
336 return rpFilter ? ERRCODE_NONE : ERRCODE_ABORT;
340 ErrCode SfxFilterMatcher::GuessFilter( SfxMedium& rMedium, std::shared_ptr<const SfxFilter>& rpFilter, SfxFilterFlags nMust, SfxFilterFlags nDont ) const
342 return GuessFilterControlDefaultUI( rMedium, rpFilter, nMust, nDont );
346 ErrCode SfxFilterMatcher::GuessFilterControlDefaultUI( SfxMedium& rMedium, std::shared_ptr<const SfxFilter>& rpFilter, SfxFilterFlags nMust, SfxFilterFlags nDont ) const
348 std::shared_ptr<const SfxFilter> pOldFilter = rpFilter;
350 // no detection service -> nothing to do !
351 uno::Reference<document::XTypeDetection> xDetection(
352 comphelper::getProcessServiceFactory()->createInstance("com.sun.star.document.TypeDetection"), uno::UNO_QUERY);
354 if (!xDetection.is())
355 return ERRCODE_ABORT;
359 // open the stream one times only ...
360 // Otherwise it will be tried more than once and show the same interaction more than once ...
362 OUString sURL( rMedium.GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
363 uno::Reference< io::XInputStream > xInStream = rMedium.GetInputStream();
364 OUString aFilterName;
365 OUString sTypeName;
367 // stream exists => deep detection (with preselection ... if possible)
368 if (xInStream.is())
370 utl::MediaDescriptor aDescriptor;
372 aDescriptor[utl::MediaDescriptor::PROP_URL ] <<= sURL;
373 aDescriptor[utl::MediaDescriptor::PROP_INPUTSTREAM ] <<= xInStream;
374 aDescriptor[utl::MediaDescriptor::PROP_INTERACTIONHANDLER] <<= rMedium.GetInteractionHandler();
375 SfxStringItem const * it = static_cast<SfxStringItem const *>(
376 rMedium.GetItemSet()->GetItem(SID_REFERER));
377 if (it != nullptr) {
378 aDescriptor[utl::MediaDescriptor::PROP_REFERRER]
379 <<= it->GetValue();
382 if ( !m_rImpl.aName.isEmpty() )
383 aDescriptor[utl::MediaDescriptor::PROP_DOCUMENTSERVICE] <<= m_rImpl.aName;
385 if ( pOldFilter )
387 aDescriptor[utl::MediaDescriptor::PROP_TYPENAME ] <<= pOldFilter->GetTypeName();
388 aDescriptor[utl::MediaDescriptor::PROP_FILTERNAME] <<= pOldFilter->GetFilterName();
391 uno::Sequence< beans::PropertyValue > lDescriptor = aDescriptor.getAsConstPropertyValueList();
392 sTypeName = xDetection->queryTypeByDescriptor(lDescriptor, true); // lDescriptor is used as In/Out param ... don't use aDescriptor.getAsConstPropertyValueList() directly!
394 for (const auto& rProp : std::as_const(lDescriptor))
396 if (rProp.Name == "FilterName")
397 // Type detection picked a preferred filter for this format.
398 aFilterName = rProp.Value.get<OUString>();
401 // no stream exists => try flat detection without preselection as fallback
402 else
403 sTypeName = xDetection->queryTypeByURL(sURL);
405 if (!sTypeName.isEmpty())
407 std::shared_ptr<const SfxFilter> pNewFilter;
408 if (!aFilterName.isEmpty())
409 // Type detection returned a suitable filter for this. Use it.
410 pNewFilter = SfxFilter::GetFilterByName(aFilterName);
412 // fdo#78742 respect requested document service if set
413 if (!pNewFilter || (!m_rImpl.aName.isEmpty()
414 && m_rImpl.aName != pNewFilter->GetServiceName()))
416 // detect filter by given type
417 // In case of this matcher is bound to a particular document type:
418 // If there is no acceptable type for this document at all, the type detection has possibly returned something else.
419 // The DocumentService property is only a preselection, and all preselections are considered as optional!
420 // This "wrong" type will be sorted out now because we match only allowed filters to the detected type
421 uno::Sequence< beans::NamedValue > lQuery { { "Name", css::uno::makeAny(sTypeName) } };
423 pNewFilter = GetFilterForProps(lQuery, nMust, nDont);
426 if (pNewFilter)
428 rpFilter = pNewFilter;
429 return ERRCODE_NONE;
433 catch (const uno::Exception&)
436 return ERRCODE_ABORT;
440 bool SfxFilterMatcher::IsFilterInstalled_Impl( const std::shared_ptr<const SfxFilter>& pFilter )
442 if ( pFilter->GetFilterFlags() & SfxFilterFlags::MUSTINSTALL )
444 // Here could a re-installation be offered
445 OUString aText( SfxResId(STR_FILTER_NOT_INSTALLED) );
446 aText = aText.replaceFirst( "$(FILTER)", pFilter->GetUIName() );
447 std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(nullptr,
448 VclMessageType::Question, VclButtonsType::YesNo,
449 aText));
450 xQueryBox->set_default_response(RET_YES);
452 short nRet = xQueryBox->run();
453 if ( nRet == RET_YES )
455 #ifdef DBG_UTIL
456 // Start Setup
457 std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(nullptr,
458 VclMessageType::Info, VclButtonsType::Ok,
459 "Here should the Setup now be starting!"));
460 xInfoBox->run();
461 #endif
462 // Installation must still give feedback if it worked or not,
463 // then the Filterflag be deleted
466 return ( !(pFilter->GetFilterFlags() & SfxFilterFlags::MUSTINSTALL) );
468 else if ( pFilter->GetFilterFlags() & SfxFilterFlags::CONSULTSERVICE )
470 OUString aText( SfxResId(STR_FILTER_CONSULT_SERVICE) );
471 aText = aText.replaceFirst( "$(FILTER)", pFilter->GetUIName() );
472 std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(nullptr,
473 VclMessageType::Info, VclButtonsType::Ok,
474 aText));
475 xInfoBox->run();
476 return false;
478 else
479 return true;
483 ErrCode SfxFilterMatcher::DetectFilter( SfxMedium& rMedium, std::shared_ptr<const SfxFilter>& rpFilter ) const
484 /* [Description]
486 Here the Filter selection box is pulled up. Otherwise GuessFilter
490 std::shared_ptr<const SfxFilter> pOldFilter = rMedium.GetFilter();
491 if ( pOldFilter )
493 if( !IsFilterInstalled_Impl( pOldFilter ) )
494 pOldFilter = nullptr;
495 else
497 const SfxStringItem* pSalvageItem = SfxItemSet::GetItem<SfxStringItem>(rMedium.GetItemSet(), SID_DOC_SALVAGE, false);
498 if ( ( pOldFilter->GetFilterFlags() & SfxFilterFlags::PACKED ) && pSalvageItem )
499 // Salvage is always done without packing
500 pOldFilter = nullptr;
504 std::shared_ptr<const SfxFilter> pFilter = pOldFilter;
506 bool bPreview = rMedium.IsPreview_Impl();
507 const SfxStringItem* pReferer = SfxItemSet::GetItem<SfxStringItem>(rMedium.GetItemSet(), SID_REFERER, false);
508 if ( bPreview && rMedium.IsRemote() && ( !pReferer || !pReferer->GetValue().match("private:searchfolder:") ) )
509 return ERRCODE_ABORT;
511 ErrCode nErr = GuessFilter( rMedium, pFilter );
512 if ( nErr == ERRCODE_ABORT )
513 return nErr;
515 if ( nErr == ERRCODE_IO_PENDING )
517 rpFilter = pFilter;
518 return nErr;
521 if ( !pFilter )
523 std::shared_ptr<const SfxFilter> pInstallFilter;
525 // Now test the filter which are not installed (ErrCode is irrelevant)
526 GuessFilter( rMedium, pInstallFilter, SfxFilterFlags::IMPORT, SfxFilterFlags::CONSULTSERVICE );
527 if ( pInstallFilter )
529 if ( IsFilterInstalled_Impl( pInstallFilter ) )
530 // Maybe the filter was installed afterwards.
531 pFilter = pInstallFilter;
533 else
535 // Now test the filter, which first must be obtained by Star
536 // (ErrCode is irrelevant)
537 GuessFilter( rMedium, pInstallFilter, SfxFilterFlags::IMPORT, SfxFilterFlags::NONE );
538 if ( pInstallFilter )
539 IsFilterInstalled_Impl( pInstallFilter );
543 bool bHidden = bPreview;
544 const SfxStringItem* pFlags = SfxItemSet::GetItem<SfxStringItem>(rMedium.GetItemSet(), SID_OPTIONS, false);
545 if ( !bHidden && pFlags )
547 OUString aFlags( pFlags->GetValue() );
548 aFlags = aFlags.toAsciiUpperCase();
549 if( -1 != aFlags.indexOf( 'H' ) )
550 bHidden = true;
552 rpFilter = pFilter;
554 if ( bHidden )
555 nErr = pFilter ? ERRCODE_NONE : ERRCODE_ABORT;
556 return nErr;
559 std::shared_ptr<const SfxFilter> SfxFilterMatcher::GetFilterForProps( const css::uno::Sequence < beans::NamedValue >& aSeq, SfxFilterFlags nMust, SfxFilterFlags nDont ) const
561 uno::Reference< lang::XMultiServiceFactory > xServiceManager = ::comphelper::getProcessServiceFactory();
562 uno::Reference< container::XContainerQuery > xTypeCFG;
563 if( xServiceManager.is() )
564 xTypeCFG.set( xServiceManager->createInstance( "com.sun.star.document.TypeDetection" ), uno::UNO_QUERY );
565 if ( xTypeCFG.is() )
567 // make query for all types matching the properties
568 uno::Reference < css::container::XEnumeration > xEnum = xTypeCFG->createSubSetEnumerationByProperties( aSeq );
569 while ( xEnum->hasMoreElements() )
571 ::comphelper::SequenceAsHashMap aProps( xEnum->nextElement() );
572 OUString aValue;
574 // try to get the preferred filter (works without loading all filters!)
575 if ( (aProps[OUString("PreferredFilter")] >>= aValue) && !aValue.isEmpty() )
577 std::shared_ptr<const SfxFilter> pFilter = SfxFilter::GetFilterByName( aValue );
578 if ( !pFilter || (pFilter->GetFilterFlags() & nMust) != nMust || (pFilter->GetFilterFlags() & nDont ) )
579 // check for filter flags
580 // pFilter == 0: if preferred filter is a Writer filter, but Writer module is not installed
581 continue;
583 if ( !m_rImpl.aName.isEmpty() )
585 // if this is not the global FilterMatcher: check if filter matches the document type
586 if ( pFilter->GetServiceName() != m_rImpl.aName )
588 // preferred filter belongs to another document type; now we must search the filter
589 m_rImpl.InitForIterating();
590 aProps[OUString("Name")] >>= aValue;
591 pFilter = GetFilter4EA( aValue, nMust, nDont );
592 if ( pFilter )
593 return pFilter;
595 else
596 return pFilter;
598 else
599 return pFilter;
604 return nullptr;
607 std::shared_ptr<const SfxFilter> SfxFilterMatcher::GetFilter4Mime( const OUString& rMediaType, SfxFilterFlags nMust, SfxFilterFlags nDont ) const
609 if ( m_rImpl.pList )
611 for (const std::shared_ptr<const SfxFilter>& pFilter : *m_rImpl.pList)
613 SfxFilterFlags nFlags = pFilter->GetFilterFlags();
614 if ( (nFlags & nMust) == nMust && !(nFlags & nDont ) && pFilter->GetMimeType() == rMediaType )
615 return pFilter;
618 return nullptr;
621 css::uno::Sequence < css::beans::NamedValue > aSeq { { "MediaType", css::uno::makeAny(rMediaType) } };
622 return GetFilterForProps( aSeq, nMust, nDont );
625 std::shared_ptr<const SfxFilter> SfxFilterMatcher::GetFilter4EA( const OUString& rType, SfxFilterFlags nMust, SfxFilterFlags nDont ) const
627 if ( m_rImpl.pList )
629 std::shared_ptr<const SfxFilter> pFirst;
630 for (const std::shared_ptr<const SfxFilter>& pFilter : *m_rImpl.pList)
632 SfxFilterFlags nFlags = pFilter->GetFilterFlags();
633 if ( (nFlags & nMust) == nMust && !(nFlags & nDont ) && pFilter->GetTypeName() == rType )
635 if (nFlags & SfxFilterFlags::PREFERED)
636 return pFilter;
637 if (!pFirst)
638 pFirst = pFilter;
641 if (pFirst)
642 return pFirst;
644 return nullptr;
647 css::uno::Sequence < css::beans::NamedValue > aSeq { { "Name", css::uno::makeAny(rType) } };
648 return GetFilterForProps( aSeq, nMust, nDont );
651 std::shared_ptr<const SfxFilter> SfxFilterMatcher::GetFilter4Extension( const OUString& rExt, SfxFilterFlags nMust, SfxFilterFlags nDont ) const
653 if ( m_rImpl.pList )
655 for (const std::shared_ptr<const SfxFilter>& pFilter : *m_rImpl.pList)
657 SfxFilterFlags nFlags = pFilter->GetFilterFlags();
658 if ( (nFlags & nMust) == nMust && !(nFlags & nDont ) )
660 OUString sWildCard = ToUpper_Impl( pFilter->GetWildcard().getGlob() );
661 OUString sExt = ToUpper_Impl( rExt );
663 if (sExt.isEmpty())
664 continue;
666 if (sExt[0] != '.')
667 sExt = "." + sExt;
669 WildCard aCheck(sWildCard, ';');
670 if (aCheck.Matches(sExt))
671 return pFilter;
675 return nullptr;
678 // Use extension without dot!
679 OUString sExt( rExt );
680 if ( sExt.startsWith(".") )
681 sExt = sExt.copy(1);
683 css::uno::Sequence < css::beans::NamedValue > aSeq
684 { { "Extensions", css::uno::makeAny(uno::Sequence < OUString > { sExt } ) } };
685 return GetFilterForProps( aSeq, nMust, nDont );
688 std::shared_ptr<const SfxFilter> SfxFilterMatcher::GetFilter4ClipBoardId( SotClipboardFormatId nId, SfxFilterFlags nMust, SfxFilterFlags nDont ) const
690 if (nId == SotClipboardFormatId::NONE)
691 return nullptr;
693 css::uno::Sequence < css::beans::NamedValue > aSeq
694 { { "ClipboardFormat", css::uno::makeAny(SotExchange::GetFormatName( nId )) } };
695 return GetFilterForProps( aSeq, nMust, nDont );
698 std::shared_ptr<const SfxFilter> SfxFilterMatcher::GetFilter4UIName( std::u16string_view rName, SfxFilterFlags nMust, SfxFilterFlags nDont ) const
700 m_rImpl.InitForIterating();
701 std::shared_ptr<const SfxFilter> pFirstFilter;
702 for (const std::shared_ptr<const SfxFilter>& pFilter : *m_rImpl.pList)
704 SfxFilterFlags nFlags = pFilter->GetFilterFlags();
705 if ( (nFlags & nMust) == nMust &&
706 !(nFlags & nDont ) && pFilter->GetUIName() == rName )
708 if ( pFilter->GetFilterFlags() & SfxFilterFlags::PREFERED )
709 return pFilter;
710 else if ( !pFirstFilter )
711 pFirstFilter = pFilter;
714 return pFirstFilter;
717 std::shared_ptr<const SfxFilter> SfxFilterMatcher::GetFilter4FilterName( const OUString& rName, SfxFilterFlags nMust, SfxFilterFlags nDont ) const
719 OUString aName( rName );
720 sal_Int32 nIndex = aName.indexOf(": ");
721 if ( nIndex != -1 )
723 SAL_WARN( "sfx.bastyp", "Old filter name used!");
724 aName = rName.copy( nIndex + 2 );
727 if ( bFirstRead )
729 uno::Reference< lang::XMultiServiceFactory > xServiceManager = ::comphelper::getProcessServiceFactory();
730 uno::Reference< container::XNameAccess > xFilterCFG ;
731 uno::Reference< container::XNameAccess > xTypeCFG ;
732 if( xServiceManager.is() )
734 xFilterCFG.set( xServiceManager->createInstance( "com.sun.star.document.FilterFactory" ), uno::UNO_QUERY );
735 xTypeCFG.set( xServiceManager->createInstance( "com.sun.star.document.TypeDetection" ), uno::UNO_QUERY );
738 if( xFilterCFG.is() && xTypeCFG.is() )
740 if ( !pFilterArr )
741 CreateFilterArr();
742 else
744 for (const std::shared_ptr<const SfxFilter>& pFilter : *pFilterArr)
746 SfxFilterFlags nFlags = pFilter->GetFilterFlags();
747 if ((nFlags & nMust) == nMust && !(nFlags & nDont) && pFilter->GetFilterName().equalsIgnoreAsciiCase(aName))
748 return pFilter;
752 SfxFilterContainer::ReadSingleFilter_Impl( rName, xTypeCFG, xFilterCFG, false );
756 SfxFilterList_Impl* pList = m_rImpl.pList;
757 if ( !pList )
758 pList = pFilterArr;
760 for (const std::shared_ptr<const SfxFilter>& pFilter : *pList)
762 SfxFilterFlags nFlags = pFilter->GetFilterFlags();
763 if ( (nFlags & nMust) == nMust && !(nFlags & nDont ) && pFilter->GetFilterName().equalsIgnoreAsciiCase(aName))
764 return pFilter;
767 return nullptr;
770 IMPL_LINK( SfxFilterMatcher, MaybeFileHdl_Impl, OUString*, pString, bool )
772 std::shared_ptr<const SfxFilter> pFilter = GetFilter4Extension( *pString );
773 return pFilter &&
774 !pFilter->GetWildcard().Matches(u"") &&
775 !pFilter->GetWildcard().Matches(u"*.*") &&
776 !pFilter->GetWildcard().Matches(u"*");
780 SfxFilterMatcherIter::SfxFilterMatcherIter(
781 const SfxFilterMatcher& rMatcher,
782 SfxFilterFlags nOrMaskP, SfxFilterFlags nAndMaskP )
783 : nOrMask( nOrMaskP ), nAndMask( nAndMaskP ),
784 nCurrent(0), m_rMatch(rMatcher.m_rImpl)
786 if( nOrMask == static_cast<SfxFilterFlags>(0xffff) ) //Due to faulty build on s
787 nOrMask = SfxFilterFlags::NONE;
788 m_rMatch.InitForIterating();
792 std::shared_ptr<const SfxFilter> SfxFilterMatcherIter::Find_Impl()
794 std::shared_ptr<const SfxFilter> pFilter;
795 while( nCurrent < m_rMatch.pList->size() )
797 pFilter = (*m_rMatch.pList)[nCurrent++];
798 SfxFilterFlags nFlags = pFilter->GetFilterFlags();
799 if( ((nFlags & nOrMask) == nOrMask ) && !(nFlags & nAndMask ) )
800 break;
801 pFilter = nullptr;
804 return pFilter;
807 std::shared_ptr<const SfxFilter> SfxFilterMatcherIter::First()
809 nCurrent = 0;
810 return Find_Impl();
814 std::shared_ptr<const SfxFilter> SfxFilterMatcherIter::Next()
816 return Find_Impl();
819 /*---------------------------------------------------------------
820 helper to build own formatted string from given stringlist by
821 using given separator
822 ---------------------------------------------------------------*/
823 static OUString implc_convertStringlistToString( const uno::Sequence< OUString >& lList ,
824 sal_Unicode cSeparator,
825 std::u16string_view sPrefix )
827 OUStringBuffer sString ( 1000 ) ;
828 sal_Int32 nCount = lList.getLength();
829 sal_Int32 nItem = 0 ;
830 for( nItem=0; nItem<nCount; ++nItem )
832 if( !sPrefix.empty() )
834 sString.append( sPrefix );
836 sString.append( lList[nItem] );
837 if( nItem+1<nCount )
839 sString.append( cSeparator );
842 return sString.makeStringAndClear();
846 void SfxFilterContainer::ReadSingleFilter_Impl(
847 const OUString& rName,
848 const uno::Reference< container::XNameAccess >& xTypeCFG,
849 const uno::Reference< container::XNameAccess >& xFilterCFG,
850 bool bUpdate
853 OUString sFilterName( rName );
854 SfxFilterList_Impl& rList = *pFilterArr;
855 uno::Sequence< beans::PropertyValue > lFilterProperties;
856 uno::Any aResult;
859 aResult = xFilterCFG->getByName( sFilterName );
861 catch( container::NoSuchElementException& )
863 aResult = uno::Any();
866 if( !(aResult >>= lFilterProperties) )
867 return;
869 // collect information to add filter to container
870 // (attention: some information aren't available on filter directly ... you must search for corresponding type too!)
871 SfxFilterFlags nFlags = SfxFilterFlags::NONE;
872 SotClipboardFormatId nClipboardId = SotClipboardFormatId::NONE;
873 sal_Int32 nFormatVersion = 0 ;
874 OUString sMimeType ;
875 OUString sType ;
876 OUString sUIName ;
877 OUString sHumanName ;
878 OUString sDefaultTemplate ;
879 OUString sUserData ;
880 OUString sExtension ;
881 OUString sServiceName ;
882 bool bEnabled = true ;
884 // first get directly available properties
885 for( const auto& rFilterProperty : std::as_const(lFilterProperties) )
887 if ( rFilterProperty.Name == "FileFormatVersion" )
889 rFilterProperty.Value >>= nFormatVersion;
891 else if ( rFilterProperty.Name == "TemplateName" )
893 rFilterProperty.Value >>= sDefaultTemplate;
895 else if ( rFilterProperty.Name == "Flags" )
897 sal_Int32 nTmp(0);
898 rFilterProperty.Value >>= nTmp;
899 assert((nTmp & ~o3tl::typed_flags<SfxFilterFlags>::mask) == 0);
900 nFlags = static_cast<SfxFilterFlags>(nTmp);
902 else if ( rFilterProperty.Name == "UIName" )
904 rFilterProperty.Value >>= sUIName;
906 else if ( rFilterProperty.Name == "UserData" )
908 uno::Sequence< OUString > lUserData;
909 rFilterProperty.Value >>= lUserData;
910 sUserData = implc_convertStringlistToString( lUserData, ',', u"" );
912 else if ( rFilterProperty.Name == "DocumentService" )
914 rFilterProperty.Value >>= sServiceName;
916 else if (rFilterProperty.Name == "ExportExtension")
918 // Extension preferred by the filter. This takes precedence
919 // over those that are given in the file format type.
920 rFilterProperty.Value >>= sExtension;
921 sExtension = "*." + sExtension;
923 else if ( rFilterProperty.Name == "Type" )
925 rFilterProperty.Value >>= sType;
926 // Try to get filter .. but look for any exceptions!
927 // May be filter was deleted by another thread ...
930 aResult = xTypeCFG->getByName( sType );
932 catch (const container::NoSuchElementException&)
934 aResult = uno::Any();
937 uno::Sequence< beans::PropertyValue > lTypeProperties;
938 if( aResult >>= lTypeProperties )
940 // get indirect available properties then (types)
941 for( const auto& rTypeProperty : std::as_const(lTypeProperties) )
943 if ( rTypeProperty.Name == "ClipboardFormat" )
945 rTypeProperty.Value >>= sHumanName;
947 else if ( rTypeProperty.Name == "MediaType" )
949 rTypeProperty.Value >>= sMimeType;
951 else if ( rTypeProperty.Name == "Extensions" )
953 if (sExtension.isEmpty())
955 uno::Sequence< OUString > lExtensions;
956 rTypeProperty.Value >>= lExtensions;
957 sExtension = implc_convertStringlistToString( lExtensions, ';', u"*." );
963 else if ( rFilterProperty.Name == "Enabled" )
965 rFilterProperty.Value >>= bEnabled;
970 if ( sServiceName.isEmpty() )
971 return;
973 // old formats are found ... using HumanPresentableName!
974 if( !sHumanName.isEmpty() )
976 nClipboardId = SotExchange::RegisterFormatName( sHumanName );
978 // For external filters ignore clipboard IDs
979 if(nFlags & SfxFilterFlags::STARONEFILTER)
981 nClipboardId = SotClipboardFormatId::NONE;
984 // register SfxFilter
985 // first erase module name from old filter names!
986 // e.g: "scalc: DIF" => "DIF"
987 sal_Int32 nStartRealName = sFilterName.indexOf( ": " );
988 if( nStartRealName != -1 )
990 SAL_WARN( "sfx.bastyp", "Old format, not supported!");
991 sFilterName = sFilterName.copy( nStartRealName+2 );
994 std::shared_ptr<const SfxFilter> pFilter = bUpdate ? SfxFilter::GetFilterByName( sFilterName ) : nullptr;
995 if (!pFilter)
997 pFilter = std::make_shared<SfxFilter>( sFilterName ,
998 sExtension ,
999 nFlags ,
1000 nClipboardId ,
1001 sType ,
1002 sMimeType ,
1003 sUserData ,
1004 sServiceName ,
1005 bEnabled );
1006 rList.push_back( pFilter );
1008 else
1010 SfxFilter* pFilt = const_cast<SfxFilter*>(pFilter.get());
1011 pFilt->maFilterName = sFilterName;
1012 pFilt->aWildCard = WildCard(sExtension, ';');
1013 pFilt->nFormatType = nFlags;
1014 pFilt->lFormat = nClipboardId;
1015 pFilt->aTypeName = sType;
1016 pFilt->aMimeType = sMimeType;
1017 pFilt->aUserData = sUserData;
1018 pFilt->aServiceName = sServiceName;
1019 pFilt->mbEnabled = bEnabled;
1022 SfxFilter* pFilt = const_cast<SfxFilter*>(pFilter.get());
1024 // Don't forget to set right UIName!
1025 // Otherwise internal name is used as fallback ...
1026 pFilt->SetUIName( sUIName );
1027 pFilt->SetDefaultTemplate( sDefaultTemplate );
1028 if( nFormatVersion )
1030 pFilt->SetVersion( nFormatVersion );
1034 void SfxFilterContainer::ReadFilters_Impl( bool bUpdate )
1036 if ( !pFilterArr )
1037 CreateFilterArr();
1039 bFirstRead = false;
1040 SfxFilterList_Impl& rList = *pFilterArr;
1044 // get the FilterFactory service to access the registered filters ... and types!
1045 uno::Reference< lang::XMultiServiceFactory > xServiceManager = ::comphelper::getProcessServiceFactory();
1046 uno::Reference< container::XNameAccess > xFilterCFG ;
1047 uno::Reference< container::XNameAccess > xTypeCFG ;
1048 if( xServiceManager.is() )
1050 xFilterCFG.set( xServiceManager->createInstance( "com.sun.star.document.FilterFactory" ), uno::UNO_QUERY );
1051 xTypeCFG.set( xServiceManager->createInstance( "com.sun.star.document.TypeDetection" ), uno::UNO_QUERY );
1054 if( xFilterCFG.is() && xTypeCFG.is() )
1056 // select right query to get right set of filters for search module
1057 const uno::Sequence< OUString > lFilterNames = xFilterCFG->getElementNames();
1058 if ( lFilterNames.hasElements() )
1060 // If list of filters already exist ...
1061 // ReadExternalFilters must work in update mode.
1062 // Best way seems to mark all filters NOT_INSTALLED
1063 // and change it back for all valid filters afterwards.
1064 if( !rList.empty() )
1066 bUpdate = true;
1067 for (const std::shared_ptr<const SfxFilter>& pFilter : rList)
1069 SfxFilter* pNonConstFilter = const_cast<SfxFilter*>(pFilter.get());
1070 pNonConstFilter->nFormatType |= SFX_FILTER_NOTINSTALLED;
1074 // get all properties of filters ... put it into the filter container
1075 for( const OUString& sFilterName : lFilterNames )
1077 // Try to get filter .. but look for any exceptions!
1078 // May be filter was deleted by another thread ...
1079 ReadSingleFilter_Impl( sFilterName, xTypeCFG, xFilterCFG, bUpdate );
1084 catch(const uno::Exception&)
1086 SAL_WARN( "sfx.bastyp", "SfxFilterContainer::ReadFilter()\nException detected. Possible not all filters could be cached." );
1089 if ( bUpdate )
1091 // global filter array was modified, factory specific ones might need an
1092 // update too
1093 for (const auto& aImpl : aImplArr)
1094 aImpl->Update();
1098 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */