1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: condformatbuffer.cxx,v $
10 * $Revision: 1.6.6.2 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 #include "oox/xls/condformatbuffer.hxx"
32 #include <rtl/ustrbuf.hxx>
33 #include <com/sun/star/beans/PropertyValue.hpp>
34 #include <com/sun/star/container/XIndexAccess.hpp>
35 #include <com/sun/star/container/XNameContainer.hpp>
36 #include <com/sun/star/table/CellAddress.hpp>
37 #include <com/sun/star/table/CellRangeAddress.hpp>
38 #include <com/sun/star/table/XCellRange.hpp>
39 #include <com/sun/star/sheet/ConditionOperator.hpp>
40 #include <com/sun/star/sheet/XSheetConditionalEntries.hpp>
41 #include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
42 #include <com/sun/star/sheet/XSpreadsheets.hpp>
43 #include <com/sun/star/sheet/XSpreadsheet.hpp>
44 #include <com/sun/star/style/XStyle.hpp>
45 #include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
46 #include "properties.hxx"
47 #include "oox/helper/attributelist.hxx"
48 #include "oox/helper/propertyset.hxx"
49 #include "oox/helper/recordinputstream.hxx"
50 #include "oox/xls/addressconverter.hxx"
51 #include "oox/xls/biffinputstream.hxx"
52 #include "oox/xls/stylesbuffer.hxx"
54 using ::rtl::OUString
;
55 using ::rtl::OUStringBuffer
;
56 using ::com::sun::star::uno::Any
;
57 using ::com::sun::star::uno::Reference
;
58 using ::com::sun::star::uno::Sequence
;
59 using ::com::sun::star::uno::Exception
;
60 using ::com::sun::star::uno::UNO_QUERY
;
61 using ::com::sun::star::uno::UNO_QUERY_THROW
;
62 using ::com::sun::star::beans::PropertyValue
;
63 using ::com::sun::star::style::XStyleFamiliesSupplier
;
64 using ::com::sun::star::container::XNameAccess
;
65 using ::com::sun::star::container::XIndexAccess
;
66 using ::com::sun::star::container::XNameContainer
;
67 using ::com::sun::star::table::CellAddress
;
68 using ::com::sun::star::table::CellRangeAddress
;
69 using ::com::sun::star::sheet::ConditionOperator
;
70 using ::com::sun::star::table::XCellRange
;
71 using ::com::sun::star::sheet::XSheetCellRanges
;
72 using ::com::sun::star::sheet::XSheetConditionalEntries
;
73 using ::com::sun::star::sheet::XSpreadsheetDocument
;
74 using ::com::sun::star::sheet::XSpreadsheets
;
75 using ::com::sun::star::sheet::XSpreadsheet
;
76 using ::com::sun::star::style::XStyle
;
81 // ============================================================================
85 const sal_Int32 OOBIN_CFRULE_TYPE_CELLIS
= 1;
86 const sal_Int32 OOBIN_CFRULE_TYPE_EXPRESSION
= 2;
87 const sal_Int32 OOBIN_CFRULE_TYPE_COLORSCALE
= 3;
88 const sal_Int32 OOBIN_CFRULE_TYPE_DATABAR
= 4;
89 const sal_Int32 OOBIN_CFRULE_TYPE_TOPTEN
= 5;
90 const sal_Int32 OOBIN_CFRULE_TYPE_ICONSET
= 6;
92 const sal_Int32 OOBIN_CFRULE_SUB_CELLIS
= 0;
93 const sal_Int32 OOBIN_CFRULE_SUB_EXPRESSION
= 1;
94 const sal_Int32 OOBIN_CFRULE_SUB_COLORSCALE
= 2;
95 const sal_Int32 OOBIN_CFRULE_SUB_DATABAR
= 3;
96 const sal_Int32 OOBIN_CFRULE_SUB_ICONSET
= 4;
97 const sal_Int32 OOBIN_CFRULE_SUB_TOPTEN
= 5;
98 const sal_Int32 OOBIN_CFRULE_SUB_UNIQUE
= 7;
99 const sal_Int32 OOBIN_CFRULE_SUB_TEXT
= 8;
100 const sal_Int32 OOBIN_CFRULE_SUB_BLANK
= 9;
101 const sal_Int32 OOBIN_CFRULE_SUB_NOTBLANK
= 10;
102 const sal_Int32 OOBIN_CFRULE_SUB_ERROR
= 11;
103 const sal_Int32 OOBIN_CFRULE_SUB_NOTERROR
= 12;
104 const sal_Int32 OOBIN_CFRULE_SUB_TODAY
= 15;
105 const sal_Int32 OOBIN_CFRULE_SUB_TOMORROW
= 16;
106 const sal_Int32 OOBIN_CFRULE_SUB_YESTERDAY
= 17;
107 const sal_Int32 OOBIN_CFRULE_SUB_LAST7DAYS
= 18;
108 const sal_Int32 OOBIN_CFRULE_SUB_LASTMONTH
= 19;
109 const sal_Int32 OOBIN_CFRULE_SUB_NEXTMONTH
= 20;
110 const sal_Int32 OOBIN_CFRULE_SUB_THISWEEK
= 21;
111 const sal_Int32 OOBIN_CFRULE_SUB_NEXTWEEK
= 22;
112 const sal_Int32 OOBIN_CFRULE_SUB_LASTWEEK
= 23;
113 const sal_Int32 OOBIN_CFRULE_SUB_THISMONTH
= 24;
114 const sal_Int32 OOBIN_CFRULE_SUB_ABOVEAVERAGE
= 25;
115 const sal_Int32 OOBIN_CFRULE_SUB_BELOWAVERAGE
= 26;
116 const sal_Int32 OOBIN_CFRULE_SUB_DUPLICATE
= 27;
117 const sal_Int32 OOBIN_CFRULE_SUB_EQABOVEAVERAGE
= 29;
118 const sal_Int32 OOBIN_CFRULE_SUB_EQBELOWAVERAGE
= 30;
120 const sal_Int32 OOBIN_CFRULE_TIMEOP_TODAY
= 0;
121 const sal_Int32 OOBIN_CFRULE_TIMEOP_YESTERDAY
= 1;
122 const sal_Int32 OOBIN_CFRULE_TIMEOP_LAST7DAYS
= 2;
123 const sal_Int32 OOBIN_CFRULE_TIMEOP_THISWEEK
= 3;
124 const sal_Int32 OOBIN_CFRULE_TIMEOP_LASTWEEK
= 4;
125 const sal_Int32 OOBIN_CFRULE_TIMEOP_LASTMONTH
= 5;
126 const sal_Int32 OOBIN_CFRULE_TIMEOP_TOMORROW
= 6;
127 const sal_Int32 OOBIN_CFRULE_TIMEOP_NEXTWEEK
= 7;
128 const sal_Int32 OOBIN_CFRULE_TIMEOP_NEXTMONTH
= 8;
129 const sal_Int32 OOBIN_CFRULE_TIMEOP_THISMONTH
= 9;
131 const sal_uInt16 OOBIN_CFRULE_STOPIFTRUE
= 0x0002;
132 const sal_uInt16 OOBIN_CFRULE_ABOVEAVERAGE
= 0x0004;
133 const sal_uInt16 OOBIN_CFRULE_BOTTOM
= 0x0008;
134 const sal_uInt16 OOBIN_CFRULE_PERCENT
= 0x0010;
136 // ----------------------------------------------------------------------------
138 template< typename Type
>
139 void lclAppendProperty( ::std::vector
< PropertyValue
>& orProps
, const OUString
& rPropName
, const Type
& rValue
)
141 orProps
.push_back( PropertyValue() );
142 orProps
.back().Name
= rPropName
;
143 orProps
.back().Value
<<= rValue
;
148 // ============================================================================
150 CondFormatRuleModel::CondFormatRuleModel() :
152 mnType( XML_TOKEN_INVALID
),
153 mnOperator( XML_TOKEN_INVALID
),
154 mnTimePeriod( XML_TOKEN_INVALID
),
158 mbStopIfTrue( false ),
161 mbAboveAverage( true ),
162 mbEqualAverage( false )
166 void CondFormatRuleModel::setBinOperator( sal_Int32 nOperator
)
168 static const sal_Int32 spnOperators
[] = {
169 XML_TOKEN_INVALID
, XML_between
, XML_notBetween
, XML_equal
, XML_notEqual
,
170 XML_greaterThan
, XML_lessThan
, XML_greaterThanOrEqual
, XML_lessThanOrEqual
};
171 mnOperator
= STATIC_ARRAY_SELECT( spnOperators
, nOperator
, XML_TOKEN_INVALID
);
174 void CondFormatRuleModel::setOobTextType( sal_Int32 nOperator
)
176 // note: type XML_notContainsText vs. operator XML_notContains
177 static const sal_Int32 spnTypes
[] = { XML_containsText
, XML_notContainsText
, XML_beginsWith
, XML_endsWith
};
178 mnType
= STATIC_ARRAY_SELECT( spnTypes
, nOperator
, XML_TOKEN_INVALID
);
179 static const sal_Int32 spnOperators
[] = { XML_containsText
, XML_notContains
, XML_beginsWith
, XML_endsWith
};
180 mnOperator
= STATIC_ARRAY_SELECT( spnOperators
, nOperator
, XML_TOKEN_INVALID
);
183 // ============================================================================
185 CondFormatRule::CondFormatRule( const CondFormat
& rCondFormat
) :
186 WorksheetHelper( rCondFormat
),
187 mrCondFormat( rCondFormat
)
191 void CondFormatRule::importCfRule( const AttributeList
& rAttribs
)
193 maModel
.maText
= rAttribs
.getString( XML_text
, OUString() );
194 maModel
.mnPriority
= rAttribs
.getInteger( XML_priority
, -1 );
195 maModel
.mnType
= rAttribs
.getToken( XML_type
, XML_TOKEN_INVALID
);
196 maModel
.mnOperator
= rAttribs
.getToken( XML_operator
, XML_TOKEN_INVALID
);
197 maModel
.mnTimePeriod
= rAttribs
.getToken( XML_timePeriod
, XML_TOKEN_INVALID
);
198 maModel
.mnRank
= rAttribs
.getInteger( XML_rank
, 0 );
199 maModel
.mnStdDev
= rAttribs
.getInteger( XML_stdDev
, 0 );
200 maModel
.mnDxfId
= rAttribs
.getInteger( XML_dxfId
, -1 );
201 maModel
.mbStopIfTrue
= rAttribs
.getBool( XML_stopIfTrue
, false );
202 maModel
.mbBottom
= rAttribs
.getBool( XML_bottom
, false );
203 maModel
.mbPercent
= rAttribs
.getBool( XML_percent
, false );
204 maModel
.mbAboveAverage
= rAttribs
.getBool( XML_aboveAverage
, true );
205 maModel
.mbEqualAverage
= rAttribs
.getBool( XML_equalAverage
, false );
208 void CondFormatRule::appendFormula( const OUString
& rFormula
)
210 TokensFormulaContext
aContext( true, false );
211 aContext
.setBaseAddress( mrCondFormat
.getRanges().getBaseAddress() );
212 getFormulaParser().importFormula( aContext
, rFormula
);
213 maModel
.maFormulas
.push_back( aContext
);
216 void CondFormatRule::importCfRule( RecordInputStream
& rStrm
)
218 sal_Int32 nType
, nSubType
, nOperator
, nFmla1Size
, nFmla2Size
, nFmla3Size
;
220 rStrm
>> nType
>> nSubType
>> maModel
.mnDxfId
>> maModel
.mnPriority
>> nOperator
;
222 rStrm
>> nFlags
>> nFmla1Size
>> nFmla2Size
>> nFmla3Size
>> maModel
.maText
;
224 /* Import the formulas. For no obvious reason, the sizes of the formulas
225 are already stored before. Nevertheless the following formulas contain
229 OSL_ENSURE( (nFmla1Size
>= 0) || ((nFmla2Size
== 0) && (nFmla3Size
== 0)), "CondFormatRule::importCfRule - missing first formula" );
230 OSL_ENSURE( (nFmla1Size
> 0) == (rStrm
.getRemaining() >= 8), "CondFormatRule::importCfRule - formula size mismatch" );
231 if( rStrm
.getRemaining() >= 8 )
233 TokensFormulaContext
aContext( true, false );
234 aContext
.setBaseAddress( mrCondFormat
.getRanges().getBaseAddress() );
235 getFormulaParser().importFormula( aContext
, rStrm
);
236 maModel
.maFormulas
.push_back( aContext
);
239 OSL_ENSURE( (nFmla2Size
>= 0) || (nFmla3Size
== 0), "CondFormatRule::importCfRule - missing second formula" );
240 OSL_ENSURE( (nFmla2Size
> 0) == (rStrm
.getRemaining() >= 8), "CondFormatRule::importCfRule - formula size mismatch" );
241 if( rStrm
.getRemaining() >= 8 )
243 getFormulaParser().importFormula( aContext
, rStrm
);
244 maModel
.maFormulas
.push_back( aContext
);
247 OSL_ENSURE( (nFmla3Size
> 0) == (rStrm
.getRemaining() >= 8), "CondFormatRule::importCfRule - formula size mismatch" );
248 if( rStrm
.getRemaining() >= 8 )
250 getFormulaParser().importFormula( aContext
, rStrm
);
251 maModel
.maFormulas
.push_back( aContext
);
257 maModel
.mbStopIfTrue
= getFlag( nFlags
, OOBIN_CFRULE_STOPIFTRUE
);
258 maModel
.mbBottom
= getFlag( nFlags
, OOBIN_CFRULE_BOTTOM
);
259 maModel
.mbPercent
= getFlag( nFlags
, OOBIN_CFRULE_PERCENT
);
260 maModel
.mbAboveAverage
= getFlag( nFlags
, OOBIN_CFRULE_ABOVEAVERAGE
);
261 // no flag for equalAverage, must be determined from subtype below...
263 // Convert the type/operator settings. This is a real mess...
266 case OOBIN_CFRULE_TYPE_CELLIS
:
267 OSL_ENSURE( nSubType
== OOBIN_CFRULE_SUB_CELLIS
, "CondFormatRule::importCfRule - rule type/subtype mismatch" );
268 maModel
.mnType
= XML_cellIs
;
269 maModel
.setBinOperator( nOperator
);
270 OSL_ENSURE( maModel
.mnOperator
!= XML_TOKEN_INVALID
, "CondFormatRule::importCfRule - unknown operator" );
272 case OOBIN_CFRULE_TYPE_EXPRESSION
:
273 // here we have to look at the subtype to find the real type...
276 case OOBIN_CFRULE_SUB_EXPRESSION
:
277 OSL_ENSURE( nOperator
== 0, "CondFormatRule::importCfRule - unexpected operator value" );
278 maModel
.mnType
= XML_expression
;
280 case OOBIN_CFRULE_SUB_UNIQUE
:
281 OSL_ENSURE( nOperator
== 0, "CondFormatRule::importCfRule - unexpected operator value" );
282 maModel
.mnType
= XML_uniqueValues
;
284 case OOBIN_CFRULE_SUB_TEXT
:
285 maModel
.setOobTextType( nOperator
);
286 OSL_ENSURE( maModel
.mnType
!= XML_TOKEN_INVALID
, "CondFormatRule::importCfRule - unexpected operator value" );
288 case OOBIN_CFRULE_SUB_BLANK
:
289 OSL_ENSURE( nOperator
== 0, "CondFormatRule::importCfRule - unexpected operator value" );
290 maModel
.mnType
= XML_containsBlanks
;
292 case OOBIN_CFRULE_SUB_NOTBLANK
:
293 OSL_ENSURE( nOperator
== 0, "CondFormatRule::importCfRule - unexpected operator value" );
294 maModel
.mnType
= XML_notContainsBlanks
;
296 case OOBIN_CFRULE_SUB_ERROR
:
297 OSL_ENSURE( nOperator
== 0, "CondFormatRule::importCfRule - unexpected operator value" );
298 maModel
.mnType
= XML_containsErrors
;
300 case OOBIN_CFRULE_SUB_NOTERROR
:
301 OSL_ENSURE( nOperator
== 0, "CondFormatRule::importCfRule - unexpected operator value" );
302 maModel
.mnType
= XML_notContainsErrors
;
304 case OOBIN_CFRULE_SUB_TODAY
:
305 OSL_ENSURE( nOperator
== OOBIN_CFRULE_TIMEOP_TODAY
, "CondFormatRule::importCfRule - unexpected time operator value" );
306 maModel
.mnType
= XML_timePeriod
;
307 maModel
.mnTimePeriod
= XML_today
;
309 case OOBIN_CFRULE_SUB_TOMORROW
:
310 OSL_ENSURE( nOperator
== OOBIN_CFRULE_TIMEOP_TOMORROW
, "CondFormatRule::importCfRule - unexpected time operator value" );
311 maModel
.mnType
= XML_timePeriod
;
312 maModel
.mnTimePeriod
= XML_tomorrow
;
314 case OOBIN_CFRULE_SUB_YESTERDAY
:
315 OSL_ENSURE( nOperator
== OOBIN_CFRULE_TIMEOP_YESTERDAY
, "CondFormatRule::importCfRule - unexpected time operator value" );
316 maModel
.mnType
= XML_timePeriod
;
317 maModel
.mnTimePeriod
= XML_yesterday
;
319 case OOBIN_CFRULE_SUB_LAST7DAYS
:
320 OSL_ENSURE( nOperator
== OOBIN_CFRULE_TIMEOP_LAST7DAYS
, "CondFormatRule::importCfRule - unexpected time operator value" );
321 maModel
.mnType
= XML_timePeriod
;
322 maModel
.mnTimePeriod
= XML_last7Days
;
324 case OOBIN_CFRULE_SUB_LASTMONTH
:
325 OSL_ENSURE( nOperator
== OOBIN_CFRULE_TIMEOP_LASTMONTH
, "CondFormatRule::importCfRule - unexpected time operator value" );
326 maModel
.mnType
= XML_timePeriod
;
327 maModel
.mnTimePeriod
= XML_lastMonth
;
329 case OOBIN_CFRULE_SUB_NEXTMONTH
:
330 OSL_ENSURE( nOperator
== OOBIN_CFRULE_TIMEOP_NEXTMONTH
, "CondFormatRule::importCfRule - unexpected time operator value" );
331 maModel
.mnType
= XML_timePeriod
;
332 maModel
.mnTimePeriod
= XML_nextMonth
;
334 case OOBIN_CFRULE_SUB_THISWEEK
:
335 OSL_ENSURE( nOperator
== OOBIN_CFRULE_TIMEOP_THISWEEK
, "CondFormatRule::importCfRule - unexpected time operator value" );
336 maModel
.mnType
= XML_timePeriod
;
337 maModel
.mnTimePeriod
= XML_thisWeek
;
339 case OOBIN_CFRULE_SUB_NEXTWEEK
:
340 OSL_ENSURE( nOperator
== OOBIN_CFRULE_TIMEOP_NEXTWEEK
, "CondFormatRule::importCfRule - unexpected time operator value" );
341 maModel
.mnType
= XML_timePeriod
;
342 maModel
.mnTimePeriod
= XML_nextWeek
;
344 case OOBIN_CFRULE_SUB_LASTWEEK
:
345 OSL_ENSURE( nOperator
== OOBIN_CFRULE_TIMEOP_LASTWEEK
, "CondFormatRule::importCfRule - unexpected time operator value" );
346 maModel
.mnType
= XML_timePeriod
;
347 maModel
.mnTimePeriod
= XML_lastWeek
;
349 case OOBIN_CFRULE_SUB_THISMONTH
:
350 OSL_ENSURE( nOperator
== OOBIN_CFRULE_TIMEOP_THISMONTH
, "CondFormatRule::importCfRule - unexpected time operator value" );
351 maModel
.mnType
= XML_timePeriod
;
352 maModel
.mnTimePeriod
= XML_thisMonth
;
354 case OOBIN_CFRULE_SUB_ABOVEAVERAGE
:
355 OSL_ENSURE( maModel
.mbAboveAverage
, "CondFormatRule::importCfRule - wrong above-average flag" );
356 maModel
.mnType
= XML_aboveAverage
;
357 maModel
.mnStdDev
= nOperator
; // operator field used for standard deviation
358 maModel
.mbAboveAverage
= true;
359 maModel
.mbEqualAverage
= false; // does not exist as real flag...
361 case OOBIN_CFRULE_SUB_BELOWAVERAGE
:
362 OSL_ENSURE( !maModel
.mbAboveAverage
, "CondFormatRule::importCfRule - wrong above-average flag" );
363 maModel
.mnType
= XML_aboveAverage
;
364 maModel
.mnStdDev
= nOperator
; // operator field used for standard deviation
365 maModel
.mbAboveAverage
= false;
366 maModel
.mbEqualAverage
= false; // does not exist as real flag...
368 case OOBIN_CFRULE_SUB_DUPLICATE
:
369 OSL_ENSURE( nOperator
== 0, "CondFormatRule::importCfRule - unexpected operator value" );
370 maModel
.mnType
= XML_duplicateValues
;
372 case OOBIN_CFRULE_SUB_EQABOVEAVERAGE
:
373 OSL_ENSURE( maModel
.mbAboveAverage
, "CondFormatRule::importCfRule - wrong above-average flag" );
374 maModel
.mnType
= XML_aboveAverage
;
375 maModel
.mnStdDev
= nOperator
; // operator field used for standard deviation
376 maModel
.mbAboveAverage
= true;
377 maModel
.mbEqualAverage
= true; // does not exist as real flag...
379 case OOBIN_CFRULE_SUB_EQBELOWAVERAGE
:
380 OSL_ENSURE( !maModel
.mbAboveAverage
, "CondFormatRule::importCfRule - wrong above-average flag" );
381 maModel
.mnType
= XML_aboveAverage
;
382 maModel
.mnStdDev
= nOperator
; // operator field used for standard deviation
383 maModel
.mbAboveAverage
= false;
384 maModel
.mbEqualAverage
= true; // does not exist as real flag...
388 case OOBIN_CFRULE_TYPE_COLORSCALE
:
389 OSL_ENSURE( nSubType
== OOBIN_CFRULE_SUB_COLORSCALE
, "CondFormatRule::importCfRule - rule type/subtype mismatch" );
390 OSL_ENSURE( nOperator
== 0, "CondFormatRule::importCfRule - unexpected operator value" );
391 maModel
.mnType
= XML_colorScale
;
393 case OOBIN_CFRULE_TYPE_DATABAR
:
394 OSL_ENSURE( nSubType
== OOBIN_CFRULE_SUB_DATABAR
, "CondFormatRule::importCfRule - rule type/subtype mismatch" );
395 OSL_ENSURE( nOperator
== 0, "CondFormatRule::importCfRule - unexpected operator value" );
396 maModel
.mnType
= XML_dataBar
;
398 case OOBIN_CFRULE_TYPE_TOPTEN
:
399 OSL_ENSURE( nSubType
== OOBIN_CFRULE_SUB_TOPTEN
, "CondFormatRule::importCfRule - rule type/subtype mismatch" );
400 maModel
.mnType
= XML_top10
;
401 maModel
.mnRank
= nOperator
; // operator field used for rank value
403 case OOBIN_CFRULE_TYPE_ICONSET
:
404 OSL_ENSURE( nSubType
== OOBIN_CFRULE_SUB_ICONSET
, "CondFormatRule::importCfRule - rule type/subtype mismatch" );
405 OSL_ENSURE( nOperator
== 0, "CondFormatRule::importCfRule - unexpected operator value" );
406 maModel
.mnType
= XML_iconSet
;
409 OSL_ENSURE( false, "CondFormatRule::importCfRule - unknown rule type" );
413 void CondFormatRule::importCfRule( BiffInputStream
& rStrm
, sal_Int32 nPriority
)
415 sal_uInt8 nType
, nOperator
;
416 sal_uInt16 nFmla1Size
, nFmla2Size
;
418 rStrm
>> nType
>> nOperator
>> nFmla1Size
>> nFmla2Size
>> nFlags
;
421 static const sal_Int32 spnTypeIds
[] = { XML_TOKEN_INVALID
, XML_cellIs
, XML_expression
};
422 maModel
.mnType
= STATIC_ARRAY_SELECT( spnTypeIds
, nType
, XML_TOKEN_INVALID
);
424 maModel
.setBinOperator( nOperator
);
425 maModel
.mnPriority
= nPriority
;
426 maModel
.mbStopIfTrue
= true;
428 DxfRef xDxf
= getStyles().createDxf( &maModel
.mnDxfId
);
429 xDxf
->importCfRule( rStrm
, nFlags
);
430 xDxf
->finalizeImport();
432 // import the formulas
433 OSL_ENSURE( (nFmla1Size
> 0) || (nFmla2Size
== 0), "CondFormatRule::importCfRule - missing first formula" );
436 TokensFormulaContext
aContext( true, false );
437 aContext
.setBaseAddress( mrCondFormat
.getRanges().getBaseAddress() );
438 getFormulaParser().importFormula( aContext
, rStrm
, &nFmla1Size
);
439 maModel
.maFormulas
.push_back( aContext
);
442 getFormulaParser().importFormula( aContext
, rStrm
, &nFmla2Size
);
443 maModel
.maFormulas
.push_back( aContext
);
448 void CondFormatRule::finalizeImport( const Reference
< XSheetConditionalEntries
>& rxEntries
)
450 ConditionOperator eOperator
= ::com::sun::star::sheet::ConditionOperator_NONE
;
452 /* Replacement formula for unsupported rule types (text comparison rules,
453 time period rules, cell type rules). The replacement formulas below may
454 contain several placeholders:
455 - '#B' will be replaced by the current relative base address (may occur
457 - '#R' will be replaced by the entire range list of the conditional
458 formatting (absolute addresses).
459 - '#T' will be replaced by the quoted comparison text.
460 - '#L' will be replaced by the length of the comparison text (from
461 the 'text' attribute) used in text comparison rules.
462 - '#K' will be replaced by the rank (from the 'rank' attribute) used in
464 - '#M' will be replaced by the top/bottom flag (from the 'bottom'
465 attribute) used in the RANK function in top-10 rules.
466 - '#C' will be replaced by one of the comparison operators <, >, <=, or
467 >=, according to the 'aboveAverage' and 'equalAverage' flags.
469 OUString aReplaceFormula
;
471 switch( maModel
.mnType
)
474 eOperator
= CondFormatBuffer::convertToApiOperator( maModel
.mnOperator
);
477 eOperator
= ::com::sun::star::sheet::ConditionOperator_FORMULA
;
479 case XML_containsText
:
480 OSL_ENSURE( maModel
.mnOperator
== XML_containsText
, "CondFormatRule::finalizeImport - unexpected operator" );
481 aReplaceFormula
= CREATE_OUSTRING( "NOT(ISERROR(SEARCH(#T,#B)))" );
483 case XML_notContainsText
:
484 // note: type XML_notContainsText vs. operator XML_notContains
485 OSL_ENSURE( maModel
.mnOperator
== XML_notContains
, "CondFormatRule::finalizeImport - unexpected operator" );
486 aReplaceFormula
= CREATE_OUSTRING( "ISERROR(SEARCH(#T,#B))" );
489 OSL_ENSURE( maModel
.mnOperator
== XML_beginsWith
, "CondFormatRule::finalizeImport - unexpected operator" );
490 aReplaceFormula
= CREATE_OUSTRING( "LEFT(#B,#L)=#T" );
493 OSL_ENSURE( maModel
.mnOperator
== XML_endsWith
, "CondFormatRule::finalizeImport - unexpected operator" );
494 aReplaceFormula
= CREATE_OUSTRING( "RIGHT(#B,#L)=#T" );
497 switch( maModel
.mnTimePeriod
)
500 aReplaceFormula
= CREATE_OUSTRING( "FLOOR(#B,1)=TODAY()-1" );
503 aReplaceFormula
= CREATE_OUSTRING( "FLOOR(#B,1)=TODAY()" );
506 aReplaceFormula
= CREATE_OUSTRING( "FLOOR(#B,1)=TODAY()+1" );
509 aReplaceFormula
= CREATE_OUSTRING( "AND(TODAY()-7<FLOOR(#B,1),FLOOR(#B,1)<=TODAY())" );
512 aReplaceFormula
= CREATE_OUSTRING( "AND(TODAY()-WEEKDAY(TODAY())-7<FLOOR(#B,1),FLOOR(#B,1)<=TODAY()-WEEKDAY(TODAY()))" );
515 aReplaceFormula
= CREATE_OUSTRING( "AND(TODAY()-WEEKDAY(TODAY())<FLOOR(#B,1),FLOOR(#B,1)<=TODAY()-WEEKDAY(TODAY())+7)" );
518 aReplaceFormula
= CREATE_OUSTRING( "AND(TODAY()-WEEKDAY(TODAY())+7<FLOOR(#B,1),FLOOR(#B,1)<=TODAY()-WEEKDAY(TODAY())+14)" );
521 aReplaceFormula
= CREATE_OUSTRING( "OR(AND(MONTH(#B)=MONTH(TODAY())-1,YEAR(#B)=YEAR(TODAY())),AND(MONTH(#B)=12,MONTH(TODAY())=1,YEAR(#B)=YEAR(TODAY())-1))" );
524 aReplaceFormula
= CREATE_OUSTRING( "AND(MONTH(#B)=MONTH(TODAY()),YEAR(#B)=YEAR(TODAY()))" );
527 aReplaceFormula
= CREATE_OUSTRING( "OR(AND(MONTH(#B)=MONTH(TODAY())+1,YEAR(#B)=YEAR(TODAY())),AND(MONTH(#B)=1,MONTH(TODAY())=12,YEAR(#B)=YEAR(TODAY())+1))" );
530 OSL_ENSURE( false, "CondFormatRule::finalizeImport - unknown time period type" );
533 case XML_containsBlanks
:
534 aReplaceFormula
= CREATE_OUSTRING( "LEN(TRIM(#B))=0" );
536 case XML_notContainsBlanks
:
537 aReplaceFormula
= CREATE_OUSTRING( "LEN(TRIM(#B))>0" );
539 case XML_containsErrors
:
540 aReplaceFormula
= CREATE_OUSTRING( "ISERROR(#B)" );
542 case XML_notContainsErrors
:
543 aReplaceFormula
= CREATE_OUSTRING( "NOT(ISERROR(#B))" );
546 if( maModel
.mbPercent
)
547 aReplaceFormula
= CREATE_OUSTRING( "RANK(#B,#R,#M)/COUNT(#R)<=#K%" );
549 aReplaceFormula
= CREATE_OUSTRING( "RANK(#B,#R,#M)<=#K" );
551 case XML_aboveAverage
:
552 if( maModel
.mnStdDev
== 0 )
553 aReplaceFormula
= CREATE_OUSTRING( "#B#CAVERAGE(#R)" );
557 if( aReplaceFormula
.getLength() > 0 )
559 OUString aAddress
, aRanges
, aText
, aComp
;
560 sal_Int32 nStrPos
= aReplaceFormula
.getLength();
561 while( (nStrPos
= aReplaceFormula
.lastIndexOf( '#', nStrPos
)) >= 0 )
563 switch( aReplaceFormula
[ nStrPos
+ 1 ] )
565 case 'B': // current base address
566 if( aAddress
.getLength() == 0 )
567 aAddress
= FormulaProcessorBase::generateAddress2dString( mrCondFormat
.getRanges().getBaseAddress(), false );
568 aReplaceFormula
= aReplaceFormula
.replaceAt( nStrPos
, 2, aAddress
);
570 case 'R': // range list of conditional formatting
571 if( aRanges
.getLength() == 0 )
572 aRanges
= FormulaProcessorBase::generateRangeList2dString( mrCondFormat
.getRanges(), true, ',', true );
573 aReplaceFormula
= aReplaceFormula
.replaceAt( nStrPos
, 2, aRanges
);
575 case 'T': // comparison text
576 if( aText
.getLength() == 0 )
577 // quote the comparison text, and handle embedded quote characters
578 aText
= FormulaProcessorBase::generateApiString( maModel
.maText
);
579 aReplaceFormula
= aReplaceFormula
.replaceAt( nStrPos
, 2, aText
);
581 case 'L': // length of comparison text
582 aReplaceFormula
= aReplaceFormula
.replaceAt( nStrPos
, 2,
583 OUString::valueOf( maModel
.maText
.getLength() ) );
585 case 'K': // top-10 rank
586 aReplaceFormula
= aReplaceFormula
.replaceAt( nStrPos
, 2,
587 OUString::valueOf( maModel
.mnRank
) );
589 case 'M': // top-10 top/bottom flag
590 aReplaceFormula
= aReplaceFormula
.replaceAt( nStrPos
, 2,
591 OUString::valueOf( static_cast< sal_Int32
>( maModel
.mbBottom
? 1 : 0 ) ) );
593 case 'C': // average comparison operator
594 if( aComp
.getLength() == 0 )
595 aComp
= maModel
.mbAboveAverage
?
596 (maModel
.mbEqualAverage
? CREATE_OUSTRING( ">=" ) : CREATE_OUSTRING( ">" )) :
597 (maModel
.mbEqualAverage
? CREATE_OUSTRING( "<=" ) : CREATE_OUSTRING( "<" ));
598 aReplaceFormula
= aReplaceFormula
.replaceAt( nStrPos
, 2, aComp
);
601 OSL_ENSURE( false, "CondFormatRule::finalizeImport - unknown placeholder" );
605 // set the replacement formula
606 maModel
.maFormulas
.clear();
607 appendFormula( aReplaceFormula
);
608 eOperator
= ::com::sun::star::sheet::ConditionOperator_FORMULA
;
611 if( rxEntries
.is() && (eOperator
!= ::com::sun::star::sheet::ConditionOperator_NONE
) && !maModel
.maFormulas
.empty() )
613 ::std::vector
< PropertyValue
> aProps
;
614 // create condition properties
615 lclAppendProperty( aProps
, CREATE_OUSTRING( "Operator" ), eOperator
);
616 lclAppendProperty( aProps
, CREATE_OUSTRING( "Formula1" ), maModel
.maFormulas
[ 0 ].getTokens() );
617 if( maModel
.maFormulas
.size() >= 2 )
618 lclAppendProperty( aProps
, CREATE_OUSTRING( "Formula2" ), maModel
.maFormulas
[ 1 ].getTokens() );
620 // style name for the formatting attributes
621 OUString aStyleName
= getStyles().createDxfStyle( maModel
.mnDxfId
);
622 if( aStyleName
.getLength() > 0 )
623 lclAppendProperty( aProps
, CREATE_OUSTRING( "StyleName" ), aStyleName
);
625 // append the new rule
628 rxEntries
->addNew( ContainerHelper::vectorToSequence( aProps
) );
636 // ============================================================================
638 CondFormatModel::CondFormatModel() :
643 // ============================================================================
645 CondFormat::CondFormat( const WorksheetHelper
& rHelper
) :
646 WorksheetHelper( rHelper
)
650 void CondFormat::importConditionalFormatting( const AttributeList
& rAttribs
)
652 getAddressConverter().convertToCellRangeList( maModel
.maRanges
, rAttribs
.getString( XML_sqref
, OUString() ), getSheetIndex(), true );
653 maModel
.mbPivot
= rAttribs
.getBool( XML_pivot
, false );
656 CondFormatRuleRef
CondFormat::importCfRule( const AttributeList
& rAttribs
)
658 CondFormatRuleRef xRule
= createRule();
659 xRule
->importCfRule( rAttribs
);
664 void CondFormat::importCondFormatting( RecordInputStream
& rStrm
)
666 BinRangeList aRanges
;
669 getAddressConverter().convertToCellRangeList( maModel
.maRanges
, aRanges
, getSheetIndex(), true );
672 void CondFormat::importCfRule( RecordInputStream
& rStrm
)
674 CondFormatRuleRef xRule
= createRule();
675 xRule
->importCfRule( rStrm
);
679 void CondFormat::importCfHeader( BiffInputStream
& rStrm
)
681 // import the CFHEADER record
682 sal_uInt16 nRuleCount
;
683 BinRangeList aRanges
;
687 getAddressConverter().convertToCellRangeList( maModel
.maRanges
, aRanges
, getSheetIndex(), true );
689 // import following list of CFRULE records
690 for( sal_uInt16 nRule
= 0; (nRule
< nRuleCount
) && (rStrm
.getNextRecId() == BIFF_ID_CFRULE
) && rStrm
.startNextRecord(); ++nRule
)
692 CondFormatRuleRef xRule
= createRule();
693 xRule
->importCfRule( rStrm
, nRule
+ 1 );
698 void CondFormat::finalizeImport()
700 Reference
< XSheetCellRanges
> xRanges
= getCellRangeList( maModel
.maRanges
);
703 PropertySet
aPropSet( xRanges
);
704 Reference
< XSheetConditionalEntries
> xEntries
;
705 aPropSet
.getProperty( xEntries
, PROP_ConditionalFormat
);
708 // maRules is sorted by rule priority
709 maRules
.forEachMem( &CondFormatRule::finalizeImport
, ::boost::cref( xEntries
) );
710 aPropSet
.setProperty( PROP_ConditionalFormat
, xEntries
);
715 CondFormatRuleRef
CondFormat::createRule()
717 return CondFormatRuleRef( new CondFormatRule( *this ) );
720 void CondFormat::insertRule( CondFormatRuleRef xRule
)
722 if( xRule
.get() && (xRule
->getPriority() > 0) )
724 OSL_ENSURE( maRules
.find( xRule
->getPriority() ) == maRules
.end(), "CondFormat::insertRule - multiple rules with equal priority" );
725 maRules
[ xRule
->getPriority() ] = xRule
;
729 // ============================================================================
731 CondFormatBuffer::CondFormatBuffer( const WorksheetHelper
& rHelper
) :
732 WorksheetHelper( rHelper
)
736 CondFormatRef
CondFormatBuffer::importConditionalFormatting( const AttributeList
& rAttribs
)
738 CondFormatRef xCondFmt
= createCondFormat();
739 xCondFmt
->importConditionalFormatting( rAttribs
);
743 CondFormatRef
CondFormatBuffer::importCondFormatting( RecordInputStream
& rStrm
)
745 CondFormatRef xCondFmt
= createCondFormat();
746 xCondFmt
->importCondFormatting( rStrm
);
750 void CondFormatBuffer::importCfHeader( BiffInputStream
& rStrm
)
752 createCondFormat()->importCfHeader( rStrm
);
755 void CondFormatBuffer::finalizeImport()
757 maCondFormats
.forEachMem( &CondFormat::finalizeImport
);
760 ConditionOperator
CondFormatBuffer::convertToApiOperator( sal_Int32 nToken
)
762 using namespace ::com::sun::star::sheet
;
765 case XML_between
: return ConditionOperator_BETWEEN
;
766 case XML_equal
: return ConditionOperator_EQUAL
;
767 case XML_greaterThan
: return ConditionOperator_GREATER
;
768 case XML_greaterThanOrEqual
: return ConditionOperator_GREATER_EQUAL
;
769 case XML_lessThan
: return ConditionOperator_LESS
;
770 case XML_lessThanOrEqual
: return ConditionOperator_LESS_EQUAL
;
771 case XML_notBetween
: return ConditionOperator_NOT_BETWEEN
;
772 case XML_notEqual
: return ConditionOperator_NOT_EQUAL
;
774 return ConditionOperator_NONE
;
777 // private --------------------------------------------------------------------
779 CondFormatRef
CondFormatBuffer::createCondFormat()
781 CondFormatRef
xCondFmt( new CondFormat( *this ) );
782 maCondFormats
.push_back( xCondFmt
);
786 // ============================================================================