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 <memory>
21 #include <unordered_set>
22 #include <unordered_map>
23 #include <condformatbuffer.hxx>
24 #include <formulaparser.hxx>
25
26 #include <com/sun/star/sheet/ConditionOperator2.hpp>
27 #include <sal/log.hxx>
28 #include <osl/diagnose.h>
29 #include <o3tl/string_view.hxx>
30 #include <svl/sharedstringpool.hxx>
31 #include <oox/core/filterbase.hxx>
32 #include <oox/helper/binaryinputstream.hxx>
33 #include <oox/helper/attributelist.hxx>
34 #include <oox/token/tokens.hxx>
35 #include <addressconverter.hxx>
36 #include <biffhelper.hxx>
37 #include <stylesbuffer.hxx>
38 #include <themebuffer.hxx>
39
40 #include <colorscale.hxx>
41 #include <conditio.hxx>
42 #include <document.hxx>
43 #include <tokenarray.hxx>
44 #include <tokenuno.hxx>
45 #include <extlstcontext.hxx>
46 #include <utility>
47
48 namespace oox::xls {
49
50 using namespace ::com::sun::star::sheet;
51 using namespace ::com::sun::star::uno;
52
53 namespace {
54
55 const sal_Int32 BIFF12_CFRULE_TYPE_CELLIS = 1;
56 const sal_Int32 BIFF12_CFRULE_TYPE_EXPRESSION = 2;
57 const sal_Int32 BIFF12_CFRULE_TYPE_COLORSCALE = 3;
58 const sal_Int32 BIFF12_CFRULE_TYPE_DATABAR = 4;
59 const sal_Int32 BIFF12_CFRULE_TYPE_TOPTEN = 5;
60 const sal_Int32 BIFF12_CFRULE_TYPE_ICONSET = 6;
61
62 const sal_Int32 BIFF12_CFRULE_SUB_CELLIS = 0;
63 const sal_Int32 BIFF12_CFRULE_SUB_EXPRESSION = 1;
64 const sal_Int32 BIFF12_CFRULE_SUB_COLORSCALE = 2;
65 const sal_Int32 BIFF12_CFRULE_SUB_DATABAR = 3;
66 const sal_Int32 BIFF12_CFRULE_SUB_ICONSET = 4;
67 const sal_Int32 BIFF12_CFRULE_SUB_TOPTEN = 5;
68 const sal_Int32 BIFF12_CFRULE_SUB_UNIQUE = 7;
69 const sal_Int32 BIFF12_CFRULE_SUB_TEXT = 8;
70 const sal_Int32 BIFF12_CFRULE_SUB_BLANK = 9;
71 const sal_Int32 BIFF12_CFRULE_SUB_NOTBLANK = 10;
72 const sal_Int32 BIFF12_CFRULE_SUB_ERROR = 11;
73 const sal_Int32 BIFF12_CFRULE_SUB_NOTERROR = 12;
74 const sal_Int32 BIFF12_CFRULE_SUB_TODAY = 15;
75 const sal_Int32 BIFF12_CFRULE_SUB_TOMORROW = 16;
76 const sal_Int32 BIFF12_CFRULE_SUB_YESTERDAY = 17;
77 const sal_Int32 BIFF12_CFRULE_SUB_LAST7DAYS = 18;
78 const sal_Int32 BIFF12_CFRULE_SUB_LASTMONTH = 19;
79 const sal_Int32 BIFF12_CFRULE_SUB_NEXTMONTH = 20;
80 const sal_Int32 BIFF12_CFRULE_SUB_THISWEEK = 21;
81 const sal_Int32 BIFF12_CFRULE_SUB_NEXTWEEK = 22;
82 const sal_Int32 BIFF12_CFRULE_SUB_LASTWEEK = 23;
83 const sal_Int32 BIFF12_CFRULE_SUB_THISMONTH = 24;
84 const sal_Int32 BIFF12_CFRULE_SUB_ABOVEAVERAGE = 25;
85 const sal_Int32 BIFF12_CFRULE_SUB_BELOWAVERAGE = 26;
86 const sal_Int32 BIFF12_CFRULE_SUB_DUPLICATE = 27;
87 const sal_Int32 BIFF12_CFRULE_SUB_EQABOVEAVERAGE = 29;
88 const sal_Int32 BIFF12_CFRULE_SUB_EQBELOWAVERAGE = 30;
89
90 const sal_Int32 BIFF12_CFRULE_TIMEOP_TODAY = 0;
91 const sal_Int32 BIFF12_CFRULE_TIMEOP_YESTERDAY = 1;
92 const sal_Int32 BIFF12_CFRULE_TIMEOP_LAST7DAYS = 2;
93 const sal_Int32 BIFF12_CFRULE_TIMEOP_THISWEEK = 3;
94 const sal_Int32 BIFF12_CFRULE_TIMEOP_LASTWEEK = 4;
95 const sal_Int32 BIFF12_CFRULE_TIMEOP_LASTMONTH = 5;
96 const sal_Int32 BIFF12_CFRULE_TIMEOP_TOMORROW = 6;
97 const sal_Int32 BIFF12_CFRULE_TIMEOP_NEXTWEEK = 7;
98 const sal_Int32 BIFF12_CFRULE_TIMEOP_NEXTMONTH = 8;
99 const sal_Int32 BIFF12_CFRULE_TIMEOP_THISMONTH = 9;
100
101 const sal_uInt16 BIFF12_CFRULE_STOPIFTRUE = 0x0002;
102 const sal_uInt16 BIFF12_CFRULE_ABOVEAVERAGE = 0x0004;
103 const sal_uInt16 BIFF12_CFRULE_BOTTOM = 0x0008;
104 const sal_uInt16 BIFF12_CFRULE_PERCENT = 0x0010;
105
isValue(std::u16string_view rStr,double & rVal)106 bool isValue(std::u16string_view rStr, double& rVal)
107 {
108 sal_Int32 nEnd = -1;
109 rVal = rtl::math::stringToDouble(o3tl::trim(rStr), '.', ',', nullptr, &nEnd);
110
111 return nEnd >= static_cast<sal_Int32>(rStr.size());
112 }
113
SetCfvoData(ColorScaleRuleModelEntry * pEntry,const AttributeList & rAttribs)114 void SetCfvoData( ColorScaleRuleModelEntry* pEntry, const AttributeList& rAttribs )
115 {
116 OUString aType = rAttribs.getString( XML_type, OUString() );
117 OUString aVal = rAttribs.getString(XML_val, OUString());
118
119 if (aVal != "\"\"")
120 {
121 double nVal = 0.0;
122 bool bVal = isValue(aVal, nVal);
123 if( !bVal || aType == "formula" )
124 {
125 pEntry->maFormula = aVal;
126 }
127 else
128 {
129 pEntry->mnVal = nVal;
130 }
131 }
132
133 if (aType == "num")
134 {
135 pEntry->mbNum = true;
136 }
137 else if( aType == "min" )
138 {
139 pEntry->mbMin = true;
140 }
141 else if( aType == "max" )
142 {
143 pEntry->mbMax = true;
144 }
145 else if( aType == "percent" )
146 {
147 pEntry->mbPercent = true;
148 }
149 else if( aType == "percentile" )
150 {
151 pEntry->mbPercentile = true;
152 }
153 }
154
155 }
156
ColorScaleRule(const CondFormat & rFormat)157 ColorScaleRule::ColorScaleRule( const CondFormat& rFormat ):
158 WorksheetHelper( rFormat ),
159 mnCfvo(0),
160 mnCol(0)
161 {
162 }
163
importCfvo(const AttributeList & rAttribs)164 void ColorScaleRule::importCfvo( const AttributeList& rAttribs )
165 {
166 if(mnCfvo >= maColorScaleRuleEntries.size())
167 maColorScaleRuleEntries.emplace_back();
168
169 SetCfvoData( &maColorScaleRuleEntries[mnCfvo], rAttribs );
170
171 ++mnCfvo;
172 }
173
174 // https://learn.microsoft.com/en-us/dotnet/api/documentformat.openxml.spreadsheet.indexedcolors?view=openxml-2.8.1
175 static ::Color IndexedColors[] = {
176 0x00000000,
177 0x00FFFFFF,
178 0x00FF0000,
179 0x0000FF00,
180 0x000000FF,
181 0x00FFFF00,
182 0x00FF00FF,
183 0x0000FFFF,
184 0x00000000,
185 0x00FFFFFF,
186 0x00FF0000,
187 0x0000FF00,
188 0x000000FF,
189 0x00FFFF00,
190 0x00FF00FF,
191 0x0000FFFF,
192 0x00800000,
193 0x00008000,
194 0x00000080,
195 0x00808000,
196 0x00800080,
197 0x00008080,
198 0x00C0C0C0,
199 0x00808080,
200 0x009999FF,
201 0x00993366,
202 0x00FFFFCC,
203 0x00CCFFFF,
204 0x00660066,
205 0x00FF8080,
206 0x000066CC,
207 0x00CCCCFF,
208 0x00000080,
209 0x00FF00FF,
210 0x00FFFF00,
211 0x0000FFFF,
212 0x00800080,
213 0x00800000,
214 0x00008080,
215 0x000000FF,
216 0x0000CCFF,
217 0x00CCFFFF,
218 0x00CCFFCC,
219 0x00FFFF99,
220 0x0099CCFF,
221 0x00FF99CC,
222 0x00CC99FF,
223 0x00FFCC99,
224 0x003366FF,
225 0x0033CCCC,
226 0x0099CC00,
227 0x00FFCC00,
228 0x00FF9900,
229 0x00FF6600,
230 0x00666699,
231 0x00969696,
232 0x00003366,
233 0x00339966,
234 0x00003300,
235 0x00333300,
236 0x00993300,
237 0x00993366,
238 0x00333399,
239 0x00333333,
240 0x00000000, // System Foreground ?
241 0x00000000, // System Background ?
242 };
243
244 namespace {
245
importOOXColor(const AttributeList & rAttribs,const ThemeBuffer & rThemeBuffer,const GraphicHelper & rGraphicHelper)246 ::Color importOOXColor(const AttributeList& rAttribs, const ThemeBuffer& rThemeBuffer, const GraphicHelper& rGraphicHelper)
247 {
248 ::Color nColor;
249 if( rAttribs.hasAttribute( XML_rgb ) )
250 nColor = ::Color(ColorTransparency, rAttribs.getUnsignedHex( XML_rgb, UNSIGNED_RGB_TRANSPARENT ));
251 else if( rAttribs.hasAttribute( XML_theme ) )
252 {
253 sal_uInt32 nThemeIndex = rAttribs.getUnsigned( XML_theme, 0 );
254
255 // Excel has a bug in the mapping of index 0, 1, 2 and 3.
256 if (nThemeIndex == 0)
257 nThemeIndex = 1;
258 else if (nThemeIndex == 1)
259 nThemeIndex = 0;
260 else if (nThemeIndex == 2)
261 nThemeIndex = 3;
262 else if (nThemeIndex == 3)
263 nThemeIndex = 2;
264
265 nColor = rThemeBuffer.getColorByIndex( nThemeIndex );
266 }
267 else if (rAttribs.hasAttribute(XML_indexed))
268 {
269 sal_uInt32 nIndexed = rAttribs.getUnsigned(XML_indexed, 0);
270 if (nIndexed < std::size(IndexedColors))
271 nColor = IndexedColors[nIndexed];
272 }
273
274 ::Color aColor;
275 double nTint = rAttribs.getDouble(XML_tint, 0.0);
276 if (nTint != 0.0)
277 {
278 oox::drawingml::Color aDMColor;
279 aDMColor.setSrgbClr(nColor);
280 aDMColor.addExcelTintTransformation(nTint);
281 aColor = aDMColor.getColor(rGraphicHelper);
282 }
283 else
284 aColor = nColor.GetRGBColor();
285
286 return aColor;
287 }
288
289 }
290
importColor(const AttributeList & rAttribs)291 void ColorScaleRule::importColor( const AttributeList& rAttribs )
292 {
293 ThemeBuffer& rThemeBuffer = getTheme();
294 GraphicHelper& rGraphicHelper = getBaseFilter().getGraphicHelper();
295 ::Color aColor = importOOXColor(rAttribs, rThemeBuffer, rGraphicHelper);
296
297 if(mnCol >= maColorScaleRuleEntries.size())
298 maColorScaleRuleEntries.emplace_back();
299
300 maColorScaleRuleEntries[mnCol].maColor = aColor;
301 ++mnCol;
302 }
303
304 namespace {
305
ConvertToModel(const ColorScaleRuleModelEntry & rEntry,ScDocument * pDoc,const ScAddress & rAddr)306 ScColorScaleEntry* ConvertToModel( const ColorScaleRuleModelEntry& rEntry, ScDocument* pDoc, const ScAddress& rAddr )
307 {
308 ScColorScaleEntry* pEntry = new ScColorScaleEntry(rEntry.mnVal, rEntry.maColor);
309
310 if(rEntry.mbMin)
311 pEntry->SetType(COLORSCALE_MIN);
312 if(rEntry.mbMax)
313 pEntry->SetType(COLORSCALE_MAX);
314 if(rEntry.mbPercent)
315 pEntry->SetType(COLORSCALE_PERCENT);
316 if(rEntry.mbPercentile)
317 pEntry->SetType(COLORSCALE_PERCENTILE);
318 if (rEntry.mbNum)
319 pEntry->SetType(COLORSCALE_VALUE);
320
321 if(!rEntry.maFormula.isEmpty())
322 {
323 pEntry->SetType(COLORSCALE_FORMULA);
324 pEntry->SetFormula(rEntry.maFormula, *pDoc, rAddr, formula::FormulaGrammar::GRAM_ENGLISH_XL_A1);
325 }
326
327 return pEntry;
328 }
329
330 }
331
AddEntries(ScColorScaleFormat * pFormat,ScDocument * pDoc,const ScAddress & rAddr)332 void ColorScaleRule::AddEntries( ScColorScaleFormat* pFormat, ScDocument* pDoc, const ScAddress& rAddr )
333 {
334 for(const ColorScaleRuleModelEntry & rEntry : maColorScaleRuleEntries)
335 {
336 ScColorScaleEntry* pEntry = ConvertToModel( rEntry, pDoc, rAddr );
337
338 pFormat->AddEntry( pEntry );
339 }
340 }
341
DataBarRule(const CondFormat & rFormat)342 DataBarRule::DataBarRule( const CondFormat& rFormat ):
343 WorksheetHelper( rFormat ),
344 mxFormat(new ScDataBarFormatData)
345 {
346 mxFormat->meAxisPosition = databar::NONE;
347 }
348
importColor(const AttributeList & rAttribs)349 void DataBarRule::importColor( const AttributeList& rAttribs )
350 {
351 ThemeBuffer& rThemeBuffer = getTheme();
352 GraphicHelper& rGraphicHelper = getBaseFilter().getGraphicHelper();
353 ::Color aColor = importOOXColor(rAttribs, rThemeBuffer, rGraphicHelper);
354
355 mxFormat->maPositiveColor = aColor;
356 }
357
importCfvo(const AttributeList & rAttribs)358 void DataBarRule::importCfvo( const AttributeList& rAttribs )
359 {
360 ColorScaleRuleModelEntry* pEntry;
361 if(!mpLowerLimit)
362 {
363 mpLowerLimit.reset(new ColorScaleRuleModelEntry);
364 pEntry = mpLowerLimit.get();
365 }
366 else
367 {
368 mpUpperLimit.reset(new ColorScaleRuleModelEntry);
369 pEntry = mpUpperLimit.get();
370 }
371
372 SetCfvoData( pEntry, rAttribs );
373 }
374
importAttribs(const AttributeList & rAttribs)375 void DataBarRule::importAttribs( const AttributeList& rAttribs )
376 {
377 mxFormat->mbOnlyBar = !rAttribs.getBool( XML_showValue, true );
378 mxFormat->mnMinLength = rAttribs.getUnsigned( XML_minLength, 10);
379 mxFormat->mnMaxLength = rAttribs.getUnsigned( XML_maxLength, 90);
380 }
381
SetData(ScDataBarFormat * pFormat,ScDocument * pDoc,const ScAddress & rAddr)382 void DataBarRule::SetData( ScDataBarFormat* pFormat, ScDocument* pDoc, const ScAddress& rAddr )
383 {
384 ScColorScaleEntry* pUpperEntry = ConvertToModel(*mpUpperLimit, pDoc, rAddr);
385 ScColorScaleEntry* pLowerEntry = ConvertToModel(*mpLowerLimit, pDoc, rAddr);
386
387 mxFormat->mpUpperLimit.reset( pUpperEntry );
388 mxFormat->mpLowerLimit.reset( pLowerEntry );
389 pFormat->SetDataBarData(mxFormat.release());
390 }
391
IconSetRule(const WorksheetHelper & rParent)392 IconSetRule::IconSetRule( const WorksheetHelper& rParent ):
393 WorksheetHelper( rParent ),
394 mxFormatData( new ScIconSetFormatData ),
395 mbCustom(false)
396 {
397 }
398
importCfvo(const AttributeList & rAttribs)399 void IconSetRule::importCfvo( const AttributeList& rAttribs )
400 {
401 ColorScaleRuleModelEntry aNewEntry;
402 SetCfvoData(&aNewEntry, rAttribs);
403
404 maEntries.push_back(aNewEntry);
405 }
406
importAttribs(const AttributeList & rAttribs)407 void IconSetRule::importAttribs( const AttributeList& rAttribs )
408 {
409 maIconSetType = rAttribs.getString( XML_iconSet, u"3TrafficLights1"_ustr );
410 mxFormatData->mbShowValue = rAttribs.getBool( XML_showValue, true );
411 mxFormatData->mbReverse = rAttribs.getBool( XML_reverse, false );
412 mbCustom = rAttribs.getBool(XML_custom, false);
413 }
414
importFormula(const OUString & rFormula)415 void IconSetRule::importFormula(const OUString& rFormula)
416 {
417 ColorScaleRuleModelEntry& rEntry = maEntries.back();
418 double nVal = 0.0;
419 if ((rEntry.mbNum || rEntry.mbPercent || rEntry.mbPercentile) && isValue(rFormula, nVal))
420 {
421 rEntry.mnVal = nVal;
422 }
423 else if (!rFormula.isEmpty())
424 rEntry.maFormula = rFormula;
425 }
426
427 namespace {
428
getType(std::u16string_view rName)429 ScIconSetType getType(std::u16string_view rName)
430 {
431 ScIconSetType eIconSetType = IconSet_3TrafficLights1;
432 const ScIconSetMap* pIconSetMap = ScIconSetFormat::g_IconSetMap;
433 for(size_t i = 0; !pIconSetMap[i].aName.isEmpty(); ++i)
434 {
435 if(pIconSetMap[i].aName == rName)
436 {
437 eIconSetType = pIconSetMap[i].eType;
438 break;
439 }
440 }
441
442 return eIconSetType;
443 }
444
445 }
446
importIcon(const AttributeList & rAttribs)447 void IconSetRule::importIcon(const AttributeList& rAttribs)
448 {
449 OUString aIconSet = rAttribs.getString(XML_iconSet, OUString());
450 sal_Int32 nIndex = rAttribs.getInteger(XML_iconId, -1);
451 if (aIconSet == "NoIcons")
452 {
453 nIndex = -1;
454 }
455
456 ScIconSetType eIconSetType = getType(aIconSet);
457 mxFormatData->maCustomVector.emplace_back(eIconSetType, nIndex);
458 }
459
SetData(ScIconSetFormat * pFormat,ScDocument * pDoc,const ScAddress & rPos)460 void IconSetRule::SetData( ScIconSetFormat* pFormat, ScDocument* pDoc, const ScAddress& rPos )
461 {
462 for(const ColorScaleRuleModelEntry & rEntry : maEntries)
463 {
464 ScColorScaleEntry* pModelEntry = ConvertToModel( rEntry, pDoc, rPos );
465 mxFormatData->m_Entries.emplace_back(pModelEntry);
466 }
467
468 mxFormatData->eIconSetType = getType(maIconSetType);
469 mxFormatData->mbCustom = mbCustom;
470 pFormat->SetIconSetData(mxFormatData.release());
471 }
472
CondFormatRuleModel()473 CondFormatRuleModel::CondFormatRuleModel() :
474 mnPriority( -1 ),
475 mnType( XML_TOKEN_INVALID ),
476 mnOperator( XML_TOKEN_INVALID ),
477 mnTimePeriod( XML_TOKEN_INVALID ),
478 mnRank( 0 ),
479 mnStdDev( 0 ),
480 mnDxfId( -1 ),
481 mbStopIfTrue( false ),
482 mbBottom( false ),
483 mbPercent( false ),
484 mbAboveAverage( true ),
485 mbEqualAverage( false )
486 {
487 }
488
setBiffOperator(sal_Int32 nOperator)489 void CondFormatRuleModel::setBiffOperator( sal_Int32 nOperator )
490 {
491 static const sal_Int32 spnOperators[] = {
492 XML_TOKEN_INVALID, XML_between, XML_notBetween, XML_equal, XML_notEqual,
493 XML_greaterThan, XML_lessThan, XML_greaterThanOrEqual, XML_lessThanOrEqual };
494 mnOperator = STATIC_ARRAY_SELECT( spnOperators, nOperator, XML_TOKEN_INVALID );
495 }
496
setBiff12TextType(sal_Int32 nOperator)497 void CondFormatRuleModel::setBiff12TextType( sal_Int32 nOperator )
498 {
499 // note: type XML_notContainsText vs. operator XML_notContains
500 static const sal_Int32 spnTypes[] = { XML_containsText, XML_notContainsText, XML_beginsWith, XML_endsWith };
501 mnType = STATIC_ARRAY_SELECT( spnTypes, nOperator, XML_TOKEN_INVALID );
502 static const sal_Int32 spnOperators[] = { XML_containsText, XML_notContains, XML_beginsWith, XML_endsWith };
503 mnOperator = STATIC_ARRAY_SELECT( spnOperators, nOperator, XML_TOKEN_INVALID );
504 }
505
CondFormatRule(const CondFormat & rCondFormat,ScConditionalFormat * pFormat)506 CondFormatRule::CondFormatRule( const CondFormat& rCondFormat, ScConditionalFormat* pFormat ) :
507 WorksheetHelper( rCondFormat ),
508 mrCondFormat( rCondFormat ),
509 mpFormat(pFormat),
510 mpFormatEntry(nullptr)
511 {
512 }
513
importCfRule(const AttributeList & rAttribs)514 void CondFormatRule::importCfRule( const AttributeList& rAttribs )
515 {
516 maModel.maText = rAttribs.getString( XML_text, OUString() );
517 maModel.mnPriority = rAttribs.getInteger( XML_priority, -1 );
518 maModel.mnType = rAttribs.getToken( XML_type, XML_TOKEN_INVALID );
519 maModel.mnOperator = rAttribs.getToken( XML_operator, XML_TOKEN_INVALID );
520 maModel.mnTimePeriod = rAttribs.getToken( XML_timePeriod, XML_TOKEN_INVALID );
521 maModel.mnRank = rAttribs.getInteger( XML_rank, 0 );
522 maModel.mnStdDev = rAttribs.getInteger( XML_stdDev, 0 );
523 maModel.mnDxfId = rAttribs.getInteger( XML_dxfId, -1 );
524 maModel.mbStopIfTrue = rAttribs.getBool( XML_stopIfTrue, false );
525 maModel.mbBottom = rAttribs.getBool( XML_bottom, false );
526 maModel.mbPercent = rAttribs.getBool( XML_percent, false );
527 maModel.mbAboveAverage = rAttribs.getBool( XML_aboveAverage, true );
528 maModel.mbEqualAverage = rAttribs.getBool( XML_equalAverage, false );
529
530 if(maModel.mnType == XML_colorScale)
531 {
532 //import the remaining values
533
534 }
535 }
536
appendFormula(const OUString & rFormula)537 void CondFormatRule::appendFormula( const OUString& rFormula )
538 {
539 ScAddress aBaseAddr = mrCondFormat.getRanges().GetTopLeftCorner();
540 ApiTokenSequence aTokens = getFormulaParser().importFormula( aBaseAddr, rFormula );
541 maModel.maFormulas.push_back( aTokens );
542 }
543
importCfRule(SequenceInputStream & rStrm)544 void CondFormatRule::importCfRule( SequenceInputStream& rStrm )
545 {
546 sal_Int32 nType, nSubType, nOperator, nFmla1Size, nFmla2Size, nFmla3Size;
547 sal_uInt16 nFlags;
548 nType = rStrm.readInt32();
549 nSubType = rStrm.readInt32();
550 maModel.mnDxfId = rStrm.readInt32();
551 maModel.mnPriority = rStrm.readInt32();
552 nOperator = rStrm.readInt32();
553 rStrm.skip( 8 );
554 nFlags = rStrm.readuInt16();
555 nFmla1Size = rStrm.readInt32();
556 nFmla2Size = rStrm.readInt32();
557 nFmla3Size = rStrm.readInt32();
558 rStrm >> maModel.maText;
559
560 /* Import the formulas. For no obvious reason, the sizes of the formulas
561 are already stored before. Nevertheless the following formulas contain
562 their own sizes. */
563
564 // first formula
565 // I am not bored enough to bother simplifying these expressions
566 SAL_WARN_IF( !( (nFmla1Size >= 0) || ((nFmla2Size == 0) && (nFmla3Size == 0)) ), "sc.filter", "CondFormatRule::importCfRule - missing first formula" );
567 SAL_WARN_IF( !( (nFmla1Size > 0) == (rStrm.getRemaining() >= 8) ), "sc.filter", "CondFormatRule::importCfRule - formula size mismatch" );
568 if( rStrm.getRemaining() >= 8 )
569 {
570 ScAddress aBaseAddr = mrCondFormat.getRanges().GetTopLeftCorner();
571 ApiTokenSequence aTokens = getFormulaParser().importFormula( aBaseAddr, FormulaType::CondFormat, rStrm );
572 maModel.maFormulas.push_back( aTokens );
573
574 // second formula
575 OSL_ENSURE( (nFmla2Size >= 0) || (nFmla3Size == 0), "CondFormatRule::importCfRule - missing second formula" );
576 OSL_ENSURE( (nFmla2Size > 0) == (rStrm.getRemaining() >= 8), "CondFormatRule::importCfRule - formula size mismatch" );
577 if( rStrm.getRemaining() >= 8 )
578 {
579 aTokens = getFormulaParser().importFormula( aBaseAddr, FormulaType::CondFormat, rStrm );
580 maModel.maFormulas.push_back( aTokens );
581
582 // third formula
583 OSL_ENSURE( (nFmla3Size > 0) == (rStrm.getRemaining() >= 8), "CondFormatRule::importCfRule - formula size mismatch" );
584 if( rStrm.getRemaining() >= 8 )
585 {
586 aTokens = getFormulaParser().importFormula( aBaseAddr, FormulaType::CondFormat, rStrm );
587 maModel.maFormulas.push_back( aTokens );
588 }
589 }
590 }
591
592 // flags
593 maModel.mbStopIfTrue = getFlag( nFlags, BIFF12_CFRULE_STOPIFTRUE );
594 maModel.mbBottom = getFlag( nFlags, BIFF12_CFRULE_BOTTOM );
595 maModel.mbPercent = getFlag( nFlags, BIFF12_CFRULE_PERCENT );
596 maModel.mbAboveAverage = getFlag( nFlags, BIFF12_CFRULE_ABOVEAVERAGE );
597 // no flag for equalAverage, must be determined from subtype below...
598
599 // Convert the type/operator settings. This is a real mess...
600 switch( nType )
601 {
602 case BIFF12_CFRULE_TYPE_CELLIS:
603 SAL_WARN_IF(
604 nSubType != BIFF12_CFRULE_SUB_CELLIS, "sc.filter",
605 "CondFormatRule::importCfRule - rule type/subtype mismatch");
606 maModel.mnType = XML_cellIs;
607 maModel.setBiffOperator( nOperator );
608 OSL_ENSURE( maModel.mnOperator != XML_TOKEN_INVALID, "CondFormatRule::importCfRule - unknown operator" );
609 break;
610 case BIFF12_CFRULE_TYPE_EXPRESSION:
611 // here we have to look at the subtype to find the real type...
612 switch( nSubType )
613 {
614 case BIFF12_CFRULE_SUB_EXPRESSION:
615 OSL_ENSURE( nOperator == 0, "CondFormatRule::importCfRule - unexpected operator value" );
616 maModel.mnType = XML_expression;
617 break;
618 case BIFF12_CFRULE_SUB_UNIQUE:
619 OSL_ENSURE( nOperator == 0, "CondFormatRule::importCfRule - unexpected operator value" );
620 maModel.mnType = XML_uniqueValues;
621 break;
622 case BIFF12_CFRULE_SUB_TEXT:
623 maModel.setBiff12TextType( nOperator );
624 OSL_ENSURE( maModel.mnType != XML_TOKEN_INVALID, "CondFormatRule::importCfRule - unexpected operator value" );
625 break;
626 case BIFF12_CFRULE_SUB_BLANK:
627 OSL_ENSURE( nOperator == 0, "CondFormatRule::importCfRule - unexpected operator value" );
628 maModel.mnType = XML_containsBlanks;
629 break;
630 case BIFF12_CFRULE_SUB_NOTBLANK:
631 OSL_ENSURE( nOperator == 0, "CondFormatRule::importCfRule - unexpected operator value" );
632 maModel.mnType = XML_notContainsBlanks;
633 break;
634 case BIFF12_CFRULE_SUB_ERROR:
635 OSL_ENSURE( nOperator == 0, "CondFormatRule::importCfRule - unexpected operator value" );
636 maModel.mnType = XML_containsErrors;
637 break;
638 case BIFF12_CFRULE_SUB_NOTERROR:
639 OSL_ENSURE( nOperator == 0, "CondFormatRule::importCfRule - unexpected operator value" );
640 maModel.mnType = XML_notContainsErrors;
641 break;
642 case BIFF12_CFRULE_SUB_TODAY:
643 SAL_WARN_IF(
644 nOperator != BIFF12_CFRULE_TIMEOP_TODAY, "sc.filter",
645 "CondFormatRule::importCfRule - unexpected time operator value");
646 maModel.mnType = XML_timePeriod;
647 maModel.mnTimePeriod = XML_today;
648 break;
649 case BIFF12_CFRULE_SUB_TOMORROW:
650 SAL_WARN_IF(
651 nOperator != BIFF12_CFRULE_TIMEOP_TOMORROW, "sc.filter",
652 "CondFormatRule::importCfRule - unexpected time operator value");
653 maModel.mnType = XML_timePeriod;
654 maModel.mnTimePeriod = XML_tomorrow;
655 break;
656 case BIFF12_CFRULE_SUB_YESTERDAY:
657 SAL_WARN_IF(
658 nOperator != BIFF12_CFRULE_TIMEOP_YESTERDAY,
659 "sc.filter",
660 "CondFormatRule::importCfRule - unexpected time operator value");
661 maModel.mnType = XML_timePeriod;
662 maModel.mnTimePeriod = XML_yesterday;
663 break;
664 case BIFF12_CFRULE_SUB_LAST7DAYS:
665 SAL_WARN_IF(
666 nOperator != BIFF12_CFRULE_TIMEOP_LAST7DAYS,
667 "sc.filter",
668 "CondFormatRule::importCfRule - unexpected time operator value");
669 maModel.mnType = XML_timePeriod;
670 maModel.mnTimePeriod = XML_last7Days;
671 break;
672 case BIFF12_CFRULE_SUB_LASTMONTH:
673 SAL_WARN_IF(
674 nOperator != BIFF12_CFRULE_TIMEOP_LASTMONTH,
675 "sc.filter",
676 "CondFormatRule::importCfRule - unexpected time operator value");
677 maModel.mnType = XML_timePeriod;
678 maModel.mnTimePeriod = XML_lastMonth;
679 break;
680 case BIFF12_CFRULE_SUB_NEXTMONTH:
681 SAL_WARN_IF(
682 nOperator != BIFF12_CFRULE_TIMEOP_NEXTMONTH,
683 "sc.filter",
684 "CondFormatRule::importCfRule - unexpected time operator value");
685 maModel.mnType = XML_timePeriod;
686 maModel.mnTimePeriod = XML_nextMonth;
687 break;
688 case BIFF12_CFRULE_SUB_THISWEEK:
689 SAL_WARN_IF(
690 nOperator != BIFF12_CFRULE_TIMEOP_THISWEEK, "sc.filter",
691 "CondFormatRule::importCfRule - unexpected time operator value");
692 maModel.mnType = XML_timePeriod;
693 maModel.mnTimePeriod = XML_thisWeek;
694 break;
695 case BIFF12_CFRULE_SUB_NEXTWEEK:
696 SAL_WARN_IF(
697 nOperator != BIFF12_CFRULE_TIMEOP_NEXTWEEK, "sc.filter",
698 "CondFormatRule::importCfRule - unexpected time operator value");
699 maModel.mnType = XML_timePeriod;
700 maModel.mnTimePeriod = XML_nextWeek;
701 break;
702 case BIFF12_CFRULE_SUB_LASTWEEK:
703 SAL_WARN_IF(
704 nOperator != BIFF12_CFRULE_TIMEOP_LASTWEEK, "sc.filter",
705 "CondFormatRule::importCfRule - unexpected time operator value");
706 maModel.mnType = XML_timePeriod;
707 maModel.mnTimePeriod = XML_lastWeek;
708 break;
709 case BIFF12_CFRULE_SUB_THISMONTH:
710 SAL_WARN_IF(
711 nOperator != BIFF12_CFRULE_TIMEOP_THISMONTH,
712 "sc.filter",
713 "CondFormatRule::importCfRule - unexpected time operator value");
714 maModel.mnType = XML_timePeriod;
715 maModel.mnTimePeriod = XML_thisMonth;
716 break;
717 case BIFF12_CFRULE_SUB_ABOVEAVERAGE:
718 OSL_ENSURE( maModel.mbAboveAverage, "CondFormatRule::importCfRule - wrong above-average flag" );
719 maModel.mnType = XML_aboveAverage;
720 maModel.mnStdDev = nOperator; // operator field used for standard deviation
721 maModel.mbAboveAverage = true;
722 maModel.mbEqualAverage = false; // does not exist as real flag...
723 break;
724 case BIFF12_CFRULE_SUB_BELOWAVERAGE:
725 OSL_ENSURE( !maModel.mbAboveAverage, "CondFormatRule::importCfRule - wrong above-average flag" );
726 maModel.mnType = XML_aboveAverage;
727 maModel.mnStdDev = nOperator; // operator field used for standard deviation
728 maModel.mbAboveAverage = false;
729 maModel.mbEqualAverage = false; // does not exist as real flag...
730 break;
731 case BIFF12_CFRULE_SUB_DUPLICATE:
732 OSL_ENSURE( nOperator == 0, "CondFormatRule::importCfRule - unexpected operator value" );
733 maModel.mnType = XML_duplicateValues;
734 break;
735 case BIFF12_CFRULE_SUB_EQABOVEAVERAGE:
736 OSL_ENSURE( maModel.mbAboveAverage, "CondFormatRule::importCfRule - wrong above-average flag" );
737 maModel.mnType = XML_aboveAverage;
738 maModel.mnStdDev = nOperator; // operator field used for standard deviation
739 maModel.mbAboveAverage = true;
740 maModel.mbEqualAverage = true; // does not exist as real flag...
741 break;
742 case BIFF12_CFRULE_SUB_EQBELOWAVERAGE:
743 OSL_ENSURE( !maModel.mbAboveAverage, "CondFormatRule::importCfRule - wrong above-average flag" );
744 maModel.mnType = XML_aboveAverage;
745 maModel.mnStdDev = nOperator; // operator field used for standard deviation
746 maModel.mbAboveAverage = false;
747 maModel.mbEqualAverage = true; // does not exist as real flag...
748 break;
749 }
750 break;
751 case BIFF12_CFRULE_TYPE_COLORSCALE:
752 SAL_WARN_IF(
753 nSubType != BIFF12_CFRULE_SUB_COLORSCALE, "sc.filter",
754 "CondFormatRule::importCfRule - rule type/subtype mismatch");
755 OSL_ENSURE( nOperator == 0, "CondFormatRule::importCfRule - unexpected operator value" );
756 maModel.mnType = XML_colorScale;
757 break;
758 case BIFF12_CFRULE_TYPE_DATABAR:
759 SAL_WARN_IF(
760 nSubType != BIFF12_CFRULE_SUB_DATABAR, "sc.filter",
761 "CondFormatRule::importCfRule - rule type/subtype mismatch");
762 OSL_ENSURE( nOperator == 0, "CondFormatRule::importCfRule - unexpected operator value" );
763 maModel.mnType = XML_dataBar;
764 break;
765 case BIFF12_CFRULE_TYPE_TOPTEN:
766 SAL_WARN_IF(
767 nSubType != BIFF12_CFRULE_SUB_TOPTEN, "sc.filter",
768 "CondFormatRule::importCfRule - rule type/subtype mismatch");
769 maModel.mnType = XML_top10;
770 maModel.mnRank = nOperator; // operator field used for rank value
771 break;
772 case BIFF12_CFRULE_TYPE_ICONSET:
773 SAL_WARN_IF(
774 nSubType != BIFF12_CFRULE_SUB_ICONSET, "sc.filter",
775 "CondFormatRule::importCfRule - rule type/subtype mismatch");
776 OSL_ENSURE( nOperator == 0, "CondFormatRule::importCfRule - unexpected operator value" );
777 maModel.mnType = XML_iconSet;
778 break;
779 default:
780 OSL_FAIL( "CondFormatRule::importCfRule - unknown rule type" );
781 }
782 }
783
setFormatEntry(sal_Int32 nPriority,ScFormatEntry * pEntry)784 void CondFormatRule::setFormatEntry(sal_Int32 nPriority, ScFormatEntry* pEntry)
785 {
786 maModel.mnPriority = nPriority;
787 mpFormatEntry = pEntry;
788 }
789
finalizeImport()790 void CondFormatRule::finalizeImport()
791 {
792 if (mpFormatEntry)
793 {
794 mpFormat->AddEntry(mpFormatEntry);
795 return;
796 }
797
798 ScConditionMode eOperator = ScConditionMode::NONE;
799
800 /* Replacement formula for unsupported rule types (text comparison rules,
801 time period rules, cell type rules). The replacement formulas below may
802 contain several placeholders:
803 - '#B' will be replaced by the current relative base address (may occur
804 several times).
805 - '#R' will be replaced by the entire range list of the conditional
806 formatting (absolute addresses).
807 - '#T' will be replaced by the quoted comparison text.
808 - '#L' will be replaced by the length of the comparison text (from
809 the 'text' attribute) used in text comparison rules.
810 - '#K' will be replaced by the rank (from the 'rank' attribute) used in
811 top-10 rules.
812 - '#M' will be replaced by the top/bottom flag (from the 'bottom'
813 attribute) used in the RANK function in top-10 rules.
814 - '#C' will be replaced by one of the comparison operators <, >, <=, or
815 >=, according to the 'aboveAverage' and 'equalAverage' flags.
816 */
817 OUString aReplaceFormula;
818
819 switch( maModel.mnType )
820 {
821 case XML_cellIs:
822 eOperator = CondFormatBuffer::convertToInternalOperator( maModel.mnOperator );
823 break;
824 case XML_duplicateValues:
825 eOperator = ScConditionMode::Duplicate;
826 break;
827 case XML_uniqueValues:
828 eOperator = ScConditionMode::NotDuplicate;
829 break;
830 case XML_expression:
831 eOperator = ScConditionMode::Direct;
832 break;
833 case XML_containsText:
834 OSL_ENSURE( maModel.mnOperator == XML_containsText, "CondFormatRule::finalizeImport - unexpected operator" );
835 eOperator = ScConditionMode::ContainsText;
836 break;
837 case XML_notContainsText:
838 // note: type XML_notContainsText vs. operator XML_notContains
839 OSL_ENSURE( maModel.mnOperator == XML_notContains, "CondFormatRule::finalizeImport - unexpected operator" );
840 eOperator = ScConditionMode::NotContainsText;
841 break;
842 case XML_beginsWith:
843 OSL_ENSURE( maModel.mnOperator == XML_beginsWith, "CondFormatRule::finalizeImport - unexpected operator" );
844 eOperator = ScConditionMode::BeginsWith;
845 break;
846 case XML_endsWith:
847 OSL_ENSURE( maModel.mnOperator == XML_endsWith, "CondFormatRule::finalizeImport - unexpected operator" );
848 eOperator = ScConditionMode::EndsWith;
849 break;
850 case XML_timePeriod:
851 break;
852 case XML_containsBlanks:
853 aReplaceFormula = "LEN(TRIM(#B))=0";
854 break;
855 case XML_notContainsBlanks:
856 aReplaceFormula = "LEN(TRIM(#B))>0";
857 break;
858 case XML_containsErrors:
859 eOperator = ScConditionMode::Error;
860 break;
861 case XML_notContainsErrors:
862 eOperator = ScConditionMode::NoError;
863 break;
864 case XML_top10:
865 if(maModel.mbPercent)
866 {
867 if(maModel.mbBottom)
868 eOperator = ScConditionMode::BottomPercent;
869 else
870 eOperator = ScConditionMode::TopPercent;
871 }
872 else
873 {
874 if(maModel.mbBottom)
875 eOperator = ScConditionMode::Bottom10;
876 else
877 eOperator = ScConditionMode::Top10;
878 }
879 break;
880 case XML_aboveAverage:
881 if(maModel.mbAboveAverage)
882 {
883 if(maModel.mbEqualAverage)
884 eOperator = ScConditionMode::AboveEqualAverage;
885 else
886 eOperator = ScConditionMode::AboveAverage;
887 }
888 else
889 {
890 if(maModel.mbEqualAverage)
891 eOperator = ScConditionMode::BelowEqualAverage;
892 else
893 eOperator = ScConditionMode::BelowAverage;
894 }
895 break;
896 case XML_colorScale:
897 break;
898 }
899
900 if( !aReplaceFormula.isEmpty() )
901 {
902 OUString aAddress;
903 sal_Int32 nStrPos = aReplaceFormula.getLength();
904 while( (nStrPos = aReplaceFormula.lastIndexOf( '#', nStrPos )) >= 0 )
905 {
906 switch( aReplaceFormula[ nStrPos + 1 ] )
907 {
908 case 'B': // current base address
909 if( aAddress.isEmpty() )
910 aAddress = FormulaProcessorBase::generateAddress2dString( mrCondFormat.getRanges().GetTopLeftCorner(), false );
911 aReplaceFormula = aReplaceFormula.replaceAt( nStrPos, 2, aAddress );
912 break;
913 default:
914 OSL_FAIL( "CondFormatRule::finalizeImport - unknown placeholder" );
915 }
916 }
917
918 // set the replacement formula
919 maModel.maFormulas.clear();
920 appendFormula( aReplaceFormula );
921 eOperator = ScConditionMode::Direct;
922 }
923
924 ScAddress aPos = mrCondFormat.getRanges().GetTopLeftCorner();
925
926 if( eOperator == ScConditionMode::Error || eOperator == ScConditionMode::NoError )
927 {
928 ScDocument& rDoc = getScDocument();
929 OUString aStyleName = getStyles().createDxfStyle( maModel.mnDxfId );
930 ScCondFormatEntry* pNewEntry = new ScCondFormatEntry( eOperator, nullptr, nullptr, rDoc, aPos, aStyleName );
931 mpFormat->AddEntry(pNewEntry);
932 }
933 else if( eOperator == ScConditionMode::BeginsWith || eOperator == ScConditionMode::EndsWith ||
934 eOperator == ScConditionMode::ContainsText || eOperator == ScConditionMode::NotContainsText )
935 {
936 ScDocument& rDoc = getScDocument();
937 ScTokenArray aTokenArray(rDoc);
938 svl::SharedStringPool& rSPool = rDoc.GetSharedStringPool();
939 aTokenArray.AddString(rSPool.intern(maModel.maText));
940 OUString aStyleName = getStyles().createDxfStyle( maModel.mnDxfId );
941 ScCondFormatEntry* pNewEntry = new ScCondFormatEntry( eOperator, &aTokenArray, nullptr, rDoc, aPos, aStyleName );
942 mpFormat->AddEntry(pNewEntry);
943 }
944 else if( (eOperator != ScConditionMode::NONE) && !maModel.maFormulas.empty() )
945 {
946 ScDocument& rDoc = getScDocument();
947 std::unique_ptr<ScTokenArray> pTokenArray2;
948 if( maModel.maFormulas.size() >= 2)
949 {
950 pTokenArray2.reset(new ScTokenArray(rDoc));
951 ScTokenConversion::ConvertToTokenArray(rDoc, *pTokenArray2, maModel.maFormulas[1]);
952 rDoc.CheckLinkFormulaNeedingCheck(*pTokenArray2);
953 }
954
955 ScTokenArray aTokenArray(rDoc);
956 OUString aStyleName = getStyles().createDxfStyle( maModel.mnDxfId );
957 ScTokenConversion::ConvertToTokenArray( rDoc, aTokenArray, maModel.maFormulas[ 0 ] );
958 rDoc.CheckLinkFormulaNeedingCheck( aTokenArray);
959 ScCondFormatEntry* pNewEntry = new ScCondFormatEntry(eOperator,
960 &aTokenArray, pTokenArray2.get(), rDoc, aPos, aStyleName);
961 mpFormat->AddEntry(pNewEntry);
962 }
963 else if ( eOperator == ScConditionMode::Top10 || eOperator == ScConditionMode::Bottom10 ||
964 eOperator == ScConditionMode::TopPercent || eOperator == ScConditionMode::BottomPercent )
965 {
966 ScDocument& rDoc = getScDocument();
967 ScTokenArray aTokenArray(rDoc);
968 aTokenArray.AddDouble( maModel.mnRank );
969 OUString aStyleName = getStyles().createDxfStyle( maModel.mnDxfId );
970 ScCondFormatEntry* pNewEntry = new ScCondFormatEntry( eOperator, &aTokenArray, nullptr, rDoc, aPos, aStyleName );
971 mpFormat->AddEntry(pNewEntry);
972 }
973 else if( eOperator == ScConditionMode::AboveAverage || eOperator == ScConditionMode::BelowAverage ||
974 eOperator == ScConditionMode::AboveEqualAverage || eOperator == ScConditionMode::BelowEqualAverage )
975 {
976 ScDocument& rDoc = getScDocument();
977 // actually that is still unsupported
978 ScTokenArray aTokenArrayDev(rDoc);
979 aTokenArrayDev.AddDouble( maModel.mnStdDev );
980 OUString aStyleName = getStyles().createDxfStyle( maModel.mnDxfId );
981 ScCondFormatEntry* pNewEntry = new ScCondFormatEntry( eOperator, &aTokenArrayDev, nullptr, rDoc, aPos, aStyleName );
982 mpFormat->AddEntry(pNewEntry);
983 }
984 else if( eOperator == ScConditionMode::Duplicate || eOperator == ScConditionMode::NotDuplicate )
985 {
986 ScDocument& rDoc = getScDocument();
987 OUString aStyleName = getStyles().createDxfStyle( maModel.mnDxfId );
988 ScCondFormatEntry* pNewEntry = new ScCondFormatEntry( eOperator, nullptr, nullptr, rDoc, aPos, aStyleName );
989 mpFormat->AddEntry(pNewEntry);
990 }
991 else if( maModel.mnType == XML_timePeriod )
992 {
993 condformat::ScCondFormatDateType eDateType = condformat::TODAY;
994 switch( maModel.mnTimePeriod )
995 {
996 case XML_yesterday:
997 eDateType = condformat::YESTERDAY;
998 break;
999 case XML_today:
1000 eDateType = condformat::TODAY;
1001 break;
1002 case XML_tomorrow:
1003 eDateType = condformat::TOMORROW;
1004 break;
1005 case XML_last7Days:
1006 eDateType = condformat::LAST7DAYS;
1007 break;
1008 case XML_lastWeek:
1009 eDateType = condformat::LASTWEEK;
1010 break;
1011 case XML_thisWeek:
1012 eDateType = condformat::THISWEEK;
1013 break;
1014 case XML_nextWeek:
1015 eDateType = condformat::NEXTWEEK;
1016 break;
1017 case XML_lastMonth:
1018 eDateType = condformat::LASTMONTH;
1019 break;
1020 case XML_thisMonth:
1021 eDateType = condformat::THISMONTH;
1022 break;
1023 case XML_nextMonth:
1024 eDateType = condformat::NEXTMONTH;
1025 break;
1026 default:
1027 SAL_WARN("sc.filter", "CondFormatRule::finalizeImport - unknown time period type" );
1028 }
1029
1030 ScDocument& rDoc = getScDocument();
1031 ScCondDateFormatEntry* pFormatEntry = new ScCondDateFormatEntry(&rDoc);
1032 pFormatEntry->SetDateType(eDateType);
1033 OUString aStyleName = getStyles().createDxfStyle( maModel.mnDxfId );
1034 pFormatEntry->SetStyleName( aStyleName );
1035
1036 mpFormat->AddEntry(pFormatEntry);
1037 }
1038 else if( mpColor )
1039 {
1040 ScDocument& rDoc = getScDocument();
1041 ScColorScaleFormat* pFormatEntry = new ScColorScaleFormat(&rDoc);
1042
1043 mpFormat->AddEntry(pFormatEntry);
1044
1045 mpColor->AddEntries( pFormatEntry, &rDoc, aPos );
1046 }
1047 else if (mpDataBar)
1048 {
1049 ScDocument& rDoc = getScDocument();
1050 ScDataBarFormat* pFormatEntry = new ScDataBarFormat(&rDoc);
1051
1052 mpFormat->AddEntry(pFormatEntry);
1053 mpDataBar->SetData( pFormatEntry, &rDoc, aPos );
1054
1055 }
1056 else if(mpIconSet)
1057 {
1058 ScDocument& rDoc = getScDocument();
1059 ScIconSetFormat* pFormatEntry = new ScIconSetFormat(&rDoc);
1060
1061 mpFormat->AddEntry(pFormatEntry);
1062 mpIconSet->SetData( pFormatEntry, &rDoc, aPos );
1063 }
1064 }
1065
getColorScale()1066 ColorScaleRule* CondFormatRule::getColorScale()
1067 {
1068 if(!mpColor)
1069 mpColor.reset( new ColorScaleRule(mrCondFormat) );
1070
1071 return mpColor.get();
1072 }
1073
getDataBar()1074 DataBarRule* CondFormatRule::getDataBar()
1075 {
1076 if(!mpDataBar)
1077 mpDataBar.reset( new DataBarRule(mrCondFormat) );
1078
1079 return mpDataBar.get();
1080 }
1081
getIconSet()1082 IconSetRule* CondFormatRule::getIconSet()
1083 {
1084 if(!mpIconSet)
1085 mpIconSet.reset( new IconSetRule(mrCondFormat) );
1086
1087 return mpIconSet.get();
1088 }
1089
CondFormatModel()1090 CondFormatModel::CondFormatModel() :
1091 mbPivot( false )
1092 {
1093 }
1094
CondFormat(const WorksheetHelper & rHelper)1095 CondFormat::CondFormat( const WorksheetHelper& rHelper ) :
1096 WorksheetHelper( rHelper ),
1097 mpFormat(nullptr),
1098 mbReadyForFinalize(false),
1099 mbOwnsFormat(true)
1100 {
1101 }
1102
~CondFormat()1103 CondFormat::~CondFormat()
1104 {
1105 if (mbOwnsFormat)
1106 delete mpFormat;
1107 }
1108
importConditionalFormatting(const AttributeList & rAttribs)1109 void CondFormat::importConditionalFormatting( const AttributeList& rAttribs )
1110 {
1111 getAddressConverter().convertToCellRangeList( maModel.maRanges, rAttribs.getString( XML_sqref, OUString() ), getSheetIndex(), true );
1112 maModel.mbPivot = rAttribs.getBool( XML_pivot, false );
1113 mpFormat = new ScConditionalFormat(0, &getScDocument());
1114 }
1115
importCfRule(const AttributeList & rAttribs)1116 CondFormatRuleRef CondFormat::importCfRule( const AttributeList& rAttribs )
1117 {
1118 CondFormatRuleRef xRule = createRule();
1119 xRule->importCfRule( rAttribs );
1120 return xRule;
1121 }
1122
importCondFormatting(SequenceInputStream & rStrm)1123 void CondFormat::importCondFormatting( SequenceInputStream& rStrm )
1124 {
1125 BinRangeList aRanges;
1126 rStrm.skip( 8 );
1127 rStrm >> aRanges;
1128 getAddressConverter().convertToCellRangeList( maModel.maRanges, aRanges, getSheetIndex(), true );
1129 mpFormat = new ScConditionalFormat(0, &getScDocument());
1130 }
1131
importCfRule(SequenceInputStream & rStrm)1132 void CondFormat::importCfRule( SequenceInputStream& rStrm )
1133 {
1134 CondFormatRuleRef xRule = createRule();
1135 xRule->importCfRule( rStrm );
1136 insertRule( xRule );
1137 }
1138
finalizeImport()1139 void CondFormat::finalizeImport()
1140 {
1141 // probably some error in the xml if we are not ready
1142 if ( !mbReadyForFinalize )
1143 return;
1144 ScDocument& rDoc = getScDocument();
1145 mpFormat->SetRange(maModel.maRanges);
1146 maRules.forEachMem( &CondFormatRule::finalizeImport );
1147
1148 if (mpFormat->size() > 0)
1149 {
1150 SCTAB nTab = maModel.maRanges.GetTopLeftCorner().Tab();
1151 mbOwnsFormat = false; // ownership transferred to std::unique_ptr -> ScDocument
1152 sal_Int32 nIndex = getScDocument().AddCondFormat(std::unique_ptr<ScConditionalFormat>(mpFormat), nTab);
1153
1154 rDoc.AddCondFormatData( maModel.maRanges, nTab, nIndex );
1155 }
1156 }
1157
createRule()1158 CondFormatRuleRef CondFormat::createRule()
1159 {
1160 return std::make_shared<CondFormatRule>( *this, mpFormat );
1161 }
1162
insertRule(CondFormatRuleRef const & xRule)1163 void CondFormat::insertRule( CondFormatRuleRef const & xRule )
1164 {
1165 if( xRule && (xRule->getPriority() > 0) )
1166 {
1167 OSL_ENSURE( maRules.find( xRule->getPriority() ) == maRules.end(), "CondFormat::insertRule - multiple rules with equal priority" );
1168 maRules[ xRule->getPriority() ] = xRule;
1169 }
1170 }
1171
CondFormatBuffer(const WorksheetHelper & rHelper)1172 CondFormatBuffer::CondFormatBuffer( const WorksheetHelper& rHelper ) :
1173 WorksheetHelper( rHelper )
1174 {
1175 }
1176
importConditionalFormatting(const AttributeList & rAttribs)1177 CondFormatRef CondFormatBuffer::importConditionalFormatting( const AttributeList& rAttribs )
1178 {
1179 CondFormatRef xCondFmt = createCondFormat();
1180 xCondFmt->importConditionalFormatting( rAttribs );
1181 return xCondFmt;
1182 }
1183
1184 namespace {
1185
findFormatByRange(const ScRangeList & rRange,const ScDocument * pDoc,SCTAB nTab)1186 ScConditionalFormat* findFormatByRange(const ScRangeList& rRange, const ScDocument* pDoc, SCTAB nTab)
1187 {
1188 ScConditionalFormatList* pList = pDoc->GetCondFormList(nTab);
1189 for (auto const& it : *pList)
1190 {
1191 if (it->GetRange() == rRange)
1192 {
1193 return it.get();
1194 }
1195 }
1196
1197 return nullptr;
1198 }
1199
1200 class ScRangeListHasher
1201 {
1202 public:
operator ()(ScRangeList const & rRanges) const1203 size_t operator() (ScRangeList const& rRanges) const
1204 {
1205 size_t nHash = 0;
1206 for (size_t nIdx = 0; nIdx < rRanges.size(); ++nIdx)
1207 nHash += rRanges[nIdx].hashArea();
1208 return nHash;
1209 }
1210 };
1211
1212 }
1213
updateImport(const ScDataBarFormatData * pTarget)1214 void CondFormatBuffer::updateImport(const ScDataBarFormatData* pTarget)
1215 {
1216 for ( const auto& rRule : maCfRules )
1217 {
1218 if ( rRule && rRule->GetDataBarData() == pTarget )
1219 rRule->finalizeImport();
1220 }
1221 }
1222
insertRule(CondFormatRef const & xCondFmt,CondFormatRuleRef const & xRule)1223 bool CondFormatBuffer::insertRule(CondFormatRef const & xCondFmt, CondFormatRuleRef const & xRule)
1224 {
1225 CondFormatRef xFoundFmt;
1226 ScRangeList aRanges = xCondFmt->getRanges();
1227
1228 for (auto& rCondFmt : maCondFormats)
1229 {
1230 if (xCondFmt == rCondFmt)
1231 continue;
1232
1233 if (aRanges == rCondFmt->getRanges())
1234 {
1235 xFoundFmt = rCondFmt;
1236 break;
1237 }
1238 }
1239
1240 if (xFoundFmt)
1241 {
1242 xRule->mpFormat = xFoundFmt->mpFormat;
1243 xFoundFmt->insertRule(xRule);
1244 }
1245
1246 return static_cast<bool>(xFoundFmt);
1247 }
1248
finalizeImport()1249 void CondFormatBuffer::finalizeImport()
1250 {
1251 std::unordered_set<size_t> aDoneExtCFs;
1252 typedef std::unordered_map<ScRangeList, CondFormat*, ScRangeListHasher> RangeMap;
1253 RangeMap aRangeMap;
1254 for (auto& rxCondFormat : maCondFormats)
1255 {
1256 if (aRangeMap.contains(rxCondFormat->getRanges()))
1257 continue;
1258 aRangeMap[rxCondFormat->getRanges()] = rxCondFormat.get();
1259 }
1260
1261 size_t nExtCFIndex = 0;
1262 for (const auto& rxExtCondFormat : maExtCondFormats)
1263 {
1264 ScDocument* pDoc = &getScDocument();
1265 const ScRangeList& rRange = rxExtCondFormat->getRange();
1266 RangeMap::iterator it = aRangeMap.find(rRange);
1267 if (it != aRangeMap.end())
1268 {
1269 CondFormat& rCondFormat = *it->second;
1270 const std::vector<std::unique_ptr<ScFormatEntry>>& rEntries = rxExtCondFormat->getEntries();
1271 const std::vector<sal_Int32>& rPriorities = rxExtCondFormat->getPriorities();
1272 size_t nEntryIdx = 0;
1273 for (const auto& rxEntry : rEntries)
1274 {
1275 CondFormatRuleRef xRule = rCondFormat.createRule();
1276 if (ScDataBarFormat *pData = dynamic_cast<ScDataBarFormat*>(rxEntry.get()))
1277 updateImport(pData->GetDataBarData());
1278 ScFormatEntry* pNewEntry = rxEntry->Clone(pDoc);
1279 sal_Int32 nPriority = rPriorities[nEntryIdx];
1280 if (nPriority == -1)
1281 nPriority = mnNonPrioritizedRuleNextPriority++;
1282 xRule->setFormatEntry(nPriority, pNewEntry);
1283 rCondFormat.insertRule(xRule);
1284 ++nEntryIdx;
1285 }
1286
1287 aDoneExtCFs.insert(nExtCFIndex);
1288 }
1289
1290 ++nExtCFIndex;
1291 }
1292
1293 // tdf#138601 sort conditional formatting rules by their priority
1294 if (maCondFormats.size() > 1)
1295 {
1296 size_t minIndex;
1297 for (size_t i = 0; i < maCondFormats.size() - 1; ++i)
1298 {
1299 minIndex = i;
1300 for (size_t j = i + 1; j < maCondFormats.size(); ++j)
1301 {
1302 const CondFormat::CondFormatRuleMap& rNextRules = maCondFormats[j]->maRules;
1303 const CondFormat::CondFormatRuleMap& rMinRules = maCondFormats[minIndex]->maRules;
1304 if (rNextRules.empty() || rMinRules.empty())
1305 continue;
1306 if (rNextRules.begin()->first < rMinRules.begin()->first)
1307 minIndex = j;
1308 }
1309 if (i != minIndex)
1310 std::swap(maCondFormats[i], maCondFormats[minIndex]);
1311 }
1312 }
1313
1314 for( const auto& rxCondFormat : maCondFormats )
1315 {
1316 if ( rxCondFormat)
1317 rxCondFormat->finalizeImport();
1318 }
1319 for ( const auto& rxCfRule : maCfRules )
1320 {
1321 if ( rxCfRule )
1322 rxCfRule->finalizeImport();
1323 }
1324
1325 nExtCFIndex = 0;
1326 for (const auto& rxExtCondFormat : maExtCondFormats)
1327 {
1328 if (aDoneExtCFs.count(nExtCFIndex))
1329 {
1330 ++nExtCFIndex;
1331 continue;
1332 }
1333
1334 ScDocument* pDoc = &getScDocument();
1335 const ScRangeList& rRange = rxExtCondFormat->getRange();
1336 SCTAB nTab = rRange.front().aStart.Tab();
1337 ScConditionalFormat* pFormat = findFormatByRange(rRange, pDoc, nTab);
1338 if (!pFormat)
1339 {
1340 // create new conditional format and insert it
1341 auto pNewFormat = std::make_unique<ScConditionalFormat>(0, pDoc);
1342 pFormat = pNewFormat.get();
1343 pNewFormat->SetRange(rRange);
1344 sal_uInt32 nKey = pDoc->AddCondFormat(std::move(pNewFormat), nTab);
1345 pDoc->AddCondFormatData(rRange, nTab, nKey);
1346 }
1347
1348 const std::vector< std::unique_ptr<ScFormatEntry> >& rEntries = rxExtCondFormat->getEntries();
1349 for (const auto& rxEntry : rEntries)
1350 {
1351 pFormat->AddEntry(rxEntry->Clone(pDoc));
1352 }
1353
1354 ++nExtCFIndex;
1355 }
1356
1357 gnStyleIdx = 0; // Resets <extlst> <cfRule> style index.
1358 }
1359
importCondFormatting(SequenceInputStream & rStrm)1360 CondFormatRef CondFormatBuffer::importCondFormatting( SequenceInputStream& rStrm )
1361 {
1362 CondFormatRef xCondFmt = createCondFormat();
1363 xCondFmt->importCondFormatting( rStrm );
1364 return xCondFmt;
1365 }
1366
createExtCfDataBarRule(ScDataBarFormatData * pTarget)1367 ExtCfDataBarRuleRef CondFormatBuffer::createExtCfDataBarRule(ScDataBarFormatData* pTarget)
1368 {
1369 ExtCfDataBarRuleRef extRule = std::make_shared<ExtCfDataBarRule>( pTarget, *this );
1370 maCfRules.push_back( extRule );
1371 return extRule;
1372 }
1373
importExtCondFormat()1374 std::vector< std::unique_ptr<ExtCfCondFormat> >& CondFormatBuffer::importExtCondFormat()
1375 {
1376 return maExtCondFormats;
1377 }
1378
importExtFormatEntries()1379 std::vector<std::unique_ptr<ScFormatEntry> >& CondFormatBuffer::importExtFormatEntries()
1380 {
1381 return maExtFormatEntries;
1382 }
1383
convertToApiOperator(sal_Int32 nToken)1384 sal_Int32 CondFormatBuffer::convertToApiOperator( sal_Int32 nToken )
1385 {
1386 switch( nToken )
1387 {
1388 case XML_between: return ConditionOperator2::BETWEEN;
1389 case XML_equal: return ConditionOperator2::EQUAL;
1390 case XML_greaterThan: return ConditionOperator2::GREATER;
1391 case XML_greaterThanOrEqual: return ConditionOperator2::GREATER_EQUAL;
1392 case XML_lessThan: return ConditionOperator2::LESS;
1393 case XML_lessThanOrEqual: return ConditionOperator2::LESS_EQUAL;
1394 case XML_notBetween: return ConditionOperator2::NOT_BETWEEN;
1395 case XML_notEqual: return ConditionOperator2::NOT_EQUAL;
1396 case XML_duplicateValues: return ConditionOperator2::DUPLICATE;
1397 }
1398 return ConditionOperator2::NONE;
1399 }
1400
convertToInternalOperator(sal_Int32 nToken)1401 ScConditionMode CondFormatBuffer::convertToInternalOperator( sal_Int32 nToken )
1402 {
1403 switch( nToken )
1404 {
1405 case XML_between: return ScConditionMode::Between;
1406 case XML_equal: return ScConditionMode::Equal;
1407 case XML_greaterThan: return ScConditionMode::Greater;
1408 case XML_greaterThanOrEqual: return ScConditionMode::EqGreater;
1409 case XML_lessThan: return ScConditionMode::Less;
1410 case XML_lessThanOrEqual: return ScConditionMode::EqLess;
1411 case XML_notBetween: return ScConditionMode::NotBetween;
1412 case XML_notEqual: return ScConditionMode::NotEqual;
1413 case XML_duplicateValues: return ScConditionMode::Duplicate;
1414 case XML_uniqueValues: return ScConditionMode::NotDuplicate;
1415 }
1416 return ScConditionMode::NONE;
1417 }
1418
1419 // private --------------------------------------------------------------------
1420
createCondFormat()1421 CondFormatRef CondFormatBuffer::createCondFormat()
1422 {
1423 CondFormatRef xCondFmt = std::make_shared<CondFormat>( *this );
1424 maCondFormats.push_back( xCondFmt );
1425 return xCondFmt;
1426 }
1427
ExtCfDataBarRule(ScDataBarFormatData * pTarget,const WorksheetHelper & rParent)1428 ExtCfDataBarRule::ExtCfDataBarRule(ScDataBarFormatData* pTarget, const WorksheetHelper& rParent):
1429 WorksheetHelper(rParent),
1430 mnRuleType( ExtCfDataBarRule::UNKNOWN ),
1431 mpTarget(pTarget)
1432 {
1433 }
1434
finalizeImport()1435 void ExtCfDataBarRule::finalizeImport()
1436 {
1437 switch ( mnRuleType )
1438 {
1439 case DATABAR:
1440 {
1441 ScDataBarFormatData* pDataBar = mpTarget;
1442 if( maModel.maAxisPosition == "none" )
1443 pDataBar->meAxisPosition = databar::NONE;
1444 else if( maModel.maAxisPosition == "middle" )
1445 pDataBar->meAxisPosition = databar::MIDDLE;
1446 else
1447 pDataBar->meAxisPosition = databar::AUTOMATIC;
1448 pDataBar->mbGradient = maModel.mbGradient;
1449 break;
1450 }
1451 case AXISCOLOR:
1452 {
1453 ScDataBarFormatData* pDataBar = mpTarget;
1454 pDataBar->maAxisColor = maModel.mnAxisColor;
1455 break;
1456 }
1457 case POSITIVEFILLCOLOR:
1458 {
1459 ScDataBarFormatData* pDataBar = mpTarget;
1460 pDataBar->maPositiveColor = maModel.mnPositiveColor;
1461 break;
1462 }
1463 case NEGATIVEFILLCOLOR:
1464 {
1465 ScDataBarFormatData* pDataBar = mpTarget;
1466 pDataBar->mxNegativeColor = maModel.mnNegativeColor;
1467 pDataBar->mbNeg = true;
1468 break;
1469 }
1470 case CFVO:
1471 {
1472 ScDataBarFormatData* pDataBar = mpTarget;
1473 ScColorScaleEntry* pEntry = nullptr;
1474 if(maModel.mbIsLower)
1475 pEntry = pDataBar->mpLowerLimit.get();
1476 else
1477 pEntry = pDataBar->mpUpperLimit.get();
1478
1479 if(maModel.maColorScaleType == "min")
1480 pEntry->SetType(COLORSCALE_MIN);
1481 else if (maModel.maColorScaleType == "max")
1482 pEntry->SetType(COLORSCALE_MAX);
1483 else if (maModel.maColorScaleType == "autoMin")
1484 pEntry->SetType(COLORSCALE_AUTO);
1485 else if (maModel.maColorScaleType == "autoMax")
1486 pEntry->SetType(COLORSCALE_AUTO);
1487 else if (maModel.maColorScaleType == "percentile")
1488 pEntry->SetType(COLORSCALE_PERCENTILE);
1489 else if (maModel.maColorScaleType == "percent")
1490 pEntry->SetType(COLORSCALE_PERCENT);
1491 else if (maModel.maColorScaleType == "formula")
1492 pEntry->SetType(COLORSCALE_FORMULA);
1493 else if (maModel.maColorScaleType == "num")
1494 {
1495 pEntry->SetType(COLORSCALE_VALUE);
1496 if (!maModel.msScaleTypeValue.isEmpty())
1497 {
1498 sal_Int32 nSize = 0;
1499 rtl_math_ConversionStatus eStatus = rtl_math_ConversionStatus_Ok;
1500 double fValue = rtl::math::stringToDouble(maModel.msScaleTypeValue, '.', '\0', &eStatus, &nSize);
1501 if (eStatus == rtl_math_ConversionStatus_Ok && nSize == maModel.msScaleTypeValue.getLength())
1502 {
1503 pEntry->SetValue(fValue);
1504 }
1505 }
1506 }
1507 break;
1508 }
1509 case UNKNOWN: // nothing to do
1510 default:
1511 break;
1512 }
1513 }
1514
importDataBar(const AttributeList & rAttribs)1515 void ExtCfDataBarRule::importDataBar( const AttributeList& rAttribs )
1516 {
1517 mnRuleType = DATABAR;
1518 maModel.mbGradient = rAttribs.getBool( XML_gradient, true );
1519 maModel.maAxisPosition = rAttribs.getString( XML_axisPosition, u"automatic"_ustr );
1520 }
1521
importPositiveFillColor(const AttributeList & rAttribs)1522 void ExtCfDataBarRule::importPositiveFillColor( const AttributeList& rAttribs )
1523 {
1524 mnRuleType = POSITIVEFILLCOLOR;
1525 ThemeBuffer& rThemeBuffer = getTheme();
1526 GraphicHelper& rGraphicHelper = getBaseFilter().getGraphicHelper();
1527 ::Color aColor = importOOXColor(rAttribs, rThemeBuffer, rGraphicHelper);
1528 maModel.mnPositiveColor = aColor;
1529 }
1530
importNegativeFillColor(const AttributeList & rAttribs)1531 void ExtCfDataBarRule::importNegativeFillColor( const AttributeList& rAttribs )
1532 {
1533 mnRuleType = NEGATIVEFILLCOLOR;
1534 ThemeBuffer& rThemeBuffer = getTheme();
1535 GraphicHelper& rGraphicHelper = getBaseFilter().getGraphicHelper();
1536 ::Color aColor = importOOXColor(rAttribs, rThemeBuffer, rGraphicHelper);
1537 maModel.mnNegativeColor = aColor;
1538 }
1539
importAxisColor(const AttributeList & rAttribs)1540 void ExtCfDataBarRule::importAxisColor( const AttributeList& rAttribs )
1541 {
1542 mnRuleType = AXISCOLOR;
1543 ThemeBuffer& rThemeBuffer = getTheme();
1544 GraphicHelper& rGraphicHelper = getBaseFilter().getGraphicHelper();
1545 ::Color aColor = importOOXColor(rAttribs, rThemeBuffer, rGraphicHelper);
1546 maModel.mnAxisColor = aColor;
1547 }
1548
importCfvo(const AttributeList & rAttribs)1549 void ExtCfDataBarRule::importCfvo( const AttributeList& rAttribs )
1550 {
1551 mnRuleType = CFVO;
1552 maModel.maColorScaleType = rAttribs.getString( XML_type, OUString() );
1553 }
1554
ExtCfCondFormat(ScRangeList aRange,std::vector<std::unique_ptr<ScFormatEntry>> & rEntries,const std::vector<sal_Int32> * pPriorities)1555 ExtCfCondFormat::ExtCfCondFormat(ScRangeList aRange, std::vector< std::unique_ptr<ScFormatEntry> >& rEntries,
1556 const std::vector<sal_Int32>* pPriorities):
1557 maRange(std::move(aRange))
1558 {
1559 maEntries.swap(rEntries);
1560 if (pPriorities)
1561 maPriorities = *pPriorities;
1562 else
1563 maPriorities.resize(maEntries.size(), -1);
1564 }
1565
~ExtCfCondFormat()1566 ExtCfCondFormat::~ExtCfCondFormat()
1567 {
1568 }
1569
getRange() const1570 const ScRangeList& ExtCfCondFormat::getRange() const
1571 {
1572 return maRange;
1573 }
1574
getEntries() const1575 const std::vector< std::unique_ptr<ScFormatEntry> >& ExtCfCondFormat::getEntries() const
1576 {
1577 return maEntries;
1578 }
1579
1580 } // namespace oox
1581
1582 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1583