Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include "filtergrouping.hxx"
21 : #include <sfx2/fcontnr.hxx>
22 : #include <sfx2/filedlghelper.hxx>
23 : #include <sfx2/sfx.hrc>
24 : #include <sfx2/docfac.hxx>
25 : #include "sfx2/sfxresid.hxx"
26 : #include <osl/thread.h>
27 : #include <rtl/strbuf.hxx>
28 : #include <com/sun/star/ui/dialogs/XFilterGroupManager.hpp>
29 : #include <com/sun/star/beans/StringPair.hpp>
30 : #include <com/sun/star/uno/Sequence.hxx>
31 : #include <unotools/confignode.hxx>
32 : #include <comphelper/processfactory.hxx>
33 : #include <comphelper/sequenceashashmap.hxx>
34 : #include <comphelper/string.hxx>
35 : #include <tools/diagnose_ex.h>
36 :
37 : #include <list>
38 : #include <vector>
39 : #include <map>
40 : #include <algorithm>
41 :
42 : //........................................................................
43 : namespace sfx2
44 : {
45 : //........................................................................
46 :
47 : using namespace ::com::sun::star::uno;
48 : using namespace ::com::sun::star::ui::dialogs;
49 : using namespace ::com::sun::star::lang;
50 : using namespace ::com::sun::star::beans;
51 : using namespace ::utl;
52 :
53 : //====================================================================
54 : /**
55 :
56 : Some general words about what's going on here ....
57 :
58 : <p>In our file open dialog, usually we display every filter we know. That's how it was before: every filter
59 : lead to an own line in the filter list box, e.g. "StarWriter 5.0 Dokument" or "Microsoft Word 97".</p>
60 :
61 : <p>But then the PM came. And everything changed ....</p>
62 :
63 : <p>A basic idea are groups: Why simply listing all the single filters? Couldn't we draw nice separators
64 : between the filters which logically belong together? I.e. all the filters which open a document in StarWriter:
65 : couldn't we separate them from all the filters which open the document in StarCalc?<br/>
66 : So spoke the PM, and engineering obeyed.</p>
67 :
68 : <p>So we have groups. They're just a visual aspect: All the filters of a group are presented together, separated
69 : by a line from other groups.</p>
70 :
71 : <p>Let's be honest: How the concrete implementation of the file picker service separates the different groups
72 : is a matter of this implementation. We only do this grouping and suggest it to the FilePicker service ...</p>
73 :
74 : <p>Now for the second concept:<br/>
75 : Thinking about it (and that's what the PM did), both "StarWriter 5.0 Dokument" and "Microsoft Word 97"
76 : describe a text document. It's a text. It's of no interest for the user that one of the texts was saved in
77 : MS' format, and one in our own format.<br/>
78 : So in a first step, we want to have a filter entry "Text documents". This would cover both above-mentioned
79 : filters, as well as any other filters for documents which are texts.</p>
80 :
81 : <p>Such an entry as "Text documents" is - within the scope of this file - called "class" or "filter class".</p>
82 :
83 : <p>In the file-open-dialog, such a class looks like an ordinary filter: it's simply a name in the filter
84 : listbox. Selecting means that all the files matching one of the "sub-filters" are displayed (in the example above,
85 : this would be "*.sdw", "*.doc" and so on).</p>
86 :
87 : <p>Now there are two types of filter classes: global ones and local ones. "Text documents" is a global class. As
88 : well as "Spreadsheets". Or "Web pages".<br/>
89 : Let's have a look at a local class: The filters "MS Word 95" and "MS WinWord 6.0" together form the class
90 : "Microsoft Word 6.0 / 95" (don't ask for the reasons. At least not me. Ask the PM). There are a lot of such
91 : local classes ...</p>
92 :
93 : <p>The difference between global and local classes is as follows: Global classes are presented in an own group.
94 : There is one dedicated group at the top of the list, containing all the global groups - no local groups and no
95 : single filters.</p>
96 :
97 : <p>Ehm - it was a lie. Not really at the top. Before this group, there is this single "All files" entry. It forms
98 : it's own group. But this is uninteresting here.</p>
99 :
100 : <p>Local classes must consist of filters which - without the classification - would all belong to the same group.
101 : Then, they're combined to one entry (in the example above: "Microsoft Word 6.0 / 95"), and this entry is inserted
102 : into the file picker filter list, instead of the single filters which form the class.</p>
103 :
104 : <p>This is an interesting difference between local and global classes: Filters which are part of a global class
105 : are listed in there own group, too. Filters in local classes aren't listed a second time - neither directly (as
106 : the filter itself) nor indirectly (as part of another local group).</p>
107 :
108 : <p>The only exception are filters which are part of a global class <em>and</em> a local class. This is allowed.
109 : Beeing cotained in two local classes isn't.</p>
110 :
111 : <p>So that's all what you need to know: Understand the concept of "filter classes" (a filter class combines
112 : different filters and acts as if it's a filter itself) and the concept of groups (a group just describes a
113 : logical correlation of filters and usually is represented to the user by drawing group separators in the filter
114 : list).</p>
115 :
116 : <p>If you got it, go try understanding this file :).</p>
117 :
118 : */
119 :
120 :
121 : //====================================================================
122 :
123 : typedef StringPair FilterDescriptor; // a single filter or a filter class (display name and filter mask)
124 : typedef ::std::list< FilterDescriptor > FilterGroup; // a list of single filter entries
125 : typedef ::std::list< FilterGroup > GroupedFilterList; // a list of all filters, already grouped
126 :
127 : /// the logical name of a filter
128 : typedef ::rtl::OUString FilterName;
129 :
130 : // a struct which holds references from a logical filter name to a filter group entry
131 : // used for quick lookup of classes (means class entries - entries representing a class)
132 : // which a given filter may belong to
133 : typedef ::std::map< ::rtl::OUString, FilterGroup::iterator > FilterGroupEntryReferrer;
134 :
135 : /// a descriptor for a filter class (which in the final dialog is represented by one filter entry)
136 0 : typedef struct _tagFilterClass
137 : {
138 : ::rtl::OUString sDisplayName; // the display name
139 : Sequence< FilterName > aSubFilters; // the (logical) names of the filter which belong to the class
140 : } FilterClass;
141 :
142 : typedef ::std::list< FilterClass > FilterClassList;
143 : typedef ::std::map< ::rtl::OUString, FilterClassList::iterator > FilterClassReferrer;
144 :
145 : typedef ::std::vector< ::rtl::OUString > StringArray;
146 :
147 : // =======================================================================
148 : // = reading of configuration data
149 : // =======================================================================
150 :
151 : //--------------------------------------------------------------------
152 0 : void lcl_ReadFilterClass( const OConfigurationNode& _rClassesNode, const ::rtl::OUString& _rLogicalClassName,
153 : FilterClass& /* [out] */ _rClass )
154 : {
155 0 : static const ::rtl::OUString sDisplaNameNodeName( "DisplayName" );
156 0 : static const ::rtl::OUString sSubFiltersNodeName( "Filters" );
157 :
158 : // the description node for the current class
159 0 : OConfigurationNode aClassDesc = _rClassesNode.openNode( _rLogicalClassName );
160 :
161 : // the values
162 0 : aClassDesc.getNodeValue( sDisplaNameNodeName ) >>= _rClass.sDisplayName;
163 0 : aClassDesc.getNodeValue( sSubFiltersNodeName ) >>= _rClass.aSubFilters;
164 0 : }
165 :
166 : //--------------------------------------------------------------------
167 : struct CreateEmptyClassRememberPos : public ::std::unary_function< FilterName, void >
168 : {
169 : protected:
170 : FilterClassList& m_rClassList;
171 : FilterClassReferrer& m_rClassesReferrer;
172 :
173 : public:
174 0 : CreateEmptyClassRememberPos( FilterClassList& _rClassList, FilterClassReferrer& _rClassesReferrer )
175 : :m_rClassList ( _rClassList )
176 0 : ,m_rClassesReferrer ( _rClassesReferrer )
177 : {
178 0 : }
179 :
180 : // operate on a single class name
181 0 : void operator() ( const FilterName& _rLogicalFilterName )
182 : {
183 : // insert a new (empty) class
184 0 : m_rClassList.push_back( FilterClass() );
185 : // get the position of this new entry
186 0 : FilterClassList::iterator aInsertPos = m_rClassList.end();
187 0 : --aInsertPos;
188 : // remember this position
189 0 : m_rClassesReferrer.insert( FilterClassReferrer::value_type( _rLogicalFilterName, aInsertPos ) );
190 0 : }
191 : };
192 :
193 : //--------------------------------------------------------------------
194 0 : struct ReadGlobalFilter : public ::std::unary_function< FilterName, void >
195 : {
196 : protected:
197 : OConfigurationNode m_aClassesNode;
198 : FilterClassReferrer& m_aClassReferrer;
199 :
200 : public:
201 0 : ReadGlobalFilter( const OConfigurationNode& _rClassesNode, FilterClassReferrer& _rClassesReferrer )
202 : :m_aClassesNode ( _rClassesNode )
203 0 : ,m_aClassReferrer ( _rClassesReferrer )
204 : {
205 0 : }
206 :
207 : // operate on a single logical name
208 0 : void operator() ( const FilterName& _rName )
209 : {
210 0 : FilterClassReferrer::iterator aClassRef = m_aClassReferrer.find( _rName );
211 0 : if ( m_aClassReferrer.end() == aClassRef )
212 : {
213 : // we do not know this global class
214 : OSL_FAIL( "ReadGlobalFilter::operator(): unknown filter name!" );
215 : // TODO: perhaps we should be more tolerant - at the moment, the filter is dropped
216 : // We could silently push_back it to the container ....
217 : }
218 : else
219 : {
220 : // read the data of this class into the node referred to by aClassRef
221 0 : lcl_ReadFilterClass( m_aClassesNode, _rName, *aClassRef->second );
222 : }
223 0 : }
224 : };
225 :
226 : //--------------------------------------------------------------------
227 0 : void lcl_ReadGlobalFilters( const OConfigurationNode& _rFilterClassification, FilterClassList& _rGlobalClasses, StringArray& _rGlobalClassNames )
228 : {
229 0 : _rGlobalClasses.clear();
230 0 : _rGlobalClassNames.clear();
231 :
232 : //================================================================
233 : // get the list describing the order of all global classes
234 0 : Sequence< ::rtl::OUString > aGlobalClasses;
235 0 : _rFilterClassification.getNodeValue( DEFINE_CONST_OUSTRING( "GlobalFilters/Order" ) ) >>= aGlobalClasses;
236 :
237 0 : const ::rtl::OUString* pNames = aGlobalClasses.getConstArray();
238 0 : const ::rtl::OUString* pNamesEnd = pNames + aGlobalClasses.getLength();
239 :
240 : // copy the logical names
241 0 : _rGlobalClassNames.resize( aGlobalClasses.getLength() );
242 0 : ::std::copy( pNames, pNamesEnd, _rGlobalClassNames.begin() );
243 :
244 : // Global classes are presented in an own group, so their order matters (while the order of the
245 : // "local classes" doesn't).
246 : // That's why we can't simply add the global classes to _rGlobalClasses using the order in which they
247 : // are returned from the configuration - it is completely undefined, and we need a _defined_ order.
248 0 : FilterClassReferrer aClassReferrer;
249 : ::std::for_each(
250 : pNames,
251 : pNamesEnd,
252 : CreateEmptyClassRememberPos( _rGlobalClasses, aClassReferrer )
253 0 : );
254 : // now _rGlobalClasses contains a dummy entry for each global class,
255 : // while aClassReferrer maps from the logical name of the class to the position within _rGlobalClasses where
256 : // it's dummy entry resides
257 :
258 : //================================================================
259 : // go for all the single class entries
260 : OConfigurationNode aFilterClassesNode =
261 0 : _rFilterClassification.openNode( DEFINE_CONST_OUSTRING( "GlobalFilters/Classes" ) );
262 0 : Sequence< ::rtl::OUString > aFilterClasses = aFilterClassesNode.getNodeNames();
263 : ::std::for_each(
264 : aFilterClasses.getConstArray(),
265 0 : aFilterClasses.getConstArray() + aFilterClasses.getLength(),
266 : ReadGlobalFilter( aFilterClassesNode, aClassReferrer )
267 0 : );
268 0 : }
269 :
270 : //--------------------------------------------------------------------
271 0 : struct ReadLocalFilter : public ::std::unary_function< FilterName, void >
272 : {
273 : protected:
274 : OConfigurationNode m_aClassesNode;
275 : FilterClassList& m_rClasses;
276 :
277 : public:
278 0 : ReadLocalFilter( const OConfigurationNode& _rClassesNode, FilterClassList& _rClasses )
279 : :m_aClassesNode ( _rClassesNode )
280 0 : ,m_rClasses ( _rClasses )
281 : {
282 0 : }
283 :
284 : // operate on a single logical name
285 0 : void operator() ( const FilterName& _rName )
286 : {
287 : // read the data for this class
288 0 : FilterClass aClass;
289 0 : lcl_ReadFilterClass( m_aClassesNode, _rName, aClass );
290 :
291 : // insert the class descriptor
292 0 : m_rClasses.push_back( aClass );
293 0 : }
294 : };
295 :
296 : //--------------------------------------------------------------------
297 0 : void lcl_ReadLocalFilters( const OConfigurationNode& _rFilterClassification, FilterClassList& _rLocalClasses )
298 : {
299 0 : _rLocalClasses.clear();
300 :
301 : // the node for the local classes
302 : OConfigurationNode aFilterClassesNode =
303 0 : _rFilterClassification.openNode( DEFINE_CONST_OUSTRING( "LocalFilters/Classes" ) );
304 0 : Sequence< ::rtl::OUString > aFilterClasses = aFilterClassesNode.getNodeNames();
305 :
306 : ::std::for_each(
307 : aFilterClasses.getConstArray(),
308 0 : aFilterClasses.getConstArray() + aFilterClasses.getLength(),
309 : ReadLocalFilter( aFilterClassesNode, _rLocalClasses )
310 0 : );
311 0 : }
312 :
313 : //--------------------------------------------------------------------
314 0 : void lcl_ReadClassification( FilterClassList& _rGlobalClasses, StringArray& _rGlobalClassNames, FilterClassList& _rLocalClasses )
315 : {
316 : //================================================================
317 : // open our config node
318 : OConfigurationTreeRoot aFilterClassification = OConfigurationTreeRoot::createWithServiceFactory(
319 : ::comphelper::getProcessServiceFactory(),
320 : DEFINE_CONST_OUSTRING( "org.openoffice.Office.UI/FilterClassification" ),
321 : -1,
322 : OConfigurationTreeRoot::CM_READONLY
323 0 : );
324 :
325 : //================================================================
326 : // go for the global classes
327 0 : lcl_ReadGlobalFilters( aFilterClassification, _rGlobalClasses, _rGlobalClassNames );
328 :
329 : //================================================================
330 : // fo for the local classes
331 0 : lcl_ReadLocalFilters( aFilterClassification, _rLocalClasses );
332 :
333 0 : }
334 :
335 : // =======================================================================
336 : // = grouping and classifying
337 : // =======================================================================
338 :
339 : //--------------------------------------------------------------------
340 : // a struct which adds helps remembering a reference to a class entry
341 : struct ReferToFilterEntry : public ::std::unary_function< FilterName, void >
342 : {
343 : protected:
344 : FilterGroupEntryReferrer& m_rEntryReferrer;
345 : FilterGroup::iterator m_aClassPos;
346 :
347 : public:
348 0 : ReferToFilterEntry( FilterGroupEntryReferrer& _rEntryReferrer, const FilterGroup::iterator& _rClassPos )
349 : :m_rEntryReferrer( _rEntryReferrer )
350 0 : ,m_aClassPos( _rClassPos )
351 : {
352 0 : }
353 :
354 : // operate on a single filter name
355 0 : void operator() ( const FilterName& _rName )
356 : {
357 : ::std::pair< FilterGroupEntryReferrer::iterator, bool > aInsertRes =
358 0 : m_rEntryReferrer.insert( FilterGroupEntryReferrer::value_type( _rName, m_aClassPos ) );
359 : SAL_WARN_IF(
360 : !aInsertRes.second, "sfx2.dialog",
361 : "already have an element for " << _rName);
362 0 : }
363 : };
364 :
365 : //--------------------------------------------------------------------
366 : struct FillClassGroup : public ::std::unary_function< FilterClass, void >
367 : {
368 : protected:
369 : FilterGroup& m_rClassGroup;
370 : FilterGroupEntryReferrer& m_rClassReferrer;
371 :
372 : public:
373 0 : FillClassGroup( FilterGroup& _rClassGroup, FilterGroupEntryReferrer& _rClassReferrer )
374 : :m_rClassGroup ( _rClassGroup )
375 0 : ,m_rClassReferrer ( _rClassReferrer )
376 : {
377 0 : }
378 :
379 : // operate on a single class
380 0 : void operator() ( const FilterClass& _rClass )
381 : {
382 : // create an empty filter descriptor for the class
383 0 : FilterDescriptor aClassEntry;
384 : // set it's name (which is all we know by now)
385 0 : aClassEntry.First = _rClass.sDisplayName;
386 :
387 : // add it to the group
388 0 : m_rClassGroup.push_back( aClassEntry );
389 : // the position of the newly added class
390 0 : FilterGroup::iterator aClassEntryPos = m_rClassGroup.end();
391 0 : --aClassEntryPos;
392 :
393 : // and for all the sub filters of the class, remember the class
394 : // (respectively the position of the class it the group)
395 : ::std::for_each(
396 : _rClass.aSubFilters.getConstArray(),
397 0 : _rClass.aSubFilters.getConstArray() + _rClass.aSubFilters.getLength(),
398 : ReferToFilterEntry( m_rClassReferrer, aClassEntryPos )
399 0 : );
400 0 : }
401 : };
402 :
403 : //--------------------------------------------------------------------
404 : static const sal_Unicode s_cWildcardSeparator( ';' );
405 :
406 : //====================================================================
407 0 : const ::rtl::OUString& getSeparatorString()
408 : {
409 0 : static ::rtl::OUString s_sSeparatorString( &s_cWildcardSeparator, 1 );
410 0 : return s_sSeparatorString;
411 : }
412 :
413 : //====================================================================
414 : struct CheckAppendSingleWildcard : public ::std::unary_function< ::rtl::OUString, void >
415 : {
416 : ::rtl::OUString& _rToBeExtended;
417 :
418 0 : CheckAppendSingleWildcard( ::rtl::OUString& _rBase ) : _rToBeExtended( _rBase ) { }
419 :
420 0 : void operator() ( const ::rtl::OUString& _rWC )
421 : {
422 : // check for double wildcards
423 0 : sal_Int32 nExistentPos = _rToBeExtended.indexOf( _rWC );
424 0 : if ( -1 < nExistentPos )
425 : { // found this wildcard (already part of _rToBeExtended)
426 0 : const sal_Unicode* pBuffer = _rToBeExtended.getStr();
427 0 : if ( ( 0 == nExistentPos )
428 0 : || ( s_cWildcardSeparator == pBuffer[ nExistentPos - 1 ] )
429 : )
430 : { // the wildcard really starts at this position (it starts at pos 0 or the previous character is a separator
431 0 : sal_Int32 nExistentWCEnd = nExistentPos + _rWC.getLength();
432 0 : if ( ( _rToBeExtended.getLength() == nExistentWCEnd )
433 0 : || ( s_cWildcardSeparator == pBuffer[ nExistentWCEnd ] )
434 : )
435 : { // it's really the complete wildcard we found
436 : // (not something like _rWC beeing "*.t" and _rToBeExtended containing "*.txt")
437 : // -> outta here
438 0 : return;
439 : }
440 : }
441 : }
442 :
443 0 : if ( !_rToBeExtended.isEmpty() )
444 0 : _rToBeExtended += getSeparatorString();
445 0 : _rToBeExtended += _rWC;
446 : }
447 : };
448 :
449 : //====================================================================
450 : // a helper struct which adds a fixed (Sfx-)filter to a filter group entry given by iterator
451 0 : struct AppendWildcardToDescriptor : public ::std::unary_function< FilterGroupEntryReferrer::value_type, void >
452 : {
453 : protected:
454 : ::std::vector< ::rtl::OUString > aWildCards;
455 :
456 : public:
457 : AppendWildcardToDescriptor( const String& _rWildCard );
458 :
459 : // operate on a single class entry
460 0 : void operator() ( const FilterGroupEntryReferrer::value_type& _rClassReference )
461 : {
462 : // simply add our wildcards
463 : ::std::for_each(
464 : aWildCards.begin(),
465 : aWildCards.end(),
466 0 : CheckAppendSingleWildcard( _rClassReference.second->Second )
467 0 : );
468 0 : }
469 : };
470 :
471 : //====================================================================
472 0 : AppendWildcardToDescriptor::AppendWildcardToDescriptor( const String& _rWildCard )
473 : {
474 : DBG_ASSERT( _rWildCard.Len(),
475 : "AppendWildcardToDescriptor::AppendWildcardToDescriptor: invalid wildcard!" );
476 : DBG_ASSERT( _rWildCard.GetBuffer()[0] != s_cWildcardSeparator,
477 : "AppendWildcardToDescriptor::AppendWildcardToDescriptor: wildcard already separated!" );
478 :
479 0 : aWildCards.reserve( comphelper::string::getTokenCount(_rWildCard, s_cWildcardSeparator) );
480 :
481 0 : const sal_Unicode* pTokenLoop = _rWildCard.GetBuffer();
482 0 : const sal_Unicode* pTokenLoopEnd = pTokenLoop + _rWildCard.Len();
483 0 : const sal_Unicode* pTokenStart = pTokenLoop;
484 0 : for ( ; pTokenLoop != pTokenLoopEnd; ++pTokenLoop )
485 : {
486 0 : if ( ( s_cWildcardSeparator == *pTokenLoop ) && ( pTokenLoop > pTokenStart ) )
487 : { // found a new token separator (and a non-empty token)
488 0 : aWildCards.push_back( ::rtl::OUString( pTokenStart, pTokenLoop - pTokenStart ) );
489 :
490 : // search the start of the next token
491 0 : while ( ( pTokenStart != pTokenLoopEnd ) && ( *pTokenStart != s_cWildcardSeparator ) )
492 0 : ++pTokenStart;
493 :
494 0 : if ( pTokenStart == pTokenLoopEnd )
495 : // reached the end
496 0 : break;
497 :
498 0 : ++pTokenStart;
499 0 : pTokenLoop = pTokenStart;
500 : }
501 : }
502 0 : if ( pTokenLoop > pTokenStart )
503 : // the last one ....
504 0 : aWildCards.push_back( ::rtl::OUString( pTokenStart, pTokenLoop - pTokenStart ) );
505 0 : }
506 :
507 : //--------------------------------------------------------------------
508 0 : void lcl_InitGlobalClasses( GroupedFilterList& _rAllFilters, const FilterClassList& _rGlobalClasses, FilterGroupEntryReferrer& _rGlobalClassesRef )
509 : {
510 : // we need an extra group in our "all filters" container
511 0 : _rAllFilters.push_front( FilterGroup() );
512 0 : FilterGroup& rGlobalFilters = _rAllFilters.front();
513 : // it's important to work on the reference: we want to access the members of this filter group
514 : // by an iterator (FilterGroup::const_iterator)
515 : // the referrer for the global classes
516 :
517 : // initialize the group
518 : ::std::for_each(
519 : _rGlobalClasses.begin(),
520 : _rGlobalClasses.end(),
521 : FillClassGroup( rGlobalFilters, _rGlobalClassesRef )
522 0 : );
523 : // now we have:
524 : // in rGlobalFilters: a list of FilterDescriptor's, where each's discriptor's display name is set to the name of a class
525 : // in aGlobalClassesRef: a mapping from logical filter names to positions within rGlobalFilters
526 : // this way, if we encounter an arbitrary filter, we can easily (and efficient) check if it belongs to a global class
527 : // and modify the descriptor for this class accordingly
528 0 : }
529 :
530 : //--------------------------------------------------------------------
531 : typedef ::std::vector< ::std::pair< FilterGroupEntryReferrer::mapped_type, FilterGroup::iterator > >
532 : MapGroupEntry2GroupEntry;
533 : // this is not really a map - it's just called this way because it is used as a map
534 :
535 : struct FindGroupEntry : public ::std::unary_function< MapGroupEntry2GroupEntry::value_type, sal_Bool >
536 : {
537 : FilterGroupEntryReferrer::mapped_type aLookingFor;
538 0 : FindGroupEntry( FilterGroupEntryReferrer::mapped_type _rLookingFor ) : aLookingFor( _rLookingFor ) { }
539 :
540 0 : sal_Bool operator() ( const MapGroupEntry2GroupEntry::value_type& _rMapEntry )
541 : {
542 0 : return _rMapEntry.first == aLookingFor ? sal_True : sal_False;
543 : }
544 : };
545 :
546 : struct CopyGroupEntryContent : public ::std::unary_function< MapGroupEntry2GroupEntry::value_type, void >
547 : {
548 0 : void operator() ( const MapGroupEntry2GroupEntry::value_type& _rMapEntry )
549 : {
550 : #ifdef DBG_UTIL
551 : FilterDescriptor aHaveALook = *_rMapEntry.first;
552 : #endif
553 0 : *_rMapEntry.second = *_rMapEntry.first;
554 0 : }
555 : };
556 :
557 : //--------------------------------------------------------------------
558 : struct CopyNonEmptyFilter : public ::std::unary_function< FilterDescriptor, void >
559 : {
560 : FilterGroup& rTarget;
561 0 : CopyNonEmptyFilter( FilterGroup& _rTarget ) :rTarget( _rTarget ) { }
562 :
563 0 : void operator() ( const FilterDescriptor& _rFilter )
564 : {
565 0 : if ( !_rFilter.Second.isEmpty() )
566 0 : rTarget.push_back( _rFilter );
567 0 : }
568 : };
569 :
570 : //--------------------------------------------------------------------
571 0 : void lcl_GroupAndClassify( TSortedFilterList& _rFilterMatcher, GroupedFilterList& _rAllFilters )
572 : {
573 0 : _rAllFilters.clear();
574 :
575 : // ===============================================================
576 : // read the classification of filters
577 0 : FilterClassList aGlobalClasses, aLocalClasses;
578 0 : StringArray aGlobalClassNames;
579 0 : lcl_ReadClassification( aGlobalClasses, aGlobalClassNames, aLocalClasses );
580 :
581 : // ===============================================================
582 : // for the global filter classes
583 0 : FilterGroupEntryReferrer aGlobalClassesRef;
584 0 : lcl_InitGlobalClasses( _rAllFilters, aGlobalClasses, aGlobalClassesRef );
585 :
586 : // insert as much placeholders (FilterGroup's) into _rAllFilter for groups as we have global classes
587 : // (this assumes that both numbers are the same, which, speaking strictly, must not hold - but it does, as we know ...)
588 0 : sal_Int32 nGlobalClasses = aGlobalClasses.size();
589 0 : while ( nGlobalClasses-- )
590 0 : _rAllFilters.push_back( FilterGroup() );
591 :
592 : // ===============================================================
593 : // for the local classes:
594 : // if n filters belong to a local class, they do not appear in their respective group explicitly, instead
595 : // and entry for the class is added to the group and the extensions of the filters are collected under
596 : // this entry
597 0 : FilterGroupEntryReferrer aLocalClassesRef;
598 0 : FilterGroup aCollectedLocals;
599 : ::std::for_each(
600 : aLocalClasses.begin(),
601 : aLocalClasses.end(),
602 : FillClassGroup( aCollectedLocals, aLocalClassesRef )
603 0 : );
604 : // to map from the position within aCollectedLocals to positions within the real groups
605 : // (where they finally belong to)
606 0 : MapGroupEntry2GroupEntry aLocalFinalPositions;
607 :
608 : // ===============================================================
609 : // now add the filters
610 : // the group which we currently work with
611 0 : GroupedFilterList::iterator aCurrentGroup = _rAllFilters.end(); // no current group
612 : // the filter container of the current group - if this changes between two filters, a new group is reached
613 0 : String aCurrentServiceName;
614 :
615 0 : String sFilterWildcard;
616 0 : ::rtl::OUString sFilterName;
617 : // loop through all the filters
618 0 : for ( const SfxFilter* pFilter = _rFilterMatcher.First(); pFilter; pFilter = _rFilterMatcher.Next() )
619 : {
620 0 : sFilterName = pFilter->GetFilterName();
621 0 : sFilterWildcard = pFilter->GetWildcard().getGlob();
622 0 : AppendWildcardToDescriptor aExtendWildcard( sFilterWildcard );
623 :
624 : DBG_ASSERT( sFilterWildcard.Len(), "sfx2::lcl_GroupAndClassify: invalid wildcard of this filter!" );
625 :
626 : // ===========================================================
627 : // check for a change in the group
628 0 : String aServiceName = pFilter->GetServiceName();
629 0 : if ( aServiceName != aCurrentServiceName )
630 : { // we reached a new group
631 :
632 0 : ::rtl::OUString sDocServName = aServiceName;
633 :
634 : // look for the place in _rAllFilters where this ne group belongs - this is determined
635 : // by the order of classes in aGlobalClassNames
636 0 : GroupedFilterList::iterator aGroupPos = _rAllFilters.begin();
637 : DBG_ASSERT( aGroupPos != _rAllFilters.end(),
638 : "sfx2::lcl_GroupAndClassify: invalid all-filters array here!" );
639 : // the loop below will work on invalid objects else ...
640 0 : ++aGroupPos;
641 0 : StringArray::iterator aGlobalIter = aGlobalClassNames.begin();
642 0 : while ( ( aGroupPos != _rAllFilters.end() )
643 0 : && ( aGlobalIter != aGlobalClassNames.end() )
644 0 : && ( *aGlobalIter != sDocServName )
645 : )
646 : {
647 0 : ++aGlobalIter;
648 0 : ++aGroupPos;
649 : }
650 0 : if ( aGroupPos != _rAllFilters.end() )
651 : // we found a global class name which matchies the doc service name -> fill the filters of this
652 : // group in the respective prepared group
653 0 : aCurrentGroup = aGroupPos;
654 : else
655 : // insert a new entry in our overall-list
656 0 : aCurrentGroup = _rAllFilters.insert( _rAllFilters.end(), FilterGroup() );
657 :
658 : // remember the container to properly detect the next group
659 0 : aCurrentServiceName = aServiceName;
660 : }
661 :
662 : DBG_ASSERT( aCurrentGroup != _rAllFilters.end(), "sfx2::lcl_GroupAndClassify: invalid current group!" );
663 :
664 : // ===========================================================
665 : // check if the filter is part of a global group
666 : ::std::pair< FilterGroupEntryReferrer::iterator, FilterGroupEntryReferrer::iterator >
667 0 : aBelongsTo = aGlobalClassesRef.equal_range( sFilterName );
668 : // add the filter to the entries for these classes
669 : // (if they exist - if not, the range is empty and the for_each is a no-op)
670 : ::std::for_each(
671 : aBelongsTo.first,
672 : aBelongsTo.second,
673 : aExtendWildcard
674 0 : );
675 :
676 : // ===========================================================
677 : // add the filter to it's group
678 :
679 : // for this, check if the filter is part of a local filter
680 0 : FilterGroupEntryReferrer::iterator aBelongsToLocal = aLocalClassesRef.find( sFilterName );
681 0 : if ( aLocalClassesRef.end() != aBelongsToLocal )
682 : {
683 : // okay, there is a local class which the filter belongs to
684 : // -> append the wildcard
685 0 : aExtendWildcard( *aBelongsToLocal );
686 :
687 : MapGroupEntry2GroupEntry::iterator aThisGroupFinalPos =
688 0 : ::std::find_if( aLocalFinalPositions.begin(), aLocalFinalPositions.end(), FindGroupEntry( aBelongsToLocal->second ) );
689 :
690 0 : if ( aLocalFinalPositions.end() == aThisGroupFinalPos )
691 : { // the position within aCollectedLocals has not been mapped to a final position
692 : // within the "real" group (aCollectedLocals is only temporary)
693 : // -> do this now (as we just encountered the first filter belonging to this local class
694 : // add a new entry which is the "real" group entry
695 0 : aCurrentGroup->push_back( FilterDescriptor( aBelongsToLocal->second->First, String() ) );
696 : // the position where we inserted the entry
697 0 : FilterGroup::iterator aInsertPos = aCurrentGroup->end();
698 0 : --aInsertPos;
699 : // remember this pos
700 0 : aLocalFinalPositions.push_back( MapGroupEntry2GroupEntry::value_type( aBelongsToLocal->second, aInsertPos ) );
701 : }
702 : }
703 : else
704 0 : aCurrentGroup->push_back( FilterDescriptor( pFilter->GetUIName(), sFilterWildcard ) );
705 0 : }
706 :
707 : // now just complete the infos for the local groups:
708 : // During the above loop, they have been collected in aCollectedLocals, but this is only temporary
709 : // They have to be copied into their final positions (which are stored in aLocalFinalPositions)
710 : ::std::for_each(
711 : aLocalFinalPositions.begin(),
712 : aLocalFinalPositions.end(),
713 : CopyGroupEntryContent()
714 0 : );
715 :
716 : // and remove local groups which do not apply - e.g. have no entries due to the limited content of the
717 : // current SfxFilterMatcherIter
718 :
719 0 : FilterGroup& rGlobalFilters = _rAllFilters.front();
720 0 : FilterGroup aNonEmptyGlobalFilters;
721 : ::std::for_each(
722 : rGlobalFilters.begin(),
723 : rGlobalFilters.end(),
724 : CopyNonEmptyFilter( aNonEmptyGlobalFilters )
725 0 : );
726 0 : rGlobalFilters.swap( aNonEmptyGlobalFilters );
727 0 : }
728 :
729 : //--------------------------------------------------------------------
730 0 : struct AppendFilter : public ::std::unary_function< FilterDescriptor, void >
731 : {
732 : protected:
733 : Reference< XFilterManager > m_xFilterManager;
734 : FileDialogHelper_Impl* m_pFileDlgImpl;
735 : bool m_bAddExtension;
736 :
737 : public:
738 0 : AppendFilter( const Reference< XFilterManager >& _rxFilterManager,
739 : FileDialogHelper_Impl* _pImpl, bool _bAddExtension ) :
740 :
741 : m_xFilterManager( _rxFilterManager ),
742 : m_pFileDlgImpl ( _pImpl ),
743 0 : m_bAddExtension ( _bAddExtension )
744 :
745 : {
746 : DBG_ASSERT( m_xFilterManager.is(), "AppendFilter::AppendFilter: invalid filter manager!" );
747 : DBG_ASSERT( m_pFileDlgImpl, "AppendFilter::AppendFilter: invalid filedlg impl!" );
748 0 : }
749 :
750 : // operate on a single filter
751 0 : void operator() ( const FilterDescriptor& _rFilterEntry )
752 : {
753 : String sDisplayText = m_bAddExtension
754 : ? addExtension( _rFilterEntry.First, _rFilterEntry.Second, sal_True, *m_pFileDlgImpl )
755 0 : : _rFilterEntry.First;
756 0 : m_xFilterManager->appendFilter( sDisplayText, _rFilterEntry.Second );
757 0 : }
758 : };
759 :
760 : // =======================================================================
761 : // = handling for the "all files" entry
762 : // =======================================================================
763 :
764 : //--------------------------------------------------------------------
765 0 : sal_Bool lcl_hasAllFilesFilter( TSortedFilterList& _rFilterMatcher, String& /* [out] */ _rAllFilterName )
766 : {
767 0 : ::rtl::OUString sUIName;
768 0 : sal_Bool bHasAll = sal_False;
769 0 : _rAllFilterName = SfxResId( STR_SFX_FILTERNAME_ALL ).toString();
770 :
771 : // ===============================================================
772 : // check if there's already a filter <ALL>
773 0 : for ( const SfxFilter* pFilter = _rFilterMatcher.First(); pFilter && !bHasAll; pFilter = _rFilterMatcher.Next() )
774 : {
775 0 : if ( pFilter->GetUIName() == _rAllFilterName )
776 0 : bHasAll = sal_True;
777 : }
778 0 : return bHasAll;
779 : }
780 :
781 : //--------------------------------------------------------------------
782 0 : void lcl_EnsureAllFilesEntry( TSortedFilterList& _rFilterMatcher, GroupedFilterList& _rFilters )
783 : {
784 : // ===============================================================
785 0 : String sAllFilterName;
786 0 : if ( !lcl_hasAllFilesFilter( _rFilterMatcher, sAllFilterName ) )
787 : {
788 : // get the first group of filters (by definition, this group contains the global classes)
789 : DBG_ASSERT( !_rFilters.empty(), "lcl_EnsureAllFilesEntry: invalid filter list!" );
790 0 : if ( !_rFilters.empty() )
791 : {
792 0 : FilterGroup& rGlobalClasses = *_rFilters.begin();
793 0 : rGlobalClasses.push_front( FilterDescriptor( sAllFilterName, DEFINE_CONST_UNICODE( FILEDIALOG_FILTER_ALL ) ) );
794 : }
795 0 : }
796 0 : }
797 :
798 : // =======================================================================
799 : // = filling an XFilterManager
800 : // =======================================================================
801 :
802 : //--------------------------------------------------------------------
803 0 : struct AppendFilterGroup : public ::std::unary_function< FilterGroup, void >
804 : {
805 : protected:
806 : Reference< XFilterManager > m_xFilterManager;
807 : Reference< XFilterGroupManager > m_xFilterGroupManager;
808 : FileDialogHelper_Impl* m_pFileDlgImpl;
809 :
810 : public:
811 0 : AppendFilterGroup( const Reference< XFilterManager >& _rxFilterManager, FileDialogHelper_Impl* _pImpl )
812 : :m_xFilterManager ( _rxFilterManager )
813 : ,m_xFilterGroupManager ( _rxFilterManager, UNO_QUERY )
814 0 : ,m_pFileDlgImpl ( _pImpl )
815 : {
816 : DBG_ASSERT( m_xFilterManager.is(), "AppendFilterGroup::AppendFilterGroup: invalid filter manager!" );
817 : DBG_ASSERT( m_pFileDlgImpl, "AppendFilterGroup::AppendFilterGroup: invalid filedlg impl!" );
818 0 : }
819 :
820 0 : void appendGroup( const FilterGroup& _rGroup, bool _bAddExtension )
821 : {
822 : try
823 : {
824 0 : if ( m_xFilterGroupManager.is() )
825 : { // the file dialog implementation supports visual grouping of filters
826 : // create a representation of the group which is understandable by the XFilterGroupManager
827 0 : if ( _rGroup.size() )
828 : {
829 0 : Sequence< StringPair > aFilters( _rGroup.size() );
830 : ::std::copy(
831 : _rGroup.begin(),
832 : _rGroup.end(),
833 : aFilters.getArray()
834 0 : );
835 0 : if ( _bAddExtension )
836 : {
837 0 : StringPair* pFilters = aFilters.getArray();
838 0 : StringPair* pEnd = pFilters + aFilters.getLength();
839 0 : for ( ; pFilters != pEnd; ++pFilters )
840 0 : pFilters->First = addExtension( pFilters->First, pFilters->Second, sal_True, *m_pFileDlgImpl );
841 : }
842 0 : m_xFilterGroupManager->appendFilterGroup( ::rtl::OUString(), aFilters );
843 : }
844 : }
845 : else
846 : {
847 : ::std::for_each(
848 : _rGroup.begin(),
849 : _rGroup.end(),
850 0 : AppendFilter( m_xFilterManager, m_pFileDlgImpl, _bAddExtension ) );
851 : }
852 : }
853 0 : catch( const Exception& )
854 : {
855 : DBG_UNHANDLED_EXCEPTION();
856 : }
857 0 : }
858 :
859 : // operate on a single filter group
860 0 : void operator() ( const FilterGroup& _rGroup )
861 : {
862 0 : appendGroup( _rGroup, true );
863 0 : }
864 : };
865 :
866 : //--------------------------------------------------------------------
867 0 : TSortedFilterList::TSortedFilterList(const ::com::sun::star::uno::Reference< ::com::sun::star::container::XEnumeration >& xFilterList)
868 0 : : m_nIterator(0)
869 : {
870 0 : if (!xFilterList.is())
871 0 : return;
872 :
873 0 : m_lFilters.clear();
874 0 : while(xFilterList->hasMoreElements())
875 : {
876 0 : ::comphelper::SequenceAsHashMap lFilterProps (xFilterList->nextElement());
877 : ::rtl::OUString sFilterName = lFilterProps.getUnpackedValueOrDefault(
878 : ::rtl::OUString("Name"),
879 0 : ::rtl::OUString());
880 0 : if (!sFilterName.isEmpty())
881 0 : m_lFilters.push_back(sFilterName);
882 0 : }
883 : }
884 :
885 : //--------------------------------------------------------------------
886 0 : const SfxFilter* TSortedFilterList::First()
887 : {
888 0 : m_nIterator = 0;
889 0 : return impl_getFilter(m_nIterator);
890 : }
891 :
892 : //--------------------------------------------------------------------
893 0 : const SfxFilter* TSortedFilterList::Next()
894 : {
895 0 : ++m_nIterator;
896 0 : return impl_getFilter(m_nIterator);
897 : }
898 :
899 : //--------------------------------------------------------------------
900 0 : const SfxFilter* TSortedFilterList::impl_getFilter(sal_Int32 nIndex)
901 : {
902 0 : if (nIndex<0 || nIndex>=(sal_Int32)m_lFilters.size())
903 0 : return 0;
904 0 : const ::rtl::OUString& sFilterName = m_lFilters[nIndex];
905 0 : if (sFilterName.isEmpty())
906 0 : return 0;
907 0 : return SfxFilter::GetFilterByName(String(sFilterName));
908 : }
909 :
910 : //--------------------------------------------------------------------
911 0 : void appendFiltersForSave( TSortedFilterList& _rFilterMatcher,
912 : const Reference< XFilterManager >& _rxFilterManager,
913 : ::rtl::OUString& _rFirstNonEmpty, FileDialogHelper_Impl& _rFileDlgImpl,
914 : const ::rtl::OUString& _rFactory )
915 : {
916 : DBG_ASSERT( _rxFilterManager.is(), "sfx2::appendFiltersForSave: invalid manager!" );
917 0 : if ( !_rxFilterManager.is() )
918 0 : return;
919 :
920 0 : ::rtl::OUString sUIName;
921 0 : ::rtl::OUString sExtension;
922 :
923 : // retrieve the default filter for this application module.
924 : // It must be set as first of the generated filter list.
925 0 : const SfxFilter* pDefaultFilter = SfxFilterContainer::GetDefaultFilter_Impl(_rFactory);
926 : // Only use one extension (#i32434#)
927 : // (and always the first if there are more than one)
928 : using comphelper::string::getToken;
929 0 : sExtension = getToken(pDefaultFilter->GetWildcard().getGlob(), 0, ';');
930 0 : sUIName = addExtension( pDefaultFilter->GetUIName(), sExtension, sal_False, _rFileDlgImpl );
931 : try
932 : {
933 0 : _rxFilterManager->appendFilter( sUIName, sExtension );
934 0 : if ( _rFirstNonEmpty.isEmpty() )
935 0 : _rFirstNonEmpty = sUIName;
936 : }
937 0 : catch( const IllegalArgumentException& )
938 : {
939 : SAL_WARN( "sfx2.dialog", "Could not append DefaultFilter" << sUIName );
940 : }
941 :
942 0 : for ( const SfxFilter* pFilter = _rFilterMatcher.First(); pFilter; pFilter = _rFilterMatcher.Next() )
943 : {
944 0 : if (pFilter->GetName() == pDefaultFilter->GetName())
945 0 : continue;
946 :
947 : // Only use one extension (#i32434#)
948 : // (and always the first if there are more than one)
949 0 : sExtension = getToken(pFilter->GetWildcard().getGlob(), 0, ';');
950 0 : sUIName = addExtension( pFilter->GetUIName(), sExtension, sal_False, _rFileDlgImpl );
951 : try
952 : {
953 0 : _rxFilterManager->appendFilter( sUIName, sExtension );
954 0 : if ( _rFirstNonEmpty.isEmpty() )
955 0 : _rFirstNonEmpty = sUIName;
956 : }
957 0 : catch( const IllegalArgumentException& )
958 : {
959 : SAL_WARN( "sfx2.dialog", "Could not append Filter" << sUIName );
960 : }
961 0 : }
962 : }
963 :
964 0 : struct ExportFilter
965 : {
966 0 : ExportFilter( const rtl::OUString& _aUIName, const rtl::OUString& _aWildcard ) :
967 0 : aUIName( _aUIName ), aWildcard( _aWildcard ) {}
968 :
969 : rtl::OUString aUIName;
970 : rtl::OUString aWildcard;
971 : };
972 :
973 : //--------------------------------------------------------------------
974 0 : void appendExportFilters( TSortedFilterList& _rFilterMatcher,
975 : const Reference< XFilterManager >& _rxFilterManager,
976 : ::rtl::OUString& _rFirstNonEmpty, FileDialogHelper_Impl& _rFileDlgImpl )
977 : {
978 : DBG_ASSERT( _rxFilterManager.is(), "sfx2::appendExportFilters: invalid manager!" );
979 0 : if ( !_rxFilterManager.is() )
980 0 : return;
981 :
982 0 : sal_Int32 nHTMLIndex = -1;
983 0 : sal_Int32 nXHTMLIndex = -1;
984 0 : sal_Int32 nPDFIndex = -1;
985 0 : sal_Int32 nFlashIndex = -1;
986 0 : ::rtl::OUString sUIName;
987 0 : ::rtl::OUString sExtensions;
988 0 : std::vector< ExportFilter > aImportantFilterGroup;
989 0 : std::vector< ExportFilter > aFilterGroup;
990 0 : Reference< XFilterGroupManager > xFilterGroupManager( _rxFilterManager, UNO_QUERY );
991 0 : ::rtl::OUString sTypeName;
992 0 : const ::rtl::OUString sWriterHTMLType( DEFINE_CONST_OUSTRING("generic_HTML") );
993 0 : const ::rtl::OUString sGraphicHTMLType( DEFINE_CONST_OUSTRING("graphic_HTML") );
994 0 : const ::rtl::OUString sXHTMLType( DEFINE_CONST_OUSTRING("XHTML_File") );
995 0 : const ::rtl::OUString sPDFType( DEFINE_CONST_OUSTRING("pdf_Portable_Document_Format") );
996 0 : const ::rtl::OUString sFlashType( DEFINE_CONST_OUSTRING("graphic_SWF") );
997 :
998 0 : for ( const SfxFilter* pFilter = _rFilterMatcher.First(); pFilter; pFilter = _rFilterMatcher.Next() )
999 : {
1000 0 : sTypeName = pFilter->GetTypeName();
1001 0 : sUIName = pFilter->GetUIName();
1002 0 : sExtensions = pFilter->GetWildcard().getGlob();
1003 0 : ExportFilter aExportFilter( sUIName, sExtensions );
1004 0 : String aExt = sExtensions;
1005 :
1006 0 : if ( nHTMLIndex == -1 &&
1007 0 : ( sTypeName.equals( sWriterHTMLType ) || sTypeName.equals( sGraphicHTMLType ) ) )
1008 : {
1009 0 : aImportantFilterGroup.insert( aImportantFilterGroup.begin(), aExportFilter );
1010 0 : nHTMLIndex = 0;
1011 : }
1012 0 : else if ( nXHTMLIndex == -1 && sTypeName.equals( sXHTMLType ) )
1013 : {
1014 0 : std::vector< ExportFilter >::iterator aIter = aImportantFilterGroup.begin();
1015 0 : if ( nHTMLIndex == -1 )
1016 0 : aImportantFilterGroup.insert( aIter, aExportFilter );
1017 : else
1018 0 : aImportantFilterGroup.insert( ++aIter, aExportFilter );
1019 0 : nXHTMLIndex = 0;
1020 : }
1021 0 : else if ( nPDFIndex == -1 && sTypeName.equals( sPDFType ) )
1022 : {
1023 0 : std::vector< ExportFilter >::iterator aIter = aImportantFilterGroup.begin();
1024 0 : if ( nHTMLIndex != -1 )
1025 0 : ++aIter;
1026 0 : if ( nXHTMLIndex != -1 )
1027 0 : ++aIter;
1028 0 : aImportantFilterGroup.insert( aIter, aExportFilter );
1029 0 : nPDFIndex = 0;
1030 : }
1031 0 : else if ( nFlashIndex == -1 && sTypeName.equals( sFlashType ) )
1032 : {
1033 0 : std::vector< ExportFilter >::iterator aIter = aImportantFilterGroup.begin();
1034 0 : if ( nHTMLIndex != -1 )
1035 0 : ++aIter;
1036 0 : if ( nXHTMLIndex != -1 )
1037 0 : ++aIter;
1038 0 : if ( nPDFIndex != -1 )
1039 0 : ++aIter;
1040 0 : aImportantFilterGroup.insert( aIter, aExportFilter );
1041 0 : nFlashIndex = 0;
1042 : }
1043 : else
1044 0 : aFilterGroup.push_back( aExportFilter );
1045 0 : }
1046 :
1047 0 : if ( xFilterGroupManager.is() )
1048 : {
1049 : // Add both html/pdf filter as a filter group to get a separator between both groups
1050 0 : if ( !aImportantFilterGroup.empty() )
1051 : {
1052 0 : Sequence< StringPair > aFilters( aImportantFilterGroup.size() );
1053 0 : for ( sal_Int32 i = 0; i < (sal_Int32)aImportantFilterGroup.size(); i++ )
1054 : {
1055 0 : aFilters[i].First = addExtension( aImportantFilterGroup[i].aUIName,
1056 0 : aImportantFilterGroup[i].aWildcard,
1057 0 : sal_False, _rFileDlgImpl );
1058 0 : aFilters[i].Second = aImportantFilterGroup[i].aWildcard;
1059 : }
1060 :
1061 : try
1062 : {
1063 0 : xFilterGroupManager->appendFilterGroup( ::rtl::OUString(), aFilters );
1064 : }
1065 0 : catch( const IllegalArgumentException& )
1066 : {
1067 0 : }
1068 : }
1069 :
1070 0 : if ( !aFilterGroup.empty() )
1071 : {
1072 0 : Sequence< StringPair > aFilters( aFilterGroup.size() );
1073 0 : for ( sal_Int32 i = 0; i < (sal_Int32)aFilterGroup.size(); i++ )
1074 : {
1075 0 : aFilters[i].First = addExtension( aFilterGroup[i].aUIName,
1076 0 : aFilterGroup[i].aWildcard,
1077 0 : sal_False, _rFileDlgImpl );
1078 0 : aFilters[i].Second = aFilterGroup[i].aWildcard;
1079 : }
1080 :
1081 : try
1082 : {
1083 0 : xFilterGroupManager->appendFilterGroup( ::rtl::OUString(), aFilters );
1084 : }
1085 0 : catch( const IllegalArgumentException& )
1086 : {
1087 0 : }
1088 : }
1089 : }
1090 : else
1091 : {
1092 : // Fallback solution just add both filter groups as single filters
1093 : sal_Int32 n;
1094 :
1095 0 : for ( n = 0; n < (sal_Int32)aImportantFilterGroup.size(); n++ )
1096 : {
1097 : try
1098 : {
1099 0 : rtl::OUString aUIName = addExtension( aImportantFilterGroup[n].aUIName,
1100 0 : aImportantFilterGroup[n].aWildcard,
1101 0 : sal_False, _rFileDlgImpl );
1102 0 : _rxFilterManager->appendFilter( aUIName, aImportantFilterGroup[n].aWildcard );
1103 0 : if ( _rFirstNonEmpty.isEmpty() )
1104 0 : _rFirstNonEmpty = sUIName;
1105 :
1106 : }
1107 0 : catch( const IllegalArgumentException& )
1108 : {
1109 : SAL_WARN( "sfx2.dialog", "Could not append Filter" << sUIName );
1110 : }
1111 : }
1112 :
1113 0 : for ( n = 0; n < (sal_Int32)aFilterGroup.size(); n++ )
1114 : {
1115 : try
1116 : {
1117 0 : rtl::OUString aUIName = addExtension( aFilterGroup[n].aUIName,
1118 0 : aFilterGroup[n].aWildcard,
1119 0 : sal_False, _rFileDlgImpl );
1120 0 : _rxFilterManager->appendFilter( aUIName, aFilterGroup[n].aWildcard );
1121 0 : if ( _rFirstNonEmpty.isEmpty() )
1122 0 : _rFirstNonEmpty = sUIName;
1123 :
1124 : }
1125 0 : catch( const IllegalArgumentException& )
1126 : {
1127 : SAL_WARN( "sfx2.dialog", "Could not append Filter" << sUIName );
1128 : }
1129 : }
1130 0 : }
1131 : }
1132 :
1133 : //--------------------------------------------------------------------
1134 0 : void appendFiltersForOpen( TSortedFilterList& _rFilterMatcher,
1135 : const Reference< XFilterManager >& _rxFilterManager,
1136 : ::rtl::OUString& _rFirstNonEmpty, FileDialogHelper_Impl& _rFileDlgImpl )
1137 : {
1138 : DBG_ASSERT( _rxFilterManager.is(), "sfx2::appendFiltersForOpen: invalid manager!" );
1139 0 : if ( !_rxFilterManager.is() )
1140 0 : return;
1141 :
1142 : // ===============================================================
1143 : // group and classify the filters
1144 0 : GroupedFilterList aAllFilters;
1145 0 : lcl_GroupAndClassify( _rFilterMatcher, aAllFilters );
1146 :
1147 : // ===============================================================
1148 : // ensure that we have the one "all files" entry
1149 0 : lcl_EnsureAllFilesEntry( _rFilterMatcher, aAllFilters );
1150 :
1151 : // ===============================================================
1152 : // the first non-empty string - which we assume is the first overall entry
1153 0 : if ( !aAllFilters.empty() )
1154 : {
1155 0 : const FilterGroup& rFirstGroup = *aAllFilters.begin(); // should be the global classes
1156 0 : if ( !rFirstGroup.empty() )
1157 0 : _rFirstNonEmpty = rFirstGroup.begin()->First;
1158 : // append first group, without extension
1159 0 : AppendFilterGroup aGroup( _rxFilterManager, &_rFileDlgImpl );
1160 0 : aGroup.appendGroup( rFirstGroup, false );
1161 : }
1162 :
1163 : // ===============================================================
1164 : // append the filters to the manager
1165 0 : if ( !aAllFilters.empty() )
1166 : {
1167 0 : ::std::list< FilterGroup >::iterator pIter = aAllFilters.begin();
1168 0 : ++pIter;
1169 : ::std::for_each(
1170 : pIter, // first filter group was handled seperately, see above
1171 : aAllFilters.end(),
1172 0 : AppendFilterGroup( _rxFilterManager, &_rFileDlgImpl ) );
1173 0 : }
1174 : }
1175 :
1176 0 : ::rtl::OUString addExtension( const ::rtl::OUString& _rDisplayText,
1177 : const ::rtl::OUString& _rExtension,
1178 : sal_Bool _bForOpen, FileDialogHelper_Impl& _rFileDlgImpl )
1179 : {
1180 0 : static ::rtl::OUString sAllFilter( "(*.*)" );
1181 0 : static ::rtl::OUString sOpenBracket( " (" );
1182 0 : static ::rtl::OUString sCloseBracket( ")" );
1183 0 : ::rtl::OUString sRet = _rDisplayText;
1184 :
1185 0 : if ( sRet.indexOf( sAllFilter ) == -1 )
1186 : {
1187 0 : String sExt = _rExtension;
1188 0 : if ( !_bForOpen )
1189 : {
1190 : // show '*' in extensions only when opening a document
1191 0 : sExt = comphelper::string::remove(sExt, '*');
1192 : }
1193 0 : sRet += sOpenBracket;
1194 0 : sRet += sExt;
1195 0 : sRet += sCloseBracket;
1196 : }
1197 0 : _rFileDlgImpl.addFilterPair( _rDisplayText, sRet );
1198 0 : return sRet;
1199 : }
1200 :
1201 : //........................................................................
1202 : } // namespace sfx2
1203 : //........................................................................
1204 :
1205 :
1206 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|