1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
64 #include <arrdecl.hxx>
70 unsigned SfxStack::nLevel
= 0;
73 using namespace com::sun::star
;
77 class theSfxFilterListener
: public rtl::Static
<SfxFilterListener
, theSfxFilterListener
> {};
80 SfxFilterList_Impl aList
;
83 SfxFilterList_Impl
& getList()
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
110 explicit SfxFilterContainer_Impl( const OUString
& 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
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
)
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
);
183 !pFilter
->GetServiceName().equalsIgnoreAsciiCase(sServiceName
)
189 // If at least no default filter could be located - use any filter of this
196 for (const std::shared_ptr
<const SfxFilter
>& pCheckFilter
: *pFilterArr
)
198 if ( pCheckFilter
->GetServiceName().equalsIgnoreAsciiCase(sServiceName
) )
200 pFilter
= pCheckFilter
;
210 // Impl-Data is shared between all FilterMatchers of the same factory
211 class SfxFilterMatcher_Impl
215 mutable SfxFilterList_Impl
* pList
; // is created on demand
217 void InitForIterating() const;
219 explicit SfxFilterMatcher_Impl(const OUString
&rName
)
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
)
236 std::vector
<std::unique_ptr
<SfxFilterMatcher_Impl
> > aImplArr
;
237 int nSfxFilterMatcherCount
;
239 SfxFilterMatcher_Impl
& getSfxFilterMatcher_Impl(const OUString
&rName
)
243 if (!rName
.isEmpty())
244 aName
= SfxObjectShell::GetServiceNameFromFactory(rName
);
246 // find the impl-Data of any comparable FilterMatcher that was created
248 for (std::unique_ptr
<SfxFilterMatcher_Impl
>& aImpl
: aImplArr
)
249 if (aImpl
->aName
== aName
)
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
269 ++nSfxFilterMatcherCount
;
272 SfxFilterMatcher::~SfxFilterMatcher()
274 --nSfxFilterMatcherCount
;
275 if (nSfxFilterMatcherCount
== 0)
279 void SfxFilterMatcher_Impl::Update() const
283 // this List was already used
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
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
;
310 // global matcher: use global filter array
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
) )
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
);
339 sTypeName
= xDetection
->queryTypeByURL( rMedium
.GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE
) );
341 catch (uno::Exception
&)
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
;
384 // stream exists => deep detection (with preselection ... if possible)
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
));
395 aDescriptor
[utl::MediaDescriptor::PROP_REFERRER()]
399 if ( !m_rImpl
.aName
.isEmpty() )
400 aDescriptor
[utl::MediaDescriptor::PROP_DOCUMENTSERVICE()] <<= m_rImpl
.aName
;
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
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
);
445 rpFilter
= pNewFilter
;
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
,
467 xQueryBox
->set_default_response(RET_YES
);
469 short nRet
= xQueryBox
->run();
470 if ( nRet
== RET_YES
)
474 std::unique_ptr
<weld::MessageDialog
> xInfoBox(Application::CreateMessageDialog(nullptr,
475 VclMessageType::Info
, VclButtonsType::Ok
,
476 "Here should the Setup now be starting!"));
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
,
500 ErrCode
SfxFilterMatcher::DetectFilter( SfxMedium
& rMedium
, std::shared_ptr
<const SfxFilter
>& rpFilter
) const
503 Here the Filter selection box is pulled up. Otherwise GuessFilter
507 std::shared_ptr
<const SfxFilter
> pOldFilter
= rMedium
.GetFilter();
510 if( !IsFilterInstalled_Impl( pOldFilter
) )
511 pOldFilter
= nullptr;
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
)
532 if ( nErr
== ERRCODE_IO_PENDING
)
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
;
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' ) )
572 nErr
= pFilter
? ERRCODE_NONE
: ERRCODE_ABORT
;
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
);
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() );
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
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
);
624 std::shared_ptr
<const SfxFilter
> SfxFilterMatcher::GetFilter4Mime( const OUString
& rMediaType
, SfxFilterFlags nMust
, SfxFilterFlags nDont
) const
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
)
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
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
)
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
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
);
686 WildCard
aCheck(sWildCard
, ';');
687 if (aCheck
.Matches(sExt
))
695 // Use extension without dot!
696 OUString
sExt( rExt
);
697 if ( sExt
.startsWith(".") )
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
)
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
)
727 else if ( !pFirstFilter
)
728 pFirstFilter
= pFilter
;
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(": ");
740 SAL_WARN( "sfx.bastyp", "Old filter name used!");
741 aName
= rName
.copy( nIndex
+ 2 );
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() )
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
))
769 SfxFilterContainer::ReadSingleFilter_Impl( rName
, xTypeCFG
, xFilterCFG
, false );
773 SfxFilterList_Impl
* pList
= m_rImpl
.pList
;
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
))
787 IMPL_LINK( SfxFilterMatcher
, MaybeFileHdl_Impl
, OUString
*, pString
, bool )
789 std::shared_ptr
<const SfxFilter
> pFilter
= GetFilter4Extension( *pString
);
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
) )
824 std::shared_ptr
<const SfxFilter
> SfxFilterMatcherIter::First()
831 std::shared_ptr
<const SfxFilter
> SfxFilterMatcherIter::Next()
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
] );
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
,
870 OUString
sFilterName( rName
);
871 SfxFilterList_Impl
& rList
= *pFilterArr
;
872 uno::Sequence
< beans::PropertyValue
> lFilterProperties
;
876 aResult
= xFilterCFG
->getByName( sFilterName
);
878 catch( container::NoSuchElementException
& )
880 aResult
= uno::Any();
883 if( !(aResult
>>= lFilterProperties
) )
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 ;
894 OUString sHumanName
;
895 OUString sDefaultTemplate
;
897 OUString sExtension
;
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" )
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() )
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;
1021 pFilter
= std::make_shared
<SfxFilter
>( sFilterName
,
1030 rList
.push_back( pFilter
);
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
)
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() )
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." );
1115 // global filter array was modified, factory specific ones might need an
1117 for (const auto& aImpl
: aImplArr
)
1122 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */