xref: /core/sc/source/filter/oox/condformatbuffer.cxx (revision 000aaf1f)
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