LCOV - code coverage report
Current view: top level - sc/source/filter/oox - autofilterbuffer.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 164 401 40.9 %
Date: 2012-08-25 Functions: 26 49 53.1 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 119 572 20.8 %

           Branch data     Line data    Source code
       1                 :            : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2                 :            : /*************************************************************************
       3                 :            :  *
       4                 :            :  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       5                 :            :  *
       6                 :            :  * Copyright 2000, 2010 Oracle and/or its affiliates.
       7                 :            :  *
       8                 :            :  * OpenOffice.org - a multi-platform office productivity suite
       9                 :            :  *
      10                 :            :  * This file is part of OpenOffice.org.
      11                 :            :  *
      12                 :            :  * OpenOffice.org is free software: you can redistribute it and/or modify
      13                 :            :  * it under the terms of the GNU Lesser General Public License version 3
      14                 :            :  * only, as published by the Free Software Foundation.
      15                 :            :  *
      16                 :            :  * OpenOffice.org is distributed in the hope that it will be useful,
      17                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      18                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      19                 :            :  * GNU Lesser General Public License version 3 for more details
      20                 :            :  * (a copy is included in the LICENSE file that accompanied this code).
      21                 :            :  *
      22                 :            :  * You should have received a copy of the GNU Lesser General Public License
      23                 :            :  * version 3 along with OpenOffice.org.  If not, see
      24                 :            :  * <http://www.openoffice.org/license.html>
      25                 :            :  * for a copy of the LGPLv3 License.
      26                 :            :  *
      27                 :            :  ************************************************************************/
      28                 :            : 
      29                 :            : #include "autofilterbuffer.hxx"
      30                 :            : 
      31                 :            : #include <com/sun/star/sheet/FilterConnection.hpp>
      32                 :            : #include <com/sun/star/sheet/FilterOperator2.hpp>
      33                 :            : #include <com/sun/star/sheet/TableFilterField3.hpp>
      34                 :            : #include <com/sun/star/sheet/XDatabaseRange.hpp>
      35                 :            : #include <com/sun/star/sheet/XSheetFilterDescriptor3.hpp>
      36                 :            : #include <com/sun/star/table/TableOrientation.hpp>
      37                 :            : #include <rtl/ustrbuf.hxx>
      38                 :            : #include "oox/helper/attributelist.hxx"
      39                 :            : #include "oox/helper/containerhelper.hxx"
      40                 :            : #include "oox/helper/propertyset.hxx"
      41                 :            : #include "oox/token/properties.hxx"
      42                 :            : #include "addressconverter.hxx"
      43                 :            : #include "biffinputstream.hxx"
      44                 :            : #include "defnamesbuffer.hxx"
      45                 :            : 
      46                 :            : namespace oox {
      47                 :            : namespace xls {
      48                 :            : 
      49                 :            : using namespace ::com::sun::star::sheet;
      50                 :            : using namespace ::com::sun::star::table;
      51                 :            : using namespace ::com::sun::star::uno;
      52                 :            : 
      53                 :            : using ::rtl::OUString;
      54                 :            : using ::rtl::OUStringBuffer;
      55                 :            : 
      56                 :            : // ============================================================================
      57                 :            : 
      58                 :            : namespace {
      59                 :            : 
      60                 :            : const sal_uInt8 BIFF12_TOP10FILTER_TOP              = 0x01;
      61                 :            : const sal_uInt8 BIFF12_TOP10FILTER_PERCENT          = 0x02;
      62                 :            : 
      63                 :            : const sal_uInt16 BIFF12_FILTERCOLUMN_HIDDENBUTTON   = 0x0001;
      64                 :            : const sal_uInt16 BIFF12_FILTERCOLUMN_SHOWBUTTON     = 0x0002;
      65                 :            : 
      66                 :            : const sal_uInt16 BIFF_FILTERCOLUMN_OR               = 0x0001;
      67                 :            : const sal_uInt16 BIFF_FILTERCOLUMN_TOP10FILTER      = 0x0010;
      68                 :            : const sal_uInt16 BIFF_FILTERCOLUMN_TOP              = 0x0020;
      69                 :            : const sal_uInt16 BIFF_FILTERCOLUMN_PERCENT          = 0x0040;
      70                 :            : 
      71                 :            : const sal_uInt8 BIFF_FILTER_DATATYPE_NONE           = 0;
      72                 :            : const sal_uInt8 BIFF_FILTER_DATATYPE_RK             = 2;
      73                 :            : const sal_uInt8 BIFF_FILTER_DATATYPE_DOUBLE         = 4;
      74                 :            : const sal_uInt8 BIFF_FILTER_DATATYPE_STRING         = 6;
      75                 :            : const sal_uInt8 BIFF_FILTER_DATATYPE_BOOLEAN        = 8;
      76                 :            : const sal_uInt8 BIFF_FILTER_DATATYPE_EMPTY          = 12;
      77                 :            : const sal_uInt8 BIFF_FILTER_DATATYPE_NOTEMPTY       = 14;
      78                 :            : 
      79                 :            : // ----------------------------------------------------------------------------
      80                 :            : 
      81                 :          3 : bool lclGetApiOperatorFromToken( sal_Int32& rnApiOperator, sal_Int32 nToken )
      82                 :            : {
      83   [ -  +  -  -  :          3 :     switch( nToken )
                -  -  - ]
      84                 :            :     {
      85                 :          0 :         case XML_lessThan:              rnApiOperator = FilterOperator2::NOT_EQUAL;     return true;
      86                 :          3 :         case XML_equal:                 rnApiOperator = FilterOperator2::EQUAL;         return true;
      87                 :          0 :         case XML_lessThanOrEqual:       rnApiOperator = FilterOperator2::LESS_EQUAL;    return true;
      88                 :          0 :         case XML_greaterThan:           rnApiOperator = FilterOperator2::GREATER;       return true;
      89                 :          0 :         case XML_notEqual:              rnApiOperator = FilterOperator2::NOT_EQUAL;     return true;
      90                 :          0 :         case XML_greaterThanOrEqual:    rnApiOperator = FilterOperator2::GREATER_EQUAL; return true;
      91                 :            :     }
      92                 :          3 :     return false;
      93                 :            : }
      94                 :            : 
      95                 :            : /** Removes leading asterisk characters from the passed string.
      96                 :            :     @return  True = at least one asterisk character has been removed. */
      97                 :          3 : bool lclTrimLeadingAsterisks( OUString& rValue )
      98                 :            : {
      99                 :          3 :     sal_Int32 nLength = rValue.getLength();
     100                 :          3 :     sal_Int32 nPos = 0;
     101 [ +  - ][ -  + ]:          3 :     while( (nPos < nLength) && (rValue[ nPos ] == '*') )
                 [ -  + ]
     102                 :          0 :         ++nPos;
     103         [ -  + ]:          3 :     if( nPos > 0 )
     104                 :            :     {
     105                 :          0 :         rValue = rValue.copy( nPos );
     106                 :          0 :         return true;
     107                 :            :     }
     108                 :          3 :     return false;
     109                 :            : }
     110                 :            : 
     111                 :            : /** Removes trailing asterisk characters from the passed string.
     112                 :            :     @return  True = at least one asterisk character has been removed. */
     113                 :          3 : bool lclTrimTrailingAsterisks( OUString& rValue )
     114                 :            : {
     115                 :          3 :     sal_Int32 nLength = rValue.getLength();
     116                 :          3 :     sal_Int32 nPos = nLength;
     117 [ +  - ][ -  + ]:          3 :     while( (nPos > 0) && (rValue[ nPos - 1 ] == '*') )
                 [ -  + ]
     118                 :          0 :         --nPos;
     119         [ -  + ]:          3 :     if( nPos < nLength )
     120                 :            :     {
     121                 :          0 :         rValue = rValue.copy( 0, nPos );
     122                 :          0 :         return true;
     123                 :            :     }
     124                 :          3 :     return false;
     125                 :            : }
     126                 :            : 
     127                 :            : /** Converts wildcard characters '*' and '?' to regular expressions and quotes
     128                 :            :     RE meta characters.
     129                 :            :     @return  True = passed string has been changed (RE needs to be enabled). */
     130                 :          3 : bool lclConvertWildcardsToRegExp( OUString& rValue )
     131                 :            : {
     132                 :            :     // check existence of the wildcard characters '*' and '?'
     133 [ +  - ][ +  - ]:          3 :     if( !rValue.isEmpty() && ((rValue.indexOf( '*' ) >= 0) || (rValue.indexOf( '?' ) >= 0)) )
         [ -  + ][ -  + ]
     134                 :            :     {
     135                 :          0 :         OUStringBuffer aBuffer;
     136         [ #  # ]:          0 :         aBuffer.ensureCapacity( rValue.getLength() + 5 );
     137                 :          0 :         const sal_Unicode* pcChar = rValue.getStr();
     138                 :          0 :         const sal_Unicode* pcEnd = pcChar + rValue.getLength();
     139         [ #  # ]:          0 :         for( ; pcChar < pcEnd; ++pcChar )
     140                 :            :         {
     141   [ #  #  #  # ]:          0 :             switch( *pcChar )
     142                 :            :             {
     143                 :            :                 case '?':
     144         [ #  # ]:          0 :                     aBuffer.append( sal_Unicode( '.' ) );
     145                 :          0 :                 break;
     146                 :            :                 case '*':
     147 [ #  # ][ #  # ]:          0 :                     aBuffer.append( sal_Unicode( '.' ) ).append( sal_Unicode( '*' ) );
     148                 :          0 :                 break;
     149                 :            :                 case '\\': case '.': case '|': case '(': case ')': case '^': case '$':
     150                 :            :                     // quote RE meta characters
     151 [ #  # ][ #  # ]:          0 :                     aBuffer.append( sal_Unicode( '\\' ) ).append( *pcChar );
     152                 :          0 :                 break;
     153                 :            :                 default:
     154         [ #  # ]:          0 :                     aBuffer.append( *pcChar );
     155                 :            :             }
     156                 :            :         }
     157         [ #  # ]:          0 :         rValue = aBuffer.makeStringAndClear();
     158                 :          0 :         return true;
     159                 :            :     }
     160                 :          3 :     return false;
     161                 :            : }
     162                 :            : 
     163                 :            : } // namespace
     164                 :            : 
     165                 :            : // ============================================================================
     166                 :            : 
     167                 :          6 : ApiFilterSettings::ApiFilterSettings()
     168                 :            : {
     169                 :          6 : }
     170                 :            : 
     171                 :          0 : void ApiFilterSettings::appendField( bool bAnd, sal_Int32 nOperator, double fValue )
     172                 :            : {
     173                 :          0 :     maFilterFields.resize( maFilterFields.size() + 1 );
     174                 :          0 :     TableFilterField3& rFilterField = maFilterFields.back();
     175         [ #  # ]:          0 :     rFilterField.Connection = bAnd ? FilterConnection_AND : FilterConnection_OR;
     176                 :          0 :     rFilterField.Operator = nOperator;
     177                 :          0 :     rFilterField.Values.realloc(1);
     178                 :          0 :     rFilterField.Values[0].IsNumeric = true;
     179                 :          0 :     rFilterField.Values[0].NumericValue = fValue;
     180                 :          0 : }
     181                 :            : 
     182                 :          3 : void ApiFilterSettings::appendField( bool bAnd, sal_Int32 nOperator, const OUString& rValue )
     183                 :            : {
     184                 :          3 :     maFilterFields.resize( maFilterFields.size() + 1 );
     185                 :          3 :     TableFilterField3& rFilterField = maFilterFields.back();
     186         [ +  - ]:          3 :     rFilterField.Connection = bAnd ? FilterConnection_AND : FilterConnection_OR;
     187                 :          3 :     rFilterField.Operator = nOperator;
     188                 :          3 :     rFilterField.Values.realloc(1);
     189                 :          3 :     rFilterField.Values[0].IsNumeric = false;
     190                 :          3 :     rFilterField.Values[0].StringValue = rValue;
     191                 :          3 : }
     192                 :            : 
     193                 :          0 : void ApiFilterSettings::appendField( bool bAnd, const std::vector<rtl::OUString>& rValues )
     194                 :            : {
     195                 :          0 :     maFilterFields.resize( maFilterFields.size() + 1 );
     196                 :          0 :     TableFilterField3& rFilterField = maFilterFields.back();
     197         [ #  # ]:          0 :     rFilterField.Connection = bAnd ? FilterConnection_AND : FilterConnection_OR;
     198                 :          0 :     rFilterField.Operator = FilterOperator2::EQUAL;
     199                 :          0 :     size_t n = rValues.size();
     200                 :          0 :     rFilterField.Values.realloc(n);
     201         [ #  # ]:          0 :     for (size_t i = 0; i < n; ++i)
     202                 :            :     {
     203                 :          0 :         rFilterField.Values[i].IsNumeric = false;
     204                 :          0 :         rFilterField.Values[i].StringValue = rValues[i];
     205                 :            :     }
     206                 :          0 : }
     207                 :            : 
     208                 :            : // ============================================================================
     209                 :            : 
     210                 :          3 : FilterSettingsBase::FilterSettingsBase( const WorkbookHelper& rHelper ) :
     211                 :          3 :     WorkbookHelper( rHelper )
     212                 :            : {
     213                 :          3 : }
     214                 :            : 
     215                 :          0 : void FilterSettingsBase::importAttribs( sal_Int32 /*nElement*/, const AttributeList& /*rAttribs*/ )
     216                 :            : {
     217                 :          0 : }
     218                 :            : 
     219                 :          0 : void FilterSettingsBase::importRecord( sal_Int32 /*nRecId*/, SequenceInputStream& /*rStrm*/ )
     220                 :            : {
     221                 :          0 : }
     222                 :            : 
     223                 :          0 : void FilterSettingsBase::importBiffRecord( BiffInputStream& /*rStrm*/, sal_uInt16 /*nFlags*/ )
     224                 :            : {
     225                 :          0 : }
     226                 :            : 
     227                 :          0 : ApiFilterSettings FilterSettingsBase::finalizeImport( sal_Int32 /*nMaxCount*/ )
     228                 :            : {
     229                 :          0 :     return ApiFilterSettings();
     230                 :            : }
     231                 :            : 
     232                 :            : // ============================================================================
     233                 :            : 
     234                 :          0 : DiscreteFilter::DiscreteFilter( const WorkbookHelper& rHelper ) :
     235                 :            :     FilterSettingsBase( rHelper ),
     236                 :            :     mnCalendarType( XML_none ),
     237         [ #  # ]:          0 :     mbShowBlank( false )
     238                 :            : {
     239                 :          0 : }
     240                 :            : 
     241                 :          0 : void DiscreteFilter::importAttribs( sal_Int32 nElement, const AttributeList& rAttribs )
     242                 :            : {
     243      [ #  #  # ]:          0 :     switch( nElement )
     244                 :            :     {
     245                 :            :         case XLS_TOKEN( filters ):
     246                 :          0 :             mnCalendarType = rAttribs.getToken( XML_calendarType, XML_none );
     247                 :          0 :             mbShowBlank = rAttribs.getBool( XML_blank, false );
     248                 :          0 :         break;
     249                 :            : 
     250                 :            :         case XLS_TOKEN( filter ):
     251                 :            :         {
     252         [ #  # ]:          0 :             OUString aValue = rAttribs.getXString( XML_val, OUString() );
     253         [ #  # ]:          0 :             if( !aValue.isEmpty() )
     254         [ #  # ]:          0 :                 maValues.push_back( aValue );
     255                 :            :         }
     256                 :          0 :         break;
     257                 :            :     }
     258                 :          0 : }
     259                 :            : 
     260                 :          0 : void DiscreteFilter::importRecord( sal_Int32 nRecId, SequenceInputStream& rStrm )
     261                 :            : {
     262      [ #  #  # ]:          0 :     switch( nRecId )
     263                 :            :     {
     264                 :            :         case BIFF12_ID_DISCRETEFILTERS:
     265                 :            :         {
     266                 :            :             sal_Int32 nShowBlank, nCalendarType;
     267 [ #  # ][ #  # ]:          0 :             rStrm >> nShowBlank >> nCalendarType;
     268                 :            : 
     269                 :            :             static const sal_Int32 spnCalendarTypes[] = {
     270                 :            :                 XML_none, XML_gregorian, XML_gregorianUs, XML_japan, XML_taiwan, XML_korea, XML_hijri, XML_thai, XML_hebrew,
     271                 :            :                 XML_gregorianMeFrench, XML_gregorianArabic, XML_gregorianXlitEnglish, XML_gregorianXlitFrench };
     272         [ #  # ]:          0 :             mnCalendarType = STATIC_ARRAY_SELECT( spnCalendarTypes, nCalendarType, XML_none );
     273                 :          0 :             mbShowBlank = nShowBlank != 0;
     274                 :            :         }
     275                 :          0 :         break;
     276                 :            : 
     277                 :            :         case BIFF12_ID_DISCRETEFILTER:
     278                 :            :         {
     279         [ #  # ]:          0 :             OUString aValue = BiffHelper::readString( rStrm );
     280         [ #  # ]:          0 :             if( !aValue.isEmpty() )
     281         [ #  # ]:          0 :                 maValues.push_back( aValue );
     282                 :            :         }
     283                 :          0 :         break;
     284                 :            :     }
     285                 :          0 : }
     286                 :            : 
     287                 :          0 : ApiFilterSettings DiscreteFilter::finalizeImport( sal_Int32 nMaxCount )
     288                 :            : {
     289                 :          0 :     ApiFilterSettings aSettings;
     290         [ #  # ]:          0 :     if( static_cast< sal_Int32 >( maValues.size() ) <= nMaxCount )
     291                 :            :     {
     292         [ #  # ]:          0 :         aSettings.maFilterFields.reserve( maValues.size() );
     293                 :            : 
     294                 :            :         // insert all filter values
     295         [ #  # ]:          0 :         aSettings.appendField( true, maValues );
     296                 :            : 
     297                 :            :         // extra field for 'show empty'
     298         [ #  # ]:          0 :         if( mbShowBlank )
     299         [ #  # ]:          0 :             aSettings.appendField( false, FilterOperator2::EMPTY, OUString() );
     300                 :            : 
     301                 :            :         /*  Require disabled regular expressions, filter entries may contain
     302                 :            :             any RE meta characters. */
     303         [ #  # ]:          0 :         if( !maValues.empty() )
     304         [ #  # ]:          0 :             aSettings.mobNeedsRegExp = false;
     305                 :            :     }
     306                 :          0 :     return aSettings;
     307                 :            : }
     308                 :            : 
     309                 :            : // ============================================================================
     310                 :            : 
     311                 :          0 : Top10Filter::Top10Filter( const WorkbookHelper& rHelper ) :
     312                 :            :     FilterSettingsBase( rHelper ),
     313                 :            :     mfValue( 0.0 ),
     314                 :            :     mbTop( true ),
     315                 :          0 :     mbPercent( false )
     316                 :            : {
     317                 :          0 : }
     318                 :            : 
     319                 :          0 : void Top10Filter::importAttribs( sal_Int32 nElement, const AttributeList& rAttribs )
     320                 :            : {
     321         [ #  # ]:          0 :     if( nElement == XLS_TOKEN( top10 ) )
     322                 :            :     {
     323                 :          0 :         mfValue = rAttribs.getDouble( XML_val, 0.0 );
     324                 :          0 :         mbTop = rAttribs.getBool( XML_top, true );
     325                 :          0 :         mbPercent = rAttribs.getBool( XML_percent, false );
     326                 :            :     }
     327                 :          0 : }
     328                 :            : 
     329                 :          0 : void Top10Filter::importRecord( sal_Int32 nRecId, SequenceInputStream& rStrm )
     330                 :            : {
     331         [ #  # ]:          0 :     if( nRecId == BIFF12_ID_TOP10FILTER )
     332                 :            :     {
     333                 :            :         sal_uInt8 nFlags;
     334 [ #  # ][ #  # ]:          0 :         rStrm >> nFlags >> mfValue;
     335                 :          0 :         mbTop = getFlag( nFlags, BIFF12_TOP10FILTER_TOP );
     336                 :          0 :         mbPercent = getFlag( nFlags, BIFF12_TOP10FILTER_PERCENT );
     337                 :            :     }
     338                 :          0 : }
     339                 :            : 
     340                 :          0 : void Top10Filter::importBiffRecord( BiffInputStream& /*rStrm*/, sal_uInt16 nFlags )
     341                 :            : {
     342                 :          0 :     mfValue = extractValue< sal_uInt16 >( nFlags, 7, 9 );
     343                 :          0 :     mbTop = getFlag( nFlags, BIFF_FILTERCOLUMN_TOP );
     344                 :          0 :     mbPercent = getFlag( nFlags, BIFF_FILTERCOLUMN_PERCENT );
     345                 :          0 : }
     346                 :            : 
     347                 :          0 : ApiFilterSettings Top10Filter::finalizeImport( sal_Int32 /*nMaxCount*/ )
     348                 :            : {
     349                 :            :     sal_Int32 nOperator = mbTop ?
     350                 :            :         (mbPercent ? FilterOperator2::TOP_PERCENT : FilterOperator2::TOP_VALUES) :
     351 [ #  # ][ #  # ]:          0 :         (mbPercent ? FilterOperator2::BOTTOM_PERCENT : FilterOperator2::BOTTOM_VALUES);
                 [ #  # ]
     352                 :          0 :     ApiFilterSettings aSettings;
     353         [ #  # ]:          0 :     aSettings.appendField( true, nOperator, mfValue );
     354                 :          0 :     return aSettings;
     355                 :            : }
     356                 :            : 
     357                 :            : // ============================================================================
     358                 :            : 
     359                 :          3 : FilterCriterionModel::FilterCriterionModel() :
     360                 :            :     mnOperator( XML_equal ),
     361                 :            :     mnDataType( BIFF_FILTER_DATATYPE_NONE ),
     362                 :          3 :     mnStrLen( 0 )
     363                 :            : {
     364                 :          3 : }
     365                 :            : 
     366                 :          0 : void FilterCriterionModel::setBiffOperator( sal_uInt8 nOperator )
     367                 :            : {
     368                 :            :     static const sal_Int32 spnOperators[] = { XML_TOKEN_INVALID,
     369                 :            :         XML_lessThan, XML_equal, XML_lessThanOrEqual, XML_greaterThan, XML_notEqual, XML_greaterThanOrEqual };
     370         [ #  # ]:          0 :     mnOperator = STATIC_ARRAY_SELECT( spnOperators, nOperator, XML_TOKEN_INVALID );
     371                 :          0 : }
     372                 :            : 
     373                 :          0 : void FilterCriterionModel::readBiffData( SequenceInputStream& rStrm )
     374                 :            : {
     375                 :            :     sal_uInt8 nOperator;
     376 [ #  # ][ #  # ]:          0 :     rStrm >> mnDataType >> nOperator;
     377                 :          0 :     setBiffOperator( nOperator );
     378                 :            : 
     379   [ #  #  #  #  :          0 :     switch( mnDataType )
                   #  # ]
     380                 :            :     {
     381                 :            :         case BIFF_FILTER_DATATYPE_DOUBLE:
     382 [ #  # ][ #  # ]:          0 :             maValue <<= rStrm.readDouble();
     383                 :          0 :         break;
     384                 :            :         case BIFF_FILTER_DATATYPE_STRING:
     385                 :            :         {
     386         [ #  # ]:          0 :             rStrm.skip( 8 );
     387         [ #  # ]:          0 :             OUString aValue = BiffHelper::readString( rStrm ).trim();
     388         [ #  # ]:          0 :             if( !aValue.isEmpty() )
     389         [ #  # ]:          0 :                 maValue <<= aValue;
     390                 :            :         }
     391                 :          0 :         break;
     392                 :            :         case BIFF_FILTER_DATATYPE_BOOLEAN:
     393 [ #  # ][ #  # ]:          0 :             maValue <<= (rStrm.readuInt8() != 0);
     394         [ #  # ]:          0 :             rStrm.skip( 7 );
     395                 :          0 :         break;
     396                 :            :         case BIFF_FILTER_DATATYPE_EMPTY:
     397         [ #  # ]:          0 :             rStrm.skip( 8 );
     398         [ #  # ]:          0 :             if( mnOperator == XML_equal )
     399         [ #  # ]:          0 :                 maValue <<= OUString();
     400                 :          0 :         break;
     401                 :            :         case BIFF_FILTER_DATATYPE_NOTEMPTY:
     402         [ #  # ]:          0 :             rStrm.skip( 8 );
     403         [ #  # ]:          0 :             if( mnOperator == XML_notEqual )
     404         [ #  # ]:          0 :                 maValue <<= OUString();
     405                 :          0 :         break;
     406                 :            :         default:
     407                 :            :             OSL_ENSURE( false, "FilterCriterionModel::readBiffData - unexpected data type" );
     408         [ #  # ]:          0 :             rStrm.skip( 8 );
     409                 :            :     }
     410                 :          0 : }
     411                 :            : 
     412                 :          0 : void FilterCriterionModel::readBiffData( BiffInputStream& rStrm )
     413                 :            : {
     414                 :            :     sal_uInt8 nOperator;
     415 [ #  # ][ #  # ]:          0 :     rStrm >> mnDataType >> nOperator;
     416                 :          0 :     setBiffOperator( nOperator );
     417                 :            : 
     418   [ #  #  #  #  :          0 :     switch( mnDataType )
             #  #  #  # ]
     419                 :            :     {
     420                 :            :         case BIFF_FILTER_DATATYPE_NONE:
     421         [ #  # ]:          0 :             rStrm.skip( 8 );
     422                 :          0 :         break;
     423                 :            :         case BIFF_FILTER_DATATYPE_RK:
     424 [ #  # ][ #  # ]:          0 :             maValue <<= BiffHelper::calcDoubleFromRk( rStrm.readInt32() );
                 [ #  # ]
     425         [ #  # ]:          0 :             rStrm.skip( 4 );
     426                 :          0 :         break;
     427                 :            :         case BIFF_FILTER_DATATYPE_DOUBLE:
     428 [ #  # ][ #  # ]:          0 :             maValue <<= rStrm.readDouble();
     429                 :          0 :         break;
     430                 :            :         case BIFF_FILTER_DATATYPE_STRING:
     431         [ #  # ]:          0 :             rStrm.skip( 4 );
     432         [ #  # ]:          0 :             rStrm >> mnStrLen;
     433         [ #  # ]:          0 :             rStrm.skip( 3 );
     434                 :          0 :         break;
     435                 :            :         case BIFF_FILTER_DATATYPE_BOOLEAN:
     436                 :            :         {
     437                 :            :             sal_uInt8 nValue, nType;
     438 [ #  # ][ #  # ]:          0 :             rStrm >> nValue >> nType;
     439         [ #  # ]:          0 :             rStrm.skip( 6 );
     440      [ #  #  # ]:          0 :             switch( nType )
     441                 :            :             {
     442         [ #  # ]:          0 :                 case BIFF_BOOLERR_BOOL:     maValue <<= (nValue != 0);                              break;
     443 [ #  # ][ #  # ]:          0 :                 case BIFF_BOOLERR_ERROR:    maValue <<= BiffHelper::calcDoubleFromError( nValue );  break;
     444                 :            :                 default:                    OSL_ENSURE( false, "FilterCriterionModel::readBiffData - unknown type" );
     445                 :            :             }
     446                 :            :         }
     447                 :          0 :         break;
     448                 :            :         case BIFF_FILTER_DATATYPE_EMPTY:
     449         [ #  # ]:          0 :             rStrm.skip( 8 );
     450         [ #  # ]:          0 :             if( mnOperator == XML_equal )
     451         [ #  # ]:          0 :                 maValue <<= OUString();
     452                 :          0 :         break;
     453                 :            :         case BIFF_FILTER_DATATYPE_NOTEMPTY:
     454         [ #  # ]:          0 :             rStrm.skip( 8 );
     455         [ #  # ]:          0 :             if( mnOperator == XML_notEqual )
     456         [ #  # ]:          0 :                 maValue <<= OUString();
     457                 :          0 :         break;
     458                 :            :         default:
     459                 :            :             OSL_ENSURE( false, "FilterCriterionModel::readBiffData - unexpected data type" );
     460         [ #  # ]:          0 :             rStrm.skip( 8 );
     461                 :            :     }
     462                 :          0 : }
     463                 :            : 
     464                 :          0 : void FilterCriterionModel::readString( BiffInputStream& rStrm, BiffType eBiff, rtl_TextEncoding eTextEnc )
     465                 :            : {
     466 [ #  # ][ #  # ]:          0 :     if( (mnDataType == BIFF_FILTER_DATATYPE_STRING) && (mnStrLen > 0) )
     467                 :            :     {
     468                 :            :         OUString aValue = (eBiff == BIFF8) ?
     469                 :            :             rStrm.readUniStringBody( mnStrLen, true ) :
     470 [ #  # ][ #  # ]:          0 :             rStrm.readCharArrayUC( mnStrLen, eTextEnc, true );
                 [ #  # ]
     471                 :          0 :         aValue = aValue.trim();
     472         [ #  # ]:          0 :         if( !aValue.isEmpty() )
     473         [ #  # ]:          0 :             maValue <<= aValue;
     474                 :            :     }
     475                 :          0 : }
     476                 :            : 
     477                 :            : // ----------------------------------------------------------------------------
     478                 :            : 
     479                 :          3 : CustomFilter::CustomFilter( const WorkbookHelper& rHelper ) :
     480                 :            :     FilterSettingsBase( rHelper ),
     481         [ +  - ]:          3 :     mbAnd( false )
     482                 :            : {
     483                 :          3 : }
     484                 :            : 
     485                 :          6 : void CustomFilter::importAttribs( sal_Int32 nElement, const AttributeList& rAttribs )
     486                 :            : {
     487      [ +  +  - ]:          6 :     switch( nElement )
     488                 :            :     {
     489                 :            :         case XLS_TOKEN( customFilters ):
     490                 :          3 :             mbAnd = rAttribs.getBool( XML_and, false );
     491                 :          3 :         break;
     492                 :            : 
     493                 :            :         case XLS_TOKEN( customFilter ):
     494                 :            :         {
     495                 :          3 :             FilterCriterionModel aCriterion;
     496         [ +  - ]:          3 :             aCriterion.mnOperator = rAttribs.getToken( XML_operator, XML_equal );
     497         [ +  - ]:          3 :             OUString aValue = rAttribs.getXString( XML_val, OUString() ).trim();
     498 [ #  # ][ #  # ]:          3 :             if( (aCriterion.mnOperator == XML_equal) || (aCriterion.mnOperator == XML_notEqual) || (!aValue.isEmpty()) )
         [ +  - ][ -  + ]
     499         [ +  - ]:          3 :                 aCriterion.maValue <<= aValue;
     500         [ +  - ]:          3 :             appendCriterion( aCriterion );
     501                 :            :         }
     502                 :          3 :         break;
     503                 :            :     }
     504                 :          6 : }
     505                 :            : 
     506                 :          0 : void CustomFilter::importRecord( sal_Int32 nRecId, SequenceInputStream& rStrm )
     507                 :            : {
     508      [ #  #  # ]:          0 :     switch( nRecId )
     509                 :            :     {
     510                 :            :         case BIFF12_ID_CUSTOMFILTERS:
     511                 :          0 :             mbAnd = rStrm.readInt32() == 0;
     512                 :          0 :         break;
     513                 :            : 
     514                 :            :         case BIFF12_ID_CUSTOMFILTER:
     515                 :            :         {
     516                 :          0 :             FilterCriterionModel aCriterion;
     517         [ #  # ]:          0 :             aCriterion.readBiffData( rStrm );
     518         [ #  # ]:          0 :             appendCriterion( aCriterion );
     519                 :            :         }
     520                 :          0 :         break;
     521                 :            :     }
     522                 :          0 : }
     523                 :            : 
     524                 :          0 : void CustomFilter::importBiffRecord( BiffInputStream& rStrm, sal_uInt16 nFlags )
     525                 :            : {
     526                 :          0 :     mbAnd = !getFlag( nFlags, BIFF_FILTERCOLUMN_OR );
     527                 :            : 
     528                 :          0 :     FilterCriterionModel aCriterion1, aCriterion2;
     529         [ #  # ]:          0 :     aCriterion1.readBiffData( rStrm );
     530         [ #  # ]:          0 :     aCriterion2.readBiffData( rStrm );
     531 [ #  # ][ #  # ]:          0 :     aCriterion1.readString( rStrm, getBiff(), getTextEncoding() );
                 [ #  # ]
     532 [ #  # ][ #  # ]:          0 :     aCriterion2.readString( rStrm, getBiff(), getTextEncoding() );
                 [ #  # ]
     533         [ #  # ]:          0 :     appendCriterion( aCriterion1 );
     534         [ #  # ]:          0 :     appendCriterion( aCriterion2 );
     535                 :          0 : }
     536                 :            : 
     537                 :          3 : ApiFilterSettings CustomFilter::finalizeImport( sal_Int32 /*nMaxCount*/ )
     538                 :            : {
     539                 :          3 :     ApiFilterSettings aSettings;
     540                 :            :     OSL_ENSURE( maCriteria.size() <= 2, "CustomFilter::finalizeImport - too many filter criteria" );
     541 [ +  - ][ +  + ]:          6 :     for( FilterCriterionVector::iterator aIt = maCriteria.begin(), aEnd = maCriteria.end(); aIt != aEnd; ++aIt )
     542                 :            :     {
     543                 :            :         // first extract the filter operator
     544                 :          3 :         sal_Int32 nOperator = 0;
     545                 :          3 :         bool bValidOperator = lclGetApiOperatorFromToken( nOperator, aIt->mnOperator );
     546         [ +  - ]:          3 :         if( bValidOperator )
     547                 :            :         {
     548 [ +  - ][ +  - ]:          3 :             if( aIt->maValue.has< OUString >() )
     549                 :            :             {
     550                 :            :                 // string argument
     551                 :          3 :                 OUString aValue;
     552                 :          3 :                 aIt->maValue >>= aValue;
     553                 :            :                 // check for 'empty', 'contains', 'begins with', or 'ends with' text filters
     554                 :          3 :                 bool bEqual = nOperator == FilterOperator2::EQUAL;
     555                 :          3 :                 bool bNotEqual = nOperator == FilterOperator2::NOT_EQUAL;
     556 [ #  # ][ -  + ]:          3 :                 if( bEqual || bNotEqual )
     557                 :            :                 {
     558         [ -  + ]:          3 :                     if( aValue.isEmpty() )
     559                 :            :                     {
     560                 :            :                         // empty comparison string: create empty/not empty filters
     561         [ #  # ]:          0 :                         nOperator = bNotEqual ? FilterOperator2::NOT_EMPTY : FilterOperator2::EMPTY;
     562                 :            :                     }
     563                 :            :                     else
     564                 :            :                     {
     565                 :            :                         // compare to something: try to find begins/ends/contains
     566                 :          3 :                         bool bHasLeadingAsterisk = lclTrimLeadingAsterisks( aValue );
     567                 :          3 :                         bool bHasTrailingAsterisk = lclTrimTrailingAsterisks( aValue );
     568                 :            :                         // just '***' matches everything, do not create a filter field
     569                 :          3 :                         bValidOperator = !aValue.isEmpty();
     570         [ +  - ]:          3 :                         if( bValidOperator )
     571                 :            :                         {
     572 [ -  + ][ #  # ]:          3 :                             if( bHasLeadingAsterisk && bHasTrailingAsterisk )
     573         [ #  # ]:          0 :                                 nOperator = bNotEqual ? FilterOperator2::DOES_NOT_CONTAIN : FilterOperator2::CONTAINS;
     574         [ -  + ]:          3 :                             else if( bHasLeadingAsterisk )
     575         [ #  # ]:          0 :                                 nOperator = bNotEqual ? FilterOperator2::DOES_NOT_END_WITH : FilterOperator2::ENDS_WITH;
     576         [ -  + ]:          3 :                             else if( bHasTrailingAsterisk )
     577         [ #  # ]:          3 :                                 nOperator = bNotEqual ? FilterOperator2::DOES_NOT_BEGIN_WITH : FilterOperator2::BEGINS_WITH;
     578                 :            :                             // else: no asterisks, stick to equal/not equal
     579                 :            :                         }
     580                 :            :                     }
     581                 :            :                 }
     582                 :            : 
     583         [ +  - ]:          3 :                 if( bValidOperator )
     584                 :            :                 {
     585                 :            :                     // if wildcards are present, require RE mode, otherwise keep don't care state
     586 [ +  - ][ -  + ]:          3 :                     if( lclConvertWildcardsToRegExp( aValue ) )
     587         [ #  # ]:          0 :                         aSettings.mobNeedsRegExp = true;
     588                 :            :                     // create a new UNO API filter field
     589         [ +  - ]:          3 :                     aSettings.appendField( mbAnd, nOperator, aValue );
     590                 :          3 :                 }
     591                 :            :             }
     592 [ #  # ][ #  # ]:          0 :             else if( aIt->maValue.has< double >() )
     593                 :            :             {
     594                 :            :                 // floating-point argument
     595                 :          0 :                 double fValue = 0.0;
     596                 :          0 :                 aIt->maValue >>= fValue;
     597         [ #  # ]:          0 :                 aSettings.appendField( mbAnd, nOperator, fValue );
     598                 :            :             }
     599                 :            :         }
     600                 :            :     }
     601                 :          3 :     return aSettings;
     602                 :            : }
     603                 :            : 
     604                 :          3 : void CustomFilter::appendCriterion( const FilterCriterionModel& rCriterion )
     605                 :            : {
     606 [ +  - ][ +  - ]:          3 :     if( (rCriterion.mnOperator != XML_TOKEN_INVALID) && rCriterion.maValue.hasValue() )
                 [ +  - ]
     607                 :          3 :         maCriteria.push_back( rCriterion );
     608                 :          3 : }
     609                 :            : 
     610                 :            : // ============================================================================
     611                 :            : 
     612                 :          3 : FilterColumn::FilterColumn( const WorkbookHelper& rHelper ) :
     613                 :            :     WorkbookHelper( rHelper ),
     614                 :            :     mnColId( -1 ),
     615                 :            :     mbHiddenButton( false ),
     616         [ +  - ]:          3 :     mbShowButton( true )
     617                 :            : {
     618                 :          3 : }
     619                 :            : 
     620                 :          3 : void FilterColumn::importFilterColumn( const AttributeList& rAttribs )
     621                 :            : {
     622                 :          3 :     mnColId = rAttribs.getInteger( XML_colId, -1 );
     623                 :          3 :     mbHiddenButton = rAttribs.getBool( XML_hiddenButton, false );
     624                 :          3 :     mbShowButton = rAttribs.getBool( XML_showButton, true );
     625                 :          3 : }
     626                 :            : 
     627                 :          0 : void FilterColumn::importFilterColumn( SequenceInputStream& rStrm )
     628                 :            : {
     629                 :            :     sal_uInt16 nFlags;
     630 [ #  # ][ #  # ]:          0 :     rStrm >> mnColId >> nFlags;
     631                 :          0 :     mbHiddenButton = getFlag( nFlags, BIFF12_FILTERCOLUMN_HIDDENBUTTON );
     632                 :          0 :     mbShowButton = getFlag( nFlags, BIFF12_FILTERCOLUMN_SHOWBUTTON );
     633                 :          0 : }
     634                 :            : 
     635                 :          3 : ApiFilterSettings FilterColumn::finalizeImport( sal_Int32 nMaxCount )
     636                 :            : {
     637                 :          3 :     ApiFilterSettings aSettings;
     638 [ +  - ][ +  - ]:          3 :     if( (0 <= mnColId) && mxSettings.get() )
                 [ +  - ]
     639                 :            :     {
     640                 :            :         // filter settings object creates a sequence of filter fields
     641         [ +  - ]:          3 :         aSettings = mxSettings->finalizeImport( nMaxCount );
     642                 :            :         // add column index to all filter fields
     643 [ +  - ][ +  + ]:          6 :         for( ApiFilterSettings::FilterFieldVector::iterator aIt = aSettings.maFilterFields.begin(), aEnd = aSettings.maFilterFields.end(); aIt != aEnd; ++aIt )
     644                 :          3 :             aIt->Field = mnColId;
     645                 :            :     }
     646                 :          3 :     return aSettings;
     647                 :            : }
     648                 :            : 
     649                 :            : // ============================================================================
     650                 :            : 
     651                 :          3 : AutoFilter::AutoFilter( const WorkbookHelper& rHelper ) :
     652         [ +  - ]:          3 :     WorkbookHelper( rHelper )
     653                 :            : {
     654                 :          3 : }
     655                 :            : 
     656                 :          3 : void AutoFilter::importAutoFilter( const AttributeList& rAttribs, sal_Int16 nSheet )
     657                 :            : {
     658         [ +  - ]:          3 :     OUString aRangeStr = rAttribs.getString( XML_ref, OUString() );
     659 [ +  - ][ +  - ]:          3 :     getAddressConverter().convertToCellRangeUnchecked( maRange, aRangeStr, nSheet );
     660                 :          3 : }
     661                 :            : 
     662                 :          0 : void AutoFilter::importAutoFilter( SequenceInputStream& rStrm, sal_Int16 nSheet )
     663                 :            : {
     664                 :          0 :     BinRange aBinRange;
     665         [ #  # ]:          0 :     rStrm >> aBinRange;
     666 [ #  # ][ #  # ]:          0 :     getAddressConverter().convertToCellRangeUnchecked( maRange, aBinRange, nSheet );
     667                 :          0 : }
     668                 :            : 
     669                 :          3 : FilterColumn& AutoFilter::createFilterColumn()
     670                 :            : {
     671 [ +  - ][ +  - ]:          3 :     FilterColumnVector::value_type xFilterColumn( new FilterColumn( *this ) );
                 [ +  - ]
     672         [ +  - ]:          3 :     maFilterColumns.push_back( xFilterColumn );
     673         [ +  - ]:          3 :     return *xFilterColumn;
     674                 :            : }
     675                 :            : 
     676                 :          3 : void AutoFilter::finalizeImport( const Reference<XSheetFilterDescriptor3>& rxFilterDesc )
     677                 :            : {
     678         [ +  - ]:          3 :     if( rxFilterDesc.is() )
     679                 :            :     {
     680                 :            :         // set some common properties for the auto filter range
     681         [ +  - ]:          3 :         PropertySet aDescProps( rxFilterDesc );
     682         [ +  - ]:          3 :         aDescProps.setProperty( PROP_IsCaseSensitive, false );
     683         [ +  - ]:          3 :         aDescProps.setProperty( PROP_SkipDuplicates, false );
     684         [ +  - ]:          3 :         aDescProps.setProperty( PROP_Orientation, TableOrientation_ROWS );
     685         [ +  - ]:          3 :         aDescProps.setProperty( PROP_ContainsHeader, true );
     686         [ +  - ]:          3 :         aDescProps.setProperty( PROP_CopyOutputData, false );
     687                 :            : 
     688                 :            :         // maximum number of UNO API filter fields
     689                 :          3 :         sal_Int32 nMaxCount = 0;
     690         [ +  - ]:          3 :         aDescProps.getProperty( nMaxCount, PROP_MaxFieldCount );
     691                 :            :         OSL_ENSURE( nMaxCount > 0, "AutoFilter::finalizeImport - invalid maximum filter field count" );
     692                 :            : 
     693                 :            :         // resulting list of all UNO API filter fields
     694         [ +  - ]:          3 :         ::std::vector<TableFilterField3> aFilterFields;
     695                 :            : 
     696                 :            :         // track if columns require to enable or disable regular expressions
     697                 :          3 :         OptValue< bool > obNeedsRegExp;
     698                 :            : 
     699                 :            :         /*  Track whether the filter fields of the first filter column are
     700                 :            :             connected with 'or'. In this case, other filter fields cannot be
     701                 :            :             inserted without altering the result of the entire filter, due to
     702                 :            :             Calc's precedence for the 'and' connection operator. Example:
     703                 :            :             Excel's filter conditions 'A1 and (B1 or B2) and C1' where B1 and
     704                 :            :             B2 belong to filter column B, will be evaluated by Calc as
     705                 :            :             '(A1 and B1) or (B2 and C1)'. */
     706                 :          3 :         bool bHasOrConnection = false;
     707                 :            : 
     708                 :            :         // process all filter column objects, exit when 'or' connection exists
     709 [ +  - ][ +  - ]:          6 :         for( FilterColumnVector::iterator aIt = maFilterColumns.begin(), aEnd = maFilterColumns.end(); !bHasOrConnection && (aIt != aEnd); ++aIt )
         [ +  + ][ +  + ]
     710                 :            :         {
     711                 :            :             // the filter settings object creates a list of filter fields
     712         [ +  - ]:          3 :             ApiFilterSettings aSettings = (*aIt)->finalizeImport( nMaxCount );
     713                 :          3 :             ApiFilterSettings::FilterFieldVector& rColumnFields = aSettings.maFilterFields;
     714                 :            : 
     715                 :            :             // new total number of filter fields
     716                 :          3 :             sal_Int32 nNewCount = static_cast< sal_Int32 >( aFilterFields.size() + rColumnFields.size() );
     717                 :            : 
     718                 :            :             /*  Check whether mode for regular expressions is compatible with
     719                 :            :                 the global mode in obNeedsRegExp. If either one is still in
     720                 :            :                 don't-care state, all is fine. If both are set, they must be
     721                 :            :                 equal. */
     722 [ #  # ][ #  # ]:          3 :             bool bRegExpCompatible = !obNeedsRegExp || !aSettings.mobNeedsRegExp || (obNeedsRegExp.get() == aSettings.mobNeedsRegExp.get());
                 [ -  + ]
     723                 :            : 
     724                 :            :             // check whether fields are connected by 'or' (see comments above).
     725         [ -  + ]:          3 :             if( rColumnFields.size() >= 2 )
     726 [ #  # ][ #  # ]:          0 :                 for( ApiFilterSettings::FilterFieldVector::iterator aSIt = rColumnFields.begin() + 1, aSEnd = rColumnFields.end(); !bHasOrConnection && (aSIt != aSEnd); ++aSIt )
         [ #  # ][ #  # ]
                 [ #  # ]
     727                 :          0 :                     bHasOrConnection = aSIt->Connection == FilterConnection_OR;
     728                 :            : 
     729                 :            :             /*  Skip the column filter, if no filter fields have been created,
     730                 :            :                 if the number of new filter fields would exceed the total limit
     731                 :            :                 of filter fields, or if the mode for regular expressions of the
     732                 :            :                 filter column does not fit. */
     733 [ +  - ][ +  - ]:          3 :             if( !rColumnFields.empty() && (nNewCount <= nMaxCount) && bRegExpCompatible )
         [ +  - ][ +  - ]
     734                 :            :             {
     735                 :            :                 /*  Add 'and' connection to the first filter field to connect
     736                 :            :                     it to the existing filter fields of other columns. */
     737                 :          3 :                 rColumnFields[ 0 ].Connection = FilterConnection_AND;
     738                 :            : 
     739                 :            :                 // insert the new filter fields
     740         [ +  - ]:          3 :                 aFilterFields.insert( aFilterFields.end(), rColumnFields.begin(), rColumnFields.end() );
     741                 :            : 
     742                 :            :                 // update the regular expressions mode
     743         [ +  - ]:          3 :                 obNeedsRegExp.assignIfUsed( aSettings.mobNeedsRegExp );
     744                 :            :             }
     745                 :          3 :         }
     746                 :            : 
     747                 :            :         // insert all filter fields to the filter descriptor
     748         [ +  - ]:          3 :         if( !aFilterFields.empty() )
     749 [ +  - ][ +  - ]:          3 :             rxFilterDesc->setFilterFields3( ContainerHelper::vectorToSequence( aFilterFields ) );
         [ +  - ][ +  - ]
     750                 :            : 
     751                 :            :         // regular expressions
     752                 :          3 :         bool bUseRegExp = obNeedsRegExp.get( false );
     753 [ +  - ][ +  - ]:          3 :         aDescProps.setProperty( PROP_UseRegularExpressions, bUseRegExp );
     754                 :            :     }
     755                 :          3 : }
     756                 :            : 
     757                 :            : // ============================================================================
     758                 :            : 
     759                 :         60 : AutoFilterBuffer::AutoFilterBuffer( const WorkbookHelper& rHelper ) :
     760         [ +  - ]:         60 :     WorkbookHelper( rHelper )
     761                 :            : {
     762                 :         60 : }
     763                 :            : 
     764                 :          3 : AutoFilter& AutoFilterBuffer::createAutoFilter()
     765                 :            : {
     766 [ +  - ][ +  - ]:          3 :     AutoFilterVector::value_type xAutoFilter( new AutoFilter( *this ) );
                 [ +  - ]
     767         [ +  - ]:          3 :     maAutoFilters.push_back( xAutoFilter );
     768         [ +  - ]:          3 :     return *xAutoFilter;
     769                 :            : }
     770                 :            : 
     771                 :         60 : void AutoFilterBuffer::finalizeImport( sal_Int16 nSheet )
     772                 :            : {
     773                 :            :     // rely on existence of the defined name '_FilterDatabase' containing the range address of the filtered area
     774         [ +  + ]:         60 :     if( const DefinedName* pFilterDBName = getDefinedNames().getByBuiltinId( BIFF_DEFNAME_FILTERDATABASE, nSheet ).get() )
     775                 :            :     {
     776                 :          3 :         CellRangeAddress aFilterRange;
     777 [ +  - ][ +  - ]:          3 :         if( pFilterDBName->getAbsoluteRange( aFilterRange ) && (aFilterRange.Sheet == nSheet) )
         [ +  - ][ +  - ]
     778                 :            :         {
     779                 :            :             // use the same name for the database range as used for the defined name '_FilterDatabase'
     780         [ +  - ]:          3 :             Reference< XDatabaseRange > xDatabaseRange = createUnnamedDatabaseRangeObject( aFilterRange );
     781                 :            :             // first, try to create an auto filter
     782         [ +  - ]:          3 :             bool bHasAutoFilter = finalizeImport( xDatabaseRange );
     783                 :            :             // no success: try to create an advanced filter
     784 [ -  + ][ #  # ]:          3 :             if( !bHasAutoFilter && xDatabaseRange.is() )
                 [ -  + ]
     785                 :            :             {
     786                 :            :                 // the built-in defined name 'Criteria' must exist
     787 [ #  # ][ #  # ]:          0 :                 if( const DefinedName* pCriteriaName = getDefinedNames().getByBuiltinId( BIFF_DEFNAME_CRITERIA, nSheet ).get() )
         [ #  # ][ #  # ]
     788                 :            :                 {
     789                 :          0 :                     CellRangeAddress aCriteriaRange;
     790 [ #  # ][ #  # ]:          0 :                     if( pCriteriaName->getAbsoluteRange( aCriteriaRange ) )
     791                 :            :                     {
     792                 :            :                         // set some common properties for the filter descriptor
     793 [ #  # ][ #  # ]:          0 :                         PropertySet aDescProps( xDatabaseRange->getFilterDescriptor() );
                 [ #  # ]
     794         [ #  # ]:          0 :                         aDescProps.setProperty( PROP_IsCaseSensitive, false );
     795         [ #  # ]:          0 :                         aDescProps.setProperty( PROP_SkipDuplicates, false );
     796         [ #  # ]:          0 :                         aDescProps.setProperty( PROP_Orientation, TableOrientation_ROWS );
     797         [ #  # ]:          0 :                         aDescProps.setProperty( PROP_ContainsHeader, true );
     798                 :            :                         // criteria range may contain wildcards, but these are incompatible with REs
     799         [ #  # ]:          0 :                         aDescProps.setProperty( PROP_UseRegularExpressions, false );
     800                 :            : 
     801                 :            :                         // position of output data (if built-in defined name 'Extract' exists)
     802 [ #  # ][ #  # ]:          0 :                         DefinedNameRef xExtractName = getDefinedNames().getByBuiltinId( BIFF_DEFNAME_EXTRACT, nSheet );
     803                 :          0 :                         CellRangeAddress aOutputRange;
     804 [ #  # ][ #  # ]:          0 :                         bool bHasOutputRange = xExtractName.get() && xExtractName->getAbsoluteRange( aOutputRange );
                 [ #  # ]
     805         [ #  # ]:          0 :                         aDescProps.setProperty( PROP_CopyOutputData, bHasOutputRange );
     806         [ #  # ]:          0 :                         if( bHasOutputRange )
     807                 :            :                         {
     808         [ #  # ]:          0 :                             aDescProps.setProperty( PROP_SaveOutputPosition, true );
     809         [ #  # ]:          0 :                             aDescProps.setProperty( PROP_OutputPosition, CellAddress( aOutputRange.Sheet, aOutputRange.StartColumn, aOutputRange.StartRow ) );
     810                 :            :                         }
     811                 :            : 
     812                 :            :                         /*  Properties of the database range (must be set after
     813                 :            :                             modifying properties of the filter descriptor,
     814                 :            :                             otherwise the 'FilterCriteriaSource' property gets
     815                 :            :                             deleted). */
     816         [ #  # ]:          0 :                         PropertySet aRangeProps( xDatabaseRange );
     817         [ #  # ]:          0 :                         aRangeProps.setProperty( PROP_AutoFilter, false );
     818 [ #  # ][ #  # ]:          0 :                         aRangeProps.setProperty( PROP_FilterCriteriaSource, aCriteriaRange );
         [ #  # ][ #  # ]
     819                 :            :                     }
     820                 :            :                 }
     821                 :          3 :             }
     822                 :            :         }
     823                 :            :     }
     824                 :         60 : }
     825                 :            : 
     826                 :          3 : bool AutoFilterBuffer::finalizeImport( const Reference< XDatabaseRange >& rxDatabaseRange )
     827                 :            : {
     828                 :          3 :     AutoFilter* pAutoFilter = getActiveAutoFilter();
     829 [ +  - ][ +  - ]:          3 :     if( pAutoFilter && rxDatabaseRange.is() ) try
                 [ +  - ]
     830                 :            :     {
     831                 :            :         // the property 'AutoFilter' enables the drop-down buttons
     832         [ +  - ]:          3 :         PropertySet aRangeProps( rxDatabaseRange );
     833         [ +  - ]:          3 :         aRangeProps.setProperty( PROP_AutoFilter, true );
     834                 :            :         // convert filter settings using the filter descriptor of the database range
     835 [ +  - ][ +  - ]:          3 :         Reference< XSheetFilterDescriptor3 > xFilterDesc( rxDatabaseRange->getFilterDescriptor(), UNO_QUERY_THROW );
                 [ +  - ]
     836         [ +  - ]:          3 :         pAutoFilter->finalizeImport( xFilterDesc );
     837                 :            :         // return true to indicate enabled autofilter
     838 [ +  - ][ #  # ]:          3 :         return true;
     839                 :            :     }
     840                 :          0 :     catch( Exception& )
     841                 :            :     {
     842                 :            :     }
     843                 :          3 :     return false;
     844                 :            : }
     845                 :            : 
     846                 :          3 : AutoFilter* AutoFilterBuffer::getActiveAutoFilter()
     847                 :            : {
     848                 :            :     // Excel expects not more than one auto filter per sheet or table
     849                 :            :     OSL_ENSURE( maAutoFilters.size() <= 1, "AutoFilterBuffer::getActiveAutoFilter - too many auto filters" );
     850                 :            :     // stick to the last imported auto filter
     851         [ -  + ]:          3 :     return maAutoFilters.empty() ? 0 : maAutoFilters.back().get();
     852                 :            : }
     853                 :            : 
     854                 :            : // ============================================================================
     855                 :            : 
     856                 :            : } // namespace xls
     857 [ +  - ][ +  - ]:         24 : } // namespace oox
     858                 :            : 
     859                 :            : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10