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