LibreOffice Module sc (master) 1
xmlcondformat.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
10#include <memory>
11#include "xmlcondformat.hxx"
12#include "xmlimprt.hxx"
14#include <xmloff/xmlictxt.hxx>
15#include <xmloff/xmltoken.hxx>
16#include <sal/log.hxx>
17
18#include <compiler.hxx>
19#include <colorscale.hxx>
20#include <conditio.hxx>
21#include <document.hxx>
23#include <rangelst.hxx>
24#include <rangeutl.hxx>
25#include "XMLConverter.hxx"
26#include <stylehelper.hxx>
27#include <tokenarray.hxx>
28
29using namespace xmloff::token;
30
32 ScXMLImportContext( rImport )
33{
35 GetScImport().GetDocument()->SetCondFormList(new ScConditionalFormatList(), GetScImport().GetTables().GetCurrentSheet());
36}
37
38css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL ScXMLConditionalFormatsContext::createFastChildContext(
39 sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
40{
41 SvXMLImportContext* pContext = nullptr;
44
45 switch (nElement)
46 {
47 case XML_ELEMENT( CALC_EXT, XML_CONDITIONAL_FORMAT ):
48 pContext = new ScXMLConditionalFormatContext( GetScImport(), pAttribList, *this );
49 break;
50 }
51
52 return pContext;
53}
54
56{
57 mvCondFormatData.erase(std::remove_if(mvCondFormatData.begin(), mvCondFormatData.end(),
58 [pFormat](CondFormatData& r){ return r.mpFormat == pFormat; }),
59 mvCondFormatData.end());
60}
61
62void SAL_CALL ScXMLConditionalFormatsContext::endFastElement( sal_Int32 /*nElement*/ )
63{
65
67 ScConditionalFormatList* pCondFormatList = pDoc->GetCondFormList(nTab);
68 bool bDeleted = !pCondFormatList->CheckAllEntries(LINK(this, ScXMLConditionalFormatsContext, FormatDeletedHdl));
69
70 SAL_WARN_IF(bDeleted, "sc", "conditional formats have been deleted because they contained empty range info");
71
72 for (const auto& i : mvCondFormatData)
73 {
74 pDoc->AddCondFormatData( i.mpFormat->GetRange(), i.mnTab, i.mpFormat->GetKey() );
75 }
76}
77
81 ScXMLImportContext( rImport ),
82 mrParent( rParent )
83{
84 OUString sRange;
85
86 if ( rAttrList.is() )
87 {
88 for (auto &aIter : *rAttrList)
89 {
90 switch (aIter.getToken())
91 {
92 case XML_ELEMENT( CALC_EXT, XML_TARGET_RANGE_ADDRESS ):
93 sRange = aIter.toString();
94 break;
95 default:
96 break;
97 }
98 }
99 }
100
101 ScRangeList aRangeList;
103 assert(pDoc);
104 ScRangeStringConverter::GetRangeListFromString(aRangeList, sRange, *pDoc,
106
107 mxFormat.reset(new ScConditionalFormat(0, pDoc));
108 mxFormat->SetRange(aRangeList);
109}
110
111css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL ScXMLConditionalFormatContext::createFastChildContext(
112 sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
113{
114 SvXMLImportContext* pContext = nullptr;
117
118 switch (nElement)
119 {
120 case XML_ELEMENT( CALC_EXT, XML_CONDITION ):
121 pContext = new ScXMLCondContext( GetScImport(), pAttribList, mxFormat.get() );
122 break;
123 case XML_ELEMENT( CALC_EXT, XML_COLOR_SCALE ):
124 pContext = new ScXMLColorScaleFormatContext( GetScImport(), mxFormat.get() );
125 break;
126 case XML_ELEMENT( CALC_EXT, XML_DATA_BAR ):
127 pContext = new ScXMLDataBarFormatContext( GetScImport(), pAttribList, mxFormat.get() );
128 break;
129 case XML_ELEMENT( CALC_EXT, XML_ICON_SET ):
130 pContext = new ScXMLIconSetFormatContext( GetScImport(), pAttribList, mxFormat.get() );
131 break;
132 case XML_ELEMENT( CALC_EXT, XML_DATE_IS ):
133 pContext = new ScXMLDateContext( GetScImport(), pAttribList, mxFormat.get() );
134 break;
135 default:
136 break;
137 }
138
139 return pContext;
140}
141
142static bool HasRelRefIgnoringSheet0Relative( ScDocument* pDoc, const ScTokenArray* pTokens, sal_uInt16 nRecursion = 0 )
143{
144 if (pTokens)
145 {
148 for( t = aIter.Next(); t; t = aIter.Next() )
149 {
150 switch( t->GetType() )
151 {
153 {
154 ScSingleRefData& rRef2 = t->GetDoubleRef()->Ref2;
155 if ( rRef2.IsColRel() || rRef2.IsRowRel() || (rRef2.IsFlag3D() && rRef2.IsTabRel()) )
156 return true;
157 [[fallthrough]];
158 }
159
161 {
162 ScSingleRefData& rRef1 = *t->GetSingleRef();
163 if ( rRef1.IsColRel() || rRef1.IsRowRel() || (rRef1.IsFlag3D() && rRef1.IsTabRel()) )
164 return true;
165 }
166 break;
167
168 case formula::svIndex:
169 {
170 if( t->GetOpCode() == ocName ) // DB areas always absolute
171 if( ScRangeData* pRangeData = pDoc->FindRangeNameBySheetAndIndex( t->GetSheet(), t->GetIndex()) )
172 if( (nRecursion < 42) && HasRelRefIgnoringSheet0Relative( pDoc, pRangeData->GetCode(), nRecursion + 1 ) )
173 return true;
174 }
175 break;
176
177 // #i34474# function result dependent on cell position
178 case formula::svByte:
179 {
180 switch( t->GetOpCode() )
181 {
182 case ocRow: // ROW() returns own row index
183 case ocColumn: // COLUMN() returns own column index
184 case ocSheet: // SHEET() returns own sheet index
185 case ocCell: // CELL() may return own cell address
186 return true;
187 default:
188 break;
189 }
190 }
191 break;
192
193 default:
194 break;
195 }
196 }
197 }
198 return false;
199}
200
202{
203 int nCount = 0;
204 if (pTokens)
205 {
208 for( t = aIter.Next(); t; t = aIter.Next() )
209 {
210 switch( t->GetType() )
211 {
213 {
214 ScSingleRefData& rRef1 = *t->GetSingleRef();
215 if ( rRef1.IsColRel() && rRef1.IsRowRel() && !rRef1.IsFlag3D() && rRef1.IsTabRel() )
216 {
217 nCount++;
218 if (nCount == 1)
219 {
220 rOffset = rRef1;
221 }
222 }
223 }
224 break;
225
226 default:
227 break;
228 }
229 }
230 }
231 return nCount == 1;
232}
233
234void SAL_CALL ScXMLConditionalFormatContext::endFastElement( sal_Int32 /*nElement*/ )
235{
237 assert(pDoc);
238
240 std::unique_ptr<ScConditionalFormat> pFormat(std::move(mxFormat));
241
242 bool bEligibleForCache = true;
243 bool bSingleRelativeReference = false;
244 ScSingleRefData aOffsetForSingleRelRef;
245 std::unique_ptr<ScTokenArray> pTokens;
246 for (size_t nFormatEntryIx = 0; nFormatEntryIx < pFormat->size(); ++nFormatEntryIx)
247 {
248 auto pFormatEntry = pFormat->GetEntry(nFormatEntryIx);
249 auto pCondFormatEntry = dynamic_cast<const ScCondFormatEntry*>(pFormatEntry);
250
251 if (pCondFormatEntry == nullptr ||
252 (pCondFormatEntry->GetOperation() != ScConditionMode::Equal &&
253 pCondFormatEntry->GetOperation() != ScConditionMode::Direct))
254 {
255 bEligibleForCache = false;
256 break;
257 }
258
259 ScAddress aSrcPos;
260 OUString aSrcString = pCondFormatEntry->GetSrcString();
261 if ( !aSrcString.isEmpty() )
262 aSrcPos.Parse( aSrcString, *pDoc );
263 ScCompiler aComp( *pDoc, aSrcPos );
265 pTokens = aComp.CompileString( pCondFormatEntry->GetExpression(aSrcPos, 0), "" );
266 if (HasRelRefIgnoringSheet0Relative( pDoc, pTokens.get() ))
267 {
268 // In general not eligible, but some might be. We handle one very special case: When the
269 // conditional format has one entry, the reference position is the first cell of the
270 // range, and with a single fully relative reference in its expression. (Possibly these
271 // conditions could be loosened, but I am too tired to think on that right now.)
272 if (pFormat->size() == 1 &&
273 pFormat->GetRange().size() == 1 &&
274 pFormat->GetRange()[0].aStart == aSrcPos &&
275 HasOneSingleFullyRelativeReference( pTokens.get(), aOffsetForSingleRelRef ))
276 {
277 bSingleRelativeReference = true;
278 }
279 else
280 {
281 bEligibleForCache = false;
282 break;
283 }
284 }
285 }
286
287 if (bEligibleForCache)
288 {
289 for (auto& aCacheEntry : mrParent.maCache)
290 if (aCacheEntry.mnAge < SAL_MAX_INT64)
291 aCacheEntry.mnAge++;
292
293 for (auto& aCacheEntry : mrParent.maCache)
294 {
295 if (!aCacheEntry.mpFormat)
296 continue;
297
298 if (aCacheEntry.mpFormat->size() != pFormat->size())
299 continue;
300
301 // Check if the conditional format is identical to an existing one (but with different range) and can be shared
302 for (size_t nFormatEntryIx = 0; nFormatEntryIx < pFormat->size(); ++nFormatEntryIx)
303 {
304 auto pCacheFormatEntry = aCacheEntry.mpFormat->GetEntry(nFormatEntryIx);
305 auto pFormatEntry = pFormat->GetEntry(nFormatEntryIx);
306 if (pCacheFormatEntry->GetType() != pFormatEntry->GetType() ||
307 pFormatEntry->GetType() != ScFormatEntry::Type::Condition)
308 break;
309
310 auto pCacheCondFormatEntry = static_cast<const ScCondFormatEntry*>(pCacheFormatEntry);
311 auto pCondFormatEntry = static_cast<const ScCondFormatEntry*>(pFormatEntry);
312
313 if (pCacheCondFormatEntry->GetStyle() != pCondFormatEntry->GetStyle())
314 break;
315
316 // Note That comparing the formulas of the ScConditionEntry at this stage is
317 // comparing just the *strings* of the formulas. For the bSingleRelativeReference
318 // case we compare the tokenized ("compiled") formulas.
319 if (bSingleRelativeReference)
320 {
321 if (aCacheEntry.mbSingleRelativeReference &&
322 pTokens->EqualTokens(aCacheEntry.mpTokens.get()))
323 ;
324 else
325 break;
326 }
327 else if (!pCacheCondFormatEntry->IsEqual(*pCondFormatEntry, /*bIgnoreSrcPos*/true))
328 {
329 break;
330 }
331 // If we get here on the last round through the for loop, we have a cache hit
332 if (nFormatEntryIx == pFormat->size() - 1)
333 {
334 // Mark cache entry as fresh, do necessary mangling of it and just return
335 aCacheEntry.mnAge = 0;
336 for (size_t k = 0; k < pFormat->GetRange().size(); ++k)
337 aCacheEntry.mpFormat->GetRangeList().Join(pFormat->GetRange()[k]);
338 return;
339 }
340 }
341 }
342 }
343
344 sal_uLong nIndex = pDoc->AddCondFormat(std::move(pFormat), nTab);
345 ScConditionalFormat* pInsertedFormat = pDoc->GetCondFormList(nTab)->GetFormat(nIndex);
346 assert(pInsertedFormat && pInsertedFormat->GetKey() == nIndex);
347
348 mrParent.mvCondFormatData.push_back( { pInsertedFormat, nTab } );
349
350 if (!bEligibleForCache)
351 return;
352
353 // Not found in cache, replace oldest cache entry
354 sal_Int64 nOldestAge = -1;
355 size_t nIndexOfOldest = 0;
356 for (auto& aCacheEntry : mrParent.maCache)
357 {
358 if (aCacheEntry.mnAge > nOldestAge)
359 {
360 nOldestAge = aCacheEntry.mnAge;
361 nIndexOfOldest = (&aCacheEntry - &mrParent.maCache.front());
362 }
363 }
364 mrParent.maCache[nIndexOfOldest].mpFormat = pInsertedFormat;
365 mrParent.maCache[nIndexOfOldest].mbSingleRelativeReference = bSingleRelativeReference;
366 mrParent.maCache[nIndexOfOldest].mpTokens = std::move(pTokens);
367 mrParent.maCache[nIndexOfOldest].mnAge = 0;
368}
369
371{
372}
373
375 ScConditionalFormat* pFormat):
376 ScXMLImportContext( rImport ),
377 pColorScaleFormat(nullptr)
378{
379 pColorScaleFormat = new ScColorScaleFormat(GetScImport().GetDocument());
380 pFormat->AddEntry(pColorScaleFormat);
381}
382
383css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL ScXMLColorScaleFormatContext::createFastChildContext(
384 sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
385{
386 SvXMLImportContext* pContext = nullptr;
389
390 switch (nElement)
391 {
392 case XML_ELEMENT( CALC_EXT, XML_COLOR_SCALE_ENTRY ):
393 pContext = new ScXMLColorScaleFormatEntryContext( GetScImport(), pAttribList, pColorScaleFormat );
394 break;
395 default:
396 break;
397 }
398
399 return pContext;
400}
401
404 ScConditionalFormat* pFormat):
405 ScXMLImportContext( rImport ),
406 mpFormatData(nullptr),
407 mpParent(pFormat),
408 mnIndex(0)
409{
410 OUString sPositiveColor;
411 OUString sNegativeColor;
412 OUString sGradient;
413 OUString sAxisPosition;
414 OUString sShowValue;
415 OUString sAxisColor;
416 OUString sMinLength;
417 OUString sMaxLength;
418
419 if ( rAttrList.is() )
420 {
421 for (auto &aIter : *rAttrList)
422 {
423 switch (aIter.getToken())
424 {
425 case XML_ELEMENT( CALC_EXT, XML_POSITIVE_COLOR ):
426 sPositiveColor = aIter.toString();
427 break;
428 case XML_ELEMENT( CALC_EXT, XML_GRADIENT ):
429 sGradient = aIter.toString();
430 break;
431 case XML_ELEMENT( CALC_EXT, XML_NEGATIVE_COLOR ):
432 sNegativeColor = aIter.toString();
433 break;
434 case XML_ELEMENT( CALC_EXT, XML_AXIS_POSITION ):
435 sAxisPosition = aIter.toString();
436 break;
437 case XML_ELEMENT( CALC_EXT, XML_SHOW_VALUE ):
438 sShowValue = aIter.toString();
439 break;
440 case XML_ELEMENT( CALC_EXT, XML_AXIS_COLOR ):
441 sAxisColor = aIter.toString();
442 break;
443 case XML_ELEMENT( CALC_EXT, XML_MIN_LENGTH ):
444 sMinLength = aIter.toString();
445 break;
446 case XML_ELEMENT( CALC_EXT, XML_MAX_LENGTH ):
447 sMaxLength = aIter.toString();
448 break;
449 default:
450 break;
451 }
452 }
453 }
454
455 ScDataBarFormat* pDataBarFormat = new ScDataBarFormat(rImport.GetDocument());
457 pDataBarFormat->SetDataBarData(mpFormatData);
458 if(!sGradient.isEmpty())
459 {
460 bool bGradient = true;
461 (void)sax::Converter::convertBool( bGradient, sGradient);
462 mpFormatData->mbGradient = bGradient;
463 }
464
465 if(!sPositiveColor.isEmpty())
466 {
468 }
469
470 if(!sNegativeColor.isEmpty())
471 {
472 // we might check here for 0xff0000 and don't write it
473 Color nColor;
474 sax::Converter::convertColor( nColor, sNegativeColor );
476 }
477 else
478 mpFormatData->mbNeg = false;
479
480 if(!sAxisPosition.isEmpty())
481 {
482 if(sAxisPosition == "middle")
484 else if (sAxisPosition == "none")
486 }
487
488 if(!sAxisColor.isEmpty())
489 {
491 }
492
493 if(!sShowValue.isEmpty())
494 {
495 bool bShowValue = true;
496 (void)sax::Converter::convertBool( bShowValue, sShowValue );
497 mpFormatData->mbOnlyBar = !bShowValue;
498 }
499
500 if (!sMinLength.isEmpty())
501 {
502 double nVal = sMinLength.toDouble();
504 }
505
506 if (!sMaxLength.isEmpty())
507 {
508 double nVal = sMaxLength.toDouble();
509 if (nVal == 0.0)
510 nVal = 100.0;
512 }
513
514 pFormat->AddEntry(pDataBarFormat);
515}
516
517css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL ScXMLDataBarFormatContext::createFastChildContext(
518 sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
519{
520 SvXMLImportContext* pContext = nullptr;
523
524 switch (nElement)
525 {
526 case XML_ELEMENT( CALC_EXT, XML_FORMATTING_ENTRY ):
527 case XML_ELEMENT( CALC_EXT, XML_DATA_BAR_ENTRY ):
528 {
529 ScColorScaleEntry* pEntry(nullptr);
530 pContext = new ScXMLFormattingEntryContext( GetScImport(), pAttribList, pEntry );
532 if(mnIndex == 0)
533 {
534 mpFormatData->mpLowerLimit.reset(pEntry);
535 }
536 else if (mnIndex == 1)
537 {
538 mpFormatData->mpUpperLimit.reset(pEntry);
539 }
540 else
541 {
542 // data bars only support 2 entries
543 assert(false);
544 }
545 ++mnIndex;
546 }
547 break;
548 default:
549 break;
550 }
551
552 return pContext;
553}
554
557 ScConditionalFormat* pFormat):
558 ScXMLImportContext( rImport ),
559 mpParent(pFormat)
560{
561 OUString aIconSetType, sShowValue;
562 if ( rAttrList.is() )
563 {
564 for (auto &aIter : *rAttrList)
565 {
566 switch (aIter.getToken())
567 {
568 case XML_ELEMENT( CALC_EXT, XML_ICON_SET_TYPE ):
569 aIconSetType = aIter.toString();
570 break;
571 case XML_ELEMENT( CALC_EXT, XML_SHOW_VALUE ):
572 sShowValue = aIter.toString();
573 break;
574 default:
575 break;
576 }
577 }
578 }
579
582 for(; pMap->pName; ++pMap)
583 {
584 OUString aName = OUString::createFromAscii(pMap->pName);
585 if(aName ==aIconSetType)
586 {
587 eType = pMap->eType;
588 break;
589 }
590 }
591
592 ScIconSetFormat* pIconSetFormat = new ScIconSetFormat(GetScImport().GetDocument());
593 ScIconSetFormatData* pIconSetFormatData = new ScIconSetFormatData;
594
595 if(!sShowValue.isEmpty())
596 {
597 bool bShowValue = true;
598 (void)sax::Converter::convertBool( bShowValue, sShowValue );
599 pIconSetFormatData->mbShowValue = !bShowValue;
600 }
601
602 pIconSetFormatData->eIconSetType = eType;
603 pIconSetFormat->SetIconSetData(pIconSetFormatData);
604 pFormat->AddEntry(pIconSetFormat);
605
606 mpFormatData = pIconSetFormatData;
607}
608
609css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL ScXMLIconSetFormatContext::createFastChildContext(
610 sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
611{
612 SvXMLImportContext* pContext = nullptr;
615
616 switch (nElement)
617 {
618 case XML_ELEMENT( CALC_EXT, XML_FORMATTING_ENTRY ):
619 {
620 ScColorScaleEntry* pEntry(nullptr);
621 pContext = new ScXMLFormattingEntryContext( GetScImport(), pAttribList, pEntry );
622 mpFormatData->m_Entries.emplace_back(pEntry);
624 }
625 break;
626 default:
627 break;
628 }
629
630 return pContext;
631}
632
633namespace {
634
635void GetConditionData(const OUString& rValue, ScConditionMode& eMode, OUString& rExpr1, OUString& rExpr2)
636{
637 if(rValue.startsWith("unique"))
638 {
640 }
641 else if(rValue.startsWith("duplicate"))
642 {
644 }
645 else if(rValue.startsWith("between"))
646 {
647 const sal_Unicode* pStr = rValue.getStr();
648 const sal_Unicode* pStart = pStr + 8;
649 const sal_Unicode* pEnd = pStr + rValue.getLength();
650 rExpr1 = ScXMLConditionHelper::getExpression( pStart, pEnd, ',');
651 rExpr2 = ScXMLConditionHelper::getExpression( pStart, pEnd, ')');
653 }
654 else if(rValue.startsWith("not-between"))
655 {
656 const sal_Unicode* pStr = rValue.getStr();
657 const sal_Unicode* pStart = pStr + 12;
658 const sal_Unicode* pEnd = pStr + rValue.getLength();
659 rExpr1 = ScXMLConditionHelper::getExpression( pStart, pEnd, ',');
660 rExpr2 = ScXMLConditionHelper::getExpression( pStart, pEnd, ')');
662 }
663 else if(rValue.startsWith("<="))
664 {
665 rExpr1 = rValue.copy(2);
667 }
668 else if(rValue.startsWith(">="))
669 {
670 rExpr1 = rValue.copy(2);
672 }
673 else if(rValue.startsWith("!="))
674 {
675 rExpr1 = rValue.copy(2);
677 }
678 else if(rValue.startsWith("<"))
679 {
680 rExpr1 = rValue.copy(1);
682 }
683 else if(rValue.startsWith("="))
684 {
685 rExpr1 = rValue.copy(1);
687 }
688 else if(rValue.startsWith(">"))
689 {
690 rExpr1 = rValue.copy(1);
692 }
693 else if(rValue.startsWith("formula-is"))
694 {
695 const sal_Unicode* pStr = rValue.getStr();
696 const sal_Unicode* pStart = pStr + 11;
697 const sal_Unicode* pEnd = pStr + rValue.getLength();
698 rExpr1 = ScXMLConditionHelper::getExpression( pStart, pEnd, ')');
700 }
701 else if(rValue.startsWith("top-elements"))
702 {
703 const sal_Unicode* pStr = rValue.getStr();
704 const sal_Unicode* pStart = pStr + 13;
705 const sal_Unicode* pEnd = pStr + rValue.getLength();
706 rExpr1 = ScXMLConditionHelper::getExpression( pStart, pEnd, ')');
708 }
709 else if(rValue.startsWith("bottom-elements"))
710 {
711 const sal_Unicode* pStr = rValue.getStr();
712 const sal_Unicode* pStart = pStr + 16;
713 const sal_Unicode* pEnd = pStr + rValue.getLength();
714 rExpr1 = ScXMLConditionHelper::getExpression( pStart, pEnd, ')');
716 }
717 else if(rValue.startsWith("top-percent"))
718 {
719 const sal_Unicode* pStr = rValue.getStr();
720 const sal_Unicode* pStart = pStr + 12;
721 const sal_Unicode* pEnd = pStr + rValue.getLength();
722 rExpr1 = ScXMLConditionHelper::getExpression( pStart, pEnd, ')');
724 }
725 else if(rValue.startsWith("bottom-percent"))
726 {
727 const sal_Unicode* pStr = rValue.getStr();
728 const sal_Unicode* pStart = pStr + 15;
729 const sal_Unicode* pEnd = pStr + rValue.getLength();
730 rExpr1 = ScXMLConditionHelper::getExpression( pStart, pEnd, ')');
732 }
733 else if(rValue.startsWith("above-average"))
734 {
736 }
737 else if(rValue.startsWith("below-average"))
738 {
740 }
741 else if(rValue.startsWith("above-equal-average"))
742 {
744 }
745 else if(rValue.startsWith("below-equal-average"))
746 {
748 }
749 else if(rValue.startsWith("is-error"))
750 {
752 }
753 else if(rValue.startsWith("is-no-error"))
754 {
756 }
757 else if(rValue.startsWith("begins-with"))
758 {
760 const sal_Unicode* pStr = rValue.getStr();
761 const sal_Unicode* pStart = pStr + 12;
762 const sal_Unicode* pEnd = pStr + rValue.getLength();
763 rExpr1 = ScXMLConditionHelper::getExpression( pStart, pEnd, ')');
764 }
765 else if(rValue.startsWith("ends-with"))
766 {
768 const sal_Unicode* pStr = rValue.getStr();
769 const sal_Unicode* pStart = pStr + 10;
770 const sal_Unicode* pEnd = pStr + rValue.getLength();
771 rExpr1 = ScXMLConditionHelper::getExpression( pStart, pEnd, ')');
772 }
773 else if(rValue.startsWith("contains-text"))
774 {
776 const sal_Unicode* pStr = rValue.getStr();
777 const sal_Unicode* pStart = pStr + 14;
778 const sal_Unicode* pEnd = pStr + rValue.getLength();
779 rExpr1 = ScXMLConditionHelper::getExpression( pStart, pEnd, ')');
780 }
781 else if(rValue.startsWith("not-contains-text"))
782 {
784 const sal_Unicode* pStr = rValue.getStr();
785 const sal_Unicode* pStart = pStr + 18;
786 const sal_Unicode* pEnd = pStr + rValue.getLength();
787 rExpr1 = ScXMLConditionHelper::getExpression( pStart, pEnd, ')');
788 }
789 else
791}
792
793}
794
797 ScConditionalFormat* pFormat ):
798 ScXMLImportContext( rImport )
799{
800 OUString sExpression;
801 OUString sStyle;
802 OUString sAddress;
803
804 if ( rAttrList.is() )
805 {
806 for (auto &aIter : *rAttrList)
807 {
808 switch (aIter.getToken())
809 {
810 case XML_ELEMENT( CALC_EXT, XML_VALUE ):
811 sExpression = aIter.toString();
812 break;
813 case XML_ELEMENT( CALC_EXT, XML_APPLY_STYLE_NAME ):
814 sStyle = ScStyleNameConversion::ProgrammaticToDisplayName(aIter.toString(), SfxStyleFamily::Para );
815 break;
816 case XML_ELEMENT( CALC_EXT, XML_BASE_CELL_ADDRESS ):
817 sAddress = aIter.toString();
818 break;
819 default:
820 break;
821 }
822 }
823 }
824
825 OUString aExpr1;
826 OUString aExpr2;
828 GetConditionData(sExpression, eMode, aExpr1, aExpr2);
829
830 ScCondFormatEntry* pFormatEntry = new ScCondFormatEntry(eMode, aExpr1, aExpr2, *GetScImport().GetDocument(), ScAddress(), sStyle,
832 pFormatEntry->SetSrcString(sAddress);
833
834 pFormat->AddEntry(pFormatEntry);
835}
836
837namespace {
838
839void setColorEntryType(std::u16string_view rType, ScColorScaleEntry* pEntry, const OUString& rFormula,
840 ScXMLImport& rImport)
841{
842 if(rType == u"minimum")
843 pEntry->SetType(COLORSCALE_MIN);
844 else if(rType == u"maximum")
845 pEntry->SetType(COLORSCALE_MAX);
846 else if(rType == u"percentile")
848 else if(rType == u"percent")
850 else if(rType == u"formula")
851 {
853 //position does not matter, only table is important
854 pEntry->SetFormula(rFormula, *rImport.GetDocument(), ScAddress(0,0,rImport.GetTables().GetCurrentSheet()), formula::FormulaGrammar::GRAM_ODFF);
855 }
856 else if(rType == u"auto-minimum")
857 pEntry->SetType(COLORSCALE_AUTO);
858 else if(rType == u"auto-maximum")
859 pEntry->SetType(COLORSCALE_AUTO);
860}
861
862}
863
866 ScColorScaleFormat* pFormat):
867 ScXMLImportContext( rImport )
868{
869 double nVal = 0;
870 Color aColor;
871
872 OUString sType;
873 OUString sVal;
874 OUString sColor;
875
876 if ( rAttrList.is() )
877 {
878 for (auto &aIter : *rAttrList)
879 {
880 switch (aIter.getToken())
881 {
882 case XML_ELEMENT( CALC_EXT, XML_TYPE ):
883 sType = aIter.toString();
884 break;
885 case XML_ELEMENT( CALC_EXT, XML_VALUE ):
886 sVal = aIter.toString();
887 break;
888 case XML_ELEMENT( CALC_EXT, XML_COLOR ):
889 sColor = aIter.toString();
890 break;
891 default:
892 break;
893 }
894 }
895 }
896
898
899 if(!sVal.isEmpty())
901
902 auto pFormatEntry = new ScColorScaleEntry(nVal, aColor);
903 setColorEntryType(sType, pFormatEntry, sVal, GetScImport());
904 pFormat->AddEntry(pFormatEntry);
905}
906
909 ScColorScaleEntry*& pColorScaleEntry):
910 ScXMLImportContext( rImport )
911{
912 OUString sVal;
913 OUString sType;
914
915 if ( rAttrList.is() )
916 {
917 for (auto &aIter : *rAttrList)
918 {
919 switch (aIter.getToken())
920 {
921 case XML_ELEMENT( CALC_EXT, XML_TYPE ):
922 sType = aIter.toString();
923 break;
924 case XML_ELEMENT( CALC_EXT, XML_VALUE ):
925 sVal = aIter.toString();
926 break;
927 default:
928 break;
929 }
930 }
931 }
932
933 double nVal = 0;
934 if(!sVal.isEmpty())
936
937 pColorScaleEntry = new ScColorScaleEntry(nVal, Color());
938 setColorEntryType(sType, pColorScaleEntry, sVal, GetScImport());
939}
940
941namespace {
942
943condformat::ScCondFormatDateType getDateFromString(const OUString& rString)
944{
945 if(rString == "today")
946 return condformat::TODAY;
947 else if(rString == "yesterday")
949 else if(rString == "tomorrow")
951 else if(rString == "last-7-days")
953 else if(rString == "this-week")
955 else if(rString == "last-week")
957 else if(rString == "next-week")
959 else if(rString == "this-month")
961 else if(rString == "last-month")
963 else if(rString == "next-month")
965 else if(rString == "this-year")
967 else if(rString == "last-year")
969 else if(rString == "next-year")
971
972 SAL_WARN("sc", "unknown date type: " << rString);
973 return condformat::TODAY;
974}
975
976}
977
980 ScConditionalFormat* pFormat ):
981 ScXMLImportContext( rImport )
982{
983 OUString sDateType, sStyle;
984 if ( rAttrList.is() )
985 {
986 for (auto &aIter : *rAttrList)
987 {
988 switch (aIter.getToken())
989 {
990 case XML_ELEMENT( CALC_EXT, XML_DATE ):
991 sDateType = aIter.toString();
992 break;
993 case XML_ELEMENT( CALC_EXT, XML_STYLE ):
994 sStyle = ScStyleNameConversion::ProgrammaticToDisplayName(aIter.toString(), SfxStyleFamily::Para );
995 break;
996 default:
997 break;
998 }
999 }
1000 }
1001
1002 ScCondDateFormatEntry* pFormatEntry = new ScCondDateFormatEntry(GetScImport().GetDocument());
1003 pFormatEntry->SetStyleName(sStyle);
1004 pFormatEntry->SetDateType(getDateFromString(sDateType));
1005 pFormat->AddEntry(pFormatEntry);
1006
1007}
1008
1009/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
OptionalString sType
XPropertyListType t
BaseContainerNodeSharedPtr & mrParent
SC_DLLPUBLIC ScRefFlags Parse(const OUString &, const ScDocument &, const Details &rDetails=detailsOOOa1, ExternalInfo *pExtInfo=nullptr, const css::uno::Sequence< css::sheet::ExternalLinkInfo > *pExternalLinks=nullptr, sal_Int32 *pSheetEndPos=nullptr, const OUString *pErrRef=nullptr)
Definition: address.cxx:1537
void SetType(ScColorScaleEntryType eType)
Definition: colorscale.cxx:323
void SetRepaintCallback(ScConditionalFormat *pParent)
Definition: colorscale.cxx:315
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 SetGrammar(const formula::FormulaGrammar::Grammar eGrammar)
Definition: compiler.cxx:260
std::unique_ptr< ScTokenArray > CompileString(const OUString &rFormula)
Tokenize formula expression string into an array of tokens.
Definition: compiler.cxx:4691
void SetDateType(condformat::ScCondFormatDateType eType)
Definition: conditio.cxx:1693
void SetStyleName(const OUString &rStyleName)
Definition: conditio.cxx:1698
void SetSrcString(const OUString &rNew)
Definition: conditio.cxx:467
ScConditionalFormat * GetFormat(sal_uInt32 nKey)
Definition: conditio.cxx:2098
bool CheckAllEntries(const Link< ScConditionalFormat *, void > &rLink=Link< ScConditionalFormat *, void >())
Checks that all cond formats have a non empty range.
Definition: conditio.cxx:2196
void AddEntry(ScFormatEntry *pNew)
Definition: conditio.cxx:1768
sal_uInt32 GetKey() const
Definition: conditio.hxx:591
void SetDataBarData(ScDataBarFormatData *pData)
Definition: colorscale.cxx:769
ScRangeData * FindRangeNameBySheetAndIndex(SCTAB nTab, sal_uInt16 nIndex) const
Find a named expression / range name in either global or a local scope.
Definition: documen3.cxx:269
void SetCondFormList(ScConditionalFormatList *pList, SCTAB nTab)
Definition: documen4.cxx:867
SC_DLLPUBLIC void AddCondFormatData(const ScRangeList &rRange, SCTAB nTab, sal_uInt32 nIndex)
Definition: document.cxx:4790
SC_DLLPUBLIC ScConditionalFormatList * GetCondFormList(SCTAB nTab) const
Definition: documen4.cxx:860
SC_DLLPUBLIC sal_uLong AddCondFormat(std::unique_ptr< ScConditionalFormat > pNew, SCTAB nTab)
Definition: documen4.cxx:708
static const ScIconSetMap g_IconSetMap[]
Definition: colorscale.hxx:387
void SetIconSetData(ScIconSetFormatData *pData)
SCTAB GetCurrentSheet() const
Definition: xmlsubti.hxx:84
static bool GetRangeListFromString(ScRangeList &rRangeList, std::u16string_view rRangeListStr, const ScDocument &rDocument, formula::FormulaGrammar::AddressConvention eConv, sal_Unicode cSeparator=' ', sal_Unicode cQuote='\'')
Definition: rangeutl.cxx:552
static SC_DLLPUBLIC OUString ProgrammaticToDisplayName(const OUString &rProgName, SfxStyleFamily nType)
ScXMLColorScaleFormatContext(ScXMLImport &rImport, ScConditionalFormat *pFormat)
ScColorScaleFormat * pColorScaleFormat
virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList > &xAttrList) override
ScXMLColorScaleFormatEntryContext(ScXMLImport &rImport, const rtl::Reference< sax_fastparser::FastAttributeList > &rAttrList, ScColorScaleFormat *pFormat)
ScXMLCondContext(ScXMLImport &rImport, const rtl::Reference< sax_fastparser::FastAttributeList > &rAttrList, ScConditionalFormat *pFormat)
virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList > &xAttrList) override
ScXMLConditionalFormatContext(ScXMLImport &rImport, const rtl::Reference< sax_fastparser::FastAttributeList > &rAttrList, ScXMLConditionalFormatsContext &rParent)
std::unique_ptr< ScConditionalFormat > mxFormat
virtual void SAL_CALL endFastElement(sal_Int32 nElement) override
ScXMLConditionalFormatsContext & mrParent
virtual ~ScXMLConditionalFormatContext() override
virtual void SAL_CALL endFastElement(sal_Int32 nElement) override
virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList > &xAttrList) override
std::vector< CondFormatData > mvCondFormatData
ScXMLConditionalFormatsContext(ScXMLImport &rImport)
std::array< CacheEntry, 4 > maCache
virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList > &xAttrList) override
ScXMLDataBarFormatContext(ScXMLImport &rImport, const rtl::Reference< sax_fastparser::FastAttributeList > &rAttrList, ScConditionalFormat *pFormat)
ScDataBarFormatData * mpFormatData
ScConditionalFormat * mpParent
ScXMLDateContext(ScXMLImport &rImport, const rtl::Reference< sax_fastparser::FastAttributeList > &rAttrList, ScConditionalFormat *pFormat)
ScXMLFormattingEntryContext(ScXMLImport &rImport, const rtl::Reference< sax_fastparser::FastAttributeList > &rAttrList, ScColorScaleEntry *&pData)
virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList > &xAttrList) override
ScConditionalFormat * mpParent
ScIconSetFormatData * mpFormatData
ScXMLIconSetFormatContext(ScXMLImport &rImport, const rtl::Reference< sax_fastparser::FastAttributeList > &rAttrList, ScConditionalFormat *pFormat)
This class exists only to provide GetScImport() to its derived classes.
ScXMLImport & GetScImport()
ScDocument * GetDocument()
Definition: xmlimprt.hxx:205
ScMyTables & GetTables()
Definition: xmlimprt.hxx:208
void SetNewCondFormatData()
Definition: xmlimprt.hxx:260
static void convertDouble(OUStringBuffer &rBuffer, double fNumber, bool bWriteUnits, sal_Int16 nSourceUnit, sal_Int16 nTargetUnit)
static bool convertColor(sal_Int32 &rColor, std::u16string_view rValue)
static bool convertBool(bool &rBool, std::u16string_view rString)
ScIconSetType
Definition: colorscale.hxx:189
@ IconSet_3Arrows
Definition: colorscale.hxx:190
@ COLORSCALE_MAX
Definition: colorscale.hxx:35
@ 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
constexpr OUStringLiteral sColor
ScConditionMode
Definition: conditio.hxx:60
int nCount
RegionData_Impl * mpParent
DocumentType eType
sal_Int32 nIndex
OUString aName
Mode eMode
#define SAL_WARN_IF(condition, area, stream)
#define SAL_WARN(area, stream)
OUString getExpression(const sal_Unicode *&rpcString, const sal_Unicode *pcEnd, sal_Unicode cEndChar)
ScCondFormatDateType
Definition: conditio.hxx:485
int i
FastAttributeList & castToFastAttributeList(const css::uno::Reference< css::xml::sax::XFastAttributeList > &xAttrList)
XML_AXIS_POSITION
XML_DATA_BAR
XML_ICON_SET_TYPE
XML_MIN_LENGTH
XML_COLOR_SCALE
XML_CONDITION
XML_SHOW_VALUE
XML_POSITIVE_COLOR
XML_APPLY_STYLE_NAME
XML_GRADIENT
XML_STYLE
XML_NEGATIVE_COLOR
XML_VALUE
XML_DATE_IS
XML_TARGET_RANGE_ADDRESS
XML_COLOR_SCALE_ENTRY
XML_ICON_SET
XML_CONDITIONAL_FORMAT
XML_DATE
XML_DATA_BAR_ENTRY
XML_BASE_CELL_ADDRESS
XML_MAX_LENGTH
XML_COLOR
XML_FORMATTING_ENTRY
XML_AXIS_COLOR
XML_TYPE
ocCell
ocRow
ocColumn
ocSheet
ocName
sal_uIntPtr sal_uLong
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
double mnMinLength
Minimal length of a databar in percent of cell length Value has to be in the range [0,...
Definition: colorscale.hxx:172
double mnMaxLength
Maximal length of a databar in percent of cell length Value has to be in the range (0,...
Definition: colorscale.hxx:177
Color maPositiveColor
Color for all Positive Values and if mbNeg == false also for negative ones.
Definition: colorscale.hxx:134
bool mbNeg
Use different color for negative values.
Definition: colorscale.hxx:159
bool mbGradient
Paint the bars with gradient.
Definition: colorscale.hxx:152
bool mbOnlyBar
If TRUE we only show the bar and not the value.
Definition: colorscale.hxx:182
std::unique_ptr< ScColorScaleEntry, o3tl::default_delete< ScColorScaleEntry > > mpUpperLimit
Definition: colorscale.hxx:184
ScIconSetType eIconSetType
Definition: colorscale.hxx:340
ScIconSetType eType
Definition: colorscale.hxx:216
const char * pName
Definition: colorscale.hxx:215
Single reference (one address) into the sheet.
Definition: refdata.hxx:30
bool IsTabRel() const
Definition: refdata.hxx:69
bool IsRowRel() const
Definition: refdata.hxx:67
bool IsColRel() const
Definition: refdata.hxx:65
bool IsFlag3D() const
Definition: refdata.hxx:90
sal_uInt32 mnIndex
#define SAL_MAX_INT64
sal_uInt16 sal_Unicode
sal_Int16 SCTAB
Definition: types.hxx:22
static bool HasOneSingleFullyRelativeReference(const ScTokenArray *pTokens, ScSingleRefData &rOffset)
IMPL_LINK(ScXMLConditionalFormatsContext, FormatDeletedHdl, ScConditionalFormat *, pFormat, void)
static bool HasRelRefIgnoringSheet0Relative(ScDocument *pDoc, const ScTokenArray *pTokens, sal_uInt16 nRecursion=0)
#define XML_ELEMENT(prefix, name)