Branch libreoffice-5-0-4
[LibreOffice.git] / sfx2 / source / bastyp / fltfnc.cxx
blob48bf28dfdbc89ae842293a770e1989c18d21142f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <com/sun/star/uno/Exception.hpp>
22 #include <com/sun/star/beans/PropertyValue.hpp>
23 #include <com/sun/star/beans/NamedValue.hpp>
24 #include <com/sun/star/container/XNameAccess.hpp>
25 #include <com/sun/star/container/XEnumeration.hpp>
26 #include <com/sun/star/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"
92 #include "bastyp.hrc"
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>
98 #include "helper.hxx"
99 #include "fltlst.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;
108 #endif
110 using namespace com::sun::star;
112 namespace
114 class theSfxFilterListener : public rtl::Static<SfxFilterListener, theSfxFilterListener> {};
115 class SfxFilterArray
117 SfxFilterList_Impl aList;
118 public:
119 ~SfxFilterArray()
121 SfxFilterList_Impl::iterator aEnd = aList.end();
122 for (SfxFilterList_Impl::iterator aI = aList.begin(); aI != aEnd; ++aI)
124 SfxFilter *pFilter = *aI;
125 delete pFilter;
128 SfxFilterList_Impl& getList()
130 return aList;
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
152 public:
153 OUString aName;
154 OUString aServiceName;
156 SfxFilterContainer_Impl( const OUString& rName )
157 : aName( 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()
191 delete pImpl;
196 const OUString SfxFilterContainer::GetName() const
198 return pImpl->aName;
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)
213 return NULL;
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);
225 if (
226 pFilter &&
227 !pFilter->GetServiceName().equalsIgnoreAsciiCase(sServiceName)
230 pFilter = 0;
233 // If at least no default filter could be located - use any filter of this
234 // factory.
235 if (!pFilter)
237 if ( bFirstRead )
238 ReadFilters_Impl();
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;
246 break;
251 return pFilter;
257 // Impl-Data is shared between all FilterMatchers of the same factory
258 class SfxFilterMatcher_Impl
260 public:
261 OUString aName;
262 mutable SfxFilterList_Impl* pList; // is created on demand
264 void InitForIterating() const;
265 void Update() const;
266 SfxFilterMatcher_Impl(const OUString &rName)
267 : aName(rName)
268 , pList(0)
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)
277 delete pList;
281 namespace
283 typedef boost::ptr_vector<SfxFilterMatcher_Impl> SfxFilterMatcherArr_Impl;
284 static SfxFilterMatcherArr_Impl aImplArr;
285 static int nSfxFilterMatcherCount;
287 class hasName :
288 public std::unary_function<SfxFilterMatcher_Impl, bool>
290 private:
291 const OUString& mrName;
292 public:
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)
302 OUString aName;
304 if (!rName.isEmpty())
305 aName = SfxObjectShell::GetServiceNameFromFactory(rName);
307 // find the impl-Data of any comparable FilterMatcher that was created
308 // previously
309 SfxFilterMatcherArr_Impl::iterator aEnd = aImplArr.end();
310 SfxFilterMatcherArr_Impl::iterator aIter =
311 std::find_if(aImplArr.begin(), aEnd, hasName(aName));
312 if (aIter != aEnd)
313 return *aIter;
315 // first Matcher created for this factory
316 SfxFilterMatcher_Impl *pImpl = new SfxFilterMatcher_Impl(aName);
317 aImplArr.push_back(pImpl);
318 return *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
332 // demand)
333 ++nSfxFilterMatcherCount;
336 SfxFilterMatcher::~SfxFilterMatcher()
338 --nSfxFilterMatcherCount;
339 if (nSfxFilterMatcherCount == 0)
340 aImplArr.clear();
343 void SfxFilterMatcher_Impl::Update() const
345 if ( pList )
347 // this List was already used
348 pList->clear();
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
360 if ( pList )
361 return;
363 if ( bFirstRead )
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;
371 Update();
373 else
375 // global matcher: use global filter array
376 pList = pFilterArr;
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 ) )
388 return pFilter;
391 return NULL;
396 sal_uInt32 SfxFilterMatcher::GuessFilterIgnoringContent(
397 SfxMedium& rMedium,
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);
405 OUString sTypeName;
408 sTypeName = xDetection->queryTypeByURL( rMedium.GetURLObject().GetMainURL( INetURLObject::NO_DECODE ) );
410 catch (uno::Exception&)
414 *ppFilter = NULL;
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;
445 OUString sTypeName;
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)
456 if (xInStream.is())
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));
465 if (it != 0) {
466 aDescriptor[utl::MediaDescriptor::PROP_REFERRER()]
467 <<= it->GetValue();
470 if ( !m_rImpl.aName.isEmpty() )
471 aDescriptor[utl::MediaDescriptor::PROP_DOCUMENTSERVICE()] <<= m_rImpl.aName;
473 if ( pOldFilter )
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
490 else
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);
516 if (pFilter)
518 *ppFilter = pFilter;
519 return ERRCODE_NONE;
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 )
541 #ifdef DBG_UTIL
542 // Start Setup
543 ScopedVclPtr<InfoBox>::Create( nullptr, "Here should the Setup now be starting!" )->Execute();
544 #endif
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();
556 return false;
558 else
559 return true;
563 sal_uInt32 SfxFilterMatcher::DetectFilter( SfxMedium& rMedium, const SfxFilter**ppFilter, bool /*bPlugIn*/, bool bAPI ) const
564 /* [Description]
566 Here the Filter selection box is pulled up. Otherwise GuessFilter
570 const SfxFilter* pOldFilter = rMedium.GetFilter();
571 if ( pOldFilter )
573 if( !IsFilterInstalled_Impl( pOldFilter ) )
574 pOldFilter = 0;
575 else
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
580 pOldFilter = 0;
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 )
593 return nErr;
595 if ( nErr == ERRCODE_IO_PENDING )
597 *ppFilter = pFilter;
598 return nErr;
601 if ( !pFilter )
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;
613 else
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' ) )
630 bHidden = true;
632 *ppFilter = pFilter;
634 if ( bHidden || (bAPI && nErr == ERRCODE_SFX_CONSULTUSER) )
635 nErr = pFilter ? ERRCODE_NONE : ERRCODE_ABORT;
636 return nErr;
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 );
645 if ( xTypeCFG.is() )
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() );
652 OUString aValue;
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
661 continue;
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 );
672 if ( pFilter )
673 return pFilter;
675 else
676 return pFilter;
678 else
679 return pFilter;
684 return 0;
687 const SfxFilter* SfxFilterMatcher::GetFilter4Mime( const OUString& rMediaType, SfxFilterFlags nMust, SfxFilterFlags nDont ) const
689 if ( m_rImpl.pList )
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 )
696 return pFilter;
699 return 0;
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
710 if ( m_rImpl.pList )
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)
720 return pFilter;
721 if (!pFirst)
722 pFirst = pFilter;
725 if (pFirst)
726 return pFirst;
728 return 0;
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
739 if ( m_rImpl.pList )
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 );
750 if (sExt.isEmpty())
751 continue;
753 if (sExt[0] != (sal_Unicode)'.')
754 sExt = "." + sExt;
756 WildCard aCheck(sWildCard, ';');
757 if (aCheck.Matches(sExt))
758 return pFilter;
762 return 0;
765 // Use extension without dot!
766 OUString sExt( rExt );
767 if ( sExt.startsWith(".") )
768 sExt = sExt.copy(1);
770 com::sun::star::uno::Sequence < com::sun::star::beans::NamedValue > aSeq(1);
771 aSeq[0].Name = "Extensions";
772 uno::Sequence < OUString > aExts(1);
773 aExts[0] = sExt;
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)
781 return 0;
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 )
802 return pFilter;
803 else if ( !pFirstFilter )
804 pFirstFilter = pFilter;
807 return pFirstFilter;
810 const SfxFilter* SfxFilterMatcher::GetFilter4FilterName( const OUString& rName, SfxFilterFlags nMust, SfxFilterFlags nDont ) const
812 OUString aName( rName );
813 sal_Int32 nIndex = aName.indexOf(": ");
814 if ( nIndex != -1 )
816 SAL_WARN( "sfx.bastyp", "Old filter name used!");
817 aName = rName.copy( nIndex + 2 );
820 if ( bFirstRead )
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() )
833 if ( !pFilterArr )
834 CreateFilterArr();
835 else
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))
842 return pFilter;
846 SfxFilterContainer::ReadSingleFilter_Impl( rName, xTypeCFG, xFilterCFG, false );
850 SfxFilterList_Impl* pList = m_rImpl.pList;
851 if ( !pList )
852 pList = pFilterArr;
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))
859 return pFilter;
862 return NULL;
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('*'))
873 return true;
875 return false;
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 ) )
901 break;
902 pFilter = 0;
905 return pFilter;
908 const SfxFilter* SfxFilterMatcherIter::First()
910 nCurrent = 0;
911 return Find_Impl();
916 const SfxFilter* SfxFilterMatcherIter::Next()
918 return Find_Impl();
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] );
939 if( nItem+1<nCount )
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,
952 bool bUpdate
955 OUString sFilterName( rName );
956 SfxFilterList_Impl& rList = *pFilterArr;
957 uno::Sequence< beans::PropertyValue > lFilterProperties;
958 uno::Any aResult;
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 ;
976 OUString sMimeType ;
977 OUString sType ;
978 OUString sUIName ;
979 OUString sHumanName ;
980 OUString sDefaultTemplate ;
981 OUString sUserData ;
982 OUString sExtension ;
983 OUString sPattern ;
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" )
1001 sal_Int32 nTmp(0);
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() )
1081 return;
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;
1105 bool bNew = false;
1106 if (!pFilter)
1108 bNew = true;
1109 pFilter = new SfxFilter( sFilterName ,
1110 sExtension ,
1111 nFlags ,
1112 nClipboardId ,
1113 sType ,
1114 (sal_uInt16)nDocumentIconId ,
1115 sMimeType ,
1116 sUserData ,
1117 sServiceName );
1119 else
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);
1142 if (bNew)
1143 rList.push_back( pFilter );
1147 void SfxFilterContainer::ReadFilters_Impl( bool bUpdate )
1149 if ( !pFilterArr )
1150 CreateFilterArr();
1152 bFirstRead = false;
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() )
1179 bUpdate = true;
1180 SfxFilter* pFilter;
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" );
1206 if ( bUpdate )
1208 // global filter arry was modified, factory specific ones might need an
1209 // update too
1210 std::for_each(aImplArr.begin(), aImplArr.end(),
1211 std::mem_fun_ref(&SfxFilterMatcher_Impl::Update));
1215 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */