Bump version to 4.1-6
[LibreOffice.git] / sfx2 / source / bastyp / fltfnc.cxx
blob42477d09916fca39c1f5fe1da3341c9d167e53fa
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 "fltfnc.hxx"
22 #include <com/sun/star/uno/Exception.hpp>
23 #include <com/sun/star/beans/PropertyValue.hpp>
24 #include <com/sun/star/beans/NamedValue.hpp>
25 #include <com/sun/star/container/XNameAccess.hpp>
26 #include <com/sun/star/container/XEnumeration.hpp>
27 #include <com/sun/star/datatransfer/DataFlavor.hpp>
28 #include <com/sun/star/document/XTypeDetection.hpp>
29 #include <com/sun/star/container/XContainerQuery.hpp>
31 #include <comphelper/sequenceashashmap.hxx>
33 #include <sot/exchange.hxx>
34 #include <basic/sbmeth.hxx>
35 #include <basic/basmgr.hxx>
36 #include <basic/sbstar.hxx>
37 #include <basic/sbxobj.hxx>
38 #include <basic/sbxmeth.hxx>
39 #include <basic/sbxcore.hxx>
40 #include <vcl/msgbox.hxx>
41 #include <rtl/ustring.hxx>
42 #include <rtl/ustrbuf.hxx>
43 #include <svl/eitem.hxx>
44 #include <svl/intitem.hxx>
45 #include <svl/stritem.hxx>
46 #include <svl/lckbitem.hxx>
47 #include <svl/inettype.hxx>
48 #include <svl/rectitem.hxx>
50 #include <sot/storage.hxx>
51 #include <com/sun/star/frame/XDispatchProviderInterceptor.hpp>
52 #include <com/sun/star/frame/XDispatch.hpp>
53 #include <com/sun/star/frame/XDispatchProvider.hpp>
54 #include <com/sun/star/frame/XStatusListener.hpp>
55 #include <com/sun/star/frame/FrameSearchFlag.hpp>
56 #include <com/sun/star/frame/XDispatchProviderInterception.hpp>
57 #include <com/sun/star/frame/FeatureStateEvent.hpp>
58 #include <com/sun/star/frame/DispatchDescriptor.hpp>
59 #include <com/sun/star/frame/XController.hpp>
60 #include <com/sun/star/frame/XFrameActionListener.hpp>
61 #include <com/sun/star/frame/XComponentLoader.hpp>
62 #include <com/sun/star/frame/XFrame.hpp>
63 #include <com/sun/star/frame/FrameActionEvent.hpp>
64 #include <com/sun/star/frame/FrameAction.hpp>
65 #include <com/sun/star/frame/XFrameLoader.hpp>
66 #include <com/sun/star/frame/XLoadEventListener.hpp>
67 #include <com/sun/star/frame/XFilterDetect.hpp>
68 #include <com/sun/star/loader/XImplementationLoader.hpp>
69 #include <comphelper/processfactory.hxx>
71 #include <sal/types.h>
72 #include <com/sun/star/uno/Reference.hxx>
73 #include <com/sun/star/ucb/XContent.hpp>
74 #include <unotools/pathoptions.hxx>
75 #include <unotools/moduleoptions.hxx>
76 #include <comphelper/mediadescriptor.hxx>
77 #include <tools/urlobj.hxx>
79 #include <rtl/logfile.hxx>
80 #include <rtl/instance.hxx>
82 #include <svl/ctypeitm.hxx>
83 #include <svtools/sfxecode.hxx>
84 #include <unotools/syslocale.hxx>
86 #include "sfx2/sfxhelp.hxx"
87 #include <sfx2/docfilt.hxx>
88 #include <sfx2/docfac.hxx>
89 #include "sfxtypes.hxx"
90 #include <sfx2/sfxuno.hxx>
91 #include <sfx2/docfile.hxx>
92 #include <sfx2/progress.hxx>
93 #include "openflag.hxx"
94 #include "bastyp.hrc"
95 #include "sfx2/sfxresid.hxx"
96 #include <sfx2/doctempl.hxx>
97 #include <sfx2/frame.hxx>
98 #include <sfx2/dispatch.hxx>
99 #include <sfx2/viewfrm.hxx>
100 #include "helper.hxx"
101 #include "fltlst.hxx"
102 #include <sfx2/request.hxx>
103 #include "arrdecl.hxx"
104 #include <sfx2/appuno.hxx>
106 #include <boost/ptr_container/ptr_vector.hpp>
107 #include <functional>
109 #if defined(DBG_UTIL) && defined(WNT)
110 unsigned SfxStack::nLevel = 0;
111 #endif
113 using namespace com::sun::star;
115 namespace
117 class theSfxFilterListener : public rtl::Static<SfxFilterListener, theSfxFilterListener> {};
118 class theSfxFilterArray : public rtl::Static<SfxFilterList_Impl, theSfxFilterArray > {};
121 static SfxFilterList_Impl* pFilterArr = 0;
122 static sal_Bool bFirstRead = sal_True;
124 static void CreateFilterArr()
126 pFilterArr = &theSfxFilterArray::get();
127 theSfxFilterListener::get();
130 //----------------------------------------------------------------
131 inline String ToUpper_Impl( const String &rStr )
133 return SvtSysLocale().GetCharClass().uppercase( rStr );
136 //----------------------------------------------------------------
137 class SfxFilterContainer_Impl
139 public:
140 String aName;
141 String aServiceName;
143 SfxFilterContainer_Impl( const String& rName )
144 : aName( rName )
146 aServiceName = SfxObjectShell::GetServiceNameFromFactory( rName );
150 #define IMPL_FORWARD_LOOP( aMethod, ArgType, aArg ) \
151 const SfxFilter* SfxFilterContainer::aMethod( ArgType aArg, SfxFilterFlags nMust, SfxFilterFlags nDont ) const \
153 SfxFilterMatcher aMatch( pImpl->aName ); \
154 return aMatch.aMethod( aArg, nMust, nDont ); \
157 IMPL_FORWARD_LOOP( GetFilter4EA, const String&, rEA );
158 IMPL_FORWARD_LOOP( GetFilter4Extension, const String&, rExt );
159 IMPL_FORWARD_LOOP( GetFilter4FilterName, const String&, rName );
161 const SfxFilter* SfxFilterContainer::GetAnyFilter( SfxFilterFlags nMust, SfxFilterFlags nDont ) const
163 SfxFilterMatcher aMatch( pImpl->aName );
164 return aMatch.GetAnyFilter( nMust, nDont );
167 //----------------------------------------------------------------
169 SfxFilterContainer::SfxFilterContainer( const String& rName )
171 pImpl = new SfxFilterContainer_Impl( rName );
174 //----------------------------------------------------------------
176 SfxFilterContainer::~SfxFilterContainer()
178 delete pImpl;
181 //----------------------------------------------------------------
183 const String SfxFilterContainer::GetName() const
185 return pImpl->aName;
188 const SfxFilter* SfxFilterContainer::GetDefaultFilter_Impl( const String& rName )
190 // Try to find out the type of factory.
191 // Interpret given name as Service- and ShortName!
192 SvtModuleOptions aOpt;
193 SvtModuleOptions::EFactory eFactory = aOpt.ClassifyFactoryByServiceName(rName);
194 if (eFactory == SvtModuleOptions::E_UNKNOWN_FACTORY)
195 eFactory = aOpt.ClassifyFactoryByShortName(rName);
197 // could not classify factory by its service nor by its short name.
198 // Must be an unknown factory! => return NULL
199 if (eFactory == SvtModuleOptions::E_UNKNOWN_FACTORY)
200 return NULL;
202 // For the following code we need some additional information.
203 String sServiceName = aOpt.GetFactoryName(eFactory);
204 String sDefaultFilter = aOpt.GetFactoryDefaultFilter(eFactory);
206 // Try to get the default filter. Dont fiorget to verify it.
207 // May the set default filter does not exists any longer or
208 // does not fit the given factory.
209 const SfxFilterMatcher aMatcher;
210 const SfxFilter* pFilter = aMatcher.GetFilter4FilterName(sDefaultFilter);
212 if (
213 pFilter &&
214 !pFilter->GetServiceName().equalsIgnoreAsciiCase(sServiceName)
217 pFilter = 0;
220 // If at least no default filter could be located - use any filter of this
221 // factory.
222 if (!pFilter)
224 if ( bFirstRead )
225 ReadFilters_Impl();
227 for ( size_t i = 0, n = pFilterArr->size(); i < n; ++i )
229 const SfxFilter* pCheckFilter = (*pFilterArr)[i];
230 if ( pCheckFilter->GetServiceName().equalsIgnoreAsciiCase(sServiceName) )
232 pFilter = pCheckFilter;
233 break;
238 return pFilter;
242 //----------------------------------------------------------------
244 // Impl-Data is shared between all FilterMatchers of the same factory
245 class SfxFilterMatcher_Impl
247 public:
248 OUString aName;
249 mutable SfxFilterList_Impl* pList; // is created on demand
251 void InitForIterating() const;
252 void Update() const;
253 SfxFilterMatcher_Impl(const OUString &rName)
254 : aName(rName)
255 , pList(0)
258 ~SfxFilterMatcher_Impl()
260 // SfxFilterMatcher_Impl::InitForIterating() will set pList to
261 // either the global filter array matcher pFilterArr, or to
262 // a new SfxFilterList_Impl.
263 if (pList != pFilterArr)
264 delete pList;
268 namespace
270 typedef boost::ptr_vector<SfxFilterMatcher_Impl> SfxFilterMatcherArr_Impl;
271 static SfxFilterMatcherArr_Impl aImplArr;
272 static int nSfxFilterMatcherCount;
274 class hasName :
275 public std::unary_function<SfxFilterMatcher_Impl, bool>
277 private:
278 const OUString& mrName;
279 public:
280 hasName(const OUString &rName) : mrName(rName) {}
281 bool operator() (const SfxFilterMatcher_Impl& rImpl) const
283 return rImpl.aName == mrName;
287 SfxFilterMatcher_Impl & getSfxFilterMatcher_Impl(const OUString &rName)
289 OUString aName;
291 if (!rName.isEmpty())
292 aName = SfxObjectShell::GetServiceNameFromFactory(rName);
294 // find the impl-Data of any comparable FilterMatcher that was created
295 // previously
296 SfxFilterMatcherArr_Impl::iterator aEnd = aImplArr.end();
297 SfxFilterMatcherArr_Impl::iterator aIter =
298 std::find_if(aImplArr.begin(), aEnd, hasName(aName));
299 if (aIter != aEnd)
300 return *aIter;
302 // first Matcher created for this factory
303 SfxFilterMatcher_Impl *pImpl = new SfxFilterMatcher_Impl(aName);
304 aImplArr.push_back(pImpl);
305 return *pImpl;
309 SfxFilterMatcher::SfxFilterMatcher( const OUString& rName )
310 : m_rImpl( getSfxFilterMatcher_Impl(rName) )
312 ++nSfxFilterMatcherCount;
315 SfxFilterMatcher::SfxFilterMatcher()
316 : m_rImpl( getSfxFilterMatcher_Impl(OUString()) )
318 // global FilterMatcher always uses global filter array (also created on
319 // demand)
320 ++nSfxFilterMatcherCount;
323 SfxFilterMatcher::~SfxFilterMatcher()
325 --nSfxFilterMatcherCount;
326 if (nSfxFilterMatcherCount == 0)
327 aImplArr.clear();
330 void SfxFilterMatcher_Impl::Update() const
332 if ( pList )
334 // this List was already used
335 pList->clear();
336 for ( size_t i = 0, n = pFilterArr->size(); i < n; ++i )
338 SfxFilter* pFilter = (*pFilterArr)[i];
339 if ( pFilter->GetServiceName() == aName )
340 pList->push_back( pFilter );
345 void SfxFilterMatcher_Impl::InitForIterating() const
347 if ( pList )
348 return;
350 if ( bFirstRead )
351 // global filter array has not been created yet
352 SfxFilterContainer::ReadFilters_Impl();
354 if ( !aName.isEmpty() )
356 // matcher of factory: use only filters of that document type
357 pList = new SfxFilterList_Impl;
358 Update();
360 else
362 // global matcher: use global filter array
363 pList = pFilterArr;
367 const SfxFilter* SfxFilterMatcher::GetAnyFilter( SfxFilterFlags nMust, SfxFilterFlags nDont ) const
369 m_rImpl.InitForIterating();
370 for ( size_t i = 0, n = m_rImpl.pList->size(); i < n; ++i )
372 const SfxFilter* pFilter = (*m_rImpl.pList)[i];
373 SfxFilterFlags nFlags = pFilter->GetFilterFlags();
374 if ( (nFlags & nMust) == nMust && !(nFlags & nDont ) )
375 return pFilter;
378 return NULL;
381 //----------------------------------------------------------------
383 sal_uInt32 SfxFilterMatcher::GuessFilterIgnoringContent(
384 SfxMedium& rMedium,
385 const SfxFilter**ppFilter,
386 SfxFilterFlags nMust,
387 SfxFilterFlags nDont ) const
389 uno::Reference<document::XTypeDetection> xDetection(
390 comphelper::getProcessServiceFactory()->createInstance("com.sun.star.document.TypeDetection"), uno::UNO_QUERY);
392 OUString sTypeName;
395 sTypeName = xDetection->queryTypeByURL( rMedium.GetURLObject().GetMainURL( INetURLObject::NO_DECODE ) );
397 catch (uno::Exception&)
401 *ppFilter = NULL;
402 if ( !sTypeName.isEmpty() )
404 // make sure filter list is initialized
405 m_rImpl.InitForIterating();
406 *ppFilter = GetFilter4EA( sTypeName, nMust, nDont );
409 return *ppFilter ? ERRCODE_NONE : ERRCODE_ABORT;
412 //----------------------------------------------------------------
414 sal_uInt32 SfxFilterMatcher::GuessFilter( SfxMedium& rMedium, const SfxFilter**ppFilter, SfxFilterFlags nMust, SfxFilterFlags nDont ) const
416 return GuessFilterControlDefaultUI( rMedium, ppFilter, nMust, nDont, sal_True );
419 //----------------------------------------------------------------
421 sal_uInt32 SfxFilterMatcher::GuessFilterControlDefaultUI( SfxMedium& rMedium, const SfxFilter** ppFilter, SfxFilterFlags nMust, SfxFilterFlags nDont, sal_Bool /*bDefUI*/ ) const
423 const SfxFilter* pOldFilter = *ppFilter;
425 // no detection service -> nothing to do !
426 uno::Reference<document::XTypeDetection> xDetection(
427 comphelper::getProcessServiceFactory()->createInstance("com.sun.star.document.TypeDetection"), uno::UNO_QUERY);
429 if (!xDetection.is())
430 return ERRCODE_ABORT;
432 OUString sTypeName;
435 // open the stream one times only ...
436 // Otherwhise it will be tried more then once and show the same interaction more then once ...
438 OUString sURL( rMedium.GetURLObject().GetMainURL( INetURLObject::NO_DECODE ) );
439 uno::Reference< io::XInputStream > xInStream = rMedium.GetInputStream();
440 OUString aFilterName;
442 // stream exists => deep detection (with preselection ... if possible)
443 if (xInStream.is())
445 ::comphelper::MediaDescriptor aDescriptor;
447 aDescriptor[::comphelper::MediaDescriptor::PROP_URL() ] <<= sURL;
448 aDescriptor[::comphelper::MediaDescriptor::PROP_INPUTSTREAM() ] <<= xInStream;
449 aDescriptor[::comphelper::MediaDescriptor::PROP_INTERACTIONHANDLER()] <<= rMedium.GetInteractionHandler();
451 if ( !m_rImpl.aName.isEmpty() )
452 aDescriptor[::comphelper::MediaDescriptor::PROP_DOCUMENTSERVICE()] <<= m_rImpl.aName;
454 if ( pOldFilter )
456 aDescriptor[::comphelper::MediaDescriptor::PROP_TYPENAME() ] <<= OUString( pOldFilter->GetTypeName() );
457 aDescriptor[::comphelper::MediaDescriptor::PROP_FILTERNAME()] <<= OUString( pOldFilter->GetFilterName() );
460 uno::Sequence< beans::PropertyValue > lDescriptor = aDescriptor.getAsConstPropertyValueList();
461 sTypeName = xDetection->queryTypeByDescriptor(lDescriptor, sal_True); // lDescriptor is used as In/Out param ... dont use aDescriptor.getAsConstPropertyValueList() directly!
463 for (sal_Int32 i = 0; i < lDescriptor.getLength(); ++i)
465 if (lDescriptor[i].Name == "FilterName")
466 // Type detection picked a preferred filter for this format.
467 aFilterName = lDescriptor[i].Value.get<OUString>();
470 // no stream exists => try flat detection without preselection as fallback
471 else
472 sTypeName = xDetection->queryTypeByURL(sURL);
474 if (!sTypeName.isEmpty())
476 const SfxFilter* pFilter = NULL;
477 if (!aFilterName.isEmpty())
478 // Type detection returned a suitable filter for this. Use it.
479 pFilter = SfxFilter::GetFilterByName(aFilterName);
481 if (!pFilter)
483 // detect filter by given type
484 // In case of this matcher is bound to a particular document type:
485 // If there is no acceptable type for this document at all, the type detection has possibly returned something else.
486 // The DocumentService property is only a preselection, and all preselections are considered as optional!
487 // This "wrong" type will be sorted out now because we match only allowed filters to the detected type
488 uno::Sequence< beans::NamedValue > lQuery(1);
489 lQuery[0].Name = OUString("Name");
490 lQuery[0].Value <<= sTypeName;
492 pFilter = GetFilterForProps(lQuery, nMust, nDont);
495 if (pFilter)
497 *ppFilter = pFilter;
498 return ERRCODE_NONE;
502 catch (const uno::Exception&)
505 return ERRCODE_ABORT;
508 //----------------------------------------------------------------
509 sal_Bool SfxFilterMatcher::IsFilterInstalled_Impl( const SfxFilter* pFilter )
511 if ( pFilter->GetFilterFlags() & SFX_FILTER_MUSTINSTALL )
513 // Here could a re-installation be offered
514 String aText( SfxResId(STR_FILTER_NOT_INSTALLED).toString() );
515 aText.SearchAndReplaceAscii( "$(FILTER)", pFilter->GetUIName() );
516 QueryBox aQuery( NULL, WB_YES_NO | WB_DEF_YES, aText );
517 short nRet = aQuery.Execute();
518 if ( nRet == RET_YES )
520 #ifdef DBG_UTIL
521 // Start Setup
522 InfoBox( NULL, "Here should the Setup now be starting!" ).Execute();
523 #endif
524 // Installation must still give feedback if it worked or not,
525 // then the Filterflag be deleted
528 return ( !(pFilter->GetFilterFlags() & SFX_FILTER_MUSTINSTALL) );
530 else if ( pFilter->GetFilterFlags() & SFX_FILTER_CONSULTSERVICE )
532 String aText( SfxResId(STR_FILTER_CONSULT_SERVICE).toString() );
533 aText.SearchAndReplaceAscii( "$(FILTER)", pFilter->GetUIName() );
534 InfoBox ( NULL, aText ).Execute();
535 return sal_False;
537 else
538 return sal_True;
542 sal_uInt32 SfxFilterMatcher::DetectFilter( SfxMedium& rMedium, const SfxFilter**ppFilter, sal_Bool /*bPlugIn*/, sal_Bool bAPI ) const
543 /* [Description]
545 Here the Filter selection box is pulled up. Otherwise GuessFilter
549 const SfxFilter* pOldFilter = rMedium.GetFilter();
550 if ( pOldFilter )
552 if( !IsFilterInstalled_Impl( pOldFilter ) )
553 pOldFilter = 0;
554 else
556 SFX_ITEMSET_ARG( rMedium.GetItemSet(), pSalvageItem, SfxStringItem, SID_DOC_SALVAGE, sal_False);
557 if ( ( pOldFilter->GetFilterFlags() & SFX_FILTER_PACKED ) && pSalvageItem )
558 // Salvage is always done without packing
559 pOldFilter = 0;
563 const SfxFilter* pFilter = pOldFilter;
565 sal_Bool bPreview = rMedium.IsPreview_Impl();
566 SFX_ITEMSET_ARG(rMedium.GetItemSet(), pReferer, SfxStringItem, SID_REFERER, sal_False);
567 if ( bPreview && rMedium.IsRemote() && ( !pReferer || !pReferer->GetValue().match("private:searchfolder:") ) )
568 return ERRCODE_ABORT;
570 ErrCode nErr = GuessFilter( rMedium, &pFilter );
571 if ( nErr == ERRCODE_ABORT )
572 return nErr;
574 if ( nErr == ERRCODE_IO_PENDING )
576 *ppFilter = pFilter;
577 return nErr;
580 if ( !pFilter )
582 const SfxFilter* pInstallFilter = NULL;
584 // Now test the filter which are not installed (ErrCode is irrelevant)
585 GuessFilter( rMedium, &pInstallFilter, SFX_FILTER_IMPORT, SFX_FILTER_CONSULTSERVICE );
586 if ( pInstallFilter )
588 if ( IsFilterInstalled_Impl( pInstallFilter ) )
589 // Maybe the filter was installed was installed afterwards.
590 pFilter = pInstallFilter;
592 else
594 // Now test the filter, which first must be obtained by Star
595 // (ErrCode is irrelevant)
596 GuessFilter( rMedium, &pInstallFilter, SFX_FILTER_IMPORT, 0 );
597 if ( pInstallFilter )
598 IsFilterInstalled_Impl( pInstallFilter );
602 sal_Bool bHidden = bPreview;
603 SFX_ITEMSET_ARG( rMedium.GetItemSet(), pFlags, SfxStringItem, SID_OPTIONS, sal_False);
604 if ( !bHidden && pFlags )
606 String aFlags( pFlags->GetValue() );
607 aFlags.ToUpperAscii();
608 if( STRING_NOTFOUND != aFlags.Search( 'H' ) )
609 bHidden = sal_True;
611 *ppFilter = pFilter;
613 if ( bHidden || (bAPI && nErr == ERRCODE_SFX_CONSULTUSER) )
614 nErr = pFilter ? ERRCODE_NONE : ERRCODE_ABORT;
615 return nErr;
618 const SfxFilter* SfxFilterMatcher::GetFilterForProps( const com::sun::star::uno::Sequence < beans::NamedValue >& aSeq, SfxFilterFlags nMust, SfxFilterFlags nDont ) const
620 uno::Reference< lang::XMultiServiceFactory > xServiceManager = ::comphelper::getProcessServiceFactory();
621 uno::Reference< container::XContainerQuery > xTypeCFG;
622 if( xServiceManager.is() == sal_True )
623 xTypeCFG = uno::Reference < com::sun::star::container::XContainerQuery >( xServiceManager->createInstance( "com.sun.star.document.TypeDetection" ), uno::UNO_QUERY );
624 if ( xTypeCFG.is() )
626 // make query for all types matching the properties
627 uno::Reference < com::sun::star::container::XEnumeration > xEnum = xTypeCFG->createSubSetEnumerationByProperties( aSeq );
628 while ( xEnum->hasMoreElements() )
630 ::comphelper::SequenceAsHashMap aProps( xEnum->nextElement() );
631 OUString aValue;
633 // try to get the preferred filter (works without loading all filters!)
634 if ( (aProps[OUString("PreferredFilter")] >>= aValue) && !aValue.isEmpty() )
636 const SfxFilter* pFilter = SfxFilter::GetFilterByName( aValue );
637 if ( !pFilter || (pFilter->GetFilterFlags() & nMust) != nMust || (pFilter->GetFilterFlags() & nDont ) )
638 // check for filter flags
639 // pFilter == 0: if preferred filter is a Writer filter, but Writer module is not installed
640 continue;
642 if ( !m_rImpl.aName.isEmpty() )
644 // if this is not the global FilterMatcher: check if filter matches the document type
645 if ( pFilter->GetServiceName() != m_rImpl.aName )
647 // preferred filter belongs to another document type; now we must search the filter
648 m_rImpl.InitForIterating();
649 aProps[OUString("Name")] >>= aValue;
650 pFilter = GetFilter4EA( aValue, nMust, nDont );
651 if ( pFilter )
652 return pFilter;
654 else
655 return pFilter;
657 else
658 return pFilter;
663 return 0;
666 const SfxFilter* SfxFilterMatcher::GetFilter4Mime( const OUString& rMediaType, SfxFilterFlags nMust, SfxFilterFlags nDont ) const
668 if ( m_rImpl.pList )
670 for ( size_t i = 0, n = m_rImpl.pList->size(); i < n; ++i )
672 const SfxFilter* pFilter = (*m_rImpl.pList)[i];
673 SfxFilterFlags nFlags = pFilter->GetFilterFlags();
674 if ( (nFlags & nMust) == nMust && !(nFlags & nDont ) && pFilter->GetMimeType() == rMediaType )
675 return pFilter;
678 return 0;
681 com::sun::star::uno::Sequence < com::sun::star::beans::NamedValue > aSeq(1);
682 aSeq[0].Name = OUString("MediaType");
683 aSeq[0].Value <<= rMediaType;
684 return GetFilterForProps( aSeq, nMust, nDont );
687 const SfxFilter* SfxFilterMatcher::GetFilter4EA( const String& rType,SfxFilterFlags nMust, SfxFilterFlags nDont ) const
689 if ( m_rImpl.pList )
691 const SfxFilter* pFirst = 0;
692 for ( size_t i = 0, n = m_rImpl.pList->size(); i < n; ++i )
694 const SfxFilter* pFilter = (*m_rImpl.pList)[i];
695 SfxFilterFlags nFlags = pFilter->GetFilterFlags();
696 if ( (nFlags & nMust) == nMust && !(nFlags & nDont ) && pFilter->GetTypeName() == rType )
698 if (nFlags & SFX_FILTER_PREFERED)
699 return pFilter;
700 if (!pFirst)
701 pFirst = pFilter;
704 if (pFirst)
705 return pFirst;
707 return 0;
710 com::sun::star::uno::Sequence < com::sun::star::beans::NamedValue > aSeq(1);
711 aSeq[0].Name = OUString("Name");
712 aSeq[0].Value <<= OUString( rType );
713 return GetFilterForProps( aSeq, nMust, nDont );
716 const SfxFilter* SfxFilterMatcher::GetFilter4Extension( const String& rExt, SfxFilterFlags nMust, SfxFilterFlags nDont ) const
718 if ( m_rImpl.pList )
720 for ( size_t i = 0, n = m_rImpl.pList->size(); i < n; ++i )
722 const SfxFilter* pFilter = (*m_rImpl.pList)[i];
723 SfxFilterFlags nFlags = pFilter->GetFilterFlags();
724 if ( (nFlags & nMust) == nMust && !(nFlags & nDont ) )
726 String sWildCard = ToUpper_Impl( pFilter->GetWildcard().getGlob() );
727 String sExt = ToUpper_Impl( rExt );
729 if (!sExt.Len())
730 continue;
732 if (sExt.GetChar(0) != (sal_Unicode)'.')
733 sExt.Insert((sal_Unicode)'.', 0);
735 WildCard aCheck(sWildCard, ';');
736 if (aCheck.Matches(sExt))
737 return pFilter;
741 return 0;
744 // Use extension without dot!
745 String sExt( rExt );
746 if ( sExt.Len() && ( sExt.GetChar(0) == (sal_Unicode)'.' ))
747 sExt.Erase(0,1);
749 com::sun::star::uno::Sequence < com::sun::star::beans::NamedValue > aSeq(1);
750 aSeq[0].Name = OUString("Extensions");
751 uno::Sequence < OUString > aExts(1);
752 aExts[0] = sExt;
753 aSeq[0].Value <<= aExts;
754 return GetFilterForProps( aSeq, nMust, nDont );
757 const SfxFilter* SfxFilterMatcher::GetFilter4ClipBoardId( sal_uInt32 nId, SfxFilterFlags nMust, SfxFilterFlags nDont ) const
759 if (nId == 0)
760 return 0;
762 com::sun::star::uno::Sequence < com::sun::star::beans::NamedValue > aSeq(1);
763 OUString aName = SotExchange::GetFormatName( nId );
764 aSeq[0].Name = OUString("ClipboardFormat");
765 aSeq[0].Value <<= aName;
766 return GetFilterForProps( aSeq, nMust, nDont );
769 const SfxFilter* SfxFilterMatcher::GetFilter4UIName( const String& rName, SfxFilterFlags nMust, SfxFilterFlags nDont ) const
771 m_rImpl.InitForIterating();
772 const SfxFilter* pFirstFilter=0;
773 for ( size_t i = 0, n = m_rImpl.pList->size(); i < n; ++i )
775 const SfxFilter* pFilter = (*m_rImpl.pList)[i];
776 SfxFilterFlags nFlags = pFilter->GetFilterFlags();
777 if ( (nFlags & nMust) == nMust &&
778 !(nFlags & nDont ) && pFilter->GetUIName() == rName )
780 if ( pFilter->GetFilterFlags() & SFX_FILTER_PREFERED )
781 return pFilter;
782 else if ( !pFirstFilter )
783 pFirstFilter = pFilter;
786 return pFirstFilter;
789 const SfxFilter* SfxFilterMatcher::GetFilter4FilterName( const String& rName, SfxFilterFlags nMust, SfxFilterFlags nDont ) const
791 String aName( rName );
792 sal_uInt16 nIndex = aName.SearchAscii(": ");
793 if ( nIndex != STRING_NOTFOUND )
795 OSL_FAIL("Old filter name used!");
796 aName = rName.Copy( nIndex + 2 );
799 if ( bFirstRead )
801 uno::Reference< lang::XMultiServiceFactory > xServiceManager = ::comphelper::getProcessServiceFactory();
802 uno::Reference< container::XNameAccess > xFilterCFG ;
803 uno::Reference< container::XNameAccess > xTypeCFG ;
804 if( xServiceManager.is() == sal_True )
806 xFilterCFG = uno::Reference< container::XNameAccess >( xServiceManager->createInstance( "com.sun.star.document.FilterFactory" ), uno::UNO_QUERY );
807 xTypeCFG = uno::Reference< container::XNameAccess >( xServiceManager->createInstance( "com.sun.star.document.TypeDetection" ), uno::UNO_QUERY );
810 if( xFilterCFG.is() && xTypeCFG.is() )
812 if ( !pFilterArr )
813 CreateFilterArr();
814 else
816 for ( size_t i = 0, n = pFilterArr->size(); i < n; ++i )
818 const SfxFilter* pFilter = (*pFilterArr)[i];
819 SfxFilterFlags nFlags = pFilter->GetFilterFlags();
820 if ((nFlags & nMust) == nMust && !(nFlags & nDont) && pFilter->GetFilterName().equalsIgnoreAsciiCase(aName))
821 return pFilter;
825 SfxFilterContainer::ReadSingleFilter_Impl( rName, xTypeCFG, xFilterCFG, sal_False );
829 SfxFilterList_Impl* pList = m_rImpl.pList;
830 if ( !pList )
831 pList = pFilterArr;
833 for ( size_t i = 0, n = pList->size(); i < n; ++i )
835 const SfxFilter* pFilter = (*pList)[i];
836 SfxFilterFlags nFlags = pFilter->GetFilterFlags();
837 if ( (nFlags & nMust) == nMust && !(nFlags & nDont ) && pFilter->GetFilterName().equalsIgnoreAsciiCase(aName))
838 return pFilter;
841 return NULL;
844 IMPL_STATIC_LINK( SfxFilterMatcher, MaybeFileHdl_Impl, String*, pString )
846 const SfxFilter* pFilter = pThis->GetFilter4Extension( *pString, SFX_FILTER_IMPORT );
847 if (pFilter && !pFilter->GetWildcard().Matches( String() ) &&
848 !pFilter->GetWildcard().Matches(OUString("*.*")) &&
849 !pFilter->GetWildcard().Matches(OUString('*'))
852 return sal_True;
854 return sal_False;
857 //----------------------------------------------------------------
859 SfxFilterMatcherIter::SfxFilterMatcherIter(
860 const SfxFilterMatcher& rMatcher,
861 SfxFilterFlags nOrMaskP, SfxFilterFlags nAndMaskP )
862 : nOrMask( nOrMaskP ), nAndMask( nAndMaskP ),
863 nCurrent(0), m_rMatch(rMatcher.m_rImpl)
865 if( nOrMask == 0xffff ) //Due to falty build on s
866 nOrMask = 0;
867 m_rMatch.InitForIterating();
870 //----------------------------------------------------------------
872 const SfxFilter* SfxFilterMatcherIter::Find_Impl()
874 const SfxFilter* pFilter = 0;
875 while( nCurrent < m_rMatch.pList->size() )
877 pFilter = (*m_rMatch.pList)[nCurrent++];
878 SfxFilterFlags nFlags = pFilter->GetFilterFlags();
879 if( ((nFlags & nOrMask) == nOrMask ) && !(nFlags & nAndMask ) )
880 break;
881 pFilter = 0;
884 return pFilter;
887 const SfxFilter* SfxFilterMatcherIter::First()
889 nCurrent = 0;
890 return Find_Impl();
893 //----------------------------------------------------------------
895 const SfxFilter* SfxFilterMatcherIter::Next()
897 return Find_Impl();
900 /*---------------------------------------------------------------
901 helper to build own formated string from given stringlist by
902 using given separator
903 ---------------------------------------------------------------*/
904 OUString implc_convertStringlistToString( const uno::Sequence< OUString >& lList ,
905 const sal_Unicode& cSeparator,
906 const OUString& sPrefix )
908 OUStringBuffer sString ( 1000 ) ;
909 sal_Int32 nCount = lList.getLength();
910 sal_Int32 nItem = 0 ;
911 for( nItem=0; nItem<nCount; ++nItem )
913 if( !sPrefix.isEmpty() )
915 sString.append( sPrefix );
917 sString.append( lList[nItem] );
918 if( nItem+1<nCount )
920 sString.append( cSeparator );
923 return sString.makeStringAndClear();
927 void SfxFilterContainer::ReadSingleFilter_Impl(
928 const OUString& rName,
929 const uno::Reference< container::XNameAccess >& xTypeCFG,
930 const uno::Reference< container::XNameAccess >& xFilterCFG,
931 sal_Bool bUpdate
934 OUString sFilterName( rName );
935 SfxFilterList_Impl& rList = *pFilterArr;
936 uno::Sequence< beans::PropertyValue > lFilterProperties;
937 uno::Any aResult;
940 aResult = xFilterCFG->getByName( sFilterName );
942 catch( container::NoSuchElementException& )
944 aResult = uno::Any();
947 if( aResult >>= lFilterProperties )
949 // collect information to add filter to container
950 // (attention: some information aren't available on filter directly ... you must search for corresponding type too!)
951 sal_Int32 nFlags = 0 ;
952 sal_Int32 nClipboardId = 0 ;
953 sal_Int32 nDocumentIconId = 0 ;
954 sal_Int32 nFormatVersion = 0 ;
955 OUString sMimeType ;
956 OUString sType ;
957 OUString sUIName ;
958 OUString sHumanName ;
959 OUString sDefaultTemplate ;
960 OUString sUserData ;
961 OUString sExtension ;
962 OUString sPattern ;
963 OUString sServiceName ;
965 // first get directly available properties
966 sal_Int32 nFilterPropertyCount = lFilterProperties.getLength();
967 sal_Int32 nFilterProperty = 0 ;
968 for( nFilterProperty=0; nFilterProperty<nFilterPropertyCount; ++nFilterProperty )
970 if ( lFilterProperties[nFilterProperty].Name == "FileFormatVersion" )
972 lFilterProperties[nFilterProperty].Value >>= nFormatVersion;
974 else if ( lFilterProperties[nFilterProperty].Name == "TemplateName" )
976 lFilterProperties[nFilterProperty].Value >>= sDefaultTemplate;
978 else if ( lFilterProperties[nFilterProperty].Name == "Flags" )
980 lFilterProperties[nFilterProperty].Value >>= nFlags;
982 else if ( lFilterProperties[nFilterProperty].Name == "UIName" )
984 lFilterProperties[nFilterProperty].Value >>= sUIName;
986 else if ( lFilterProperties[nFilterProperty].Name == "UserData" )
988 uno::Sequence< OUString > lUserData;
989 lFilterProperties[nFilterProperty].Value >>= lUserData;
990 sUserData = implc_convertStringlistToString( lUserData, ',', OUString() );
992 else if ( lFilterProperties[nFilterProperty].Name == "DocumentService" )
994 lFilterProperties[nFilterProperty].Value >>= sServiceName;
996 else if (lFilterProperties[nFilterProperty].Name == "ExportExtension")
998 // Extension preferred by the filter. This takes precedence
999 // over those that are given in the file format type.
1000 lFilterProperties[nFilterProperty].Value >>= sExtension;
1001 sExtension = OUString("*.") + sExtension;
1003 else if ( lFilterProperties[nFilterProperty].Name == "Type" )
1005 lFilterProperties[nFilterProperty].Value >>= sType;
1006 // Try to get filter .. but look for any exceptions!
1007 // May be filter was deleted by another thread ...
1010 aResult = xTypeCFG->getByName( sType );
1012 catch (const container::NoSuchElementException&)
1014 aResult = uno::Any();
1017 uno::Sequence< beans::PropertyValue > lTypeProperties;
1018 if( aResult >>= lTypeProperties )
1020 // get indirect available properties then (types)
1021 sal_Int32 nTypePropertyCount = lTypeProperties.getLength();
1022 sal_Int32 nTypeProperty = 0 ;
1023 for( nTypeProperty=0; nTypeProperty<nTypePropertyCount; ++nTypeProperty )
1025 if ( lTypeProperties[nTypeProperty].Name == "ClipboardFormat" )
1027 lTypeProperties[nTypeProperty].Value >>= sHumanName;
1029 else if ( lTypeProperties[nTypeProperty].Name == "DocumentIconID" )
1031 lTypeProperties[nTypeProperty].Value >>= nDocumentIconId;
1033 else if ( lTypeProperties[nTypeProperty].Name == "MediaType" )
1035 lTypeProperties[nTypeProperty].Value >>= sMimeType;
1037 else if ( lTypeProperties[nTypeProperty].Name == "Extensions" )
1039 if (sExtension.isEmpty())
1041 uno::Sequence< OUString > lExtensions;
1042 lTypeProperties[nTypeProperty].Value >>= lExtensions;
1043 sExtension = implc_convertStringlistToString( lExtensions, ';', "*." );
1046 else if ( lTypeProperties[nTypeProperty].Name == "URLPattern" )
1048 uno::Sequence< OUString > lPattern;
1049 lTypeProperties[nTypeProperty].Value >>= lPattern;
1050 sPattern = implc_convertStringlistToString( lPattern, ';', OUString() );
1057 if ( sServiceName.isEmpty() )
1058 return;
1060 // old formats are found ... using HumanPresentableName!
1061 if( !sHumanName.isEmpty() )
1063 nClipboardId = SotExchange::RegisterFormatName( sHumanName );
1065 // For external filters ignore clipboard IDs
1066 if((nFlags & SFX_FILTER_STARONEFILTER) == SFX_FILTER_STARONEFILTER)
1068 nClipboardId = 0;
1071 // register SfxFilter
1072 // first erase module name from old filter names!
1073 // e.g: "scalc: DIF" => "DIF"
1074 sal_Int32 nStartRealName = sFilterName.indexOf( ": ", 0 );
1075 if( nStartRealName != -1 )
1077 OSL_FAIL("Old format, not supported!");
1078 sFilterName = sFilterName.copy( nStartRealName+2 );
1081 SfxFilter* pFilter = bUpdate ? (SfxFilter*) SfxFilter::GetFilterByName( sFilterName ) : 0;
1082 sal_Bool bNew = sal_False;
1083 if (!pFilter)
1085 bNew = sal_True;
1086 pFilter = new SfxFilter( sFilterName ,
1087 sExtension ,
1088 nFlags ,
1089 nClipboardId ,
1090 sType ,
1091 (sal_uInt16)nDocumentIconId ,
1092 sMimeType ,
1093 sUserData ,
1094 sServiceName );
1096 else
1098 pFilter->maFilterName = sFilterName;
1099 pFilter->aWildCard = WildCard(sExtension, ';');
1100 pFilter->nFormatType = nFlags;
1101 pFilter->lFormat = nClipboardId;
1102 pFilter->aTypeName = sType;
1103 pFilter->nDocIcon = (sal_uInt16)nDocumentIconId;
1104 pFilter->aMimeType = sMimeType;
1105 pFilter->aUserData = sUserData;
1106 pFilter->aServiceName = sServiceName;
1109 // Don't forget to set right UIName!
1110 // Otherwise internal name is used as fallback ...
1111 pFilter->SetUIName( sUIName );
1112 pFilter->SetDefaultTemplate( sDefaultTemplate );
1113 if( nFormatVersion )
1115 pFilter->SetVersion( nFormatVersion );
1117 pFilter->SetURLPattern(sPattern);
1119 if (bNew)
1120 rList.push_back( pFilter );
1124 void SfxFilterContainer::ReadFilters_Impl( sal_Bool bUpdate )
1126 RTL_LOGFILE_CONTEXT( aMeasure, "sfx2 (as96863) ::SfxFilterContainer::ReadFilters" );
1127 if ( !pFilterArr )
1128 CreateFilterArr();
1130 bFirstRead = sal_False;
1131 SfxFilterList_Impl& rList = *pFilterArr;
1135 // get the FilterFactory service to access the registered filters ... and types!
1136 uno::Reference< lang::XMultiServiceFactory > xServiceManager = ::comphelper::getProcessServiceFactory();
1137 uno::Reference< container::XNameAccess > xFilterCFG ;
1138 uno::Reference< container::XNameAccess > xTypeCFG ;
1139 if( xServiceManager.is() == sal_True )
1141 xFilterCFG = uno::Reference< container::XNameAccess >( xServiceManager->createInstance( "com.sun.star.document.FilterFactory" ), uno::UNO_QUERY );
1142 xTypeCFG = uno::Reference< container::XNameAccess >( xServiceManager->createInstance( "com.sun.star.document.TypeDetection" ), uno::UNO_QUERY );
1146 ( xFilterCFG.is() == sal_True ) &&
1147 ( xTypeCFG.is() == sal_True )
1150 // select right query to get right set of filters for search modul
1151 uno::Sequence< OUString > lFilterNames = xFilterCFG->getElementNames();
1152 if ( lFilterNames.getLength() )
1154 // If list of filters already exist ...
1155 // ReadExternalFilters must work in update mode.
1156 // Best way seams to mark all filters NOT_INSTALLED
1157 // and change it back for all valid filters afterwards.
1158 if( !rList.empty() )
1160 bUpdate = sal_True;
1161 SfxFilter* pFilter;
1162 for ( size_t i = 0, n = rList.size(); i < n; ++i )
1164 pFilter = rList[ i ];
1165 pFilter->nFormatType |= SFX_FILTER_NOTINSTALLED;
1169 // get all properties of filters ... put it into the filter container
1170 sal_Int32 nFilterCount = lFilterNames.getLength();
1171 sal_Int32 nFilter=0;
1172 for( nFilter=0; nFilter<nFilterCount; ++nFilter )
1174 // Try to get filter .. but look for any exceptions!
1175 // May be filter was deleted by another thread ...
1176 OUString sFilterName = lFilterNames[nFilter];
1177 ReadSingleFilter_Impl( sFilterName, xTypeCFG, xFilterCFG, bUpdate );
1182 catch(const uno::Exception&)
1184 DBG_ASSERT( sal_False, "SfxFilterContainer::ReadFilter()\nException detected. Possible not all filters could be cached.\n" );
1187 if ( bUpdate )
1189 // global filter arry was modified, factory specific ones might need an
1190 // update too
1191 std::for_each(aImplArr.begin(), aImplArr.end(),
1192 std::mem_fun_ref(&SfxFilterMatcher_Impl::Update));
1196 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */