fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / sc / source / filter / oox / autofilterbuffer.cxx
blob982daa1a746616e9cad3def4d3b57e06d4d229f2
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "autofilterbuffer.hxx"
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 <osl/diagnose.h>
30 #include <oox/helper/attributelist.hxx>
31 #include <oox/helper/containerhelper.hxx>
32 #include <oox/helper/propertyset.hxx>
33 #include <oox/token/properties.hxx>
34 #include "addressconverter.hxx"
35 #include "biffinputstream.hxx"
36 #include "defnamesbuffer.hxx"
38 namespace oox {
39 namespace xls {
41 using namespace ::com::sun::star::sheet;
42 using namespace ::com::sun::star::table;
43 using namespace ::com::sun::star::uno;
45 namespace {
47 const sal_uInt8 BIFF12_TOP10FILTER_TOP = 0x01;
48 const sal_uInt8 BIFF12_TOP10FILTER_PERCENT = 0x02;
50 const sal_uInt16 BIFF12_FILTERCOLUMN_HIDDENBUTTON = 0x0001;
51 const sal_uInt16 BIFF12_FILTERCOLUMN_SHOWBUTTON = 0x0002;
53 const sal_uInt8 BIFF_FILTER_DATATYPE_NONE = 0;
54 const sal_uInt8 BIFF_FILTER_DATATYPE_DOUBLE = 4;
55 const sal_uInt8 BIFF_FILTER_DATATYPE_STRING = 6;
56 const sal_uInt8 BIFF_FILTER_DATATYPE_BOOLEAN = 8;
57 const sal_uInt8 BIFF_FILTER_DATATYPE_EMPTY = 12;
58 const sal_uInt8 BIFF_FILTER_DATATYPE_NOTEMPTY = 14;
60 bool lclGetApiOperatorFromToken( sal_Int32& rnApiOperator, sal_Int32 nToken )
62 switch( nToken )
64 case XML_lessThan: rnApiOperator = FilterOperator2::NOT_EQUAL; return true;
65 case XML_equal: rnApiOperator = FilterOperator2::EQUAL; return true;
66 case XML_lessThanOrEqual: rnApiOperator = FilterOperator2::LESS_EQUAL; return true;
67 case XML_greaterThan: rnApiOperator = FilterOperator2::GREATER; return true;
68 case XML_notEqual: rnApiOperator = FilterOperator2::NOT_EQUAL; return true;
69 case XML_greaterThanOrEqual: rnApiOperator = FilterOperator2::GREATER_EQUAL; return true;
71 return false;
74 /** Removes leading asterisk characters from the passed string.
75 @return True = at least one asterisk character has been removed. */
76 bool lclTrimLeadingAsterisks( OUString& rValue )
78 sal_Int32 nLength = rValue.getLength();
79 sal_Int32 nPos = 0;
80 while( (nPos < nLength) && (rValue[ nPos ] == '*') )
81 ++nPos;
82 if( nPos > 0 )
84 rValue = rValue.copy( nPos );
85 return true;
87 return false;
90 /** Removes trailing asterisk characters from the passed string.
91 @return True = at least one asterisk character has been removed. */
92 bool lclTrimTrailingAsterisks( OUString& rValue )
94 sal_Int32 nLength = rValue.getLength();
95 sal_Int32 nPos = nLength;
96 while( (nPos > 0) && (rValue[ nPos - 1 ] == '*') )
97 --nPos;
98 if( nPos < nLength )
100 rValue = rValue.copy( 0, nPos );
101 return true;
103 return false;
106 /** Converts wildcard characters '*' and '?' to regular expressions and quotes
107 RE meta characters.
108 @return True = passed string has been changed (RE needs to be enabled). */
109 bool lclConvertWildcardsToRegExp( OUString& rValue )
111 // check existence of the wildcard characters '*' and '?'
112 if( !rValue.isEmpty() && ((rValue.indexOf( '*' ) >= 0) || (rValue.indexOf( '?' ) >= 0)) )
114 OUStringBuffer aBuffer;
115 aBuffer.ensureCapacity( rValue.getLength() + 5 );
116 const sal_Unicode* pcChar = rValue.getStr();
117 const sal_Unicode* pcEnd = pcChar + rValue.getLength();
118 for( ; pcChar < pcEnd; ++pcChar )
120 switch( *pcChar )
122 case '?':
123 aBuffer.append( '.' );
124 break;
125 case '*':
126 aBuffer.append( '.' ).append( '*' );
127 break;
128 case '\\': case '.': case '|': case '(': case ')': case '^': case '$':
129 // quote RE meta characters
130 aBuffer.append( '\\' ).append( *pcChar );
131 break;
132 default:
133 aBuffer.append( *pcChar );
136 rValue = aBuffer.makeStringAndClear();
137 return true;
139 return false;
142 } // namespace
144 ApiFilterSettings::ApiFilterSettings()
148 void ApiFilterSettings::appendField( bool bAnd, sal_Int32 nOperator, double fValue )
150 maFilterFields.resize( maFilterFields.size() + 1 );
151 TableFilterField3& rFilterField = maFilterFields.back();
152 rFilterField.Connection = bAnd ? FilterConnection_AND : FilterConnection_OR;
153 rFilterField.Operator = nOperator;
154 rFilterField.Values.realloc(1);
155 rFilterField.Values[0].IsNumeric = true;
156 rFilterField.Values[0].NumericValue = fValue;
159 void ApiFilterSettings::appendField( bool bAnd, sal_Int32 nOperator, const OUString& rValue )
161 maFilterFields.resize( maFilterFields.size() + 1 );
162 TableFilterField3& rFilterField = maFilterFields.back();
163 rFilterField.Connection = bAnd ? FilterConnection_AND : FilterConnection_OR;
164 rFilterField.Operator = nOperator;
165 rFilterField.Values.realloc(1);
166 rFilterField.Values[0].IsNumeric = false;
167 rFilterField.Values[0].StringValue = rValue;
170 void ApiFilterSettings::appendField( bool bAnd, const std::vector<OUString>& rValues )
172 maFilterFields.resize( maFilterFields.size() + 1 );
173 TableFilterField3& rFilterField = maFilterFields.back();
174 rFilterField.Connection = bAnd ? FilterConnection_AND : FilterConnection_OR;
175 rFilterField.Operator = FilterOperator2::EQUAL;
176 size_t n = rValues.size();
177 rFilterField.Values.realloc(n);
178 for (size_t i = 0; i < n; ++i)
180 rFilterField.Values[i].IsNumeric = false;
181 rFilterField.Values[i].StringValue = rValues[i];
185 FilterSettingsBase::FilterSettingsBase( const WorkbookHelper& rHelper ) :
186 WorkbookHelper( rHelper )
190 void FilterSettingsBase::importAttribs( sal_Int32 /*nElement*/, const AttributeList& /*rAttribs*/ )
194 void FilterSettingsBase::importRecord( sal_Int32 /*nRecId*/, SequenceInputStream& /*rStrm*/ )
198 ApiFilterSettings FilterSettingsBase::finalizeImport( sal_Int32 /*nMaxCount*/ )
200 return ApiFilterSettings();
203 DiscreteFilter::DiscreteFilter( const WorkbookHelper& rHelper ) :
204 FilterSettingsBase( rHelper ),
205 mnCalendarType( XML_none ),
206 mbShowBlank( false )
210 void DiscreteFilter::importAttribs( sal_Int32 nElement, const AttributeList& rAttribs )
212 switch( nElement )
214 case XLS_TOKEN( filters ):
215 mnCalendarType = rAttribs.getToken( XML_calendarType, XML_none );
216 mbShowBlank = rAttribs.getBool( XML_blank, false );
217 break;
219 case XLS_TOKEN( filter ):
221 OUString aValue = rAttribs.getXString( XML_val, OUString() );
222 if( !aValue.isEmpty() )
223 maValues.push_back( aValue );
225 break;
229 void DiscreteFilter::importRecord( sal_Int32 nRecId, SequenceInputStream& rStrm )
231 switch( nRecId )
233 case BIFF12_ID_DISCRETEFILTERS:
235 sal_Int32 nShowBlank, nCalendarType;
236 nShowBlank = rStrm.readInt32();
237 nCalendarType = rStrm.readInt32();
239 static const sal_Int32 spnCalendarTypes[] = {
240 XML_none, XML_gregorian, XML_gregorianUs, XML_japan, XML_taiwan, XML_korea, XML_hijri, XML_thai, XML_hebrew,
241 XML_gregorianMeFrench, XML_gregorianArabic, XML_gregorianXlitEnglish, XML_gregorianXlitFrench };
242 mnCalendarType = STATIC_ARRAY_SELECT( spnCalendarTypes, nCalendarType, XML_none );
243 mbShowBlank = nShowBlank != 0;
245 break;
247 case BIFF12_ID_DISCRETEFILTER:
249 OUString aValue = BiffHelper::readString( rStrm );
250 if( !aValue.isEmpty() )
251 maValues.push_back( aValue );
253 break;
257 ApiFilterSettings DiscreteFilter::finalizeImport( sal_Int32 nMaxCount )
259 ApiFilterSettings aSettings;
260 if( static_cast< sal_Int32 >( maValues.size() ) <= nMaxCount )
262 aSettings.maFilterFields.reserve( maValues.size() );
264 // insert all filter values
265 aSettings.appendField( true, maValues );
267 // extra field for 'show empty'
268 if( mbShowBlank )
269 aSettings.appendField( false, FilterOperator2::EMPTY, OUString() );
271 /* Require disabled regular expressions, filter entries may contain
272 any RE meta characters. */
273 if( !maValues.empty() )
274 aSettings.mobNeedsRegExp = false;
276 return aSettings;
279 Top10Filter::Top10Filter( const WorkbookHelper& rHelper ) :
280 FilterSettingsBase( rHelper ),
281 mfValue( 0.0 ),
282 mbTop( true ),
283 mbPercent( false )
287 void Top10Filter::importAttribs( sal_Int32 nElement, const AttributeList& rAttribs )
289 if( nElement == XLS_TOKEN( top10 ) )
291 mfValue = rAttribs.getDouble( XML_val, 0.0 );
292 mbTop = rAttribs.getBool( XML_top, true );
293 mbPercent = rAttribs.getBool( XML_percent, false );
297 void Top10Filter::importRecord( sal_Int32 nRecId, SequenceInputStream& rStrm )
299 if( nRecId == BIFF12_ID_TOP10FILTER )
301 sal_uInt8 nFlags;
302 nFlags = rStrm.readuChar();
303 mfValue = rStrm.readDouble();
304 mbTop = getFlag( nFlags, BIFF12_TOP10FILTER_TOP );
305 mbPercent = getFlag( nFlags, BIFF12_TOP10FILTER_PERCENT );
309 ApiFilterSettings Top10Filter::finalizeImport( sal_Int32 /*nMaxCount*/ )
311 sal_Int32 nOperator = mbTop ?
312 (mbPercent ? FilterOperator2::TOP_PERCENT : FilterOperator2::TOP_VALUES) :
313 (mbPercent ? FilterOperator2::BOTTOM_PERCENT : FilterOperator2::BOTTOM_VALUES);
314 ApiFilterSettings aSettings;
315 aSettings.appendField( true, nOperator, mfValue );
316 return aSettings;
319 FilterCriterionModel::FilterCriterionModel() :
320 mnOperator( XML_equal ),
321 mnDataType( BIFF_FILTER_DATATYPE_NONE ),
322 mnStrLen( 0 )
326 void FilterCriterionModel::setBiffOperator( sal_uInt8 nOperator )
328 static const sal_Int32 spnOperators[] = { XML_TOKEN_INVALID,
329 XML_lessThan, XML_equal, XML_lessThanOrEqual, XML_greaterThan, XML_notEqual, XML_greaterThanOrEqual };
330 mnOperator = STATIC_ARRAY_SELECT( spnOperators, nOperator, XML_TOKEN_INVALID );
333 void FilterCriterionModel::readBiffData( SequenceInputStream& rStrm )
335 sal_uInt8 nOperator;
336 mnDataType = rStrm.readuChar();
337 nOperator = rStrm.readuChar();
338 setBiffOperator( nOperator );
340 switch( mnDataType )
342 case BIFF_FILTER_DATATYPE_DOUBLE:
343 maValue <<= rStrm.readDouble();
344 break;
345 case BIFF_FILTER_DATATYPE_STRING:
347 rStrm.skip( 8 );
348 OUString aValue = BiffHelper::readString( rStrm ).trim();
349 if( !aValue.isEmpty() )
350 maValue <<= aValue;
352 break;
353 case BIFF_FILTER_DATATYPE_BOOLEAN:
354 maValue <<= (rStrm.readuInt8() != 0);
355 rStrm.skip( 7 );
356 break;
357 case BIFF_FILTER_DATATYPE_EMPTY:
358 rStrm.skip( 8 );
359 if( mnOperator == XML_equal )
360 maValue <<= OUString();
361 break;
362 case BIFF_FILTER_DATATYPE_NOTEMPTY:
363 rStrm.skip( 8 );
364 if( mnOperator == XML_notEqual )
365 maValue <<= OUString();
366 break;
367 default:
368 OSL_ENSURE( false, "FilterCriterionModel::readBiffData - unexpected data type" );
369 rStrm.skip( 8 );
373 CustomFilter::CustomFilter( const WorkbookHelper& rHelper ) :
374 FilterSettingsBase( rHelper ),
375 mbAnd( false )
379 void CustomFilter::importAttribs( sal_Int32 nElement, const AttributeList& rAttribs )
381 switch( nElement )
383 case XLS_TOKEN( customFilters ):
384 mbAnd = rAttribs.getBool( XML_and, false );
385 break;
387 case XLS_TOKEN( customFilter ):
389 FilterCriterionModel aCriterion;
390 aCriterion.mnOperator = rAttribs.getToken( XML_operator, XML_equal );
391 OUString aValue = rAttribs.getXString( XML_val, OUString() ).trim();
392 if( (aCriterion.mnOperator == XML_equal) || (aCriterion.mnOperator == XML_notEqual) || (!aValue.isEmpty()) )
393 aCriterion.maValue <<= aValue;
394 appendCriterion( aCriterion );
396 break;
400 void CustomFilter::importRecord( sal_Int32 nRecId, SequenceInputStream& rStrm )
402 switch( nRecId )
404 case BIFF12_ID_CUSTOMFILTERS:
405 mbAnd = rStrm.readInt32() == 0;
406 break;
408 case BIFF12_ID_CUSTOMFILTER:
410 FilterCriterionModel aCriterion;
411 aCriterion.readBiffData( rStrm );
412 appendCriterion( aCriterion );
414 break;
418 ApiFilterSettings CustomFilter::finalizeImport( sal_Int32 /*nMaxCount*/ )
420 ApiFilterSettings aSettings;
421 OSL_ENSURE( maCriteria.size() <= 2, "CustomFilter::finalizeImport - too many filter criteria" );
422 for( FilterCriterionVector::iterator aIt = maCriteria.begin(), aEnd = maCriteria.end(); aIt != aEnd; ++aIt )
424 // first extract the filter operator
425 sal_Int32 nOperator = 0;
426 bool bValidOperator = lclGetApiOperatorFromToken( nOperator, aIt->mnOperator );
427 if( bValidOperator )
429 if( aIt->maValue.has< OUString >() )
431 // string argument
432 OUString aValue;
433 aIt->maValue >>= aValue;
434 // check for 'empty', 'contains', 'begins with', or 'ends with' text filters
435 bool bEqual = nOperator == FilterOperator2::EQUAL;
436 bool bNotEqual = nOperator == FilterOperator2::NOT_EQUAL;
437 if( bEqual || bNotEqual )
439 if( aValue.isEmpty() )
441 // empty comparison string: create empty/not empty filters
442 nOperator = bNotEqual ? FilterOperator2::NOT_EMPTY : FilterOperator2::EMPTY;
444 else
446 // compare to something: try to find begins/ends/contains
447 bool bHasLeadingAsterisk = lclTrimLeadingAsterisks( aValue );
448 bool bHasTrailingAsterisk = lclTrimTrailingAsterisks( aValue );
449 // just '***' matches everything, do not create a filter field
450 bValidOperator = !aValue.isEmpty();
451 if( bValidOperator )
453 if( bHasLeadingAsterisk && bHasTrailingAsterisk )
454 nOperator = bNotEqual ? FilterOperator2::DOES_NOT_CONTAIN : FilterOperator2::CONTAINS;
455 else if( bHasLeadingAsterisk )
456 nOperator = bNotEqual ? FilterOperator2::DOES_NOT_END_WITH : FilterOperator2::ENDS_WITH;
457 else if( bHasTrailingAsterisk )
458 nOperator = bNotEqual ? FilterOperator2::DOES_NOT_BEGIN_WITH : FilterOperator2::BEGINS_WITH;
459 // else: no asterisks, stick to equal/not equal
464 if( bValidOperator )
466 // if wildcards are present, require RE mode, otherwise keep don't care state
467 if( lclConvertWildcardsToRegExp( aValue ) )
468 aSettings.mobNeedsRegExp = true;
469 // create a new UNO API filter field
470 aSettings.appendField( mbAnd, nOperator, aValue );
473 else if( aIt->maValue.has< double >() )
475 // floating-point argument
476 double fValue = 0.0;
477 aIt->maValue >>= fValue;
478 aSettings.appendField( mbAnd, nOperator, fValue );
482 return aSettings;
485 void CustomFilter::appendCriterion( const FilterCriterionModel& rCriterion )
487 if( (rCriterion.mnOperator != XML_TOKEN_INVALID) && rCriterion.maValue.hasValue() )
488 maCriteria.push_back( rCriterion );
491 FilterColumn::FilterColumn( const WorkbookHelper& rHelper ) :
492 WorkbookHelper( rHelper ),
493 mnColId( -1 ),
494 mbHiddenButton( false ),
495 mbShowButton( true )
499 void FilterColumn::importFilterColumn( const AttributeList& rAttribs )
501 mnColId = rAttribs.getInteger( XML_colId, -1 );
502 mbHiddenButton = rAttribs.getBool( XML_hiddenButton, false );
503 mbShowButton = rAttribs.getBool( XML_showButton, true );
506 void FilterColumn::importFilterColumn( SequenceInputStream& rStrm )
508 sal_uInt16 nFlags;
509 mnColId = rStrm.readInt32();
510 nFlags = rStrm.readuInt16();
511 mbHiddenButton = getFlag( nFlags, BIFF12_FILTERCOLUMN_HIDDENBUTTON );
512 mbShowButton = getFlag( nFlags, BIFF12_FILTERCOLUMN_SHOWBUTTON );
515 ApiFilterSettings FilterColumn::finalizeImport( sal_Int32 nMaxCount )
517 ApiFilterSettings aSettings;
518 if( (0 <= mnColId) && mxSettings.get() )
520 // filter settings object creates a sequence of filter fields
521 aSettings = mxSettings->finalizeImport( nMaxCount );
522 // add column index to all filter fields
523 for( ApiFilterSettings::FilterFieldVector::iterator aIt = aSettings.maFilterFields.begin(), aEnd = aSettings.maFilterFields.end(); aIt != aEnd; ++aIt )
524 aIt->Field = mnColId;
526 return aSettings;
529 AutoFilter::AutoFilter( const WorkbookHelper& rHelper ) :
530 WorkbookHelper( rHelper )
534 void AutoFilter::importAutoFilter( const AttributeList& rAttribs, sal_Int16 nSheet )
536 OUString aRangeStr = rAttribs.getString( XML_ref, OUString() );
537 AddressConverter::convertToCellRangeUnchecked( maRange, aRangeStr, nSheet );
540 void AutoFilter::importAutoFilter( SequenceInputStream& rStrm, sal_Int16 nSheet )
542 BinRange aBinRange;
543 rStrm >> aBinRange;
544 AddressConverter::convertToCellRangeUnchecked( maRange, aBinRange, nSheet );
547 FilterColumn& AutoFilter::createFilterColumn()
549 FilterColumnVector::value_type xFilterColumn( new FilterColumn( *this ) );
550 maFilterColumns.push_back( xFilterColumn );
551 return *xFilterColumn;
554 void AutoFilter::finalizeImport( const Reference<XSheetFilterDescriptor3>& rxFilterDesc )
556 if( rxFilterDesc.is() )
558 // set some common properties for the auto filter range
559 PropertySet aDescProps( rxFilterDesc );
560 aDescProps.setProperty( PROP_IsCaseSensitive, false );
561 aDescProps.setProperty( PROP_SkipDuplicates, false );
562 aDescProps.setProperty( PROP_Orientation, TableOrientation_ROWS );
563 aDescProps.setProperty( PROP_ContainsHeader, true );
564 aDescProps.setProperty( PROP_CopyOutputData, false );
566 // maximum number of UNO API filter fields
567 sal_Int32 nMaxCount = 0;
568 aDescProps.getProperty( nMaxCount, PROP_MaxFieldCount );
569 OSL_ENSURE( nMaxCount > 0, "AutoFilter::finalizeImport - invalid maximum filter field count" );
571 // resulting list of all UNO API filter fields
572 ::std::vector<TableFilterField3> aFilterFields;
574 // track if columns require to enable or disable regular expressions
575 OptValue< bool > obNeedsRegExp;
577 /* Track whether the filter fields of the first filter column are
578 connected with 'or'. In this case, other filter fields cannot be
579 inserted without altering the result of the entire filter, due to
580 Calc's precedence for the 'and' connection operator. Example:
581 Excel's filter conditions 'A1 and (B1 or B2) and C1' where B1 and
582 B2 belong to filter column B, will be evaluated by Calc as
583 '(A1 and B1) or (B2 and C1)'. */
584 bool bHasOrConnection = false;
586 // process all filter column objects, exit when 'or' connection exists
587 for( FilterColumnVector::iterator aIt = maFilterColumns.begin(), aEnd = maFilterColumns.end(); !bHasOrConnection && (aIt != aEnd); ++aIt )
589 // the filter settings object creates a list of filter fields
590 ApiFilterSettings aSettings = (*aIt)->finalizeImport( nMaxCount );
591 ApiFilterSettings::FilterFieldVector& rColumnFields = aSettings.maFilterFields;
593 // new total number of filter fields
594 sal_Int32 nNewCount = static_cast< sal_Int32 >( aFilterFields.size() + rColumnFields.size() );
596 /* Check whether mode for regular expressions is compatible with
597 the global mode in obNeedsRegExp. If either one is still in
598 don't-care state, all is fine. If both are set, they must be
599 equal. */
600 bool bRegExpCompatible = !obNeedsRegExp || !aSettings.mobNeedsRegExp || (obNeedsRegExp.get() == aSettings.mobNeedsRegExp.get());
602 // check whether fields are connected by 'or' (see comments above).
603 if( rColumnFields.size() >= 2 )
604 for( ApiFilterSettings::FilterFieldVector::iterator aSIt = rColumnFields.begin() + 1, aSEnd = rColumnFields.end(); !bHasOrConnection && (aSIt != aSEnd); ++aSIt )
605 bHasOrConnection = aSIt->Connection == FilterConnection_OR;
607 /* Skip the column filter, if no filter fields have been created,
608 if the number of new filter fields would exceed the total limit
609 of filter fields, or if the mode for regular expressions of the
610 filter column does not fit. */
611 if( !rColumnFields.empty() && (nNewCount <= nMaxCount) && bRegExpCompatible )
613 /* Add 'and' connection to the first filter field to connect
614 it to the existing filter fields of other columns. */
615 rColumnFields[ 0 ].Connection = FilterConnection_AND;
617 // insert the new filter fields
618 aFilterFields.insert( aFilterFields.end(), rColumnFields.begin(), rColumnFields.end() );
620 // update the regular expressions mode
621 obNeedsRegExp.assignIfUsed( aSettings.mobNeedsRegExp );
625 // insert all filter fields to the filter descriptor
626 if( !aFilterFields.empty() )
627 rxFilterDesc->setFilterFields3( ContainerHelper::vectorToSequence( aFilterFields ) );
629 // regular expressions
630 bool bUseRegExp = obNeedsRegExp.get( false );
631 aDescProps.setProperty( PROP_UseRegularExpressions, bUseRegExp );
635 AutoFilterBuffer::AutoFilterBuffer( const WorkbookHelper& rHelper ) :
636 WorkbookHelper( rHelper )
640 AutoFilter& AutoFilterBuffer::createAutoFilter()
642 AutoFilterVector::value_type xAutoFilter( new AutoFilter( *this ) );
643 maAutoFilters.push_back( xAutoFilter );
644 return *xAutoFilter;
647 void AutoFilterBuffer::finalizeImport( sal_Int16 nSheet )
649 // rely on existence of the defined name '_FilterDatabase' containing the range address of the filtered area
650 if( const DefinedName* pFilterDBName = getDefinedNames().getByBuiltinId( BIFF_DEFNAME_FILTERDATABASE, nSheet ).get() )
652 CellRangeAddress aFilterRange;
653 if( pFilterDBName->getAbsoluteRange( aFilterRange ) && (aFilterRange.Sheet == nSheet) )
655 // use the same name for the database range as used for the defined name '_FilterDatabase'
656 Reference< XDatabaseRange > xDatabaseRange = createUnnamedDatabaseRangeObject( aFilterRange );
657 // first, try to create an auto filter
658 bool bHasAutoFilter = finalizeImport( xDatabaseRange );
659 // no success: try to create an advanced filter
660 if( !bHasAutoFilter && xDatabaseRange.is() )
662 // the built-in defined name 'Criteria' must exist
663 if( const DefinedName* pCriteriaName = getDefinedNames().getByBuiltinId( BIFF_DEFNAME_CRITERIA, nSheet ).get() )
665 CellRangeAddress aCriteriaRange;
666 if( pCriteriaName->getAbsoluteRange( aCriteriaRange ) )
668 // set some common properties for the filter descriptor
669 PropertySet aDescProps( xDatabaseRange->getFilterDescriptor() );
670 aDescProps.setProperty( PROP_IsCaseSensitive, false );
671 aDescProps.setProperty( PROP_SkipDuplicates, false );
672 aDescProps.setProperty( PROP_Orientation, TableOrientation_ROWS );
673 aDescProps.setProperty( PROP_ContainsHeader, true );
674 // criteria range may contain wildcards, but these are incompatible with REs
675 aDescProps.setProperty( PROP_UseRegularExpressions, false );
677 // position of output data (if built-in defined name 'Extract' exists)
678 DefinedNameRef xExtractName = getDefinedNames().getByBuiltinId( BIFF_DEFNAME_EXTRACT, nSheet );
679 CellRangeAddress aOutputRange;
680 bool bHasOutputRange = xExtractName.get() && xExtractName->getAbsoluteRange( aOutputRange );
681 aDescProps.setProperty( PROP_CopyOutputData, bHasOutputRange );
682 if( bHasOutputRange )
684 aDescProps.setProperty( PROP_SaveOutputPosition, true );
685 aDescProps.setProperty( PROP_OutputPosition, CellAddress( aOutputRange.Sheet, aOutputRange.StartColumn, aOutputRange.StartRow ) );
688 /* Properties of the database range (must be set after
689 modifying properties of the filter descriptor,
690 otherwise the 'FilterCriteriaSource' property gets
691 deleted). */
692 PropertySet aRangeProps( xDatabaseRange );
693 aRangeProps.setProperty( PROP_AutoFilter, false );
694 aRangeProps.setProperty( PROP_FilterCriteriaSource, aCriteriaRange );
702 bool AutoFilterBuffer::finalizeImport( const Reference< XDatabaseRange >& rxDatabaseRange )
704 AutoFilter* pAutoFilter = getActiveAutoFilter();
705 if( pAutoFilter && rxDatabaseRange.is() ) try
707 // the property 'AutoFilter' enables the drop-down buttons
708 PropertySet aRangeProps( rxDatabaseRange );
709 aRangeProps.setProperty( PROP_AutoFilter, true );
710 // convert filter settings using the filter descriptor of the database range
711 Reference< XSheetFilterDescriptor3 > xFilterDesc( rxDatabaseRange->getFilterDescriptor(), UNO_QUERY_THROW );
712 pAutoFilter->finalizeImport( xFilterDesc );
713 // return true to indicate enabled autofilter
714 return true;
716 catch( Exception& )
719 return false;
722 AutoFilter* AutoFilterBuffer::getActiveAutoFilter()
724 // Excel expects not more than one auto filter per sheet or table
725 OSL_ENSURE( maAutoFilters.size() <= 1, "AutoFilterBuffer::getActiveAutoFilter - too many auto filters" );
726 // stick to the last imported auto filter
727 return maAutoFilters.empty() ? 0 : maAutoFilters.back().get();
730 } // namespace xls
731 } // namespace oox
733 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */