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/datatransfer/DataFlavor.hpp>
27 #include <com/sun/star/document/XTypeDetection.hpp>
28 #include <com/sun/star/container/XContainerQuery.hpp>
30 #include <comphelper/sequenceashashmap.hxx>
32 #include <sot/exchange.hxx>
33 #include <basic/sbmeth.hxx>
34 #include <basic/basmgr.hxx>
35 #include <basic/sbstar.hxx>
36 #include <basic/sbxobj.hxx>
37 #include <basic/sbxmeth.hxx>
38 #include <basic/sbxcore.hxx>
39 #include <vcl/msgbox.hxx>
40 #include <rtl/ustring.hxx>
41 #include <rtl/ustrbuf.hxx>
42 #include <svl/eitem.hxx>
43 #include <svl/intitem.hxx>
44 #include <svl/stritem.hxx>
45 #include <svl/lckbitem.hxx>
46 #include <svl/inettype.hxx>
47 #include <svl/rectitem.hxx>
49 #include <sot/storage.hxx>
50 #include <com/sun/star/frame/XDispatchProviderInterceptor.hpp>
51 #include <com/sun/star/frame/XDispatch.hpp>
52 #include <com/sun/star/frame/XDispatchProvider.hpp>
53 #include <com/sun/star/frame/XStatusListener.hpp>
54 #include <com/sun/star/frame/FrameSearchFlag.hpp>
55 #include <com/sun/star/frame/XDispatchProviderInterception.hpp>
56 #include <com/sun/star/frame/FeatureStateEvent.hpp>
57 #include <com/sun/star/frame/DispatchDescriptor.hpp>
58 #include <com/sun/star/frame/XController.hpp>
59 #include <com/sun/star/frame/XFrameActionListener.hpp>
60 #include <com/sun/star/frame/XComponentLoader.hpp>
61 #include <com/sun/star/frame/XFrame.hpp>
62 #include <com/sun/star/frame/FrameActionEvent.hpp>
63 #include <com/sun/star/frame/FrameAction.hpp>
64 #include <com/sun/star/frame/XFrameLoader.hpp>
65 #include <com/sun/star/frame/XLoadEventListener.hpp>
66 #include <com/sun/star/frame/XFilterDetect.hpp>
67 #include <com/sun/star/loader/XImplementationLoader.hpp>
68 #include <comphelper/processfactory.hxx>
70 #include <sal/types.h>
71 #include <com/sun/star/uno/Reference.hxx>
72 #include <com/sun/star/ucb/XContent.hpp>
73 #include <unotools/pathoptions.hxx>
74 #include <unotools/moduleoptions.hxx>
75 #include <unotools/mediadescriptor.hxx>
76 #include <tools/urlobj.hxx>
78 #include <rtl/instance.hxx>
80 #include <svl/ctypeitm.hxx>
81 #include <svtools/sfxecode.hxx>
82 #include <unotools/syslocale.hxx>
84 #include <sfx2/sfxhelp.hxx>
85 #include <sfx2/docfilt.hxx>
86 #include <sfx2/docfac.hxx>
87 #include "sfxtypes.hxx"
88 #include <sfx2/sfxuno.hxx>
89 #include <sfx2/docfile.hxx>
90 #include <sfx2/progress.hxx>
91 #include "openflag.hxx"
93 #include <sfx2/sfxresid.hxx>
94 #include <sfx2/doctempl.hxx>
95 #include <sfx2/frame.hxx>
96 #include <sfx2/dispatch.hxx>
97 #include <sfx2/viewfrm.hxx>
100 #include <sfx2/request.hxx>
101 #include "arrdecl.hxx"
103 #include <boost/ptr_container/ptr_vector.hpp>
104 #include <functional>
106 #if defined(DBG_UTIL)
107 unsigned SfxStack::nLevel
= 0;
110 using namespace com::sun::star
;
114 class theSfxFilterListener
: public rtl::Static
<SfxFilterListener
, theSfxFilterListener
> {};
117 SfxFilterList_Impl aList
;
121 SfxFilterList_Impl::iterator aEnd
= aList
.end();
122 for (SfxFilterList_Impl::iterator aI
= aList
.begin(); aI
!= aEnd
; ++aI
)
124 SfxFilter
*pFilter
= *aI
;
128 SfxFilterList_Impl
& getList()
133 class theSfxFilterArray
: public rtl::Static
<SfxFilterArray
, theSfxFilterArray
> {};
136 static SfxFilterList_Impl
* pFilterArr
= 0;
137 static bool bFirstRead
= true;
139 static void CreateFilterArr()
141 pFilterArr
= &theSfxFilterArray::get().getList();
142 theSfxFilterListener::get();
145 inline OUString
ToUpper_Impl( const OUString
&rStr
)
147 return SvtSysLocale().GetCharClass().uppercase( rStr
);
150 class SfxFilterContainer_Impl
154 OUString aServiceName
;
156 SfxFilterContainer_Impl( const OUString
& rName
)
159 aServiceName
= SfxObjectShell::GetServiceNameFromFactory( rName
);
163 #define IMPL_FORWARD_LOOP( aMethod, ArgType, aArg ) \
164 const SfxFilter* SfxFilterContainer::aMethod( ArgType aArg, SfxFilterFlags nMust, SfxFilterFlags nDont ) const \
166 SfxFilterMatcher aMatch( pImpl->aName ); \
167 return aMatch.aMethod( aArg, nMust, nDont ); \
170 IMPL_FORWARD_LOOP( GetFilter4EA
, const OUString
&, rEA
);
171 IMPL_FORWARD_LOOP( GetFilter4Extension
, const OUString
&, rExt
);
172 IMPL_FORWARD_LOOP( GetFilter4FilterName
, const OUString
&, rName
);
174 const SfxFilter
* SfxFilterContainer::GetAnyFilter( SfxFilterFlags nMust
, SfxFilterFlags nDont
) const
176 SfxFilterMatcher
aMatch( pImpl
->aName
);
177 return aMatch
.GetAnyFilter( nMust
, nDont
);
182 SfxFilterContainer::SfxFilterContainer( const OUString
& rName
)
184 pImpl
= new SfxFilterContainer_Impl( rName
);
189 SfxFilterContainer::~SfxFilterContainer()
196 const OUString
SfxFilterContainer::GetName() const
201 const SfxFilter
* SfxFilterContainer::GetDefaultFilter_Impl( const OUString
& rName
)
203 // Try to find out the type of factory.
204 // Interpret given name as Service- and ShortName!
205 SvtModuleOptions aOpt
;
206 SvtModuleOptions::EFactory eFactory
= SvtModuleOptions::ClassifyFactoryByServiceName(rName
);
207 if (eFactory
== SvtModuleOptions::EFactory::UNKNOWN_FACTORY
)
208 eFactory
= SvtModuleOptions::ClassifyFactoryByShortName(rName
);
210 // could not classify factory by its service nor by its short name.
211 // Must be an unknown factory! => return NULL
212 if (eFactory
== SvtModuleOptions::EFactory::UNKNOWN_FACTORY
)
215 // For the following code we need some additional information.
216 OUString sServiceName
= aOpt
.GetFactoryName(eFactory
);
217 OUString sDefaultFilter
= aOpt
.GetFactoryDefaultFilter(eFactory
);
219 // Try to get the default filter. Dont fiorget to verify it.
220 // May the set default filter does not exists any longer or
221 // does not fit the given factory.
222 const SfxFilterMatcher aMatcher
;
223 const SfxFilter
* pFilter
= aMatcher
.GetFilter4FilterName(sDefaultFilter
);
227 !pFilter
->GetServiceName().equalsIgnoreAsciiCase(sServiceName
)
233 // If at least no default filter could be located - use any filter of this
240 for ( size_t i
= 0, n
= pFilterArr
->size(); i
< n
; ++i
)
242 const SfxFilter
* pCheckFilter
= (*pFilterArr
)[i
];
243 if ( pCheckFilter
->GetServiceName().equalsIgnoreAsciiCase(sServiceName
) )
245 pFilter
= pCheckFilter
;
257 // Impl-Data is shared between all FilterMatchers of the same factory
258 class SfxFilterMatcher_Impl
262 mutable SfxFilterList_Impl
* pList
; // is created on demand
264 void InitForIterating() const;
266 SfxFilterMatcher_Impl(const OUString
&rName
)
271 ~SfxFilterMatcher_Impl()
273 // SfxFilterMatcher_Impl::InitForIterating() will set pList to
274 // either the global filter array matcher pFilterArr, or to
275 // a new SfxFilterList_Impl.
276 if (pList
!= pFilterArr
)
283 typedef boost::ptr_vector
<SfxFilterMatcher_Impl
> SfxFilterMatcherArr_Impl
;
284 static SfxFilterMatcherArr_Impl aImplArr
;
285 static int nSfxFilterMatcherCount
;
288 public std::unary_function
<SfxFilterMatcher_Impl
, bool>
291 const OUString
& mrName
;
293 hasName(const OUString
&rName
) : mrName(rName
) {}
294 bool operator() (const SfxFilterMatcher_Impl
& rImpl
) const
296 return rImpl
.aName
== mrName
;
300 SfxFilterMatcher_Impl
& getSfxFilterMatcher_Impl(const OUString
&rName
)
304 if (!rName
.isEmpty())
305 aName
= SfxObjectShell::GetServiceNameFromFactory(rName
);
307 // find the impl-Data of any comparable FilterMatcher that was created
309 SfxFilterMatcherArr_Impl::iterator aEnd
= aImplArr
.end();
310 SfxFilterMatcherArr_Impl::iterator aIter
=
311 std::find_if(aImplArr
.begin(), aEnd
, hasName(aName
));
315 // first Matcher created for this factory
316 SfxFilterMatcher_Impl
*pImpl
= new SfxFilterMatcher_Impl(aName
);
317 aImplArr
.push_back(pImpl
);
322 SfxFilterMatcher::SfxFilterMatcher( const OUString
& rName
)
323 : m_rImpl( getSfxFilterMatcher_Impl(rName
) )
325 ++nSfxFilterMatcherCount
;
328 SfxFilterMatcher::SfxFilterMatcher()
329 : m_rImpl( getSfxFilterMatcher_Impl(OUString()) )
331 // global FilterMatcher always uses global filter array (also created on
333 ++nSfxFilterMatcherCount
;
336 SfxFilterMatcher::~SfxFilterMatcher()
338 --nSfxFilterMatcherCount
;
339 if (nSfxFilterMatcherCount
== 0)
343 void SfxFilterMatcher_Impl::Update() const
347 // this List was already used
349 for ( size_t i
= 0, n
= pFilterArr
->size(); i
< n
; ++i
)
351 SfxFilter
* pFilter
= (*pFilterArr
)[i
];
352 if ( pFilter
->GetServiceName() == aName
)
353 pList
->push_back( pFilter
);
358 void SfxFilterMatcher_Impl::InitForIterating() const
364 // global filter array has not been created yet
365 SfxFilterContainer::ReadFilters_Impl();
367 if ( !aName
.isEmpty() )
369 // matcher of factory: use only filters of that document type
370 pList
= new SfxFilterList_Impl
;
375 // global matcher: use global filter array
380 const SfxFilter
* SfxFilterMatcher::GetAnyFilter( SfxFilterFlags nMust
, SfxFilterFlags nDont
) const
382 m_rImpl
.InitForIterating();
383 for ( size_t i
= 0, n
= m_rImpl
.pList
->size(); i
< n
; ++i
)
385 const SfxFilter
* pFilter
= (*m_rImpl
.pList
)[i
];
386 SfxFilterFlags nFlags
= pFilter
->GetFilterFlags();
387 if ( (nFlags
& nMust
) == nMust
&& !(nFlags
& nDont
) )
396 sal_uInt32
SfxFilterMatcher::GuessFilterIgnoringContent(
398 const SfxFilter
**ppFilter
,
399 SfxFilterFlags nMust
,
400 SfxFilterFlags nDont
) const
402 uno::Reference
<document::XTypeDetection
> xDetection(
403 comphelper::getProcessServiceFactory()->createInstance("com.sun.star.document.TypeDetection"), uno::UNO_QUERY
);
408 sTypeName
= xDetection
->queryTypeByURL( rMedium
.GetURLObject().GetMainURL( INetURLObject::NO_DECODE
) );
410 catch (uno::Exception
&)
415 if ( !sTypeName
.isEmpty() )
417 // make sure filter list is initialized
418 m_rImpl
.InitForIterating();
419 *ppFilter
= GetFilter4EA( sTypeName
, nMust
, nDont
);
422 return *ppFilter
? ERRCODE_NONE
: ERRCODE_ABORT
;
427 sal_uInt32
SfxFilterMatcher::GuessFilter( SfxMedium
& rMedium
, const SfxFilter
**ppFilter
, SfxFilterFlags nMust
, SfxFilterFlags nDont
) const
429 return GuessFilterControlDefaultUI( rMedium
, ppFilter
, nMust
, nDont
, true );
434 sal_uInt32
SfxFilterMatcher::GuessFilterControlDefaultUI( SfxMedium
& rMedium
, const SfxFilter
** ppFilter
, SfxFilterFlags nMust
, SfxFilterFlags nDont
, bool /*bDefUI*/ ) const
436 const SfxFilter
* pOldFilter
= *ppFilter
;
438 // no detection service -> nothing to do !
439 uno::Reference
<document::XTypeDetection
> xDetection(
440 comphelper::getProcessServiceFactory()->createInstance("com.sun.star.document.TypeDetection"), uno::UNO_QUERY
);
442 if (!xDetection
.is())
443 return ERRCODE_ABORT
;
448 // open the stream one times only ...
449 // Otherwhise it will be tried more than once and show the same interaction more than once ...
451 OUString
sURL( rMedium
.GetURLObject().GetMainURL( INetURLObject::NO_DECODE
) );
452 uno::Reference
< io::XInputStream
> xInStream
= rMedium
.GetInputStream();
453 OUString aFilterName
;
455 // stream exists => deep detection (with preselection ... if possible)
458 utl::MediaDescriptor aDescriptor
;
460 aDescriptor
[utl::MediaDescriptor::PROP_URL() ] <<= sURL
;
461 aDescriptor
[utl::MediaDescriptor::PROP_INPUTSTREAM() ] <<= xInStream
;
462 aDescriptor
[utl::MediaDescriptor::PROP_INTERACTIONHANDLER()] <<= rMedium
.GetInteractionHandler();
463 SfxStringItem
const * it
= static_cast<SfxStringItem
const *>(
464 rMedium
.GetItemSet()->GetItem(SID_REFERER
));
466 aDescriptor
[utl::MediaDescriptor::PROP_REFERRER()]
470 if ( !m_rImpl
.aName
.isEmpty() )
471 aDescriptor
[utl::MediaDescriptor::PROP_DOCUMENTSERVICE()] <<= m_rImpl
.aName
;
475 aDescriptor
[utl::MediaDescriptor::PROP_TYPENAME() ] <<= OUString( pOldFilter
->GetTypeName() );
476 aDescriptor
[utl::MediaDescriptor::PROP_FILTERNAME()] <<= OUString( pOldFilter
->GetFilterName() );
479 uno::Sequence
< beans::PropertyValue
> lDescriptor
= aDescriptor
.getAsConstPropertyValueList();
480 sTypeName
= xDetection
->queryTypeByDescriptor(lDescriptor
, sal_True
); // lDescriptor is used as In/Out param ... dont use aDescriptor.getAsConstPropertyValueList() directly!
482 for (sal_Int32 i
= 0; i
< lDescriptor
.getLength(); ++i
)
484 if (lDescriptor
[i
].Name
== "FilterName")
485 // Type detection picked a preferred filter for this format.
486 aFilterName
= lDescriptor
[i
].Value
.get
<OUString
>();
489 // no stream exists => try flat detection without preselection as fallback
491 sTypeName
= xDetection
->queryTypeByURL(sURL
);
493 if (!sTypeName
.isEmpty())
495 const SfxFilter
* pFilter
= NULL
;
496 if (!aFilterName
.isEmpty())
497 // Type detection returned a suitable filter for this. Use it.
498 pFilter
= SfxFilter::GetFilterByName(aFilterName
);
500 // fdo#78742 respect requested document service if set
501 if (!pFilter
|| (!m_rImpl
.aName
.isEmpty()
502 && m_rImpl
.aName
!= pFilter
->GetServiceName()))
504 // detect filter by given type
505 // In case of this matcher is bound to a particular document type:
506 // If there is no acceptable type for this document at all, the type detection has possibly returned something else.
507 // The DocumentService property is only a preselection, and all preselections are considered as optional!
508 // This "wrong" type will be sorted out now because we match only allowed filters to the detected type
509 uno::Sequence
< beans::NamedValue
> lQuery(1);
510 lQuery
[0].Name
= "Name";
511 lQuery
[0].Value
<<= sTypeName
;
513 pFilter
= GetFilterForProps(lQuery
, nMust
, nDont
);
523 catch (const uno::Exception
&)
526 return ERRCODE_ABORT
;
530 bool SfxFilterMatcher::IsFilterInstalled_Impl( const SfxFilter
* pFilter
)
532 if ( pFilter
->GetFilterFlags() & SfxFilterFlags::MUSTINSTALL
)
534 // Here could a re-installation be offered
535 OUString
aText( SfxResId(STR_FILTER_NOT_INSTALLED
).toString() );
536 aText
= aText
.replaceFirst( "$(FILTER)", pFilter
->GetUIName() );
537 ScopedVclPtrInstance
< QueryBox
> aQuery(nullptr, WB_YES_NO
| WB_DEF_YES
, aText
);
538 short nRet
= aQuery
->Execute();
539 if ( nRet
== RET_YES
)
543 ScopedVclPtr
<InfoBox
>::Create( nullptr, "Here should the Setup now be starting!" )->Execute();
545 // Installation must still give feedback if it worked or not,
546 // then the Filterflag be deleted
549 return ( !(pFilter
->GetFilterFlags() & SfxFilterFlags::MUSTINSTALL
) );
551 else if ( pFilter
->GetFilterFlags() & SfxFilterFlags::CONSULTSERVICE
)
553 OUString
aText( SfxResId(STR_FILTER_CONSULT_SERVICE
).toString() );
554 aText
= aText
.replaceFirst( "$(FILTER)", pFilter
->GetUIName() );
555 ScopedVclPtr
<InfoBox
>::Create( nullptr, aText
)->Execute();
563 sal_uInt32
SfxFilterMatcher::DetectFilter( SfxMedium
& rMedium
, const SfxFilter
**ppFilter
, bool /*bPlugIn*/, bool bAPI
) const
566 Here the Filter selection box is pulled up. Otherwise GuessFilter
570 const SfxFilter
* pOldFilter
= rMedium
.GetFilter();
573 if( !IsFilterInstalled_Impl( pOldFilter
) )
577 SFX_ITEMSET_ARG( rMedium
.GetItemSet(), pSalvageItem
, SfxStringItem
, SID_DOC_SALVAGE
, false);
578 if ( ( pOldFilter
->GetFilterFlags() & SfxFilterFlags::PACKED
) && pSalvageItem
)
579 // Salvage is always done without packing
584 const SfxFilter
* pFilter
= pOldFilter
;
586 bool bPreview
= rMedium
.IsPreview_Impl();
587 SFX_ITEMSET_ARG(rMedium
.GetItemSet(), pReferer
, SfxStringItem
, SID_REFERER
, false);
588 if ( bPreview
&& rMedium
.IsRemote() && ( !pReferer
|| !pReferer
->GetValue().match("private:searchfolder:") ) )
589 return ERRCODE_ABORT
;
591 ErrCode nErr
= GuessFilter( rMedium
, &pFilter
);
592 if ( nErr
== ERRCODE_ABORT
)
595 if ( nErr
== ERRCODE_IO_PENDING
)
603 const SfxFilter
* pInstallFilter
= NULL
;
605 // Now test the filter which are not installed (ErrCode is irrelevant)
606 GuessFilter( rMedium
, &pInstallFilter
, SfxFilterFlags::IMPORT
, SfxFilterFlags::CONSULTSERVICE
);
607 if ( pInstallFilter
)
609 if ( IsFilterInstalled_Impl( pInstallFilter
) )
610 // Maybe the filter was installed was installed afterwards.
611 pFilter
= pInstallFilter
;
615 // Now test the filter, which first must be obtained by Star
616 // (ErrCode is irrelevant)
617 GuessFilter( rMedium
, &pInstallFilter
, SfxFilterFlags::IMPORT
, SfxFilterFlags::NONE
);
618 if ( pInstallFilter
)
619 IsFilterInstalled_Impl( pInstallFilter
);
623 bool bHidden
= bPreview
;
624 SFX_ITEMSET_ARG( rMedium
.GetItemSet(), pFlags
, SfxStringItem
, SID_OPTIONS
, false);
625 if ( !bHidden
&& pFlags
)
627 OUString
aFlags( pFlags
->GetValue() );
628 aFlags
= aFlags
.toAsciiUpperCase();
629 if( -1 != aFlags
.indexOf( 'H' ) )
634 if ( bHidden
|| (bAPI
&& nErr
== ERRCODE_SFX_CONSULTUSER
) )
635 nErr
= pFilter
? ERRCODE_NONE
: ERRCODE_ABORT
;
639 const SfxFilter
* SfxFilterMatcher::GetFilterForProps( const com::sun::star::uno::Sequence
< beans::NamedValue
>& aSeq
, SfxFilterFlags nMust
, SfxFilterFlags nDont
) const
641 uno::Reference
< lang::XMultiServiceFactory
> xServiceManager
= ::comphelper::getProcessServiceFactory();
642 uno::Reference
< container::XContainerQuery
> xTypeCFG
;
643 if( xServiceManager
.is() )
644 xTypeCFG
= uno::Reference
< com::sun::star::container::XContainerQuery
>( xServiceManager
->createInstance( "com.sun.star.document.TypeDetection" ), uno::UNO_QUERY
);
647 // make query for all types matching the properties
648 uno::Reference
< com::sun::star::container::XEnumeration
> xEnum
= xTypeCFG
->createSubSetEnumerationByProperties( aSeq
);
649 while ( xEnum
->hasMoreElements() )
651 ::comphelper::SequenceAsHashMap
aProps( xEnum
->nextElement() );
654 // try to get the preferred filter (works without loading all filters!)
655 if ( (aProps
[OUString("PreferredFilter")] >>= aValue
) && !aValue
.isEmpty() )
657 const SfxFilter
* pFilter
= SfxFilter::GetFilterByName( aValue
);
658 if ( !pFilter
|| (pFilter
->GetFilterFlags() & nMust
) != nMust
|| (pFilter
->GetFilterFlags() & nDont
) )
659 // check for filter flags
660 // pFilter == 0: if preferred filter is a Writer filter, but Writer module is not installed
663 if ( !m_rImpl
.aName
.isEmpty() )
665 // if this is not the global FilterMatcher: check if filter matches the document type
666 if ( pFilter
->GetServiceName() != m_rImpl
.aName
)
668 // preferred filter belongs to another document type; now we must search the filter
669 m_rImpl
.InitForIterating();
670 aProps
[OUString("Name")] >>= aValue
;
671 pFilter
= GetFilter4EA( aValue
, nMust
, nDont
);
687 const SfxFilter
* SfxFilterMatcher::GetFilter4Mime( const OUString
& rMediaType
, SfxFilterFlags nMust
, SfxFilterFlags nDont
) const
691 for ( size_t i
= 0, n
= m_rImpl
.pList
->size(); i
< n
; ++i
)
693 const SfxFilter
* pFilter
= (*m_rImpl
.pList
)[i
];
694 SfxFilterFlags nFlags
= pFilter
->GetFilterFlags();
695 if ( (nFlags
& nMust
) == nMust
&& !(nFlags
& nDont
) && pFilter
->GetMimeType() == rMediaType
)
702 com::sun::star::uno::Sequence
< com::sun::star::beans::NamedValue
> aSeq(1);
703 aSeq
[0].Name
= "MediaType";
704 aSeq
[0].Value
<<= rMediaType
;
705 return GetFilterForProps( aSeq
, nMust
, nDont
);
708 const SfxFilter
* SfxFilterMatcher::GetFilter4EA( const OUString
& rType
, SfxFilterFlags nMust
, SfxFilterFlags nDont
) const
712 const SfxFilter
* pFirst
= 0;
713 for ( size_t i
= 0, n
= m_rImpl
.pList
->size(); i
< n
; ++i
)
715 const SfxFilter
* pFilter
= (*m_rImpl
.pList
)[i
];
716 SfxFilterFlags nFlags
= pFilter
->GetFilterFlags();
717 if ( (nFlags
& nMust
) == nMust
&& !(nFlags
& nDont
) && pFilter
->GetTypeName() == rType
)
719 if (nFlags
& SfxFilterFlags::PREFERED
)
731 com::sun::star::uno::Sequence
< com::sun::star::beans::NamedValue
> aSeq(1);
732 aSeq
[0].Name
= "Name";
733 aSeq
[0].Value
<<= OUString( rType
);
734 return GetFilterForProps( aSeq
, nMust
, nDont
);
737 const SfxFilter
* SfxFilterMatcher::GetFilter4Extension( const OUString
& rExt
, SfxFilterFlags nMust
, SfxFilterFlags nDont
) const
741 for ( size_t i
= 0, n
= m_rImpl
.pList
->size(); i
< n
; ++i
)
743 const SfxFilter
* pFilter
= (*m_rImpl
.pList
)[i
];
744 SfxFilterFlags nFlags
= pFilter
->GetFilterFlags();
745 if ( (nFlags
& nMust
) == nMust
&& !(nFlags
& nDont
) )
747 OUString sWildCard
= ToUpper_Impl( pFilter
->GetWildcard().getGlob() );
748 OUString sExt
= ToUpper_Impl( rExt
);
753 if (sExt
[0] != (sal_Unicode
)'.')
756 WildCard
aCheck(sWildCard
, ';');
757 if (aCheck
.Matches(sExt
))
765 // Use extension without dot!
766 OUString
sExt( rExt
);
767 if ( sExt
.startsWith(".") )
770 com::sun::star::uno::Sequence
< com::sun::star::beans::NamedValue
> aSeq(1);
771 aSeq
[0].Name
= "Extensions";
772 uno::Sequence
< OUString
> aExts(1);
774 aSeq
[0].Value
<<= aExts
;
775 return GetFilterForProps( aSeq
, nMust
, nDont
);
778 const SfxFilter
* SfxFilterMatcher::GetFilter4ClipBoardId( SotClipboardFormatId nId
, SfxFilterFlags nMust
, SfxFilterFlags nDont
) const
780 if (nId
== SotClipboardFormatId::NONE
)
783 com::sun::star::uno::Sequence
< com::sun::star::beans::NamedValue
> aSeq(1);
784 OUString aName
= SotExchange::GetFormatName( nId
);
785 aSeq
[0].Name
= "ClipboardFormat";
786 aSeq
[0].Value
<<= aName
;
787 return GetFilterForProps( aSeq
, nMust
, nDont
);
790 const SfxFilter
* SfxFilterMatcher::GetFilter4UIName( const OUString
& rName
, SfxFilterFlags nMust
, SfxFilterFlags nDont
) const
792 m_rImpl
.InitForIterating();
793 const SfxFilter
* pFirstFilter
=0;
794 for ( size_t i
= 0, n
= m_rImpl
.pList
->size(); i
< n
; ++i
)
796 const SfxFilter
* pFilter
= (*m_rImpl
.pList
)[i
];
797 SfxFilterFlags nFlags
= pFilter
->GetFilterFlags();
798 if ( (nFlags
& nMust
) == nMust
&&
799 !(nFlags
& nDont
) && pFilter
->GetUIName() == rName
)
801 if ( pFilter
->GetFilterFlags() & SfxFilterFlags::PREFERED
)
803 else if ( !pFirstFilter
)
804 pFirstFilter
= pFilter
;
810 const SfxFilter
* SfxFilterMatcher::GetFilter4FilterName( const OUString
& rName
, SfxFilterFlags nMust
, SfxFilterFlags nDont
) const
812 OUString
aName( rName
);
813 sal_Int32 nIndex
= aName
.indexOf(": ");
816 SAL_WARN( "sfx.bastyp", "Old filter name used!");
817 aName
= rName
.copy( nIndex
+ 2 );
822 uno::Reference
< lang::XMultiServiceFactory
> xServiceManager
= ::comphelper::getProcessServiceFactory();
823 uno::Reference
< container::XNameAccess
> xFilterCFG
;
824 uno::Reference
< container::XNameAccess
> xTypeCFG
;
825 if( xServiceManager
.is() )
827 xFilterCFG
= uno::Reference
< container::XNameAccess
>( xServiceManager
->createInstance( "com.sun.star.document.FilterFactory" ), uno::UNO_QUERY
);
828 xTypeCFG
= uno::Reference
< container::XNameAccess
>( xServiceManager
->createInstance( "com.sun.star.document.TypeDetection" ), uno::UNO_QUERY
);
831 if( xFilterCFG
.is() && xTypeCFG
.is() )
837 for ( size_t i
= 0, n
= pFilterArr
->size(); i
< n
; ++i
)
839 const SfxFilter
* pFilter
= (*pFilterArr
)[i
];
840 SfxFilterFlags nFlags
= pFilter
->GetFilterFlags();
841 if ((nFlags
& nMust
) == nMust
&& !(nFlags
& nDont
) && pFilter
->GetFilterName().equalsIgnoreAsciiCase(aName
))
846 SfxFilterContainer::ReadSingleFilter_Impl( rName
, xTypeCFG
, xFilterCFG
, false );
850 SfxFilterList_Impl
* pList
= m_rImpl
.pList
;
854 for ( size_t i
= 0, n
= pList
->size(); i
< n
; ++i
)
856 const SfxFilter
* pFilter
= (*pList
)[i
];
857 SfxFilterFlags nFlags
= pFilter
->GetFilterFlags();
858 if ( (nFlags
& nMust
) == nMust
&& !(nFlags
& nDont
) && pFilter
->GetFilterName().equalsIgnoreAsciiCase(aName
))
865 IMPL_LINK_TYPED( SfxFilterMatcher
, MaybeFileHdl_Impl
, OUString
*, pString
, bool )
867 const SfxFilter
* pFilter
= GetFilter4Extension( *pString
, SfxFilterFlags::IMPORT
);
868 if (pFilter
&& !pFilter
->GetWildcard().Matches( OUString() ) &&
869 !pFilter
->GetWildcard().Matches(OUString("*.*")) &&
870 !pFilter
->GetWildcard().Matches(OUString('*'))
880 SfxFilterMatcherIter::SfxFilterMatcherIter(
881 const SfxFilterMatcher
& rMatcher
,
882 SfxFilterFlags nOrMaskP
, SfxFilterFlags nAndMaskP
)
883 : nOrMask( nOrMaskP
), nAndMask( nAndMaskP
),
884 nCurrent(0), m_rMatch(rMatcher
.m_rImpl
)
886 if( nOrMask
== static_cast<SfxFilterFlags
>(0xffff) ) //Due to faulty build on s
887 nOrMask
= SfxFilterFlags::NONE
;
888 m_rMatch
.InitForIterating();
893 const SfxFilter
* SfxFilterMatcherIter::Find_Impl()
895 const SfxFilter
* pFilter
= 0;
896 while( nCurrent
< m_rMatch
.pList
->size() )
898 pFilter
= (*m_rMatch
.pList
)[nCurrent
++];
899 SfxFilterFlags nFlags
= pFilter
->GetFilterFlags();
900 if( ((nFlags
& nOrMask
) == nOrMask
) && !(nFlags
& nAndMask
) )
908 const SfxFilter
* SfxFilterMatcherIter::First()
916 const SfxFilter
* SfxFilterMatcherIter::Next()
921 /*---------------------------------------------------------------
922 helper to build own formatted string from given stringlist by
923 using given separator
924 ---------------------------------------------------------------*/
925 OUString
implc_convertStringlistToString( const uno::Sequence
< OUString
>& lList
,
926 const sal_Unicode
& cSeparator
,
927 const OUString
& sPrefix
)
929 OUStringBuffer
sString ( 1000 ) ;
930 sal_Int32 nCount
= lList
.getLength();
931 sal_Int32 nItem
= 0 ;
932 for( nItem
=0; nItem
<nCount
; ++nItem
)
934 if( !sPrefix
.isEmpty() )
936 sString
.append( sPrefix
);
938 sString
.append( lList
[nItem
] );
941 sString
.append( cSeparator
);
944 return sString
.makeStringAndClear();
948 void SfxFilterContainer::ReadSingleFilter_Impl(
949 const OUString
& rName
,
950 const uno::Reference
< container::XNameAccess
>& xTypeCFG
,
951 const uno::Reference
< container::XNameAccess
>& xFilterCFG
,
955 OUString
sFilterName( rName
);
956 SfxFilterList_Impl
& rList
= *pFilterArr
;
957 uno::Sequence
< beans::PropertyValue
> lFilterProperties
;
961 aResult
= xFilterCFG
->getByName( sFilterName
);
963 catch( container::NoSuchElementException
& )
965 aResult
= uno::Any();
968 if( aResult
>>= lFilterProperties
)
970 // collect information to add filter to container
971 // (attention: some information aren't available on filter directly ... you must search for corresponding type too!)
972 SfxFilterFlags nFlags
= SfxFilterFlags::NONE
;
973 SotClipboardFormatId nClipboardId
= SotClipboardFormatId::NONE
;
974 sal_Int32 nDocumentIconId
= 0 ;
975 sal_Int32 nFormatVersion
= 0 ;
979 OUString sHumanName
;
980 OUString sDefaultTemplate
;
982 OUString sExtension
;
984 OUString sServiceName
;
986 // first get directly available properties
987 sal_Int32 nFilterPropertyCount
= lFilterProperties
.getLength();
988 sal_Int32 nFilterProperty
= 0 ;
989 for( nFilterProperty
=0; nFilterProperty
<nFilterPropertyCount
; ++nFilterProperty
)
991 if ( lFilterProperties
[nFilterProperty
].Name
== "FileFormatVersion" )
993 lFilterProperties
[nFilterProperty
].Value
>>= nFormatVersion
;
995 else if ( lFilterProperties
[nFilterProperty
].Name
== "TemplateName" )
997 lFilterProperties
[nFilterProperty
].Value
>>= sDefaultTemplate
;
999 else if ( lFilterProperties
[nFilterProperty
].Name
== "Flags" )
1002 lFilterProperties
[nFilterProperty
].Value
>>= nTmp
;
1003 nFlags
= static_cast<SfxFilterFlags
>(nTmp
);
1005 else if ( lFilterProperties
[nFilterProperty
].Name
== "UIName" )
1007 lFilterProperties
[nFilterProperty
].Value
>>= sUIName
;
1009 else if ( lFilterProperties
[nFilterProperty
].Name
== "UserData" )
1011 uno::Sequence
< OUString
> lUserData
;
1012 lFilterProperties
[nFilterProperty
].Value
>>= lUserData
;
1013 sUserData
= implc_convertStringlistToString( lUserData
, ',', OUString() );
1015 else if ( lFilterProperties
[nFilterProperty
].Name
== "DocumentService" )
1017 lFilterProperties
[nFilterProperty
].Value
>>= sServiceName
;
1019 else if (lFilterProperties
[nFilterProperty
].Name
== "ExportExtension")
1021 // Extension preferred by the filter. This takes precedence
1022 // over those that are given in the file format type.
1023 lFilterProperties
[nFilterProperty
].Value
>>= sExtension
;
1024 sExtension
= "*." + sExtension
;
1026 else if ( lFilterProperties
[nFilterProperty
].Name
== "Type" )
1028 lFilterProperties
[nFilterProperty
].Value
>>= sType
;
1029 // Try to get filter .. but look for any exceptions!
1030 // May be filter was deleted by another thread ...
1033 aResult
= xTypeCFG
->getByName( sType
);
1035 catch (const container::NoSuchElementException
&)
1037 aResult
= uno::Any();
1040 uno::Sequence
< beans::PropertyValue
> lTypeProperties
;
1041 if( aResult
>>= lTypeProperties
)
1043 // get indirect available properties then (types)
1044 sal_Int32 nTypePropertyCount
= lTypeProperties
.getLength();
1045 sal_Int32 nTypeProperty
= 0 ;
1046 for( nTypeProperty
=0; nTypeProperty
<nTypePropertyCount
; ++nTypeProperty
)
1048 if ( lTypeProperties
[nTypeProperty
].Name
== "ClipboardFormat" )
1050 lTypeProperties
[nTypeProperty
].Value
>>= sHumanName
;
1052 else if ( lTypeProperties
[nTypeProperty
].Name
== "DocumentIconID" )
1054 lTypeProperties
[nTypeProperty
].Value
>>= nDocumentIconId
;
1056 else if ( lTypeProperties
[nTypeProperty
].Name
== "MediaType" )
1058 lTypeProperties
[nTypeProperty
].Value
>>= sMimeType
;
1060 else if ( lTypeProperties
[nTypeProperty
].Name
== "Extensions" )
1062 if (sExtension
.isEmpty())
1064 uno::Sequence
< OUString
> lExtensions
;
1065 lTypeProperties
[nTypeProperty
].Value
>>= lExtensions
;
1066 sExtension
= implc_convertStringlistToString( lExtensions
, ';', "*." );
1069 else if ( lTypeProperties
[nTypeProperty
].Name
== "URLPattern" )
1071 uno::Sequence
< OUString
> lPattern
;
1072 lTypeProperties
[nTypeProperty
].Value
>>= lPattern
;
1073 sPattern
= implc_convertStringlistToString( lPattern
, ';', OUString() );
1080 if ( sServiceName
.isEmpty() )
1083 // old formats are found ... using HumanPresentableName!
1084 if( !sHumanName
.isEmpty() )
1086 nClipboardId
= SotExchange::RegisterFormatName( sHumanName
);
1088 // For external filters ignore clipboard IDs
1089 if(nFlags
& SfxFilterFlags::STARONEFILTER
)
1091 nClipboardId
= SotClipboardFormatId::NONE
;
1094 // register SfxFilter
1095 // first erase module name from old filter names!
1096 // e.g: "scalc: DIF" => "DIF"
1097 sal_Int32 nStartRealName
= sFilterName
.indexOf( ": ", 0 );
1098 if( nStartRealName
!= -1 )
1100 SAL_WARN( "sfx.bastyp", "Old format, not supported!");
1101 sFilterName
= sFilterName
.copy( nStartRealName
+2 );
1104 SfxFilter
* pFilter
= bUpdate
? const_cast<SfxFilter
*>(SfxFilter::GetFilterByName( sFilterName
)) : 0;
1109 pFilter
= new SfxFilter( sFilterName
,
1114 (sal_uInt16
)nDocumentIconId
,
1121 pFilter
->maFilterName
= sFilterName
;
1122 pFilter
->aWildCard
= WildCard(sExtension
, ';');
1123 pFilter
->nFormatType
= nFlags
;
1124 pFilter
->lFormat
= nClipboardId
;
1125 pFilter
->aTypeName
= sType
;
1126 pFilter
->nDocIcon
= (sal_uInt16
)nDocumentIconId
;
1127 pFilter
->aMimeType
= sMimeType
;
1128 pFilter
->aUserData
= sUserData
;
1129 pFilter
->aServiceName
= sServiceName
;
1132 // Don't forget to set right UIName!
1133 // Otherwise internal name is used as fallback ...
1134 pFilter
->SetUIName( sUIName
);
1135 pFilter
->SetDefaultTemplate( sDefaultTemplate
);
1136 if( nFormatVersion
)
1138 pFilter
->SetVersion( nFormatVersion
);
1140 pFilter
->SetURLPattern(sPattern
);
1143 rList
.push_back( pFilter
);
1147 void SfxFilterContainer::ReadFilters_Impl( bool bUpdate
)
1153 SfxFilterList_Impl
& rList
= *pFilterArr
;
1157 // get the FilterFactory service to access the registered filters ... and types!
1158 uno::Reference
< lang::XMultiServiceFactory
> xServiceManager
= ::comphelper::getProcessServiceFactory();
1159 uno::Reference
< container::XNameAccess
> xFilterCFG
;
1160 uno::Reference
< container::XNameAccess
> xTypeCFG
;
1161 if( xServiceManager
.is() )
1163 xFilterCFG
= uno::Reference
< container::XNameAccess
>( xServiceManager
->createInstance( "com.sun.star.document.FilterFactory" ), uno::UNO_QUERY
);
1164 xTypeCFG
= uno::Reference
< container::XNameAccess
>( xServiceManager
->createInstance( "com.sun.star.document.TypeDetection" ), uno::UNO_QUERY
);
1167 if( xFilterCFG
.is() && xTypeCFG
.is() )
1169 // select right query to get right set of filters for search modul
1170 uno::Sequence
< OUString
> lFilterNames
= xFilterCFG
->getElementNames();
1171 if ( lFilterNames
.getLength() )
1173 // If list of filters already exist ...
1174 // ReadExternalFilters must work in update mode.
1175 // Best way seems to mark all filters NOT_INSTALLED
1176 // and change it back for all valid filters afterwards.
1177 if( !rList
.empty() )
1181 for ( size_t i
= 0, n
= rList
.size(); i
< n
; ++i
)
1183 pFilter
= rList
[ i
];
1184 pFilter
->nFormatType
|= SFX_FILTER_NOTINSTALLED
;
1188 // get all properties of filters ... put it into the filter container
1189 sal_Int32 nFilterCount
= lFilterNames
.getLength();
1190 sal_Int32 nFilter
=0;
1191 for( nFilter
=0; nFilter
<nFilterCount
; ++nFilter
)
1193 // Try to get filter .. but look for any exceptions!
1194 // May be filter was deleted by another thread ...
1195 OUString sFilterName
= lFilterNames
[nFilter
];
1196 ReadSingleFilter_Impl( sFilterName
, xTypeCFG
, xFilterCFG
, bUpdate
);
1201 catch(const uno::Exception
&)
1203 SAL_WARN( "sfx.bastyp", "SfxFilterContainer::ReadFilter()\nException detected. Possible not all filters could be cached.\n" );
1208 // global filter arry was modified, factory specific ones might need an
1210 std::for_each(aImplArr
.begin(), aImplArr
.end(),
1211 std::mem_fun_ref(&SfxFilterMatcher_Impl::Update
));
1215 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */