LibreOffice Module sc (master)  1
autofilterbuffer.cxx
Go to the documentation of this file.
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/beans/XPropertySet.hpp>
23 #include <com/sun/star/sheet/FilterConnection.hpp>
24 #include <com/sun/star/sheet/FilterOperator2.hpp>
25 #include <com/sun/star/sheet/TableFilterField3.hpp>
26 #include <com/sun/star/sheet/XDatabaseRange.hpp>
27 #include <com/sun/star/sheet/XSheetFilterDescriptor3.hpp>
28 #include <com/sun/star/table/TableOrientation.hpp>
29 #include <com/sun/star/table/CellAddress.hpp>
30 #include <rtl/ustrbuf.hxx>
31 #include <osl/diagnose.h>
36 #include <oox/token/namespaces.hxx>
37 #include <oox/token/properties.hxx>
38 #include <oox/token/tokens.hxx>
39 #include <addressconverter.hxx>
40 #include <defnamesbuffer.hxx>
41 #include <biffhelper.hxx>
42 #include <document.hxx>
43 #include <dbdata.hxx>
44 #include <sortparam.hxx>
45 #include <userlist.hxx>
46 
47 namespace oox::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 namespace {
54 
55 const sal_uInt8 BIFF12_TOP10FILTER_TOP = 0x01;
56 const sal_uInt8 BIFF12_TOP10FILTER_PERCENT = 0x02;
57 
58 const sal_uInt16 BIFF12_FILTERCOLUMN_HIDDENBUTTON = 0x0001;
59 const sal_uInt16 BIFF12_FILTERCOLUMN_SHOWBUTTON = 0x0002;
60 
61 const sal_uInt8 BIFF_FILTER_DATATYPE_NONE = 0;
62 const sal_uInt8 BIFF_FILTER_DATATYPE_DOUBLE = 4;
63 const sal_uInt8 BIFF_FILTER_DATATYPE_STRING = 6;
64 const sal_uInt8 BIFF_FILTER_DATATYPE_BOOLEAN = 8;
65 const sal_uInt8 BIFF_FILTER_DATATYPE_EMPTY = 12;
66 const sal_uInt8 BIFF_FILTER_DATATYPE_NOTEMPTY = 14;
67 
68 bool lclGetApiOperatorFromToken( sal_Int32& rnApiOperator, sal_Int32 nToken )
69 {
70  switch( nToken )
71  {
72  case XML_lessThan: rnApiOperator = FilterOperator2::NOT_EQUAL; return true;
73  case XML_equal: rnApiOperator = FilterOperator2::EQUAL; return true;
74  case XML_lessThanOrEqual: rnApiOperator = FilterOperator2::LESS_EQUAL; return true;
75  case XML_greaterThan: rnApiOperator = FilterOperator2::GREATER; return true;
76  case XML_notEqual: rnApiOperator = FilterOperator2::NOT_EQUAL; return true;
77  case XML_greaterThanOrEqual: rnApiOperator = FilterOperator2::GREATER_EQUAL; return true;
78  }
79  return false;
80 }
81 
84 bool lclTrimLeadingAsterisks( OUString& rValue )
85 {
86  sal_Int32 nLength = rValue.getLength();
87  sal_Int32 nPos = 0;
88  while( (nPos < nLength) && (rValue[ nPos ] == '*') )
89  ++nPos;
90  if( nPos > 0 )
91  {
92  rValue = rValue.copy( nPos );
93  return true;
94  }
95  return false;
96 }
97 
100 bool lclTrimTrailingAsterisks( OUString& rValue )
101 {
102  sal_Int32 nLength = rValue.getLength();
103  sal_Int32 nPos = nLength;
104  while( (nPos > 0) && (rValue[ nPos - 1 ] == '*') )
105  --nPos;
106  if( nPos < nLength )
107  {
108  rValue = rValue.copy( 0, nPos );
109  return true;
110  }
111  return false;
112 }
113 
117 bool lclConvertWildcardsToRegExp( OUString& rValue )
118 {
119  // check existence of the wildcard characters '*' and '?'
120  if( !rValue.isEmpty() && ((rValue.indexOf( '*' ) >= 0) || (rValue.indexOf( '?' ) >= 0)) )
121  {
122  OUStringBuffer aBuffer;
123  aBuffer.ensureCapacity( rValue.getLength() + 5 );
124  const sal_Unicode* pcChar = rValue.getStr();
125  const sal_Unicode* pcEnd = pcChar + rValue.getLength();
126  for( ; pcChar < pcEnd; ++pcChar )
127  {
128  switch( *pcChar )
129  {
130  case '?':
131  aBuffer.append( '.' );
132  break;
133  case '*':
134  aBuffer.append( '.' ).append( '*' );
135  break;
136  case '\\': case '.': case '|': case '(': case ')': case '^': case '$':
137  // quote RE meta characters
138  aBuffer.append( '\\' ).append( *pcChar );
139  break;
140  default:
141  aBuffer.append( *pcChar );
142  }
143  }
144  rValue = aBuffer.makeStringAndClear();
145  return true;
146  }
147  return false;
148 }
149 
150 } // namespace
151 
153 {
154 }
155 
156 void ApiFilterSettings::appendField( bool bAnd, sal_Int32 nOperator, double fValue )
157 {
158  maFilterFields.emplace_back();
159  TableFilterField3& rFilterField = maFilterFields.back();
160  rFilterField.Connection = bAnd ? FilterConnection_AND : FilterConnection_OR;
161  rFilterField.Operator = nOperator;
162  rFilterField.Values.realloc(1);
163  rFilterField.Values[0].IsNumeric = true;
164  rFilterField.Values[0].NumericValue = fValue;
165 }
166 
167 void ApiFilterSettings::appendField( bool bAnd, sal_Int32 nOperator, const OUString& rValue )
168 {
169  maFilterFields.emplace_back();
170  TableFilterField3& rFilterField = maFilterFields.back();
171  rFilterField.Connection = bAnd ? FilterConnection_AND : FilterConnection_OR;
172  rFilterField.Operator = nOperator;
173  rFilterField.Values.realloc(1);
174  rFilterField.Values[0].IsNumeric = false;
175  rFilterField.Values[0].StringValue = rValue;
176 }
177 
178 void ApiFilterSettings::appendField( bool bAnd, const std::vector<OUString>& rValues )
179 {
180  maFilterFields.emplace_back();
181  TableFilterField3& rFilterField = maFilterFields.back();
182  rFilterField.Connection = bAnd ? FilterConnection_AND : FilterConnection_OR;
183  rFilterField.Operator = FilterOperator2::EQUAL;
184  size_t n = rValues.size();
185  rFilterField.Values.realloc(n);
186  for (size_t i = 0; i < n; ++i)
187  {
188  rFilterField.Values[i].IsNumeric = false;
189  rFilterField.Values[i].StringValue = rValues[i];
190  }
191 }
192 
194  WorkbookHelper( rHelper )
195 {
196 }
197 
198 void FilterSettingsBase::importAttribs( sal_Int32 /*nElement*/, const AttributeList& /*rAttribs*/ )
199 {
200 }
201 
202 void FilterSettingsBase::importRecord( sal_Int32 /*nRecId*/, SequenceInputStream& /*rStrm*/ )
203 {
204 }
205 
207 {
208  return ApiFilterSettings();
209 }
210 
212  FilterSettingsBase( rHelper ),
213  mnCalendarType( XML_none ),
214  mbShowBlank( false )
215 {
216 }
217 
218 void DiscreteFilter::importAttribs( sal_Int32 nElement, const AttributeList& rAttribs )
219 {
220  switch( nElement )
221  {
222  case XLS_TOKEN( filters ):
223  mnCalendarType = rAttribs.getToken( XML_calendarType, XML_none );
224  mbShowBlank = rAttribs.getBool( XML_blank, false );
225  break;
226 
227  case XLS_TOKEN( filter ):
228  {
229  OUString aValue = rAttribs.getXString( XML_val, OUString() );
230  if( !aValue.isEmpty() )
231  maValues.push_back( aValue );
232  }
233  break;
234  }
235 }
236 
237 void DiscreteFilter::importRecord( sal_Int32 nRecId, SequenceInputStream& rStrm )
238 {
239  switch( nRecId )
240  {
242  {
243  sal_Int32 nShowBlank, nCalendarType;
244  nShowBlank = rStrm.readInt32();
245  nCalendarType = rStrm.readInt32();
246 
247  static const sal_Int32 spnCalendarTypes[] = {
248  XML_none, XML_gregorian, XML_gregorianUs, XML_japan, XML_taiwan, XML_korea, XML_hijri, XML_thai, XML_hebrew,
249  XML_gregorianMeFrench, XML_gregorianArabic, XML_gregorianXlitEnglish, XML_gregorianXlitFrench };
250  mnCalendarType = STATIC_ARRAY_SELECT( spnCalendarTypes, nCalendarType, XML_none );
251  mbShowBlank = nShowBlank != 0;
252  }
253  break;
254 
256  {
257  OUString aValue = BiffHelper::readString( rStrm );
258  if( !aValue.isEmpty() )
259  maValues.push_back( aValue );
260  }
261  break;
262  }
263 }
264 
266 {
267  ApiFilterSettings aSettings;
268  if( static_cast< sal_Int32 >( maValues.size() ) <= nMaxCount )
269  {
270  aSettings.maFilterFields.reserve( maValues.size() );
271 
272  // insert all filter values
273  aSettings.appendField( true, maValues );
274 
275  // extra field for 'show empty'
276  if( mbShowBlank )
277  aSettings.appendField( false, FilterOperator2::EMPTY, OUString() );
278 
279  /* Require disabled regular expressions, filter entries may contain
280  any RE meta characters. */
281  if( !maValues.empty() )
282  aSettings.mobNeedsRegExp = false;
283  }
284  return aSettings;
285 }
286 
288  FilterSettingsBase( rHelper ),
289  mfValue( 0.0 ),
290  mbTop( true ),
291  mbPercent( false )
292 {
293 }
294 
295 void Top10Filter::importAttribs( sal_Int32 nElement, const AttributeList& rAttribs )
296 {
297  if( nElement == XLS_TOKEN( top10 ) )
298  {
299  mfValue = rAttribs.getDouble( XML_val, 0.0 );
300  mbTop = rAttribs.getBool( XML_top, true );
301  mbPercent = rAttribs.getBool( XML_percent, false );
302  }
303 }
304 
305 void Top10Filter::importRecord( sal_Int32 nRecId, SequenceInputStream& rStrm )
306 {
307  if( nRecId == BIFF12_ID_TOP10FILTER )
308  {
309  sal_uInt8 nFlags;
310  nFlags = rStrm.readuChar();
311  mfValue = rStrm.readDouble();
312  mbTop = getFlag( nFlags, BIFF12_TOP10FILTER_TOP );
313  mbPercent = getFlag( nFlags, BIFF12_TOP10FILTER_PERCENT );
314  }
315 }
316 
318 {
319  sal_Int32 nOperator = mbTop ?
320  (mbPercent ? FilterOperator2::TOP_PERCENT : FilterOperator2::TOP_VALUES) :
321  (mbPercent ? FilterOperator2::BOTTOM_PERCENT : FilterOperator2::BOTTOM_VALUES);
322  ApiFilterSettings aSettings;
323  aSettings.appendField( true, nOperator, mfValue );
324  return aSettings;
325 }
326 
328  mnOperator( XML_equal ),
329  mnDataType( BIFF_FILTER_DATATYPE_NONE )
330 {
331 }
332 
334 {
335  static const sal_Int32 spnOperators[] = { XML_TOKEN_INVALID,
336  XML_lessThan, XML_equal, XML_lessThanOrEqual, XML_greaterThan, XML_notEqual, XML_greaterThanOrEqual };
337  mnOperator = STATIC_ARRAY_SELECT( spnOperators, nOperator, XML_TOKEN_INVALID );
338 }
339 
341 {
342  sal_uInt8 nOperator;
343  mnDataType = rStrm.readuChar();
344  nOperator = rStrm.readuChar();
345  setBiffOperator( nOperator );
346 
347  switch( mnDataType )
348  {
349  case BIFF_FILTER_DATATYPE_DOUBLE:
350  maValue <<= rStrm.readDouble();
351  break;
352  case BIFF_FILTER_DATATYPE_STRING:
353  {
354  rStrm.skip( 8 );
355  OUString aValue = BiffHelper::readString( rStrm ).trim();
356  if( !aValue.isEmpty() )
357  maValue <<= aValue;
358  }
359  break;
360  case BIFF_FILTER_DATATYPE_BOOLEAN:
361  maValue <<= (rStrm.readuInt8() != 0);
362  rStrm.skip( 7 );
363  break;
364  case BIFF_FILTER_DATATYPE_EMPTY:
365  rStrm.skip( 8 );
366  if( mnOperator == XML_equal )
367  maValue <<= OUString();
368  break;
369  case BIFF_FILTER_DATATYPE_NOTEMPTY:
370  rStrm.skip( 8 );
371  if( mnOperator == XML_notEqual )
372  maValue <<= OUString();
373  break;
374  default:
375  OSL_ENSURE( false, "FilterCriterionModel::readBiffData - unexpected data type" );
376  rStrm.skip( 8 );
377  }
378 }
379 
381  FilterSettingsBase( rHelper ),
382  mbAnd( false )
383 {
384 }
385 
386 void CustomFilter::importAttribs( sal_Int32 nElement, const AttributeList& rAttribs )
387 {
388  switch( nElement )
389  {
390  case XLS_TOKEN( customFilters ):
391  mbAnd = rAttribs.getBool( XML_and, false );
392  break;
393 
394  case XLS_TOKEN( customFilter ):
395  {
396  FilterCriterionModel aCriterion;
397  aCriterion.mnOperator = rAttribs.getToken( XML_operator, XML_equal );
398  OUString aValue = rAttribs.getXString( XML_val, OUString() ).trim();
399  if( (aCriterion.mnOperator == XML_equal) || (aCriterion.mnOperator == XML_notEqual) || (!aValue.isEmpty()) )
400  aCriterion.maValue <<= aValue;
401  appendCriterion( aCriterion );
402  }
403  break;
404  }
405 }
406 
407 void CustomFilter::importRecord( sal_Int32 nRecId, SequenceInputStream& rStrm )
408 {
409  switch( nRecId )
410  {
412  mbAnd = rStrm.readInt32() == 0;
413  break;
414 
416  {
417  FilterCriterionModel aCriterion;
418  aCriterion.readBiffData( rStrm );
419  appendCriterion( aCriterion );
420  }
421  break;
422  }
423 }
424 
426 {
427  ApiFilterSettings aSettings;
428  OSL_ENSURE( maCriteria.size() <= 2, "CustomFilter::finalizeImport - too many filter criteria" );
429  for( const auto& rCriterion : maCriteria )
430  {
431  // first extract the filter operator
432  sal_Int32 nOperator = 0;
433  bool bValidOperator = lclGetApiOperatorFromToken( nOperator, rCriterion.mnOperator );
434  if( bValidOperator )
435  {
436  if( rCriterion.maValue.has< OUString >() )
437  {
438  // string argument
439  OUString aValue;
440  rCriterion.maValue >>= aValue;
441  // check for 'empty', 'contains', 'begins with', or 'ends with' text filters
442  bool bEqual = nOperator == FilterOperator2::EQUAL;
443  bool bNotEqual = nOperator == FilterOperator2::NOT_EQUAL;
444  if( bEqual || bNotEqual )
445  {
446  if( aValue.isEmpty() )
447  {
448  // empty comparison string: create empty/not empty filters
449  nOperator = bNotEqual ? FilterOperator2::NOT_EMPTY : FilterOperator2::EMPTY;
450  }
451  else
452  {
453  // compare to something: try to find begins/ends/contains
454  bool bHasLeadingAsterisk = lclTrimLeadingAsterisks( aValue );
455  bool bHasTrailingAsterisk = lclTrimTrailingAsterisks( aValue );
456  // just '***' matches everything, do not create a filter field
457  bValidOperator = !aValue.isEmpty();
458  if( bValidOperator )
459  {
460  if( bHasLeadingAsterisk && bHasTrailingAsterisk )
461  nOperator = bNotEqual ? FilterOperator2::DOES_NOT_CONTAIN : FilterOperator2::CONTAINS;
462  else if( bHasLeadingAsterisk )
463  nOperator = bNotEqual ? FilterOperator2::DOES_NOT_END_WITH : FilterOperator2::ENDS_WITH;
464  else if( bHasTrailingAsterisk )
465  nOperator = bNotEqual ? FilterOperator2::DOES_NOT_BEGIN_WITH : FilterOperator2::BEGINS_WITH;
466  // else: no asterisks, stick to equal/not equal
467  }
468  }
469  }
470 
471  if( bValidOperator )
472  {
473  // if wildcards are present, require RE mode, otherwise keep don't care state
474  if( lclConvertWildcardsToRegExp( aValue ) )
475  aSettings.mobNeedsRegExp = true;
476  // create a new UNO API filter field
477  aSettings.appendField( mbAnd, nOperator, aValue );
478  }
479  }
480  else if( rCriterion.maValue.has< double >() )
481  {
482  // floating-point argument
483  double fValue = 0.0;
484  rCriterion.maValue >>= fValue;
485  aSettings.appendField( mbAnd, nOperator, fValue );
486  }
487  }
488  }
489  return aSettings;
490 }
491 
493 {
494  if( (rCriterion.mnOperator != XML_TOKEN_INVALID) && rCriterion.maValue.hasValue() )
495  maCriteria.push_back( rCriterion );
496 }
497 
499  WorkbookHelper( rHelper ),
500  mnColId( -1 ),
501  mbHiddenButton( false ),
502  mbShowButton( true )
503 {
504 }
505 
507 {
508  mnColId = rAttribs.getInteger( XML_colId, -1 );
509  mbHiddenButton = rAttribs.getBool( XML_hiddenButton, false );
510  mbShowButton = rAttribs.getBool( XML_showButton, true );
511 }
512 
514 {
515  sal_uInt16 nFlags;
516  mnColId = rStrm.readInt32();
517  nFlags = rStrm.readuInt16();
518  mbHiddenButton = getFlag( nFlags, BIFF12_FILTERCOLUMN_HIDDENBUTTON );
519  mbShowButton = getFlag( nFlags, BIFF12_FILTERCOLUMN_SHOWBUTTON );
520 }
521 
523 {
524  ApiFilterSettings aSettings;
525  if( (0 <= mnColId) && mxSettings )
526  {
527  // filter settings object creates a sequence of filter fields
528  aSettings = mxSettings->finalizeImport( nMaxCount );
529  // add column index to all filter fields
530  for( auto& rFilterField : aSettings.maFilterFields )
531  rFilterField.Field = mnColId;
532  }
533  return aSettings;
534 }
535 
536 // SortCondition
537 
539  WorkbookHelper( rHelper ),
540  mbDescending( false )
541 {
542 }
543 
544 void SortCondition::importSortCondition( const AttributeList& rAttribs, sal_Int16 nSheet )
545 {
546  OUString aRangeStr = rAttribs.getString( XML_ref, OUString() );
548 
549  maSortCustomList = rAttribs.getString( XML_customList, OUString() );
550  mbDescending = rAttribs.getBool( XML_descending, false );
551 }
552 
553 // AutoFilter
554 
556  WorkbookHelper( rHelper )
557 {
558 }
559 
560 void AutoFilter::importAutoFilter( const AttributeList& rAttribs, sal_Int16 nSheet )
561 {
562  OUString aRangeStr = rAttribs.getString( XML_ref, OUString() );
564 }
565 
566 void AutoFilter::importAutoFilter( SequenceInputStream& rStrm, sal_Int16 nSheet )
567 {
568  BinRange aBinRange;
569  rStrm >> aBinRange;
571 }
572 
573 void AutoFilter::importSortState( const AttributeList& rAttribs, sal_Int16 nSheet )
574 {
575  OUString aRangeStr = rAttribs.getString( XML_ref, OUString() );
577 }
578 
580 {
581  FilterColumnVector::value_type xFilterColumn = std::make_shared<FilterColumn>( *this );
582  maFilterColumns.push_back( xFilterColumn );
583  return *xFilterColumn;
584 }
585 
587 {
588  SortConditionVector::value_type xSortCondition = std::make_shared<SortCondition>( *this );
589  maSortConditions.push_back( xSortCondition );
590  return *xSortCondition;
591 }
592 
593 void AutoFilter::finalizeImport( const Reference< XDatabaseRange >& rxDatabaseRange, sal_Int16 nSheet )
594 {
595  // convert filter settings using the filter descriptor of the database range
596  const Reference<XSheetFilterDescriptor3> xFilterDesc( rxDatabaseRange->getFilterDescriptor(), UNO_QUERY_THROW );
597  if( !xFilterDesc.is() )
598  return;
599 
600  // set some common properties for the auto filter range
601  PropertySet aDescProps( xFilterDesc );
602  aDescProps.setProperty( PROP_IsCaseSensitive, false );
603  aDescProps.setProperty( PROP_SkipDuplicates, false );
604  aDescProps.setProperty( PROP_Orientation, TableOrientation_ROWS );
605  aDescProps.setProperty( PROP_ContainsHeader, true );
606  aDescProps.setProperty( PROP_CopyOutputData, false );
607 
608  // maximum number of UNO API filter fields
609  sal_Int32 nMaxCount = 0;
610  aDescProps.getProperty( nMaxCount, PROP_MaxFieldCount );
611  OSL_ENSURE( nMaxCount > 0, "AutoFilter::finalizeImport - invalid maximum filter field count" );
612 
613  // resulting list of all UNO API filter fields
614  ::std::vector<TableFilterField3> aFilterFields;
615 
616  // track if columns require to enable or disable regular expressions
617  OptValue< bool > obNeedsRegExp;
618 
619  /* Track whether the filter fields of the first filter column are
620  connected with 'or'. In this case, other filter fields cannot be
621  inserted without altering the result of the entire filter, due to
622  Calc's precedence for the 'and' connection operator. Example:
623  Excel's filter conditions 'A1 and (B1 or B2) and C1' where B1 and
624  B2 belong to filter column B, will be evaluated by Calc as
625  '(A1 and B1) or (B2 and C1)'. */
626  bool bHasOrConnection = false;
627 
628  // process all filter column objects, exit when 'or' connection exists
629  for( const auto& rxFilterColumn : maFilterColumns )
630  {
631  // the filter settings object creates a list of filter fields
632  ApiFilterSettings aSettings = rxFilterColumn->finalizeImport( nMaxCount );
633  ApiFilterSettings::FilterFieldVector& rColumnFields = aSettings.maFilterFields;
634 
635  // new total number of filter fields
636  sal_Int32 nNewCount = static_cast< sal_Int32 >( aFilterFields.size() + rColumnFields.size() );
637 
638  /* Check whether mode for regular expressions is compatible with
639  the global mode in obNeedsRegExp. If either one is still in
640  don't-care state, all is fine. If both are set, they must be
641  equal. */
642  bool bRegExpCompatible = !obNeedsRegExp || !aSettings.mobNeedsRegExp || (obNeedsRegExp.get() == aSettings.mobNeedsRegExp.get());
643 
644  // check whether fields are connected by 'or' (see comments above).
645  if( rColumnFields.size() >= 2 )
646  bHasOrConnection = std::any_of(rColumnFields.begin() + 1, rColumnFields.end(),
647  [](const css::sheet::TableFilterField3& rColumnField) { return rColumnField.Connection == FilterConnection_OR; });
648 
649  /* Skip the column filter, if no filter fields have been created,
650  if the number of new filter fields would exceed the total limit
651  of filter fields, or if the mode for regular expressions of the
652  filter column does not fit. */
653  if( !rColumnFields.empty() && (nNewCount <= nMaxCount) && bRegExpCompatible )
654  {
655  /* Add 'and' connection to the first filter field to connect
656  it to the existing filter fields of other columns. */
657  rColumnFields[ 0 ].Connection = FilterConnection_AND;
658 
659  // insert the new filter fields
660  aFilterFields.insert( aFilterFields.end(), rColumnFields.begin(), rColumnFields.end() );
661 
662  // update the regular expressions mode
663  obNeedsRegExp.assignIfUsed( aSettings.mobNeedsRegExp );
664  }
665 
666  if( bHasOrConnection )
667  break;
668  }
669 
670  // insert all filter fields to the filter descriptor
671  if( !aFilterFields.empty() )
672  xFilterDesc->setFilterFields3( ContainerHelper::vectorToSequence( aFilterFields ) );
673 
674  // regular expressions
675  bool bUseRegExp = obNeedsRegExp.get( false );
676  aDescProps.setProperty( PROP_UseRegularExpressions, bUseRegExp );
677 
678  // sort
679  if (!maSortConditions.empty())
680  {
681  const SortConditionVector::value_type& xSortConditionPointer = *maSortConditions.begin();
682  const SortCondition& rSorConditionLoaded = *xSortConditionPointer;
683 
684  ScSortParam aParam;
685  aParam.bUserDef = false;
686  aParam.nUserIndex = 0;
687  aParam.bByRow = false;
688 
689  ScUserList* pUserList = ScGlobal::GetUserList();
690  if (!rSorConditionLoaded.maSortCustomList.isEmpty())
691  {
692  for (size_t i=0; pUserList && i < pUserList->size(); i++)
693  {
694  const OUString aEntry((*pUserList)[i].GetString());
695  if (aEntry.equalsIgnoreAsciiCase(rSorConditionLoaded.maSortCustomList))
696  {
697  aParam.bUserDef = true;
698  aParam.nUserIndex = i;
699  break;
700  }
701  }
702  }
703 
704  if (!aParam.bUserDef)
705  {
706  pUserList->push_back(new ScUserListData(rSorConditionLoaded.maSortCustomList));
707  aParam.bUserDef = true;
708  aParam.nUserIndex = pUserList->size()-1;
709  }
710 
711  // set sort parameter if we have detected it
712  if (aParam.bUserDef)
713  {
714  SCCOLROW nStartPos = aParam.bByRow ? maRange.aStart.Col() : maRange.aStart.Row();
715  if (rSorConditionLoaded.mbDescending)
716  {
717  // descending sort - need to enable 1st SortParam slot
718  assert(aParam.GetSortKeyCount() == DEFSORT);
719 
720  aParam.maKeyState[0].bDoSort = true;
721  aParam.maKeyState[0].bAscending = false;
722  aParam.maKeyState[0].nField += nStartPos;
723  }
724 
725  ScDocument& rDoc = getScDocument();
726  ScDBData* pDBData = rDoc.GetDBAtArea(
727  nSheet,
729  maRange.aEnd.Col(), maRange.aEnd.Row());
730 
731  if (pDBData)
732  pDBData->SetSortParam(aParam);
733  else
734  OSL_FAIL("AutoFilter::finalizeImport(): cannot find matching DBData");
735  }
736  }
737 }
738 
740  WorkbookHelper( rHelper )
741 {
742 }
743 
745 {
746  AutoFilterVector::value_type xAutoFilter = std::make_shared<AutoFilter>( *this );
747  maAutoFilters.push_back( xAutoFilter );
748  return *xAutoFilter;
749 }
750 
751 void AutoFilterBuffer::finalizeImport( sal_Int16 nSheet )
752 {
753  // rely on existence of the defined name '_FilterDatabase' containing the range address of the filtered area
754  const DefinedName* pFilterDBName = getDefinedNames().getByBuiltinId( BIFF_DEFNAME_FILTERDATABASE, nSheet ).get();
755  if(!pFilterDBName)
756  return;
757 
758  ScRange aFilterRange;
759  if( !(pFilterDBName->getAbsoluteRange( aFilterRange ) && (aFilterRange.aStart.Tab() == nSheet)) )
760  return;
761 
762  // use the same name for the database range as used for the defined name '_FilterDatabase'
763  Reference< XDatabaseRange > xDatabaseRange = createUnnamedDatabaseRangeObject( aFilterRange );
764  // first, try to create an auto filter
765  bool bHasAutoFilter = finalizeImport( xDatabaseRange, nSheet );
766  // no success: try to create an advanced filter
767  if( bHasAutoFilter || !xDatabaseRange.is() )
768  return;
769 
770  // the built-in defined name 'Criteria' must exist
771  const DefinedName* pCriteriaName = getDefinedNames().getByBuiltinId( BIFF_DEFNAME_CRITERIA, nSheet ).get();
772  if( !pCriteriaName )
773  return;
774 
775  ScRange aCriteriaRange;
776  if( !pCriteriaName->getAbsoluteRange( aCriteriaRange ) )
777  return;
778 
779  // set some common properties for the filter descriptor
780  PropertySet aDescProps( xDatabaseRange->getFilterDescriptor() );
781  aDescProps.setProperty( PROP_IsCaseSensitive, false );
782  aDescProps.setProperty( PROP_SkipDuplicates, false );
783  aDescProps.setProperty( PROP_Orientation, TableOrientation_ROWS );
784  aDescProps.setProperty( PROP_ContainsHeader, true );
785  // criteria range may contain wildcards, but these are incompatible with REs
786  aDescProps.setProperty( PROP_UseRegularExpressions, false );
787 
788  // position of output data (if built-in defined name 'Extract' exists)
790  ScRange aOutputRange;
791  bool bHasOutputRange = xExtractName && xExtractName->getAbsoluteRange( aOutputRange );
792  aDescProps.setProperty( PROP_CopyOutputData, bHasOutputRange );
793  if( bHasOutputRange )
794  {
795  aDescProps.setProperty( PROP_SaveOutputPosition, true );
796  aDescProps.setProperty( PROP_OutputPosition, CellAddress( aOutputRange.aStart.Tab(), aOutputRange.aStart.Col(), aOutputRange.aStart.Row() ) );
797  }
798 
799  /* Properties of the database range (must be set after
800  modifying properties of the filter descriptor,
801  otherwise the 'FilterCriteriaSource' property gets
802  deleted). */
803  PropertySet aRangeProps( xDatabaseRange );
804  aRangeProps.setProperty( PROP_AutoFilter, false );
805  aRangeProps.setProperty( PROP_FilterCriteriaSource,
806  CellRangeAddress( aCriteriaRange.aStart.Tab(),
807  aCriteriaRange.aStart.Col(), aCriteriaRange.aStart.Row(),
808  aCriteriaRange.aEnd.Col(), aCriteriaRange.aEnd.Row() ));
809 }
810 
811 bool AutoFilterBuffer::finalizeImport( const Reference< XDatabaseRange >& rxDatabaseRange, sal_Int16 nSheet )
812 {
813  AutoFilter* pAutoFilter = getActiveAutoFilter();
814  if( pAutoFilter && rxDatabaseRange.is() ) try
815  {
816  // the property 'AutoFilter' enables the drop-down buttons
817  PropertySet aRangeProps( rxDatabaseRange );
818  aRangeProps.setProperty( PROP_AutoFilter, true );
819 
820  pAutoFilter->finalizeImport( rxDatabaseRange, nSheet );
821 
822  // return true to indicate enabled autofilter
823  return true;
824  }
825  catch( Exception& )
826  {
827  }
828  return false;
829 }
830 
832 {
833  // Excel expects not more than one auto filter per sheet or table
834  OSL_ENSURE( maAutoFilters.size() <= 1, "AutoFilterBuffer::getActiveAutoFilter - too many auto filters" );
835  // stick to the last imported auto filter
836  return maAutoFilters.empty() ? nullptr : maAutoFilters.back().get();
837 }
838 
839 } // namespace oox
840 
841 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Helper class to provide access to global workbook data.
::std::vector< ScSortKeyState > maKeyState
Definition: sortparam.hxx:61
sal_uInt16 nUserIndex
Definition: sortparam.hxx:47
const sal_Int32 BIFF12_ID_CUSTOMFILTER
Definition: biffhelper.hxx:80
Collection of user-defined sort lists.
Definition: userlist.hxx:66
void importSortState(const AttributeList &rAttribs, sal_Int16 nSheet)
ScAddress aStart
Definition: address.hxx:500
virtual void skip(sal_Int32 nBytes, size_t nAtomSize=1) override
OptValue< bool > getBool(sal_Int32 nAttrToken) const
::std::vector< css::sheet::TableFilterField3 > FilterFieldVector
SC_DLLPUBLIC void SetSortParam(const ScSortParam &rSortParam)
Definition: dbdata.cxx:399
SCROW Row() const
Definition: address.hxx:262
bool getProperty(Type &orValue, sal_Int32 nPropId) const
OptValue< OUString > getXString(sal_Int32 nAttrToken) const
void appendCriterion(const FilterCriterionModel &rCriterion)
Appends the passed filter criterion, if it contains valid settings.
OptValue< sal_Int32 > getInteger(sal_Int32 nAttrToken) const
A 2D cell range address struct for binary filters.
sal_Int32 mnOperator
Comparison operand.
sal_Int64 n
bool mbTop
Number of items or percentage.
SortConditionVector maSortConditions
SC_DLLPUBLIC const ScDBData * GetDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2) const
Definition: documen3.cxx:333
value_type get(sal_Int32 nIndex) const
size_t size() const
Definition: userlist.cxx:345
ScAddress aEnd
Definition: address.hxx:501
OptValue< double > getDouble(sal_Int32 nAttrToken) const
FilterColumnVector maFilterColumns
#define STATIC_ARRAY_SELECT(array, index, def)
OptValue< OUString > getString(sal_Int32 nAttrToken) const
unsigned char readuChar()
const sal_Unicode BIFF_DEFNAME_CRITERIA
static bool convertToCellRangeUnchecked(ScRange &orRange, const OUString &rString, sal_Int16 nSheet)
Converts the passed string to a cell range address, without checking any sheet limits.
virtual void importAttribs(sal_Int32 nElement, const AttributeList &rAttribs)
Derived classes import filter settings from the passed attribute list.
bool bUserDef
Definition: sortparam.hxx:54
OptValue< bool > mobNeedsRegExp
List of UNO API filter settings.
Contains UNO API filter settings for a column in a filtered range.
void importAutoFilter(const AttributeList &rAttribs, sal_Int16 nSheet)
Imports auto filter settings from the autoFilter element.
OUString GetString(int nId)
virtual ApiFilterSettings finalizeImport(sal_Int32 nMaxCount) override
Returns converted UNO API filter settings representing all filter settings.
sal_uInt16 sal_Unicode
sal_uInt16 readuInt16()
void push_back(ScUserListData *p)
Definition: userlist.cxx:350
AutoFilter & createAutoFilter()
Creates a new auto filter and stores it internally.
Stores individual user-defined sort list.
Definition: userlist.hxx:33
A filter criterion for a custom filter.
const BorderLinePrimitive2D *pCandidateB assert(pCandidateA)
sal_Int32 SCCOLROW
a type capable of holding either SCCOL or SCROW
Definition: types.hxx:24
SortCondition & createSortCondition()
void importFilterColumn(const AttributeList &rAttribs)
Imports auto filter column settings from the filterColumn element.
FilterCriterionModel()
Operand data type (BIFF only).
const sal_Int32 BIFF12_ID_DISCRETEFILTERS
Definition: biffhelper.hxx:97
void importSortCondition(const AttributeList &rAttribs, sal_Int16 nSheet)
const Type & get() const
SCTAB Tab() const
Definition: address.hxx:271
AutoFilter(const WorkbookHelper &rHelper)
FilterCriterionVector maCriteria
DiscreteFilter(const WorkbookHelper &rHelper)
CustomFilter(const WorkbookHelper &rHelper)
bool getFlag(Type nBitField, Type nMask)
FilterColumn(const WorkbookHelper &rHelper)
int i
AutoFilter * getActiveAutoFilter()
Returns the auto filter object used to perform auto filtering.
container_type::value_type value_type
void assignIfUsed(const OptValue &rValue)
const sal_Unicode BIFF_DEFNAME_FILTERDATABASE
static OUString readString(SequenceInputStream &rStrm, bool b32BitLen=true)
Reads a BIFF12 string with leading 16-bit or 32-bit length field.
Definition: biffhelper.cxx:78
virtual void importAttribs(sal_Int32 nElement, const AttributeList &rAttribs) override
Imports filter settings from the filters and filter elements.
XML_TOKEN_INVALID
const sal_Int32 BIFF12_ID_CUSTOMFILTERS
Definition: biffhelper.hxx:81
static SC_DLLPUBLIC ScUserList * GetUserList()
Definition: global.cxx:274
std::vector< OUString > maValues
ApiFilterSettings()
If set, requires regular expressions to be enabled/disabled.
virtual void importAttribs(sal_Int32 nElement, const AttributeList &rAttribs) override
Imports filter settings from the filters and filter elements.
sal_uInt8 mnDataType
Comparison operator.
void finalizeImport(sal_Int16 nSheet)
Applies filter settings to a new database range object (used for sheet autofilter or advanced filter ...
void appendField(bool bAnd, sal_Int32 nOperator, double fValue)
void readBiffData(SequenceInputStream &rStrm)
Imports the criterion model from the passed BIFF12 stream.
const sal_Unicode BIFF_DEFNAME_EXTRACT
FilterColumn & createFilterColumn()
Creates a new auto filter column and stores it internally.
const sal_Int32 BIFF12_ID_DISCRETEFILTER
Definition: biffhelper.hxx:96
SCCOL Col() const
Definition: address.hxx:267
virtual void importRecord(sal_Int32 nRecId, SequenceInputStream &rStrm) override
Imports filter settings from the FILTERS and FILTER records.
virtual void importRecord(sal_Int32 nRecId, SequenceInputStream &rStrm) override
Imports filter settings from the FILTERS and FILTER records.
ApiFilterSettings finalizeImport(sal_Int32 nMaxCount)
Returns converted UNO API filter settings representing all filter settings of this column...
DefTokenId nToken
Definition: qproform.cxx:400
virtual void importAttribs(sal_Int32 nElement, const AttributeList &rAttribs) override
Imports filter settings from the filters and filter elements.
std::unique_ptr< char[]> aBuffer
virtual void importRecord(sal_Int32 nRecId, SequenceInputStream &rStrm)
Derived classes import filter settings from the passed record.
SortCondition(const WorkbookHelper &rHelper)
bool mbPercent
True = show top (greatest) items/percentage.
std::shared_ptr< DefinedName > DefinedNameRef
unsigned char sal_uInt8
A column in a filtered range.
FilterSettingsBase(const WorkbookHelper &rHelper)
std::shared_ptr< FilterSettingsBase > mxSettings
sal_uInt16 GetSortKeyCount() const
Definition: sortparam.hxx:79
const sal_Int32 BIFF12_ID_TOP10FILTER
Definition: biffhelper.hxx:231
virtual ApiFilterSettings finalizeImport(sal_Int32 nMaxCount) override
Returns converted UNO API filter settings representing all filter settings.
static css::uno::Sequence< typename VectorType::value_type > vectorToSequence(const VectorType &rVector)
void finalizeImport(const css::uno::Reference< css::sheet::XDatabaseRange > &rxDatabaseRange, sal_Int16 nSheet)
Applies the filter to the passed filter descriptor.
DefinedNameRef getByBuiltinId(sal_Unicode cBuiltinId, sal_Int16 nCalcSheet) const
Returns a built-in defined name by its built-in identifier.
Top10Filter(const WorkbookHelper &rHelper)
Base class for specific filter settings for a column in a filtered range.
sal_Int32 nLength
virtual ApiFilterSettings finalizeImport(sal_Int32 nMaxCount) override
Returns converted UNO API filter settings representing all filter settings.
bool getAbsoluteRange(ScRange &orRange) const
Tries to resolve the defined name to an absolute cell range.
virtual void importRecord(sal_Int32 nRecId, SequenceInputStream &rStrm) override
Imports filter settings from the FILTERS and FILTER records.
#define DEFSORT
Definition: sortparam.hxx:23
void setBiffOperator(sal_uInt8 nOperator)
Sets the passed BIFF operator constant.
css::uno::Reference< css::sheet::XDatabaseRange > createUnnamedDatabaseRangeObject(const ScRange &rRangeAddr) const
Creates and returns an unnamed database range on-the-fly in the Calc document.
AutoFilterBuffer(const WorkbookHelper &rHelper)
FilterFieldVector maFilterFields
virtual ApiFilterSettings finalizeImport(sal_Int32 nMaxCount)
Derived classes return converted UNO API filter settings representing all filter settings.
DefinedNamesBuffer & getDefinedNames() const
Returns the defined names read from the workbook globals.
bool setProperty(sal_Int32 nPropId, const Type &rValue)
sal_uInt16 nPos
OptValue< sal_Int32 > getToken(sal_Int32 nAttrToken) const