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

Generated by: LCOV version 1.10