LCOV - code coverage report
Current view: top level - sfx2/source/dialog - filtergrouping.cxx (source / functions) Hit Total Coverage
Test: commit 0e63ca4fde4e446f346e35849c756a30ca294aab Lines: 0 409 0.0 %
Date: 2014-04-11 Functions: 0 61 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10