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