LibreOffice Module sc (master) 1
condformatbuffer.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <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>
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
48namespace oox::xls {
49
50using namespace ::com::sun::star::sheet;
51using namespace ::com::sun::star::uno;
52
53namespace {
54
55const sal_Int32 BIFF12_CFRULE_TYPE_CELLIS = 1;
56const sal_Int32 BIFF12_CFRULE_TYPE_EXPRESSION = 2;
57const sal_Int32 BIFF12_CFRULE_TYPE_COLORSCALE = 3;
58const sal_Int32 BIFF12_CFRULE_TYPE_DATABAR = 4;
59const sal_Int32 BIFF12_CFRULE_TYPE_TOPTEN = 5;
60const sal_Int32 BIFF12_CFRULE_TYPE_ICONSET = 6;
61
62const sal_Int32 BIFF12_CFRULE_SUB_CELLIS = 0;
63const sal_Int32 BIFF12_CFRULE_SUB_EXPRESSION = 1;
64const sal_Int32 BIFF12_CFRULE_SUB_COLORSCALE = 2;
65const sal_Int32 BIFF12_CFRULE_SUB_DATABAR = 3;
66const sal_Int32 BIFF12_CFRULE_SUB_ICONSET = 4;
67const sal_Int32 BIFF12_CFRULE_SUB_TOPTEN = 5;
68const sal_Int32 BIFF12_CFRULE_SUB_UNIQUE = 7;
69const sal_Int32 BIFF12_CFRULE_SUB_TEXT = 8;
70const sal_Int32 BIFF12_CFRULE_SUB_BLANK = 9;
71const sal_Int32 BIFF12_CFRULE_SUB_NOTBLANK = 10;
72const sal_Int32 BIFF12_CFRULE_SUB_ERROR = 11;
73const sal_Int32 BIFF12_CFRULE_SUB_NOTERROR = 12;
74const sal_Int32 BIFF12_CFRULE_SUB_TODAY = 15;
75const sal_Int32 BIFF12_CFRULE_SUB_TOMORROW = 16;
76const sal_Int32 BIFF12_CFRULE_SUB_YESTERDAY = 17;
77const sal_Int32 BIFF12_CFRULE_SUB_LAST7DAYS = 18;
78const sal_Int32 BIFF12_CFRULE_SUB_LASTMONTH = 19;
79const sal_Int32 BIFF12_CFRULE_SUB_NEXTMONTH = 20;
80const sal_Int32 BIFF12_CFRULE_SUB_THISWEEK = 21;
81const sal_Int32 BIFF12_CFRULE_SUB_NEXTWEEK = 22;
82const sal_Int32 BIFF12_CFRULE_SUB_LASTWEEK = 23;
83const sal_Int32 BIFF12_CFRULE_SUB_THISMONTH = 24;
84const sal_Int32 BIFF12_CFRULE_SUB_ABOVEAVERAGE = 25;
85const sal_Int32 BIFF12_CFRULE_SUB_BELOWAVERAGE = 26;
86const sal_Int32 BIFF12_CFRULE_SUB_DUPLICATE = 27;
87const sal_Int32 BIFF12_CFRULE_SUB_EQABOVEAVERAGE = 29;
88const sal_Int32 BIFF12_CFRULE_SUB_EQBELOWAVERAGE = 30;
89
90const sal_Int32 BIFF12_CFRULE_TIMEOP_TODAY = 0;
91const sal_Int32 BIFF12_CFRULE_TIMEOP_YESTERDAY = 1;
92const sal_Int32 BIFF12_CFRULE_TIMEOP_LAST7DAYS = 2;
93const sal_Int32 BIFF12_CFRULE_TIMEOP_THISWEEK = 3;
94const sal_Int32 BIFF12_CFRULE_TIMEOP_LASTWEEK = 4;
95const sal_Int32 BIFF12_CFRULE_TIMEOP_LASTMONTH = 5;
96const sal_Int32 BIFF12_CFRULE_TIMEOP_TOMORROW = 6;
97const sal_Int32 BIFF12_CFRULE_TIMEOP_NEXTWEEK = 7;
98const sal_Int32 BIFF12_CFRULE_TIMEOP_NEXTMONTH = 8;
99const sal_Int32 BIFF12_CFRULE_TIMEOP_THISMONTH = 9;
100
101const sal_uInt16 BIFF12_CFRULE_STOPIFTRUE = 0x0002;
102const sal_uInt16 BIFF12_CFRULE_ABOVEAVERAGE = 0x0004;
103const sal_uInt16 BIFF12_CFRULE_BOTTOM = 0x0008;
104const sal_uInt16 BIFF12_CFRULE_PERCENT = 0x0010;
105
106bool 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
114void 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 double nVal = 0.0;
120 bool bVal = isValue(aVal, nVal);
121 if( !bVal || aType == "formula" )
122 {
123 pEntry->maFormula = aVal;
124 }
125 else
126 {
127 pEntry->mnVal = nVal;
128 }
129
130 if (aType == "num")
131 {
132 pEntry->mbNum = true;
133 }
134 else if( aType == "min" )
135 {
136 pEntry->mbMin = true;
137 }
138 else if( aType == "max" )
139 {
140 pEntry->mbMax = true;
141 }
142 else if( aType == "percent" )
143 {
144 pEntry->mbPercent = true;
145 }
146 else if( aType == "percentile" )
147 {
148 pEntry->mbPercentile = true;
149 }
150}
151
152}
153
155 WorksheetHelper( rFormat ),
156 mnCfvo(0),
157 mnCol(0)
158{
159}
160
162{
163 if(mnCfvo >= maColorScaleRuleEntries.size())
164 maColorScaleRuleEntries.emplace_back();
165
166 SetCfvoData( &maColorScaleRuleEntries[mnCfvo], rAttribs );
167
168 ++mnCfvo;
169}
170
171namespace {
172
173::Color importOOXColor(const AttributeList& rAttribs, const ThemeBuffer& rThemeBuffer, const GraphicHelper& rGraphicHelper)
174{
175 ::Color nColor;
176 if( rAttribs.hasAttribute( XML_rgb ) )
177 nColor = ::Color(ColorTransparency, rAttribs.getUnsignedHex( XML_rgb, UNSIGNED_RGB_TRANSPARENT ));
178 else if( rAttribs.hasAttribute( XML_theme ) )
179 {
180 sal_uInt32 nThemeIndex = rAttribs.getUnsigned( XML_theme, 0 );
181
182 // Excel has a bug in the mapping of index 0, 1, 2 and 3.
183 if (nThemeIndex == 0)
184 nThemeIndex = 1;
185 else if (nThemeIndex == 1)
186 nThemeIndex = 0;
187 else if (nThemeIndex == 2)
188 nThemeIndex = 3;
189 else if (nThemeIndex == 3)
190 nThemeIndex = 2;
191
192 nColor = rThemeBuffer.getColorByIndex( nThemeIndex );
193 }
194
195 ::Color aColor;
196 double nTint = rAttribs.getDouble(XML_tint, 0.0);
197 if (nTint != 0.0)
198 {
199 oox::drawingml::Color aDMColor;
200 aDMColor.setSrgbClr(nColor);
201 aDMColor.addExcelTintTransformation(nTint);
202 aColor = aDMColor.getColor(rGraphicHelper);
203 }
204 else
205 aColor = nColor.GetRGBColor();
206
207 return aColor;
208}
209
210}
211
213{
214 ThemeBuffer& rThemeBuffer = getTheme();
215 GraphicHelper& rGraphicHelper = getBaseFilter().getGraphicHelper();
216 ::Color aColor = importOOXColor(rAttribs, rThemeBuffer, rGraphicHelper);
217
218 if(mnCol >= maColorScaleRuleEntries.size())
219 maColorScaleRuleEntries.emplace_back();
220
221 maColorScaleRuleEntries[mnCol].maColor = aColor;
222 ++mnCol;
223}
224
225namespace {
226
227ScColorScaleEntry* ConvertToModel( const ColorScaleRuleModelEntry& rEntry, ScDocument* pDoc, const ScAddress& rAddr )
228{
229 ScColorScaleEntry* pEntry = new ScColorScaleEntry(rEntry.mnVal, rEntry.maColor);
230
231 if(rEntry.mbMin)
232 pEntry->SetType(COLORSCALE_MIN);
233 if(rEntry.mbMax)
234 pEntry->SetType(COLORSCALE_MAX);
235 if(rEntry.mbPercent)
237 if(rEntry.mbPercentile)
239 if (rEntry.mbNum)
240 pEntry->SetType(COLORSCALE_VALUE);
241
242 if(!rEntry.maFormula.isEmpty())
243 {
246 }
247
248 return pEntry;
249}
250
251}
252
254{
256 {
257 ScColorScaleEntry* pEntry = ConvertToModel( rEntry, pDoc, rAddr );
258
259 pFormat->AddEntry( pEntry );
260 }
261}
262
264 WorksheetHelper( rFormat ),
265 mxFormat(new ScDataBarFormatData)
266{
267 mxFormat->meAxisPosition = databar::NONE;
268}
269
271{
272 ThemeBuffer& rThemeBuffer = getTheme();
273 GraphicHelper& rGraphicHelper = getBaseFilter().getGraphicHelper();
274 ::Color aColor = importOOXColor(rAttribs, rThemeBuffer, rGraphicHelper);
275
276 mxFormat->maPositiveColor = aColor;
277}
278
280{
282 if(!mpLowerLimit)
283 {
285 pEntry = mpLowerLimit.get();
286 }
287 else
288 {
290 pEntry = mpUpperLimit.get();
291 }
292
293 SetCfvoData( pEntry, rAttribs );
294}
295
297{
298 mxFormat->mbOnlyBar = !rAttribs.getBool( XML_showValue, true );
299 mxFormat->mnMinLength = rAttribs.getUnsigned( XML_minLength, 10);
300 mxFormat->mnMaxLength = rAttribs.getUnsigned( XML_maxLength, 90);
301}
302
303void DataBarRule::SetData( ScDataBarFormat* pFormat, ScDocument* pDoc, const ScAddress& rAddr )
304{
305 ScColorScaleEntry* pUpperEntry = ConvertToModel(*mpUpperLimit, pDoc, rAddr);
306 ScColorScaleEntry* pLowerEntry = ConvertToModel(*mpLowerLimit, pDoc, rAddr);
307
308 mxFormat->mpUpperLimit.reset( pUpperEntry );
309 mxFormat->mpLowerLimit.reset( pLowerEntry );
310 pFormat->SetDataBarData(mxFormat.release());
311}
312
314 WorksheetHelper( rParent ),
315 mxFormatData( new ScIconSetFormatData ),
316 mbCustom(false)
317{
318}
319
321{
322 ColorScaleRuleModelEntry aNewEntry;
323 SetCfvoData(&aNewEntry, rAttribs);
324
325 maEntries.push_back(aNewEntry);
326}
327
329{
330 maIconSetType = rAttribs.getString( XML_iconSet, "3TrafficLights1" );
331 mxFormatData->mbShowValue = rAttribs.getBool( XML_showValue, true );
332 mxFormatData->mbReverse = rAttribs.getBool( XML_reverse, false );
333 mbCustom = rAttribs.getBool(XML_custom, false);
334}
335
336void IconSetRule::importFormula(const OUString& rFormula)
337{
338 ColorScaleRuleModelEntry& rEntry = maEntries.back();
339 double nVal = 0.0;
340 if ((rEntry.mbNum || rEntry.mbPercent || rEntry.mbPercentile) && isValue(rFormula, nVal))
341 {
342 rEntry.mnVal = nVal;
343 }
344 else if (!rFormula.isEmpty())
345 rEntry.maFormula = rFormula;
346}
347
348namespace {
349
350ScIconSetType getType(std::u16string_view rName)
351{
353 const ScIconSetMap* pIconSetMap = ScIconSetFormat::g_IconSetMap;
354 for(size_t i = 0; pIconSetMap[i].pName; ++i)
355 {
356 if(OUString::createFromAscii(pIconSetMap[i].pName) == rName)
357 {
358 eIconSetType = pIconSetMap[i].eType;
359 break;
360 }
361 }
362
363 return eIconSetType;
364}
365
366}
367
369{
370 OUString aIconSet = rAttribs.getString(XML_iconSet, OUString());
371 sal_Int32 nIndex = rAttribs.getInteger(XML_iconId, -1);
372 if (aIconSet == "NoIcons")
373 {
374 nIndex = -1;
375 }
376
377 ScIconSetType eIconSetType = getType(aIconSet);
378 mxFormatData->maCustomVector.emplace_back(eIconSetType, nIndex);
379}
380
381void IconSetRule::SetData( ScIconSetFormat* pFormat, ScDocument* pDoc, const ScAddress& rPos )
382{
383 for(const ColorScaleRuleModelEntry & rEntry : maEntries)
384 {
385 ScColorScaleEntry* pModelEntry = ConvertToModel( rEntry, pDoc, rPos );
386 mxFormatData->m_Entries.emplace_back(pModelEntry);
387 }
388
389 mxFormatData->eIconSetType = getType(maIconSetType);
390 mxFormatData->mbCustom = mbCustom;
391 pFormat->SetIconSetData(mxFormatData.release());
392}
393
395 mnPriority( -1 ),
397 mnOperator( XML_TOKEN_INVALID ),
398 mnTimePeriod( XML_TOKEN_INVALID ),
399 mnRank( 0 ),
400 mnStdDev( 0 ),
401 mnDxfId( -1 ),
402 mbStopIfTrue( false ),
403 mbBottom( false ),
404 mbPercent( false ),
405 mbAboveAverage( true ),
406 mbEqualAverage( false )
407{
408}
409
410void CondFormatRuleModel::setBiffOperator( sal_Int32 nOperator )
411{
412 static const sal_Int32 spnOperators[] = {
413 XML_TOKEN_INVALID, XML_between, XML_notBetween, XML_equal, XML_notEqual,
414 XML_greaterThan, XML_lessThan, XML_greaterThanOrEqual, XML_lessThanOrEqual };
415 mnOperator = STATIC_ARRAY_SELECT( spnOperators, nOperator, XML_TOKEN_INVALID );
416}
417
418void CondFormatRuleModel::setBiff12TextType( sal_Int32 nOperator )
419{
420 // note: type XML_notContainsText vs. operator XML_notContains
421 static const sal_Int32 spnTypes[] = { XML_containsText, XML_notContainsText, XML_beginsWith, XML_endsWith };
422 mnType = STATIC_ARRAY_SELECT( spnTypes, nOperator, XML_TOKEN_INVALID );
423 static const sal_Int32 spnOperators[] = { XML_containsText, XML_notContains, XML_beginsWith, XML_endsWith };
424 mnOperator = STATIC_ARRAY_SELECT( spnOperators, nOperator, XML_TOKEN_INVALID );
425}
426
428 WorksheetHelper( rCondFormat ),
429 mrCondFormat( rCondFormat ),
430 mpFormat(pFormat),
431 mpFormatEntry(nullptr)
432{
433}
434
436{
437 maModel.maText = rAttribs.getString( XML_text, OUString() );
438 maModel.mnPriority = rAttribs.getInteger( XML_priority, -1 );
440 maModel.mnOperator = rAttribs.getToken( XML_operator, XML_TOKEN_INVALID );
441 maModel.mnTimePeriod = rAttribs.getToken( XML_timePeriod, XML_TOKEN_INVALID );
442 maModel.mnRank = rAttribs.getInteger( XML_rank, 0 );
443 maModel.mnStdDev = rAttribs.getInteger( XML_stdDev, 0 );
444 maModel.mnDxfId = rAttribs.getInteger( XML_dxfId, -1 );
445 maModel.mbStopIfTrue = rAttribs.getBool( XML_stopIfTrue, false );
446 maModel.mbBottom = rAttribs.getBool( XML_bottom, false );
447 maModel.mbPercent = rAttribs.getBool( XML_percent, false );
448 maModel.mbAboveAverage = rAttribs.getBool( XML_aboveAverage, true );
449 maModel.mbEqualAverage = rAttribs.getBool( XML_equalAverage, false );
450
451 if(maModel.mnType == XML_colorScale)
452 {
453 //import the remaining values
454
455 }
456}
457
458void CondFormatRule::appendFormula( const OUString& rFormula )
459{
461 ApiTokenSequence aTokens = getFormulaParser().importFormula( aBaseAddr, rFormula );
462 maModel.maFormulas.push_back( aTokens );
463}
464
466{
467 sal_Int32 nType, nSubType, nOperator, nFmla1Size, nFmla2Size, nFmla3Size;
468 sal_uInt16 nFlags;
469 nType = rStrm.readInt32();
470 nSubType = rStrm.readInt32();
471 maModel.mnDxfId = rStrm.readInt32();
472 maModel.mnPriority = rStrm.readInt32();
473 nOperator = rStrm.readInt32();
474 rStrm.skip( 8 );
475 nFlags = rStrm.readuInt16();
476 nFmla1Size = rStrm.readInt32();
477 nFmla2Size = rStrm.readInt32();
478 nFmla3Size = rStrm.readInt32();
480
481 /* Import the formulas. For no obvious reason, the sizes of the formulas
482 are already stored before. Nevertheless the following formulas contain
483 their own sizes. */
484
485 // first formula
486 // I am not bored enough to bother simplifying these expressions
487 SAL_WARN_IF( !( (nFmla1Size >= 0) || ((nFmla2Size == 0) && (nFmla3Size == 0)) ), "sc.filter", "CondFormatRule::importCfRule - missing first formula" );
488 SAL_WARN_IF( !( (nFmla1Size > 0) == (rStrm.getRemaining() >= 8) ), "sc.filter", "CondFormatRule::importCfRule - formula size mismatch" );
489 if( rStrm.getRemaining() >= 8 )
490 {
493 maModel.maFormulas.push_back( aTokens );
494
495 // second formula
496 OSL_ENSURE( (nFmla2Size >= 0) || (nFmla3Size == 0), "CondFormatRule::importCfRule - missing second formula" );
497 OSL_ENSURE( (nFmla2Size > 0) == (rStrm.getRemaining() >= 8), "CondFormatRule::importCfRule - formula size mismatch" );
498 if( rStrm.getRemaining() >= 8 )
499 {
501 maModel.maFormulas.push_back( aTokens );
502
503 // third formula
504 OSL_ENSURE( (nFmla3Size > 0) == (rStrm.getRemaining() >= 8), "CondFormatRule::importCfRule - formula size mismatch" );
505 if( rStrm.getRemaining() >= 8 )
506 {
508 maModel.maFormulas.push_back( aTokens );
509 }
510 }
511 }
512
513 // flags
514 maModel.mbStopIfTrue = getFlag( nFlags, BIFF12_CFRULE_STOPIFTRUE );
515 maModel.mbBottom = getFlag( nFlags, BIFF12_CFRULE_BOTTOM );
516 maModel.mbPercent = getFlag( nFlags, BIFF12_CFRULE_PERCENT );
517 maModel.mbAboveAverage = getFlag( nFlags, BIFF12_CFRULE_ABOVEAVERAGE );
518 // no flag for equalAverage, must be determined from subtype below...
519
520 // Convert the type/operator settings. This is a real mess...
521 switch( nType )
522 {
523 case BIFF12_CFRULE_TYPE_CELLIS:
525 nSubType != BIFF12_CFRULE_SUB_CELLIS, "sc.filter",
526 "CondFormatRule::importCfRule - rule type/subtype mismatch");
527 maModel.mnType = XML_cellIs;
528 maModel.setBiffOperator( nOperator );
529 OSL_ENSURE( maModel.mnOperator != XML_TOKEN_INVALID, "CondFormatRule::importCfRule - unknown operator" );
530 break;
531 case BIFF12_CFRULE_TYPE_EXPRESSION:
532 // here we have to look at the subtype to find the real type...
533 switch( nSubType )
534 {
535 case BIFF12_CFRULE_SUB_EXPRESSION:
536 OSL_ENSURE( nOperator == 0, "CondFormatRule::importCfRule - unexpected operator value" );
537 maModel.mnType = XML_expression;
538 break;
539 case BIFF12_CFRULE_SUB_UNIQUE:
540 OSL_ENSURE( nOperator == 0, "CondFormatRule::importCfRule - unexpected operator value" );
541 maModel.mnType = XML_uniqueValues;
542 break;
543 case BIFF12_CFRULE_SUB_TEXT:
544 maModel.setBiff12TextType( nOperator );
545 OSL_ENSURE( maModel.mnType != XML_TOKEN_INVALID, "CondFormatRule::importCfRule - unexpected operator value" );
546 break;
547 case BIFF12_CFRULE_SUB_BLANK:
548 OSL_ENSURE( nOperator == 0, "CondFormatRule::importCfRule - unexpected operator value" );
549 maModel.mnType = XML_containsBlanks;
550 break;
551 case BIFF12_CFRULE_SUB_NOTBLANK:
552 OSL_ENSURE( nOperator == 0, "CondFormatRule::importCfRule - unexpected operator value" );
553 maModel.mnType = XML_notContainsBlanks;
554 break;
555 case BIFF12_CFRULE_SUB_ERROR:
556 OSL_ENSURE( nOperator == 0, "CondFormatRule::importCfRule - unexpected operator value" );
557 maModel.mnType = XML_containsErrors;
558 break;
559 case BIFF12_CFRULE_SUB_NOTERROR:
560 OSL_ENSURE( nOperator == 0, "CondFormatRule::importCfRule - unexpected operator value" );
561 maModel.mnType = XML_notContainsErrors;
562 break;
563 case BIFF12_CFRULE_SUB_TODAY:
565 nOperator != BIFF12_CFRULE_TIMEOP_TODAY, "sc.filter",
566 "CondFormatRule::importCfRule - unexpected time operator value");
567 maModel.mnType = XML_timePeriod;
568 maModel.mnTimePeriod = XML_today;
569 break;
570 case BIFF12_CFRULE_SUB_TOMORROW:
572 nOperator != BIFF12_CFRULE_TIMEOP_TOMORROW, "sc.filter",
573 "CondFormatRule::importCfRule - unexpected time operator value");
574 maModel.mnType = XML_timePeriod;
575 maModel.mnTimePeriod = XML_tomorrow;
576 break;
577 case BIFF12_CFRULE_SUB_YESTERDAY:
579 nOperator != BIFF12_CFRULE_TIMEOP_YESTERDAY,
580 "sc.filter",
581 "CondFormatRule::importCfRule - unexpected time operator value");
582 maModel.mnType = XML_timePeriod;
583 maModel.mnTimePeriod = XML_yesterday;
584 break;
585 case BIFF12_CFRULE_SUB_LAST7DAYS:
587 nOperator != BIFF12_CFRULE_TIMEOP_LAST7DAYS,
588 "sc.filter",
589 "CondFormatRule::importCfRule - unexpected time operator value");
590 maModel.mnType = XML_timePeriod;
591 maModel.mnTimePeriod = XML_last7Days;
592 break;
593 case BIFF12_CFRULE_SUB_LASTMONTH:
595 nOperator != BIFF12_CFRULE_TIMEOP_LASTMONTH,
596 "sc.filter",
597 "CondFormatRule::importCfRule - unexpected time operator value");
598 maModel.mnType = XML_timePeriod;
599 maModel.mnTimePeriod = XML_lastMonth;
600 break;
601 case BIFF12_CFRULE_SUB_NEXTMONTH:
603 nOperator != BIFF12_CFRULE_TIMEOP_NEXTMONTH,
604 "sc.filter",
605 "CondFormatRule::importCfRule - unexpected time operator value");
606 maModel.mnType = XML_timePeriod;
607 maModel.mnTimePeriod = XML_nextMonth;
608 break;
609 case BIFF12_CFRULE_SUB_THISWEEK:
611 nOperator != BIFF12_CFRULE_TIMEOP_THISWEEK, "sc.filter",
612 "CondFormatRule::importCfRule - unexpected time operator value");
613 maModel.mnType = XML_timePeriod;
614 maModel.mnTimePeriod = XML_thisWeek;
615 break;
616 case BIFF12_CFRULE_SUB_NEXTWEEK:
618 nOperator != BIFF12_CFRULE_TIMEOP_NEXTWEEK, "sc.filter",
619 "CondFormatRule::importCfRule - unexpected time operator value");
620 maModel.mnType = XML_timePeriod;
621 maModel.mnTimePeriod = XML_nextWeek;
622 break;
623 case BIFF12_CFRULE_SUB_LASTWEEK:
625 nOperator != BIFF12_CFRULE_TIMEOP_LASTWEEK, "sc.filter",
626 "CondFormatRule::importCfRule - unexpected time operator value");
627 maModel.mnType = XML_timePeriod;
628 maModel.mnTimePeriod = XML_lastWeek;
629 break;
630 case BIFF12_CFRULE_SUB_THISMONTH:
632 nOperator != BIFF12_CFRULE_TIMEOP_THISMONTH,
633 "sc.filter",
634 "CondFormatRule::importCfRule - unexpected time operator value");
635 maModel.mnType = XML_timePeriod;
636 maModel.mnTimePeriod = XML_thisMonth;
637 break;
638 case BIFF12_CFRULE_SUB_ABOVEAVERAGE:
639 OSL_ENSURE( maModel.mbAboveAverage, "CondFormatRule::importCfRule - wrong above-average flag" );
640 maModel.mnType = XML_aboveAverage;
641 maModel.mnStdDev = nOperator; // operator field used for standard deviation
642 maModel.mbAboveAverage = true;
643 maModel.mbEqualAverage = false; // does not exist as real flag...
644 break;
645 case BIFF12_CFRULE_SUB_BELOWAVERAGE:
646 OSL_ENSURE( !maModel.mbAboveAverage, "CondFormatRule::importCfRule - wrong above-average flag" );
647 maModel.mnType = XML_aboveAverage;
648 maModel.mnStdDev = nOperator; // operator field used for standard deviation
649 maModel.mbAboveAverage = false;
650 maModel.mbEqualAverage = false; // does not exist as real flag...
651 break;
652 case BIFF12_CFRULE_SUB_DUPLICATE:
653 OSL_ENSURE( nOperator == 0, "CondFormatRule::importCfRule - unexpected operator value" );
654 maModel.mnType = XML_duplicateValues;
655 break;
656 case BIFF12_CFRULE_SUB_EQABOVEAVERAGE:
657 OSL_ENSURE( maModel.mbAboveAverage, "CondFormatRule::importCfRule - wrong above-average flag" );
658 maModel.mnType = XML_aboveAverage;
659 maModel.mnStdDev = nOperator; // operator field used for standard deviation
660 maModel.mbAboveAverage = true;
661 maModel.mbEqualAverage = true; // does not exist as real flag...
662 break;
663 case BIFF12_CFRULE_SUB_EQBELOWAVERAGE:
664 OSL_ENSURE( !maModel.mbAboveAverage, "CondFormatRule::importCfRule - wrong above-average flag" );
665 maModel.mnType = XML_aboveAverage;
666 maModel.mnStdDev = nOperator; // operator field used for standard deviation
667 maModel.mbAboveAverage = false;
668 maModel.mbEqualAverage = true; // does not exist as real flag...
669 break;
670 }
671 break;
672 case BIFF12_CFRULE_TYPE_COLORSCALE:
674 nSubType != BIFF12_CFRULE_SUB_COLORSCALE, "sc.filter",
675 "CondFormatRule::importCfRule - rule type/subtype mismatch");
676 OSL_ENSURE( nOperator == 0, "CondFormatRule::importCfRule - unexpected operator value" );
677 maModel.mnType = XML_colorScale;
678 break;
679 case BIFF12_CFRULE_TYPE_DATABAR:
681 nSubType != BIFF12_CFRULE_SUB_DATABAR, "sc.filter",
682 "CondFormatRule::importCfRule - rule type/subtype mismatch");
683 OSL_ENSURE( nOperator == 0, "CondFormatRule::importCfRule - unexpected operator value" );
684 maModel.mnType = XML_dataBar;
685 break;
686 case BIFF12_CFRULE_TYPE_TOPTEN:
688 nSubType != BIFF12_CFRULE_SUB_TOPTEN, "sc.filter",
689 "CondFormatRule::importCfRule - rule type/subtype mismatch");
690 maModel.mnType = XML_top10;
691 maModel.mnRank = nOperator; // operator field used for rank value
692 break;
693 case BIFF12_CFRULE_TYPE_ICONSET:
695 nSubType != BIFF12_CFRULE_SUB_ICONSET, "sc.filter",
696 "CondFormatRule::importCfRule - rule type/subtype mismatch");
697 OSL_ENSURE( nOperator == 0, "CondFormatRule::importCfRule - unexpected operator value" );
698 maModel.mnType = XML_iconSet;
699 break;
700 default:
701 OSL_FAIL( "CondFormatRule::importCfRule - unknown rule type" );
702 }
703}
704
705void CondFormatRule::setFormatEntry(sal_Int32 nPriority, ScFormatEntry* pEntry)
706{
707 maModel.mnPriority = nPriority;
708 mpFormatEntry = pEntry;
709}
710
712{
713 if (mpFormatEntry)
714 {
716 return;
717 }
718
720
721 /* Replacement formula for unsupported rule types (text comparison rules,
722 time period rules, cell type rules). The replacement formulas below may
723 contain several placeholders:
724 - '#B' will be replaced by the current relative base address (may occur
725 several times).
726 - '#R' will be replaced by the entire range list of the conditional
727 formatting (absolute addresses).
728 - '#T' will be replaced by the quoted comparison text.
729 - '#L' will be replaced by the length of the comparison text (from
730 the 'text' attribute) used in text comparison rules.
731 - '#K' will be replaced by the rank (from the 'rank' attribute) used in
732 top-10 rules.
733 - '#M' will be replaced by the top/bottom flag (from the 'bottom'
734 attribute) used in the RANK function in top-10 rules.
735 - '#C' will be replaced by one of the comparison operators <, >, <=, or
736 >=, according to the 'aboveAverage' and 'equalAverage' flags.
737 */
738 OUString aReplaceFormula;
739
740 switch( maModel.mnType )
741 {
742 case XML_cellIs:
744 break;
745 case XML_duplicateValues:
746 eOperator = ScConditionMode::Duplicate;
747 break;
748 case XML_uniqueValues:
750 break;
751 case XML_expression:
752 eOperator = ScConditionMode::Direct;
753 break;
754 case XML_containsText:
755 OSL_ENSURE( maModel.mnOperator == XML_containsText, "CondFormatRule::finalizeImport - unexpected operator" );
757 break;
758 case XML_notContainsText:
759 // note: type XML_notContainsText vs. operator XML_notContains
760 OSL_ENSURE( maModel.mnOperator == XML_notContains, "CondFormatRule::finalizeImport - unexpected operator" );
762 break;
763 case XML_beginsWith:
764 OSL_ENSURE( maModel.mnOperator == XML_beginsWith, "CondFormatRule::finalizeImport - unexpected operator" );
765 eOperator = ScConditionMode::BeginsWith;
766 break;
767 case XML_endsWith:
768 OSL_ENSURE( maModel.mnOperator == XML_endsWith, "CondFormatRule::finalizeImport - unexpected operator" );
769 eOperator = ScConditionMode::EndsWith;
770 break;
771 case XML_timePeriod:
772 break;
773 case XML_containsBlanks:
774 aReplaceFormula = "LEN(TRIM(#B))=0";
775 break;
776 case XML_notContainsBlanks:
777 aReplaceFormula = "LEN(TRIM(#B))>0";
778 break;
779 case XML_containsErrors:
780 eOperator = ScConditionMode::Error;
781 break;
782 case XML_notContainsErrors:
783 eOperator = ScConditionMode::NoError;
784 break;
785 case XML_top10:
787 {
788 if(maModel.mbBottom)
790 else
791 eOperator = ScConditionMode::TopPercent;
792 }
793 else
794 {
795 if(maModel.mbBottom)
796 eOperator = ScConditionMode::Bottom10;
797 else
798 eOperator = ScConditionMode::Top10;
799 }
800 break;
801 case XML_aboveAverage:
803 {
806 else
808 }
809 else
810 {
813 else
815 }
816 break;
817 case XML_colorScale:
818 break;
819 }
820
821 if( !aReplaceFormula.isEmpty() )
822 {
823 OUString aAddress;
824 sal_Int32 nStrPos = aReplaceFormula.getLength();
825 while( (nStrPos = aReplaceFormula.lastIndexOf( '#', nStrPos )) >= 0 )
826 {
827 switch( aReplaceFormula[ nStrPos + 1 ] )
828 {
829 case 'B': // current base address
830 if( aAddress.isEmpty() )
832 aReplaceFormula = aReplaceFormula.replaceAt( nStrPos, 2, aAddress );
833 break;
834 default:
835 OSL_FAIL( "CondFormatRule::finalizeImport - unknown placeholder" );
836 }
837 }
838
839 // set the replacement formula
840 maModel.maFormulas.clear();
841 appendFormula( aReplaceFormula );
842 eOperator = ScConditionMode::Direct;
843 }
844
846
847 if( eOperator == ScConditionMode::Error || eOperator == ScConditionMode::NoError )
848 {
849 ScDocument& rDoc = getScDocument();
850 OUString aStyleName = getStyles().createDxfStyle( maModel.mnDxfId );
851 ScCondFormatEntry* pNewEntry = new ScCondFormatEntry( eOperator, nullptr, nullptr, rDoc, aPos, aStyleName );
852 mpFormat->AddEntry(pNewEntry);
853 }
854 else if( eOperator == ScConditionMode::BeginsWith || eOperator == ScConditionMode::EndsWith ||
856 {
857 ScDocument& rDoc = getScDocument();
858 ScTokenArray aTokenArray(rDoc);
860 aTokenArray.AddString(rSPool.intern(maModel.maText));
861 OUString aStyleName = getStyles().createDxfStyle( maModel.mnDxfId );
862 ScCondFormatEntry* pNewEntry = new ScCondFormatEntry( eOperator, &aTokenArray, nullptr, rDoc, aPos, aStyleName );
863 mpFormat->AddEntry(pNewEntry);
864 }
865 else if( (eOperator != ScConditionMode::NONE) && !maModel.maFormulas.empty() )
866 {
867 ScDocument& rDoc = getScDocument();
868 std::unique_ptr<ScTokenArray> pTokenArray2;
869 if( maModel.maFormulas.size() >= 2)
870 {
871 pTokenArray2.reset(new ScTokenArray(rDoc));
873 rDoc.CheckLinkFormulaNeedingCheck(*pTokenArray2);
874 }
875
876 ScTokenArray aTokenArray(rDoc);
877 OUString aStyleName = getStyles().createDxfStyle( maModel.mnDxfId );
879 rDoc.CheckLinkFormulaNeedingCheck( aTokenArray);
880 ScCondFormatEntry* pNewEntry = new ScCondFormatEntry(eOperator,
881 &aTokenArray, pTokenArray2.get(), rDoc, aPos, aStyleName);
882 mpFormat->AddEntry(pNewEntry);
883 }
884 else if ( eOperator == ScConditionMode::Top10 || eOperator == ScConditionMode::Bottom10 ||
886 {
887 ScDocument& rDoc = getScDocument();
888 ScTokenArray aTokenArray(rDoc);
889 aTokenArray.AddDouble( maModel.mnRank );
890 OUString aStyleName = getStyles().createDxfStyle( maModel.mnDxfId );
891 ScCondFormatEntry* pNewEntry = new ScCondFormatEntry( eOperator, &aTokenArray, nullptr, rDoc, aPos, aStyleName );
892 mpFormat->AddEntry(pNewEntry);
893 }
894 else if( eOperator == ScConditionMode::AboveAverage || eOperator == ScConditionMode::BelowAverage ||
896 {
897 ScDocument& rDoc = getScDocument();
898 // actually that is still unsupported
899 ScTokenArray aTokenArrayDev(rDoc);
900 aTokenArrayDev.AddDouble( maModel.mnStdDev );
901 OUString aStyleName = getStyles().createDxfStyle( maModel.mnDxfId );
902 ScCondFormatEntry* pNewEntry = new ScCondFormatEntry( eOperator, &aTokenArrayDev, nullptr, rDoc, aPos, aStyleName );
903 mpFormat->AddEntry(pNewEntry);
904 }
905 else if( eOperator == ScConditionMode::Duplicate || eOperator == ScConditionMode::NotDuplicate )
906 {
907 ScDocument& rDoc = getScDocument();
908 OUString aStyleName = getStyles().createDxfStyle( maModel.mnDxfId );
909 ScCondFormatEntry* pNewEntry = new ScCondFormatEntry( eOperator, nullptr, nullptr, rDoc, aPos, aStyleName );
910 mpFormat->AddEntry(pNewEntry);
911 }
912 else if( maModel.mnType == XML_timePeriod )
913 {
915 switch( maModel.mnTimePeriod )
916 {
917 case XML_yesterday:
918 eDateType = condformat::YESTERDAY;
919 break;
920 case XML_today:
921 eDateType = condformat::TODAY;
922 break;
923 case XML_tomorrow:
924 eDateType = condformat::TOMORROW;
925 break;
926 case XML_last7Days:
927 eDateType = condformat::LAST7DAYS;
928 break;
929 case XML_lastWeek:
930 eDateType = condformat::LASTWEEK;
931 break;
932 case XML_thisWeek:
933 eDateType = condformat::THISWEEK;
934 break;
935 case XML_nextWeek:
936 eDateType = condformat::NEXTWEEK;
937 break;
938 case XML_lastMonth:
939 eDateType = condformat::LASTMONTH;
940 break;
941 case XML_thisMonth:
942 eDateType = condformat::THISMONTH;
943 break;
944 case XML_nextMonth:
945 eDateType = condformat::NEXTMONTH;
946 break;
947 default:
948 SAL_WARN("sc.filter", "CondFormatRule::finalizeImport - unknown time period type" );
949 }
950
951 ScDocument& rDoc = getScDocument();
952 ScCondDateFormatEntry* pFormatEntry = new ScCondDateFormatEntry(&rDoc);
953 pFormatEntry->SetDateType(eDateType);
954 OUString aStyleName = getStyles().createDxfStyle( maModel.mnDxfId );
955 pFormatEntry->SetStyleName( aStyleName );
956
957 mpFormat->AddEntry(pFormatEntry);
958 }
959 else if( mpColor )
960 {
961 ScDocument& rDoc = getScDocument();
962 ScColorScaleFormat* pFormatEntry = new ScColorScaleFormat(&rDoc);
963
964 mpFormat->AddEntry(pFormatEntry);
965
966 mpColor->AddEntries( pFormatEntry, &rDoc, aPos );
967 }
968 else if (mpDataBar)
969 {
970 ScDocument& rDoc = getScDocument();
971 ScDataBarFormat* pFormatEntry = new ScDataBarFormat(&rDoc);
972
973 mpFormat->AddEntry(pFormatEntry);
974 mpDataBar->SetData( pFormatEntry, &rDoc, aPos );
975
976 }
977 else if(mpIconSet)
978 {
979 ScDocument& rDoc = getScDocument();
980 ScIconSetFormat* pFormatEntry = new ScIconSetFormat(&rDoc);
981
982 mpFormat->AddEntry(pFormatEntry);
983 mpIconSet->SetData( pFormatEntry, &rDoc, aPos );
984 }
985}
986
988{
989 if(!mpColor)
990 mpColor.reset( new ColorScaleRule(mrCondFormat) );
991
992 return mpColor.get();
993}
994
996{
997 if(!mpDataBar)
998 mpDataBar.reset( new DataBarRule(mrCondFormat) );
999
1000 return mpDataBar.get();
1001}
1002
1004{
1005 if(!mpIconSet)
1006 mpIconSet.reset( new IconSetRule(mrCondFormat) );
1007
1008 return mpIconSet.get();
1009}
1010
1012 mbPivot( false )
1013{
1014}
1015
1017 WorksheetHelper( rHelper ),
1018 mpFormat(nullptr),
1019 mbReadyForFinalize(false)
1020{
1021}
1022
1024{
1025 getAddressConverter().convertToCellRangeList( maModel.maRanges, rAttribs.getString( XML_sqref, OUString() ), getSheetIndex(), true );
1026 maModel.mbPivot = rAttribs.getBool( XML_pivot, false );
1028}
1029
1031{
1032 CondFormatRuleRef xRule = createRule();
1033 xRule->importCfRule( rAttribs );
1034 insertRule( xRule );
1035 return xRule;
1036}
1037
1039{
1040 BinRangeList aRanges;
1041 rStrm.skip( 8 );
1042 rStrm >> aRanges;
1045}
1046
1048{
1049 CondFormatRuleRef xRule = createRule();
1050 xRule->importCfRule( rStrm );
1051 insertRule( xRule );
1052}
1053
1055{
1056 // probably some error in the xml if we are not ready
1057 if ( !mbReadyForFinalize )
1058 return;
1059 ScDocument& rDoc = getScDocument();
1063 sal_Int32 nIndex = getScDocument().AddCondFormat(std::unique_ptr<ScConditionalFormat>(mpFormat), nTab);
1064
1066}
1067
1069{
1070 return std::make_shared<CondFormatRule>( *this, mpFormat );
1071}
1072
1074{
1075 if( xRule && (xRule->getPriority() > 0) )
1076 {
1077 OSL_ENSURE( maRules.find( xRule->getPriority() ) == maRules.end(), "CondFormat::insertRule - multiple rules with equal priority" );
1078 maRules[ xRule->getPriority() ] = xRule;
1079 }
1080}
1081
1083 WorksheetHelper( rHelper )
1084{
1085}
1086
1088{
1089 CondFormatRef xCondFmt = createCondFormat();
1090 xCondFmt->importConditionalFormatting( rAttribs );
1091 return xCondFmt;
1092}
1093
1094namespace {
1095
1096ScConditionalFormat* findFormatByRange(const ScRangeList& rRange, const ScDocument* pDoc, SCTAB nTab)
1097{
1098 ScConditionalFormatList* pList = pDoc->GetCondFormList(nTab);
1099 for (auto const& it : *pList)
1100 {
1101 if (it->GetRange() == rRange)
1102 {
1103 return it.get();
1104 }
1105 }
1106
1107 return nullptr;
1108}
1109
1110class ScRangeListHasher
1111{
1112public:
1113 size_t operator() (ScRangeList const& rRanges) const
1114 {
1115 size_t nHash = 0;
1116 for (size_t nIdx = 0; nIdx < rRanges.size(); ++nIdx)
1117 nHash += rRanges[nIdx].hashArea();
1118 return nHash;
1119 }
1120};
1121
1122}
1123
1125{
1126 std::unordered_set<size_t> aDoneExtCFs;
1127 typedef std::unordered_map<ScRangeList, CondFormat*, ScRangeListHasher> RangeMap;
1128 RangeMap aRangeMap;
1129 for (auto& rxCondFormat : maCondFormats)
1130 {
1131 if (aRangeMap.find(rxCondFormat->getRanges()) != aRangeMap.end())
1132 continue;
1133 aRangeMap[rxCondFormat->getRanges()] = rxCondFormat.get();
1134 }
1135
1136 size_t nExtCFIndex = 0;
1137 for (const auto& rxExtCondFormat : maExtCondFormats)
1138 {
1139 ScDocument* pDoc = &getScDocument();
1140 const ScRangeList& rRange = rxExtCondFormat->getRange();
1141 RangeMap::iterator it = aRangeMap.find(rRange);
1142 if (it != aRangeMap.end())
1143 {
1144 CondFormat& rCondFormat = *it->second;
1145 const std::vector<std::unique_ptr<ScFormatEntry>>& rEntries = rxExtCondFormat->getEntries();
1146 const std::vector<sal_Int32>& rPriorities = rxExtCondFormat->getPriorities();
1147 size_t nEntryIdx = 0;
1148 for (const auto& rxEntry : rEntries)
1149 {
1150 CondFormatRuleRef xRule = rCondFormat.createRule();
1151 ScFormatEntry* pNewEntry = rxEntry->Clone(pDoc);
1152 sal_Int32 nPriority = rPriorities[nEntryIdx];
1153 if (nPriority == -1)
1155 xRule->setFormatEntry(nPriority, pNewEntry);
1156 rCondFormat.insertRule(xRule);
1157 ++nEntryIdx;
1158 }
1159
1160 aDoneExtCFs.insert(nExtCFIndex);
1161 }
1162
1163 ++nExtCFIndex;
1164 }
1165
1166 // tdf#138601 sort conditional formatting rules by their priority
1167 if (maCondFormats.size() > 1)
1168 {
1169 size_t minIndex;
1170 for (size_t i = 0; i < maCondFormats.size() - 1; ++i)
1171 {
1172 minIndex = i;
1173 for (size_t j = i + 1; j < maCondFormats.size(); ++j)
1174 {
1175 const CondFormat::CondFormatRuleMap& rNextRules = maCondFormats[j]->maRules;
1176 const CondFormat::CondFormatRuleMap& rMinRules = maCondFormats[minIndex]->maRules;
1177 if (rNextRules.empty() || rMinRules.empty())
1178 continue;
1179 if (rNextRules.begin()->first < rMinRules.begin()->first)
1180 minIndex = j;
1181 }
1182 if (i != minIndex)
1183 std::swap(maCondFormats[i], maCondFormats[minIndex]);
1184 }
1185 }
1186
1187 for( const auto& rxCondFormat : maCondFormats )
1188 {
1189 if ( rxCondFormat)
1190 rxCondFormat->finalizeImport();
1191 }
1192 for ( const auto& rxCfRule : maCfRules )
1193 {
1194 if ( rxCfRule )
1195 rxCfRule->finalizeImport();
1196 }
1197
1198 nExtCFIndex = 0;
1199 for (const auto& rxExtCondFormat : maExtCondFormats)
1200 {
1201 if (aDoneExtCFs.count(nExtCFIndex))
1202 {
1203 ++nExtCFIndex;
1204 continue;
1205 }
1206
1207 ScDocument* pDoc = &getScDocument();
1208 const ScRangeList& rRange = rxExtCondFormat->getRange();
1209 SCTAB nTab = rRange.front().aStart.Tab();
1210 ScConditionalFormat* pFormat = findFormatByRange(rRange, pDoc, nTab);
1211 if (!pFormat)
1212 {
1213 // create new conditional format and insert it
1214 auto pNewFormat = std::make_unique<ScConditionalFormat>(0, pDoc);
1215 pFormat = pNewFormat.get();
1216 pNewFormat->SetRange(rRange);
1217 sal_uLong nKey = pDoc->AddCondFormat(std::move(pNewFormat), nTab);
1218 pDoc->AddCondFormatData(rRange, nTab, nKey);
1219 }
1220
1221 const std::vector< std::unique_ptr<ScFormatEntry> >& rEntries = rxExtCondFormat->getEntries();
1222 for (const auto& rxEntry : rEntries)
1223 {
1224 pFormat->AddEntry(rxEntry->Clone(pDoc));
1225 }
1226
1227 ++nExtCFIndex;
1228 }
1229
1230 rStyleIdx = 0; // Resets <extlst> <cfRule> style index.
1231}
1232
1234{
1235 CondFormatRef xCondFmt = createCondFormat();
1236 xCondFmt->importCondFormatting( rStrm );
1237 return xCondFmt;
1238}
1239
1241{
1242 ExtCfDataBarRuleRef extRule = std::make_shared<ExtCfDataBarRule>( pTarget, *this );
1243 maCfRules.push_back( extRule );
1244 return extRule;
1245}
1246
1247std::vector< std::unique_ptr<ExtCfCondFormat> >& CondFormatBuffer::importExtCondFormat()
1248{
1249 return maExtCondFormats;
1250}
1251
1253{
1254 switch( nToken )
1255 {
1256 case XML_between: return ConditionOperator2::BETWEEN;
1257 case XML_equal: return ConditionOperator2::EQUAL;
1258 case XML_greaterThan: return ConditionOperator2::GREATER;
1259 case XML_greaterThanOrEqual: return ConditionOperator2::GREATER_EQUAL;
1260 case XML_lessThan: return ConditionOperator2::LESS;
1261 case XML_lessThanOrEqual: return ConditionOperator2::LESS_EQUAL;
1262 case XML_notBetween: return ConditionOperator2::NOT_BETWEEN;
1263 case XML_notEqual: return ConditionOperator2::NOT_EQUAL;
1264 case XML_duplicateValues: return ConditionOperator2::DUPLICATE;
1265 }
1267}
1268
1270{
1271 switch( nToken )
1272 {
1273 case XML_between: return ScConditionMode::Between;
1274 case XML_equal: return ScConditionMode::Equal;
1275 case XML_greaterThan: return ScConditionMode::Greater;
1276 case XML_greaterThanOrEqual: return ScConditionMode::EqGreater;
1277 case XML_lessThan: return ScConditionMode::Less;
1278 case XML_lessThanOrEqual: return ScConditionMode::EqLess;
1279 case XML_notBetween: return ScConditionMode::NotBetween;
1280 case XML_notEqual: return ScConditionMode::NotEqual;
1281 case XML_duplicateValues: return ScConditionMode::Duplicate;
1282 case XML_uniqueValues: return ScConditionMode::NotDuplicate;
1283 }
1284 return ScConditionMode::NONE;
1285}
1286
1287// private --------------------------------------------------------------------
1288
1290{
1291 CondFormatRef xCondFmt = std::make_shared<CondFormat>( *this );
1292 maCondFormats.push_back( xCondFmt );
1293 return xCondFmt;
1294}
1295
1297 WorksheetHelper(rParent),
1298 mnRuleType( ExtCfDataBarRule::UNKNOWN ),
1299 mpTarget(pTarget)
1300{
1301}
1302
1304{
1305 switch ( mnRuleType )
1306 {
1307 case DATABAR:
1308 {
1309 ScDataBarFormatData* pDataBar = mpTarget;
1310 if( maModel.maAxisPosition == "none" )
1311 pDataBar->meAxisPosition = databar::NONE;
1312 else if( maModel.maAxisPosition == "middle" )
1313 pDataBar->meAxisPosition = databar::MIDDLE;
1314 else
1316 pDataBar->mbGradient = maModel.mbGradient;
1317 break;
1318 }
1319 case AXISCOLOR:
1320 {
1321 ScDataBarFormatData* pDataBar = mpTarget;
1322 pDataBar->maAxisColor = maModel.mnAxisColor;
1323 break;
1324 }
1325 case NEGATIVEFILLCOLOR:
1326 {
1327 ScDataBarFormatData* pDataBar = mpTarget;
1329 pDataBar->mbNeg = true;
1330 break;
1331 }
1332 case CFVO:
1333 {
1334 ScDataBarFormatData* pDataBar = mpTarget;
1335 ScColorScaleEntry* pEntry = nullptr;
1336 if(maModel.mbIsLower)
1337 pEntry = pDataBar->mpLowerLimit.get();
1338 else
1339 pEntry = pDataBar->mpUpperLimit.get();
1340
1341 if(maModel.maColorScaleType == "min")
1342 pEntry->SetType(COLORSCALE_MIN);
1343 else if (maModel.maColorScaleType == "max")
1344 pEntry->SetType(COLORSCALE_MAX);
1345 else if (maModel.maColorScaleType == "autoMin")
1346 pEntry->SetType(COLORSCALE_AUTO);
1347 else if (maModel.maColorScaleType == "autoMax")
1348 pEntry->SetType(COLORSCALE_AUTO);
1349 else if (maModel.maColorScaleType == "percentile")
1351 else if (maModel.maColorScaleType == "percent")
1352 pEntry->SetType(COLORSCALE_PERCENT);
1353 else if (maModel.maColorScaleType == "formula")
1354 pEntry->SetType(COLORSCALE_FORMULA);
1355 break;
1356 }
1357 case UNKNOWN: // nothing to do
1358 default:
1359 break;
1360 }
1361}
1362
1364{
1366 maModel.mbGradient = rAttribs.getBool( XML_gradient, true );
1367 maModel.maAxisPosition = rAttribs.getString( XML_axisPosition, "automatic" );
1368}
1369
1371{
1373 ThemeBuffer& rThemeBuffer = getTheme();
1374 GraphicHelper& rGraphicHelper = getBaseFilter().getGraphicHelper();
1375 ::Color aColor = importOOXColor(rAttribs, rThemeBuffer, rGraphicHelper);
1376 maModel.mnNegativeColor = aColor;
1377}
1378
1380{
1382 ThemeBuffer& rThemeBuffer = getTheme();
1383 GraphicHelper& rGraphicHelper = getBaseFilter().getGraphicHelper();
1384 ::Color aColor = importOOXColor(rAttribs, rThemeBuffer, rGraphicHelper);
1385 maModel.mnAxisColor = aColor;
1386}
1387
1389{
1390 mnRuleType = CFVO;
1391 maModel.maColorScaleType = rAttribs.getString( XML_type, OUString() );
1392}
1393
1394ExtCfCondFormat::ExtCfCondFormat(ScRangeList aRange, std::vector< std::unique_ptr<ScFormatEntry> >& rEntries,
1395 const std::vector<sal_Int32>* pPriorities):
1396 maRange(std::move(aRange))
1397{
1398 maEntries.swap(rEntries);
1399 if (pPriorities)
1400 maPriorities = *pPriorities;
1401 else
1402 maPriorities.resize(maEntries.size(), -1);
1403}
1404
1406{
1407}
1408
1410{
1411 return maRange;
1412}
1413
1414const std::vector< std::unique_ptr<ScFormatEntry> >& ExtCfCondFormat::getEntries() const
1415{
1416 return maEntries;
1417}
1418
1419} // namespace oox
1420
1421/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
B2DRange maRange
Color GetRGBColor() const
SCTAB Tab() const
Definition: address.hxx:283
void SetType(ScColorScaleEntryType eType)
Definition: colorscale.cxx:323
void SetFormula(const OUString &rFormula, ScDocument &rDoc, const ScAddress &rAddr, formula::FormulaGrammar::Grammar eGrammar=formula::FormulaGrammar::GRAM_DEFAULT)
Definition: colorscale.cxx:207
void AddEntry(ScColorScaleEntry *pEntry)
Definition: colorscale.cxx:404
void SetDateType(condformat::ScCondFormatDateType eType)
Definition: conditio.cxx:1691
void SetStyleName(const OUString &rStyleName)
Definition: conditio.cxx:1696
void SetRange(const ScRangeList &rRanges)
Definition: conditio.cxx:1760
void AddEntry(ScFormatEntry *pNew)
Definition: conditio.cxx:1766
void SetDataBarData(ScDataBarFormatData *pData)
Definition: colorscale.cxx:765
SC_DLLPUBLIC void CheckLinkFormulaNeedingCheck(const ScTokenArray &rCode)
Check token array and set link check if ocDde/ocWebservice is contained.
Definition: documen8.cxx:1154
SC_DLLPUBLIC svl::SharedStringPool & GetSharedStringPool()
Definition: documen2.cxx:603
SC_DLLPUBLIC void AddCondFormatData(const ScRangeList &rRange, SCTAB nTab, sal_uInt32 nIndex)
Definition: document.cxx:4885
SC_DLLPUBLIC ScConditionalFormatList * GetCondFormList(SCTAB nTab) const
Definition: documen4.cxx:866
SC_DLLPUBLIC sal_uLong AddCondFormat(std::unique_ptr< ScConditionalFormat > pNew, SCTAB nTab)
Definition: documen4.cxx:714
virtual ScFormatEntry * Clone(ScDocument *pDoc) const =0
static const ScIconSetMap g_IconSetMap[]
Definition: colorscale.hxx:387
void SetIconSetData(ScIconSetFormatData *pData)
ScRange & front()
Definition: rangelst.hxx:92
ScAddress GetTopLeftCorner() const
Definition: rangelst.cxx:1150
size_t size() const
Definition: rangelst.hxx:89
ScAddress aStart
Definition: address.hxx:497
static SC_DLLPUBLIC bool ConvertToTokenArray(ScDocument &rDoc, ScTokenArray &rTokenArray, const css::uno::Sequence< css::sheet::FormulaToken > &rSequence)
Definition: tokenuno.cxx:374
FormulaToken * AddDouble(double fVal)
FormulaToken * AddString(const svl::SharedString &rStr)
sal_uInt32 getUnsignedHex(sal_Int32 nAttrToken, sal_uInt32 nDefault) const
bool hasAttribute(sal_Int32 nAttrToken) const
std::optional< sal_uInt32 > getUnsigned(sal_Int32 nAttrToken) const
std::optional< sal_Int32 > getInteger(sal_Int32 nAttrToken) const
std::optional< OUString > getString(sal_Int32 nAttrToken) const
std::optional< bool > getBool(sal_Int32 nAttrToken) const
std::optional< sal_Int32 > getToken(sal_Int32 nAttrToken) const
std::optional< double > getDouble(sal_Int32 nAttrToken) const
void forEachMem(FuncType pFunc) const
GraphicHelper & getGraphicHelper() const
void addExcelTintTransformation(double fTint)
::Color getColor(const GraphicHelper &rGraphicHelper, ::Color nPhClr=API_RGB_TRANSPARENT) const
void setSrgbClr(sal_Int32 nRgb)
void convertToCellRangeList(ScRangeList &orRanges, std::u16string_view aString, sal_Int16 nSheet, bool bTrackOverflow)
Tries to convert the passed string to a cell range list.
A 2D cell range address list for binary filters.
std::vector< ColorScaleRuleModelEntry > maColorScaleRuleEntries
void importColor(const AttributeList &rAttribs)
ColorScaleRule(const CondFormat &rFormat)
void importCfvo(const AttributeList &rAttribs)
void AddEntries(ScColorScaleFormat *pFormat, ScDocument *pDoc, const ScAddress &rAddr)
std::vector< std::unique_ptr< ExtCfCondFormat > > & importExtCondFormat()
ExtCfDataBarRuleVec maCfRules
All conditional formatting in a sheet.
ExtCfDataBarRuleRef createExtCfDataBarRule(ScDataBarFormatData *pTarget)
CondFormatRef importConditionalFormatting(const AttributeList &rAttribs)
Imports settings from the conditionalFormatting element.
static ScConditionMode convertToInternalOperator(sal_Int32 nToken)
std::vector< std::unique_ptr< ExtCfCondFormat > > maExtCondFormats
All external conditional formatting rules in a sheet.
CondFormatBuffer(const WorksheetHelper &rHelper)
static sal_Int32 convertToApiOperator(sal_Int32 nToken)
Converts an OOXML condition operator token to the API constant.
CondFormatRef importCondFormatting(SequenceInputStream &rStrm)
Imports settings from the CONDFORMATTING record.
void importCfRule(const AttributeList &rAttribs)
Imports rule settings from the cfRule element.
CondFormatRuleModel maModel
void appendFormula(const OUString &rFormula)
Appends a new condition formula string.
std::unique_ptr< ColorScaleRule > mpColor
ScConditionalFormat * mpFormat
void finalizeImport()
Creates a conditional formatting rule in the Calc document.
const CondFormat & mrCondFormat
void setFormatEntry(sal_Int32 nPriority, ScFormatEntry *pEntry)
Directly set a ScFormatEntry with a priority ready for finalizeImport().
ColorScaleRule * getColorScale()
std::unique_ptr< IconSetRule > mpIconSet
CondFormatRule(const CondFormat &rCondFormat, ScConditionalFormat *pFormat)
std::unique_ptr< DataBarRule > mpDataBar
Represents a conditional formatting object with a list of affected cell ranges.
CondFormat(const WorksheetHelper &rHelper)
void insertRule(CondFormatRuleRef const &xRule)
const ScRangeList & getRanges() const
Returns the cell ranges this conditional formatting belongs to.
ScConditionalFormat * mpFormat
Maps formatting rules by priority.
void importConditionalFormatting(const AttributeList &rAttribs)
Imports settings from the conditionalFormatting element.
CondFormatRuleMap maRules
Model of this conditional formatting.
CondFormatRuleRef createRule()
void importCondFormatting(SequenceInputStream &rStrm)
Imports settings from the CONDFORMATTING record.
CondFormatRuleRef importCfRule(const AttributeList &rAttribs)
Imports a conditional formatting rule from the cfRule element.
void finalizeImport()
Creates the conditional formatting in the Calc document.
std::unique_ptr< ColorScaleRuleModelEntry > mpLowerLimit
void importCfvo(const AttributeList &rAttribs)
DataBarRule(const CondFormat &rFormat)
std::unique_ptr< ScDataBarFormatData > mxFormat
std::unique_ptr< ColorScaleRuleModelEntry > mpUpperLimit
void importColor(const AttributeList &rAttribs)
void SetData(ScDataBarFormat *pFormat, ScDocument *pDoc, const ScAddress &rAddr)
void importAttribs(const AttributeList &rAttribs)
const ScRangeList & getRange() const
std::vector< sal_Int32 > maPriorities
std::vector< std::unique_ptr< ScFormatEntry > > maEntries
const std::vector< std::unique_ptr< ScFormatEntry > > & getEntries() const
ExtCfCondFormat(ScRangeList aRange, std::vector< std::unique_ptr< ScFormatEntry > > &rEntries, const std::vector< sal_Int32 > *pPriorities=nullptr)
ScDataBarFormatData * mpTarget
void importDataBar(const AttributeList &rAttribs)
void importNegativeFillColor(const AttributeList &rAttribs)
void importCfvo(const AttributeList &rAttribs)
ExtCfDataBarRule(ScDataBarFormatData *pTarget, const WorksheetHelper &rParent)
void importAxisColor(const AttributeList &rAttribs)
ApiTokenSequence importFormula(const ScAddress &rBaseAddr, const OUString &rFormulaString) const
Converts an OOXML formula string.
static OUString generateAddress2dString(const ScAddress &rAddress, bool bAbsolute)
Generates a cell address string in A1 notation from the passed cell address.
std::unique_ptr< ScIconSetFormatData > mxFormatData
void importIcon(const AttributeList &rAttribs)
std::vector< ColorScaleRuleModelEntry > maEntries
void SetData(ScIconSetFormat *pFormat, ScDocument *pDoc, const ScAddress &rAddr)
IconSetRule(const WorksheetHelper &rParent)
void importFormula(const OUString &rFormula)
void importAttribs(const AttributeList &rAttribs)
void importCfvo(const AttributeList &rAttribs)
OUString createDxfStyle(sal_Int32 nDxfId) const
Creates the style sheet described by the DXF with the passed identifier.
::Color getColorByIndex(size_t nIndex) const
Definition: themebuffer.cxx:46
AddressConverter & getAddressConverter() const
Returns the converter for string to cell address/range conversion.
StylesBuffer & getStyles() const
Returns all cell formatting objects read from the styles substream.
ThemeBuffer & getTheme() const
Returns the office theme object read from the theme substorage.
::oox::core::FilterBase & getBaseFilter() const
Returns the base filter object (base class of all filters).
FormulaParser & getFormulaParser() const
Returns a shared import formula parser (import filter only!).
SCTAB getSheetIndex() const
Returns the index of the current sheet.
SharedString intern(const OUString &rStr)
ScIconSetType
Definition: colorscale.hxx:189
@ IconSet_3TrafficLights1
Definition: colorscale.hxx:193
@ COLORSCALE_MAX
Definition: colorscale.hxx:35
@ COLORSCALE_VALUE
Definition: colorscale.hxx:37
@ COLORSCALE_FORMULA
Definition: colorscale.hxx:39
@ COLORSCALE_PERCENT
Definition: colorscale.hxx:38
@ COLORSCALE_PERCENTILE
Definition: colorscale.hxx:36
@ COLORSCALE_AUTO
Definition: colorscale.hxx:33
@ COLORSCALE_MIN
Definition: colorscale.hxx:34
ScConditionMode
Definition: conditio.hxx:60
sal_Int32 mnCol
sal_Int32 rStyleIdx
UNKNOWN
#define STATIC_ARRAY_SELECT(array, index, def)
sal_Int32 nIndex
#define SAL_WARN_IF(condition, area, stream)
#define SAL_WARN(area, stream)
ScCondFormatDateType
Definition: conditio.hxx:485
int i
void SvStream & rStrm
std::basic_string_view< charT, traits > trim(std::basic_string_view< charT, traits > str)
std::shared_ptr< CondFormatRule > CondFormatRuleRef
css::uno::Sequence< ApiToken > ApiTokenSequence
@ CondFormat
Shared formula definition.
std::shared_ptr< CondFormat > CondFormatRef
std::shared_ptr< ExtCfDataBarRule > ExtCfDataBarRuleRef
const sal_uInt32 UNSIGNED_RGB_TRANSPARENT
bool getFlag(Type nBitField, Type nMask)
XML_type
XML_TOKEN_INVALID
bool getType(BSTR name, Type &type)
DefTokenId nToken
Definition: qproform.cxx:397
QPRO_FUNC_TYPE nType
Definition: qproform.cxx:398
sal_Int32 mnType
double mnPriority
sal_uIntPtr sal_uLong
T * mpTarget
Color maAxisColor
Color of the axis if used Default color is black.
Definition: colorscale.hxx:145
std::optional< Color > mxNegativeColor
Specifies the color for negative values.
Definition: colorscale.hxx:140
std::unique_ptr< ScColorScaleEntry, o3tl::default_delete< ScColorScaleEntry > > mpLowerLimit
Definition: colorscale.hxx:185
databar::ScAxisPosition meAxisPosition
Paint negative values into the same direction as positive values If false we will set the mid point a...
Definition: colorscale.hxx:167
bool mbNeg
Use different color for negative values.
Definition: colorscale.hxx:159
bool mbGradient
Paint the bars with gradient.
Definition: colorscale.hxx:152
std::unique_ptr< ScColorScaleEntry, o3tl::default_delete< ScColorScaleEntry > > mpUpperLimit
Definition: colorscale.hxx:184
ScIconSetType eType
Definition: colorscale.hxx:216
const char * pName
Definition: colorscale.hxx:215
bool mbPivot
Cell ranges for this conditional format.
CondFormatModel()
Conditional formatting belongs to pivot table.
bool mbEqualAverage
In average rules: True = above average, false = below.
bool mbAboveAverage
In top-10 rules: True = percent, false = rank.
sal_Int32 mnTimePeriod
In cell-is rules: Comparison operator.
sal_Int32 mnPriority
Text for 'contains' rules.
CondFormatRuleModel()
In average rules: True = include average, false = exclude.
bool mbPercent
In top-10 rules: True = bottom, false = top.
sal_Int32 mnType
Priority of this rule.
bool mbStopIfTrue
Differential formatting identifier.
ApiTokenSequenceVector maFormulas
sal_Int32 mnRank
In time-period rules: Type of time period.
OUString maText
Formulas for rule conditions.
bool mbBottom
True = stop evaluating rules, if this rule is true.
sal_Int32 mnStdDev
In top-10 rules: True = bottom, false = top.
void setBiff12TextType(sal_Int32 nOperator)
Sets the passed BIFF12 text comparison type and operator.
sal_Int32 mnOperator
Type of the rule.
void setBiffOperator(sal_Int32 nOperator)
Sets the passed BIFF operator for condition type cellIs.
sal_Int32 mnDxfId
In average rules: Number of std deviations.
sal_Int16 SCTAB
Definition: types.hxx:22