File: | home/maarten/src/libreoffice/core/sc/source/filter/oox/autofilterbuffer.cxx |
Warning: | line 706, column 13 Called C++ object pointer is null |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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> | ||||
32 | #include <oox/helper/attributelist.hxx> | ||||
33 | #include <oox/helper/containerhelper.hxx> | ||||
34 | #include <oox/helper/propertyset.hxx> | ||||
35 | #include <oox/helper/binaryinputstream.hxx> | ||||
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 | |||||
82 | /** Removes leading asterisk characters from the passed string. | ||||
83 | @return True = at least one asterisk character has been removed. */ | ||||
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 | |||||
98 | /** Removes trailing asterisk characters from the passed string. | ||||
99 | @return True = at least one asterisk character has been removed. */ | ||||
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 | |||||
114 | /** Converts wildcard characters '*' and '?' to regular expressions and quotes | ||||
115 | RE meta characters. | ||||
116 | @return True = passed string has been changed (RE needs to be enabled). */ | ||||
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 | |||||
152 | ApiFilterSettings::ApiFilterSettings() | ||||
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 | |||||
193 | FilterSettingsBase::FilterSettingsBase( const WorkbookHelper& rHelper ) : | ||||
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 | |||||
206 | ApiFilterSettings FilterSettingsBase::finalizeImport( sal_Int32 /*nMaxCount*/ ) | ||||
207 | { | ||||
208 | return ApiFilterSettings(); | ||||
209 | } | ||||
210 | |||||
211 | DiscreteFilter::DiscreteFilter( const WorkbookHelper& rHelper ) : | ||||
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 )(::oox::NMSP_xls | ::oox::XML_filters): | ||||
223 | mnCalendarType = rAttribs.getToken( XML_calendarType, XML_none ); | ||||
224 | mbShowBlank = rAttribs.getBool( XML_blank, false ); | ||||
225 | break; | ||||
226 | |||||
227 | case XLS_TOKEN( filter )(::oox::NMSP_xls | ::oox::XML_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 | { | ||||
241 | case BIFF12_ID_DISCRETEFILTERS: | ||||
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 )((detail::make_unsigned(nCalendarType) < (sizeof(sal_n_array_size (spnCalendarTypes)))) ? ((spnCalendarTypes)[static_cast<size_t >(nCalendarType)]) : (XML_none)); | ||||
251 | mbShowBlank = nShowBlank != 0; | ||||
252 | } | ||||
253 | break; | ||||
254 | |||||
255 | case BIFF12_ID_DISCRETEFILTER: | ||||
256 | { | ||||
257 | OUString aValue = BiffHelper::readString( rStrm ); | ||||
258 | if( !aValue.isEmpty() ) | ||||
259 | maValues.push_back( aValue ); | ||||
260 | } | ||||
261 | break; | ||||
262 | } | ||||
263 | } | ||||
264 | |||||
265 | ApiFilterSettings DiscreteFilter::finalizeImport( sal_Int32 nMaxCount ) | ||||
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 | |||||
287 | Top10Filter::Top10Filter( const WorkbookHelper& rHelper ) : | ||||
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 )(::oox::NMSP_xls | ::oox::XML_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 | |||||
317 | ApiFilterSettings Top10Filter::finalizeImport( sal_Int32 /*nMaxCount*/ ) | ||||
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 | |||||
327 | FilterCriterionModel::FilterCriterionModel() : | ||||
328 | mnOperator( XML_equal ), | ||||
329 | mnDataType( BIFF_FILTER_DATATYPE_NONE ) | ||||
330 | { | ||||
331 | } | ||||
332 | |||||
333 | void FilterCriterionModel::setBiffOperator( sal_uInt8 nOperator ) | ||||
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 )((detail::make_unsigned(nOperator) < (sizeof(sal_n_array_size (spnOperators)))) ? ((spnOperators)[static_cast<size_t> (nOperator)]) : (XML_TOKEN_INVALID)); | ||||
338 | } | ||||
339 | |||||
340 | void FilterCriterionModel::readBiffData( SequenceInputStream& rStrm ) | ||||
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" )do { if (true && (!(false))) { sal_detail_logFormat(( SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/filter/oox/autofilterbuffer.cxx" ":" "375" ": "), "%s", "FilterCriterionModel::readBiffData - unexpected data type" ); } } while (false); | ||||
376 | rStrm.skip( 8 ); | ||||
377 | } | ||||
378 | } | ||||
379 | |||||
380 | CustomFilter::CustomFilter( const WorkbookHelper& rHelper ) : | ||||
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 )(::oox::NMSP_xls | ::oox::XML_customFilters): | ||||
391 | mbAnd = rAttribs.getBool( XML_and, false ); | ||||
392 | break; | ||||
393 | |||||
394 | case XLS_TOKEN( customFilter )(::oox::NMSP_xls | ::oox::XML_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 | { | ||||
411 | case BIFF12_ID_CUSTOMFILTERS: | ||||
412 | mbAnd = rStrm.readInt32() == 0; | ||||
413 | break; | ||||
414 | |||||
415 | case BIFF12_ID_CUSTOMFILTER: | ||||
416 | { | ||||
417 | FilterCriterionModel aCriterion; | ||||
418 | aCriterion.readBiffData( rStrm ); | ||||
419 | appendCriterion( aCriterion ); | ||||
420 | } | ||||
421 | break; | ||||
422 | } | ||||
423 | } | ||||
424 | |||||
425 | ApiFilterSettings CustomFilter::finalizeImport( sal_Int32 /*nMaxCount*/ ) | ||||
426 | { | ||||
427 | ApiFilterSettings aSettings; | ||||
428 | OSL_ENSURE( maCriteria.size() <= 2, "CustomFilter::finalizeImport - too many filter criteria" )do { if (true && (!(maCriteria.size() <= 2))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/filter/oox/autofilterbuffer.cxx" ":" "428" ": "), "%s", "CustomFilter::finalizeImport - too many filter criteria" ); } } while (false); | ||||
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 | |||||
492 | void CustomFilter::appendCriterion( const FilterCriterionModel& rCriterion ) | ||||
493 | { | ||||
494 | if( (rCriterion.mnOperator != XML_TOKEN_INVALID) && rCriterion.maValue.hasValue() ) | ||||
495 | maCriteria.push_back( rCriterion ); | ||||
496 | } | ||||
497 | |||||
498 | FilterColumn::FilterColumn( const WorkbookHelper& rHelper ) : | ||||
499 | WorkbookHelper( rHelper ), | ||||
500 | mnColId( -1 ), | ||||
501 | mbHiddenButton( false ), | ||||
502 | mbShowButton( true ) | ||||
503 | { | ||||
504 | } | ||||
505 | |||||
506 | void FilterColumn::importFilterColumn( const AttributeList& rAttribs ) | ||||
507 | { | ||||
508 | mnColId = rAttribs.getInteger( XML_colId, -1 ); | ||||
509 | mbHiddenButton = rAttribs.getBool( XML_hiddenButton, false ); | ||||
510 | mbShowButton = rAttribs.getBool( XML_showButton, true ); | ||||
511 | } | ||||
512 | |||||
513 | void FilterColumn::importFilterColumn( SequenceInputStream& rStrm ) | ||||
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 | |||||
522 | ApiFilterSettings FilterColumn::finalizeImport( sal_Int32 nMaxCount ) | ||||
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 | |||||
538 | SortCondition::SortCondition( const WorkbookHelper& rHelper ) : | ||||
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() ); | ||||
547 | AddressConverter::convertToCellRangeUnchecked( maRange, aRangeStr, nSheet ); | ||||
548 | |||||
549 | maSortCustomList = rAttribs.getString( XML_customList, OUString() ); | ||||
550 | mbDescending = rAttribs.getBool( XML_descending, false ); | ||||
551 | } | ||||
552 | |||||
553 | // AutoFilter | ||||
554 | |||||
555 | AutoFilter::AutoFilter( const WorkbookHelper& rHelper ) : | ||||
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() ); | ||||
563 | AddressConverter::convertToCellRangeUnchecked( maRange, aRangeStr, nSheet ); | ||||
564 | } | ||||
565 | |||||
566 | void AutoFilter::importAutoFilter( SequenceInputStream& rStrm, sal_Int16 nSheet ) | ||||
567 | { | ||||
568 | BinRange aBinRange; | ||||
569 | rStrm >> aBinRange; | ||||
570 | AddressConverter::convertToCellRangeUnchecked( maRange, aBinRange, nSheet ); | ||||
571 | } | ||||
572 | |||||
573 | void AutoFilter::importSortState( const AttributeList& rAttribs, sal_Int16 nSheet ) | ||||
574 | { | ||||
575 | OUString aRangeStr = rAttribs.getString( XML_ref, OUString() ); | ||||
576 | AddressConverter::convertToCellRangeUnchecked( maSortRange, aRangeStr, nSheet ); | ||||
577 | } | ||||
578 | |||||
579 | FilterColumn& AutoFilter::createFilterColumn() | ||||
580 | { | ||||
581 | FilterColumnVector::value_type xFilterColumn = std::make_shared<FilterColumn>( *this ); | ||||
582 | maFilterColumns.push_back( xFilterColumn ); | ||||
583 | return *xFilterColumn; | ||||
584 | } | ||||
585 | |||||
586 | SortCondition& AutoFilter::createSortCondition() | ||||
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" )do { if (true && (!(nMaxCount > 0))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/filter/oox/autofilterbuffer.cxx" ":" "611" ": "), "%s", "AutoFilter::finalizeImport - invalid maximum filter field count" ); } } while (false); | ||||
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)(static_cast <bool> (aParam.GetSortKeyCount() == 3) ? void (0) : __assert_fail ("aParam.GetSortKeyCount() == DEFSORT", "/home/maarten/src/libreoffice/core/sc/source/filter/oox/autofilterbuffer.cxx" , 718, __extension__ __PRETTY_FUNCTION__)); | ||||
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, | ||||
728 | maRange.aStart.Col(), maRange.aStart.Row(), | ||||
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")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/filter/oox/autofilterbuffer.cxx" ":" "734" ": "), "%s", "AutoFilter::finalizeImport(): cannot find matching DBData" ); } } while (false); | ||||
735 | } | ||||
736 | } | ||||
737 | } | ||||
738 | |||||
739 | AutoFilterBuffer::AutoFilterBuffer( const WorkbookHelper& rHelper ) : | ||||
740 | WorkbookHelper( rHelper ) | ||||
741 | { | ||||
742 | } | ||||
743 | |||||
744 | AutoFilter& AutoFilterBuffer::createAutoFilter() | ||||
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) | ||||
789 | DefinedNameRef xExtractName = getDefinedNames().getByBuiltinId( BIFF_DEFNAME_EXTRACT, nSheet ); | ||||
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 | |||||
831 | AutoFilter* AutoFilterBuffer::getActiveAutoFilter() | ||||
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" )do { if (true && (!(maAutoFilters.size() <= 1))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl" ), ("/home/maarten/src/libreoffice/core/sc/source/filter/oox/autofilterbuffer.cxx" ":" "834" ": "), "%s", "AutoFilterBuffer::getActiveAutoFilter - too many auto filters" ); } } while (false); | ||||
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: */ |
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 | #ifndef INCLUDED_COM_SUN_STAR_UNO_REFERENCE_H |
20 | #define INCLUDED_COM_SUN_STAR_UNO_REFERENCE_H |
21 | |
22 | #include "sal/config.h" |
23 | |
24 | #include <cassert> |
25 | #include <cstddef> |
26 | |
27 | #if defined LIBO_INTERNAL_ONLY1 |
28 | #include <type_traits> |
29 | #endif |
30 | |
31 | #include "rtl/alloc.h" |
32 | |
33 | namespace com |
34 | { |
35 | namespace sun |
36 | { |
37 | namespace star |
38 | { |
39 | namespace uno |
40 | { |
41 | |
42 | class RuntimeException; |
43 | class XInterface; |
44 | class Type; |
45 | class Any; |
46 | |
47 | /** Enum defining UNO_REF_NO_ACQUIRE for setting reference without acquiring a given interface. |
48 | Deprecated, please use SAL_NO_ACQUIRE. |
49 | @deprecated |
50 | */ |
51 | enum UnoReference_NoAcquire |
52 | { |
53 | /** This enum value can be used for creating a reference granting a given interface, |
54 | i.e. transferring ownership to it. |
55 | */ |
56 | UNO_REF_NO_ACQUIRE |
57 | }; |
58 | |
59 | /** This base class serves as a base class for all template reference classes and |
60 | has been introduced due to compiler problems with templated operators ==, =!. |
61 | */ |
62 | class BaseReference |
63 | { |
64 | protected: |
65 | /** the interface pointer |
66 | */ |
67 | XInterface * _pInterface; |
68 | |
69 | /** Queries given interface for type rType. |
70 | |
71 | @param pInterface interface pointer |
72 | @param rType interface type |
73 | @return interface of demanded type (may be null) |
74 | */ |
75 | inline static XInterface * SAL_CALL iquery( XInterface * pInterface, const Type & rType ); |
76 | /** Queries given interface for type rType. |
77 | Throws a RuntimeException if the demanded interface cannot be queried. |
78 | |
79 | @param pInterface interface pointer |
80 | @param rType interface type |
81 | @return interface of demanded type |
82 | */ |
83 | inline static XInterface * SAL_CALL iquery_throw( XInterface * pInterface, const Type & rType ); |
84 | |
85 | public: |
86 | /** Gets interface pointer. This call does not acquire the interface. |
87 | |
88 | @return UNacquired interface pointer |
89 | */ |
90 | XInterface * SAL_CALL get() const |
91 | { return _pInterface; } |
92 | |
93 | /** Checks if reference is null. |
94 | |
95 | @return true if reference acquires an interface, i.e. true if it is not null |
96 | */ |
97 | bool SAL_CALL is() const |
98 | { return (NULL__null != _pInterface); } |
99 | |
100 | #if defined LIBO_INTERNAL_ONLY1 |
101 | /** Checks if reference is null. |
102 | |
103 | @return true if reference acquires an interface, i.e. true if it is not null |
104 | */ |
105 | explicit operator bool() const |
106 | { return is(); } |
107 | #endif |
108 | |
109 | /** Equality operator: compares two interfaces |
110 | Checks if both references are null or refer to the same object. |
111 | |
112 | @param pInterface another interface |
113 | @return true if both references are null or refer to the same object, false otherwise |
114 | */ |
115 | inline bool SAL_CALL operator == ( XInterface * pInterface ) const; |
116 | /** Inequality operator: compares two interfaces |
117 | Checks if both references are null or refer to the same object. |
118 | |
119 | @param pInterface another interface |
120 | @return false if both references are null or refer to the same object, true otherwise |
121 | */ |
122 | inline bool SAL_CALL operator != ( XInterface * pInterface ) const; |
123 | |
124 | /** Equality operator: compares two interfaces |
125 | Checks if both references are null or refer to the same object. |
126 | |
127 | @param rRef another reference |
128 | @return true if both references are null or refer to the same object, false otherwise |
129 | */ |
130 | inline bool SAL_CALL operator == ( const BaseReference & rRef ) const; |
131 | /** Inequality operator: compares two interfaces |
132 | Checks if both references are null or refer to the same object. |
133 | |
134 | @param rRef another reference |
135 | @return false if both references are null or refer to the same object, true otherwise |
136 | */ |
137 | inline bool SAL_CALL operator != ( const BaseReference & rRef ) const; |
138 | |
139 | /** Needed by some STL containers. |
140 | |
141 | @param rRef another reference |
142 | @return true, if this reference is less than rRef |
143 | */ |
144 | inline bool SAL_CALL operator < ( const BaseReference & rRef ) const; |
145 | }; |
146 | |
147 | /** Enum defining UNO_QUERY for implicit interface query. |
148 | */ |
149 | enum UnoReference_Query |
150 | { |
151 | /** This enum value can be used for implicit interface query. |
152 | */ |
153 | UNO_QUERY |
154 | }; |
155 | /** Enum defining UNO_QUERY_THROW for implicit interface query. |
156 | If the demanded interface is unavailable, then a RuntimeException is thrown. |
157 | */ |
158 | enum UnoReference_QueryThrow |
159 | { |
160 | /** This enum value can be used for implicit interface query. |
161 | */ |
162 | UNO_QUERY_THROW |
163 | }; |
164 | /** Enum defining UNO_SET_THROW for throwing if attempts are made to assign a null |
165 | interface |
166 | |
167 | @since UDK 3.2.8 |
168 | */ |
169 | enum UnoReference_SetThrow |
170 | { |
171 | UNO_SET_THROW |
172 | }; |
173 | |
174 | /** Template reference class for interface type derived from BaseReference. |
175 | A special constructor given the UNO_QUERY identifier queries interfaces |
176 | for reference type. |
177 | */ |
178 | template< class interface_type > |
179 | class SAL_DLLPUBLIC_RTTI__attribute__ ((type_visibility("default"))) Reference : public BaseReference |
180 | { |
181 | /** Queries given interface for type interface_type. |
182 | |
183 | @param pInterface interface pointer |
184 | @return interface of demanded type (may be null) |
185 | */ |
186 | inline static XInterface * SAL_CALL iquery( XInterface * pInterface ); |
187 | /** Queries given interface for type interface_type. |
188 | Throws a RuntimeException if the demanded interface cannot be queried. |
189 | |
190 | @param pInterface interface pointer |
191 | @return interface of demanded type |
192 | */ |
193 | inline static XInterface * SAL_CALL iquery_throw( XInterface * pInterface ); |
194 | /** Returns the given interface if it is not <NULL/>, throws a RuntimeException otherwise. |
195 | |
196 | @param pInterface interface pointer |
197 | @return pInterface |
198 | */ |
199 | inline static interface_type * SAL_CALL iset_throw( interface_type * pInterface ); |
200 | |
201 | /** Cast from an "interface pointer" (e.g., BaseReference::_pInterface) to a |
202 | pointer to this interface_type. |
203 | |
204 | To work around ambiguities in the case of multiple-inheritance interface |
205 | types (which inherit XInterface more than once), use reinterpret_cast |
206 | (resp. a sequence of two static_casts, to avoid warnings about |
207 | reinterpret_cast used between related classes) to switch from a pointer |
208 | to XInterface to a pointer to this derived interface_type. In |
209 | principle, this is not guaranteed to work. In practice, it seems to |
210 | work on all supported platforms. |
211 | */ |
212 | static interface_type * castFromXInterface(XInterface * p) { |
213 | return static_cast< interface_type * >(static_cast< void * >(p)); |
214 | } |
215 | |
216 | /** Cast from a pointer to this interface_type to an "interface pointer" |
217 | (e.g., BaseReference::_pInterface). |
218 | |
219 | To work around ambiguities in the case of multiple-inheritance interface |
220 | types (which inherit XInterface more than once), use reinterpret_cast |
221 | (resp. a sequence of two static_casts, to avoid warnings about |
222 | reinterpret_cast used between related classes) to switch from a pointer |
223 | to this derived interface_type to a pointer to XInterface. In |
224 | principle, this is not guaranteed to work. In practice, it seems to |
225 | work on all supported platforms. |
226 | */ |
227 | static XInterface * castToXInterface(interface_type * p) { |
228 | return static_cast< XInterface * >(static_cast< void * >(p)); |
229 | } |
230 | |
231 | public: |
232 | /// @cond INTERNAL |
233 | // these are here to force memory de/allocation to sal lib. |
234 | static void * SAL_CALL operator new ( ::size_t nSize ) |
235 | { return ::rtl_allocateMemory( nSize ); } |
236 | static void SAL_CALL operator delete ( void * pMem ) |
237 | { ::rtl_freeMemory( pMem ); } |
238 | static void * SAL_CALL operator new ( ::size_t, void * pMem ) |
239 | { return pMem; } |
240 | static void SAL_CALL operator delete ( void *, void * ) |
241 | {} |
242 | /// @endcond |
243 | |
244 | /** Destructor: Releases interface if set. |
245 | */ |
246 | inline ~Reference() COVERITY_NOEXCEPT_FALSE; |
247 | |
248 | /** Default Constructor: Sets null reference. |
249 | */ |
250 | inline Reference(); |
251 | |
252 | /** Copy constructor: Copies interface reference. |
253 | |
254 | @param rRef another reference |
255 | */ |
256 | inline Reference( const Reference< interface_type > & rRef ); |
257 | |
258 | #if defined LIBO_INTERNAL_ONLY1 |
259 | /** Move constructor |
260 | |
261 | @param rRef another reference |
262 | */ |
263 | inline Reference( Reference< interface_type > && rRef ) noexcept; |
264 | |
265 | /** Up-casting conversion constructor: Copies interface reference. |
266 | |
267 | Does not work for up-casts to ambiguous bases. For the special case of |
268 | up-casting to Reference< XInterface >, see the corresponding conversion |
269 | operator. |
270 | |
271 | @param rRef another reference |
272 | */ |
273 | template< class derived_type > |
274 | inline Reference( |
275 | const Reference< derived_type > & rRef, |
276 | std::enable_if_t< |
277 | std::is_base_of_v<interface_type, derived_type> |
278 | && !std::is_same_v<interface_type, XInterface>, void *> = nullptr); |
279 | #endif |
280 | |
281 | /** Constructor: Sets given interface pointer. |
282 | |
283 | @param pInterface an interface pointer |
284 | */ |
285 | inline Reference( interface_type * pInterface ); |
286 | |
287 | /** Constructor: Sets given interface pointer without acquiring it. |
288 | |
289 | @param pInterface another reference |
290 | @param dummy SAL_NO_ACQUIRE to force obvious distinction to other constructors |
291 | */ |
292 | inline Reference( interface_type * pInterface, __sal_NoAcquire dummy); |
293 | /** Constructor: Sets given interface pointer without acquiring it. |
294 | Deprecated, please use SAL_NO_ACQUIRE version. |
295 | |
296 | @deprecated |
297 | @param pInterface another reference |
298 | @param dummy UNO_REF_NO_ACQUIRE to force obvious distinction to other constructors |
299 | */ |
300 | inline SAL_DEPRECATED("use SAL_NO_ACQUIRE version")__attribute__((deprecated("use SAL_NO_ACQUIRE version"))) Reference( interface_type * pInterface, UnoReference_NoAcquire dummy ); |
301 | |
302 | /** Constructor: Queries given interface for reference interface type (interface_type). |
303 | |
304 | @param rRef another reference |
305 | @param dummy UNO_QUERY to force obvious distinction to other constructors |
306 | */ |
307 | inline Reference( const BaseReference & rRef, UnoReference_Query dummy ); |
308 | /** Constructor: Queries given interface for reference interface type (interface_type). |
309 | |
310 | @param pInterface an interface pointer |
311 | @param dummy UNO_QUERY to force obvious distinction to other constructors |
312 | */ |
313 | inline Reference( XInterface * pInterface, UnoReference_Query dummy); |
314 | /** Constructor: Queries given any for reference interface type (interface_type). |
315 | |
316 | @param rAny an any |
317 | @param dummy UNO_QUERY to force obvious distinction to other constructors |
318 | */ |
319 | inline Reference( const Any & rAny, UnoReference_Query dummy); |
320 | /** Constructor: Queries given interface for reference interface type (interface_type). |
321 | Throws a RuntimeException if the demanded interface cannot be queried. |
322 | |
323 | @param rRef another reference |
324 | @param dummy UNO_QUERY_THROW to force obvious distinction |
325 | to other constructors |
326 | */ |
327 | inline Reference( const BaseReference & rRef, UnoReference_QueryThrow dummy ); |
328 | #ifdef LIBO_INTERNAL_ONLY1 |
329 | /** |
330 | Prevent code from calling the QUERY_THROW constructor, when they meant to use the SET_THROW constructor. |
331 | */ |
332 | Reference( const Reference< interface_type > & rRef, UnoReference_QueryThrow dummy ) = delete; |
333 | #endif |
334 | /** Constructor: Queries given interface for reference interface type (interface_type). |
335 | Throws a RuntimeException if the demanded interface cannot be queried. |
336 | |
337 | @param pInterface an interface pointer |
338 | @param dummy UNO_QUERY_THROW to force obvious distinction |
339 | to other constructors |
340 | */ |
341 | inline Reference( XInterface * pInterface, UnoReference_QueryThrow dummy ); |
342 | /** Constructor: Queries given any for reference interface type (interface_type). |
343 | Throws a RuntimeException if the demanded interface cannot be queried. |
344 | |
345 | @param rAny an any |
346 | @param dummy UNO_QUERY_THROW to force obvious distinction |
347 | to other constructors |
348 | */ |
349 | inline Reference( const Any & rAny, UnoReference_QueryThrow dummy ); |
350 | /** Constructor: assigns from the given interface of the same type. Throws a RuntimeException |
351 | if the source interface is NULL. |
352 | |
353 | @param rRef another interface reference of the same type |
354 | @param dummy UNO_SET_THROW to distinguish from default copy constructor |
355 | |
356 | @since UDK 3.2.8 |
357 | */ |
358 | inline Reference( const Reference< interface_type > & rRef, UnoReference_SetThrow dummy ); |
359 | /** Constructor: assigns from the given interface of the same type. Throws a RuntimeException |
360 | if the source interface is NULL. |
361 | |
362 | @param pInterface an interface pointer |
363 | @param dummy UNO_SET_THROW to distinguish from default assignment constructor |
364 | |
365 | @since UDK 3.2.8 |
366 | */ |
367 | inline Reference( interface_type * pInterface, UnoReference_SetThrow dummy ); |
368 | |
369 | /** Cast operator to Reference< XInterface >: Reference objects are binary compatible and |
370 | any interface must be derived from com.sun.star.uno.XInterface. |
371 | This a useful direct cast possibility. |
372 | */ |
373 | SAL_CALL operator const Reference< XInterface > & () const |
374 | { return * reinterpret_cast< const Reference< XInterface > * >( this ); } |
375 | |
376 | /** Dereference operator: Used to call interface methods. |
377 | |
378 | @return UNacquired interface pointer |
379 | */ |
380 | interface_type * SAL_CALL operator -> () const { |
381 | assert(_pInterface != NULL)(static_cast <bool> (_pInterface != __null) ? void (0) : __assert_fail ("_pInterface != NULL", "/home/maarten/src/libreoffice/core/include/com/sun/star/uno/Reference.h" , 381, __extension__ __PRETTY_FUNCTION__)); |
382 | return castFromXInterface(_pInterface); |
383 | } |
384 | |
385 | /** Indirection operator. |
386 | |
387 | @since LibreOffice 6.3 |
388 | @return UNacquired interface reference |
389 | */ |
390 | interface_type & SAL_CALL operator * () const { |
391 | assert(_pInterface != NULL)(static_cast <bool> (_pInterface != __null) ? void (0) : __assert_fail ("_pInterface != NULL", "/home/maarten/src/libreoffice/core/include/com/sun/star/uno/Reference.h" , 391, __extension__ __PRETTY_FUNCTION__)); |
392 | return *castFromXInterface(_pInterface); |
393 | } |
394 | |
395 | /** Gets interface pointer. This call does not acquire the interface. |
396 | |
397 | @return UNacquired interface pointer |
398 | */ |
399 | interface_type * SAL_CALL get() const |
400 | { return castFromXInterface(_pInterface); } |
401 | |
402 | /** Clears reference, i.e. releases interface. Reference is null after clear() call. |
403 | */ |
404 | inline void SAL_CALL clear(); |
405 | |
406 | /** Sets the given interface. An interface already set will be released. |
407 | |
408 | @param rRef another reference |
409 | @return true, if non-null interface was set |
410 | */ |
411 | inline bool SAL_CALL set( const Reference< interface_type > & rRef ); |
412 | /** Sets the given interface. An interface already set will be released. |
413 | |
414 | @param pInterface another interface |
415 | @return true, if non-null interface was set |
416 | */ |
417 | inline bool SAL_CALL set( interface_type * pInterface ); |
418 | |
419 | /** Sets interface pointer without acquiring it. An interface already set will be released. |
420 | |
421 | @param pInterface an interface pointer |
422 | @param dummy SAL_NO_ACQUIRE to force obvious distinction to set methods |
423 | @return true, if non-null interface was set |
424 | */ |
425 | inline bool SAL_CALL set( interface_type * pInterface, __sal_NoAcquire dummy); |
426 | /** Sets interface pointer without acquiring it. An interface already set will be released. |
427 | Deprecated, please use SAL_NO_ACQUIRE version. |
428 | |
429 | @deprecated |
430 | @param pInterface an interface pointer |
431 | @param dummy UNO_REF_NO_ACQUIRE to force obvious distinction to set methods |
432 | @return true, if non-null interface was set |
433 | */ |
434 | inline SAL_DEPRECATED("use SAL_NO_ACQUIRE version")__attribute__((deprecated("use SAL_NO_ACQUIRE version"))) bool SAL_CALL set( interface_type * pInterface, UnoReference_NoAcquire dummy); |
435 | |
436 | /** Queries given interface for reference interface type (interface_type) and sets it. |
437 | An interface already set will be released. |
438 | |
439 | @param pInterface an interface pointer |
440 | @param dummy UNO_QUERY to force obvious distinction to set methods |
441 | @return true, if non-null interface was set |
442 | */ |
443 | inline bool SAL_CALL set( XInterface * pInterface, UnoReference_Query dummy ); |
444 | /** Queries given interface for reference interface type (interface_type) and sets it. |
445 | An interface already set will be released. |
446 | |
447 | @param rRef another reference |
448 | @param dummy UNO_QUERY to force obvious distinction to set methods |
449 | @return true, if non-null interface was set |
450 | */ |
451 | inline bool SAL_CALL set( const BaseReference & rRef, UnoReference_Query dummy); |
452 | |
453 | /** Queries given any for reference interface type (interface_type) |
454 | and sets it. An interface already set will be released. |
455 | |
456 | @param rAny |
457 | an Any containing an interface |
458 | @param dummy |
459 | UNO_QUERY to force obvious distinction |
460 | to set methods |
461 | @return |
462 | true, if non-null interface was set |
463 | */ |
464 | inline bool set( Any const & rAny, UnoReference_Query dummy ); |
465 | |
466 | /** Queries given interface for reference interface type (interface_type) and sets it. |
467 | An interface already set will be released. |
468 | Throws a RuntimeException if the demanded interface cannot be set. |
469 | |
470 | @param pInterface an interface pointer |
471 | @param dummy UNO_QUERY_THROW to force obvious distinction |
472 | to set methods |
473 | */ |
474 | inline void SAL_CALL set( XInterface * pInterface, UnoReference_QueryThrow dummy ); |
475 | /** Queries given interface for reference interface type (interface_type) and sets it. |
476 | An interface already set will be released. |
477 | Throws a RuntimeException if the demanded interface cannot be set. |
478 | |
479 | @param rRef another reference |
480 | @param dummy UNO_QUERY_THROW to force obvious distinction |
481 | to set methods |
482 | */ |
483 | inline void SAL_CALL set( const BaseReference & rRef, UnoReference_QueryThrow dummy ); |
484 | #ifdef LIBO_INTERNAL_ONLY1 |
485 | /** |
486 | Prevent code from calling the QUERY_THROW version, when they meant to use the SET_THROW version. |
487 | */ |
488 | void set( const Reference< interface_type > & rRef, UnoReference_QueryThrow dummy ) = delete; |
489 | #endif |
490 | |
491 | /** Queries given any for reference interface type (interface_type) and |
492 | sets it. An interface already set will be released. |
493 | Throws a RuntimeException if the demanded interface cannot be set. |
494 | |
495 | @param rAny |
496 | an Any containing an interface |
497 | @param dummy |
498 | UNO_QUERY_THROW to force obvious distinction to set methods |
499 | */ |
500 | inline void set( Any const & rAny, UnoReference_QueryThrow dummy); |
501 | /** sets the given interface |
502 | An interface already set will be released. |
503 | Throws a RuntimeException if the source interface is @b NULL. |
504 | |
505 | @param pInterface an interface pointer |
506 | @param dummy UNO_SET_THROW to force obvious distinction to other set methods |
507 | |
508 | @since UDK 3.2.8 |
509 | */ |
510 | inline void SAL_CALL set( interface_type * pInterface, UnoReference_SetThrow dummy); |
511 | /** sets the given interface |
512 | An interface already set will be released. |
513 | Throws a RuntimeException if the source interface is @b NULL. |
514 | |
515 | @param rRef an interface reference |
516 | @param dummy UNO_SET_THROW to force obvious distinction to other set methods |
517 | |
518 | @since UDK 3.2.8 |
519 | */ |
520 | inline void SAL_CALL set( const Reference< interface_type > & rRef, UnoReference_SetThrow dummy); |
521 | |
522 | |
523 | /** Assignment operator: Acquires given interface pointer and sets reference. |
524 | An interface already set will be released. |
525 | |
526 | @param pInterface an interface pointer |
527 | @return this reference |
528 | */ |
529 | inline Reference< interface_type > & SAL_CALL operator = ( interface_type * pInterface ); |
530 | /** Assignment operator: Acquires given interface reference and sets reference. |
531 | An interface already set will be released. |
532 | |
533 | @param rRef an interface reference |
534 | @return this reference |
535 | */ |
536 | inline Reference< interface_type > & SAL_CALL operator = ( const Reference< interface_type > & rRef ); |
537 | #if defined LIBO_INTERNAL_ONLY1 |
538 | /** Assignment move operator: Acquires given interface reference and sets reference. |
539 | An interface already set will be released. |
540 | |
541 | @param rRef an interface reference |
542 | @return this reference |
543 | */ |
544 | inline Reference< interface_type > & SAL_CALL operator = ( Reference< interface_type > && rRef ) noexcept; |
545 | #endif |
546 | /** Queries given interface reference for type interface_type. |
547 | |
548 | @param rRef interface reference |
549 | @return interface reference of demanded type (may be null) |
550 | */ |
551 | SAL_WARN_UNUSED_RESULT[[nodiscard]] inline static Reference< interface_type > SAL_CALL query( const BaseReference & rRef ); |
552 | /** Queries given interface for type interface_type. |
553 | |
554 | @param pInterface interface pointer |
555 | @return interface reference of demanded type (may be null) |
556 | */ |
557 | SAL_WARN_UNUSED_RESULT[[nodiscard]] inline static Reference< interface_type > SAL_CALL query( XInterface * pInterface ); |
558 | }; |
559 | |
560 | } |
561 | } |
562 | } |
563 | } |
564 | |
565 | #endif |
566 | |
567 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |