update dev300-m57
[ooovba.git] / sfx2 / source / dialog / filtergrouping.cxx
blob47a75137d8254b03308da3268677bcbf6b13f875
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: filtergrouping.cxx,v $
10 * $Revision: 1.30 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sfx2.hxx"
33 #include "filtergrouping.hxx"
34 #include <sfx2/fcontnr.hxx>
35 #include <sfx2/filedlghelper.hxx>
36 #include <sfx2/sfx.hrc>
37 #include <sfx2/docfac.hxx>
38 #include "sfxresid.hxx"
39 #include <osl/thread.h>
40 #include <com/sun/star/ui/dialogs/XFilterGroupManager.hpp>
41 #include <com/sun/star/beans/StringPair.hpp>
42 #include <com/sun/star/uno/Sequence.hxx>
43 #include <unotools/confignode.hxx>
44 #include <comphelper/processfactory.hxx>
45 #include <comphelper/sequenceashashmap.hxx>
46 #include <tools/wldcrd.hxx>
47 #include <tools/diagnose_ex.h>
49 #include <list>
50 #include <vector>
51 #include <map>
52 #include <algorithm>
54 //........................................................................
55 namespace sfx2
57 //........................................................................
59 //#define DISABLE_GROUPING_AND_CLASSIFYING
60 // not using the functionallity herein, yet
62 using namespace ::com::sun::star::uno;
63 using namespace ::com::sun::star::ui::dialogs;
64 using namespace ::com::sun::star::lang;
65 using namespace ::com::sun::star::beans;
66 using namespace ::utl;
68 //====================================================================
69 /**
71 Some general words about what's going on here ....
73 <p>In our file open dialog, usually we display every filter we know. That's how it was before: every filter
74 lead to an own line in the filter list box, e.g. "StarWriter 5.0 Dokument" or "Microsoft Word 97".</p>
76 <p>But then the PM came. And everything changed ....</p>
78 <p>A basic idea are groups: Why simply listing all the single filters? Couldn't we draw nice separators
79 between the filters which logically belong together? I.e. all the filters which open a document in StarWriter:
80 couldn't we separate them from all the filters which open the document in StarCalc?<br/>
81 So spoke the PM, and engineering obeyed.</p>
83 <p>So we have groups. They're just a visual aspect: All the filters of a group are presented together, separated
84 by a line from other groups.</p>
86 <p>Let's be honest: How the concrete implementation of the file picker service separates the different groups
87 is a matter of this implementation. We only do this grouping and suggest it to the FilePicker service ...</p>
89 <p>Now for the second concept:<br/>
90 Thinking about it (and that's what the PM did), both "StarWriter 5.0 Dokument" and "Microsoft Word 97"
91 describe a text document. It's a text. It's of no interest for the user that one of the texts was saved in
92 MS' format, and one in our own format.<br/>
93 So in a first step, we want to have a filter entry "Text documents". This would cover both above-mentioned
94 filters, as well as any other filters for documents which are texts.</p>
96 <p>Such an entry as "Text documents" is - within the scope of this file - called "class" or "filter class".</p>
98 <p>In the file-open-dialog, such a class looks like an ordinary filter: it's simply a name in the filter
99 listbox. Selecting means that all the files matching one of the "sub-filters" are displayed (in the example above,
100 this would be "*.sdw", "*.doc" and so on).</p>
102 <p>Now there are two types of filter classes: global ones and local ones. "Text documents" is a global class. As
103 well as "Spreadsheets". Or "Web pages".<br/>
104 Let's have a look at a local class: The filters "MS Word 95" and "MS WinWord 6.0" together form the class
105 "Microsoft Word 6.0 / 95" (don't ask for the reasons. At least not me. Ask the PM). There are a lot of such
106 local classes ...</p>
108 <p>The difference between global and local classes is as follows: Global classes are presented in an own group.
109 There is one dedicated group at the top of the list, containing all the global groups - no local groups and no
110 single filters.</p>
112 <p>Ehm - it was a lie. Not really at the top. Before this group, there is this single "All files" entry. It forms
113 it's own group. But this is uninteresting here.</p>
115 <p>Local classes must consist of filters which - without the classification - would all belong to the same group.
116 Then, they're combined to one entry (in the example above: "Microsoft Word 6.0 / 95"), and this entry is inserted
117 into the file picker filter list, instead of the single filters which form the class.</p>
119 <p>This is an interesting difference between local and global classes: Filters which are part of a global class
120 are listed in there own group, too. Filters in local classes aren't listed a second time - neither directly (as
121 the filter itself) nor indirectly (as part of another local group).</p>
123 <p>The only exception are filters which are part of a global class <em>and</em> a local class. This is allowed.
124 Beeing cotained in two local classes isn't.</p>
126 <p>So that's all what you need to know: Understand the concept of "filter classes" (a filter class combines
127 different filters and acts as if it's a filter itself) and the concept of groups (a group just describes a
128 logical correlation of filters and usually is represented to the user by drawing group separators in the filter
129 list).</p>
131 <p>If you got it, go try understanding this file :).</p>
136 //====================================================================
138 typedef StringPair FilterDescriptor; // a single filter or a filter class (display name and filter mask)
139 typedef ::std::list< FilterDescriptor > FilterGroup; // a list of single filter entries
140 typedef ::std::list< FilterGroup > GroupedFilterList; // a list of all filters, already grouped
142 /// the logical name of a filter
143 typedef ::rtl::OUString FilterName;
145 // a struct which holds references from a logical filter name to a filter group entry
146 // used for quick lookup of classes (means class entries - entries representing a class)
147 // which a given filter may belong to
148 typedef ::std::map< ::rtl::OUString, FilterGroup::iterator > FilterGroupEntryReferrer;
150 /// a descriptor for a filter class (which in the final dialog is represented by one filter entry)
151 typedef struct _tagFilterClass
153 ::rtl::OUString sDisplayName; // the display name
154 Sequence< FilterName > aSubFilters; // the (logical) names of the filter which belong to the class
155 } FilterClass;
157 typedef ::std::list< FilterClass > FilterClassList;
158 typedef ::std::map< ::rtl::OUString, FilterClassList::iterator > FilterClassReferrer;
160 typedef ::std::vector< ::rtl::OUString > StringArray;
162 // =======================================================================
163 // = reading of configuration data
164 // =======================================================================
166 //--------------------------------------------------------------------
167 void lcl_ReadFilterClass( const OConfigurationNode& _rClassesNode, const ::rtl::OUString& _rLogicalClassName,
168 FilterClass& /* [out] */ _rClass )
170 static const ::rtl::OUString sDisplaNameNodeName( RTL_CONSTASCII_USTRINGPARAM( "DisplayName" ) );
171 static const ::rtl::OUString sSubFiltersNodeName( RTL_CONSTASCII_USTRINGPARAM( "Filters" ) );
173 // the description node for the current class
174 OConfigurationNode aClassDesc = _rClassesNode.openNode( _rLogicalClassName );
176 // the values
177 aClassDesc.getNodeValue( sDisplaNameNodeName ) >>= _rClass.sDisplayName;
178 aClassDesc.getNodeValue( sSubFiltersNodeName ) >>= _rClass.aSubFilters;
181 //--------------------------------------------------------------------
182 struct CreateEmptyClassRememberPos : public ::std::unary_function< FilterName, void >
184 protected:
185 FilterClassList& m_rClassList;
186 FilterClassReferrer& m_rClassesReferrer;
188 public:
189 CreateEmptyClassRememberPos( FilterClassList& _rClassList, FilterClassReferrer& _rClassesReferrer )
190 :m_rClassList ( _rClassList )
191 ,m_rClassesReferrer ( _rClassesReferrer )
195 // operate on a single class name
196 void operator() ( const FilterName& _rLogicalFilterName )
198 // insert a new (empty) class
199 m_rClassList.push_back( FilterClass() );
200 // get the position of this new entry
201 FilterClassList::iterator aInsertPos = m_rClassList.end();
202 --aInsertPos;
203 // remember this position
204 m_rClassesReferrer.insert( FilterClassReferrer::value_type( _rLogicalFilterName, aInsertPos ) );
208 //--------------------------------------------------------------------
209 struct ReadGlobalFilter : public ::std::unary_function< FilterName, void >
211 protected:
212 OConfigurationNode m_aClassesNode;
213 FilterClassReferrer& m_aClassReferrer;
215 public:
216 ReadGlobalFilter( const OConfigurationNode& _rClassesNode, FilterClassReferrer& _rClassesReferrer )
217 :m_aClassesNode ( _rClassesNode )
218 ,m_aClassReferrer ( _rClassesReferrer )
222 // operate on a single logical name
223 void operator() ( const FilterName& _rName )
225 FilterClassReferrer::iterator aClassRef = m_aClassReferrer.find( _rName );
226 if ( m_aClassReferrer.end() == aClassRef )
228 // we do not know this global class
229 DBG_ERROR( "ReadGlobalFilter::operator(): unknown filter name!" );
230 // TODO: perhaps we should be more tolerant - at the moment, the filter is dropped
231 // We could silently push_back it to the container ....
233 else
235 // read the data of this class into the node referred to by aClassRef
236 lcl_ReadFilterClass( m_aClassesNode, _rName, *aClassRef->second );
241 //--------------------------------------------------------------------
242 void lcl_ReadGlobalFilters( const OConfigurationNode& _rFilterClassification, FilterClassList& _rGlobalClasses, StringArray& _rGlobalClassNames )
244 _rGlobalClasses.clear();
245 _rGlobalClassNames.clear();
247 //================================================================
248 // get the list describing the order of all global classes
249 Sequence< ::rtl::OUString > aGlobalClasses;
250 _rFilterClassification.getNodeValue( DEFINE_CONST_OUSTRING( "GlobalFilters/Order" ) ) >>= aGlobalClasses;
252 const ::rtl::OUString* pNames = aGlobalClasses.getConstArray();
253 const ::rtl::OUString* pNamesEnd = pNames + aGlobalClasses.getLength();
255 // copy the logical names
256 _rGlobalClassNames.resize( aGlobalClasses.getLength() );
257 ::std::copy( pNames, pNamesEnd, _rGlobalClassNames.begin() );
259 // Global classes are presented in an own group, so their order matters (while the order of the
260 // "local classes" doesn't).
261 // That's why we can't simply add the global classes to _rGlobalClasses using the order in which they
262 // are returned from the configuration - it is completely undefined, and we need a _defined_ order.
263 FilterClassReferrer aClassReferrer;
264 ::std::for_each(
265 pNames,
266 pNamesEnd,
267 CreateEmptyClassRememberPos( _rGlobalClasses, aClassReferrer )
269 // now _rGlobalClasses contains a dummy entry for each global class,
270 // while aClassReferrer maps from the logical name of the class to the position within _rGlobalClasses where
271 // it's dummy entry resides
273 //================================================================
274 // go for all the single class entries
275 OConfigurationNode aFilterClassesNode =
276 _rFilterClassification.openNode( DEFINE_CONST_OUSTRING( "GlobalFilters/Classes" ) );
277 Sequence< ::rtl::OUString > aFilterClasses = aFilterClassesNode.getNodeNames();
278 ::std::for_each(
279 aFilterClasses.getConstArray(),
280 aFilterClasses.getConstArray() + aFilterClasses.getLength(),
281 ReadGlobalFilter( aFilterClassesNode, aClassReferrer )
285 //--------------------------------------------------------------------
286 struct ReadLocalFilter : public ::std::unary_function< FilterName, void >
288 protected:
289 OConfigurationNode m_aClassesNode;
290 FilterClassList& m_rClasses;
292 public:
293 ReadLocalFilter( const OConfigurationNode& _rClassesNode, FilterClassList& _rClasses )
294 :m_aClassesNode ( _rClassesNode )
295 ,m_rClasses ( _rClasses )
299 // operate on a single logical name
300 void operator() ( const FilterName& _rName )
302 // read the data for this class
303 FilterClass aClass;
304 lcl_ReadFilterClass( m_aClassesNode, _rName, aClass );
306 // insert the class descriptor
307 m_rClasses.push_back( aClass );
311 //--------------------------------------------------------------------
312 void lcl_ReadLocalFilters( const OConfigurationNode& _rFilterClassification, FilterClassList& _rLocalClasses )
314 _rLocalClasses.clear();
316 // the node for the local classes
317 OConfigurationNode aFilterClassesNode =
318 _rFilterClassification.openNode( DEFINE_CONST_OUSTRING( "LocalFilters/Classes" ) );
319 Sequence< ::rtl::OUString > aFilterClasses = aFilterClassesNode.getNodeNames();
321 ::std::for_each(
322 aFilterClasses.getConstArray(),
323 aFilterClasses.getConstArray() + aFilterClasses.getLength(),
324 ReadLocalFilter( aFilterClassesNode, _rLocalClasses )
328 //--------------------------------------------------------------------
329 void lcl_ReadClassification( FilterClassList& _rGlobalClasses, StringArray& _rGlobalClassNames, FilterClassList& _rLocalClasses )
331 //================================================================
332 // open our config node
333 OConfigurationTreeRoot aFilterClassification = OConfigurationTreeRoot::createWithServiceFactory(
334 ::comphelper::getProcessServiceFactory(),
335 DEFINE_CONST_OUSTRING( "org.openoffice.Office.UI/FilterClassification" ),
337 OConfigurationTreeRoot::CM_READONLY
340 //================================================================
341 // go for the global classes
342 lcl_ReadGlobalFilters( aFilterClassification, _rGlobalClasses, _rGlobalClassNames );
344 //================================================================
345 // fo for the local classes
346 lcl_ReadLocalFilters( aFilterClassification, _rLocalClasses );
350 // =======================================================================
351 // = grouping and classifying
352 // =======================================================================
354 //--------------------------------------------------------------------
355 // a struct which adds helps remembering a reference to a class entry
356 struct ReferToFilterEntry : public ::std::unary_function< FilterName, void >
358 protected:
359 FilterGroupEntryReferrer& m_rEntryReferrer;
360 FilterGroup::iterator m_aClassPos;
362 public:
363 ReferToFilterEntry( FilterGroupEntryReferrer& _rEntryReferrer, const FilterGroup::iterator& _rClassPos )
364 :m_rEntryReferrer( _rEntryReferrer )
365 ,m_aClassPos( _rClassPos )
369 // operate on a single filter name
370 void operator() ( const FilterName& _rName )
372 #ifdef DBG_UTIL
373 ::std::pair< FilterGroupEntryReferrer::iterator, bool > aInsertRes =
374 #endif
375 m_rEntryReferrer.insert( FilterGroupEntryReferrer::value_type( _rName, m_aClassPos ) );
376 DBG_ASSERT( aInsertRes.second, "ReferToFilterEntry::operator(): already have an element for this name!" );
380 //--------------------------------------------------------------------
381 struct FillClassGroup : public ::std::unary_function< FilterClass, void >
383 protected:
384 FilterGroup& m_rClassGroup;
385 FilterGroupEntryReferrer& m_rClassReferrer;
387 public:
388 FillClassGroup( FilterGroup& _rClassGroup, FilterGroupEntryReferrer& _rClassReferrer )
389 :m_rClassGroup ( _rClassGroup )
390 ,m_rClassReferrer ( _rClassReferrer )
394 // operate on a single class
395 void operator() ( const FilterClass& _rClass )
397 // create an empty filter descriptor for the class
398 FilterDescriptor aClassEntry;
399 // set it's name (which is all we know by now)
400 aClassEntry.First = _rClass.sDisplayName;
402 // add it to the group
403 m_rClassGroup.push_back( aClassEntry );
404 // the position of the newly added class
405 FilterGroup::iterator aClassEntryPos = m_rClassGroup.end();
406 --aClassEntryPos;
408 // and for all the sub filters of the class, remember the class
409 // (respectively the position of the class it the group)
410 ::std::for_each(
411 _rClass.aSubFilters.getConstArray(),
412 _rClass.aSubFilters.getConstArray() + _rClass.aSubFilters.getLength(),
413 ReferToFilterEntry( m_rClassReferrer, aClassEntryPos )
418 //--------------------------------------------------------------------
419 static const sal_Unicode s_cWildcardSeparator( ';' );
421 //====================================================================
422 const ::rtl::OUString& getSeparatorString()
424 static ::rtl::OUString s_sSeparatorString( &s_cWildcardSeparator, 1 );
425 return s_sSeparatorString;
428 //====================================================================
429 struct CheckAppendSingleWildcard : public ::std::unary_function< ::rtl::OUString, void >
431 ::rtl::OUString& _rToBeExtended;
433 CheckAppendSingleWildcard( ::rtl::OUString& _rBase ) : _rToBeExtended( _rBase ) { }
435 void operator() ( const ::rtl::OUString& _rWC )
437 // check for double wildcards
438 sal_Int32 nExistentPos = _rToBeExtended.indexOf( _rWC );
439 if ( -1 < nExistentPos )
440 { // found this wildcard (already part of _rToBeExtended)
441 const sal_Unicode* pBuffer = _rToBeExtended.getStr();
442 if ( ( 0 == nExistentPos )
443 || ( s_cWildcardSeparator == pBuffer[ nExistentPos - 1 ] )
445 { // the wildcard really starts at this position (it starts at pos 0 or the previous character is a separator
446 sal_Int32 nExistentWCEnd = nExistentPos + _rWC.getLength();
447 if ( ( _rToBeExtended.getLength() == nExistentWCEnd )
448 || ( s_cWildcardSeparator == pBuffer[ nExistentWCEnd ] )
450 { // it's really the complete wildcard we found
451 // (not something like _rWC beeing "*.t" and _rToBeExtended containing "*.txt")
452 // -> outta here
453 return;
458 if ( _rToBeExtended.getLength() )
459 _rToBeExtended += getSeparatorString();
460 _rToBeExtended += _rWC;
464 //====================================================================
465 // a helper struct which adds a fixed (Sfx-)filter to a filter group entry given by iterator
466 struct AppendWildcardToDescriptor : public ::std::unary_function< FilterGroupEntryReferrer::value_type, void >
468 protected:
469 ::std::vector< ::rtl::OUString > aWildCards;
471 public:
472 AppendWildcardToDescriptor( const String& _rWildCard );
474 // operate on a single class entry
475 void operator() ( const FilterGroupEntryReferrer::value_type& _rClassReference )
477 // simply add our wildcards
478 ::std::for_each(
479 aWildCards.begin(),
480 aWildCards.end(),
481 CheckAppendSingleWildcard( _rClassReference.second->Second )
486 //====================================================================
487 AppendWildcardToDescriptor::AppendWildcardToDescriptor( const String& _rWildCard )
489 DBG_ASSERT( _rWildCard.Len(),
490 "AppendWildcardToDescriptor::AppendWildcardToDescriptor: invalid wildcard!" );
491 DBG_ASSERT( _rWildCard.GetBuffer()[0] != s_cWildcardSeparator,
492 "AppendWildcardToDescriptor::AppendWildcardToDescriptor: wildcard already separated!" );
494 aWildCards.reserve( _rWildCard.GetTokenCount( s_cWildcardSeparator ) );
496 const sal_Unicode* pTokenLoop = _rWildCard.GetBuffer();
497 const sal_Unicode* pTokenLoopEnd = pTokenLoop + _rWildCard.Len();
498 const sal_Unicode* pTokenStart = pTokenLoop;
499 for ( ; pTokenLoop != pTokenLoopEnd; ++pTokenLoop )
501 if ( ( s_cWildcardSeparator == *pTokenLoop ) && ( pTokenLoop > pTokenStart ) )
502 { // found a new token separator (and a non-empty token)
503 aWildCards.push_back( ::rtl::OUString( pTokenStart, pTokenLoop - pTokenStart ) );
505 // search the start of the next token
506 while ( ( pTokenStart != pTokenLoopEnd ) && ( *pTokenStart != s_cWildcardSeparator ) )
507 ++pTokenStart;
509 if ( pTokenStart == pTokenLoopEnd )
510 // reached the end
511 break;
513 ++pTokenStart;
514 pTokenLoop = pTokenStart;
517 if ( pTokenLoop > pTokenStart )
518 // the last one ....
519 aWildCards.push_back( ::rtl::OUString( pTokenStart, pTokenLoop - pTokenStart ) );
522 //--------------------------------------------------------------------
523 void lcl_InitGlobalClasses( GroupedFilterList& _rAllFilters, const FilterClassList& _rGlobalClasses, FilterGroupEntryReferrer& _rGlobalClassesRef )
525 // we need an extra group in our "all filters" container
526 _rAllFilters.push_front( FilterGroup() );
527 FilterGroup& rGlobalFilters = _rAllFilters.front();
528 // it's important to work on the reference: we want to access the members of this filter group
529 // by an iterator (FilterGroup::const_iterator)
530 // the referrer for the global classes
532 // initialize the group
533 ::std::for_each(
534 _rGlobalClasses.begin(),
535 _rGlobalClasses.end(),
536 FillClassGroup( rGlobalFilters, _rGlobalClassesRef )
538 // now we have:
539 // in rGlobalFilters: a list of FilterDescriptor's, where each's discriptor's display name is set to the name of a class
540 // in aGlobalClassesRef: a mapping from logical filter names to positions within rGlobalFilters
541 // this way, if we encounter an arbitrary filter, we can easily (and efficient) check if it belongs to a global class
542 // and modify the descriptor for this class accordingly
545 //--------------------------------------------------------------------
546 typedef ::std::vector< ::std::pair< FilterGroupEntryReferrer::mapped_type, FilterGroup::iterator > >
547 MapGroupEntry2GroupEntry;
548 // this is not really a map - it's just called this way because it is used as a map
550 struct FindGroupEntry : public ::std::unary_function< MapGroupEntry2GroupEntry::value_type, sal_Bool >
552 FilterGroupEntryReferrer::mapped_type aLookingFor;
553 FindGroupEntry( FilterGroupEntryReferrer::mapped_type _rLookingFor ) : aLookingFor( _rLookingFor ) { }
555 sal_Bool operator() ( const MapGroupEntry2GroupEntry::value_type& _rMapEntry )
557 return _rMapEntry.first == aLookingFor ? sal_True : sal_False;
561 struct CopyGroupEntryContent : public ::std::unary_function< MapGroupEntry2GroupEntry::value_type, void >
563 void operator() ( const MapGroupEntry2GroupEntry::value_type& _rMapEntry )
565 #ifdef DBG_UTIL
566 FilterDescriptor aHaveALook = *_rMapEntry.first;
567 #endif
568 *_rMapEntry.second = *_rMapEntry.first;
572 //--------------------------------------------------------------------
573 struct CopyNonEmptyFilter : public ::std::unary_function< FilterDescriptor, void >
575 FilterGroup& rTarget;
576 CopyNonEmptyFilter( FilterGroup& _rTarget ) :rTarget( _rTarget ) { }
578 void operator() ( const FilterDescriptor& _rFilter )
580 if ( _rFilter.Second.getLength() )
581 rTarget.push_back( _rFilter );
585 //--------------------------------------------------------------------
586 void lcl_GroupAndClassify( TSortedFilterList& _rFilterMatcher, GroupedFilterList& _rAllFilters )
588 _rAllFilters.clear();
590 // ===============================================================
591 // read the classification of filters
592 FilterClassList aGlobalClasses, aLocalClasses;
593 StringArray aGlobalClassNames;
594 lcl_ReadClassification( aGlobalClasses, aGlobalClassNames, aLocalClasses );
596 // ===============================================================
597 // for the global filter classes
598 FilterGroupEntryReferrer aGlobalClassesRef;
599 lcl_InitGlobalClasses( _rAllFilters, aGlobalClasses, aGlobalClassesRef );
601 // insert as much placeholders (FilterGroup's) into _rAllFilter for groups as we have global classes
602 // (this assumes that both numbers are the same, which, speaking strictly, must not hold - but it does, as we know ...)
603 sal_Int32 nGlobalClasses = aGlobalClasses.size();
604 while ( nGlobalClasses-- )
605 _rAllFilters.push_back( FilterGroup() );
607 // ===============================================================
608 // for the local classes:
609 // if n filters belong to a local class, they do not appear in their respective group explicitly, instead
610 // and entry for the class is added to the group and the extensions of the filters are collected under
611 // this entry
612 FilterGroupEntryReferrer aLocalClassesRef;
613 FilterGroup aCollectedLocals;
614 ::std::for_each(
615 aLocalClasses.begin(),
616 aLocalClasses.end(),
617 FillClassGroup( aCollectedLocals, aLocalClassesRef )
619 // to map from the position within aCollectedLocals to positions within the real groups
620 // (where they finally belong to)
621 MapGroupEntry2GroupEntry aLocalFinalPositions;
623 // ===============================================================
624 // now add the filters
625 // the group which we currently work with
626 GroupedFilterList::iterator aCurrentGroup = _rAllFilters.end(); // no current group
627 // the filter container of the current group - if this changes between two filters, a new group is reached
628 String aCurrentServiceName;
630 String sFilterWildcard;
631 ::rtl::OUString sFilterName;
632 // loop through all the filters
633 for ( const SfxFilter* pFilter = _rFilterMatcher.First(); pFilter; pFilter = _rFilterMatcher.Next() )
635 sFilterName = pFilter->GetFilterName();
636 sFilterWildcard = pFilter->GetWildcard().GetWildCard();
637 AppendWildcardToDescriptor aExtendWildcard( sFilterWildcard );
639 DBG_ASSERT( sFilterWildcard.Len(), "sfx2::lcl_GroupAndClassify: invalid wildcard of this filter!" );
641 // ===========================================================
642 // check for a change in the group
643 String aServiceName = pFilter->GetServiceName();
644 if ( aServiceName != aCurrentServiceName )
645 { // we reached a new group
647 ::rtl::OUString sDocServName = aServiceName;
649 // look for the place in _rAllFilters where this ne group belongs - this is determined
650 // by the order of classes in aGlobalClassNames
651 GroupedFilterList::iterator aGroupPos = _rAllFilters.begin();
652 DBG_ASSERT( aGroupPos != _rAllFilters.end(),
653 "sfx2::lcl_GroupAndClassify: invalid all-filters array here!" );
654 // the loop below will work on invalid objects else ...
655 ++aGroupPos;
656 StringArray::iterator aGlobalIter = aGlobalClassNames.begin();
657 while ( ( aGroupPos != _rAllFilters.end() )
658 && ( aGlobalIter != aGlobalClassNames.end() )
659 && ( *aGlobalIter != sDocServName )
662 ++aGlobalIter;
663 ++aGroupPos;
665 if ( aGroupPos != _rAllFilters.end() )
666 // we found a global class name which matchies the doc service name -> fill the filters of this
667 // group in the respective prepared group
668 aCurrentGroup = aGroupPos;
669 else
670 // insert a new entry in our overall-list
671 aCurrentGroup = _rAllFilters.insert( _rAllFilters.end(), FilterGroup() );
673 // remember the container to properly detect the next group
674 aCurrentServiceName = aServiceName;
677 DBG_ASSERT( aCurrentGroup != _rAllFilters.end(), "sfx2::lcl_GroupAndClassify: invalid current group!" );
679 // ===========================================================
680 // check if the filter is part of a global group
681 ::std::pair< FilterGroupEntryReferrer::iterator, FilterGroupEntryReferrer::iterator >
682 aBelongsTo = aGlobalClassesRef.equal_range( sFilterName );
683 // add the filter to the entries for these classes
684 // (if they exist - if not, the range is empty and the for_each is a no-op)
685 ::std::for_each(
686 aBelongsTo.first,
687 aBelongsTo.second,
688 aExtendWildcard
691 // ===========================================================
692 // add the filter to it's group
694 // for this, check if the filter is part of a local filter
695 FilterGroupEntryReferrer::iterator aBelongsToLocal = aLocalClassesRef.find( sFilterName );
696 if ( aLocalClassesRef.end() != aBelongsToLocal )
699 #ifdef DBG_UTIL
700 const ::rtl::OUString& rLocalClassDisplayName = aBelongsToLocal->second->First;
701 const ::rtl::OUString& rLocalClassExtension = aBelongsToLocal->second->Second;
702 #endif
704 // okay, there is a local class which the filter belongs to
705 // -> append the wildcard
706 aExtendWildcard( *aBelongsToLocal );
708 MapGroupEntry2GroupEntry::iterator aThisGroupFinalPos =
709 ::std::find_if( aLocalFinalPositions.begin(), aLocalFinalPositions.end(), FindGroupEntry( aBelongsToLocal->second ) );
711 if ( aLocalFinalPositions.end() == aThisGroupFinalPos )
712 { // the position within aCollectedLocals has not been mapped to a final position
713 // within the "real" group (aCollectedLocals is only temporary)
714 // -> do this now (as we just encountered the first filter belonging to this local class
715 // add a new entry which is the "real" group entry
716 aCurrentGroup->push_back( FilterDescriptor( aBelongsToLocal->second->First, String() ) );
717 // the position where we inserted the entry
718 FilterGroup::iterator aInsertPos = aCurrentGroup->end();
719 --aInsertPos;
720 // remember this pos
721 aLocalFinalPositions.push_back( MapGroupEntry2GroupEntry::value_type( aBelongsToLocal->second, aInsertPos ) );
724 else
725 aCurrentGroup->push_back( FilterDescriptor( pFilter->GetUIName(), sFilterWildcard ) );
728 // now just complete the infos for the local groups:
729 // During the above loop, they have been collected in aCollectedLocals, but this is only temporary
730 // They have to be copied into their final positions (which are stored in aLocalFinalPositions)
731 ::std::for_each(
732 aLocalFinalPositions.begin(),
733 aLocalFinalPositions.end(),
734 CopyGroupEntryContent()
737 // and remove local groups which do not apply - e.g. have no entries due to the limited content of the
738 // current SfxFilterMatcherIter
740 FilterGroup& rGlobalFilters = _rAllFilters.front();
741 FilterGroup aNonEmptyGlobalFilters;
742 ::std::for_each(
743 rGlobalFilters.begin(),
744 rGlobalFilters.end(),
745 CopyNonEmptyFilter( aNonEmptyGlobalFilters )
747 rGlobalFilters.swap( aNonEmptyGlobalFilters );
750 //--------------------------------------------------------------------
751 struct AppendFilter : public ::std::unary_function< FilterDescriptor, void >
753 protected:
754 Reference< XFilterManager > m_xFilterManager;
755 FileDialogHelper_Impl* m_pFileDlgImpl;
756 bool m_bAddExtension;
758 public:
759 AppendFilter( const Reference< XFilterManager >& _rxFilterManager,
760 FileDialogHelper_Impl* _pImpl, bool _bAddExtension ) :
762 m_xFilterManager( _rxFilterManager ),
763 m_pFileDlgImpl ( _pImpl ),
764 m_bAddExtension ( _bAddExtension )
767 DBG_ASSERT( m_xFilterManager.is(), "AppendFilter::AppendFilter: invalid filter manager!" );
768 DBG_ASSERT( m_pFileDlgImpl, "AppendFilter::AppendFilter: invalid filedlg impl!" );
771 // operate on a single filter
772 void operator() ( const FilterDescriptor& _rFilterEntry )
774 String sDisplayText = m_bAddExtension
775 ? addExtension( _rFilterEntry.First, _rFilterEntry.Second, sal_True, *m_pFileDlgImpl )
776 : _rFilterEntry.First;
777 m_xFilterManager->appendFilter( sDisplayText, _rFilterEntry.Second );
781 // =======================================================================
782 // = handling for the "all files" entry
783 // =======================================================================
785 //--------------------------------------------------------------------
786 sal_Bool lcl_hasAllFilesFilter( TSortedFilterList& _rFilterMatcher, String& /* [out] */ _rAllFilterName )
788 ::rtl::OUString sUIName;
789 sal_Bool bHasAll = sal_False;
790 _rAllFilterName = String( SfxResId( STR_SFX_FILTERNAME_ALL ) );
792 // ===============================================================
793 // check if there's already a filter <ALL>
794 for ( const SfxFilter* pFilter = _rFilterMatcher.First(); pFilter && !bHasAll; pFilter = _rFilterMatcher.Next() )
796 if ( pFilter->GetUIName() == _rAllFilterName )
797 bHasAll = sal_True;
799 return bHasAll;
802 //--------------------------------------------------------------------
803 void lcl_EnsureAllFilesEntry( TSortedFilterList& _rFilterMatcher, GroupedFilterList& _rFilters )
805 // ===============================================================
806 String sAllFilterName;
807 if ( !lcl_hasAllFilesFilter( _rFilterMatcher, sAllFilterName ) )
809 // get the first group of filters (by definition, this group contains the global classes)
810 DBG_ASSERT( !_rFilters.empty(), "lcl_EnsureAllFilesEntry: invalid filter list!" );
811 if ( !_rFilters.empty() )
813 FilterGroup& rGlobalClasses = *_rFilters.begin();
814 rGlobalClasses.push_front( FilterDescriptor( sAllFilterName, DEFINE_CONST_UNICODE( FILEDIALOG_FILTER_ALL ) ) );
819 #ifdef DISABLE_GROUPING_AND_CLASSIFYING
820 //--------------------------------------------------------------------
821 void lcl_EnsureAllFilesEntry( TSortedFilterList& _rFilterMatcher, const Reference< XFilterManager >& _rxFilterManager, ::rtl::OUString& _rFirstNonEmpty )
823 // ===============================================================
824 String sAllFilterName;
825 if ( !lcl_hasAllFilesFilter( _rFilterMatcher, sAllFilterName ) )
829 _rxFilterManager->appendFilter( sAllFilterName, DEFINE_CONST_UNICODE( FILEDIALOG_FILTER_ALL ) );
830 _rFirstNonEmpty = sAllFilterName;
832 catch( const IllegalArgumentException& )
834 #ifdef DBG_UTIL
835 ByteString aMsg( "sfx2::lcl_EnsureAllFilesEntry: could not append Filter" );
836 aMsg += ByteString( String( sAllFilterName ), RTL_TEXTENCODING_UTF8 );
837 DBG_ERROR( aMsg.GetBuffer() );
838 #endif
843 #endif
845 // =======================================================================
846 // = filling an XFilterManager
847 // =======================================================================
849 //--------------------------------------------------------------------
850 struct AppendFilterGroup : public ::std::unary_function< FilterGroup, void >
852 protected:
853 Reference< XFilterManager > m_xFilterManager;
854 Reference< XFilterGroupManager > m_xFilterGroupManager;
855 FileDialogHelper_Impl* m_pFileDlgImpl;
857 public:
858 AppendFilterGroup( const Reference< XFilterManager >& _rxFilterManager, FileDialogHelper_Impl* _pImpl )
859 :m_xFilterManager ( _rxFilterManager )
860 ,m_xFilterGroupManager ( _rxFilterManager, UNO_QUERY )
861 ,m_pFileDlgImpl ( _pImpl )
863 DBG_ASSERT( m_xFilterManager.is(), "AppendFilterGroup::AppendFilterGroup: invalid filter manager!" );
864 DBG_ASSERT( m_pFileDlgImpl, "AppendFilterGroup::AppendFilterGroup: invalid filedlg impl!" );
867 void appendGroup( const FilterGroup& _rGroup, bool _bAddExtension )
871 if ( m_xFilterGroupManager.is() )
872 { // the file dialog implementation supports visual grouping of filters
873 // create a representation of the group which is understandable by the XFilterGroupManager
874 if ( _rGroup.size() )
876 Sequence< StringPair > aFilters( _rGroup.size() );
877 ::std::copy(
878 _rGroup.begin(),
879 _rGroup.end(),
880 aFilters.getArray()
882 if ( _bAddExtension )
884 StringPair* pFilters = aFilters.getArray();
885 StringPair* pEnd = pFilters + aFilters.getLength();
886 for ( ; pFilters != pEnd; ++pFilters )
887 pFilters->First = addExtension( pFilters->First, pFilters->Second, sal_True, *m_pFileDlgImpl );
889 m_xFilterGroupManager->appendFilterGroup( ::rtl::OUString(), aFilters );
892 else
894 ::std::for_each(
895 _rGroup.begin(),
896 _rGroup.end(),
897 AppendFilter( m_xFilterManager, m_pFileDlgImpl, _bAddExtension ) );
900 catch( const Exception& )
902 DBG_UNHANDLED_EXCEPTION();
906 // operate on a single filter group
907 void operator() ( const FilterGroup& _rGroup )
909 appendGroup( _rGroup, true );
913 //--------------------------------------------------------------------
914 TSortedFilterList::TSortedFilterList(const ::com::sun::star::uno::Reference< ::com::sun::star::container::XEnumeration >& xFilterList)
915 : m_nIterator(0)
917 if (!xFilterList.is())
918 return;
920 m_lFilters.clear();
921 while(xFilterList->hasMoreElements())
923 ::comphelper::SequenceAsHashMap lFilterProps (xFilterList->nextElement());
924 ::rtl::OUString sFilterName = lFilterProps.getUnpackedValueOrDefault(
925 ::rtl::OUString::createFromAscii("Name"),
926 ::rtl::OUString());
927 if (sFilterName.getLength())
928 m_lFilters.push_back(sFilterName);
932 //--------------------------------------------------------------------
933 const SfxFilter* TSortedFilterList::First()
935 m_nIterator = 0;
936 return impl_getFilter(m_nIterator);
939 //--------------------------------------------------------------------
940 const SfxFilter* TSortedFilterList::Next()
942 ++m_nIterator;
943 return impl_getFilter(m_nIterator);
946 //--------------------------------------------------------------------
947 const SfxFilter* TSortedFilterList::impl_getFilter(sal_Int32 nIndex)
949 if (nIndex<0 || nIndex>=(sal_Int32)m_lFilters.size())
950 return 0;
951 const ::rtl::OUString& sFilterName = m_lFilters[nIndex];
952 if (!sFilterName.getLength())
953 return 0;
954 return SfxFilter::GetFilterByName(String(sFilterName));
957 //--------------------------------------------------------------------
958 void appendFiltersForSave( TSortedFilterList& _rFilterMatcher,
959 const Reference< XFilterManager >& _rxFilterManager,
960 ::rtl::OUString& _rFirstNonEmpty, FileDialogHelper_Impl& _rFileDlgImpl,
961 const ::rtl::OUString& _rFactory )
963 DBG_ASSERT( _rxFilterManager.is(), "sfx2::appendFiltersForSave: invalid manager!" );
964 if ( !_rxFilterManager.is() )
965 return;
967 ::rtl::OUString sUIName;
968 ::rtl::OUString sExtension;
970 // retrieve the default filter for this application module.
971 // It must be set as first of the generated filter list.
972 const SfxFilter* pDefaultFilter = SfxFilterContainer::GetDefaultFilter_Impl(_rFactory);
973 // --> PB 2004-11-01 #i32434# only use one extension
974 // (and always the first if there are more than one)
975 sExtension = pDefaultFilter->GetWildcard().GetWildCard().GetToken( 0, ';' );
976 // <--
977 sUIName = addExtension( pDefaultFilter->GetUIName(), sExtension, sal_False, _rFileDlgImpl );
980 _rxFilterManager->appendFilter( sUIName, sExtension );
981 if ( !_rFirstNonEmpty.getLength() )
982 _rFirstNonEmpty = sUIName;
984 catch( IllegalArgumentException )
986 #ifdef DBG_UTIL
987 ByteString aMsg( "Could not append DefaultFilter" );
988 aMsg += ByteString( String( sUIName ), osl_getThreadTextEncoding() );
989 DBG_ERRORFILE( aMsg.GetBuffer() );
990 #endif
993 for ( const SfxFilter* pFilter = _rFilterMatcher.First(); pFilter; pFilter = _rFilterMatcher.Next() )
995 if (pFilter->GetName() == pDefaultFilter->GetName())
996 continue;
998 // --> PB 2004-09-21 #i32434# only use one extension
999 // (and always the first if there are more than one)
1000 sExtension = pFilter->GetWildcard().GetWildCard().GetToken( 0, ';' );
1001 // <--
1002 sUIName = addExtension( pFilter->GetUIName(), sExtension, sal_False, _rFileDlgImpl );
1005 _rxFilterManager->appendFilter( sUIName, sExtension );
1006 if ( !_rFirstNonEmpty.getLength() )
1007 _rFirstNonEmpty = sUIName;
1009 catch( IllegalArgumentException )
1011 #ifdef DBG_UTIL
1012 ByteString aMsg( "Could not append Filter" );
1013 aMsg += ByteString( String( sUIName ), osl_getThreadTextEncoding() );
1014 DBG_ERRORFILE( aMsg.GetBuffer() );
1015 #endif
1020 struct ExportFilter
1022 ExportFilter( const rtl::OUString& _aUIName, const rtl::OUString& _aWildcard ) :
1023 aUIName( _aUIName ), aWildcard( _aWildcard ) {}
1025 rtl::OUString aUIName;
1026 rtl::OUString aWildcard;
1029 //--------------------------------------------------------------------
1030 void appendExportFilters( TSortedFilterList& _rFilterMatcher,
1031 const Reference< XFilterManager >& _rxFilterManager,
1032 ::rtl::OUString& _rFirstNonEmpty, FileDialogHelper_Impl& _rFileDlgImpl )
1034 DBG_ASSERT( _rxFilterManager.is(), "sfx2::appendExportFilters: invalid manager!" );
1035 if ( !_rxFilterManager.is() )
1036 return;
1038 sal_Int32 nHTMLIndex = -1;
1039 sal_Int32 nXHTMLIndex = -1;
1040 sal_Int32 nPDFIndex = -1;
1041 sal_Int32 nFlashIndex = -1;
1042 ::rtl::OUString sUIName;
1043 ::rtl::OUString sExtensions;
1044 std::vector< ExportFilter > aImportantFilterGroup;
1045 std::vector< ExportFilter > aFilterGroup;
1046 Reference< XFilterGroupManager > xFilterGroupManager( _rxFilterManager, UNO_QUERY );
1047 ::rtl::OUString sTypeName;
1048 const ::rtl::OUString sWriterHTMLType( DEFINE_CONST_OUSTRING("writer_web_HTML") );
1049 const ::rtl::OUString sGraphicHTMLType( DEFINE_CONST_OUSTRING("graphic_HTML") );
1050 const ::rtl::OUString sXHTMLType( DEFINE_CONST_OUSTRING("XHTML_File") );
1051 const ::rtl::OUString sPDFType( DEFINE_CONST_OUSTRING("pdf_Portable_Document_Format") );
1052 const ::rtl::OUString sFlashType( DEFINE_CONST_OUSTRING("graphic_SWF") );
1054 for ( const SfxFilter* pFilter = _rFilterMatcher.First(); pFilter; pFilter = _rFilterMatcher.Next() )
1056 sTypeName = pFilter->GetTypeName();
1057 sUIName = pFilter->GetUIName();
1058 sExtensions = pFilter->GetWildcard().GetWildCard();
1059 ExportFilter aExportFilter( sUIName, sExtensions );
1060 String aExt = sExtensions;
1062 if ( nHTMLIndex == -1 &&
1063 ( sTypeName.equals( sWriterHTMLType ) || sTypeName.equals( sGraphicHTMLType ) ) )
1065 aImportantFilterGroup.insert( aImportantFilterGroup.begin(), aExportFilter );
1066 nHTMLIndex = 0;
1068 else if ( nXHTMLIndex == -1 && sTypeName.equals( sXHTMLType ) )
1070 std::vector< ExportFilter >::iterator aIter = aImportantFilterGroup.begin();
1071 if ( nHTMLIndex == -1 )
1072 aImportantFilterGroup.insert( aIter, aExportFilter );
1073 else
1074 aImportantFilterGroup.insert( ++aIter, aExportFilter );
1075 nXHTMLIndex = 0;
1077 else if ( nPDFIndex == -1 && sTypeName.equals( sPDFType ) )
1079 std::vector< ExportFilter >::iterator aIter = aImportantFilterGroup.begin();
1080 if ( nHTMLIndex != -1 )
1081 aIter++;
1082 if ( nXHTMLIndex != -1 )
1083 aIter++;
1084 aImportantFilterGroup.insert( aIter, aExportFilter );
1085 nPDFIndex = 0;
1087 else if ( nFlashIndex == -1 && sTypeName.equals( sFlashType ) )
1089 std::vector< ExportFilter >::iterator aIter = aImportantFilterGroup.begin();
1090 if ( nHTMLIndex != -1 )
1091 aIter++;
1092 if ( nXHTMLIndex != -1 )
1093 aIter++;
1094 if ( nPDFIndex != -1 )
1095 aIter++;
1096 aImportantFilterGroup.insert( aIter, aExportFilter );
1097 nFlashIndex = 0;
1099 else
1100 aFilterGroup.push_back( aExportFilter );
1103 if ( xFilterGroupManager.is() )
1105 // Add both html/pdf filter as a filter group to get a separator between both groups
1106 if ( aImportantFilterGroup.size() > 0 )
1108 Sequence< StringPair > aFilters( aImportantFilterGroup.size() );
1109 for ( sal_Int32 i = 0; i < (sal_Int32)aImportantFilterGroup.size(); i++ )
1111 aFilters[i].First = addExtension( aImportantFilterGroup[i].aUIName,
1112 aImportantFilterGroup[i].aWildcard,
1113 sal_False, _rFileDlgImpl );
1114 aFilters[i].Second = aImportantFilterGroup[i].aWildcard;
1119 xFilterGroupManager->appendFilterGroup( ::rtl::OUString(), aFilters );
1121 catch( IllegalArgumentException )
1126 if ( aFilterGroup.size() > 0 )
1128 Sequence< StringPair > aFilters( aFilterGroup.size() );
1129 for ( sal_Int32 i = 0; i < (sal_Int32)aFilterGroup.size(); i++ )
1131 aFilters[i].First = addExtension( aFilterGroup[i].aUIName,
1132 aFilterGroup[i].aWildcard,
1133 sal_False, _rFileDlgImpl );
1134 aFilters[i].Second = aFilterGroup[i].aWildcard;
1139 xFilterGroupManager->appendFilterGroup( ::rtl::OUString(), aFilters );
1141 catch( IllegalArgumentException )
1146 else
1148 // Fallback solution just add both filter groups as single filters
1149 sal_Int32 n;
1151 for ( n = 0; n < (sal_Int32)aImportantFilterGroup.size(); n++ )
1155 rtl::OUString aUIName = addExtension( aImportantFilterGroup[n].aUIName,
1156 aImportantFilterGroup[n].aWildcard,
1157 sal_False, _rFileDlgImpl );
1158 _rxFilterManager->appendFilter( aUIName, aImportantFilterGroup[n].aWildcard );
1159 if ( !_rFirstNonEmpty.getLength() )
1160 _rFirstNonEmpty = sUIName;
1163 catch( IllegalArgumentException )
1165 #ifdef DBG_UTIL
1166 ByteString aMsg( "Could not append Filter" );
1167 aMsg += ByteString( String( sUIName ), osl_getThreadTextEncoding() );
1168 DBG_ERRORFILE( aMsg.GetBuffer() );
1169 #endif
1173 for ( n = 0; n < (sal_Int32)aFilterGroup.size(); n++ )
1177 rtl::OUString aUIName = addExtension( aFilterGroup[n].aUIName,
1178 aFilterGroup[n].aWildcard,
1179 sal_False, _rFileDlgImpl );
1180 _rxFilterManager->appendFilter( aUIName, aFilterGroup[n].aWildcard );
1181 if ( !_rFirstNonEmpty.getLength() )
1182 _rFirstNonEmpty = sUIName;
1185 catch( IllegalArgumentException )
1187 #ifdef DBG_UTIL
1188 ByteString aMsg( "Could not append Filter" );
1189 aMsg += ByteString( String( sUIName ), osl_getThreadTextEncoding() );
1190 DBG_ERRORFILE( aMsg.GetBuffer() );
1191 #endif
1197 //--------------------------------------------------------------------
1198 void appendFiltersForOpen( TSortedFilterList& _rFilterMatcher,
1199 const Reference< XFilterManager >& _rxFilterManager,
1200 ::rtl::OUString& _rFirstNonEmpty, FileDialogHelper_Impl& _rFileDlgImpl )
1202 DBG_ASSERT( _rxFilterManager.is(), "sfx2::appendFiltersForOpen: invalid manager!" );
1203 if ( !_rxFilterManager.is() )
1204 return;
1206 #ifdef DISABLE_GROUPING_AND_CLASSIFYING
1207 // ===============================================================
1208 // ensure that there's an entry "all" (with wildcard *.*)
1209 lcl_EnsureAllFilesEntry( _rFilterMatcher, _rxFilterManager, _rFirstNonEmpty );
1211 // ===============================================================
1212 appendFilters( _rFilterMatcher, _rxFilterManager, _rFirstNonEmpty );
1213 #else
1215 // ===============================================================
1216 // group and classify the filters
1217 GroupedFilterList aAllFilters;
1218 lcl_GroupAndClassify( _rFilterMatcher, aAllFilters );
1220 // ===============================================================
1221 // ensure that we have the one "all files" entry
1222 lcl_EnsureAllFilesEntry( _rFilterMatcher, aAllFilters );
1224 // ===============================================================
1225 // the first non-empty string - which we assume is the first overall entry
1226 if ( !aAllFilters.empty() )
1228 const FilterGroup& rFirstGroup = *aAllFilters.begin(); // should be the global classes
1229 if ( !rFirstGroup.empty() )
1230 _rFirstNonEmpty = rFirstGroup.begin()->First;
1231 // append first group, without extension
1232 AppendFilterGroup aGroup( _rxFilterManager, &_rFileDlgImpl );
1233 aGroup.appendGroup( rFirstGroup, false );
1236 // ===============================================================
1237 // append the filters to the manager
1238 if ( !aAllFilters.empty() )
1240 ::std::list< FilterGroup >::iterator pIter = aAllFilters.begin();
1241 ++pIter;
1242 ::std::for_each(
1243 pIter, // first filter group was handled seperately, see above
1244 aAllFilters.end(),
1245 AppendFilterGroup( _rxFilterManager, &_rFileDlgImpl ) );
1247 #endif
1250 ::rtl::OUString addExtension( const ::rtl::OUString& _rDisplayText,
1251 const ::rtl::OUString& _rExtension,
1252 sal_Bool _bForOpen, FileDialogHelper_Impl& _rFileDlgImpl )
1254 static ::rtl::OUString sAllFilter( RTL_CONSTASCII_USTRINGPARAM( "(*.*)" ) );
1255 static ::rtl::OUString sOpenBracket( RTL_CONSTASCII_USTRINGPARAM( " (" ) );
1256 static ::rtl::OUString sCloseBracket( RTL_CONSTASCII_USTRINGPARAM( ")" ) );
1257 ::rtl::OUString sRet = _rDisplayText;
1259 if ( sRet.indexOf( sAllFilter ) == -1 )
1261 String sExt = _rExtension;
1262 if ( !_bForOpen )
1263 // show '*' in extensions only when opening a document
1264 sExt.EraseAllChars( '*' );
1265 sRet += sOpenBracket;
1266 sRet += sExt;
1267 sRet += sCloseBracket;
1269 _rFileDlgImpl.addFilterPair( _rDisplayText, sRet );
1270 return sRet;
1273 //........................................................................
1274 } // namespace sfx2
1275 //........................................................................